2 * Routines for Diameter packet disassembly
6 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
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.
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.
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.
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
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"
62 /* This must be defined before we include packet-diameter-defs.h */
64 /* Valid data types */
67 DIAMETER_OCTET_STRING = 1,
71 DIAMETER_UNSIGNED32ENUM,
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 */
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"},
125 typedef struct value_name {
128 struct value_name *next;
131 typedef struct old_avp_info {
134 diameterDataType type;
135 const value_string *values;
138 typedef struct avp_info {
142 diameterDataType type;
144 struct avp_info *next;
147 typedef struct command_code {
151 struct command_code *next;
154 typedef struct vendor_id {
158 struct vendor_id *next;
161 typedef struct application_id {
164 struct application_id *next;
167 static avpInfo *avpListHead=NULL;
168 static VendorId *vendorListHead=NULL;
169 static CommandCode *commandListHead=NULL;
170 static ApplicationId *ApplicationIdHead=NULL;
173 #include "packet-diameter-defs.h"
175 #define NTP_TIME_DIFF (2208988800UL)
177 #define TCP_PORT_DIAMETER 3868
178 #define SCTP_PORT_DIAMETER 3868
180 static const true_false_string reserved_set = {
181 "*** Error! Reserved Bit is Set",
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;
203 static int hf_diameter_avp_code = -1;
204 static int hf_diameter_avp_length = -1;
205 static int hf_diameter_avp_flags = -1;
206 static int hf_diameter_avp_flags_vendor_specific = -1;
207 static int hf_diameter_avp_flags_mandatory = -1;
208 static int hf_diameter_avp_flags_protected = -1;
209 static int hf_diameter_avp_flags_reserved3 = -1;
210 static int hf_diameter_avp_flags_reserved4 = -1;
211 static int hf_diameter_avp_flags_reserved5 = -1;
212 static int hf_diameter_avp_flags_reserved6 = -1;
213 static int hf_diameter_avp_flags_reserved7 = -1;
214 static int hf_diameter_avp_vendor_id = -1;
217 static int hf_diameter_avp_data_uint32 = -1;
218 static int hf_diameter_avp_data_int32 = -1;
219 static int hf_diameter_avp_data_uint64 = -1;
220 static int hf_diameter_avp_data_int64 = -1;
221 static int hf_diameter_avp_data_bytes = -1;
222 static int hf_diameter_avp_data_string = -1;
223 static int hf_diameter_avp_data_addrfamily = -1;
224 static int hf_diameter_avp_data_v4addr = -1;
225 static int hf_diameter_avp_data_v6addr = -1;
226 static int hf_diameter_avp_data_time = -1;
227 static int hf_diameter_avp_diameter_uri = -1;
228 static int hf_diameter_avp_session_id = -1;
229 static int hf_diameter_avp_public_id = -1;
230 static int hf_diameter_avp_private_id = -1;
232 static gint ett_diameter = -1;
233 static gint ett_diameter_flags = -1;
234 static gint ett_diameter_avp = -1;
235 static gint ett_diameter_avp_flags = -1;
236 static gint ett_diameter_avpinfo = -1;
238 static guint gbl_diameterTcpPort=TCP_PORT_DIAMETER;
239 static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
241 /* desegmentation of Diameter over TCP */
242 static gboolean gbl_diameter_desegment = TRUE;
244 /* Allow zero as a valid application ID */
245 static gboolean allow_zero_as_app_id = TRUE;
247 /* Suppress console output at unknown AVP:s,Flags etc */
248 static gboolean suppress_console_output = TRUE;
250 static gboolean gbl_use_xml_dictionary = TRUE;
251 #define DICT_FN "diameter/dictionary.xml"
252 static const gchar *gbl_diameterDictionary;
254 typedef struct _e_diameterhdr_v16 {
255 guint32 versionLength;
256 guint32 flagsCmdCode;
262 typedef struct _e_diameterhdr_rfc {
263 guint32 versionLength;
264 guint32 flagsCmdCode;
265 guint32 applicationId;
270 typedef struct _e_avphdr {
272 guint32 avp_flagsLength;
273 guint32 avp_vendorId; /* optional */
276 /* Diameter Header Flags */
277 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
278 #define DIAM_FLAGS_R 0x80
279 #define DIAM_FLAGS_P 0x40
280 #define DIAM_FLAGS_E 0x20
281 #define DIAM_FLAGS_T 0x10
282 #define DIAM_FLAGS_RESERVED4 0x08
283 #define DIAM_FLAGS_RESERVED5 0x04
284 #define DIAM_FLAGS_RESERVED6 0x02
285 #define DIAM_FLAGS_RESERVED7 0x01
286 #define DIAM_FLAGS_RESERVED 0x0f
288 #define DIAM_LENGTH_MASK 0x00ffffffl
289 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
290 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
291 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
292 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
293 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
295 /* Diameter AVP Flags */
296 #define AVP_FLAGS_P 0x20
297 #define AVP_FLAGS_V 0x80
298 #define AVP_FLAGS_M 0x40
299 #define AVP_FLAGS_RESERVED3 0x10
300 #define AVP_FLAGS_RESERVED4 0x08
301 #define AVP_FLAGS_RESERVED5 0x04
302 #define AVP_FLAGS_RESERVED6 0x02
303 #define AVP_FLAGS_RESERVED7 0x01
304 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
306 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
307 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr_rfc))
309 static Version_Type gbl_version = DIAMETER_RFC;
311 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
312 static gchar *diameter_vendor_to_str(guint32 vendorId, gboolean longName);
315 * This routine will do a push-parse of the passed in
316 * filename. This was taken almost verbatum from
317 * the xmlsoft examples.
320 xmlParseFilePush( const char *filename, int checkValid
321 #ifndef WIRESHARK_XML_DO_VALIDITY_CHECKING
327 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
330 int res, size = 1024;
332 xmlParserCtxtPtr ctxt;
334 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
335 /* I wonder what kind of a performance hit this is? */
336 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
339 f = fopen(filename, "r");
341 report_open_failure(filename, errno, FALSE);
345 res = fread(chars, 1, 4, f);
347 ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
348 chars, res, filename);
349 while ((res = fread(chars, 1, size-1, f)) > 0) {
350 XmlStub.xmlParseChunk(ctxt, chars, res, 0);
352 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
354 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
357 XmlStub.xmlFreeParserCtxt(ctxt);
361 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
364 report_failure( "Error! Invalid xml in %s! Failed DTD check!",
371 } /* xmlParseFilePush */
374 * This routine will add a static avp to the avp list. It is
375 * only called when the XML dictionary fails to load properly.
378 addStaticAVP(int code, const gchar *name, diameterDataType type, const value_string *values)
381 ValueName *vEntry=NULL;
384 /* Parse our values array, if we have one */
386 for (i=0; values[i].strptr != NULL; i++) {
387 ValueName *ve = NULL;
389 ve = g_malloc(sizeof(ValueName));
390 ve->name = strdup(values[i].strptr);
391 ve->value = values[i].value;
397 /* And, create the entry */
398 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
399 entry->name = g_strdup(name);
401 entry->vendorName = NULL;
403 entry->values = vEntry;
404 /* Unsigned32 might have values to ( Result-code 268 ) */
407 case DIAMETER_UNSIGNED32:
408 entry->type = DIAMETER_UNSIGNED32ENUM;
410 case DIAMETER_VENDOR_ID:
411 /* Ignore data from the xml file, use sminmpec.h vals */
414 entry->type = DIAMETER_ENUMERATED;
419 /* And, add it to the list */
420 entry->next = avpListHead;
427 * This routine will add a Vendor avp to the avp list. It is
428 * only called when the XML dictionary fails to load properly.
431 addVendorAVP(int code, const gchar *name, diameterDataType type, const value_string *values,int vendorId)
434 ValueName *vEntry=NULL;
438 /* Parse our values array, if we have one */
440 for (i=0; values[i].strptr != NULL; i++) {
441 ValueName *ve = NULL;
443 ve = g_malloc(sizeof(ValueName));
444 ve->name = strdup(values[i].strptr);
445 ve->value = values[i].value;
451 /* And, create the entry */
452 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
453 entry->name = g_strdup(name);
456 vendorName = diameter_vendor_to_str(vendorId, FALSE);
459 entry->vendorName = g_strdup(vendorName);
461 entry->vendorName = NULL;
463 entry->values = vEntry;
465 /* Unsigned32 might have values to ( Result-code 268 ) */
468 case DIAMETER_UNSIGNED32:
469 entry->type = DIAMETER_UNSIGNED32ENUM;
471 case DIAMETER_VENDOR_ID:
472 /* Ignore data from the xml file, use sminmpec.h vals */
475 entry->type = DIAMETER_ENUMERATED;
479 /* And, add it to the list */
480 entry->next = avpListHead;
487 * This routine will parse an XML avp entry, and add it to our
488 * avp list. If any values are present in the avp, it will
492 xmlParseAVP(xmlNodePtr cur)
494 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
495 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
500 ValueName *vEntry=NULL;
503 /* First, get our properties */
504 name = XmlStub.xmlGetProp(cur, "name");
505 description = XmlStub.xmlGetProp(cur, "description");
506 code = XmlStub.xmlGetProp(cur, "code");
507 mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
508 mandatory = XmlStub.xmlGetProp(cur, "mandatory");
509 protected = XmlStub.xmlGetProp(cur, "protected");
510 vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
511 vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
512 constrained = XmlStub.xmlGetProp(cur, "constrained");
514 cur = cur->xmlChildrenNode;
516 while (cur != NULL ) {
517 if (strcasecmp((const char *)cur->name, "type") == 0) {
518 type = XmlStub.xmlGetProp(cur, "type-name");
519 } else if (strcasecmp((const char *)cur->name, "enum") == 0) {
520 char *valueName=NULL, *valueCode=NULL;
521 ValueName *ve = NULL;
522 valueName = XmlStub.xmlGetProp(cur, "name");
523 valueCode = XmlStub.xmlGetProp(cur, "code");
525 if (!valueName || !valueCode) {
526 report_failure( "Error, bad value on avp %s", name);
530 ve = g_malloc(sizeof(ValueName));
531 ve->name = strdup(valueName);
532 ve->value = atol(valueCode);
536 } else if (strcasecmp((const char *)cur->name, "grouped") == 0) {
537 /* WORK Recurse here for grouped AVPs */
544 * Check for the AVP Type.
547 for (i = 0; TypeValues[i].strptr; i++) {
548 if (!strcasecmp(type, TypeValues[i].strptr)) {
549 avpType = TypeValues[i].value;
554 if (TypeValues[i].strptr == NULL) {
555 report_failure( "Invalid Type field in dictionary! avp %s (%s)", name, type);
558 } else if (!vEntry) {
559 report_failure("Missing type/enum field in dictionary avpName=%s",
564 /* WORK - Handle flags -- for validation later */
567 /* And, create the entry */
568 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
569 entry->name = g_strdup(name);
570 entry->code = atol(code);
572 entry->vendorName = g_strdup(vendorName);
574 entry->vendorName = NULL;
575 entry->type = avpType;
576 entry->values = vEntry;
577 /* Unsigned32 might have values to ( Result-code 268 ) */
580 case DIAMETER_UNSIGNED32:
581 entry->type = DIAMETER_UNSIGNED32ENUM;
583 case DIAMETER_VENDOR_ID:
584 /* Ignore data from the xml file, use sminmpec.h vals */
587 entry->type = DIAMETER_ENUMERATED;
590 /* And, add it to the list */
591 entry->next = avpListHead;
598 * This routine will add a command to the list of commands.
601 addCommand(int code, const char *name, char *vendorId)
606 * Allocate the memory required for the dictionary.
608 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
611 report_failure("Unable to allocate memory");
616 * Allocate memory for the AVPName and copy the name to the
619 entry->name = g_strdup(name);
622 entry->vendorName = g_strdup(vendorId);
624 entry->vendorName = "None";
626 /* Add the entry to the list */
627 entry->next = commandListHead;
628 commandListHead = entry;
634 * This routine will parse the XML command, and add it to our
638 xmlParseCommand(xmlNodePtr cur)
640 char *name, *code, *vendorIdString;
645 name = XmlStub.xmlGetProp(cur, "name");
646 code = XmlStub.xmlGetProp(cur, "code");
648 g_warning("xmlParseCommand Name: %s code %s",name,code);
650 if (!name || !code) {
651 report_failure("Invalid command. Name or code missing!");
654 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
656 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
657 vendorIdString = NULL;
660 return (addCommand(atoi(code), name, vendorIdString));
661 } /* xmlParseCommand */
663 /* This routine adds an application to the name<-> id table */
665 dictionaryAddApplication(char *name, guint32 id)
667 ApplicationId *entry;
669 if (!name || (id == 0 && !allow_zero_as_app_id)) {
670 report_failure( "Diameter Error: Invalid application (name=%s, id=%d)",
673 } /* Sanity Checks */
675 entry = g_malloc(sizeof(ApplicationId));
677 report_failure( "Unable to allocate memory");
681 entry->name = g_strdup(name);
684 /* Add it to the list */
685 entry->next = ApplicationIdHead;
686 ApplicationIdHead = entry;
689 } /* dictionaryAddApplication */
692 * This routine will add a vendor to the vendors list
695 addVendor(int id, const gchar *name, const gchar *longName)
700 vendor=g_malloc(sizeof(VendorId));
706 vendor->name = g_strdup(name);
707 vendor->longName = g_strdup(longName);
708 vendor->next = vendorListHead;
709 vendorListHead = vendor;
715 * This routine will pars in a XML vendor entry.
718 xmlParseVendor(xmlNodePtr cur)
720 char *name=NULL, *code=NULL, *id=NULL;
722 /* First, get our properties */
723 id = XmlStub.xmlGetProp(cur, "vendor-id");
724 name = XmlStub.xmlGetProp(cur, "name");
725 code = XmlStub.xmlGetProp(cur, "code");
727 if (!id || !name || !code) {
728 report_failure( "Invalid vendor section. vendor-id, name, and code must be specified");
732 return (addVendor(atoi(code), id, name));
737 * This routine will either parse in the base protocol, or an application.
740 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
746 /* Add our application */
747 id = XmlStub.xmlGetProp(cur, "id");
748 name = XmlStub.xmlGetProp(cur, "name");
752 report_failure("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
753 name?name:"NULL", id?id:"NULL");
756 /* Add the application */
757 if (dictionaryAddApplication(name, (guint32)atol(id)) != 0) {
767 cur = cur->xmlChildrenNode;
768 while (cur != NULL) {
769 if (strcasecmp((const char *)cur->name, "avp") == 0) {
770 /* we have an avp!!! */
772 } else if (strcasecmp((const char *)cur->name, "vendor") == 0) {
773 /* we have a vendor */
775 /* For now, ignore typedefn and text */
776 } else if (strcasecmp((const char *)cur->name, "command") == 0) {
777 /* Found a command */
778 xmlParseCommand(cur);
779 } else if (strcasecmp((const char *)cur->name, "text") == 0) {
780 } else if (strcasecmp((const char *)cur->name, "comment") == 0) {
781 } else if (strcasecmp((const char *)cur->name, "typedefn") == 0) {
782 /* WORK -- parse in valid types . . . */
784 /* IF we got here, we're an error */
785 report_failure("Error! expecting an avp or a typedefn (got \"%s\")",
792 } /* xmlDictionaryParseSegment */
795 * The main xml parse routine. This will walk through an XML
796 * dictionary that has been parsed by libxml.
799 xmlDictionaryParse(xmlNodePtr cur)
801 /* We should expect a base protocol, followed by multiple applications */
802 while (cur != NULL) {
803 if (strcasecmp((const char *)cur->name, "base") == 0) {
804 /* Base protocol. Descend and parse */
805 xmlDictionaryParseSegment(cur, 1);
806 } else if (strcasecmp((const char *)cur->name, "application") == 0) {
807 /* Application. Descend and parse */
808 xmlDictionaryParseSegment(cur, 0);
809 } else if (strcasecmp((const char *)cur->name, "text") == 0) {
811 } else if (strcasecmp((const char *)cur->name, "comment") == 0) {
814 report_failure( "Diameter: XML Expecting a base or an application (got \"%s\")",
823 } /* xmlDictionaryParse */
826 * This routine will call libxml to parse in the dictionary.
829 loadXMLDictionary(void)
835 * build an XML tree from the file;
837 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
838 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
839 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
841 /* Check for invalid xml.
842 Note that xmlParseFilePush reports details of problems found,
843 and it should be obvious from the default filename that the error relates
851 * Check the document is of the right kind
853 cur = XmlStub.xmlDocGetRootElement(doc);
855 report_failure("Diameter: Error: \"%s\": empty document",
856 gbl_diameterDictionary);
857 XmlStub.xmlFreeDoc(doc);
860 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
861 report_failure("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
862 gbl_diameterDictionary);
863 XmlStub.xmlFreeDoc(doc);
868 * Ok, the dictionary has been parsed by libxml, and is valid.
869 * All we have to do now is read in our information.
871 if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
872 /* Error has already been printed */
876 /* Once we're done parsing, free up the xml memory */
877 XmlStub.xmlFreeDoc(doc);
881 } /* loadXMLDictionary */
884 * Fallback routine. In the event of ANY error when loading the XML
885 * dictionary, this routine will populate the new avp list structures
886 * with the old static data from packet-diameter-defs.h
889 initializeDictionaryDefaults(void)
893 /* Add static vendors to list */
894 for(i=0; sminmpec_values[i].strptr; i++) {
895 addVendor(sminmpec_values[i].value,
896 sminmpec_values[i].strptr,
897 sminmpec_values[i].strptr);
900 /* Add static commands to list. */
901 for(i=0; diameter_command_code_vals[i].strptr; i++) {
902 addCommand(diameter_command_code_vals[i].value,
903 diameter_command_code_vals[i].strptr, NULL);
906 /* Add static AVPs to list */
907 for (i=0; old_diameter_avps[i].name; i++) {
908 addStaticAVP(old_diameter_avps[i].code,
909 old_diameter_avps[i].name,
910 old_diameter_avps[i].type,
911 old_diameter_avps[i].values);
913 /* Add 3GPP AVPs to list */
914 for (i=0; ThreeGPP_vendor_diameter_avps[i].name; i++) {
915 addVendorAVP(ThreeGPP_vendor_diameter_avps[i].code,
916 ThreeGPP_vendor_diameter_avps[i].name,
917 ThreeGPP_vendor_diameter_avps[i].type,
918 ThreeGPP_vendor_diameter_avps[i].values,
922 } /* initializeDictionaryDefaults */
925 * This routine will attempt to load the XML dictionary if configured to.
926 * Otherwise, or if load fails, it will call initializeDictionaryDefaults
927 * to load in our static dictionary instead.
930 initializeDictionary(void)
933 * First, empty the dictionary of any previous contents
936 ApplicationId *tmpApplicationId = ApplicationIdHead;
937 VendorId *tmpVendorId = vendorListHead;
938 CommandCode *tmpCommandCode = commandListHead;
939 avpInfo *tmpAvpInfo = avpListHead;
941 /* ApplicationId list */
942 while (tmpApplicationId != NULL) {
943 g_free(tmpApplicationId->name);
944 tmpApplicationId = tmpApplicationId->next;
946 ApplicationIdHead = NULL;
949 while (tmpVendorId != NULL) {
950 g_free(tmpVendorId->name);
951 g_free(tmpVendorId->longName);
952 tmpVendorId = tmpVendorId->next;
954 vendorListHead = NULL;
956 /* CommandCode list */
957 while (tmpCommandCode != NULL) {
958 g_free(tmpCommandCode->name);
959 g_free(tmpCommandCode->vendorName);
960 tmpCommandCode = tmpCommandCode->next;
962 commandListHead = NULL;
965 while (tmpAvpInfo != NULL) {
966 ValueName *valueNamePtr = tmpAvpInfo->values;
967 g_free(tmpAvpInfo->name);
968 g_free(tmpAvpInfo->vendorName);
969 while (valueNamePtr) {
970 g_free(valueNamePtr->name);
971 valueNamePtr = valueNamePtr->next;
973 tmpAvpInfo = tmpAvpInfo->next;
979 * Using ugly ordering here. If loadLibXML succeeds, then
980 * loadXMLDictionary will be called. This is one of the few times when
981 * I think this is prettier than the nested if alternative.
983 if (gbl_use_xml_dictionary) {
984 if (loadLibXML() || (loadXMLDictionary() != 0)) {
985 /* Something failed. Use the static dictionary */
986 report_failure("Diameter: Using static dictionary! (Unable to use XML)");
987 initializeDictionaryDefaults();
991 initializeDictionaryDefaults();
994 } /* initializeDictionary */
999 * These routines manipulate the diameter structures.
1002 /* return vendor string, based on the id */
1004 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
1008 for (probe=vendorListHead; probe; probe=probe->next) {
1009 if (vendorId == probe->id) {
1011 return probe->longName;
1017 buffer=ep_alloc(64);
1018 g_snprintf(buffer, 64, "Vendor 0x%08x", vendorId);
1020 } /*diameter_vendor_to_str */
1022 /* return command string, based on the code */
1024 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
1028 gchar *vendorName=NULL;
1030 switch(gbl_version) {
1032 /* In draft-v16 version, command code is depending on vendorID */
1034 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1036 for (probe=commandListHead; probe; probe=probe->next) {
1037 if (commandCode == probe->code) {
1039 /* g_warning("Command: Comparing \"%s\" to \"%s\"", */
1040 /* vendorName?vendorName:"(null)", */
1041 /* probe->vendorName?probe->vendorName:"(null)"); */
1042 /* Now check the vendor name */
1043 if (!strcmp(vendorName, probe->vendorName))
1047 /* With no vendor id, the Command's entry should be "None" */
1048 if (!strcmp(probe->vendorName, "None")) {
1056 if ( suppress_console_output == FALSE )
1057 g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
1058 commandCode, vendorId);
1059 buffer=ep_alloc(64);
1060 g_snprintf(buffer, 64,
1061 "Cmd-0x%08x", commandCode);
1064 /* In RFC3588 version, command code is independant on vendorID */
1065 for (probe=commandListHead; probe; probe=probe->next) {
1066 if (commandCode == probe->code) {
1072 if ( suppress_console_output == FALSE )
1073 g_warning("Diameter: Unable to find name for command code 0x%08x!",
1075 buffer=ep_alloc(64);
1076 g_snprintf(buffer, 64,
1077 "Cmd-0x%08x", commandCode);
1081 }/*diameter_command_to_str */
1083 /* return application string, based on the id */
1085 diameter_app_to_str(guint32 appId) {
1086 ApplicationId *probe;
1089 for (probe=ApplicationIdHead; probe; probe=probe->next) {
1090 if (appId == probe->id) {
1095 buffer=ep_alloc(64);
1096 g_snprintf(buffer, 64, "Unknown");
1098 } /*diameter_app_to_str */
1100 /* return an avp type, based on the code */
1101 static diameterDataType
1102 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
1104 gchar *vendorName=NULL;
1107 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1109 for (probe=avpListHead; probe; probe=probe->next) {
1110 if (avpCode == probe->code) {
1113 /* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
1114 /* vendorName?vendorName:"(null)", */
1115 /* probe->vendorName?probe->vendorName:"(null)"); */
1116 /* Now check the vendor name */
1117 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
1121 /* No Vendor ID -- vendorName should be null */
1122 if (!probe->vendorName)
1129 /* If we don't find it, assume it's data */
1130 if ( suppress_console_output == FALSE )
1131 g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
1133 return DIAMETER_OCTET_STRING;
1134 } /* diameter_avp_get_type */
1136 /* return an avp name from the code */
1138 diameter_avp_get_name(guint32 avpCode, guint32 vendorId, gboolean *AVPFound)
1142 gchar *vendorName=NULL;
1143 *AVPFound = TRUE; /* will set to FALSE only if fail to match */
1146 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1148 for (probe=avpListHead; probe; probe=probe->next) {
1149 if (avpCode == probe->code) {
1151 /* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
1152 /* vendorName?vendorName:"(null)", */
1153 /* probe->vendorName?probe->vendorName:"(null)"); */
1154 /* Now check the vendor name */
1155 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
1159 /* No Vendor ID -- vendorName should be null */
1160 if (!probe->vendorName)
1166 if ( suppress_console_output == FALSE )
1167 g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
1170 /* If we don't find it, build a name string */
1171 buffer=ep_alloc(64);
1172 g_snprintf(buffer, 64, "Unknown AVP:0x%08x (%d)", avpCode, avpCode);
1175 } /* diameter_avp_get_name */
1177 static const gchar *
1178 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
1181 gchar *vendorName=NULL;
1184 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1186 for (probe=avpListHead; probe; probe=probe->next) {
1187 if (avpCode == probe->code) {
1189 /* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
1190 /* vendorName?vendorName:"(null)", */
1191 /* probe->vendorName?probe->vendorName:"(null)"); */
1192 /* Now check the vendor name */
1193 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
1195 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
1196 if (avpValue == vprobe->value) {
1197 return vprobe->name;
1200 return "(Unknown value)";
1203 if (!probe->vendorName) {
1205 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
1206 if (avpValue == vprobe->value) {
1207 return vprobe->name;
1210 return "(Unknown value)";
1215 /* We didn't find the avp */
1216 return "(Unknown AVP)";
1217 } /* diameter_avp_get_value */
1220 /* Code to actually dissect the packets */
1223 check_diameter(tvbuff_t *tvb)
1225 if (!tvb_bytes_exist(tvb, 0, 1))
1226 return FALSE; /* not enough bytes to check the version */
1227 if (tvb_get_guint8(tvb, 0) != 1)
1228 return FALSE; /* not version 1 */
1230 /* XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE?
1231 Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits
1240 dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1243 /* Set up structures needed to add the protocol subtree and manage it */
1246 proto_tree *flags_tree;
1248 proto_tree *diameter_tree;
1249 e_diameterhdr_v16 dh;
1250 e_diameterhdr_rfc dh2;
1253 proto_tree *avp_tree;
1255 int BadPacket = FALSE;
1256 guint32 commandCode=0, pktLength=0;
1257 guint8 version=0, flags=0;
1258 gchar *flagstr="<None>";
1259 const gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1260 gchar *commandString=NULL, *vendorName=NULL, *applicationName=NULL, *commandStringType=NULL;
1263 static int initialized=FALSE;
1265 /* Keep track of preference settings affecting dictionary source */
1266 static gboolean previous_use_xml_dictionary=FALSE;
1267 #define MAX_DICT_NAME_SIZE 256
1268 static gchar previous_diameterDictionary[MAX_DICT_NAME_SIZE];
1271 * Only parse in dictionary if there are diameter packets to
1273 * Keeps track of preference settings and frees/reinitializes the
1274 * dictionary when appropriate.
1277 (gbl_use_xml_dictionary != previous_use_xml_dictionary) ||
1278 (strncmp(gbl_diameterDictionary,
1279 previous_diameterDictionary,
1280 MAX_DICT_NAME_SIZE) != 0)) {
1281 /* Populate dictionary according to preferences */
1282 initializeDictionary();
1285 /* Record current preference settings */
1286 previous_use_xml_dictionary = gbl_use_xml_dictionary;
1287 strncpy(previous_diameterDictionary, gbl_diameterDictionary, MAX_DICT_NAME_SIZE);
1290 /* Make entries in Protocol column and Info column on summary display */
1291 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1292 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1293 if (check_col(pinfo->cinfo, COL_INFO))
1294 col_clear(pinfo->cinfo, COL_INFO);
1296 /* Copy our header */
1297 switch(gbl_version) {
1299 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1300 /* Fix byte ordering in our static structure */
1301 dh.versionLength = g_ntohl(dh.versionLength);
1302 dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
1303 dh.vendorId = g_ntohl(dh.vendorId);
1304 dh.hopByHopId = g_ntohl(dh.hopByHopId);
1305 dh.endToEndId = g_ntohl(dh.endToEndId);
1307 vendorName=diameter_vendor_to_str(dh.vendorId, TRUE);
1311 /* Do the bit twiddling */
1312 version = DIAM_GET_VERSION(dh);
1313 pktLength = DIAM_GET_LENGTH(dh);
1314 flags = DIAM_GET_FLAGS(dh);
1315 commandCode = DIAM_GET_COMMAND(dh);
1318 tvb_memcpy(tvb, (guint8*) &dh2, offset, sizeof(dh2));
1319 /* Fix byte ordering in our static structure */
1320 dh2.versionLength = g_ntohl(dh2.versionLength);
1321 dh2.flagsCmdCode = g_ntohl(dh2.flagsCmdCode);
1322 dh2.applicationId = g_ntohl(dh2.applicationId);
1323 dh2.hopByHopId = g_ntohl(dh2.hopByHopId);
1324 dh2.endToEndId = g_ntohl(dh2.endToEndId);
1325 if (dh2.applicationId) {
1326 applicationName=diameter_app_to_str(dh2.applicationId);
1327 /* If not found, it might be a vendor ID? */
1328 if (strcmp(applicationName, "Unknown") == 0){
1329 applicationName=diameter_vendor_to_str(dh2.applicationId,FALSE);
1332 applicationName="None";
1334 /* Do the bit twiddling */
1335 version = DIAM_GET_VERSION(dh2);
1336 pktLength = DIAM_GET_LENGTH(dh2);
1337 flags = DIAM_GET_FLAGS(dh2);
1338 commandCode = DIAM_GET_COMMAND(dh2);
1343 /* Set up our flags */
1344 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1347 #define FLAG_STR_LEN 64
1348 flagstr=ep_alloc(FLAG_STR_LEN);
1351 for (i = 0; i < 8; i++) {
1355 fslen+=MIN(FLAG_STR_LEN-fslen,
1356 g_snprintf(flagstr+fslen, FLAG_STR_LEN-fslen, ", "));
1358 fslen+=MIN(FLAG_STR_LEN-fslen,
1359 g_snprintf(flagstr+fslen, FLAG_STR_LEN-fslen, "%s", fstr[i]));
1362 if (flagstr[0] == 0) {
1367 /* Set up our commandString */
1368 switch(gbl_version) {
1370 commandString=diameter_command_to_str(commandCode, dh.vendorId);
1373 /* FIXME: in RFC, is applicationID needed to decode the command code? */
1374 commandString=diameter_command_to_str(commandCode, dh2.applicationId);
1378 if (flags & DIAM_FLAGS_R)
1379 commandStringType="Request";
1381 commandStringType="Answer";
1383 /* Short packet. Should have at LEAST one avp */
1384 if (pktLength < MIN_DIAMETER_SIZE) {
1385 if ( suppress_console_output == FALSE )
1386 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1387 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1391 /* And, check our reserved flags/version */
1392 if ((flags & DIAM_FLAGS_RESERVED) ||
1394 if ( suppress_console_output == FALSE )
1395 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1400 if (check_col(pinfo->cinfo, COL_INFO)) {
1401 switch(gbl_version) {
1403 col_add_fstr(pinfo->cinfo, COL_INFO,
1404 "%s%s%s%s%s-%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1405 (BadPacket)?"***** Bad Packet!: ":"",
1406 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1407 (flags & DIAM_FLAGS_E)?" Error":"",
1409 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1411 commandString, commandStringType, vendorName,
1412 dh.hopByHopId, dh.endToEndId,
1413 (flags & DIAM_FLAGS_R)?1:0,
1414 (flags & DIAM_FLAGS_P)?1:0,
1415 (flags & DIAM_FLAGS_E)?1:0);
1418 col_add_fstr(pinfo->cinfo, COL_INFO,
1419 "%s%s%s%s%s-%s app=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1420 (BadPacket)?"***** Bad Packet!: ":"",
1421 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1422 (flags & DIAM_FLAGS_E)?" Error":"",
1424 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1426 commandString, commandStringType, applicationName,
1427 dh2.hopByHopId, dh2.endToEndId,
1428 (flags & DIAM_FLAGS_R)?1:0,
1429 (flags & DIAM_FLAGS_P)?1:0,
1430 (flags & DIAM_FLAGS_E)?1:0);
1436 /* In the interest of speed, if "tree" is NULL, don't do any work not
1437 necessary to generate protocol tree items. */
1440 /* create display subtree for the protocol */
1441 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1442 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1443 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1446 proto_tree_add_uint(diameter_tree,
1447 hf_diameter_version,
1454 proto_tree_add_uint(diameter_tree,
1455 hf_diameter_length, tvb,
1456 offset, 3, pktLength);
1460 tf = proto_tree_add_uint_format_value(diameter_tree, hf_diameter_flags, tvb,
1461 offset, 1, flags, "0x%02x (%s)", flags,
1463 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1464 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1465 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1466 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1467 proto_tree_add_boolean(flags_tree, hf_diameter_flags_T, tvb, offset, 1, flags);
1468 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1469 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1470 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1471 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1476 proto_tree_add_uint_format_value(diameter_tree, hf_diameter_code,
1477 tvb, offset, 3, commandCode, "%s-%s (%d)",
1478 commandString, commandStringType, commandCode);
1481 switch(gbl_version) {
1485 proto_tree_add_item(diameter_tree, hf_diameter_vendor_id, tvb, offset, 4, FALSE);
1487 /* Hop-by-hop Identifier */
1488 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1489 tvb, offset, 4, dh.hopByHopId);
1491 /* End-to-end Identifier */
1492 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1493 tvb, offset, 4, dh.endToEndId);
1497 /* Application Id */
1498 proto_tree_add_item(diameter_tree, hf_diameter_application_id, tvb, offset, 4, FALSE);
1500 /* Hop-by-hop Identifier */
1501 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1502 tvb, offset, 4, dh2.hopByHopId);
1504 /* End-to-end Identifier */
1505 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1506 tvb, offset, 4, dh2.endToEndId);
1512 /* If we have a bad packet, don't bother trying to parse the AVPs */
1517 /* Start looking at the AVPS */
1518 /* Make the next tvbuff */
1520 /* Update the lengths */
1521 switch(gbl_version) {
1523 avplength= pktLength - sizeof(e_diameterhdr_v16);
1526 avplength= pktLength - sizeof(e_diameterhdr_rfc);
1530 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1531 avptf = proto_tree_add_text(diameter_tree,
1532 tvb, offset, avplength,
1533 "Attribute Value Pairs");
1535 avp_tree = proto_item_add_subtree(avptf,
1537 if (avp_tree != NULL) {
1538 dissect_avps( avp_tvb, pinfo, avp_tree);
1542 } /* dissect_diameter_common */
1546 get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1548 /* Get the length of the Diameter packet. */
1549 return tvb_get_ntoh24(tvb, offset + 1);
1553 dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1555 if (!check_diameter(tvb))
1557 dissect_diameter_common(tvb, pinfo, tree);
1558 return tvb_length(tvb);
1562 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1564 tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
1565 get_diameter_pdu_len, dissect_diameter_common);
1566 } /* dissect_diameter_tcp */
1569 * Call the mip_dissector, after saving our pinfo variables
1570 * so it doesn't write to our column display.
1573 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1574 size_t offset, size_t length)
1576 static dissector_handle_t mip_handle;
1577 static int mipInitialized=FALSE;
1579 address save_dl_src;
1580 address save_dl_dst;
1581 address save_net_src;
1582 address save_net_dst;
1585 gboolean save_in_error_pkt;
1587 if (!mipInitialized) {
1588 mip_handle = find_dissector("mip");
1589 mipInitialized=TRUE;
1592 mip_tvb = tvb_new_subset(tvb, offset,
1593 MIN(length, tvb_length(tvb)-offset),
1596 /* The contained packet is a MIP registration request;
1597 dissect it with the MIP dissector. */
1598 col_set_writable(pinfo->cinfo, FALSE);
1600 /* Also, save the current values of the addresses, and restore
1601 them when we're finished dissecting the contained packet, so
1602 that the address columns in the summary don't reflect the
1603 contained packet, but reflect this packet instead. */
1604 save_dl_src = pinfo->dl_src;
1605 save_dl_dst = pinfo->dl_dst;
1606 save_net_src = pinfo->net_src;
1607 save_net_dst = pinfo->net_dst;
1608 save_src = pinfo->src;
1609 save_dst = pinfo->dst;
1610 save_in_error_pkt = pinfo->in_error_pkt;
1612 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1614 /* Restore the "we're inside an error packet" flag. */
1615 pinfo->in_error_pkt = save_in_error_pkt;
1616 pinfo->dl_src = save_dl_src;
1617 pinfo->dl_dst = save_dl_dst;
1618 pinfo->net_src = save_net_src;
1619 pinfo->net_dst = save_net_dst;
1620 pinfo->src = save_src;
1621 pinfo->dst = save_dst;
1624 } /* safe_dissect_mip */
1627 * This function will dissect the AVPs in a diameter packet. It handles
1628 * all normal types, and even recursively calls itself for grouped AVPs
1630 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1632 /* adds the attribute value pairs to the tree */
1634 const gchar *avpTypeString;
1635 const gchar *avpNameString;
1636 const gchar *valstr;
1641 proto_tree *avpi_tree;
1643 tvbuff_t *group_tvb;
1644 proto_tree *group_tree;
1645 proto_item *grouptf;
1648 int BadPacket = FALSE;
1652 proto_tree *flags_tree;
1654 gint32 packetLength;
1655 size_t avpDataLength;
1657 gchar *flagstr="<None>";
1658 const gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1662 packetLength = tvb_length(tvb);
1664 /* Check for invalid packet lengths */
1665 if (packetLength <= 0) {
1666 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1667 "No Attribute Value Pairs Found");
1671 /* Spin around until we run out of packet */
1672 while (packetLength > 0 )
1674 gboolean AVP_code_found;
1676 /* Check for short packet */
1677 if (packetLength < (long)MIN_AVP_SIZE) {
1678 if ( suppress_console_output == FALSE )
1679 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1680 packetLength, (long)MIN_AVP_SIZE);
1682 /* Don't even bother trying to parse a short packet. */
1686 /* Copy our header */
1687 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1689 /* Fix the byte ordering */
1690 avph.avp_code = g_ntohl(avph.avp_code);
1691 avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1693 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1694 avpLength = avph.avp_flagsLength & 0x00ffffff;
1696 /* Set up our flags string */
1697 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1700 #define FLAG_STR_LEN 64
1701 flagstr=ep_alloc(FLAG_STR_LEN);
1704 for (i = 0; i < 8; i++) {
1708 fslen+=MIN(FLAG_STR_LEN-fslen,
1709 g_snprintf(flagstr+fslen, FLAG_STR_LEN-fslen, ", "));
1711 fslen+=MIN(FLAG_STR_LEN-fslen,
1712 g_snprintf(flagstr+fslen, FLAG_STR_LEN-fslen, "%s", fstr[i]));
1715 if (flagstr[0] == 0) {
1720 /* Dissect our vendor id if it exists and set hdr length */
1721 if (flags & AVP_FLAGS_V) {
1722 vendorId = g_ntohl(avph.avp_vendorId);
1724 hdrLength = sizeof(e_avphdr);
1727 hdrLength = sizeof(e_avphdr) - sizeof(guint32);
1732 vendorName=diameter_vendor_to_str(vendorId, TRUE);
1737 /* Check for bad length */
1738 if (avpLength < MIN_AVP_SIZE ||
1739 ((long)avpLength > packetLength))
1741 if ( suppress_console_output == FALSE )
1742 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1743 "min: %ld bytes, packetLen: %d",
1744 (long)avpLength, (long)MIN_AVP_SIZE, packetLength);
1748 /* Check for bad flags */
1749 if (flags & AVP_FLAGS_RESERVED) {
1750 if ( suppress_console_output == FALSE )
1751 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1753 flags, AVP_FLAGS_RESERVED);
1754 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit
1760 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1763 fixAmt = 4 - (avpLength % 4);
1767 /* shrink our packetLength */
1768 packetLength = packetLength - (avpLength + fixAmt);
1770 /* Check for out of bounds */
1771 if (packetLength < 0) {
1772 if ( suppress_console_output == FALSE )
1773 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1778 /* Make avp Name & type */
1779 avpTypeString=val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1781 "Unknown-Type: 0x%08x");
1782 avpNameString=diameter_avp_get_name(avph.avp_code, vendorId, &AVP_code_found);
1784 avptf = proto_tree_add_text(avp_tree, tvb,
1785 offset, avpLength + fixAmt,
1786 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1787 avpNameString, avpTypeString, avpLength,
1788 avpLength, avpLength+fixAmt);
1789 avpi_tree = proto_item_add_subtree(avptf, ett_diameter_avpinfo);
1791 if (avpi_tree !=NULL)
1795 ti = proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_code,
1796 tvb, offset, 4, avph.avp_code, "%s (%u)",
1797 avpNameString,avph.avp_code);
1798 if (!AVP_code_found)
1800 expert_add_info_format(pinfo, ti,
1801 PI_UNDECODED, PI_NOTE,
1802 "AVP info not available (code %u)",
1807 tf = proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_flags, tvb,
1808 offset, 1, flags, "0x%02x (%s)", flags,
1810 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1811 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1812 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1813 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1814 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1815 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1816 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1817 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1818 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1821 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1822 tvb, offset, 3, avpLength);
1825 if (flags & AVP_FLAGS_V) {
1826 proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_vendor_id,
1827 tvb, offset, 4, vendorId, "%s (%u)", vendorName, vendorId);
1831 avpDataLength = avpLength - hdrLength;
1834 * If we've got a bad packet, just highlight the data. Don't try
1835 * to parse it, and, don't move to next AVP.
1838 offset -= hdrLength;
1839 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1840 tvb, offset, tvb_length(tvb) - offset,
1841 tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1842 "Bad AVP (Suspect Data Not Dissected)");
1846 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1850 case DIAMETER_GROUPED:
1851 buffer=ep_alloc(256);
1852 g_snprintf(buffer, 256, "%s Grouped AVPs", avpNameString);
1853 /* Recursively call ourselves */
1854 grouptf = proto_tree_add_text(avpi_tree,
1855 tvb, offset, tvb_length(tvb),
1858 group_tree = proto_item_add_subtree(grouptf, ett_diameter_avp);
1860 group_tvb = tvb_new_subset(tvb, offset,
1861 MIN(avpDataLength, tvb_length(tvb)-offset),
1863 if (group_tree != NULL) {
1864 dissect_avps( group_tvb, pinfo, group_tree);
1868 case DIAMETER_IDENTITY:
1872 data = tvb_get_ptr(tvb, offset, avpDataLength);
1873 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1874 tvb, offset, avpDataLength, data,
1877 (int)avpDataLength, data);
1880 case DIAMETER_UTF8STRING:
1884 data = tvb_get_ptr(tvb, offset, avpDataLength);
1885 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1886 tvb, offset, avpDataLength, data,
1887 "UTF8String: %*.*s",
1889 (int)avpDataLength, data);
1892 case DIAMETER_IP_ADDRESS:
1897 if (avpDataLength == 4) {
1898 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1899 tvb, offset, avpDataLength, FALSE);
1900 } else if (avpDataLength == 16) {
1901 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1902 tvb, offset, avpDataLength, FALSE);
1904 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1905 tvb, offset, avpDataLength,
1906 tvb_get_ptr(tvb, offset, avpDataLength),
1907 "Error! Bad Address Length (Address in RFC3588 format?)");
1908 expert_add_info_format(pinfo, ti,
1909 PI_MALFORMED, PI_NOTE,
1910 "Bad Address Length (%u)",
1915 /* Indicate the address family */
1916 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_addrfamily,
1917 tvb, offset, 2, FALSE);
1918 if (tvb_get_ntohs(tvb, offset) == 0x0001) {
1919 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1920 tvb, offset+2, 4, FALSE);
1921 } else if (tvb_get_ntohs(tvb, offset) == 0x0002) {
1922 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1923 tvb, offset+2, 16, FALSE);
1925 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1926 tvb, offset, avpDataLength,
1927 tvb_get_ptr(tvb, offset, avpDataLength),
1928 "Error! Can't Parse Address Family %d (Address in draft v16 format?)",
1929 (int)tvb_get_ntohs(tvb, offset));
1936 case DIAMETER_INTEGER32:
1937 if (avpDataLength == 4) {
1938 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1939 tvb, offset, avpDataLength, FALSE);
1941 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1942 tvb, offset, avpDataLength,
1943 tvb_get_ptr(tvb, offset, avpDataLength),
1944 "Error! Bad Integer32 Length");
1945 expert_add_info_format(pinfo, ti,
1946 PI_MALFORMED, PI_NOTE,
1947 "Bad Integer32 Length (%u)",
1952 case DIAMETER_UNSIGNED32:
1953 if (avpDataLength == 4) {
1956 data = tvb_get_ntohl(tvb, offset);
1957 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1958 tvb, offset, avpDataLength, data,
1959 "Value: 0x%08x (%u)", data, data);
1961 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1962 tvb, offset, avpDataLength,
1963 tvb_get_ptr(tvb, offset, avpDataLength),
1964 "Error! Bad Unsigned32 Length");
1965 expert_add_info_format(pinfo, ti,
1966 PI_MALFORMED, PI_NOTE,
1967 "Bad Unsigned32 Length (%u)",
1972 case DIAMETER_UNSIGNED32ENUM:
1973 if (avpDataLength == 4) {
1976 data = tvb_get_ntohl(tvb, offset);
1977 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1978 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1979 tvb, offset, avpDataLength, data,
1980 "Value: 0x%08x (%u): %s", data,
1983 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1984 tvb, offset, avpDataLength,
1985 tvb_get_ptr(tvb, offset, avpDataLength),
1986 "Error! Bad Enumerated Length");
1987 expert_add_info_format(pinfo, ti,
1988 PI_MALFORMED, PI_NOTE,
1989 "Bad Enumerated Length (%u)",
1994 case DIAMETER_INTEGER64:
1995 if (avpDataLength == 8) {
1996 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1997 tvb, offset, 8, FALSE);
1999 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2000 tvb, offset, avpDataLength,
2001 tvb_get_ptr(tvb, offset, avpDataLength),
2002 "Error! Bad Integer64 Length");
2003 expert_add_info_format(pinfo, ti,
2004 PI_MALFORMED, PI_NOTE,
2005 "Bad Integer64 Length (%u)",
2010 case DIAMETER_UNSIGNED64:
2011 if (avpDataLength == 8) {
2012 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
2013 tvb, offset, 8, FALSE);
2015 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2016 tvb, offset, avpDataLength,
2017 tvb_get_ptr(tvb, offset, avpDataLength),
2018 "Error! Bad Unsigned64 Length");
2019 expert_add_info_format(pinfo, ti,
2020 PI_MALFORMED, PI_NOTE,
2021 "Bad Unsigned64 Length (%u)",
2027 if (avpDataLength == 4) {
2031 data.secs = tvb_get_ntohl(tvb, offset);
2032 /* Present the time as UTC, Time before 00:00:00 UTC, January 1, 1970 can't be presented correctly */
2033 if ( data.secs >= NTP_TIME_DIFF){
2034 data.secs -= NTP_TIME_DIFF;
2037 gmtp = gmtime(&data.secs);
2038 buffer=ep_alloc(64);
2039 strftime(buffer, 64, "%a, %d %b %Y %H:%M:%S UTC", gmtp);
2041 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
2042 tvb, offset, avpDataLength, &data,
2043 "Time: %s", buffer);
2045 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2046 tvb, offset, avpDataLength,
2047 tvb_get_ptr(tvb, offset, avpDataLength),
2048 "Error! Time before 00:00:00 UTC, January 1, 1970");
2051 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2052 tvb, offset, avpDataLength,
2053 tvb_get_ptr(tvb, offset, avpDataLength),
2054 "Error! Bad Time Length");
2055 expert_add_info_format(pinfo, ti,
2056 PI_MALFORMED, PI_NOTE,
2057 "Bad Time Length (%u)",
2062 case DIAMETER_ENUMERATED:
2063 if (avpDataLength == 4) {
2066 data = tvb_get_ntohl(tvb, offset);
2067 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
2068 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
2069 tvb, offset, avpDataLength, data,
2070 "Value: 0x%08x (%u): %s", data,
2073 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2074 tvb, offset, avpDataLength,
2075 tvb_get_ptr(tvb, offset, avpDataLength),
2076 "Error! Bad Enumerated Length");
2077 expert_add_info_format(pinfo, ti,
2078 PI_MALFORMED, PI_NOTE,
2079 "Bad Enumerated Length (%u)",
2084 case DIAMETER_VENDOR_ID:
2085 if (avpDataLength == 4) {
2086 proto_tree_add_item(avpi_tree, hf_diameter_vendor_id, tvb, offset, avpDataLength, FALSE);
2088 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2089 tvb, offset, avpDataLength,
2090 tvb_get_ptr(tvb, offset, avpDataLength),
2091 "Error! Bad Vendor ID Length");
2092 expert_add_info_format(pinfo, ti,
2093 PI_MALFORMED, PI_NOTE,
2094 "Bad Vendor ID Length (%u)",
2099 case DIAMETER_APPLICATION_ID:
2100 if (avpDataLength == 4) {
2103 data = tvb_get_ntohl(tvb, offset);
2104 valstr = diameter_app_to_str(data);
2105 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
2106 tvb, offset, avpDataLength, data,
2107 "Application ID: %s %d (0x%08x)",
2108 valstr, data, data);
2110 ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2111 tvb, offset, avpDataLength,
2112 tvb_get_ptr(tvb, offset, avpDataLength),
2113 "Error! Bad Application ID Length");
2114 expert_add_info_format(pinfo, ti,
2115 PI_MALFORMED, PI_NOTE,
2116 "Bad Application ID Length (%u)",
2121 case DIAMETER_MIP_REG_REQ:
2122 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
2126 proto_tree_add_item(avpi_tree, hf_diameter_avp_diameter_uri,
2127 tvb, offset, avpDataLength, FALSE);
2130 case DIAMETER_SESSION_ID:
2131 proto_tree_add_item(avpi_tree, hf_diameter_avp_session_id,
2132 tvb, offset, avpDataLength, FALSE);
2135 case DIAMETER_PUBLIC_ID:
2137 proto_tree_add_item(avpi_tree, hf_diameter_avp_public_id,
2138 tvb, offset, avpDataLength, FALSE);
2139 /* This is a SIP address, to be able to filter the SIP messages
2140 * belonging to this Diameter session add this to the SIP filter.
2142 dfilter_store_sip_from_addr(tvb, avpi_tree, offset, avpDataLength);
2145 case DIAMETER_PRIVATE_ID:
2146 proto_tree_add_item(avpi_tree, hf_diameter_avp_private_id,
2147 tvb, offset, avpDataLength, FALSE);
2151 case DIAMETER_OCTET_STRING:
2152 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
2153 tvb, offset, avpDataLength,
2154 tvb_get_ptr(tvb, offset, avpDataLength),
2155 "Hex Data Highlighted Below");
2158 } /* avpi_tree != null */
2159 offset += (avpLength - hdrLength);
2160 offset += fixAmt; /* fix byte alignment */
2162 } /* dissect_avps */
2167 proto_reg_handoff_diameter(void)
2169 static int Initialized=FALSE;
2170 static int TcpPort=0;
2171 static int SctpPort=0;
2172 static dissector_handle_t diameter_tcp_handle;
2173 static dissector_handle_t diameter_handle;
2176 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
2178 diameter_handle = new_create_dissector_handle(dissect_diameter,
2182 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
2183 dissector_delete("sctp.port", SctpPort, diameter_handle);
2186 /* set port for future deletes */
2187 TcpPort=gbl_diameterTcpPort;
2188 SctpPort=gbl_diameterSctpPort;
2190 /* g_warning ("Diameter: Adding tcp dissector to port %d",
2191 gbl_diameterTcpPort); */
2192 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
2193 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
2196 /* registration with the filtering engine */
2198 proto_register_diameter(void)
2200 static hf_register_info hf[] = {
2201 { &hf_diameter_version,
2202 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
2204 { &hf_diameter_length,
2205 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
2208 { &hf_diameter_flags,
2209 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
2211 { &hf_diameter_flags_request,
2212 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
2214 { &hf_diameter_flags_proxyable,
2215 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
2217 { &hf_diameter_flags_error,
2218 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
2220 { &hf_diameter_flags_T,
2221 { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&flags_set_truth),DIAM_FLAGS_T,
2223 { &hf_diameter_flags_reserved4,
2224 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
2225 DIAM_FLAGS_RESERVED4, "", HFILL }},
2226 { &hf_diameter_flags_reserved5,
2227 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
2228 DIAM_FLAGS_RESERVED5, "", HFILL }},
2229 { &hf_diameter_flags_reserved6,
2230 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
2231 DIAM_FLAGS_RESERVED6, "", HFILL }},
2232 { &hf_diameter_flags_reserved7,
2233 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
2234 DIAM_FLAGS_RESERVED7, "", HFILL }},
2236 { &hf_diameter_code,
2237 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
2238 NULL, 0x0, "", HFILL }},
2239 { &hf_diameter_vendor_id,
2240 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, VALS(sminmpec_values),
2242 { &hf_diameter_application_id,
2243 { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC, VALS(diameter_application_id_vals),
2245 { &hf_diameter_hopbyhopid,
2246 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
2247 BASE_HEX, NULL, 0x0, "", HFILL }},
2248 { &hf_diameter_endtoendid,
2249 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
2250 BASE_HEX, NULL, 0x0, "", HFILL }},
2252 { &hf_diameter_avp_code,
2253 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
2254 NULL, 0x0, "", HFILL }},
2255 { &hf_diameter_avp_length,
2256 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
2257 NULL, 0x0, "", HFILL }},
2260 { &hf_diameter_avp_flags,
2261 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
2262 NULL, 0x0, "", HFILL }},
2263 { &hf_diameter_avp_flags_vendor_specific,
2264 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
2266 { &hf_diameter_avp_flags_mandatory,
2267 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
2269 { &hf_diameter_avp_flags_protected,
2270 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
2272 { &hf_diameter_avp_flags_reserved3,
2273 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
2274 AVP_FLAGS_RESERVED3, "", HFILL }},
2275 { &hf_diameter_avp_flags_reserved4,
2276 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
2277 AVP_FLAGS_RESERVED4, "", HFILL }},
2278 { &hf_diameter_avp_flags_reserved5,
2279 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
2280 AVP_FLAGS_RESERVED5, "", HFILL }},
2281 { &hf_diameter_avp_flags_reserved6,
2282 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
2283 AVP_FLAGS_RESERVED6, "", HFILL }},
2284 { &hf_diameter_avp_flags_reserved7,
2285 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
2286 AVP_FLAGS_RESERVED7, "", HFILL }},
2287 { &hf_diameter_avp_vendor_id,
2288 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
2289 NULL, 0x0, "", HFILL }},
2290 { &hf_diameter_avp_data_uint64,
2291 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
2292 NULL, 0x0, "", HFILL }},
2293 { &hf_diameter_avp_data_int64,
2294 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
2295 NULL, 0x0, "", HFILL }},
2296 { &hf_diameter_avp_data_uint32,
2297 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
2298 NULL, 0x0, "", HFILL }},
2299 { &hf_diameter_avp_data_int32,
2300 { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
2301 NULL, 0x0, "", HFILL }},
2302 { &hf_diameter_avp_data_bytes,
2303 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
2304 NULL, 0x0, "", HFILL }},
2305 { &hf_diameter_avp_data_string,
2306 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
2307 NULL, 0x0, "", HFILL }},
2308 { &hf_diameter_avp_data_addrfamily,
2309 { "Address Family","diameter.avp.data.addrfamily", FT_UINT16, BASE_DEC,
2310 VALS(diameter_avp_data_addrfamily_vals), 0x0, "", HFILL }},
2311 { &hf_diameter_avp_data_v4addr,
2312 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
2313 NULL, 0x0, "", HFILL }},
2314 { &hf_diameter_avp_data_v6addr,
2315 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
2316 NULL, 0x0, "", HFILL }},
2317 { &hf_diameter_avp_data_time,
2318 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
2319 NULL, 0x0, "", HFILL }},
2320 { &hf_diameter_avp_diameter_uri,
2321 { "Diameter URI","diameter.avp.diameter_uri", FT_STRING, BASE_NONE,
2322 NULL, 0x0, "", HFILL }},
2323 { &hf_diameter_avp_session_id,
2324 { "Session ID","diameter.avp.session_id", FT_STRING, BASE_NONE,
2325 NULL, 0x0, "", HFILL }},
2326 { &hf_diameter_avp_public_id,
2327 { "Public ID","diameter.avp.public_id", FT_STRING, BASE_NONE,
2328 NULL, 0x0, "", HFILL }},
2329 { &hf_diameter_avp_private_id,
2330 { "Private ID","diameter.avp.private_id", FT_STRING, BASE_NONE,
2331 NULL, 0x0, "", HFILL }},
2334 static gint *ett[] = {
2336 &ett_diameter_flags,
2338 &ett_diameter_avp_flags,
2339 &ett_diameter_avpinfo
2341 module_t *diameter_module;
2342 gchar *default_diameterDictionary;
2344 proto_diameter = proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter");
2345 proto_register_field_array(proto_diameter, hf, array_length(hf));
2346 proto_register_subtree_array(ett, array_length(ett));
2348 /* Allow dissector to find be found by name. */
2349 new_register_dissector("diameter", dissect_diameter, proto_diameter);
2351 /* Register a configuration option for port */
2352 diameter_module = prefs_register_protocol(proto_diameter,
2353 proto_reg_handoff_diameter);
2354 /* Register a configuration option for Diameter version */
2355 prefs_register_enum_preference(diameter_module, "version", "Diameter version", "Standard version used for decoding", (gint *)&gbl_version, options, FALSE);
2357 prefs_register_uint_preference(diameter_module, "tcp.port",
2358 "Diameter TCP Port",
2359 "Set the TCP port for Diameter messages",
2361 &gbl_diameterTcpPort);
2362 prefs_register_uint_preference(diameter_module, "sctp.port",
2363 "Diameter SCTP Port",
2364 "Set the SCTP port for Diameter messages",
2366 &gbl_diameterSctpPort);
2368 * Build our default dictionary filename
2370 default_diameterDictionary = get_datafile_path(DICT_FN);
2373 * Now register the dictionary filename as a preference,
2374 * so it can be changed.
2376 gbl_diameterDictionary = default_diameterDictionary;
2377 prefs_register_string_preference(diameter_module, "dictionary.name",
2378 "Diameter XML Dictionary",
2379 "Set the dictionary used for Diameter messages",
2380 &gbl_diameterDictionary);
2383 * We don't need the default dictionary, so free it (a copy was made
2384 * of it in "gbl_diameterDictionary" by
2385 * "prefs_register_string_preference()").
2387 g_free(default_diameterDictionary);
2390 * Make use of the dictionary optional. Avoids error popups if xml library
2391 * or dictionary file aren't available.
2393 prefs_register_bool_preference(diameter_module, "dictionary.use",
2394 "Attempt to load/use Diameter XML Dictionary",
2395 "Only attempt to load and use the Diameter XML "
2396 "Dictionary when this option is selected",
2397 &gbl_use_xml_dictionary);
2399 /* Desegmentation */
2400 prefs_register_bool_preference(diameter_module, "desegment",
2401 "Reassemble Diameter messages\nspanning multiple TCP segments",
2402 "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
2403 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2404 &gbl_diameter_desegment);
2405 /* Allow zero as valid application ID */
2406 prefs_register_bool_preference(diameter_module, "allow_zero_as_app_id",
2407 "Allow 0 as valid application ID",
2408 "If set, the value 0 (zero) can be used as a valid "
2409 "application ID. This is used in experimental cases.",
2410 &allow_zero_as_app_id);
2411 /* Register some preferences we no longer support, so we can report
2412 them as obsolete rather than just illegal. */
2413 /* Suppress console output or not */
2414 prefs_register_bool_preference(diameter_module, "suppress_console_output",
2415 "Suppress console output for unknown AVP:s Flags etc.",
2416 "If console output for errors should be suppressed or not",
2417 &suppress_console_output);
2418 /* Register some preferences we no longer support, so we can report
2419 them as obsolete rather than just illegal. */
2420 prefs_register_obsolete_preference(diameter_module, "udp.port");
2421 prefs_register_obsolete_preference(diameter_module, "command_in_header");
2422 } /* proto_register_diameter */