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