Don't copy the AVP data to a buffer from the tvbuff and then extract
[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.44 2002/01/31 01:55:14 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
1006 /* Code to actually dissect the packets */
1007
1008 /*
1009  * Main dissector
1010  */
1011 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
1012                                                                            proto_tree *tree)
1013 {
1014
1015   /* Set up structures needed to add the protocol subtree and manage it */
1016   proto_item      *ti;
1017   proto_item      *tf;
1018   proto_tree      *flags_tree;
1019   tvbuff_t        *avp_tvb;
1020   proto_tree      *diameter_tree;
1021   e_diameterhdr    dh;
1022   size_t           offset=0;
1023   size_t           avplength;
1024   proto_tree      *avp_tree;
1025   proto_item      *avptf;
1026   int              BadPacket = FALSE;
1027   guint32          commandCode, pktLength;
1028   guint8           version, flags;
1029   gchar            flagstr[64] = "<None>";
1030   gchar           *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1031   gchar            commandString[64], vendorName[64];
1032   gint        i;
1033   guint      bpos;
1034   static  int initialized=FALSE;
1035
1036   /* set our offset */
1037   offset=start;
1038
1039   /*
1040    * Only parse in dictionary if there are diameter packets to
1041    * dissect.
1042    */
1043   if (!initialized) {
1044           /* Read in our dictionary, if it exists. */
1045           initializeDictionary();
1046           initialized=TRUE;
1047   }
1048         
1049   /* Make entries in Protocol column and Info column on summary display */
1050   if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
1051         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1052   if (check_col(pinfo->cinfo, COL_INFO)) 
1053         col_clear(pinfo->cinfo, COL_INFO);
1054         
1055   /* Copy our header */
1056   tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1057         
1058   /* Fix byte ordering in our static structure */
1059   dh.versionLength = ntohl(dh.versionLength);
1060   dh.flagsCmdCode = ntohl(dh.flagsCmdCode);
1061   dh.vendorId = ntohl(dh.vendorId);
1062   dh.hopByHopId = ntohl(dh.hopByHopId);
1063   dh.endToEndId = ntohl(dh.endToEndId);
1064
1065   if (dh.vendorId) {
1066         strcpy(vendorName, 
1067                    diameter_vendor_to_str(dh.vendorId, TRUE));
1068   } else {
1069         strcpy(vendorName, "None");
1070   }
1071
1072
1073   /* Do the bit twiddling */
1074   version = DIAM_GET_VERSION(dh);
1075   pktLength = DIAM_GET_LENGTH(dh);
1076   flags = DIAM_GET_FLAGS(dh);
1077   commandCode = DIAM_GET_COMMAND(dh);
1078
1079   /* Set up our flags */
1080   if (check_col(pinfo->cinfo, COL_INFO) || tree) {  
1081         flagstr[0]=0;
1082         for (i = 0; i < 8; i++) {
1083           bpos = 1 << i;
1084           if (flags & bpos) {
1085                 if (flagstr[0]) {
1086                   strcat(flagstr, ", ");
1087                 }
1088                 strcat(flagstr, fstr[i]);
1089           }
1090         }
1091         if (strlen(flagstr) == 0) {
1092           strcpy(flagstr,"<None>");
1093         }
1094   }
1095   
1096   /* Set up our commandString */
1097   strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1098   if (flags & DIAM_FLAGS_R) 
1099         strcat(commandString, "-Request");
1100   else
1101         strcat(commandString, "-Answer");
1102
1103   /* Short packet.  Should have at LEAST one avp */
1104   if (pktLength < MIN_DIAMETER_SIZE) {
1105         g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1106                           pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1107         BadPacket = TRUE;
1108   }
1109
1110   /* And, check our reserved flags/version */
1111   if ((flags & DIAM_FLAGS_RESERVED) ||
1112           (version != 1)) {
1113         g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1114                           flags, version);
1115         BadPacket = TRUE;
1116   }
1117
1118   if (check_col(pinfo->cinfo, COL_INFO)) {
1119         col_add_fstr(pinfo->cinfo, COL_INFO,
1120                                  "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1121                                  (BadPacket)?"***** Bad Packet!: ":"",
1122                                  (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1123                                  (flags & DIAM_FLAGS_E)?" Error":"",
1124                                  ((BadPacket ||
1125                                    (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1126                                    ": " : ""),
1127                                  commandString, vendorName,
1128                                  dh.hopByHopId, dh.endToEndId,
1129                                  (flags & DIAM_FLAGS_R)?1:0,
1130                                  (flags & DIAM_FLAGS_P)?1:0,
1131                                  (flags & DIAM_FLAGS_E)?1:0);
1132   }
1133         
1134
1135   /* In the interest of speed, if "tree" is NULL, don't do any work not
1136          necessary to generate protocol tree items. */
1137   if (tree) {
1138
1139         /* create display subtree for the protocol */
1140         ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1141                                                          MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1142         diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1143
1144         /* Version */
1145         proto_tree_add_uint(diameter_tree,
1146                                                 hf_diameter_version,
1147                                                 tvb, offset, 1,
1148                                                 version);
1149
1150         offset+=1;
1151
1152         /* Length */
1153         proto_tree_add_uint(diameter_tree,
1154                                                 hf_diameter_length, tvb,
1155                                                 offset, 3, pktLength);
1156         offset += 3;
1157
1158         /* Flags */
1159         tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1160                                                                         offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1161                                                                         flagstr);
1162         flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1163         proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1164         proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1165         proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1166         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1167         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1168         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1169         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1170         proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1171
1172         offset += 1;
1173
1174         /* Command Code */
1175         proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1176                                                            tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1177         offset += 3;
1178
1179         /* Vendor Id */
1180         proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1181                                                            tvb, offset, 4,      dh.vendorId, "Vendor-Id: %s", vendorName);
1182         offset += 4;
1183
1184         /* Hop-by-hop Identifier */
1185         proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1186                                                 tvb, offset, 4, dh.hopByHopId);
1187         offset += 4;
1188
1189         /* End-to-end Identifier */
1190         proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1191                                                 tvb, offset, 4, dh.endToEndId);
1192         offset += 4;
1193
1194         /* If we have a bad packet, don't bother trying to parse the AVPs */
1195         if (BadPacket) {
1196           return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1197         }
1198
1199         /* Start looking at the AVPS */
1200         /* Make the next tvbuff */
1201
1202         /* Update the lengths */
1203         avplength= pktLength - sizeof(e_diameterhdr);
1204     
1205         avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1206         avptf = proto_tree_add_text(diameter_tree,
1207                                                                 tvb, offset, avplength,
1208                                                                 "Attribute Value Pairs");
1209                 
1210         avp_tree = proto_item_add_subtree(avptf,
1211                                                                           ett_diameter_avp);
1212         if (avp_tree != NULL) {
1213           dissect_avps( avp_tvb, pinfo, avp_tree);
1214         }
1215         return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1216   }
1217   return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1218
1219 } /* dissect_diameter_common */
1220
1221 static void
1222 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1223 {
1224         dissect_diameter_common(tvb, 0, pinfo, tree);
1225 }
1226
1227 static void
1228 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1229 {
1230         size_t offset = 0;
1231         guint32 plen;
1232         guint32 available_bytes;
1233 /*      guint32 noffset; */
1234         
1235         /* Loop through the packet, dissecting multiple diameter messages */
1236         do {
1237                 available_bytes = tvb_length_remaining(tvb, offset);
1238                 if (available_bytes < 4) {
1239                         g_warning("Diameter:  Bailing because only %d bytes of packet are available",
1240                                           available_bytes);
1241                         return; /* Bail.  We can't even get our length */
1242                 }
1243
1244                 /* get our packet length */
1245                 plen = tvb_get_ntohl(tvb, offset);
1246                 plen &= 0x00ffffff; /* get rid of the flags */
1247
1248                 /*Desegmentation */
1249                 if (gbl_diameter_desegment) {
1250                         if (pinfo->can_desegment
1251                                 && plen > available_bytes) {
1252                                 pinfo->desegment_offset = offset;
1253                                 pinfo->desegment_len = plen - available_bytes;
1254 /*                              g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1255 /*                                                plen, available_bytes); */
1256                                 return;
1257                         }
1258                 }
1259         
1260                 /* Otherwise, dissect our packet */
1261                 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1262
1263 /*              g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1264 /*                                offset, noffset, tvb_length(tvb), available_bytes, plen); */
1265 /*              offset=noffset; */
1266         } while (offset < tvb_reported_length(tvb));
1267
1268 } /* dissect_diameter_tcp */
1269
1270 /*
1271  * Call the mip_dissector, after saving our pinfo variables
1272  * so it doesn't write to our column display.
1273  */
1274 static void
1275 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1276                                  size_t offset, size_t length)
1277 {
1278   static dissector_handle_t mip_handle;
1279   static int mipInitialized=FALSE;
1280   tvbuff_t *mip_tvb;
1281   address save_dl_src;
1282   address save_dl_dst;
1283   address save_net_src;
1284   address save_net_dst;
1285   address save_src;
1286   address save_dst;
1287   gboolean save_in_error_pkt;
1288
1289   if (!mipInitialized) {
1290         mip_handle = find_dissector("mip");
1291         mipInitialized=TRUE;
1292   }
1293
1294   mip_tvb = tvb_new_subset(tvb, offset,
1295                                                    MIN(length, tvb_length(tvb)-offset),
1296                                                    length);
1297         
1298   /* The contained packet is a MIP registration request;
1299          dissect it with the MIP dissector. */
1300   col_set_writable(pinfo->cinfo, FALSE);
1301
1302   /* Also, save the current values of the addresses, and restore
1303          them when we're finished dissecting the contained packet, so
1304          that the address columns in the summary don't reflect the
1305          contained packet, but reflect this packet instead. */
1306   save_dl_src = pinfo->dl_src;
1307   save_dl_dst = pinfo->dl_dst;
1308   save_net_src = pinfo->net_src;
1309   save_net_dst = pinfo->net_dst;
1310   save_src = pinfo->src;
1311   save_dst = pinfo->dst;
1312   save_in_error_pkt = pinfo->in_error_pkt;
1313
1314   call_dissector(mip_handle, mip_tvb, pinfo, tree);
1315
1316   /* Restore the "we're inside an error packet" flag. */
1317   pinfo->in_error_pkt = save_in_error_pkt;
1318   pinfo->dl_src = save_dl_src;
1319   pinfo->dl_dst = save_dl_dst;
1320   pinfo->net_src = save_net_src;
1321   pinfo->net_dst = save_net_dst;
1322   pinfo->src = save_src;
1323   pinfo->dst = save_dst;
1324
1325
1326 } /* safe_dissect_mip */
1327
1328 /*
1329  * This function will dissect the AVPs in a diameter packet.  It handles
1330  * all normal types, and even recursively calls itself for grouped AVPs
1331  */
1332 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1333 {
1334   /* adds the attribute value pairs to the tree */
1335   e_avphdr avph;
1336   gchar avpTypeString[64];
1337   gchar avpNameString[64];
1338   gchar *valstr;
1339   guint32 vendorId=0;
1340   gchar    vendorName[64];
1341   int hdrLength;
1342   int fixAmt;
1343   proto_tree *avpi_tree;
1344   size_t offset = 0;
1345   tvbuff_t        *group_tvb;
1346   proto_tree *group_tree;
1347   proto_item *grouptf;
1348   proto_item *avptf;
1349   char buffer[1024];
1350   int BadPacket = FALSE;
1351   guint32 avpLength;
1352   guint8 flags;
1353   proto_item      *tf;
1354   proto_tree      *flags_tree;
1355         
1356   gint32 packetLength;
1357   size_t avpDataLength;
1358   int avpType;
1359   gchar flagstr[64] = "<None>";
1360   gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1361   gint        i;
1362   guint      bpos;
1363
1364   packetLength = tvb_length(tvb);
1365
1366   /* Check for invalid packet lengths */
1367   if (packetLength <= 0) {
1368         proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1369                                                 "No Attribute Value Pairs Found");
1370         return;
1371   }
1372
1373   /* Spin around until we run out of packet */
1374   while (packetLength > 0 ) {
1375
1376         /* Check for short packet */
1377         if (packetLength < (long)MIN_AVP_SIZE) {
1378           g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1379                                 packetLength, (long)MIN_AVP_SIZE);
1380           BadPacket = TRUE;
1381           /* Don't even bother trying to parse a short packet. */
1382           return;
1383         }
1384         
1385         /* Copy our header */
1386         tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1387         
1388         /* Fix the byte ordering */
1389         avph.avp_code = ntohl(avph.avp_code);
1390         avph.avp_flagsLength = ntohl(avph.avp_flagsLength);
1391         
1392         flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1393         avpLength = avph.avp_flagsLength & 0x00ffffff;
1394         
1395         /* Set up our flags string */
1396         if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {  
1397           flagstr[0]=0;
1398           for (i = 0; i < 8; i++) {
1399                 bpos = 1 << i;
1400                 if (flags & bpos) {
1401                   if (flagstr[0]) {
1402                         strcat(flagstr, ", ");
1403                   }
1404                   strcat(flagstr, fstr[i]);
1405                 }
1406           }
1407           if (strlen(flagstr) == 0) {
1408                 strcpy(flagstr,"<None>");
1409           }
1410         }
1411
1412         /* Dissect our vendor id if it exists  and set hdr length */
1413         if (flags & AVP_FLAGS_V) {
1414           vendorId = ntohl(avph.avp_vendorId);
1415           /* Vendor id */
1416           hdrLength = sizeof(e_avphdr);
1417         } else {
1418           /* No vendor */
1419           hdrLength = sizeof(e_avphdr) - 
1420                 sizeof(guint32);
1421           vendorId = 0;
1422         }
1423
1424         if (vendorId) {
1425           strcpy(vendorName, 
1426                          diameter_vendor_to_str(vendorId, TRUE));
1427         } else {
1428           vendorName[0]='\0';
1429         }
1430
1431         /* Check for bad length */
1432         if (avpLength < MIN_AVP_SIZE || 
1433                 ((long)avpLength > packetLength)) {
1434           g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes,  "
1435                                 "min: %ld bytes,    packetLen: %d",
1436                                 (long)avpLength, (long)MIN_AVP_SIZE,
1437                                 packetLength);
1438           BadPacket = TRUE;
1439         }
1440
1441         /* Check for bad flags */
1442         if (flags & AVP_FLAGS_RESERVED) {
1443           g_warning("Diameter: Invalid AVP: Reserved bit set.  flags = 0x%x,"
1444                                 " resFl=0x%x",
1445                                 flags, AVP_FLAGS_RESERVED);
1446           /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1447           /* BadPacket = TRUE; */
1448         }
1449                 
1450         /*
1451          * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1452          * boundries)
1453          */
1454         fixAmt = 4 - (avpLength % 4);
1455         if (fixAmt == 4) fixAmt = 0;
1456         
1457         /* shrink our packetLength */
1458         packetLength = packetLength - (avpLength + fixAmt);
1459         
1460         /* Check for out of bounds */
1461         if (packetLength < 0) {
1462           g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1463                                 packetLength);
1464           BadPacket = TRUE;
1465         }
1466
1467         /* Make avp Name & type */
1468         strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1469                                                                          TypeValues, 
1470                                                                          "Unknown-Type: 0x%08x"));
1471         strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1472
1473         avptf = proto_tree_add_text(avp_tree, tvb,
1474                                                                 offset, avpLength + fixAmt,
1475                                                                 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1476                                                                 avpNameString, avpTypeString, avpLength,
1477                                                                 avpLength, avpLength+fixAmt);
1478         avpi_tree = proto_item_add_subtree(avptf,
1479                                                                            ett_diameter_avpinfo);
1480
1481         if (avpi_tree !=NULL) {
1482           /* Command Code */
1483           proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1484                                                                  tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1485           offset += 4;
1486                 
1487           tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1488                                                                           offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1489                                                                           flagstr);
1490           flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1491           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1492           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1493           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1494           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3,  tvb, offset, 1, flags);
1495           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4,  tvb, offset, 1, flags);
1496           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5,  tvb, offset, 1, flags);
1497           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6,  tvb, offset, 1, flags);
1498           proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7,  tvb, offset, 1, flags);
1499           offset += 1;
1500
1501           proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1502                                                   tvb, offset, 3, avpLength);
1503           offset += 3;
1504
1505           if (flags & AVP_FLAGS_V) {
1506                 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1507                                                                    tvb, offset, 4, vendorId, vendorName);
1508                 offset += 4;
1509           }
1510
1511           avpDataLength = avpLength - hdrLength;
1512
1513           /*
1514            * If we've got a bad packet, just highlight the data.  Don't try
1515            * to parse it, and, don't move to next AVP.
1516            */
1517           if (BadPacket) {
1518                 offset -= hdrLength;
1519                 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1520                                         tvb, offset, tvb_length(tvb) - offset,
1521                                         tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1522                                         "Bad AVP (Suspect Data Not Dissected)");
1523                 return;
1524           }
1525
1526           avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1527
1528           switch(avpType) {
1529           case DIAMETER_GROUPED:
1530                 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1531                 /* Recursively call ourselves */
1532                 grouptf = proto_tree_add_text(avpi_tree,
1533                                                                           tvb, offset, tvb_length(tvb),
1534                                                                           buffer);
1535                                 
1536                 group_tree = proto_item_add_subtree(grouptf,
1537                                                                                         ett_diameter_avp);
1538
1539                 group_tvb = tvb_new_subset(tvb, offset,
1540                                                                    MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1541                 if (group_tree != NULL) {
1542                   dissect_avps( group_tvb, pinfo, group_tree);
1543                 }
1544                 break;
1545
1546           case DIAMETER_IDENTITY:
1547                 {
1548                   const guint8 *data;
1549
1550                   data = tvb_get_ptr(tvb, offset, avpDataLength);
1551                   proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1552                                                tvb, offset, avpDataLength, data,
1553                                                "Identity: %*.*s",
1554                                                (int)avpDataLength,
1555                                                (int)avpDataLength, data);
1556                 }
1557                 break;
1558           case DIAMETER_UTF8STRING:
1559                 {
1560                   const guint8 *data;
1561
1562                   data = tvb_get_ptr(tvb, offset, avpDataLength);
1563                   proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1564                                                tvb, offset, avpDataLength, data,
1565                                                "UTF8String: %*.*s",
1566                                                (int)avpDataLength,
1567                                                (int)avpDataLength, data);
1568                 }
1569                 break;
1570           case DIAMETER_IP_ADDRESS:
1571                 if (avpDataLength == 4) {
1572                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1573                                       tvb, offset, avpDataLength, FALSE);
1574                 } else if (avpDataLength == 16) {
1575                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1576                                       tvb, offset, avpDataLength, FALSE);
1577                 } else {
1578                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1579                                               tvb, offset, avpDataLength,
1580                                               tvb_get_ptr(tvb, offset, avpDataLength),
1581                                               "Error!  Bad Address Length");
1582                 }
1583                 break;
1584
1585           case DIAMETER_INTEGER32:
1586                 if (avpDataLength == 4) {
1587                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1588                                       tvb, offset, avpDataLength, FALSE);
1589                 } else {
1590                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1591                                               tvb, offset, avpDataLength,
1592                                               tvb_get_ptr(tvb, offset, avpDataLength),
1593                                               "Error!  Bad Integer32 Length");
1594                 }
1595                 break;
1596
1597           case DIAMETER_UNSIGNED32:
1598                 if (avpDataLength == 4) {
1599                   guint32 data;
1600
1601                   data = tvb_get_ntohl(tvb, offset);
1602                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1603                                              tvb, offset, avpDataLength, data,
1604                                              "Value: 0x%08x (%u)", data, data);
1605                 } else {
1606                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1607                                               tvb, offset, avpDataLength,
1608                                               tvb_get_ptr(tvb, offset, avpDataLength),
1609                                               "Error!  Bad Unsigned32 Length");
1610                 }
1611                 break;
1612
1613           case DIAMETER_INTEGER64:
1614                 if (avpDataLength == 8) {
1615                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1616                                       tvb, offset, 8, FALSE);
1617                 } else {
1618                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1619                                               tvb, offset, avpDataLength,
1620                                               tvb_get_ptr(tvb, offset, avpDataLength),
1621                                               "Error!  Bad Integer64 Length");
1622                 }
1623                 break;
1624
1625           case DIAMETER_UNSIGNED64:
1626                 if (avpDataLength == 8) {
1627                   proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1628                                       tvb, offset, 8, FALSE);
1629                 } else {
1630                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1631                                               tvb, offset, avpDataLength,
1632                                               tvb_get_ptr(tvb, offset, avpDataLength),
1633                                               "Error!  Bad Unsigned64 Length");
1634                 }
1635                 break;
1636
1637           case DIAMETER_TIME:
1638                 if (avpDataLength == 4) {
1639                   nstime_t data;
1640                   gchar buffer[64];
1641                   struct tm *ltp;
1642
1643                   data.secs = tvb_get_ntohl(tvb, offset);
1644                   data.secs -= NTP_TIME_DIFF;
1645                   data.nsecs = 0;
1646
1647                   ltp = localtime(&data.secs);
1648                   strftime(buffer, 64, 
1649                            "%a, %d %b %Y %H:%M:%S %z", ltp);
1650
1651                   proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1652                                              tvb, offset, avpDataLength, &data,
1653                                              "Time: %s", buffer);
1654                 } else {
1655                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1656                                               tvb, offset, avpDataLength,
1657                                               tvb_get_ptr(tvb, offset, avpDataLength),
1658                                               "Error!  Bad Time Length");
1659                 }
1660                 break;
1661
1662           case DIAMETER_ENUMERATED:
1663                 if (avpDataLength == 4) {
1664                   guint32 data;
1665                   
1666                   data = tvb_get_ntohl(tvb, offset);
1667                   valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1668                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1669                                              tvb, offset, avpDataLength, data,
1670                                              "Value: 0x%08x (%u): %s", data,
1671                                              data, valstr);
1672                 } else {
1673                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1674                                               tvb, offset, avpDataLength,
1675                                               tvb_get_ptr(tvb, offset, avpDataLength),
1676                                               "Error!  Bad Enumerated Length");
1677                 }
1678                 break;
1679           case DIAMETER_VENDOR_ID:
1680                 if (avpDataLength == 4) {
1681                   guint32 data;
1682                   
1683                   data = tvb_get_ntohl(tvb, offset);
1684                   valstr = diameter_vendor_to_str(data, TRUE);
1685                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1686                                              tvb, offset, avpDataLength, data,
1687                                              "Vendor ID: %s (0x%08x)", valstr,
1688                                              data);
1689                 } else {
1690                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1691                                               tvb, offset, avpDataLength,
1692                                               tvb_get_ptr(tvb, offset, avpDataLength),
1693                                               "Error!  Bad Vendor ID Length");
1694                 }
1695                 break;
1696           case DIAMETER_APPLICATION_ID:
1697                 if (avpDataLength == 4) {
1698                   guint32 data;
1699                   
1700                   data = tvb_get_ntohl(tvb, offset);
1701                   valstr = diameter_app_to_str(data);
1702                   proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1703                                              tvb, offset, avpDataLength, data,
1704                                              "Application ID: %s (0x%08x)",
1705                                              valstr, data);
1706                 } else {
1707                   proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1708                                               tvb, offset, avpDataLength,
1709                                               tvb_get_ptr(tvb, offset, avpDataLength),
1710                                               "Error!  Bad Application ID Length");
1711                 }
1712                 break;
1713           case DIAMETER_MIP_REG_REQ:
1714                 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1715                 break;
1716
1717           default:
1718           case DIAMETER_OCTET_STRING:
1719                 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1720                                             tvb, offset, avpDataLength,
1721                                             tvb_get_ptr(tvb, offset, avpDataLength),
1722                                            "Hex Data Highlighted Below");
1723                 break;
1724                                 
1725           } /* switch type */
1726         } /* avpi_tree != null */
1727         offset += (avpLength - hdrLength);
1728         offset += fixAmt; /* fix byte alignment */
1729   } /* loop */
1730 } /* dissect_avps */
1731
1732
1733
1734 void
1735 proto_reg_handoff_diameter(void)
1736 {
1737   static int Initialized=FALSE;
1738   static int TcpPort=0;
1739   static int SctpPort=0;
1740   static dissector_handle_t diameter_tcp_handle;
1741   static dissector_handle_t diameter_sctp_handle;
1742
1743   if (!Initialized) {
1744         diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1745             proto_diameter);
1746         diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1747             proto_diameter);
1748         Initialized=TRUE;
1749   } else {
1750         dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1751         dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1752   }
1753
1754   /* set port for future deletes */
1755   TcpPort=gbl_diameterTcpPort;
1756   SctpPort=gbl_diameterSctpPort;
1757
1758   strcpy(gbl_diameterString, "Diameter Protocol");
1759
1760   /* g_warning ("Diameter: Adding tcp dissector to port %d",
1761          gbl_diameterTcpPort); */
1762   dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1763   dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1764 }
1765
1766 /* registration with the filtering engine */
1767 void
1768 proto_register_diameter(void)
1769 {
1770         static hf_register_info hf[] = {
1771                 { &hf_diameter_version,
1772                   { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1773                     "", HFILL }},
1774                 { &hf_diameter_length,
1775                   { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1776                     "", HFILL }},
1777                 
1778                 { &hf_diameter_flags,
1779                   { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1780                     "", HFILL }},
1781                 { &hf_diameter_flags_request,
1782                   { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1783                         "", HFILL }},
1784                 { &hf_diameter_flags_proxyable,
1785                   { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1786                         "", HFILL }},
1787                 { &hf_diameter_flags_error,
1788                   { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1789                         "", HFILL }},
1790                 { &hf_diameter_flags_reserved3,
1791                   { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1792                         DIAM_FLAGS_RESERVED3, "", HFILL }},
1793                 { &hf_diameter_flags_reserved4,
1794                   { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1795                         DIAM_FLAGS_RESERVED4, "", HFILL }},
1796                 { &hf_diameter_flags_reserved5,
1797                   { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1798                         DIAM_FLAGS_RESERVED5, "", HFILL }},
1799                 { &hf_diameter_flags_reserved6,
1800                   { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1801                         DIAM_FLAGS_RESERVED6, "", HFILL }},
1802                 { &hf_diameter_flags_reserved7,
1803                   { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1804                         DIAM_FLAGS_RESERVED7, "", HFILL }},
1805
1806                 { &hf_diameter_code,
1807                   { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1808                     NULL, 0x0, "", HFILL }},
1809                 { &hf_diameter_vendor_id,
1810                   { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1811                         0x0,"", HFILL }},
1812                 { &hf_diameter_hopbyhopid,
1813                   { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1814                     BASE_HEX, NULL, 0x0, "", HFILL }},
1815                 { &hf_diameter_endtoendid,
1816                   { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32, 
1817                     BASE_HEX, NULL, 0x0, "", HFILL }},
1818                 
1819                 { &hf_diameter_avp_code,
1820                   { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1821                     NULL, 0x0, "", HFILL }},
1822                 { &hf_diameter_avp_length,
1823                   { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1824                     NULL, 0x0, "", HFILL }},
1825
1826
1827                 { &hf_diameter_avp_flags,
1828                   { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1829                     NULL, 0x0, "", HFILL }},
1830                 { &hf_diameter_avp_flags_vendor_specific,
1831                   { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1832                         "", HFILL }},
1833                 { &hf_diameter_avp_flags_mandatory,
1834                   { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1835                         "", HFILL }},
1836                 { &hf_diameter_avp_flags_protected,
1837                   { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1838                         "", HFILL }},
1839                 { &hf_diameter_avp_flags_reserved3,
1840                   { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1841                         AVP_FLAGS_RESERVED3,    "", HFILL }},
1842                 { &hf_diameter_avp_flags_reserved4,
1843                   { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1844                         AVP_FLAGS_RESERVED4,    "", HFILL }},
1845                 { &hf_diameter_avp_flags_reserved5,
1846                   { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1847                         AVP_FLAGS_RESERVED5,    "", HFILL }},
1848                 { &hf_diameter_avp_flags_reserved6,
1849                   { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1850                         AVP_FLAGS_RESERVED6,    "", HFILL }},
1851                 { &hf_diameter_avp_flags_reserved7,
1852                   { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1853                         AVP_FLAGS_RESERVED7,    "", HFILL }},
1854                 { &hf_diameter_avp_vendor_id,
1855                   { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1856                     NULL, 0x0, "", HFILL }},
1857                 { &hf_diameter_avp_data_uint64,
1858                   { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1859                     NULL, 0x0, "", HFILL }},
1860                 { &hf_diameter_avp_data_int64,
1861                   { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1862                     NULL, 0x0, "", HFILL }},
1863                 { &hf_diameter_avp_data_uint32,
1864                   { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1865                     NULL, 0x0, "", HFILL }},
1866                 { &hf_diameter_avp_data_int32,
1867                   { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1868                     NULL, 0x0, "", HFILL }},
1869                 { &hf_diameter_avp_data_bytes,
1870                   { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1871                     NULL, 0x0, "", HFILL }},
1872                 { &hf_diameter_avp_data_string,
1873                   { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1874                     NULL, 0x0, "", HFILL }},
1875                 { &hf_diameter_avp_data_v4addr,
1876                   { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1877                     NULL, 0x0, "", HFILL }},
1878                 { &hf_diameter_avp_data_v6addr,
1879                   { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1880                     NULL, 0x0, "", HFILL }},
1881                 { &hf_diameter_avp_data_time,
1882                   { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1883                     NULL, 0x0, "", HFILL }},
1884
1885         };
1886         static gint *ett[] = {
1887                 &ett_diameter,
1888                 &ett_diameter_flags,
1889                 &ett_diameter_avp,
1890                 &ett_diameter_avp_flags,
1891                 &ett_diameter_avpinfo
1892         };
1893         module_t *diameter_module;
1894
1895         proto_diameter = proto_register_protocol (gbl_diameterString,
1896                                                                                           "Diameter", "diameter");
1897         proto_register_field_array(proto_diameter, hf, array_length(hf));
1898         proto_register_subtree_array(ett, array_length(ett));
1899
1900         /* Register a configuration option for port */
1901         diameter_module = prefs_register_protocol(proto_diameter,
1902                                                                                           proto_reg_handoff_diameter);
1903         prefs_register_uint_preference(diameter_module, "tcp.port",
1904                                                                    "Diameter TCP Port",
1905                                                                    "Set the TCP port for Diameter messages",
1906                                                                    10,
1907                                                                    &gbl_diameterTcpPort);
1908         prefs_register_uint_preference(diameter_module, "sctp.port",
1909                                                                    "Diameter SCTP Port",
1910                                                                    "Set the SCTP port for Diameter messages",
1911                                                                    10,
1912                                                                    &gbl_diameterSctpPort);
1913         /*
1914          * Build our default dictionary filename
1915          */
1916         if (! gbl_diameterDictionary) {
1917                 gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
1918                                                                                                         1 + strlen(DICT_FN) + 1); /* slash + fn + null */
1919                 sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
1920                                 get_datafile_dir(), DICT_FN );
1921         }
1922         /* Now register its preferences so it can be changed. */
1923         prefs_register_string_preference(diameter_module, "dictionary.name",
1924                                                                          "Diameter XML Dictionary",
1925                                                                          "Set the dictionary used for Diameter messages",
1926                                                                          &gbl_diameterDictionary);
1927
1928         /* Desegmentation */
1929         prefs_register_bool_preference(diameter_module, "desegment",
1930                                                                    "Desegment all Diameter messages spanning multiple TCP segments",
1931                                                                    "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1932                                                                    &gbl_diameter_desegment);
1933
1934         /* Register some preferences we no longer support, so we can report
1935            them as obsolete rather than just illegal. */
1936         prefs_register_obsolete_preference(diameter_module, "udp.port");
1937         prefs_register_obsolete_preference(diameter_module, "command_in_header");
1938 } /* proto_register_diameter */