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