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