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