From Aaron Woo (via Jeff Weston): Optimized Link State Routing Protocol
[obnox/wireshark/wip.git] / packet-diameter.c
1 /* packet-diameter.c
2  * Routines for Diameter packet disassembly
3  *
4  * $Id: packet-diameter.c,v 1.56 2003/10/29 21:19:44 guy Exp $
5  *
6  * Copyright (c) 2001 by David Frascone <dave@frascone.com>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <glib.h>
37 #include <epan/filesystem.h>
38 #include "xmlstub.h"
39 #include <epan/packet.h>
40 #include <epan/resolv.h>
41 #include "prefs.h"
42
43 #ifdef NEED_SNPRINTF_H
44 # include "snprintf.h"
45 #endif
46
47 /* This must be defined before we include packet-diameter-defs.h */
48
49 /* Valid data types */
50 typedef enum {
51   /* Base Types */
52   DIAMETER_OCTET_STRING = 1,
53   DIAMETER_INTEGER32,
54   DIAMETER_INTEGER64,
55   DIAMETER_UNSIGNED32,
56   DIAMETER_UNSIGNED64,
57   DIAMETER_FLOAT32,
58   DIAMETER_FLOAT64,
59   DIAMETER_FLOAT128,
60   DIAMETER_GROUPED,
61
62   /* Derived Types */
63   DIAMETER_IP_ADDRESS,         /* OctetString */
64   DIAMETER_TIME,               /* Integer 32 */
65   DIAMETER_UTF8STRING,         /* OctetString */
66   DIAMETER_IDENTITY,           /* OctetString */
67   DIAMETER_ENUMERATED,         /* Integer 32 */
68   DIAMETER_IP_FILTER_RULE,     /* OctetString */
69   DIAMETER_QOS_FILTER_RULE,    /* OctetString */
70   DIAMETER_MIP_REG_REQ,        /* OctetString */
71   DIAMETER_VENDOR_ID,           /* Integer32  */
72   DIAMETER_APPLICATION_ID
73
74 } diameterDataType;
75
76
77 static value_string TypeValues[]={
78   {  DIAMETER_OCTET_STRING,    "OctetString" },
79   {  DIAMETER_INTEGER32,       "Integer32" },
80   {  DIAMETER_INTEGER64,       "Integer64" },
81   {  DIAMETER_UNSIGNED32,      "Unsigned32" },
82   {  DIAMETER_UNSIGNED64,      "Unsigned64" },
83   {  DIAMETER_FLOAT32,         "Float32" },
84   {  DIAMETER_FLOAT64,         "Float64" },
85   {  DIAMETER_FLOAT128,        "Float128" },
86   {  DIAMETER_GROUPED,         "Grouped" },
87   {  DIAMETER_IP_ADDRESS,      "IpAddress" },
88   {  DIAMETER_TIME,            "Time" },
89   {  DIAMETER_UTF8STRING,      "UTF8String" },
90   {  DIAMETER_IDENTITY,        "DiameterIdentity" },
91   {  DIAMETER_ENUMERATED,      "Enumerated" },
92   {  DIAMETER_IP_FILTER_RULE,  "IPFilterRule" },
93   {  DIAMETER_QOS_FILTER_RULE, "QOSFilterRule" },
94   {  DIAMETER_MIP_REG_REQ,     "MIPRegistrationRequest"},
95   {  DIAMETER_VENDOR_ID,       "VendorId"},
96   {  DIAMETER_APPLICATION_ID,  "AppId"},
97   {0, (char *)NULL}
98 };
99
100 typedef struct value_name {
101   guint32            value;
102   gchar             *name;
103   struct value_name *next;
104 } ValueName;
105
106 typedef struct old_avp_info {
107   guint32           code;
108   gchar            *name;
109   diameterDataType  type;
110   value_string     *values;
111 } oldAvpInfo;
112
113 typedef struct avp_info {
114   guint32           code;
115   gchar            *name;
116   gchar            *vendorName;
117   diameterDataType  type;
118   ValueName        *values;
119   struct avp_info  *next;
120 } avpInfo;
121
122 typedef struct command_code {
123   guint32              code;
124   gchar               *name;
125   gchar               *vendorName;
126   struct command_code *next;
127 } CommandCode;
128
129 typedef struct vendor_id {
130   guint32              id;
131   gchar               *name;
132   gchar               *longName;
133   struct vendor_id    *next;
134 } VendorId;
135
136 typedef struct application_id {
137   guint32              id;
138   gchar               *name;
139   struct application_id    *next;
140 } ApplicationId;
141
142 static avpInfo         *avpListHead=NULL;
143 static VendorId        *vendorListHead=NULL;
144 static CommandCode     *commandListHead=NULL;
145 static ApplicationId   *ApplicationIdHead=NULL;
146
147
148 #include "packet-diameter-defs.h"
149
150 #define  NTP_TIME_DIFF                   (2208988800UL)
151
152 #define TCP_PORT_DIAMETER       1812
153 #define SCTP_PORT_DIAMETER      1812
154
155 static const true_false_string reserved_set = {
156   "*** Error! Reserved Bit is Set",
157   "Ok"
158 };
159 static int proto_diameter = -1;
160 static int hf_diameter_length = -1;
161 static int hf_diameter_code = -1;
162 static int hf_diameter_hopbyhopid =-1;
163 static int hf_diameter_endtoendid =-1;
164 static int hf_diameter_version = -1;
165 static int hf_diameter_vendor_id = -1;
166 static int hf_diameter_flags = -1;
167 static int hf_diameter_flags_request = -1;
168 static int hf_diameter_flags_proxyable = -1;
169 static int hf_diameter_flags_error = -1;
170 static int hf_diameter_flags_reserved3 = -1;
171 static int hf_diameter_flags_reserved4 = -1;
172 static int hf_diameter_flags_reserved5 = -1;
173 static int hf_diameter_flags_reserved6 = -1;
174 static int hf_diameter_flags_reserved7 = -1;
175
176 static int hf_diameter_avp_code = -1;
177 static int hf_diameter_avp_length = -1;
178 static int hf_diameter_avp_flags = -1;
179 static int hf_diameter_avp_flags_vendor_specific = -1;
180 static int hf_diameter_avp_flags_mandatory = -1;
181 static int hf_diameter_avp_flags_protected = -1;
182 static int hf_diameter_avp_flags_reserved3 = -1;
183 static int hf_diameter_avp_flags_reserved4 = -1;
184 static int hf_diameter_avp_flags_reserved5 = -1;
185 static int hf_diameter_avp_flags_reserved6 = -1;
186 static int hf_diameter_avp_flags_reserved7 = -1;
187 static int hf_diameter_avp_vendor_id = -1;
188
189
190 static int hf_diameter_avp_data_uint32 = -1;
191 static int hf_diameter_avp_data_int32 = -1;
192 static int hf_diameter_avp_data_uint64 = -1;
193 static int hf_diameter_avp_data_int64 = -1;
194 static int hf_diameter_avp_data_bytes = -1;
195 static int hf_diameter_avp_data_string = -1;
196 static int hf_diameter_avp_data_v4addr = -1;
197 static int hf_diameter_avp_data_v6addr = -1;
198 static int hf_diameter_avp_data_time = -1;
199
200 static gint ett_diameter = -1;
201 static gint ett_diameter_flags = -1;
202 static gint ett_diameter_avp = -1;
203 static gint ett_diameter_avp_flags = -1;
204 static gint ett_diameter_avpinfo = -1;
205
206 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
207 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
208
209 /* desegmentation of Diameter over TCP */
210 static gboolean gbl_diameter_desegment = TRUE;
211
212 #define DICT_FN  "diameter/dictionary.xml"
213 static gchar *gbl_diameterDictionary;
214
215 typedef struct _e_diameterhdr {
216   guint32  versionLength;
217   guint32  flagsCmdCode;
218   guint32  vendorId;
219   guint32  hopByHopId;
220   guint32  endToEndId;
221 } e_diameterhdr;
222
223 typedef struct _e_avphdr {
224   guint32 avp_code;
225   guint32 avp_flagsLength;
226   guint32 avp_vendorId;           /* optional */
227 } e_avphdr;
228
229 /* Diameter Header Flags */
230 /*                                      RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC  */
231 #define DIAM_FLAGS_R 0x80
232 #define DIAM_FLAGS_P 0x40
233 #define DIAM_FLAGS_E 0x20
234 #define DIAM_FLAGS_RESERVED3 0x10
235 #define DIAM_FLAGS_RESERVED4 0x08
236 #define DIAM_FLAGS_RESERVED5 0x04
237 #define DIAM_FLAGS_RESERVED6 0x02
238 #define DIAM_FLAGS_RESERVED7 0x01
239 #define DIAM_FLAGS_RESERVED  0x1f
240
241 #define DIAM_LENGTH_MASK  0x00ffffffl
242 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
243 #define DIAM_GET_FLAGS(dh)                ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
244 #define DIAM_GET_VERSION(dh)              ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
245 #define DIAM_GET_COMMAND(dh)              (dh.flagsCmdCode & DIAM_COMMAND_MASK)
246 #define DIAM_GET_LENGTH(dh)               (dh.versionLength & DIAM_LENGTH_MASK)
247
248 /* Diameter AVP Flags */
249 #define AVP_FLAGS_P 0x20
250 #define AVP_FLAGS_V 0x80
251 #define AVP_FLAGS_M 0x40
252 #define AVP_FLAGS_RESERVED3 0x10
253 #define AVP_FLAGS_RESERVED4 0x08
254 #define AVP_FLAGS_RESERVED5 0x04
255 #define AVP_FLAGS_RESERVED6 0x02
256 #define AVP_FLAGS_RESERVED7 0x01
257 #define AVP_FLAGS_RESERVED 0x1f          /* 00011111  -- V M P X X X X X */
258
259 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
260 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
261
262 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
263
264
265 /*
266  * This routine will do a push-parse of the passed in
267  * filename.  This was taken almost verbatum from
268  * the xmlsoft examples.
269  */
270 static xmlDocPtr
271 xmlParseFilePush( char *filename, int checkValid) {
272   FILE *f;
273   xmlDocPtr doc=NULL;
274   int valid=0;
275   int res, size = 1024;
276   char chars[1024];
277   xmlParserCtxtPtr ctxt;
278
279   /* I wonder what kind of a performance hit this is? */
280   *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
281
282   f = fopen(filename, "r");
283   if (f == NULL) {
284         g_warning("Diameter: Unable to open %s", filename);
285         return NULL;
286   }
287
288   res = fread(chars, 1, 4, f);
289   if (res > 0) {
290         ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
291                                                                                    chars, res, filename);
292         while ((res = fread(chars, 1, size-1, f)) > 0) {
293           XmlStub.xmlParseChunk(ctxt, chars, res, 0);
294         }
295         XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
296         doc = ctxt->myDoc;
297         valid=ctxt->valid;
298         XmlStub.xmlFreeParserCtxt(ctxt);
299   }
300   fclose(f);
301
302   /* Check valid */
303   if (!valid) {
304         g_warning( "Error!  Invalid xml in %s!  Failed DTD check!",
305                            filename);
306         return NULL;
307   }
308   return doc;
309 } /* xmlParseFilePush */
310
311 /*
312  * This routine will add a static avp to the avp list.  It is
313  * only called when the XML dictionary fails to load properly.
314  */
315 static int
316 addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
317 {
318   avpInfo *entry;
319   ValueName *vEntry=NULL;
320   int i;
321
322   /* Parse our values array, if we have one */
323   if (values) {
324         for (i=0; values[i].strptr != NULL; i++) {
325           ValueName *ve = NULL;
326
327           ve = g_malloc(sizeof(ValueName));
328           ve->name = strdup(values[i].strptr);
329           ve->value = values[i].value;
330           ve->next = vEntry;
331           vEntry = ve;
332         }
333   } /* if values */
334
335         /* And, create the entry */
336   entry = (avpInfo *)g_malloc(sizeof(avpInfo));
337   entry->name = g_strdup(name);
338   entry->code = code;
339   entry->vendorName = NULL;
340   entry->type = type;
341   entry->values = vEntry;
342   if (vEntry)
343         entry->type = DIAMETER_INTEGER32;
344
345   /* And, add it to the list */
346   entry->next = avpListHead;
347   avpListHead = entry;
348
349   return (0);
350
351 } /* addStaticAVP */
352
353 /*
354  * This routine will parse an XML avp entry, and add it to our
355  * avp list.  If any values are present in the avp, it will
356  * add them too.
357  */
358 static int
359 xmlParseAVP(xmlNodePtr cur)
360 {
361   char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
362         *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
363         *constrained=NULL;
364   char *type=NULL;
365   avpInfo *entry;
366   guint32 avpType=0;
367   ValueName *vEntry=NULL;
368   int i;
369
370   /* First, get our properties */
371   name = XmlStub.xmlGetProp(cur, "name");
372   description = XmlStub.xmlGetProp(cur, "description");
373   code = XmlStub.xmlGetProp(cur, "code");
374   mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
375   mandatory = XmlStub.xmlGetProp(cur, "mandatory");
376   protected = XmlStub.xmlGetProp(cur, "protected");
377   vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
378   vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
379   constrained = XmlStub.xmlGetProp(cur, "constrained");
380
381   cur = cur->xmlChildrenNode;
382
383   while (cur != NULL ) {
384         if (strcasecmp(cur->name, "type") == 0) {
385           type = XmlStub.xmlGetProp(cur, "type-name");
386         } else if (strcasecmp(cur->name, "enum") == 0) {
387           char *valueName=NULL, *valueCode=NULL;
388           ValueName *ve = NULL;
389           valueName = XmlStub.xmlGetProp(cur, "name");
390           valueCode = XmlStub.xmlGetProp(cur, "code");
391
392           if (!valueName || !valueCode) {
393                 g_warning( "Error, bad value on avp %s", name);
394                 return (-1);
395           }
396
397           ve = g_malloc(sizeof(ValueName));
398           ve->name = strdup(valueName);
399           ve->value = atol(valueCode);
400
401           ve->next = vEntry;
402           vEntry = ve;
403         } else if (strcasecmp(cur->name, "grouped") == 0) {
404           /* WORK Recurse here for grouped AVPs */
405           type = "grouped";
406         }
407         cur=cur->next;
408   } /* while */
409
410         /*
411          * Check for the AVP Type.
412          */
413   if (type) {
414         for (i = 0; TypeValues[i].strptr; i++) {
415           if (!strcasecmp(type, TypeValues[i].strptr)) {
416                 avpType = TypeValues[i].value;
417                 break;
418           }
419         }
420
421         if (TypeValues[i].strptr == NULL) {
422           g_warning( "Invalid Type field in dictionary! avp %s (%s)",  name, type);
423           return (-1);
424         }
425   } else if (!vEntry) {
426         g_warning("Missing type/enum field in dictionary avpName=%s",
427                           name);
428         return (-1);
429   }
430
431   /* WORK - Handle flags  -- for validation later */
432
433
434   /* And, create the entry */
435   entry = (avpInfo *)g_malloc(sizeof(avpInfo));
436   entry->name = g_strdup(name);
437   entry->code = atol(code);
438   if (vendorName)
439         entry->vendorName = g_strdup(vendorName);
440   else
441         entry->vendorName = NULL;
442   entry->type = avpType;
443   entry->values = vEntry;
444   if (vEntry)
445         entry->type = DIAMETER_INTEGER32;
446
447   /* And, add it to the list */
448   entry->next = avpListHead;
449   avpListHead = entry;
450
451   return (0);
452 } /* xmlParseAVP */
453
454 /*
455  * This routine will add a command to the list of commands.
456  */
457 static int
458 addCommand(int code, char *name, char *vendorId)
459 {
460   CommandCode *entry;
461
462   /*
463    * Allocate the memory required for the dictionary.
464    */
465   entry = (CommandCode *) g_malloc(sizeof (CommandCode));
466
467   if (entry == NULL) {
468         g_warning("Unable to allocate memory");
469         return (-1);
470   }
471
472   /*
473    * Allocate memory for the AVPName and copy the name to the
474    * structure
475    */
476   entry->name = g_strdup(name);
477   entry->code = code;
478   if (vendorId)
479         entry->vendorName = g_strdup(vendorId);
480   else
481         entry->vendorName = "None";
482
483   /* Add the entry to the list */
484   entry->next = commandListHead;
485   commandListHead = entry;
486
487   return 0;
488 } /* addCommand */
489
490 /*
491  * This routine will parse the XML command, and add it to our
492  * list of commands.
493  */
494 static int
495 xmlParseCommand(xmlNodePtr cur)
496 {
497   char *name, *code, *vendorIdString;
498
499   /*
500    * Get the Attributes
501    */
502   name = XmlStub.xmlGetProp(cur, "name");
503   code = XmlStub.xmlGetProp(cur, "code");
504   if (!name || !code) {
505         g_warning("Invalid command.  Name or code missing!");
506         return -1;
507   }
508   vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
509
510   if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
511         vendorIdString = NULL;
512   }
513
514   return (addCommand(atoi(code), name, vendorIdString));
515 } /* xmlParseCommand */
516
517 /* This routine adds an application to the name<-> id table */
518 static int
519 dictionaryAddApplication(char *name, int id)
520 {
521   ApplicationId *entry;
522
523   if (!name || (id <= 0)) {
524         g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
525                            name, id);
526         return (-1);
527   } /* Sanity Checks */
528
529   entry = g_malloc(sizeof(ApplicationId));
530   if (!entry) {
531         g_warning( "Unable to allocate memory");
532         return (-1);
533   }
534
535   entry->name = g_strdup(name);
536   entry->id = id;
537
538   /* Add it to the list */
539   entry->next = ApplicationIdHead;
540   ApplicationIdHead = entry;
541
542   return 0;
543 } /* dictionaryAddApplication */
544
545 /*
546  * This routine will add a vendor to the vendors list
547  */
548 static int
549 addVendor(int id, gchar *name, gchar *longName)
550 {
551   VendorId *vendor;
552
553   /* add entry */
554   vendor=g_malloc(sizeof(VendorId));
555   if (!vendor) {
556         return (-1);
557   }
558
559   vendor->id = id;
560   vendor->name = g_strdup(name);
561   vendor->longName = g_strdup(longName);
562   vendor->next = vendorListHead;
563   vendorListHead = vendor;
564
565   return 0;
566 } /* addVendor */
567
568 /*
569  * This routine will pars in a XML vendor entry.
570  */
571 static int
572 xmlParseVendor(xmlNodePtr cur)
573 {
574   char *name=NULL, *code=NULL, *id=NULL;
575
576   /* First, get our properties */
577   id = XmlStub.xmlGetProp(cur, "vendor-id");
578   name = XmlStub.xmlGetProp(cur, "name");
579   code = XmlStub.xmlGetProp(cur, "code");
580
581   if (!id || !name || !code) {
582         g_warning( "Invalid vendor section.  vendor-id, name, and code must be specified");
583         return -1;
584   }
585
586   return (addVendor(atoi(code), id, name));
587 } /* addVendor */
588
589 /*
590  * This routine will either parse in the base protocol, or an application.
591  */
592 static int
593 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
594 {
595   if (!base) {
596         char *name;
597         char *id;
598
599         /* Add our application */
600         id = XmlStub.xmlGetProp(cur, "id");
601         name = XmlStub.xmlGetProp(cur, "name");
602
603         if (!name || !id) {
604           /* ERROR!!! */
605           g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
606                                 name?name:"NULL", id?id:"NULL");
607           return -1;
608         }
609
610         /* Add the application */
611         if (dictionaryAddApplication(name, atol(id)) != 0) {
612           /* ERROR! */
613           return -1;
614         }
615   }
616
617
618   /*
619    * Get segment values
620    */
621   cur = cur->xmlChildrenNode;
622   while (cur != NULL) {
623         if (strcasecmp(cur->name, "avp") == 0) {
624           /* we have an avp!!! */
625           xmlParseAVP(cur);
626         } else if (strcasecmp(cur->name, "vendor") == 0) {
627           /* we have a vendor */
628           xmlParseVendor(cur);
629           /* For now, ignore typedefn and text */
630         } else if (strcasecmp(cur->name, "command") == 0) {
631           /* Found a command */
632           xmlParseCommand(cur);
633         } else if (strcasecmp(cur->name, "text") == 0) {
634         } else if (strcasecmp(cur->name, "comment") == 0) {
635         } else if (strcasecmp(cur->name, "typedefn") == 0) {
636           /* WORK -- parse in valid types . . . */
637         } else {
638           /* IF we got here, we're an error */
639           g_warning("Error!  expecting an avp or a typedefn (got \"%s\")",
640                                 cur->name);
641           return (-1);
642         }
643         cur = cur->next;
644   } /* while */
645   return 0;
646 } /* xmlDictionaryParseSegment */
647
648 /*
649  * The main xml parse routine.  This will walk through an XML
650  * dictionary that has been parsed by libxml.
651  */
652 static int
653 xmlDictionaryParse(xmlNodePtr cur)
654 {
655   /* We should expect a base protocol, followed by multiple applicaitons */
656   while (cur != NULL) {
657         if (strcasecmp(cur->name, "base") == 0) {
658           /* Base protocol.  Descend and parse */
659           xmlDictionaryParseSegment(cur, 1);
660         } else if (strcasecmp(cur->name, "application") == 0) {
661           /* Application.  Descend and parse */
662           xmlDictionaryParseSegment(cur, 0);
663         } else if (strcasecmp(cur->name, "text") == 0) {
664           /* Ignore text */
665         } else {
666           g_warning( "Diameter: XML Expecting a base or an application  (got \"%s\")",
667                                  cur->name);
668           return (-1);
669         }
670         cur = cur->next;
671   }
672
673   return 0;
674
675 } /* xmlDictionaryParse */
676
677 /*
678  * This routine will call libxml to parse in the dictionary.
679  */
680 static int
681 loadXMLDictionary()
682 {
683   xmlDocPtr doc;
684   xmlNodePtr cur;
685
686   /*
687    * build an XML tree from a the file;
688    */
689   XmlStub.xmlKeepBlanksDefault(0);                    /* Strip leading and trailing blanks */
690   XmlStub.xmlSubstituteEntitiesDefault(1);            /* Substitute entities automagically */
691   doc = xmlParseFilePush(gbl_diameterDictionary, 1);  /* Parse the XML (do validity checks)*/
692
693   /* Check for invalid xml */
694   if (doc == NULL) {
695         g_warning("Diameter: Unable to parse xmldictionary %s",
696                           gbl_diameterDictionary);
697         return -1;
698   }
699
700   /*
701    * Check the document is of the right kind
702    */
703   cur = XmlStub.xmlDocGetRootElement(doc);
704   if (cur == NULL) {
705         g_warning("Diameter: Error: \"%s\": empty document",
706                           gbl_diameterDictionary);
707         XmlStub.xmlFreeDoc(doc);
708         return -1;
709   }
710   if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
711         g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
712                           gbl_diameterDictionary);
713         XmlStub.xmlFreeDoc(doc);
714         return -1;
715   }
716
717   /*
718    * Ok, the dictionary has been parsed by libxml, and is valid.
719    * All we have to do now is read in our information.
720    */
721   if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
722         /* Error has already been printed */
723         return -1;
724   }
725
726   /* Once we're done parsing, free up the xml memory */
727   XmlStub.xmlFreeDoc(doc);
728
729   return 0;
730
731 } /* loadXMLDictionary */
732
733 /*
734  * Fallback routine.  In the event of ANY error when loading the XML
735  * dictionary, this routine will populate the new avp list structures
736  * with the old static data from packet-diameter-defs.h
737  */
738 static void
739 initializeDictionaryDefaults()
740 {
741   int i;
742
743   /* Add static vendors to list */
744   for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
745         addVendor(diameter_vendor_specific_vendors[i].value,
746                           diameter_vendor_specific_vendors[i].strptr,
747                           diameter_vendor_specific_vendors[i].strptr);
748   }
749   /* Add static commands to list. */
750   for(i=0; diameter_command_code_vals[i].strptr; i++) {
751         addCommand(diameter_command_code_vals[i].value,
752                            diameter_command_code_vals[i].strptr, NULL);
753   }
754
755   /* Add static AVPs to list */
756   for (i=0; old_diameter_avps[i].name; i++) {
757         addStaticAVP(old_diameter_avps[i].code,
758                                  old_diameter_avps[i].name,
759                                  old_diameter_avps[i].type,
760                                  old_diameter_avps[i].values);
761   }
762
763 } /* initializeDictionaryDefaults */
764
765 /*
766  * This routine will attempt to load the XML dictionary, and on
767  * failure, will call initializeDictionaryDefaults to load in
768  * our static dictionary.
769  */
770 static void
771 initializeDictionary()
772 {
773   /*
774    * Using ugly ordering here.  If loadLibXML succeeds, then
775    * loadXMLDictionary will be called.  This is one of the few times when
776    * I think this is prettier than the nested if alternative.
777    */
778   if (loadLibXML() ||
779           (loadXMLDictionary() != 0)) {
780         /* Something failed.  Use the static dictionary */
781         g_warning("Diameter: Using static dictionary! (Unable to use XML)");
782         initializeDictionaryDefaults();
783   }
784 } /* initializeDictionary */
785
786
787
788 /*
789  * These routines manipulate the diameter structures.
790  */
791
792 /* return vendor string, based on the id */
793 static gchar *
794 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
795   VendorId *probe;
796   static gchar buffer[64];
797
798   for (probe=vendorListHead; probe; probe=probe->next) {
799         if (vendorId == probe->id) {
800           if (longName)
801                 return probe->longName;
802           else
803                 return probe->name;
804         }
805   }
806
807   snprintf(buffer, sizeof(buffer),
808                    "Vendor 0x%08x", vendorId);
809   return buffer;
810 } /*diameter_vendor_to_str */
811
812 /* return command string, based on the code */
813 static gchar *
814 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
815 {
816   CommandCode *probe;
817   static gchar buffer[64];
818   gchar *vendorName=NULL;
819
820   if (vendorId)
821         vendorName = diameter_vendor_to_str(vendorId, FALSE);
822
823   for (probe=commandListHead; probe; probe=probe->next) {
824         if (commandCode == probe->code) {
825           if (vendorId) {
826 /*              g_warning("Command: Comparing \"%s\" to \"%s\"", */
827 /*                                vendorName?vendorName:"(null)", */
828 /*                                probe->vendorName?probe->vendorName:"(null)"); */
829                 /* Now check the vendor name */
830                 if (!strcmp(vendorName, probe->vendorName))
831                   /* We found it */
832                   return probe->name;
833           } else {
834                 /* With no vendor id, the Command's entry should be "None" */
835                 if (!strcmp(probe->vendorName, "None")) {
836                   /* We found it */
837                   return probe->name;
838                 }
839           }
840         }
841   }
842
843   g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
844                         commandCode, vendorId);
845   snprintf(buffer, sizeof(buffer),
846                    "Cmd-0x%08x", commandCode);
847   return buffer;
848 }/*diameter_command_to_str */
849
850 /* return application string, based on the id */
851 static gchar *
852 diameter_app_to_str(guint32 vendorId) {
853   ApplicationId *probe;
854   static gchar buffer[64];
855
856   for (probe=ApplicationIdHead; probe; probe=probe->next) {
857         if (vendorId == probe->id) {
858           return probe->name;
859         }
860   }
861
862   snprintf(buffer, sizeof(buffer),
863                    "AppId 0x%08x", vendorId);
864   return buffer;
865 } /*diameter_app_to_str */
866
867 /* return an avp type, based on the code */
868 static diameterDataType
869 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
870   avpInfo *probe;
871   gchar *vendorName=NULL;
872
873   if (vendorId)
874         vendorName = diameter_vendor_to_str(vendorId, FALSE);
875
876   for (probe=avpListHead; probe; probe=probe->next) {
877         if (avpCode == probe->code) {
878
879           if (vendorId) {
880 /*              g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
881 /*                                vendorName?vendorName:"(null)", */
882 /*                                probe->vendorName?probe->vendorName:"(null)"); */
883                 /* Now check the vendor name */
884                 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
885                   /* We found it! */
886                   return probe->type;
887           } else {
888                 /* No Vendor ID -- vendorName should be null */
889                 if (!probe->vendorName)
890                   /* We found it! */
891                   return probe->type;
892           }
893         }
894   }
895
896   /* If we don't find it, assume it's data */
897   g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
898                         vendorId);
899   return DIAMETER_OCTET_STRING;
900 } /* diameter_avp_get_type */
901
902 /* return an avp name from the code */
903 static gchar *
904 diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
905 {
906   static gchar buffer[64];
907   avpInfo *probe;
908   gchar *vendorName=NULL;
909
910   if (vendorId)
911         vendorName = diameter_vendor_to_str(vendorId, FALSE);
912
913   for (probe=avpListHead; probe; probe=probe->next) {
914         if (avpCode == probe->code) {
915           if (vendorId) {
916 /*              g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
917 /*                                vendorName?vendorName:"(null)", */
918 /*                                probe->vendorName?probe->vendorName:"(null)"); */
919                 /* Now check the vendor name */
920                 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
921                   /* We found it! */
922                   return probe->name;
923           } else {
924                 /* No Vendor ID -- vendorName should be null */
925                 if (!probe->vendorName)
926                   /* We found it! */
927                   return probe->name;
928           }
929         }
930   }
931
932   g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
933                         avpCode, vendorId);
934
935   /* If we don't find it, build a name string */
936   sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
937   return buffer;
938 } /* diameter_avp_get_name */
939 static gchar *
940 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
941 {
942   static gchar buffer[64];
943
944   avpInfo *probe;
945   gchar *vendorName=NULL;
946
947   if (vendorId)
948         vendorName = diameter_vendor_to_str(vendorId, FALSE);
949
950   for (probe=avpListHead; probe; probe=probe->next) {
951         if (avpCode == probe->code) {
952           if (vendorId) {
953 /*              g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
954 /*                                vendorName?vendorName:"(null)", */
955 /*                                probe->vendorName?probe->vendorName:"(null)"); */
956                 /* Now check the vendor name */
957                 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
958                   ValueName *vprobe;
959                   for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
960                         if (avpValue == vprobe->value) {
961                           return vprobe->name;
962                         }
963                   }
964                   sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
965                   return buffer;
966                 }
967           } else {
968                 if (!probe->vendorName) {
969                   ValueName *vprobe;
970                   for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
971                         if (avpValue == vprobe->value) {
972                           return vprobe->name;
973                         }
974                   }
975                   sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
976                   return buffer;
977                 }
978           }
979         }
980   }
981   /* If we don't find the avp, build a value string */
982   sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
983   return buffer;
984 } /* diameter_avp_get_value */
985
986
987 /* Code to actually dissect the packets */
988
989 /*
990  * Main dissector
991  */
992 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
993                                                                            proto_tree *tree)
994 {
995
996   /* Set up structures needed to add the protocol subtree and manage it */
997   proto_item      *ti;
998   proto_item      *tf;
999   proto_tree      *flags_tree;
1000   tvbuff_t        *avp_tvb;
1001   proto_tree      *diameter_tree;
1002   e_diameterhdr    dh;
1003   size_t           offset=0;
1004   size_t           avplength;
1005   proto_tree      *avp_tree;
1006   proto_item      *avptf;
1007   int              BadPacket = FALSE;
1008   guint32          commandCode, pktLength;
1009   guint8           version, flags;
1010   gchar            flagstr[64] = "<None>";
1011   gchar           *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1012   gchar            commandString[64], vendorName[64];
1013   gint        i;
1014   guint      bpos;
1015   static  int initialized=FALSE;
1016
1017   /* set our offset */
1018   offset=start;
1019
1020   /*
1021    * Only parse in dictionary if there are diameter packets to
1022    * dissect.
1023    */
1024   if (!initialized) {
1025           /* Read in our dictionary, if it exists. */
1026           initializeDictionary();
1027           initialized=TRUE;
1028   }
1029
1030   /* Make entries in Protocol column and Info column on summary display */
1031   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1032         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1033   if (check_col(pinfo->cinfo, COL_INFO))
1034         col_clear(pinfo->cinfo, COL_INFO);
1035
1036   /* Copy our header */
1037   tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1038
1039   /* Fix byte ordering in our static structure */
1040   dh.versionLength = g_ntohl(dh.versionLength);
1041   dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
1042   dh.vendorId = g_ntohl(dh.vendorId);
1043   dh.hopByHopId = g_ntohl(dh.hopByHopId);
1044   dh.endToEndId = g_ntohl(dh.endToEndId);
1045
1046   if (dh.vendorId) {
1047         strcpy(vendorName,
1048                    diameter_vendor_to_str(dh.vendorId, TRUE));
1049   } else {
1050         strcpy(vendorName, "None");
1051   }
1052
1053
1054   /* Do the bit twiddling */
1055   version = DIAM_GET_VERSION(dh);
1056   pktLength = DIAM_GET_LENGTH(dh);
1057   flags = DIAM_GET_FLAGS(dh);
1058   commandCode = DIAM_GET_COMMAND(dh);
1059
1060   /* Set up our flags */
1061   if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1062         flagstr[0]=0;
1063         for (i = 0; i < 8; i++) {
1064           bpos = 1 << i;
1065           if (flags & bpos) {
1066                 if (flagstr[0]) {
1067                   strcat(flagstr, ", ");
1068                 }
1069                 strcat(flagstr, fstr[i]);
1070           }
1071         }
1072         if (strlen(flagstr) == 0) {
1073           strcpy(flagstr,"<None>");
1074         }
1075   }
1076
1077   /* Set up our commandString */
1078   strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1079   if (flags & DIAM_FLAGS_R)
1080         strcat(commandString, "-Request");
1081   else
1082         strcat(commandString, "-Answer");
1083
1084   /* Short packet.  Should have at LEAST one avp */
1085   if (pktLength < MIN_DIAMETER_SIZE) {
1086         g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1087                           pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1088         BadPacket = TRUE;
1089   }
1090
1091   /* And, check our reserved flags/version */
1092   if ((flags & DIAM_FLAGS_RESERVED) ||
1093           (version != 1)) {
1094         g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1095                           flags, version);
1096         BadPacket = TRUE;
1097   }
1098
1099   if (check_col(pinfo->cinfo, COL_INFO)) {
1100         col_add_fstr(pinfo->cinfo, COL_INFO,
1101                                  "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1102                                  (BadPacket)?"***** Bad Packet!: ":"",
1103                                  (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1104                                  (flags & DIAM_FLAGS_E)?" Error":"",
1105                                  ((BadPacket ||
1106                                    (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1107                                    ": " : ""),
1108                                  commandString, vendorName,
1109                                  dh.hopByHopId, dh.endToEndId,
1110                                  (flags & DIAM_FLAGS_R)?1:0,
1111                                  (flags & DIAM_FLAGS_P)?1:0,
1112                                  (flags & DIAM_FLAGS_E)?1:0);
1113   }
1114
1115
1116   /* In the interest of speed, if "tree" is NULL, don't do any work not
1117          necessary to generate protocol tree items. */
1118   if (tree) {
1119
1120         /* create display subtree for the protocol */
1121         ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1122                                                          MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1123         diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1124
1125         /* Version */
1126         proto_tree_add_uint(diameter_tree,
1127                                                 hf_diameter_version,
1128                                                 tvb, offset, 1,
1129                                                 version);
1130
1131         offset+=1;
1132
1133         /* Length */
1134         proto_tree_add_uint(diameter_tree,
1135                                                 hf_diameter_length, tvb,
1136                                                 offset, 3, pktLength);
1137         offset += 3;
1138
1139         /* Flags */
1140         tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1141                                                                         offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1142                                                                         flagstr);
1143         flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1144         proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1145         proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1146         proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1147         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1148         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1149         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1150         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1151         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1152
1153         offset += 1;
1154
1155         /* Command Code */
1156         proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1157                                                            tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1158         offset += 3;
1159
1160         /* Vendor Id */
1161         proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1162                                                            tvb, offset, 4,      dh.vendorId, "Vendor-Id: %s", vendorName);
1163         offset += 4;
1164
1165         /* Hop-by-hop Identifier */
1166         proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1167                                                 tvb, offset, 4, dh.hopByHopId);
1168         offset += 4;
1169
1170         /* End-to-end Identifier */
1171         proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1172                                                 tvb, offset, 4, dh.endToEndId);
1173         offset += 4;
1174
1175         /* If we have a bad packet, don't bother trying to parse the AVPs */
1176         if (BadPacket) {
1177           return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1178         }
1179
1180         /* Start looking at the AVPS */
1181         /* Make the next tvbuff */
1182
1183         /* Update the lengths */
1184         avplength= pktLength - sizeof(e_diameterhdr);
1185
1186         avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1187         avptf = proto_tree_add_text(diameter_tree,
1188                                                                 tvb, offset, avplength,
1189                                                                 "Attribute Value Pairs");
1190
1191         avp_tree = proto_item_add_subtree(avptf,
1192                                                                           ett_diameter_avp);
1193         if (avp_tree != NULL) {
1194           dissect_avps( avp_tvb, pinfo, avp_tree);
1195         }
1196         return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1197   }
1198   return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1199
1200 } /* dissect_diameter_common */
1201
1202 static void
1203 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1204 {
1205         dissect_diameter_common(tvb, 0, pinfo, tree);
1206 }
1207
1208 static void
1209 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1210 {
1211         size_t offset = 0;
1212         guint32 plen;
1213         guint32 available_bytes;
1214 /*      guint32 noffset; */
1215
1216         /* Loop through the packet, dissecting multiple diameter messages */
1217         do {
1218                 available_bytes = tvb_length_remaining(tvb, offset);
1219                 if (available_bytes < 4) {
1220                         g_warning("Diameter:  Bailing because only %d bytes of packet are available",
1221                                           available_bytes);
1222                         return; /* Bail.  We can't even get our length */
1223                 }
1224
1225                 /* get our packet length */
1226                 plen = tvb_get_ntohl(tvb, offset);
1227                 plen &= 0x00ffffff; /* get rid of the flags */
1228
1229                 /*Desegmentation */
1230                 if (gbl_diameter_desegment) {
1231                         if (pinfo->can_desegment
1232                                 && plen > available_bytes) {
1233                                 pinfo->desegment_offset = offset;
1234                                 pinfo->desegment_len = plen - available_bytes;
1235 /*                              g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1236 /*                                                plen, available_bytes); */
1237                                 return;
1238                         }
1239                 }
1240
1241                 /* Otherwise, dissect our packet */
1242                 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1243
1244 /*              g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1245 /*                                offset, noffset, tvb_length(tvb), available_bytes, plen); */
1246 /*              offset=noffset; */
1247         } while (offset < tvb_reported_length(tvb));
1248
1249 } /* dissect_diameter_tcp */
1250
1251 /*
1252  * Call the mip_dissector, after saving our pinfo variables
1253  * so it doesn't write to our column display.
1254  */
1255 static void
1256 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1257                                  size_t offset, size_t length)
1258 {
1259   static dissector_handle_t mip_handle;
1260   static int mipInitialized=FALSE;
1261   tvbuff_t *mip_tvb;
1262   address save_dl_src;
1263   address save_dl_dst;
1264   address save_net_src;
1265   address save_net_dst;
1266   address save_src;
1267   address save_dst;
1268   gboolean save_in_error_pkt;
1269
1270   if (!mipInitialized) {
1271         mip_handle = find_dissector("mip");
1272         mipInitialized=TRUE;
1273   }
1274
1275   mip_tvb = tvb_new_subset(tvb, offset,
1276                                                    MIN(length, tvb_length(tvb)-offset),
1277                                                    length);
1278
1279   /* The contained packet is a MIP registration request;
1280          dissect it with the MIP dissector. */
1281   col_set_writable(pinfo->cinfo, FALSE);
1282
1283   /* Also, save the current values of the addresses, and restore
1284          them when we're finished dissecting the contained packet, so
1285          that the address columns in the summary don't reflect the
1286          contained packet, but reflect this packet instead. */
1287   save_dl_src = pinfo->dl_src;
1288   save_dl_dst = pinfo->dl_dst;
1289   save_net_src = pinfo->net_src;
1290   save_net_dst = pinfo->net_dst;
1291   save_src = pinfo->src;
1292   save_dst = pinfo->dst;
1293   save_in_error_pkt = pinfo->in_error_pkt;
1294
1295   call_dissector(mip_handle, mip_tvb, pinfo, tree);
1296
1297   /* Restore the "we're inside an error packet" flag. */
1298   pinfo->in_error_pkt = save_in_error_pkt;
1299   pinfo->dl_src = save_dl_src;
1300   pinfo->dl_dst = save_dl_dst;
1301   pinfo->net_src = save_net_src;
1302   pinfo->net_dst = save_net_dst;
1303   pinfo->src = save_src;
1304   pinfo->dst = save_dst;
1305
1306
1307 } /* safe_dissect_mip */
1308
1309 /*
1310  * This function will dissect the AVPs in a diameter packet.  It handles
1311  * all normal types, and even recursively calls itself for grouped AVPs
1312  */
1313 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1314 {
1315   /* adds the attribute value pairs to the tree */
1316   e_avphdr avph;
1317   gchar avpTypeString[64];
1318   gchar avpNameString[64];
1319   gchar *valstr;
1320   guint32 vendorId=0;
1321   gchar    vendorName[64];
1322   int hdrLength;
1323   int fixAmt;
1324   proto_tree *avpi_tree;
1325   size_t offset = 0;
1326   tvbuff_t        *group_tvb;
1327   proto_tree *group_tree;
1328   proto_item *grouptf;
1329   proto_item *avptf;
1330   char buffer[1024];
1331   int BadPacket = FALSE;
1332   guint32 avpLength;
1333   guint8 flags;
1334   proto_item      *tf;
1335   proto_tree      *flags_tree;
1336
1337   gint32 packetLength;
1338   size_t avpDataLength;
1339   int avpType;
1340   gchar flagstr[64] = "<None>";
1341   gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1342   gint        i;
1343   guint      bpos;
1344
1345   packetLength = tvb_length(tvb);
1346
1347   /* Check for invalid packet lengths */
1348   if (packetLength <= 0) {
1349         proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1350                                                 "No Attribute Value Pairs Found");
1351         return;
1352   }
1353
1354   /* Spin around until we run out of packet */
1355   while (packetLength > 0 ) {
1356
1357         /* Check for short packet */
1358         if (packetLength < (long)MIN_AVP_SIZE) {
1359           g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1360                                 packetLength, (long)MIN_AVP_SIZE);
1361           BadPacket = TRUE;
1362           /* Don't even bother trying to parse a short packet. */
1363           return;
1364         }
1365
1366         /* Copy our header */
1367         tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1368
1369         /* Fix the byte ordering */
1370         avph.avp_code = g_ntohl(avph.avp_code);
1371         avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1372
1373         flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1374         avpLength = avph.avp_flagsLength & 0x00ffffff;
1375
1376         /* Set up our flags string */
1377         if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1378           flagstr[0]=0;
1379           for (i = 0; i < 8; i++) {
1380                 bpos = 1 << i;
1381                 if (flags & bpos) {
1382                   if (flagstr[0]) {
1383                         strcat(flagstr, ", ");
1384                   }
1385                   strcat(flagstr, fstr[i]);
1386                 }
1387           }
1388           if (strlen(flagstr) == 0) {
1389                 strcpy(flagstr,"<None>");
1390           }
1391         }
1392
1393         /* Dissect our vendor id if it exists  and set hdr length */
1394         if (flags & AVP_FLAGS_V) {
1395           vendorId = g_ntohl(avph.avp_vendorId);
1396           /* Vendor id */
1397           hdrLength = sizeof(e_avphdr);
1398         } else {
1399           /* No vendor */
1400           hdrLength = sizeof(e_avphdr) -
1401                 sizeof(guint32);
1402           vendorId = 0;
1403         }
1404
1405         if (vendorId) {
1406           strcpy(vendorName,
1407                          diameter_vendor_to_str(vendorId, TRUE));
1408         } else {
1409           vendorName[0]='\0';
1410         }
1411
1412         /* Check for bad length */
1413         if (avpLength < MIN_AVP_SIZE ||
1414                 ((long)avpLength > packetLength)) {
1415           g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes,  "
1416                                 "min: %ld bytes,    packetLen: %d",
1417                                 (long)avpLength, (long)MIN_AVP_SIZE,
1418                                 packetLength);
1419           BadPacket = TRUE;
1420         }
1421
1422         /* Check for bad flags */
1423         if (flags & AVP_FLAGS_RESERVED) {
1424           g_warning("Diameter: Invalid AVP: Reserved bit set.  flags = 0x%x,"
1425                                 " resFl=0x%x",
1426                                 flags, AVP_FLAGS_RESERVED);
1427           /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1428           /* BadPacket = TRUE; */
1429         }
1430
1431         /*
1432          * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1433          * boundries)
1434          */
1435         fixAmt = 4 - (avpLength % 4);
1436         if (fixAmt == 4) fixAmt = 0;
1437
1438         /* shrink our packetLength */
1439         packetLength = packetLength - (avpLength + fixAmt);
1440
1441         /* Check for out of bounds */
1442         if (packetLength < 0) {
1443           g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1444                                 packetLength);
1445           BadPacket = TRUE;
1446         }
1447
1448         /* Make avp Name & type */
1449         strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1450                                                                          TypeValues,
1451                                                                          "Unknown-Type: 0x%08x"));
1452         strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1453
1454         avptf = proto_tree_add_text(avp_tree, tvb,
1455                                                                 offset, avpLength + fixAmt,
1456                                                                 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1457                                                                 avpNameString, avpTypeString, avpLength,
1458                                                                 avpLength, avpLength+fixAmt);
1459         avpi_tree = proto_item_add_subtree(avptf,
1460                                                                            ett_diameter_avpinfo);
1461
1462         if (avpi_tree !=NULL) {
1463           /* Command Code */
1464           proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1465                                                                  tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1466           offset += 4;
1467
1468           tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1469                                                                           offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1470                                                                           flagstr);
1471           flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1472           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1473           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1474           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1475           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3,  tvb, offset, 1, flags);
1476           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4,  tvb, offset, 1, flags);
1477           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5,  tvb, offset, 1, flags);
1478           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6,  tvb, offset, 1, flags);
1479           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7,  tvb, offset, 1, flags);
1480           offset += 1;
1481
1482           proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1483                                                   tvb, offset, 3, avpLength);
1484           offset += 3;
1485
1486           if (flags & AVP_FLAGS_V) {
1487                 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1488                                                                    tvb, offset, 4, vendorId, vendorName);
1489                 offset += 4;
1490           }
1491
1492           avpDataLength = avpLength - hdrLength;
1493
1494           /*
1495            * If we've got a bad packet, just highlight the data.  Don't try
1496            * to parse it, and, don't move to next AVP.
1497            */
1498           if (BadPacket) {
1499                 offset -= hdrLength;
1500                 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1501                                         tvb, offset, tvb_length(tvb) - offset,
1502                                         tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1503                                         "Bad AVP (Suspect Data Not Dissected)");
1504                 return;
1505           }
1506
1507           avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1508
1509           switch(avpType) {
1510           case DIAMETER_GROUPED:
1511                 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1512                 /* Recursively call ourselves */
1513                 grouptf = proto_tree_add_text(avpi_tree,
1514                                                                           tvb, offset, tvb_length(tvb),
1515                                                                           buffer);
1516
1517                 group_tree = proto_item_add_subtree(grouptf,
1518                                                                                         ett_diameter_avp);
1519
1520                 group_tvb = tvb_new_subset(tvb, offset,
1521                                                                    MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1522                 if (group_tree != NULL) {
1523                   dissect_avps( group_tvb, pinfo, group_tree);
1524                 }
1525                 break;
1526
1527           case DIAMETER_IDENTITY:
1528                 {
1529                   const guint8 *data;
1530
1531                   data = tvb_get_ptr(tvb, offset, avpDataLength);
1532                   proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1533                                                tvb, offset, avpDataLength, data,
1534                                                "Identity: %*.*s",
1535                                                (int)avpDataLength,
1536                                                (int)avpDataLength, data);
1537                 }
1538                 break;
1539           case DIAMETER_UTF8STRING:
1540                 {
1541                   const guint8 *data;
1542
1543                   data = tvb_get_ptr(tvb, offset, avpDataLength);
1544                   proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1545                                                tvb, offset, avpDataLength, data,
1546                                                "UTF8String: %*.*s",
1547                                                (int)avpDataLength,
1548                                                (int)avpDataLength, data);
1549                 }
1550                 break;
1551           case DIAMETER_IP_ADDRESS:
1552                 if (avpDataLength == 4) {
1553                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1554                                       tvb, offset, avpDataLength, FALSE);
1555                 } else if (avpDataLength == 16) {
1556                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1557                                       tvb, offset, avpDataLength, FALSE);
1558                 } else {
1559                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1560                                               tvb, offset, avpDataLength,
1561                                               tvb_get_ptr(tvb, offset, avpDataLength),
1562                                               "Error!  Bad Address Length");
1563                 }
1564                 break;
1565
1566           case DIAMETER_INTEGER32:
1567                 if (avpDataLength == 4) {
1568                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1569                                       tvb, offset, avpDataLength, FALSE);
1570                 } else {
1571                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1572                                               tvb, offset, avpDataLength,
1573                                               tvb_get_ptr(tvb, offset, avpDataLength),
1574                                               "Error!  Bad Integer32 Length");
1575                 }
1576                 break;
1577
1578           case DIAMETER_UNSIGNED32:
1579                 if (avpDataLength == 4) {
1580                   guint32 data;
1581
1582                   data = tvb_get_ntohl(tvb, offset);
1583                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1584                                              tvb, offset, avpDataLength, data,
1585                                              "Value: 0x%08x (%u)", data, data);
1586                 } else {
1587                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1588                                               tvb, offset, avpDataLength,
1589                                               tvb_get_ptr(tvb, offset, avpDataLength),
1590                                               "Error!  Bad Unsigned32 Length");
1591                 }
1592                 break;
1593
1594           case DIAMETER_INTEGER64:
1595                 if (avpDataLength == 8) {
1596                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1597                                       tvb, offset, 8, FALSE);
1598                 } else {
1599                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1600                                               tvb, offset, avpDataLength,
1601                                               tvb_get_ptr(tvb, offset, avpDataLength),
1602                                               "Error!  Bad Integer64 Length");
1603                 }
1604                 break;
1605
1606           case DIAMETER_UNSIGNED64:
1607                 if (avpDataLength == 8) {
1608                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1609                                       tvb, offset, 8, FALSE);
1610                 } else {
1611                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1612                                               tvb, offset, avpDataLength,
1613                                               tvb_get_ptr(tvb, offset, avpDataLength),
1614                                               "Error!  Bad Unsigned64 Length");
1615                 }
1616                 break;
1617
1618           case DIAMETER_TIME:
1619                 if (avpDataLength == 4) {
1620                   nstime_t data;
1621                   gchar buffer[64];
1622                   struct tm *ltp;
1623
1624                   data.secs = tvb_get_ntohl(tvb, offset);
1625                   data.secs -= NTP_TIME_DIFF;
1626                   data.nsecs = 0;
1627
1628                   ltp = localtime(&data.secs);
1629                   strftime(buffer, 64,
1630                            "%a, %d %b %Y %H:%M:%S %z", ltp);
1631
1632                   proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1633                                              tvb, offset, avpDataLength, &data,
1634                                              "Time: %s", buffer);
1635                 } else {
1636                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1637                                               tvb, offset, avpDataLength,
1638                                               tvb_get_ptr(tvb, offset, avpDataLength),
1639                                               "Error!  Bad Time Length");
1640                 }
1641                 break;
1642
1643           case DIAMETER_ENUMERATED:
1644                 if (avpDataLength == 4) {
1645                   guint32 data;
1646
1647                   data = tvb_get_ntohl(tvb, offset);
1648                   valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1649                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1650                                              tvb, offset, avpDataLength, data,
1651                                              "Value: 0x%08x (%u): %s", data,
1652                                              data, valstr);
1653                 } else {
1654                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1655                                               tvb, offset, avpDataLength,
1656                                               tvb_get_ptr(tvb, offset, avpDataLength),
1657                                               "Error!  Bad Enumerated Length");
1658                 }
1659                 break;
1660           case DIAMETER_VENDOR_ID:
1661                 if (avpDataLength == 4) {
1662                   guint32 data;
1663
1664                   data = tvb_get_ntohl(tvb, offset);
1665                   valstr = diameter_vendor_to_str(data, TRUE);
1666                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1667                                              tvb, offset, avpDataLength, data,
1668                                              "Vendor ID: %s (0x%08x)", valstr,
1669                                              data);
1670                 } else {
1671                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1672                                               tvb, offset, avpDataLength,
1673                                               tvb_get_ptr(tvb, offset, avpDataLength),
1674                                               "Error!  Bad Vendor ID Length");
1675                 }
1676                 break;
1677           case DIAMETER_APPLICATION_ID:
1678                 if (avpDataLength == 4) {
1679                   guint32 data;
1680
1681                   data = tvb_get_ntohl(tvb, offset);
1682                   valstr = diameter_app_to_str(data);
1683                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1684                                              tvb, offset, avpDataLength, data,
1685                                              "Application ID: %s (0x%08x)",
1686                                              valstr, data);
1687                 } else {
1688                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1689                                               tvb, offset, avpDataLength,
1690                                               tvb_get_ptr(tvb, offset, avpDataLength),
1691                                               "Error!  Bad Application ID Length");
1692                 }
1693                 break;
1694           case DIAMETER_MIP_REG_REQ:
1695                 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1696                 break;
1697
1698           default:
1699           case DIAMETER_OCTET_STRING:
1700                 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1701                                             tvb, offset, avpDataLength,
1702                                             tvb_get_ptr(tvb, offset, avpDataLength),
1703                                            "Hex Data Highlighted Below");
1704                 break;
1705
1706           } /* switch type */
1707         } /* avpi_tree != null */
1708         offset += (avpLength - hdrLength);
1709         offset += fixAmt; /* fix byte alignment */
1710   } /* loop */
1711 } /* dissect_avps */
1712
1713
1714
1715 void
1716 proto_reg_handoff_diameter(void)
1717 {
1718   static int Initialized=FALSE;
1719   static int TcpPort=0;
1720   static int SctpPort=0;
1721   static dissector_handle_t diameter_tcp_handle;
1722   static dissector_handle_t diameter_sctp_handle;
1723
1724   if (!Initialized) {
1725         diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1726             proto_diameter);
1727         diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1728             proto_diameter);
1729         Initialized=TRUE;
1730   } else {
1731         dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1732         dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1733   }
1734
1735   /* set port for future deletes */
1736   TcpPort=gbl_diameterTcpPort;
1737   SctpPort=gbl_diameterSctpPort;
1738
1739   /* g_warning ("Diameter: Adding tcp dissector to port %d",
1740          gbl_diameterTcpPort); */
1741   dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1742   dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1743 }
1744
1745 /* registration with the filtering engine */
1746 void
1747 proto_register_diameter(void)
1748 {
1749         static hf_register_info hf[] = {
1750                 { &hf_diameter_version,
1751                   { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1752                     "", HFILL }},
1753                 { &hf_diameter_length,
1754                   { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1755                     "", HFILL }},
1756
1757                 { &hf_diameter_flags,
1758                   { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1759                     "", HFILL }},
1760                 { &hf_diameter_flags_request,
1761                   { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1762                         "", HFILL }},
1763                 { &hf_diameter_flags_proxyable,
1764                   { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1765                         "", HFILL }},
1766                 { &hf_diameter_flags_error,
1767                   { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1768                         "", HFILL }},
1769                 { &hf_diameter_flags_reserved3,
1770                   { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1771                         DIAM_FLAGS_RESERVED3, "", HFILL }},
1772                 { &hf_diameter_flags_reserved4,
1773                   { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1774                         DIAM_FLAGS_RESERVED4, "", HFILL }},
1775                 { &hf_diameter_flags_reserved5,
1776                   { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1777                         DIAM_FLAGS_RESERVED5, "", HFILL }},
1778                 { &hf_diameter_flags_reserved6,
1779                   { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1780                         DIAM_FLAGS_RESERVED6, "", HFILL }},
1781                 { &hf_diameter_flags_reserved7,
1782                   { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1783                         DIAM_FLAGS_RESERVED7, "", HFILL }},
1784
1785                 { &hf_diameter_code,
1786                   { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1787                     NULL, 0x0, "", HFILL }},
1788                 { &hf_diameter_vendor_id,
1789                   { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1790                         0x0,"", HFILL }},
1791                 { &hf_diameter_hopbyhopid,
1792                   { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1793                     BASE_HEX, NULL, 0x0, "", HFILL }},
1794                 { &hf_diameter_endtoendid,
1795                   { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1796                     BASE_HEX, NULL, 0x0, "", HFILL }},
1797
1798                 { &hf_diameter_avp_code,
1799                   { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1800                     NULL, 0x0, "", HFILL }},
1801                 { &hf_diameter_avp_length,
1802                   { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1803                     NULL, 0x0, "", HFILL }},
1804
1805
1806                 { &hf_diameter_avp_flags,
1807                   { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1808                     NULL, 0x0, "", HFILL }},
1809                 { &hf_diameter_avp_flags_vendor_specific,
1810                   { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1811                         "", HFILL }},
1812                 { &hf_diameter_avp_flags_mandatory,
1813                   { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1814                         "", HFILL }},
1815                 { &hf_diameter_avp_flags_protected,
1816                   { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1817                         "", HFILL }},
1818                 { &hf_diameter_avp_flags_reserved3,
1819                   { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1820                         AVP_FLAGS_RESERVED3,    "", HFILL }},
1821                 { &hf_diameter_avp_flags_reserved4,
1822                   { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1823                         AVP_FLAGS_RESERVED4,    "", HFILL }},
1824                 { &hf_diameter_avp_flags_reserved5,
1825                   { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1826                         AVP_FLAGS_RESERVED5,    "", HFILL }},
1827                 { &hf_diameter_avp_flags_reserved6,
1828                   { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1829                         AVP_FLAGS_RESERVED6,    "", HFILL }},
1830                 { &hf_diameter_avp_flags_reserved7,
1831                   { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1832                         AVP_FLAGS_RESERVED7,    "", HFILL }},
1833                 { &hf_diameter_avp_vendor_id,
1834                   { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1835                     NULL, 0x0, "", HFILL }},
1836                 { &hf_diameter_avp_data_uint64,
1837                   { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1838                     NULL, 0x0, "", HFILL }},
1839                 { &hf_diameter_avp_data_int64,
1840                   { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1841                     NULL, 0x0, "", HFILL }},
1842                 { &hf_diameter_avp_data_uint32,
1843                   { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1844                     NULL, 0x0, "", HFILL }},
1845                 { &hf_diameter_avp_data_int32,
1846                   { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1847                     NULL, 0x0, "", HFILL }},
1848                 { &hf_diameter_avp_data_bytes,
1849                   { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1850                     NULL, 0x0, "", HFILL }},
1851                 { &hf_diameter_avp_data_string,
1852                   { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1853                     NULL, 0x0, "", HFILL }},
1854                 { &hf_diameter_avp_data_v4addr,
1855                   { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1856                     NULL, 0x0, "", HFILL }},
1857                 { &hf_diameter_avp_data_v6addr,
1858                   { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1859                     NULL, 0x0, "", HFILL }},
1860                 { &hf_diameter_avp_data_time,
1861                   { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1862                     NULL, 0x0, "", HFILL }},
1863
1864         };
1865         static gint *ett[] = {
1866                 &ett_diameter,
1867                 &ett_diameter_flags,
1868                 &ett_diameter_avp,
1869                 &ett_diameter_avp_flags,
1870                 &ett_diameter_avpinfo
1871         };
1872         module_t *diameter_module;
1873         gchar *default_diameterDictionary;
1874
1875         proto_diameter = proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
1876         proto_register_field_array(proto_diameter, hf, array_length(hf));
1877         proto_register_subtree_array(ett, array_length(ett));
1878
1879         /* Register a configuration option for port */
1880         diameter_module = prefs_register_protocol(proto_diameter,
1881                                                                                           proto_reg_handoff_diameter);
1882         prefs_register_uint_preference(diameter_module, "tcp.port",
1883                                                                    "Diameter TCP Port",
1884                                                                    "Set the TCP port for Diameter messages",
1885                                                                    10,
1886                                                                    &gbl_diameterTcpPort);
1887         prefs_register_uint_preference(diameter_module, "sctp.port",
1888                                                                    "Diameter SCTP Port",
1889                                                                    "Set the SCTP port for Diameter messages",
1890                                                                    10,
1891                                                                    &gbl_diameterSctpPort);
1892         /*
1893          * Build our default dictionary filename
1894          */
1895         default_diameterDictionary = get_datafile_path(DICT_FN);
1896
1897         /*
1898          * Now register the dictionary filename as a preference,
1899          * so it can be changed.
1900          */
1901         gbl_diameterDictionary = default_diameterDictionary;
1902         prefs_register_string_preference(diameter_module, "dictionary.name",
1903                                                                          "Diameter XML Dictionary",
1904                                                                          "Set the dictionary used for Diameter messages",
1905                                                                          &gbl_diameterDictionary);
1906
1907         /*
1908          * We don't need the default dictionary, so free it (a copy was made
1909          * of it in "gbl_diameterDictionary" by
1910          * "prefs_register_string_preference()").
1911          */
1912         g_free(default_diameterDictionary);
1913
1914         /* Desegmentation */
1915         prefs_register_bool_preference(diameter_module, "desegment",
1916                                                                    "Desegment all Diameter messages spanning multiple TCP segments",
1917                                                                    "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1918                                                                    &gbl_diameter_desegment);
1919
1920         /* Register some preferences we no longer support, so we can report
1921            them as obsolete rather than just illegal. */
1922         prefs_register_obsolete_preference(diameter_module, "udp.port");
1923         prefs_register_obsolete_preference(diameter_module, "command_in_header");
1924 } /* proto_register_diameter */