2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.44 2002/01/31 01:55:14 guy Exp $
6 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
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.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
45 #include <epan/filesystem.h>
47 #include <epan/packet.h>
48 #include <epan/resolv.h>
51 #ifdef NEED_SNPRINTF_H
52 # include "snprintf.h"
55 /* This must be defined before we include packet-diameter-defs.h */
57 /* Valid data types */
60 DIAMETER_OCTET_STRING = 1,
71 DIAMETER_IP_ADDRESS, /* OctetString */
72 DIAMETER_TIME, /* Integer 32 */
73 DIAMETER_UTF8STRING, /* OctetString */
74 DIAMETER_IDENTITY, /* OctetString */
75 DIAMETER_ENUMERATED, /* Integer 32 */
76 DIAMETER_IP_FILTER_RULE, /* OctetString */
77 DIAMETER_QOS_FILTER_RULE, /* OctetString */
78 DIAMETER_MIP_REG_REQ, /* OctetString */
79 DIAMETER_VENDOR_ID, /* Integer32 */
80 DIAMETER_APPLICATION_ID
85 static value_string TypeValues[]={
86 { DIAMETER_OCTET_STRING, "OctetString" },
87 { DIAMETER_INTEGER32, "Integer32" },
88 { DIAMETER_INTEGER64, "Integer64" },
89 { DIAMETER_UNSIGNED32, "Unsigned32" },
90 { DIAMETER_UNSIGNED64, "Unsigned64" },
91 { DIAMETER_FLOAT32, "Float32" },
92 { DIAMETER_FLOAT64, "Float64" },
93 { DIAMETER_FLOAT128, "Float128" },
94 { DIAMETER_GROUPED, "Grouped" },
95 { DIAMETER_IP_ADDRESS, "IpAddress" },
96 { DIAMETER_TIME, "Time" },
97 { DIAMETER_UTF8STRING, "UTF8String" },
98 { DIAMETER_IDENTITY, "DiameterIdentity" },
99 { DIAMETER_ENUMERATED, "Enumerated" },
100 { DIAMETER_IP_FILTER_RULE, "IPFilterRule" },
101 { DIAMETER_QOS_FILTER_RULE, "QOSFilterRule" },
102 { DIAMETER_MIP_REG_REQ, "MIPRegistrationRequest"},
103 { DIAMETER_VENDOR_ID, "VendorId"},
104 { DIAMETER_APPLICATION_ID, "AppId"},
108 typedef struct value_name {
111 struct value_name *next;
114 typedef struct old_avp_info {
117 diameterDataType type;
118 value_string *values;
121 typedef struct avp_info {
125 diameterDataType type;
127 struct avp_info *next;
130 typedef struct command_code {
134 struct command_code *next;
137 typedef struct vendor_id {
141 struct vendor_id *next;
144 typedef struct application_id {
147 struct application_id *next;
150 static avpInfo *avpListHead=NULL;
151 static VendorId *vendorListHead=NULL;
152 static CommandCode *commandListHead=NULL;
153 static ApplicationId *ApplicationIdHead=NULL;
156 #include "packet-diameter-defs.h"
158 #define NTP_TIME_DIFF (2208988800UL)
160 #define TCP_PORT_DIAMETER 1812
161 #define SCTP_PORT_DIAMETER 1812
163 static const true_false_string flags_set_truth = {
168 static const true_false_string reserved_set = {
169 "*** Error! Reserved Bit is Set",
172 static int proto_diameter = -1;
173 static int hf_diameter_length = -1;
174 static int hf_diameter_code = -1;
175 static int hf_diameter_hopbyhopid =-1;
176 static int hf_diameter_endtoendid =-1;
177 static int hf_diameter_reserved = -1;
178 static int hf_diameter_version = -1;
179 static int hf_diameter_vendor_id = -1;
180 static int hf_diameter_flags = -1;
181 static int hf_diameter_flags_request = -1;
182 static int hf_diameter_flags_proxyable = -1;
183 static int hf_diameter_flags_error = -1;
184 static int hf_diameter_flags_reserved3 = -1;
185 static int hf_diameter_flags_reserved4 = -1;
186 static int hf_diameter_flags_reserved5 = -1;
187 static int hf_diameter_flags_reserved6 = -1;
188 static int hf_diameter_flags_reserved7 = -1;
190 static int hf_diameter_avp_code = -1;
191 static int hf_diameter_avp_length = -1;
192 static int hf_diameter_avp_reserved = -1;
193 static int hf_diameter_avp_flags = -1;
194 static int hf_diameter_avp_flags_vendor_specific = -1;
195 static int hf_diameter_avp_flags_mandatory = -1;
196 static int hf_diameter_avp_flags_protected = -1;
197 static int hf_diameter_avp_flags_reserved3 = -1;
198 static int hf_diameter_avp_flags_reserved4 = -1;
199 static int hf_diameter_avp_flags_reserved5 = -1;
200 static int hf_diameter_avp_flags_reserved6 = -1;
201 static int hf_diameter_avp_flags_reserved7 = -1;
202 static int hf_diameter_avp_vendor_id = -1;
205 static int hf_diameter_avp_data_uint32 = -1;
206 static int hf_diameter_avp_data_int32 = -1;
207 static int hf_diameter_avp_data_uint64 = -1;
208 static int hf_diameter_avp_data_int64 = -1;
209 static int hf_diameter_avp_data_bytes = -1;
210 static int hf_diameter_avp_data_string = -1;
211 static int hf_diameter_avp_data_v4addr = -1;
212 static int hf_diameter_avp_data_v6addr = -1;
213 static int hf_diameter_avp_data_time = -1;
215 static gint ett_diameter = -1;
216 static gint ett_diameter_flags = -1;
217 static gint ett_diameter_avp = -1;
218 static gint ett_diameter_avp_flags = -1;
219 static gint ett_diameter_avpinfo = -1;
221 static char gbl_diameterString[200];
222 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
223 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
225 /* desegmentation of Diameter over TCP */
226 static gboolean gbl_diameter_desegment = TRUE;
228 #define DIAMETER_DIR "diameter"
229 #define DICT_FN "dictionary.xml"
230 static gchar *gbl_diameterDictionary = NULL;
232 typedef struct _e_diameterhdr {
233 guint32 versionLength;
234 guint32 flagsCmdCode;
240 typedef struct _e_avphdr {
242 guint32 avp_flagsLength;
243 guint32 avp_vendorId; /* optional */
246 /* Diameter Header Flags */
247 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
248 #define DIAM_FLAGS_R 0x80
249 #define DIAM_FLAGS_P 0x40
250 #define DIAM_FLAGS_E 0x20
251 #define DIAM_FLAGS_RESERVED3 0x10
252 #define DIAM_FLAGS_RESERVED4 0x08
253 #define DIAM_FLAGS_RESERVED5 0x04
254 #define DIAM_FLAGS_RESERVED6 0x02
255 #define DIAM_FLAGS_RESERVED7 0x01
256 #define DIAM_FLAGS_RESERVED 0x1f
258 #define DIAM_LENGTH_MASK 0x00ffffffl
259 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
260 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
261 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
262 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
263 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
265 /* Diameter AVP Flags */
266 #define AVP_FLAGS_P 0x20
267 #define AVP_FLAGS_V 0x80
268 #define AVP_FLAGS_M 0x40
269 #define AVP_FLAGS_RESERVED3 0x10
270 #define AVP_FLAGS_RESERVED4 0x08
271 #define AVP_FLAGS_RESERVED5 0x04
272 #define AVP_FLAGS_RESERVED6 0x02
273 #define AVP_FLAGS_RESERVED7 0x01
274 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
276 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
277 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
279 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
283 * This routine will do a push-parse of the passed in
284 * filename. This was taken almost verbatum from
285 * the xmlsoft examples.
288 xmlParseFilePush( char *filename, int checkValid) {
292 int res, size = 1024;
294 xmlParserCtxtPtr ctxt;
296 /* I wonder what kind of a performance hit this is? */
297 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
299 f = fopen(filename, "r");
301 g_warning("Diameter: Unable to open %s", filename);
305 res = fread(chars, 1, 4, f);
307 ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
308 chars, res, filename);
309 while ((res = fread(chars, 1, size-1, f)) > 0) {
310 XmlStub.xmlParseChunk(ctxt, chars, res, 0);
312 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
315 XmlStub.xmlFreeParserCtxt(ctxt);
321 g_warning( "Error! Invalid xml in %s! Failed DTD check!",
326 } /* xmlParseFilePush */
329 * This routine will add a static avp to the avp list. It is
330 * only called when the XML dictionary fails to load properly.
333 addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
336 ValueName *vEntry=NULL;
339 /* Parse our values array, if we have one */
341 for (i=0; values[i].strptr != NULL; i++) {
342 ValueName *ve = NULL;
344 ve = g_malloc(sizeof(ValueName));
345 ve->name = strdup(values[i].strptr);
346 ve->value = values[i].value;
352 /* And, create the entry */
353 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
354 entry->name = g_strdup(name);
356 entry->vendorName = NULL;
358 entry->values = vEntry;
360 entry->type = DIAMETER_INTEGER32;
362 /* And, add it to the list */
363 entry->next = avpListHead;
371 * This routine will parse an XML avp entry, and add it to our
372 * avp list. If any values are present in the avp, it will
376 xmlParseAVP(xmlDocPtr doc, xmlNodePtr cur)
378 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
379 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
384 ValueName *vEntry=NULL;
387 /* First, get our properties */
388 name = XmlStub.xmlGetProp(cur, "name");
389 description = XmlStub.xmlGetProp(cur, "description");
390 code = XmlStub.xmlGetProp(cur, "code");
391 mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
392 mandatory = XmlStub.xmlGetProp(cur, "mandatory");
393 protected = XmlStub.xmlGetProp(cur, "protected");
394 vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
395 vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
396 constrained = XmlStub.xmlGetProp(cur, "constrained");
398 cur = cur->xmlChildrenNode;
400 while (cur != NULL ) {
401 if (!strcasecmp((char *)cur->name, "type")) {
402 type = XmlStub.xmlGetProp(cur, "type-name");
404 if (!strcasecmp((char *)cur->name, "enum")) {
405 char *valueName=NULL, *valueCode=NULL;
406 ValueName *ve = NULL;
407 valueName = XmlStub.xmlGetProp(cur, "name");
408 valueCode = XmlStub.xmlGetProp(cur, "code");
410 if (!valueName || !valueCode) {
411 g_warning( "Error, bad value on avp %s", name);
415 ve = g_malloc(sizeof(ValueName));
416 ve->name = strdup(valueName);
417 ve->value = atol(valueCode);
422 if (!strcasecmp((char *)cur->name, "grouped")) {
423 /* WORK Recurse here for grouped AVPs */
430 * Check for the AVP Type.
433 for (i = 0; TypeValues[i].strptr; i++) {
434 if (!strcasecmp(type, TypeValues[i].strptr)) {
435 avpType = TypeValues[i].value;
440 if (TypeValues[i].strptr == NULL) {
441 g_warning( "Invalid Type field in dictionary! avp %s (%s)", name, type);
444 } else if (!vEntry) {
445 g_warning("Missing type/enum field in dictionary avpName=%s",
450 /* WORK - Handle flags -- for validation later */
453 /* And, create the entry */
454 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
455 entry->name = g_strdup(name);
456 entry->code = atol(code);
458 entry->vendorName = g_strdup(vendorName);
460 entry->vendorName = NULL;
461 entry->type = avpType;
462 entry->values = vEntry;
464 entry->type = DIAMETER_INTEGER32;
466 /* And, add it to the list */
467 entry->next = avpListHead;
474 * This routine will add a command to the list of commands.
477 addCommand(int code, char *name, char *vendorId)
482 * Allocate the memory required for the dictionary.
484 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
487 g_warning("Unable to allocate memory");
492 * Allocate memory for the AVPName and copy the name to the
495 entry->name = g_strdup(name);
498 entry->vendorName = g_strdup(vendorId);
500 entry->vendorName = "None";
502 /* Add the entry to the list */
503 entry->next = commandListHead;
504 commandListHead = entry;
510 * This routine will parse the XML command, and add it to our
514 xmlParseCommand(xmlDocPtr doc, xmlNodePtr cur)
516 char *name, *code, *vendorIdString;
521 name = XmlStub.xmlGetProp(cur, "name");
522 code = XmlStub.xmlGetProp(cur, "code");
523 if (!name || !code) {
524 g_warning("Invalid command. Name or code missing!");
527 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
529 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
530 vendorIdString = NULL;
533 return (addCommand(atoi(code), name, vendorIdString));
534 } /* xmlParseCommand */
536 /* This routine adds an application to the name<-> id table */
538 dictionaryAddApplication(char *name, int id)
540 ApplicationId *entry;
542 if (!name || (id <= 0)) {
543 g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
546 } /* Sanity Checks */
548 entry = g_malloc(sizeof(ApplicationId));
550 g_warning( "Unable to allocate memory");
554 entry->name = g_strdup(name);
557 /* Add it to the list */
558 entry->next = ApplicationIdHead;
559 ApplicationIdHead = entry;
562 } /* dictionaryAddApplication */
565 * This routine will add a vendor to the vendors list
568 addVendor(int id, gchar *name, gchar *longName)
573 vendor=g_malloc(sizeof(VendorId));
579 vendor->name = g_strdup(name);
580 vendor->longName = g_strdup(longName);
581 vendor->next = vendorListHead;
582 vendorListHead = vendor;
588 * This routine will pars in a XML vendor entry.
591 xmlParseVendor(xmlDocPtr doc, xmlNodePtr cur)
593 char *name=NULL, *code=NULL, *id=NULL;
595 /* First, get our properties */
596 id = XmlStub.xmlGetProp(cur, "vendor-id");
597 name = XmlStub.xmlGetProp(cur, "name");
598 code = XmlStub.xmlGetProp(cur, "code");
600 if (!id || !name || !code) {
601 g_warning( "Invalid vendor section. vendor-id, name, and code must be specified");
605 return (addVendor(atoi(code), id, name));
609 * This routine will either parse in the base protocol, or an application.
612 xmlDictionaryParseSegment(xmlDocPtr doc, xmlNodePtr cur, int base)
618 /* Add our application */
619 id = XmlStub.xmlGetProp(cur, "id");
620 name = XmlStub.xmlGetProp(cur, "name");
624 g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
625 name?name:"NULL", id?id:"NULL");
629 /* Add the application */
630 if (dictionaryAddApplication(name, atol(id)) != 0) {
640 cur = cur->xmlChildrenNode;
641 while (cur != NULL) {
642 if (!strcasecmp((char *)cur->name, "avp")) {
643 /* we have an avp!!! */
644 xmlParseAVP(doc, cur);
645 } else if (!strcasecmp((char *)cur->name, "vendor")) {
646 /* we have a vendor */
647 xmlParseVendor(doc, cur);
648 /* For now, ignore typedefn and text */
649 } else if (!strcasecmp((char *)cur->name, "command")) {
650 /* Found a command */
651 xmlParseCommand(doc,cur);
652 } else if (!strcasecmp((char *)cur->name, "text")) {
653 } else if (!strcasecmp((char *)cur->name, "comment")) {
654 } else if (!strcasecmp((char *)cur->name, "typedefn")) {
655 /* WORK -- parse in valid types . . . */
657 /* IF we got here, we're an error */
658 g_warning("Error! expecting an avp or a typedefn (got \"%s\")",
665 } /* xmlDictionaryParseSegment */
668 * The main xml parse routine. This will walk through an XML
669 * dictionary that has been parsed by libxml.
672 xmlDictionaryParse(xmlDocPtr doc, xmlNodePtr cur)
674 /* We should expect a base protocol, followed by multiple applicaitons */
675 while (cur != NULL) {
676 if (!strcasecmp((char *)cur->name, "base")) {
677 /* Base protocol. Descend and parse */
678 xmlDictionaryParseSegment(doc, cur, 1);
679 } else if (!strcasecmp((char *)cur->name, "application")) {
680 /* Application. Descend and parse */
681 xmlDictionaryParseSegment(doc, cur, 0);
682 } else if (!strcasecmp((char *)cur->name, "text")) {
685 g_warning( "Diameter: XML Expecting a base or an application (got \"%s\")",
694 } /* xmlDictionaryParse */
697 * This routine will call libxml to parse in the dictionary.
706 * build an XML tree from a the file;
708 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
709 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
710 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
712 /* Check for invalid xml */
714 g_warning("Diameter: Unable to parse xmldictionary %s",
715 gbl_diameterDictionary);
720 * Check the document is of the right kind
722 cur = XmlStub.xmlDocGetRootElement(doc);
724 g_warning("Diameter: Error: \"%s\": empty document",
725 gbl_diameterDictionary);
726 XmlStub.xmlFreeDoc(doc);
729 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
730 g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
731 gbl_diameterDictionary);
732 XmlStub.xmlFreeDoc(doc);
737 * Ok, the dictionary has been parsed by libxml, and is valid.
738 * All we have to do now is read in our information.
740 if (xmlDictionaryParse(doc, cur->xmlChildrenNode) != 0) {
741 /* Error has already been printed */
745 /* Once we're done parsing, free up the xml memory */
746 XmlStub.xmlFreeDoc(doc);
750 } /* loadXMLDictionary */
753 * Fallback routine. In the event of ANY error when loading the XML
754 * dictionary, this routine will populate the new avp list structures
755 * with the old static data from packet-diameter-defs.h
758 initializeDictionaryDefaults()
762 /* Add static vendors to list */
763 for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
764 addVendor(diameter_vendor_specific_vendors[i].value,
765 diameter_vendor_specific_vendors[i].strptr,
766 diameter_vendor_specific_vendors[i].strptr);
768 /* Add static commands to list. */
769 for(i=0; diameter_command_code_vals[i].strptr; i++) {
770 addCommand(diameter_command_code_vals[i].value,
771 diameter_command_code_vals[i].strptr, NULL);
774 /* Add static AVPs to list */
775 for (i=0; old_diameter_avps[i].name; i++) {
776 addStaticAVP(old_diameter_avps[i].code,
777 old_diameter_avps[i].name,
778 old_diameter_avps[i].type,
779 old_diameter_avps[i].values);
782 } /* initializeDictionaryDefaults */
785 * This routine will attempt to load the XML dictionary, and on
786 * failure, will call initializeDictionaryDefaults to load in
787 * our static dictionary.
790 initializeDictionary()
793 * Using ugly ordering here. If loadLibXML succeeds, then
794 * loadXMLDictionary will be called. This is one of the few times when
795 * I think this is prettier than the nested if alternative.
798 (loadXMLDictionary() != 0)) {
799 /* Something failed. Use the static dictionary */
800 g_warning("Diameter: Using static dictionary! (Unable to use XML)");
801 initializeDictionaryDefaults();
803 } /* initializeDictionary */
808 * These routines manipulate the diameter structures.
811 /* return vendor string, based on the id */
813 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
815 static gchar buffer[64];
817 for (probe=vendorListHead; probe; probe=probe->next) {
818 if (vendorId == probe->id) {
820 return probe->longName;
826 snprintf(buffer, sizeof(buffer),
827 "Vendor 0x%08x", vendorId);
829 } /*diameter_vendor_to_str */
831 /* return command string, based on the code */
833 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
836 static gchar buffer[64];
837 gchar *vendorName=NULL;
840 vendorName = diameter_vendor_to_str(vendorId, FALSE);
842 for (probe=commandListHead; probe; probe=probe->next) {
843 if (commandCode == probe->code) {
845 /* g_warning("Command: Comparing \"%s\" to \"%s\"", */
846 /* vendorName?vendorName:"(null)", */
847 /* probe->vendorName?probe->vendorName:"(null)"); */
848 /* Now check the vendor name */
849 if (!strcmp(vendorName, probe->vendorName))
853 /* With no vendor id, the Command's entry should be "None" */
854 if (!strcmp(probe->vendorName, "None")) {
862 g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
863 commandCode, vendorId);
864 snprintf(buffer, sizeof(buffer),
865 "Cmd-0x%08x", commandCode);
867 }/*diameter_command_to_str */
869 /* return application string, based on the id */
871 diameter_app_to_str(guint32 vendorId) {
872 ApplicationId *probe;
873 static gchar buffer[64];
875 for (probe=ApplicationIdHead; probe; probe=probe->next) {
876 if (vendorId == probe->id) {
881 snprintf(buffer, sizeof(buffer),
882 "AppId 0x%08x", vendorId);
884 } /*diameter_app_to_str */
886 /* return an avp type, based on the code */
888 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
890 gchar *vendorName=NULL;
893 vendorName = diameter_vendor_to_str(vendorId, FALSE);
895 for (probe=avpListHead; probe; probe=probe->next) {
896 if (avpCode == probe->code) {
899 /* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
900 /* vendorName?vendorName:"(null)", */
901 /* probe->vendorName?probe->vendorName:"(null)"); */
902 /* Now check the vendor name */
903 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
907 /* No Vendor ID -- vendorName should be null */
908 if (!probe->vendorName)
915 /* If we don't find it, assume it's data */
916 g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
918 return DIAMETER_OCTET_STRING;
919 } /* diameter_avp_get_type */
921 /* return an avp name from the code */
923 diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
925 static gchar buffer[64];
927 gchar *vendorName=NULL;
930 vendorName = diameter_vendor_to_str(vendorId, FALSE);
932 for (probe=avpListHead; probe; probe=probe->next) {
933 if (avpCode == probe->code) {
935 /* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
936 /* vendorName?vendorName:"(null)", */
937 /* probe->vendorName?probe->vendorName:"(null)"); */
938 /* Now check the vendor name */
939 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
943 /* No Vendor ID -- vendorName should be null */
944 if (!probe->vendorName)
951 g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
954 /* If we don't find it, build a name string */
955 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
957 } /* diameter_avp_get_name */
959 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
961 static gchar buffer[64];
964 gchar *vendorName=NULL;
967 vendorName = diameter_vendor_to_str(vendorId, FALSE);
969 for (probe=avpListHead; probe; probe=probe->next) {
970 if (avpCode == probe->code) {
972 /* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
973 /* vendorName?vendorName:"(null)", */
974 /* probe->vendorName?probe->vendorName:"(null)"); */
975 /* Now check the vendor name */
976 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
978 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
979 if (avpValue == vprobe->value) {
983 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
987 if (!probe->vendorName) {
989 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
990 if (avpValue == vprobe->value) {
994 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
1000 /* If we don't find the avp, build a value string */
1001 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
1003 } /* diameter_avp_get_value */
1006 /* Code to actually dissect the packets */
1011 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
1015 /* Set up structures needed to add the protocol subtree and manage it */
1018 proto_tree *flags_tree;
1020 proto_tree *diameter_tree;
1024 proto_tree *avp_tree;
1026 int BadPacket = FALSE;
1027 guint32 commandCode, pktLength;
1028 guint8 version, flags;
1029 gchar flagstr[64] = "<None>";
1030 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1031 gchar commandString[64], vendorName[64];
1034 static int initialized=FALSE;
1036 /* set our offset */
1040 * Only parse in dictionary if there are diameter packets to
1044 /* Read in our dictionary, if it exists. */
1045 initializeDictionary();
1049 /* Make entries in Protocol column and Info column on summary display */
1050 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1051 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1052 if (check_col(pinfo->cinfo, COL_INFO))
1053 col_clear(pinfo->cinfo, COL_INFO);
1055 /* Copy our header */
1056 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1058 /* Fix byte ordering in our static structure */
1059 dh.versionLength = ntohl(dh.versionLength);
1060 dh.flagsCmdCode = ntohl(dh.flagsCmdCode);
1061 dh.vendorId = ntohl(dh.vendorId);
1062 dh.hopByHopId = ntohl(dh.hopByHopId);
1063 dh.endToEndId = ntohl(dh.endToEndId);
1067 diameter_vendor_to_str(dh.vendorId, TRUE));
1069 strcpy(vendorName, "None");
1073 /* Do the bit twiddling */
1074 version = DIAM_GET_VERSION(dh);
1075 pktLength = DIAM_GET_LENGTH(dh);
1076 flags = DIAM_GET_FLAGS(dh);
1077 commandCode = DIAM_GET_COMMAND(dh);
1079 /* Set up our flags */
1080 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1082 for (i = 0; i < 8; i++) {
1086 strcat(flagstr, ", ");
1088 strcat(flagstr, fstr[i]);
1091 if (strlen(flagstr) == 0) {
1092 strcpy(flagstr,"<None>");
1096 /* Set up our commandString */
1097 strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1098 if (flags & DIAM_FLAGS_R)
1099 strcat(commandString, "-Request");
1101 strcat(commandString, "-Answer");
1103 /* Short packet. Should have at LEAST one avp */
1104 if (pktLength < MIN_DIAMETER_SIZE) {
1105 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1106 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1110 /* And, check our reserved flags/version */
1111 if ((flags & DIAM_FLAGS_RESERVED) ||
1113 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1118 if (check_col(pinfo->cinfo, COL_INFO)) {
1119 col_add_fstr(pinfo->cinfo, COL_INFO,
1120 "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1121 (BadPacket)?"***** Bad Packet!: ":"",
1122 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1123 (flags & DIAM_FLAGS_E)?" Error":"",
1125 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1127 commandString, vendorName,
1128 dh.hopByHopId, dh.endToEndId,
1129 (flags & DIAM_FLAGS_R)?1:0,
1130 (flags & DIAM_FLAGS_P)?1:0,
1131 (flags & DIAM_FLAGS_E)?1:0);
1135 /* In the interest of speed, if "tree" is NULL, don't do any work not
1136 necessary to generate protocol tree items. */
1139 /* create display subtree for the protocol */
1140 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1141 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1142 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1145 proto_tree_add_uint(diameter_tree,
1146 hf_diameter_version,
1153 proto_tree_add_uint(diameter_tree,
1154 hf_diameter_length, tvb,
1155 offset, 3, pktLength);
1159 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1160 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1162 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1163 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1164 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1165 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1166 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1167 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1168 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1169 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1170 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1175 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1176 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1180 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1181 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
1184 /* Hop-by-hop Identifier */
1185 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1186 tvb, offset, 4, dh.hopByHopId);
1189 /* End-to-end Identifier */
1190 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1191 tvb, offset, 4, dh.endToEndId);
1194 /* If we have a bad packet, don't bother trying to parse the AVPs */
1196 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1199 /* Start looking at the AVPS */
1200 /* Make the next tvbuff */
1202 /* Update the lengths */
1203 avplength= pktLength - sizeof(e_diameterhdr);
1205 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1206 avptf = proto_tree_add_text(diameter_tree,
1207 tvb, offset, avplength,
1208 "Attribute Value Pairs");
1210 avp_tree = proto_item_add_subtree(avptf,
1212 if (avp_tree != NULL) {
1213 dissect_avps( avp_tvb, pinfo, avp_tree);
1215 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1217 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1219 } /* dissect_diameter_common */
1222 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1224 dissect_diameter_common(tvb, 0, pinfo, tree);
1228 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1232 guint32 available_bytes;
1233 /* guint32 noffset; */
1235 /* Loop through the packet, dissecting multiple diameter messages */
1237 available_bytes = tvb_length_remaining(tvb, offset);
1238 if (available_bytes < 4) {
1239 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1241 return; /* Bail. We can't even get our length */
1244 /* get our packet length */
1245 plen = tvb_get_ntohl(tvb, offset);
1246 plen &= 0x00ffffff; /* get rid of the flags */
1249 if (gbl_diameter_desegment) {
1250 if (pinfo->can_desegment
1251 && plen > available_bytes) {
1252 pinfo->desegment_offset = offset;
1253 pinfo->desegment_len = plen - available_bytes;
1254 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1255 /* plen, available_bytes); */
1260 /* Otherwise, dissect our packet */
1261 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1263 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1264 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1265 /* offset=noffset; */
1266 } while (offset < tvb_reported_length(tvb));
1268 } /* dissect_diameter_tcp */
1271 * Call the mip_dissector, after saving our pinfo variables
1272 * so it doesn't write to our column display.
1275 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1276 size_t offset, size_t length)
1278 static dissector_handle_t mip_handle;
1279 static int mipInitialized=FALSE;
1281 address save_dl_src;
1282 address save_dl_dst;
1283 address save_net_src;
1284 address save_net_dst;
1287 gboolean save_in_error_pkt;
1289 if (!mipInitialized) {
1290 mip_handle = find_dissector("mip");
1291 mipInitialized=TRUE;
1294 mip_tvb = tvb_new_subset(tvb, offset,
1295 MIN(length, tvb_length(tvb)-offset),
1298 /* The contained packet is a MIP registration request;
1299 dissect it with the MIP dissector. */
1300 col_set_writable(pinfo->cinfo, FALSE);
1302 /* Also, save the current values of the addresses, and restore
1303 them when we're finished dissecting the contained packet, so
1304 that the address columns in the summary don't reflect the
1305 contained packet, but reflect this packet instead. */
1306 save_dl_src = pinfo->dl_src;
1307 save_dl_dst = pinfo->dl_dst;
1308 save_net_src = pinfo->net_src;
1309 save_net_dst = pinfo->net_dst;
1310 save_src = pinfo->src;
1311 save_dst = pinfo->dst;
1312 save_in_error_pkt = pinfo->in_error_pkt;
1314 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1316 /* Restore the "we're inside an error packet" flag. */
1317 pinfo->in_error_pkt = save_in_error_pkt;
1318 pinfo->dl_src = save_dl_src;
1319 pinfo->dl_dst = save_dl_dst;
1320 pinfo->net_src = save_net_src;
1321 pinfo->net_dst = save_net_dst;
1322 pinfo->src = save_src;
1323 pinfo->dst = save_dst;
1326 } /* safe_dissect_mip */
1329 * This function will dissect the AVPs in a diameter packet. It handles
1330 * all normal types, and even recursively calls itself for grouped AVPs
1332 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1334 /* adds the attribute value pairs to the tree */
1336 gchar avpTypeString[64];
1337 gchar avpNameString[64];
1340 gchar vendorName[64];
1343 proto_tree *avpi_tree;
1345 tvbuff_t *group_tvb;
1346 proto_tree *group_tree;
1347 proto_item *grouptf;
1350 int BadPacket = FALSE;
1354 proto_tree *flags_tree;
1356 gint32 packetLength;
1357 size_t avpDataLength;
1359 gchar flagstr[64] = "<None>";
1360 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1364 packetLength = tvb_length(tvb);
1366 /* Check for invalid packet lengths */
1367 if (packetLength <= 0) {
1368 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1369 "No Attribute Value Pairs Found");
1373 /* Spin around until we run out of packet */
1374 while (packetLength > 0 ) {
1376 /* Check for short packet */
1377 if (packetLength < (long)MIN_AVP_SIZE) {
1378 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1379 packetLength, (long)MIN_AVP_SIZE);
1381 /* Don't even bother trying to parse a short packet. */
1385 /* Copy our header */
1386 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1388 /* Fix the byte ordering */
1389 avph.avp_code = ntohl(avph.avp_code);
1390 avph.avp_flagsLength = ntohl(avph.avp_flagsLength);
1392 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1393 avpLength = avph.avp_flagsLength & 0x00ffffff;
1395 /* Set up our flags string */
1396 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1398 for (i = 0; i < 8; i++) {
1402 strcat(flagstr, ", ");
1404 strcat(flagstr, fstr[i]);
1407 if (strlen(flagstr) == 0) {
1408 strcpy(flagstr,"<None>");
1412 /* Dissect our vendor id if it exists and set hdr length */
1413 if (flags & AVP_FLAGS_V) {
1414 vendorId = ntohl(avph.avp_vendorId);
1416 hdrLength = sizeof(e_avphdr);
1419 hdrLength = sizeof(e_avphdr) -
1426 diameter_vendor_to_str(vendorId, TRUE));
1431 /* Check for bad length */
1432 if (avpLength < MIN_AVP_SIZE ||
1433 ((long)avpLength > packetLength)) {
1434 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1435 "min: %ld bytes, packetLen: %d",
1436 (long)avpLength, (long)MIN_AVP_SIZE,
1441 /* Check for bad flags */
1442 if (flags & AVP_FLAGS_RESERVED) {
1443 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1445 flags, AVP_FLAGS_RESERVED);
1446 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1447 /* BadPacket = TRUE; */
1451 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1454 fixAmt = 4 - (avpLength % 4);
1455 if (fixAmt == 4) fixAmt = 0;
1457 /* shrink our packetLength */
1458 packetLength = packetLength - (avpLength + fixAmt);
1460 /* Check for out of bounds */
1461 if (packetLength < 0) {
1462 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1467 /* Make avp Name & type */
1468 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1470 "Unknown-Type: 0x%08x"));
1471 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1473 avptf = proto_tree_add_text(avp_tree, tvb,
1474 offset, avpLength + fixAmt,
1475 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1476 avpNameString, avpTypeString, avpLength,
1477 avpLength, avpLength+fixAmt);
1478 avpi_tree = proto_item_add_subtree(avptf,
1479 ett_diameter_avpinfo);
1481 if (avpi_tree !=NULL) {
1483 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1484 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1487 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1488 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1490 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1491 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1492 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1493 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1494 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1495 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1496 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1497 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1498 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1501 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1502 tvb, offset, 3, avpLength);
1505 if (flags & AVP_FLAGS_V) {
1506 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1507 tvb, offset, 4, vendorId, vendorName);
1511 avpDataLength = avpLength - hdrLength;
1514 * If we've got a bad packet, just highlight the data. Don't try
1515 * to parse it, and, don't move to next AVP.
1518 offset -= hdrLength;
1519 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1520 tvb, offset, tvb_length(tvb) - offset,
1521 tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1522 "Bad AVP (Suspect Data Not Dissected)");
1526 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1529 case DIAMETER_GROUPED:
1530 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1531 /* Recursively call ourselves */
1532 grouptf = proto_tree_add_text(avpi_tree,
1533 tvb, offset, tvb_length(tvb),
1536 group_tree = proto_item_add_subtree(grouptf,
1539 group_tvb = tvb_new_subset(tvb, offset,
1540 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1541 if (group_tree != NULL) {
1542 dissect_avps( group_tvb, pinfo, group_tree);
1546 case DIAMETER_IDENTITY:
1550 data = tvb_get_ptr(tvb, offset, avpDataLength);
1551 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1552 tvb, offset, avpDataLength, data,
1555 (int)avpDataLength, data);
1558 case DIAMETER_UTF8STRING:
1562 data = tvb_get_ptr(tvb, offset, avpDataLength);
1563 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1564 tvb, offset, avpDataLength, data,
1565 "UTF8String: %*.*s",
1567 (int)avpDataLength, data);
1570 case DIAMETER_IP_ADDRESS:
1571 if (avpDataLength == 4) {
1572 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1573 tvb, offset, avpDataLength, FALSE);
1574 } else if (avpDataLength == 16) {
1575 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1576 tvb, offset, avpDataLength, FALSE);
1578 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1579 tvb, offset, avpDataLength,
1580 tvb_get_ptr(tvb, offset, avpDataLength),
1581 "Error! Bad Address Length");
1585 case DIAMETER_INTEGER32:
1586 if (avpDataLength == 4) {
1587 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1588 tvb, offset, avpDataLength, FALSE);
1590 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1591 tvb, offset, avpDataLength,
1592 tvb_get_ptr(tvb, offset, avpDataLength),
1593 "Error! Bad Integer32 Length");
1597 case DIAMETER_UNSIGNED32:
1598 if (avpDataLength == 4) {
1601 data = tvb_get_ntohl(tvb, offset);
1602 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1603 tvb, offset, avpDataLength, data,
1604 "Value: 0x%08x (%u)", data, data);
1606 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1607 tvb, offset, avpDataLength,
1608 tvb_get_ptr(tvb, offset, avpDataLength),
1609 "Error! Bad Unsigned32 Length");
1613 case DIAMETER_INTEGER64:
1614 if (avpDataLength == 8) {
1615 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1616 tvb, offset, 8, FALSE);
1618 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1619 tvb, offset, avpDataLength,
1620 tvb_get_ptr(tvb, offset, avpDataLength),
1621 "Error! Bad Integer64 Length");
1625 case DIAMETER_UNSIGNED64:
1626 if (avpDataLength == 8) {
1627 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1628 tvb, offset, 8, FALSE);
1630 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1631 tvb, offset, avpDataLength,
1632 tvb_get_ptr(tvb, offset, avpDataLength),
1633 "Error! Bad Unsigned64 Length");
1638 if (avpDataLength == 4) {
1643 data.secs = tvb_get_ntohl(tvb, offset);
1644 data.secs -= NTP_TIME_DIFF;
1647 ltp = localtime(&data.secs);
1648 strftime(buffer, 64,
1649 "%a, %d %b %Y %H:%M:%S %z", ltp);
1651 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1652 tvb, offset, avpDataLength, &data,
1653 "Time: %s", buffer);
1655 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1656 tvb, offset, avpDataLength,
1657 tvb_get_ptr(tvb, offset, avpDataLength),
1658 "Error! Bad Time Length");
1662 case DIAMETER_ENUMERATED:
1663 if (avpDataLength == 4) {
1666 data = tvb_get_ntohl(tvb, offset);
1667 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1668 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1669 tvb, offset, avpDataLength, data,
1670 "Value: 0x%08x (%u): %s", data,
1673 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1674 tvb, offset, avpDataLength,
1675 tvb_get_ptr(tvb, offset, avpDataLength),
1676 "Error! Bad Enumerated Length");
1679 case DIAMETER_VENDOR_ID:
1680 if (avpDataLength == 4) {
1683 data = tvb_get_ntohl(tvb, offset);
1684 valstr = diameter_vendor_to_str(data, TRUE);
1685 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1686 tvb, offset, avpDataLength, data,
1687 "Vendor ID: %s (0x%08x)", valstr,
1690 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1691 tvb, offset, avpDataLength,
1692 tvb_get_ptr(tvb, offset, avpDataLength),
1693 "Error! Bad Vendor ID Length");
1696 case DIAMETER_APPLICATION_ID:
1697 if (avpDataLength == 4) {
1700 data = tvb_get_ntohl(tvb, offset);
1701 valstr = diameter_app_to_str(data);
1702 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1703 tvb, offset, avpDataLength, data,
1704 "Application ID: %s (0x%08x)",
1707 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1708 tvb, offset, avpDataLength,
1709 tvb_get_ptr(tvb, offset, avpDataLength),
1710 "Error! Bad Application ID Length");
1713 case DIAMETER_MIP_REG_REQ:
1714 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1718 case DIAMETER_OCTET_STRING:
1719 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1720 tvb, offset, avpDataLength,
1721 tvb_get_ptr(tvb, offset, avpDataLength),
1722 "Hex Data Highlighted Below");
1726 } /* avpi_tree != null */
1727 offset += (avpLength - hdrLength);
1728 offset += fixAmt; /* fix byte alignment */
1730 } /* dissect_avps */
1735 proto_reg_handoff_diameter(void)
1737 static int Initialized=FALSE;
1738 static int TcpPort=0;
1739 static int SctpPort=0;
1740 static dissector_handle_t diameter_tcp_handle;
1741 static dissector_handle_t diameter_sctp_handle;
1744 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1746 diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1750 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1751 dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1754 /* set port for future deletes */
1755 TcpPort=gbl_diameterTcpPort;
1756 SctpPort=gbl_diameterSctpPort;
1758 strcpy(gbl_diameterString, "Diameter Protocol");
1760 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1761 gbl_diameterTcpPort); */
1762 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1763 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1766 /* registration with the filtering engine */
1768 proto_register_diameter(void)
1770 static hf_register_info hf[] = {
1771 { &hf_diameter_version,
1772 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1774 { &hf_diameter_length,
1775 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1778 { &hf_diameter_flags,
1779 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1781 { &hf_diameter_flags_request,
1782 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1784 { &hf_diameter_flags_proxyable,
1785 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1787 { &hf_diameter_flags_error,
1788 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1790 { &hf_diameter_flags_reserved3,
1791 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1792 DIAM_FLAGS_RESERVED3, "", HFILL }},
1793 { &hf_diameter_flags_reserved4,
1794 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1795 DIAM_FLAGS_RESERVED4, "", HFILL }},
1796 { &hf_diameter_flags_reserved5,
1797 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1798 DIAM_FLAGS_RESERVED5, "", HFILL }},
1799 { &hf_diameter_flags_reserved6,
1800 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1801 DIAM_FLAGS_RESERVED6, "", HFILL }},
1802 { &hf_diameter_flags_reserved7,
1803 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1804 DIAM_FLAGS_RESERVED7, "", HFILL }},
1806 { &hf_diameter_code,
1807 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1808 NULL, 0x0, "", HFILL }},
1809 { &hf_diameter_vendor_id,
1810 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1812 { &hf_diameter_hopbyhopid,
1813 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1814 BASE_HEX, NULL, 0x0, "", HFILL }},
1815 { &hf_diameter_endtoendid,
1816 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1817 BASE_HEX, NULL, 0x0, "", HFILL }},
1819 { &hf_diameter_avp_code,
1820 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1821 NULL, 0x0, "", HFILL }},
1822 { &hf_diameter_avp_length,
1823 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1824 NULL, 0x0, "", HFILL }},
1827 { &hf_diameter_avp_flags,
1828 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1829 NULL, 0x0, "", HFILL }},
1830 { &hf_diameter_avp_flags_vendor_specific,
1831 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1833 { &hf_diameter_avp_flags_mandatory,
1834 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1836 { &hf_diameter_avp_flags_protected,
1837 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1839 { &hf_diameter_avp_flags_reserved3,
1840 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1841 AVP_FLAGS_RESERVED3, "", HFILL }},
1842 { &hf_diameter_avp_flags_reserved4,
1843 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1844 AVP_FLAGS_RESERVED4, "", HFILL }},
1845 { &hf_diameter_avp_flags_reserved5,
1846 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1847 AVP_FLAGS_RESERVED5, "", HFILL }},
1848 { &hf_diameter_avp_flags_reserved6,
1849 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1850 AVP_FLAGS_RESERVED6, "", HFILL }},
1851 { &hf_diameter_avp_flags_reserved7,
1852 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1853 AVP_FLAGS_RESERVED7, "", HFILL }},
1854 { &hf_diameter_avp_vendor_id,
1855 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1856 NULL, 0x0, "", HFILL }},
1857 { &hf_diameter_avp_data_uint64,
1858 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1859 NULL, 0x0, "", HFILL }},
1860 { &hf_diameter_avp_data_int64,
1861 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1862 NULL, 0x0, "", HFILL }},
1863 { &hf_diameter_avp_data_uint32,
1864 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1865 NULL, 0x0, "", HFILL }},
1866 { &hf_diameter_avp_data_int32,
1867 { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1868 NULL, 0x0, "", HFILL }},
1869 { &hf_diameter_avp_data_bytes,
1870 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1871 NULL, 0x0, "", HFILL }},
1872 { &hf_diameter_avp_data_string,
1873 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1874 NULL, 0x0, "", HFILL }},
1875 { &hf_diameter_avp_data_v4addr,
1876 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1877 NULL, 0x0, "", HFILL }},
1878 { &hf_diameter_avp_data_v6addr,
1879 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1880 NULL, 0x0, "", HFILL }},
1881 { &hf_diameter_avp_data_time,
1882 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1883 NULL, 0x0, "", HFILL }},
1886 static gint *ett[] = {
1888 &ett_diameter_flags,
1890 &ett_diameter_avp_flags,
1891 &ett_diameter_avpinfo
1893 module_t *diameter_module;
1895 proto_diameter = proto_register_protocol (gbl_diameterString,
1896 "Diameter", "diameter");
1897 proto_register_field_array(proto_diameter, hf, array_length(hf));
1898 proto_register_subtree_array(ett, array_length(ett));
1900 /* Register a configuration option for port */
1901 diameter_module = prefs_register_protocol(proto_diameter,
1902 proto_reg_handoff_diameter);
1903 prefs_register_uint_preference(diameter_module, "tcp.port",
1904 "Diameter TCP Port",
1905 "Set the TCP port for Diameter messages",
1907 &gbl_diameterTcpPort);
1908 prefs_register_uint_preference(diameter_module, "sctp.port",
1909 "Diameter SCTP Port",
1910 "Set the SCTP port for Diameter messages",
1912 &gbl_diameterSctpPort);
1914 * Build our default dictionary filename
1916 if (! gbl_diameterDictionary) {
1917 gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
1918 1 + strlen(DICT_FN) + 1); /* slash + fn + null */
1919 sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
1920 get_datafile_dir(), DICT_FN );
1922 /* Now register its preferences so it can be changed. */
1923 prefs_register_string_preference(diameter_module, "dictionary.name",
1924 "Diameter XML Dictionary",
1925 "Set the dictionary used for Diameter messages",
1926 &gbl_diameterDictionary);
1928 /* Desegmentation */
1929 prefs_register_bool_preference(diameter_module, "desegment",
1930 "Desegment all Diameter messages spanning multiple TCP segments",
1931 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1932 &gbl_diameter_desegment);
1934 /* Register some preferences we no longer support, so we can report
1935 them as obsolete rather than just illegal. */
1936 prefs_register_obsolete_preference(diameter_module, "udp.port");
1937 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1938 } /* proto_register_diameter */