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