2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.43 2002/01/30 23:08:26 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 diameter_time_to_string(gchar *timeValue)
1008 static gchar buffer[64];
1012 intval=pntohl(timeValue);
1013 intval -= NTP_TIME_DIFF;
1014 lt=*localtime((time_t *)&intval);
1015 strftime(buffer, 1024,
1016 "%a, %d %b %Y %H:%M:%S %z",<);
1018 } /* diameter_time_to_string */
1021 /* Code to actually dissect the packets */
1026 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
1030 /* Set up structures needed to add the protocol subtree and manage it */
1033 proto_tree *flags_tree;
1035 proto_tree *diameter_tree;
1039 proto_tree *avp_tree;
1041 int BadPacket = FALSE;
1042 guint32 commandCode, pktLength;
1043 guint8 version, flags;
1044 gchar flagstr[64] = "<None>";
1045 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1046 gchar commandString[64], vendorName[64];
1049 static int initialized=FALSE;
1051 /* set our offset */
1055 * Only parse in dictionary if there are diameter packets to
1059 /* Read in our dictionary, if it exists. */
1060 initializeDictionary();
1064 /* Make entries in Protocol column and Info column on summary display */
1065 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1066 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1067 if (check_col(pinfo->cinfo, COL_INFO))
1068 col_clear(pinfo->cinfo, COL_INFO);
1070 /* Copy our header */
1071 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1073 /* Fix byte ordering in our static structure */
1074 dh.versionLength = ntohl(dh.versionLength);
1075 dh.flagsCmdCode = ntohl(dh.flagsCmdCode);
1076 dh.vendorId = ntohl(dh.vendorId);
1077 dh.hopByHopId = ntohl(dh.hopByHopId);
1078 dh.endToEndId = ntohl(dh.endToEndId);
1082 diameter_vendor_to_str(dh.vendorId, TRUE));
1084 strcpy(vendorName, "None");
1088 /* Do the bit twiddling */
1089 version = DIAM_GET_VERSION(dh);
1090 pktLength = DIAM_GET_LENGTH(dh);
1091 flags = DIAM_GET_FLAGS(dh);
1092 commandCode = DIAM_GET_COMMAND(dh);
1094 /* Set up our flags */
1095 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1097 for (i = 0; i < 8; i++) {
1101 strcat(flagstr, ", ");
1103 strcat(flagstr, fstr[i]);
1106 if (strlen(flagstr) == 0) {
1107 strcpy(flagstr,"<None>");
1111 /* Set up our commandString */
1112 strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1113 if (flags & DIAM_FLAGS_R)
1114 strcat(commandString, "-Request");
1116 strcat(commandString, "-Answer");
1118 /* Short packet. Should have at LEAST one avp */
1119 if (pktLength < MIN_DIAMETER_SIZE) {
1120 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1121 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1125 /* And, check our reserved flags/version */
1126 if ((flags & DIAM_FLAGS_RESERVED) ||
1128 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1133 if (check_col(pinfo->cinfo, COL_INFO)) {
1134 col_add_fstr(pinfo->cinfo, COL_INFO,
1135 "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1136 (BadPacket)?"***** Bad Packet!: ":"",
1137 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1138 (flags & DIAM_FLAGS_E)?" Error":"",
1140 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1142 commandString, vendorName,
1143 dh.hopByHopId, dh.endToEndId,
1144 (flags & DIAM_FLAGS_R)?1:0,
1145 (flags & DIAM_FLAGS_P)?1:0,
1146 (flags & DIAM_FLAGS_E)?1:0);
1150 /* In the interest of speed, if "tree" is NULL, don't do any work not
1151 necessary to generate protocol tree items. */
1154 /* create display subtree for the protocol */
1155 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1156 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1157 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1160 proto_tree_add_uint(diameter_tree,
1161 hf_diameter_version,
1168 proto_tree_add_uint(diameter_tree,
1169 hf_diameter_length, tvb,
1170 offset, 3, pktLength);
1174 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1175 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1177 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1178 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1179 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1180 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1181 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1182 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1183 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1184 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1185 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1190 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1191 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1195 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1196 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
1199 /* Hop-by-hop Identifier */
1200 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1201 tvb, offset, 4, dh.hopByHopId);
1204 /* End-to-end Identifier */
1205 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1206 tvb, offset, 4, dh.endToEndId);
1209 /* If we have a bad packet, don't bother trying to parse the AVPs */
1211 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1214 /* Start looking at the AVPS */
1215 /* Make the next tvbuff */
1217 /* Update the lengths */
1218 avplength= pktLength - sizeof(e_diameterhdr);
1220 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1221 avptf = proto_tree_add_text(diameter_tree,
1222 tvb, offset, avplength,
1223 "Attribute Value Pairs");
1225 avp_tree = proto_item_add_subtree(avptf,
1227 if (avp_tree != NULL) {
1228 dissect_avps( avp_tvb, pinfo, avp_tree);
1230 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1232 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1234 } /* dissect_diameter_common */
1237 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1239 dissect_diameter_common(tvb, 0, pinfo, tree);
1243 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1247 guint32 available_bytes;
1248 /* guint32 noffset; */
1250 /* Loop through the packet, dissecting multiple diameter messages */
1252 available_bytes = tvb_length_remaining(tvb, offset);
1253 if (available_bytes < 4) {
1254 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1256 return; /* Bail. We can't even get our length */
1259 /* get our packet length */
1260 plen = tvb_get_ntohl(tvb, offset);
1261 plen &= 0x00ffffff; /* get rid of the flags */
1264 if (gbl_diameter_desegment) {
1265 if (pinfo->can_desegment
1266 && plen > available_bytes) {
1267 pinfo->desegment_offset = offset;
1268 pinfo->desegment_len = plen - available_bytes;
1269 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1270 /* plen, available_bytes); */
1275 /* Otherwise, dissect our packet */
1276 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1278 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1279 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1280 /* offset=noffset; */
1281 } while (offset < tvb_reported_length(tvb));
1283 } /* dissect_diameter_tcp */
1286 * Call the mip_dissector, after saving our pinfo variables
1287 * so it doesn't write to our column display.
1290 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1291 size_t offset, size_t length)
1293 static dissector_handle_t mip_handle;
1294 static int mipInitialized=FALSE;
1296 address save_dl_src;
1297 address save_dl_dst;
1298 address save_net_src;
1299 address save_net_dst;
1302 gboolean save_in_error_pkt;
1304 if (!mipInitialized) {
1305 mip_handle = find_dissector("mip");
1306 mipInitialized=TRUE;
1309 mip_tvb = tvb_new_subset(tvb, offset,
1310 MIN(length, tvb_length(tvb)-offset),
1313 /* The contained packet is a MIP registration request;
1314 dissect it with the MIP dissector. */
1315 col_set_writable(pinfo->cinfo, FALSE);
1317 /* Also, save the current values of the addresses, and restore
1318 them when we're finished dissecting the contained packet, so
1319 that the address columns in the summary don't reflect the
1320 contained packet, but reflect this packet instead. */
1321 save_dl_src = pinfo->dl_src;
1322 save_dl_dst = pinfo->dl_dst;
1323 save_net_src = pinfo->net_src;
1324 save_net_dst = pinfo->net_dst;
1325 save_src = pinfo->src;
1326 save_dst = pinfo->dst;
1327 save_in_error_pkt = pinfo->in_error_pkt;
1329 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1331 /* Restore the "we're inside an error packet" flag. */
1332 pinfo->in_error_pkt = save_in_error_pkt;
1333 pinfo->dl_src = save_dl_src;
1334 pinfo->dl_dst = save_dl_dst;
1335 pinfo->net_src = save_net_src;
1336 pinfo->net_dst = save_net_dst;
1337 pinfo->src = save_src;
1338 pinfo->dst = save_dst;
1341 } /* safe_dissect_mip */
1344 * This function will dissect the AVPs in a diameter packet. It handles
1345 * all normal types, and even recursively calls itself for grouped AVPs
1347 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1349 /* adds the attribute value pairs to the tree */
1351 gchar avpTypeString[64];
1352 gchar avpNameString[64];
1355 gchar vendorName[64];
1358 proto_tree *avpi_tree;
1360 char dataBuffer[4096];
1361 tvbuff_t *group_tvb;
1362 proto_tree *group_tree;
1363 proto_item *grouptf;
1366 int BadPacket = FALSE;
1370 proto_tree *flags_tree;
1372 gint32 packetLength;
1373 size_t avpDataLength;
1375 gchar flagstr[64] = "<None>";
1376 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1380 packetLength = tvb_length(tvb);
1382 /* Check for invalid packet lengths */
1383 if (packetLength <= 0) {
1384 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1385 "No Attribute Value Pairs Found");
1389 /* Spin around until we run out of packet */
1390 while (packetLength > 0 ) {
1392 /* Check for short packet */
1393 if (packetLength < (long)MIN_AVP_SIZE) {
1394 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1395 packetLength, (long)MIN_AVP_SIZE);
1397 /* Don't even bother trying to parse a short packet. */
1401 /* Copy our header */
1402 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1404 /* Fix the byte ordering */
1405 avph.avp_code = ntohl(avph.avp_code);
1406 avph.avp_flagsLength = ntohl(avph.avp_flagsLength);
1408 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1409 avpLength = avph.avp_flagsLength & 0x00ffffff;
1411 /* Set up our flags string */
1412 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1414 for (i = 0; i < 8; i++) {
1418 strcat(flagstr, ", ");
1420 strcat(flagstr, fstr[i]);
1423 if (strlen(flagstr) == 0) {
1424 strcpy(flagstr,"<None>");
1428 /* Dissect our vendor id if it exists and set hdr length */
1429 if (flags & AVP_FLAGS_V) {
1430 vendorId = ntohl(avph.avp_vendorId);
1432 hdrLength = sizeof(e_avphdr);
1435 hdrLength = sizeof(e_avphdr) -
1442 diameter_vendor_to_str(vendorId, TRUE));
1447 /* Check for bad length */
1448 if (avpLength < MIN_AVP_SIZE ||
1449 ((long)avpLength > packetLength)) {
1450 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1451 "min: %ld bytes, packetLen: %d",
1452 (long)avpLength, (long)MIN_AVP_SIZE,
1457 /* Check for bad flags */
1458 if (flags & AVP_FLAGS_RESERVED) {
1459 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1461 flags, AVP_FLAGS_RESERVED);
1462 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1463 /* BadPacket = TRUE; */
1467 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1470 fixAmt = 4 - (avpLength % 4);
1471 if (fixAmt == 4) fixAmt = 0;
1473 /* shrink our packetLength */
1474 packetLength = packetLength - (avpLength + fixAmt);
1476 /* Check for out of bounds */
1477 if (packetLength < 0) {
1478 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1483 /* Make avp Name & type */
1484 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1486 "Unknown-Type: 0x%08x"));
1487 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1489 avptf = proto_tree_add_text(avp_tree, tvb,
1490 offset, avpLength + fixAmt,
1491 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1492 avpNameString, avpTypeString, avpLength,
1493 avpLength, avpLength+fixAmt);
1494 avpi_tree = proto_item_add_subtree(avptf,
1495 ett_diameter_avpinfo);
1497 if (avpi_tree !=NULL) {
1499 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1500 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1503 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1504 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1506 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1507 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1508 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1509 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1510 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1511 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1512 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1513 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1514 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1517 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1518 tvb, offset, 3, avpLength);
1521 if (flags & AVP_FLAGS_V) {
1522 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1523 tvb, offset, 4, vendorId, vendorName);
1527 avpDataLength = avpLength - hdrLength;
1530 * If we've got a bad packet, just highlight the data. Don't try
1531 * to parse it, and, don't move to next AVP.
1534 offset -= hdrLength;
1535 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1536 tvb, offset, tvb_length(tvb) - offset, dataBuffer,
1537 "Bad AVP (Suspect Data Not Dissected)");
1541 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1542 tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095,avpDataLength));
1546 case DIAMETER_GROUPED:
1547 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1548 /* Recursively call ourselves */
1549 grouptf = proto_tree_add_text(avpi_tree,
1550 tvb, offset, tvb_length(tvb),
1553 group_tree = proto_item_add_subtree(grouptf,
1556 group_tvb = tvb_new_subset(tvb, offset,
1557 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1558 if (group_tree != NULL) {
1559 dissect_avps( group_tvb, pinfo, group_tree);
1563 case DIAMETER_IDENTITY:
1564 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1565 tvb, offset, avpDataLength, dataBuffer,
1566 "Identity: %*.*s", (int)avpDataLength, (int)avpDataLength,
1569 case DIAMETER_UTF8STRING:
1570 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1571 tvb, offset, avpDataLength, dataBuffer,
1572 "UTF8String: %*.*s", (int)avpDataLength, (int)avpDataLength,
1575 case DIAMETER_IP_ADDRESS:
1576 if (avpDataLength == 4) {
1577 guint32 ipv4Address = ntohl((*(guint32*)dataBuffer));
1578 proto_tree_add_ipv4_format(avpi_tree, hf_diameter_avp_data_v4addr,
1579 tvb, offset, avpDataLength, ipv4Address,
1580 "IPv4 Address: %u.%u.%u.%u",
1581 (ipv4Address&0xff000000)>>24,
1582 (ipv4Address&0xff0000)>>16,
1583 (ipv4Address&0xff00)>>8,
1584 (ipv4Address&0xff));
1585 } else if (avpDataLength == 16) {
1586 proto_tree_add_ipv6_format(avpi_tree, hf_diameter_avp_data_v6addr,
1587 tvb, offset, avpDataLength, dataBuffer,
1588 "IPv6 Address: %04x:%04x:%04x:%04x",
1589 *((guint32*)dataBuffer),
1590 *((guint32*)&dataBuffer[4]),
1591 *((guint32*)&dataBuffer[8]),
1592 *((guint32*)&dataBuffer[12]));
1594 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1595 tvb, offset, avpDataLength, dataBuffer,
1596 "Error! Bad Address Length");
1600 case DIAMETER_INTEGER32:
1603 memcpy(&data, dataBuffer, 4);
1605 proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32,
1606 tvb, offset, avpDataLength, data,
1607 "Value: %d", data );
1611 case DIAMETER_UNSIGNED32:
1615 memcpy(&data, dataBuffer, 4);
1617 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1618 tvb, offset, avpDataLength, data,
1619 "Value: 0x%08x (%u)", data,
1624 case DIAMETER_INTEGER64:
1625 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64, tvb, offset, 8, FALSE);
1628 case DIAMETER_UNSIGNED64:
1629 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64, tvb, offset, 8, FALSE);
1633 valstr=diameter_time_to_string(dataBuffer);
1635 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1636 tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr);
1639 case DIAMETER_ENUMERATED:
1643 memcpy(&data, dataBuffer, 4);
1645 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1646 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1647 tvb, offset, avpDataLength, data,
1648 "Value: 0x%08x (%u): %s", data, data, valstr);
1651 case DIAMETER_VENDOR_ID:
1655 memcpy(&data, dataBuffer, 4);
1657 valstr = diameter_vendor_to_str(data, TRUE);
1658 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1659 tvb, offset, avpDataLength, data,
1660 "%s (0x%08x)", valstr, data);
1663 case DIAMETER_APPLICATION_ID:
1667 memcpy(&data, dataBuffer, 4);
1669 valstr = diameter_app_to_str(data);
1670 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1671 tvb, offset, avpDataLength, data,
1672 "%s (0x%08x)", valstr, data);
1675 case DIAMETER_MIP_REG_REQ:
1676 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1680 case DIAMETER_OCTET_STRING:
1681 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1682 tvb, offset, avpDataLength, dataBuffer,
1683 "Hex Data Highlighted Below");
1687 } /* avpi_tree != null */
1688 offset += (avpLength - hdrLength);
1689 offset += fixAmt; /* fix byte alignment */
1691 } /* dissect_avps */
1696 proto_reg_handoff_diameter(void)
1698 static int Initialized=FALSE;
1699 static int TcpPort=0;
1700 static int SctpPort=0;
1701 static dissector_handle_t diameter_tcp_handle;
1702 static dissector_handle_t diameter_sctp_handle;
1705 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1707 diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1711 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1712 dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1715 /* set port for future deletes */
1716 TcpPort=gbl_diameterTcpPort;
1717 SctpPort=gbl_diameterSctpPort;
1719 strcpy(gbl_diameterString, "Diameter Protocol");
1721 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1722 gbl_diameterTcpPort); */
1723 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1724 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1727 /* registration with the filtering engine */
1729 proto_register_diameter(void)
1731 static hf_register_info hf[] = {
1732 { &hf_diameter_version,
1733 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1735 { &hf_diameter_length,
1736 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1739 { &hf_diameter_flags,
1740 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1742 { &hf_diameter_flags_request,
1743 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1745 { &hf_diameter_flags_proxyable,
1746 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1748 { &hf_diameter_flags_error,
1749 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1751 { &hf_diameter_flags_reserved3,
1752 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1753 DIAM_FLAGS_RESERVED3, "", HFILL }},
1754 { &hf_diameter_flags_reserved4,
1755 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1756 DIAM_FLAGS_RESERVED4, "", HFILL }},
1757 { &hf_diameter_flags_reserved5,
1758 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1759 DIAM_FLAGS_RESERVED5, "", HFILL }},
1760 { &hf_diameter_flags_reserved6,
1761 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1762 DIAM_FLAGS_RESERVED6, "", HFILL }},
1763 { &hf_diameter_flags_reserved7,
1764 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1765 DIAM_FLAGS_RESERVED7, "", HFILL }},
1767 { &hf_diameter_code,
1768 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1769 NULL, 0x0, "", HFILL }},
1770 { &hf_diameter_vendor_id,
1771 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1773 { &hf_diameter_hopbyhopid,
1774 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1775 BASE_HEX, NULL, 0x0, "", HFILL }},
1776 { &hf_diameter_endtoendid,
1777 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1778 BASE_HEX, NULL, 0x0, "", HFILL }},
1780 { &hf_diameter_avp_code,
1781 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1782 NULL, 0x0, "", HFILL }},
1783 { &hf_diameter_avp_length,
1784 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1785 NULL, 0x0, "", HFILL }},
1788 { &hf_diameter_avp_flags,
1789 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1790 NULL, 0x0, "", HFILL }},
1791 { &hf_diameter_avp_flags_vendor_specific,
1792 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1794 { &hf_diameter_avp_flags_mandatory,
1795 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1797 { &hf_diameter_avp_flags_protected,
1798 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1800 { &hf_diameter_avp_flags_reserved3,
1801 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1802 AVP_FLAGS_RESERVED3, "", HFILL }},
1803 { &hf_diameter_avp_flags_reserved4,
1804 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1805 AVP_FLAGS_RESERVED4, "", HFILL }},
1806 { &hf_diameter_avp_flags_reserved5,
1807 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1808 AVP_FLAGS_RESERVED5, "", HFILL }},
1809 { &hf_diameter_avp_flags_reserved6,
1810 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1811 AVP_FLAGS_RESERVED6, "", HFILL }},
1812 { &hf_diameter_avp_flags_reserved7,
1813 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1814 AVP_FLAGS_RESERVED7, "", HFILL }},
1815 { &hf_diameter_avp_vendor_id,
1816 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1817 NULL, 0x0, "", HFILL }},
1818 { &hf_diameter_avp_data_uint64,
1819 { "AVP Data","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1820 NULL, 0x0, "", HFILL }},
1821 { &hf_diameter_avp_data_int64,
1822 { "AVP Data","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1823 NULL, 0x0, "", HFILL }},
1824 { &hf_diameter_avp_data_uint32,
1825 { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1826 NULL, 0x0, "", HFILL }},
1827 { &hf_diameter_avp_data_int32,
1828 { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1829 NULL, 0x0, "", HFILL }},
1830 { &hf_diameter_avp_data_bytes,
1831 { "AVP Data","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1832 NULL, 0x0, "", HFILL }},
1834 { &hf_diameter_avp_data_string,
1835 { "AVP Data","diameter.avp.data.string", FT_STRING, BASE_NONE,
1836 NULL, 0x0, "", HFILL }},
1837 { &hf_diameter_avp_data_v4addr,
1838 { "AVP Data","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1839 NULL, 0x0, "", HFILL }},
1840 { &hf_diameter_avp_data_v6addr,
1841 { "AVP Data","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1842 NULL, 0x0, "", HFILL }},
1843 { &hf_diameter_avp_data_time,
1844 { "AVP Data","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1845 NULL, 0x0, "", HFILL }},
1848 static gint *ett[] = {
1850 &ett_diameter_flags,
1852 &ett_diameter_avp_flags,
1853 &ett_diameter_avpinfo
1855 module_t *diameter_module;
1857 proto_diameter = proto_register_protocol (gbl_diameterString,
1858 "Diameter", "diameter");
1859 proto_register_field_array(proto_diameter, hf, array_length(hf));
1860 proto_register_subtree_array(ett, array_length(ett));
1862 /* Register a configuration option for port */
1863 diameter_module = prefs_register_protocol(proto_diameter,
1864 proto_reg_handoff_diameter);
1865 prefs_register_uint_preference(diameter_module, "tcp.port",
1866 "Diameter TCP Port",
1867 "Set the TCP port for Diameter messages",
1869 &gbl_diameterTcpPort);
1870 prefs_register_uint_preference(diameter_module, "sctp.port",
1871 "Diameter SCTP Port",
1872 "Set the SCTP port for Diameter messages",
1874 &gbl_diameterSctpPort);
1876 * Build our default dictionary filename
1878 if (! gbl_diameterDictionary) {
1879 gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
1880 1 + strlen(DICT_FN) + 1); /* slash + fn + null */
1881 sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
1882 get_datafile_dir(), DICT_FN );
1884 /* Now register its preferences so it can be changed. */
1885 prefs_register_string_preference(diameter_module, "dictionary.name",
1886 "Diameter XML Dictionary",
1887 "Set the dictionary used for Diameter messages",
1888 &gbl_diameterDictionary);
1890 /* Desegmentation */
1891 prefs_register_bool_preference(diameter_module, "desegment",
1892 "Desegment all Diameter messages spanning multiple TCP segments",
1893 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1894 &gbl_diameter_desegment);
1896 /* Register some preferences we no longer support, so we can report
1897 them as obsolete rather than just illegal. */
1898 prefs_register_obsolete_preference(diameter_module, "udp.port");
1899 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1900 } /* proto_register_diameter */