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