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