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 (2208988800U)
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 = -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;
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;
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;
239 static guint gbl_diameterTcpPort=TCP_PORT_DIAMETER;
240 static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
242 /* desegmentation of Diameter over TCP */
243 static gboolean gbl_diameter_desegment = TRUE;
245 /* Allow zero as a valid application ID */
246 static gboolean allow_zero_as_app_id = TRUE;
248 /* Suppress console output at unknown AVP:s,Flags etc */
249 static gboolean suppress_console_output = TRUE;
251 static gboolean gbl_use_xml_dictionary = TRUE;
252 #define DICT_FN "diameter/dictionary.xml"
253 static const gchar *gbl_diameterDictionary;
255 typedef struct _e_diameterhdr_v16 {
256 guint32 versionLength;
257 guint32 flagsCmdCode;
263 typedef struct _e_diameterhdr_rfc {
264 guint32 versionLength;
265 guint32 flagsCmdCode;
266 guint32 applicationId;
271 typedef struct _e_avphdr {
273 guint32 avp_flagsLength;
274 guint32 avp_vendorId; /* optional */
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
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)
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 */
307 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
308 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr_rfc))
310 static Version_Type gbl_version = DIAMETER_RFC;
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);
316 * This routine will do a push-parse of the passed in
317 * filename. This was taken almost verbatum from
318 * the xmlsoft examples.
321 xmlParseFilePush( const char *filename, int checkValid
322 #ifndef WIRESHARK_XML_DO_VALIDITY_CHECKING
328 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
331 int res, size = 1024;
333 xmlParserCtxtPtr ctxt;
335 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
336 /* I wonder what kind of a performance hit this is? */
337 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
340 f = fopen(filename, "r");
342 report_open_failure(filename, errno, FALSE);
346 res = fread(chars, 1, 4, f);
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);
353 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
355 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
358 XmlStub.xmlFreeParserCtxt(ctxt);
362 #ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING
365 report_failure( "Error! Invalid xml in %s! Failed DTD check!",
372 } /* xmlParseFilePush */
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.
379 addStaticAVP(int code, const gchar *name, diameterDataType type, const value_string *values)
382 ValueName *vEntry=NULL;
385 /* Parse our values array, if we have one */
387 for (i=0; values[i].strptr != NULL; i++) {
388 ValueName *ve = NULL;
390 ve = g_malloc(sizeof(ValueName));
391 ve->name = strdup(values[i].strptr);
392 ve->value = values[i].value;
398 /* And, create the entry */
399 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
400 entry->name = g_strdup(name);
402 entry->vendorName = NULL;
404 entry->values = vEntry;
405 /* Unsigned32 might have values to ( Result-code 268 ) */
408 case DIAMETER_UNSIGNED32:
409 entry->type = DIAMETER_UNSIGNED32ENUM;
411 case DIAMETER_VENDOR_ID:
412 /* Ignore data from the xml file, use sminmpec.h vals */
415 entry->type = DIAMETER_ENUMERATED;
420 /* And, add it to the list */
421 entry->next = avpListHead;
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.
432 addVendorAVP(int code, const gchar *name, diameterDataType type, const value_string *values,int vendorId)
435 ValueName *vEntry=NULL;
439 /* Parse our values array, if we have one */
441 for (i=0; values[i].strptr != NULL; i++) {
442 ValueName *ve = NULL;
444 ve = g_malloc(sizeof(ValueName));
445 ve->name = strdup(values[i].strptr);
446 ve->value = values[i].value;
452 /* And, create the entry */
453 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
454 entry->name = g_strdup(name);
457 vendorName = diameter_vendor_to_str(vendorId, FALSE);
460 entry->vendorName = g_strdup(vendorName);
462 entry->vendorName = NULL;
464 entry->values = vEntry;
466 /* Unsigned32 might have values to ( Result-code 268 ) */
469 case DIAMETER_UNSIGNED32:
470 entry->type = DIAMETER_UNSIGNED32ENUM;
472 case DIAMETER_VENDOR_ID:
473 /* Ignore data from the xml file, use sminmpec.h vals */
476 entry->type = DIAMETER_ENUMERATED;
480 /* And, add it to the list */
481 entry->next = avpListHead;
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
493 xmlParseAVP(xmlNodePtr cur)
495 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
496 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
501 ValueName *vEntry=NULL;
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");
515 cur = cur->xmlChildrenNode;
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");
526 if (!valueName || !valueCode) {
527 report_failure( "Error, bad value on avp %s", name);
531 ve = g_malloc(sizeof(ValueName));
532 ve->name = strdup(valueName);
533 ve->value = atol(valueCode);
537 } else if (strcasecmp((const char *)cur->name, "grouped") == 0) {
538 /* WORK Recurse here for grouped AVPs */
545 * Check for the AVP Type.
548 for (i = 0; TypeValues[i].strptr; i++) {
549 if (!strcasecmp(type, TypeValues[i].strptr)) {
550 avpType = TypeValues[i].value;
555 if (TypeValues[i].strptr == NULL) {
556 report_failure( "Invalid Type field in dictionary! avp %s (%s)", name, type);
559 } else if (!vEntry) {
560 report_failure("Missing type/enum field in dictionary avpName=%s",
565 /* WORK - Handle flags -- for validation later */
568 /* And, create the entry */
569 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
570 entry->name = g_strdup(name);
571 entry->code = atol(code);
573 entry->vendorName = g_strdup(vendorName);
575 entry->vendorName = NULL;
576 entry->type = avpType;
577 entry->values = vEntry;
578 /* Unsigned32 might have values to ( Result-code 268 ) */
581 case DIAMETER_UNSIGNED32:
582 entry->type = DIAMETER_UNSIGNED32ENUM;
584 case DIAMETER_VENDOR_ID:
585 /* Ignore data from the xml file, use sminmpec.h vals */
588 entry->type = DIAMETER_ENUMERATED;
591 /* And, add it to the list */
592 entry->next = avpListHead;
599 * This routine will add a command to the list of commands.
602 addCommand(int code, const char *name, char *vendorId)
607 * Allocate the memory required for the dictionary.
609 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
612 report_failure("Unable to allocate memory");
617 * Allocate memory for the AVPName and copy the name to the
620 entry->name = g_strdup(name);
623 entry->vendorName = g_strdup(vendorId);
625 entry->vendorName = "None";
627 /* Add the entry to the list */
628 entry->next = commandListHead;
629 commandListHead = entry;
635 * This routine will parse the XML command, and add it to our
639 xmlParseCommand(xmlNodePtr cur)
641 char *name, *code, *vendorIdString;
646 name = XmlStub.xmlGetProp(cur, "name");
647 code = XmlStub.xmlGetProp(cur, "code");
649 g_warning("xmlParseCommand Name: %s code %s",name,code);
651 if (!name || !code) {
652 report_failure("Invalid command. Name or code missing!");
655 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
657 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
658 vendorIdString = NULL;
661 return (addCommand(atoi(code), name, vendorIdString));
662 } /* xmlParseCommand */
664 /* This routine adds an application to the name<-> id table */
666 dictionaryAddApplication(char *name, guint32 id)
668 ApplicationId *entry;
670 if (!name || (id == 0 && !allow_zero_as_app_id)) {
671 report_failure( "Diameter Error: Invalid application (name=%s, id=%d)",
674 } /* Sanity Checks */
676 entry = g_malloc(sizeof(ApplicationId));
678 report_failure( "Unable to allocate memory");
682 entry->name = g_strdup(name);
685 /* Add it to the list */
686 entry->next = ApplicationIdHead;
687 ApplicationIdHead = entry;
690 } /* dictionaryAddApplication */
693 * This routine will add a vendor to the vendors list
696 addVendor(int id, const gchar *name, const gchar *longName)
701 vendor=g_malloc(sizeof(VendorId));
707 vendor->name = g_strdup(name);
708 vendor->longName = g_strdup(longName);
709 vendor->next = vendorListHead;
710 vendorListHead = vendor;
716 * This routine will pars in a XML vendor entry.
719 xmlParseVendor(xmlNodePtr cur)
721 char *name=NULL, *code=NULL, *id=NULL;
723 /* First, get our properties */
724 id = XmlStub.xmlGetProp(cur, "vendor-id");
725 name = XmlStub.xmlGetProp(cur, "name");
726 code = XmlStub.xmlGetProp(cur, "code");
728 if (!id || !name || !code) {
729 report_failure( "Invalid vendor section. vendor-id, name, and code must be specified");
733 return (addVendor(atoi(code), id, name));
738 * This routine will either parse in the base protocol, or an application.
741 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
747 /* Add our application */
748 id = XmlStub.xmlGetProp(cur, "id");
749 name = XmlStub.xmlGetProp(cur, "name");
753 report_failure("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
754 name?name:"NULL", id?id:"NULL");
757 /* Add the application */
758 if (dictionaryAddApplication(name, (guint32)atol(id)) != 0) {
768 cur = cur->xmlChildrenNode;
769 while (cur != NULL) {
770 if (strcasecmp((const char *)cur->name, "avp") == 0) {
771 /* we have an avp!!! */
773 } else if (strcasecmp((const char *)cur->name, "vendor") == 0) {
774 /* we have a vendor */
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 . . . */
785 /* IF we got here, we're an error */
786 report_failure("Error! expecting an avp or a typedefn (got \"%s\")",
793 } /* xmlDictionaryParseSegment */
796 * The main xml parse routine. This will walk through an XML
797 * dictionary that has been parsed by libxml.
800 xmlDictionaryParse(xmlNodePtr cur)
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) {
812 } else if (strcasecmp((const char *)cur->name, "comment") == 0) {
815 report_failure( "Diameter: XML Expecting a base or an application (got \"%s\")",
824 } /* xmlDictionaryParse */
827 * This routine will call libxml to parse in the dictionary.
830 loadXMLDictionary(void)
836 * build an XML tree from the file;
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)*/
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
852 * Check the document is of the right kind
854 cur = XmlStub.xmlDocGetRootElement(doc);
856 report_failure("Diameter: Error: \"%s\": empty document",
857 gbl_diameterDictionary);
858 XmlStub.xmlFreeDoc(doc);
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);
869 * Ok, the dictionary has been parsed by libxml, and is valid.
870 * All we have to do now is read in our information.
872 if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
873 /* Error has already been printed */
877 /* Once we're done parsing, free up the xml memory */
878 XmlStub.xmlFreeDoc(doc);
882 } /* loadXMLDictionary */
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
890 initializeDictionaryDefaults(void)
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);
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);
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);
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,
923 } /* initializeDictionaryDefaults */
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.
931 initializeDictionary(void)
934 * First, empty the dictionary of any previous contents
937 ApplicationId *tmpApplicationId = ApplicationIdHead;
938 VendorId *tmpVendorId = vendorListHead;
939 CommandCode *tmpCommandCode = commandListHead;
940 avpInfo *tmpAvpInfo = avpListHead;
942 /* ApplicationId list */
943 while (tmpApplicationId != NULL) {
944 g_free(tmpApplicationId->name);
945 tmpApplicationId = tmpApplicationId->next;
947 ApplicationIdHead = NULL;
950 while (tmpVendorId != NULL) {
951 g_free(tmpVendorId->name);
952 g_free(tmpVendorId->longName);
953 tmpVendorId = tmpVendorId->next;
955 vendorListHead = NULL;
957 /* CommandCode list */
958 while (tmpCommandCode != NULL) {
959 g_free(tmpCommandCode->name);
960 g_free(tmpCommandCode->vendorName);
961 tmpCommandCode = tmpCommandCode->next;
963 commandListHead = NULL;
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;
974 tmpAvpInfo = tmpAvpInfo->next;
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.
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();
992 initializeDictionaryDefaults();
995 } /* initializeDictionary */
1000 * These routines manipulate the diameter structures.
1003 /* return vendor string, based on the id */
1005 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
1009 for (probe=vendorListHead; probe; probe=probe->next) {
1010 if (vendorId == probe->id) {
1012 return probe->longName;
1018 buffer=ep_alloc(64);
1019 g_snprintf(buffer, 64, "Vendor 0x%08x", vendorId);
1021 } /*diameter_vendor_to_str */
1023 /* return command string, based on the code */
1025 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
1029 gchar *vendorName=NULL;
1031 switch(gbl_version) {
1033 /* In draft-v16 version, command code is depending on vendorID */
1035 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1037 for (probe=commandListHead; probe; probe=probe->next) {
1038 if (commandCode == probe->code) {
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))
1048 /* With no vendor id, the Command's entry should be "None" */
1049 if (!strcmp(probe->vendorName, "None")) {
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);
1065 /* In RFC3588 version, command code is independant on vendorID */
1066 for (probe=commandListHead; probe; probe=probe->next) {
1067 if (commandCode == probe->code) {
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);
1082 }/*diameter_command_to_str */
1084 /* return application string, based on the id */
1086 diameter_app_to_str(guint32 appId) {
1087 ApplicationId *probe;
1090 for (probe=ApplicationIdHead; probe; probe=probe->next) {
1091 if (appId == probe->id) {
1096 buffer=ep_alloc(64);
1097 g_snprintf(buffer, 64, "Unknown");
1099 } /*diameter_app_to_str */
1101 /* return an avp type, based on the code */
1102 static diameterDataType
1103 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
1105 gchar *vendorName=NULL;
1108 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1110 for (probe=avpListHead; probe; probe=probe->next) {
1111 if (avpCode == probe->code) {
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)))
1122 /* No Vendor ID -- vendorName should be null */
1123 if (!probe->vendorName)
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,
1134 return DIAMETER_OCTET_STRING;
1135 } /* diameter_avp_get_type */
1137 /* return an avp name from the code */
1139 diameter_avp_get_name(guint32 avpCode, guint32 vendorId, gboolean *AVPFound)
1143 gchar *vendorName=NULL;
1144 *AVPFound = TRUE; /* will set to FALSE only if fail to match */
1147 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1149 for (probe=avpListHead; probe; probe=probe->next) {
1150 if (avpCode == probe->code) {
1152 /* Now check the vendor name */
1153 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
1157 /* Print explanation */
1158 if (!suppress_console_output) {
1159 g_warning("AVP %u: Found vendor name (%s) didn't match definition (%s)",
1161 vendorName ? vendorName : "(null)",
1162 probe->vendorName ? probe->vendorName : "(null)");
1167 /* No Vendor ID -- vendorName should be null */
1168 if (!probe->vendorName)
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)");
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);
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);
1190 } /* diameter_avp_get_name */
1192 static const gchar *
1193 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
1196 gchar *vendorName=NULL;
1199 vendorName = diameter_vendor_to_str(vendorId, FALSE);
1201 for (probe=avpListHead; probe; probe=probe->next) {
1202 if (avpCode == probe->code) {
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))) {
1210 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
1211 if (avpValue == vprobe->value) {
1212 return vprobe->name;
1215 return "(Unknown value)";
1218 if (!probe->vendorName) {
1220 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
1221 if (avpValue == vprobe->value) {
1222 return vprobe->name;
1225 return "(Unknown value)";
1230 /* We didn't find the avp */
1231 return "(Unknown AVP)";
1232 } /* diameter_avp_get_value */
1235 /* Code to actually dissect the packets */
1238 check_diameter(tvbuff_t *tvb)
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 */
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
1255 dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1258 /* Set up structures needed to add the protocol subtree and manage it */
1261 proto_tree *flags_tree;
1263 proto_tree *diameter_tree;
1264 e_diameterhdr_v16 dh;
1265 e_diameterhdr_rfc dh2;
1268 proto_tree *avp_tree;
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;
1278 static int initialized=FALSE;
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];
1286 * Only parse in dictionary if there are diameter packets to
1288 * Keeps track of preference settings and frees/reinitializes the
1289 * dictionary when appropriate.
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();
1300 /* Record current preference settings */
1301 previous_use_xml_dictionary = gbl_use_xml_dictionary;
1302 strncpy(previous_diameterDictionary, gbl_diameterDictionary, MAX_DICT_NAME_SIZE);
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);
1311 /* Copy our header */
1312 switch(gbl_version) {
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);
1322 vendorName=diameter_vendor_to_str(dh.vendorId, TRUE);
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);
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);
1347 applicationName="None";
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);
1358 /* Set up our flags */
1359 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1363 #define FLAG_STR_LEN 64
1364 flagbuf=ep_alloc(FLAG_STR_LEN);
1367 for (i = 0; i < 8; i++) {
1371 fslen+=MIN(FLAG_STR_LEN-fslen,
1372 g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, ", "));
1374 fslen+=MIN(FLAG_STR_LEN-fslen,
1375 g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, "%s", fstr[i]));
1379 if (flagstr[0] == 0) {
1384 /* Set up our commandString */
1385 switch(gbl_version) {
1387 commandString=diameter_command_to_str(commandCode, dh.vendorId);
1390 /* FIXME: in RFC, is applicationID needed to decode the command code? */
1391 commandString=diameter_command_to_str(commandCode, dh2.applicationId);
1395 if (flags & DIAM_FLAGS_R)
1396 commandStringType="Request";
1398 commandStringType="Answer";
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);
1408 /* And, check our reserved flags/version */
1409 if ((flags & DIAM_FLAGS_RESERVED) ||
1411 if ( suppress_console_output == FALSE )
1412 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1417 if (check_col(pinfo->cinfo, COL_INFO)) {
1418 switch(gbl_version) {
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":"",
1426 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
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);
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":"",
1441 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
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);
1453 /* In the interest of speed, if "tree" is NULL, don't do any work not
1454 necessary to generate protocol tree items. */
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);
1463 proto_tree_add_uint(diameter_tree,
1464 hf_diameter_version,
1471 proto_tree_add_uint(diameter_tree,
1472 hf_diameter_length, tvb,
1473 offset, 3, pktLength);
1477 tf = proto_tree_add_uint_format_value(diameter_tree, hf_diameter_flags, tvb,
1478 offset, 1, flags, "0x%02x (%s)", flags,
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);
1493 proto_tree_add_uint_format_value(diameter_tree, hf_diameter_code,
1494 tvb, offset, 3, commandCode, "%s-%s (%d)",
1495 commandString, commandStringType, commandCode);
1498 switch(gbl_version) {
1502 proto_tree_add_item(diameter_tree, hf_diameter_vendor_id, tvb, offset, 4, FALSE);
1504 /* Hop-by-hop Identifier */
1505 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1506 tvb, offset, 4, dh.hopByHopId);
1508 /* End-to-end Identifier */
1509 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1510 tvb, offset, 4, dh.endToEndId);
1514 /* Application Id */
1515 proto_tree_add_item(diameter_tree, hf_diameter_application_id, tvb, offset, 4, FALSE);
1517 /* Hop-by-hop Identifier */
1518 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1519 tvb, offset, 4, dh2.hopByHopId);
1521 /* End-to-end Identifier */
1522 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1523 tvb, offset, 4, dh2.endToEndId);
1529 /* If we have a bad packet, don't bother trying to parse the AVPs */
1534 /* Start looking at the AVPS */
1535 /* Make the next tvbuff */
1537 /* Update the lengths */
1538 switch(gbl_version) {
1540 avplength= pktLength - sizeof(e_diameterhdr_v16);
1543 avplength= pktLength - sizeof(e_diameterhdr_rfc);
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");
1552 avp_tree = proto_item_add_subtree(avptf,
1554 if (avp_tree != NULL) {
1555 dissect_avps( avp_tvb, pinfo, avp_tree);
1559 } /* dissect_diameter_common */
1563 get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1565 /* Get the length of the Diameter packet. */
1566 return tvb_get_ntoh24(tvb, offset + 1);
1570 dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1572 if (!check_diameter(tvb))
1574 dissect_diameter_common(tvb, pinfo, tree);
1575 return tvb_length(tvb);
1579 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1581 tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
1582 get_diameter_pdu_len, dissect_diameter_common);
1583 } /* dissect_diameter_tcp */
1586 * Call the mip_dissector, after saving our pinfo variables
1587 * so it doesn't write to our column display.
1590 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1591 size_t offset, size_t length)
1593 static dissector_handle_t mip_handle;
1594 static int mipInitialized=FALSE;
1596 address save_dl_src;
1597 address save_dl_dst;
1598 address save_net_src;
1599 address save_net_dst;
1602 gboolean save_in_error_pkt;
1604 if (!mipInitialized) {
1605 mip_handle = find_dissector("mip");
1606 mipInitialized=TRUE;
1609 mip_tvb = tvb_new_subset(tvb, offset,
1610 MIN(length, tvb_length(tvb)-offset),
1613 /* The contained packet is a MIP registration request;
1614 dissect it with the MIP dissector. */
1615 col_set_writable(pinfo->cinfo, FALSE);
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;
1629 call_dissector(mip_handle, mip_tvb, pinfo, tree);
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;
1641 } /* safe_dissect_mip */
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
1647 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1649 /* adds the attribute value pairs to the tree */
1651 const gchar *avpTypeString;
1652 const gchar *avpNameString;
1653 const gchar *valstr;
1655 const gchar *vendorName;
1658 proto_tree *avpi_tree;
1660 tvbuff_t *group_tvb;
1661 proto_tree *group_tree;
1662 proto_item *grouptf;
1665 int BadPacket = FALSE;
1669 proto_tree *flags_tree;
1671 gint32 packetLength;
1672 size_t avpDataLength;
1674 const gchar *flagstr="<None>";
1675 const gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1679 packetLength = tvb_length(tvb);
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");
1688 /* Spin around until we run out of packet */
1689 while (packetLength > 0 )
1691 gboolean AVP_code_found;
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);
1699 /* Don't even bother trying to parse a short packet. */
1703 /* Copy our header */
1704 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1706 /* Fix the byte ordering */
1707 avph.avp_code = g_ntohl(avph.avp_code);
1708 avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1710 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1711 avpLength = avph.avp_flagsLength & 0x00ffffff;
1713 /* Set up our flags string */
1714 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1718 #define FLAG_STR_LEN 64
1719 flagbuf=ep_alloc(FLAG_STR_LEN);
1722 for (i = 0; i < 8; i++) {
1726 fslen+=MIN(FLAG_STR_LEN-fslen,
1727 g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, ", "));
1729 fslen+=MIN(FLAG_STR_LEN-fslen,
1730 g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, "%s", fstr[i]));
1734 if (flagstr[0] == 0) {
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);
1743 hdrLength = sizeof(e_avphdr);
1746 hdrLength = sizeof(e_avphdr) - sizeof(guint32);
1751 vendorName=diameter_vendor_to_str(vendorId, TRUE);
1756 /* Check for bad length */
1757 if (avpLength < MIN_AVP_SIZE ||
1758 ((long)avpLength > packetLength))
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);
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,"
1772 flags, AVP_FLAGS_RESERVED);
1773 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit
1779 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1782 fixAmt = 4 - (avpLength % 4);
1786 /* shrink our packetLength */
1787 packetLength = packetLength - (avpLength + fixAmt);
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) ",
1797 /* Make avp Name & type */
1798 avpTypeString=val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1800 "Unknown-Type: 0x%08x");
1801 avpNameString=diameter_avp_get_name(avph.avp_code, vendorId, &AVP_code_found);
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);
1810 avpi_tree = proto_item_add_subtree(avptf, ett_diameter_avpinfo);
1812 if (avpi_tree !=NULL)
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)
1821 expert_add_info_format(pinfo, ti,
1822 PI_UNDECODED, PI_NOTE,
1823 "AVP info not available (code %u)",
1828 tf = proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_flags, tvb,
1829 offset, 1, flags, "0x%02x (%s)", flags,
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);
1842 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1843 tvb, offset, 3, avpLength);
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);
1852 avpDataLength = avpLength - hdrLength;
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.
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)");
1867 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
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),
1879 group_tree = proto_item_add_subtree(grouptf, ett_diameter_avp);
1881 group_tvb = tvb_new_subset(tvb, offset,
1882 MIN(avpDataLength, tvb_length(tvb)-offset),
1884 if (group_tree != NULL) {
1885 dissect_avps( group_tvb, pinfo, group_tree);
1889 case DIAMETER_IDENTITY:
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,
1898 (int)avpDataLength, data);
1901 case DIAMETER_UTF8STRING:
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",
1910 (int)avpDataLength, data);
1913 case DIAMETER_IP_ADDRESS:
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);
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)",
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) {
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);
1954 } else if (tvb_get_ntohs(tvb, offset) == 0x0002) {
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);
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));
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);
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)",
1997 case DIAMETER_UNSIGNED32:
1998 if (avpDataLength == 4) {
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);
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)",
2017 case DIAMETER_UNSIGNED32ENUM:
2018 if (avpDataLength == 4) {
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,
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)",
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);
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)",
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);
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)",
2072 if (avpDataLength == 4) {
2073 guint32 ntp_timestamp_secs;
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;
2083 gmtp = gmtime(&data.secs);
2084 buffer=ep_alloc(64);
2085 strftime(buffer, 64, "%a, %d %b %Y %H:%M:%S UTC", gmtp);
2087 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
2088 tvb, offset, avpDataLength, &data,
2089 "Time: %s", buffer);
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");
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)",
2108 case DIAMETER_ENUMERATED:
2109 if (avpDataLength == 4) {
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,
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)",
2130 case DIAMETER_VENDOR_ID:
2131 if (avpDataLength == 4) {
2132 proto_tree_add_item(avpi_tree, hf_diameter_vendor_id, tvb, offset, avpDataLength, FALSE);
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)",
2145 case DIAMETER_APPLICATION_ID:
2146 if (avpDataLength == 4) {
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);
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)",
2167 case DIAMETER_MIP_REG_REQ:
2168 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
2172 proto_tree_add_item(avpi_tree, hf_diameter_avp_diameter_uri,
2173 tvb, offset, avpDataLength, FALSE);
2176 case DIAMETER_SESSION_ID:
2177 proto_tree_add_item(avpi_tree, hf_diameter_avp_session_id,
2178 tvb, offset, avpDataLength, FALSE);
2181 case DIAMETER_PUBLIC_ID:
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.
2188 dfilter_store_sip_from_addr(tvb, avpi_tree, offset, avpDataLength);
2191 case DIAMETER_PRIVATE_ID:
2192 proto_tree_add_item(avpi_tree, hf_diameter_avp_private_id,
2193 tvb, offset, avpDataLength, FALSE);
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");
2204 } /* avpi_tree != null */
2205 offset += (avpLength - hdrLength);
2206 offset += fixAmt; /* fix byte alignment */
2208 } /* dissect_avps */
2213 proto_reg_handoff_diameter(void)
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;
2222 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
2224 diameter_handle = new_create_dissector_handle(dissect_diameter,
2228 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
2229 dissector_delete("sctp.port", SctpPort, diameter_handle);
2232 /* set port for future deletes */
2233 TcpPort=gbl_diameterTcpPort;
2234 SctpPort=gbl_diameterSctpPort;
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);
2242 /* registration with the filtering engine */
2244 proto_register_diameter(void)
2246 static hf_register_info hf[] = {
2247 { &hf_diameter_version,
2248 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
2250 { &hf_diameter_length,
2251 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
2254 { &hf_diameter_flags,
2255 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
2257 { &hf_diameter_flags_request,
2258 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
2260 { &hf_diameter_flags_proxyable,
2261 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
2263 { &hf_diameter_flags_error,
2264 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
2266 { &hf_diameter_flags_T,
2267 { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&flags_set_truth),DIAM_FLAGS_T,
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 }},
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),
2288 { &hf_diameter_application_id,
2289 { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC, VALS(diameter_application_id_vals),
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 }},
2299 { "AVP","diameter.avp", FT_BYTES, BASE_HEX,
2300 NULL, 0x0, "", HFILL }},
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 }},
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,
2316 { &hf_diameter_avp_flags_mandatory,
2317 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
2319 { &hf_diameter_avp_flags_protected,
2320 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
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 }},
2384 static gint *ett[] = {
2386 &ett_diameter_flags,
2388 &ett_diameter_avp_flags,
2389 &ett_diameter_avpinfo
2391 module_t *diameter_module;
2392 gchar *default_diameterDictionary;
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));
2398 /* Allow dissector to find be found by name. */
2399 new_register_dissector("diameter", dissect_diameter, proto_diameter);
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);
2407 prefs_register_uint_preference(diameter_module, "tcp.port",
2408 "Diameter TCP Port",
2409 "Set the TCP port for Diameter messages",
2411 &gbl_diameterTcpPort);
2412 prefs_register_uint_preference(diameter_module, "sctp.port",
2413 "Diameter SCTP Port",
2414 "Set the SCTP port for Diameter messages",
2416 &gbl_diameterSctpPort);
2418 * Build our default dictionary filename
2420 default_diameterDictionary = get_datafile_path(DICT_FN);
2423 * Now register the dictionary filename as a preference,
2424 * so it can be changed.
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);
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()").
2437 g_free(default_diameterDictionary);
2440 * Make use of the dictionary optional. Avoids error popups if xml library
2441 * or dictionary file aren't available.
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);
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 */