2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.56 2003/10/29 21:19:44 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.
37 #include <epan/filesystem.h>
39 #include <epan/packet.h>
40 #include <epan/resolv.h>
43 #ifdef NEED_SNPRINTF_H
44 # include "snprintf.h"
47 /* This must be defined before we include packet-diameter-defs.h */
49 /* Valid data types */
52 DIAMETER_OCTET_STRING = 1,
63 DIAMETER_IP_ADDRESS, /* OctetString */
64 DIAMETER_TIME, /* Integer 32 */
65 DIAMETER_UTF8STRING, /* OctetString */
66 DIAMETER_IDENTITY, /* OctetString */
67 DIAMETER_ENUMERATED, /* Integer 32 */
68 DIAMETER_IP_FILTER_RULE, /* OctetString */
69 DIAMETER_QOS_FILTER_RULE, /* OctetString */
70 DIAMETER_MIP_REG_REQ, /* OctetString */
71 DIAMETER_VENDOR_ID, /* Integer32 */
72 DIAMETER_APPLICATION_ID
77 static value_string TypeValues[]={
78 { DIAMETER_OCTET_STRING, "OctetString" },
79 { DIAMETER_INTEGER32, "Integer32" },
80 { DIAMETER_INTEGER64, "Integer64" },
81 { DIAMETER_UNSIGNED32, "Unsigned32" },
82 { DIAMETER_UNSIGNED64, "Unsigned64" },
83 { DIAMETER_FLOAT32, "Float32" },
84 { DIAMETER_FLOAT64, "Float64" },
85 { DIAMETER_FLOAT128, "Float128" },
86 { DIAMETER_GROUPED, "Grouped" },
87 { DIAMETER_IP_ADDRESS, "IpAddress" },
88 { DIAMETER_TIME, "Time" },
89 { DIAMETER_UTF8STRING, "UTF8String" },
90 { DIAMETER_IDENTITY, "DiameterIdentity" },
91 { DIAMETER_ENUMERATED, "Enumerated" },
92 { DIAMETER_IP_FILTER_RULE, "IPFilterRule" },
93 { DIAMETER_QOS_FILTER_RULE, "QOSFilterRule" },
94 { DIAMETER_MIP_REG_REQ, "MIPRegistrationRequest"},
95 { DIAMETER_VENDOR_ID, "VendorId"},
96 { DIAMETER_APPLICATION_ID, "AppId"},
100 typedef struct value_name {
103 struct value_name *next;
106 typedef struct old_avp_info {
109 diameterDataType type;
110 value_string *values;
113 typedef struct avp_info {
117 diameterDataType type;
119 struct avp_info *next;
122 typedef struct command_code {
126 struct command_code *next;
129 typedef struct vendor_id {
133 struct vendor_id *next;
136 typedef struct application_id {
139 struct application_id *next;
142 static avpInfo *avpListHead=NULL;
143 static VendorId *vendorListHead=NULL;
144 static CommandCode *commandListHead=NULL;
145 static ApplicationId *ApplicationIdHead=NULL;
148 #include "packet-diameter-defs.h"
150 #define NTP_TIME_DIFF (2208988800UL)
152 #define TCP_PORT_DIAMETER 1812
153 #define SCTP_PORT_DIAMETER 1812
155 static const true_false_string reserved_set = {
156 "*** Error! Reserved Bit is Set",
159 static int proto_diameter = -1;
160 static int hf_diameter_length = -1;
161 static int hf_diameter_code = -1;
162 static int hf_diameter_hopbyhopid =-1;
163 static int hf_diameter_endtoendid =-1;
164 static int hf_diameter_version = -1;
165 static int hf_diameter_vendor_id = -1;
166 static int hf_diameter_flags = -1;
167 static int hf_diameter_flags_request = -1;
168 static int hf_diameter_flags_proxyable = -1;
169 static int hf_diameter_flags_error = -1;
170 static int hf_diameter_flags_reserved3 = -1;
171 static int hf_diameter_flags_reserved4 = -1;
172 static int hf_diameter_flags_reserved5 = -1;
173 static int hf_diameter_flags_reserved6 = -1;
174 static int hf_diameter_flags_reserved7 = -1;
176 static int hf_diameter_avp_code = -1;
177 static int hf_diameter_avp_length = -1;
178 static int hf_diameter_avp_flags = -1;
179 static int hf_diameter_avp_flags_vendor_specific = -1;
180 static int hf_diameter_avp_flags_mandatory = -1;
181 static int hf_diameter_avp_flags_protected = -1;
182 static int hf_diameter_avp_flags_reserved3 = -1;
183 static int hf_diameter_avp_flags_reserved4 = -1;
184 static int hf_diameter_avp_flags_reserved5 = -1;
185 static int hf_diameter_avp_flags_reserved6 = -1;
186 static int hf_diameter_avp_flags_reserved7 = -1;
187 static int hf_diameter_avp_vendor_id = -1;
190 static int hf_diameter_avp_data_uint32 = -1;
191 static int hf_diameter_avp_data_int32 = -1;
192 static int hf_diameter_avp_data_uint64 = -1;
193 static int hf_diameter_avp_data_int64 = -1;
194 static int hf_diameter_avp_data_bytes = -1;
195 static int hf_diameter_avp_data_string = -1;
196 static int hf_diameter_avp_data_v4addr = -1;
197 static int hf_diameter_avp_data_v6addr = -1;
198 static int hf_diameter_avp_data_time = -1;
200 static gint ett_diameter = -1;
201 static gint ett_diameter_flags = -1;
202 static gint ett_diameter_avp = -1;
203 static gint ett_diameter_avp_flags = -1;
204 static gint ett_diameter_avpinfo = -1;
206 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
207 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
209 /* desegmentation of Diameter over TCP */
210 static gboolean gbl_diameter_desegment = TRUE;
212 #define DICT_FN "diameter/dictionary.xml"
213 static gchar *gbl_diameterDictionary;
215 typedef struct _e_diameterhdr {
216 guint32 versionLength;
217 guint32 flagsCmdCode;
223 typedef struct _e_avphdr {
225 guint32 avp_flagsLength;
226 guint32 avp_vendorId; /* optional */
229 /* Diameter Header Flags */
230 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
231 #define DIAM_FLAGS_R 0x80
232 #define DIAM_FLAGS_P 0x40
233 #define DIAM_FLAGS_E 0x20
234 #define DIAM_FLAGS_RESERVED3 0x10
235 #define DIAM_FLAGS_RESERVED4 0x08
236 #define DIAM_FLAGS_RESERVED5 0x04
237 #define DIAM_FLAGS_RESERVED6 0x02
238 #define DIAM_FLAGS_RESERVED7 0x01
239 #define DIAM_FLAGS_RESERVED 0x1f
241 #define DIAM_LENGTH_MASK 0x00ffffffl
242 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
243 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
244 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
245 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
246 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
248 /* Diameter AVP Flags */
249 #define AVP_FLAGS_P 0x20
250 #define AVP_FLAGS_V 0x80
251 #define AVP_FLAGS_M 0x40
252 #define AVP_FLAGS_RESERVED3 0x10
253 #define AVP_FLAGS_RESERVED4 0x08
254 #define AVP_FLAGS_RESERVED5 0x04
255 #define AVP_FLAGS_RESERVED6 0x02
256 #define AVP_FLAGS_RESERVED7 0x01
257 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
259 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
260 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
262 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
266 * This routine will do a push-parse of the passed in
267 * filename. This was taken almost verbatum from
268 * the xmlsoft examples.
271 xmlParseFilePush( char *filename, int checkValid) {
275 int res, size = 1024;
277 xmlParserCtxtPtr ctxt;
279 /* I wonder what kind of a performance hit this is? */
280 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
282 f = fopen(filename, "r");
284 g_warning("Diameter: Unable to open %s", filename);
288 res = fread(chars, 1, 4, f);
290 ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
291 chars, res, filename);
292 while ((res = fread(chars, 1, size-1, f)) > 0) {
293 XmlStub.xmlParseChunk(ctxt, chars, res, 0);
295 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
298 XmlStub.xmlFreeParserCtxt(ctxt);
304 g_warning( "Error! Invalid xml in %s! Failed DTD check!",
309 } /* xmlParseFilePush */
312 * This routine will add a static avp to the avp list. It is
313 * only called when the XML dictionary fails to load properly.
316 addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
319 ValueName *vEntry=NULL;
322 /* Parse our values array, if we have one */
324 for (i=0; values[i].strptr != NULL; i++) {
325 ValueName *ve = NULL;
327 ve = g_malloc(sizeof(ValueName));
328 ve->name = strdup(values[i].strptr);
329 ve->value = values[i].value;
335 /* And, create the entry */
336 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
337 entry->name = g_strdup(name);
339 entry->vendorName = NULL;
341 entry->values = vEntry;
343 entry->type = DIAMETER_INTEGER32;
345 /* And, add it to the list */
346 entry->next = avpListHead;
354 * This routine will parse an XML avp entry, and add it to our
355 * avp list. If any values are present in the avp, it will
359 xmlParseAVP(xmlNodePtr cur)
361 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
362 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
367 ValueName *vEntry=NULL;
370 /* First, get our properties */
371 name = XmlStub.xmlGetProp(cur, "name");
372 description = XmlStub.xmlGetProp(cur, "description");
373 code = XmlStub.xmlGetProp(cur, "code");
374 mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
375 mandatory = XmlStub.xmlGetProp(cur, "mandatory");
376 protected = XmlStub.xmlGetProp(cur, "protected");
377 vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
378 vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
379 constrained = XmlStub.xmlGetProp(cur, "constrained");
381 cur = cur->xmlChildrenNode;
383 while (cur != NULL ) {
384 if (strcasecmp(cur->name, "type") == 0) {
385 type = XmlStub.xmlGetProp(cur, "type-name");
386 } else if (strcasecmp(cur->name, "enum") == 0) {
387 char *valueName=NULL, *valueCode=NULL;
388 ValueName *ve = NULL;
389 valueName = XmlStub.xmlGetProp(cur, "name");
390 valueCode = XmlStub.xmlGetProp(cur, "code");
392 if (!valueName || !valueCode) {
393 g_warning( "Error, bad value on avp %s", name);
397 ve = g_malloc(sizeof(ValueName));
398 ve->name = strdup(valueName);
399 ve->value = atol(valueCode);
403 } else if (strcasecmp(cur->name, "grouped") == 0) {
404 /* WORK Recurse here for grouped AVPs */
411 * Check for the AVP Type.
414 for (i = 0; TypeValues[i].strptr; i++) {
415 if (!strcasecmp(type, TypeValues[i].strptr)) {
416 avpType = TypeValues[i].value;
421 if (TypeValues[i].strptr == NULL) {
422 g_warning( "Invalid Type field in dictionary! avp %s (%s)", name, type);
425 } else if (!vEntry) {
426 g_warning("Missing type/enum field in dictionary avpName=%s",
431 /* WORK - Handle flags -- for validation later */
434 /* And, create the entry */
435 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
436 entry->name = g_strdup(name);
437 entry->code = atol(code);
439 entry->vendorName = g_strdup(vendorName);
441 entry->vendorName = NULL;
442 entry->type = avpType;
443 entry->values = vEntry;
445 entry->type = DIAMETER_INTEGER32;
447 /* And, add it to the list */
448 entry->next = avpListHead;
455 * This routine will add a command to the list of commands.
458 addCommand(int code, char *name, char *vendorId)
463 * Allocate the memory required for the dictionary.
465 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
468 g_warning("Unable to allocate memory");
473 * Allocate memory for the AVPName and copy the name to the
476 entry->name = g_strdup(name);
479 entry->vendorName = g_strdup(vendorId);
481 entry->vendorName = "None";
483 /* Add the entry to the list */
484 entry->next = commandListHead;
485 commandListHead = entry;
491 * This routine will parse the XML command, and add it to our
495 xmlParseCommand(xmlNodePtr cur)
497 char *name, *code, *vendorIdString;
502 name = XmlStub.xmlGetProp(cur, "name");
503 code = XmlStub.xmlGetProp(cur, "code");
504 if (!name || !code) {
505 g_warning("Invalid command. Name or code missing!");
508 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
510 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
511 vendorIdString = NULL;
514 return (addCommand(atoi(code), name, vendorIdString));
515 } /* xmlParseCommand */
517 /* This routine adds an application to the name<-> id table */
519 dictionaryAddApplication(char *name, int id)
521 ApplicationId *entry;
523 if (!name || (id <= 0)) {
524 g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
527 } /* Sanity Checks */
529 entry = g_malloc(sizeof(ApplicationId));
531 g_warning( "Unable to allocate memory");
535 entry->name = g_strdup(name);
538 /* Add it to the list */
539 entry->next = ApplicationIdHead;
540 ApplicationIdHead = entry;
543 } /* dictionaryAddApplication */
546 * This routine will add a vendor to the vendors list
549 addVendor(int id, gchar *name, gchar *longName)
554 vendor=g_malloc(sizeof(VendorId));
560 vendor->name = g_strdup(name);
561 vendor->longName = g_strdup(longName);
562 vendor->next = vendorListHead;
563 vendorListHead = vendor;
569 * This routine will pars in a XML vendor entry.
572 xmlParseVendor(xmlNodePtr cur)
574 char *name=NULL, *code=NULL, *id=NULL;
576 /* First, get our properties */
577 id = XmlStub.xmlGetProp(cur, "vendor-id");
578 name = XmlStub.xmlGetProp(cur, "name");
579 code = XmlStub.xmlGetProp(cur, "code");
581 if (!id || !name || !code) {
582 g_warning( "Invalid vendor section. vendor-id, name, and code must be specified");
586 return (addVendor(atoi(code), id, name));
590 * This routine will either parse in the base protocol, or an application.
593 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
599 /* Add our application */
600 id = XmlStub.xmlGetProp(cur, "id");
601 name = XmlStub.xmlGetProp(cur, "name");
605 g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
606 name?name:"NULL", id?id:"NULL");
610 /* Add the application */
611 if (dictionaryAddApplication(name, atol(id)) != 0) {
621 cur = cur->xmlChildrenNode;
622 while (cur != NULL) {
623 if (strcasecmp(cur->name, "avp") == 0) {
624 /* we have an avp!!! */
626 } else if (strcasecmp(cur->name, "vendor") == 0) {
627 /* we have a vendor */
629 /* For now, ignore typedefn and text */
630 } else if (strcasecmp(cur->name, "command") == 0) {
631 /* Found a command */
632 xmlParseCommand(cur);
633 } else if (strcasecmp(cur->name, "text") == 0) {
634 } else if (strcasecmp(cur->name, "comment") == 0) {
635 } else if (strcasecmp(cur->name, "typedefn") == 0) {
636 /* WORK -- parse in valid types . . . */
638 /* IF we got here, we're an error */
639 g_warning("Error! expecting an avp or a typedefn (got \"%s\")",
646 } /* xmlDictionaryParseSegment */
649 * The main xml parse routine. This will walk through an XML
650 * dictionary that has been parsed by libxml.
653 xmlDictionaryParse(xmlNodePtr cur)
655 /* We should expect a base protocol, followed by multiple applicaitons */
656 while (cur != NULL) {
657 if (strcasecmp(cur->name, "base") == 0) {
658 /* Base protocol. Descend and parse */
659 xmlDictionaryParseSegment(cur, 1);
660 } else if (strcasecmp(cur->name, "application") == 0) {
661 /* Application. Descend and parse */
662 xmlDictionaryParseSegment(cur, 0);
663 } else if (strcasecmp(cur->name, "text") == 0) {
666 g_warning( "Diameter: XML Expecting a base or an application (got \"%s\")",
675 } /* xmlDictionaryParse */
678 * This routine will call libxml to parse in the dictionary.
687 * build an XML tree from a the file;
689 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
690 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
691 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
693 /* Check for invalid xml */
695 g_warning("Diameter: Unable to parse xmldictionary %s",
696 gbl_diameterDictionary);
701 * Check the document is of the right kind
703 cur = XmlStub.xmlDocGetRootElement(doc);
705 g_warning("Diameter: Error: \"%s\": empty document",
706 gbl_diameterDictionary);
707 XmlStub.xmlFreeDoc(doc);
710 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
711 g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
712 gbl_diameterDictionary);
713 XmlStub.xmlFreeDoc(doc);
718 * Ok, the dictionary has been parsed by libxml, and is valid.
719 * All we have to do now is read in our information.
721 if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
722 /* Error has already been printed */
726 /* Once we're done parsing, free up the xml memory */
727 XmlStub.xmlFreeDoc(doc);
731 } /* loadXMLDictionary */
734 * Fallback routine. In the event of ANY error when loading the XML
735 * dictionary, this routine will populate the new avp list structures
736 * with the old static data from packet-diameter-defs.h
739 initializeDictionaryDefaults()
743 /* Add static vendors to list */
744 for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
745 addVendor(diameter_vendor_specific_vendors[i].value,
746 diameter_vendor_specific_vendors[i].strptr,
747 diameter_vendor_specific_vendors[i].strptr);
749 /* Add static commands to list. */
750 for(i=0; diameter_command_code_vals[i].strptr; i++) {
751 addCommand(diameter_command_code_vals[i].value,
752 diameter_command_code_vals[i].strptr, NULL);
755 /* Add static AVPs to list */
756 for (i=0; old_diameter_avps[i].name; i++) {
757 addStaticAVP(old_diameter_avps[i].code,
758 old_diameter_avps[i].name,
759 old_diameter_avps[i].type,
760 old_diameter_avps[i].values);
763 } /* initializeDictionaryDefaults */
766 * This routine will attempt to load the XML dictionary, and on
767 * failure, will call initializeDictionaryDefaults to load in
768 * our static dictionary.
771 initializeDictionary()
774 * Using ugly ordering here. If loadLibXML succeeds, then
775 * loadXMLDictionary will be called. This is one of the few times when
776 * I think this is prettier than the nested if alternative.
779 (loadXMLDictionary() != 0)) {
780 /* Something failed. Use the static dictionary */
781 g_warning("Diameter: Using static dictionary! (Unable to use XML)");
782 initializeDictionaryDefaults();
784 } /* initializeDictionary */
789 * These routines manipulate the diameter structures.
792 /* return vendor string, based on the id */
794 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
796 static gchar buffer[64];
798 for (probe=vendorListHead; probe; probe=probe->next) {
799 if (vendorId == probe->id) {
801 return probe->longName;
807 snprintf(buffer, sizeof(buffer),
808 "Vendor 0x%08x", vendorId);
810 } /*diameter_vendor_to_str */
812 /* return command string, based on the code */
814 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
817 static gchar buffer[64];
818 gchar *vendorName=NULL;
821 vendorName = diameter_vendor_to_str(vendorId, FALSE);
823 for (probe=commandListHead; probe; probe=probe->next) {
824 if (commandCode == probe->code) {
826 /* g_warning("Command: Comparing \"%s\" to \"%s\"", */
827 /* vendorName?vendorName:"(null)", */
828 /* probe->vendorName?probe->vendorName:"(null)"); */
829 /* Now check the vendor name */
830 if (!strcmp(vendorName, probe->vendorName))
834 /* With no vendor id, the Command's entry should be "None" */
835 if (!strcmp(probe->vendorName, "None")) {
843 g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
844 commandCode, vendorId);
845 snprintf(buffer, sizeof(buffer),
846 "Cmd-0x%08x", commandCode);
848 }/*diameter_command_to_str */
850 /* return application string, based on the id */
852 diameter_app_to_str(guint32 vendorId) {
853 ApplicationId *probe;
854 static gchar buffer[64];
856 for (probe=ApplicationIdHead; probe; probe=probe->next) {
857 if (vendorId == probe->id) {
862 snprintf(buffer, sizeof(buffer),
863 "AppId 0x%08x", vendorId);
865 } /*diameter_app_to_str */
867 /* return an avp type, based on the code */
868 static diameterDataType
869 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
871 gchar *vendorName=NULL;
874 vendorName = diameter_vendor_to_str(vendorId, FALSE);
876 for (probe=avpListHead; probe; probe=probe->next) {
877 if (avpCode == probe->code) {
880 /* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
881 /* vendorName?vendorName:"(null)", */
882 /* probe->vendorName?probe->vendorName:"(null)"); */
883 /* Now check the vendor name */
884 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
888 /* No Vendor ID -- vendorName should be null */
889 if (!probe->vendorName)
896 /* If we don't find it, assume it's data */
897 g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
899 return DIAMETER_OCTET_STRING;
900 } /* diameter_avp_get_type */
902 /* return an avp name from the code */
904 diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
906 static gchar buffer[64];
908 gchar *vendorName=NULL;
911 vendorName = diameter_vendor_to_str(vendorId, FALSE);
913 for (probe=avpListHead; probe; probe=probe->next) {
914 if (avpCode == probe->code) {
916 /* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
917 /* vendorName?vendorName:"(null)", */
918 /* probe->vendorName?probe->vendorName:"(null)"); */
919 /* Now check the vendor name */
920 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
924 /* No Vendor ID -- vendorName should be null */
925 if (!probe->vendorName)
932 g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
935 /* If we don't find it, build a name string */
936 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
938 } /* diameter_avp_get_name */
940 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
942 static gchar buffer[64];
945 gchar *vendorName=NULL;
948 vendorName = diameter_vendor_to_str(vendorId, FALSE);
950 for (probe=avpListHead; probe; probe=probe->next) {
951 if (avpCode == probe->code) {
953 /* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
954 /* vendorName?vendorName:"(null)", */
955 /* probe->vendorName?probe->vendorName:"(null)"); */
956 /* Now check the vendor name */
957 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
959 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
960 if (avpValue == vprobe->value) {
964 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
968 if (!probe->vendorName) {
970 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
971 if (avpValue == vprobe->value) {
975 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
981 /* If we don't find the avp, build a value string */
982 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
984 } /* diameter_avp_get_value */
987 /* Code to actually dissect the packets */
992 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
996 /* Set up structures needed to add the protocol subtree and manage it */
999 proto_tree *flags_tree;
1001 proto_tree *diameter_tree;
1005 proto_tree *avp_tree;
1007 int BadPacket = FALSE;
1008 guint32 commandCode, pktLength;
1009 guint8 version, flags;
1010 gchar flagstr[64] = "<None>";
1011 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1012 gchar commandString[64], vendorName[64];
1015 static int initialized=FALSE;
1017 /* set our offset */
1021 * Only parse in dictionary if there are diameter packets to
1025 /* Read in our dictionary, if it exists. */
1026 initializeDictionary();
1030 /* Make entries in Protocol column and Info column on summary display */
1031 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1032 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1033 if (check_col(pinfo->cinfo, COL_INFO))
1034 col_clear(pinfo->cinfo, COL_INFO);
1036 /* Copy our header */
1037 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1039 /* Fix byte ordering in our static structure */
1040 dh.versionLength = g_ntohl(dh.versionLength);
1041 dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
1042 dh.vendorId = g_ntohl(dh.vendorId);
1043 dh.hopByHopId = g_ntohl(dh.hopByHopId);
1044 dh.endToEndId = g_ntohl(dh.endToEndId);
1048 diameter_vendor_to_str(dh.vendorId, TRUE));
1050 strcpy(vendorName, "None");
1054 /* Do the bit twiddling */
1055 version = DIAM_GET_VERSION(dh);
1056 pktLength = DIAM_GET_LENGTH(dh);
1057 flags = DIAM_GET_FLAGS(dh);
1058 commandCode = DIAM_GET_COMMAND(dh);
1060 /* Set up our flags */
1061 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1063 for (i = 0; i < 8; i++) {
1067 strcat(flagstr, ", ");
1069 strcat(flagstr, fstr[i]);
1072 if (strlen(flagstr) == 0) {
1073 strcpy(flagstr,"<None>");
1077 /* Set up our commandString */
1078 strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1079 if (flags & DIAM_FLAGS_R)
1080 strcat(commandString, "-Request");
1082 strcat(commandString, "-Answer");
1084 /* Short packet. Should have at LEAST one avp */
1085 if (pktLength < MIN_DIAMETER_SIZE) {
1086 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1087 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1091 /* And, check our reserved flags/version */
1092 if ((flags & DIAM_FLAGS_RESERVED) ||
1094 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1099 if (check_col(pinfo->cinfo, COL_INFO)) {
1100 col_add_fstr(pinfo->cinfo, COL_INFO,
1101 "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1102 (BadPacket)?"***** Bad Packet!: ":"",
1103 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1104 (flags & DIAM_FLAGS_E)?" Error":"",
1106 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1108 commandString, vendorName,
1109 dh.hopByHopId, dh.endToEndId,
1110 (flags & DIAM_FLAGS_R)?1:0,
1111 (flags & DIAM_FLAGS_P)?1:0,
1112 (flags & DIAM_FLAGS_E)?1:0);
1116 /* In the interest of speed, if "tree" is NULL, don't do any work not
1117 necessary to generate protocol tree items. */
1120 /* create display subtree for the protocol */
1121 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1122 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1123 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1126 proto_tree_add_uint(diameter_tree,
1127 hf_diameter_version,
1134 proto_tree_add_uint(diameter_tree,
1135 hf_diameter_length, tvb,
1136 offset, 3, pktLength);
1140 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1141 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1143 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1144 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1145 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1146 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1147 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1148 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1149 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1150 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1151 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1156 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1157 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1161 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1162 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
1165 /* Hop-by-hop Identifier */
1166 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1167 tvb, offset, 4, dh.hopByHopId);
1170 /* End-to-end Identifier */
1171 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1172 tvb, offset, 4, dh.endToEndId);
1175 /* If we have a bad packet, don't bother trying to parse the AVPs */
1177 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1180 /* Start looking at the AVPS */
1181 /* Make the next tvbuff */
1183 /* Update the lengths */
1184 avplength= pktLength - sizeof(e_diameterhdr);
1186 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1187 avptf = proto_tree_add_text(diameter_tree,
1188 tvb, offset, avplength,
1189 "Attribute Value Pairs");
1191 avp_tree = proto_item_add_subtree(avptf,
1193 if (avp_tree != NULL) {
1194 dissect_avps( avp_tvb, pinfo, avp_tree);
1196 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1198 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1200 } /* dissect_diameter_common */
1203 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1205 dissect_diameter_common(tvb, 0, pinfo, tree);
1209 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1213 guint32 available_bytes;
1214 /* guint32 noffset; */
1216 /* Loop through the packet, dissecting multiple diameter messages */
1218 available_bytes = tvb_length_remaining(tvb, offset);
1219 if (available_bytes < 4) {
1220 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1222 return; /* Bail. We can't even get our length */
1225 /* get our packet length */
1226 plen = tvb_get_ntohl(tvb, offset);
1227 plen &= 0x00ffffff; /* get rid of the flags */
1230 if (gbl_diameter_desegment) {
1231 if (pinfo->can_desegment
1232 && plen > available_bytes) {
1233 pinfo->desegment_offset = offset;
1234 pinfo->desegment_len = plen - available_bytes;
1235 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1236 /* plen, available_bytes); */
1241 /* Otherwise, dissect our packet */
1242 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1244 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1245 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1246 /* offset=noffset; */
1247 } while (offset < tvb_reported_length(tvb));
1249 } /* dissect_diameter_tcp */
1252 * Call the mip_dissector, after saving our pinfo variables
1253 * so it doesn't write to our column display.
1256 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1257 size_t offset, size_t length)
1259 static dissector_handle_t mip_handle;
1260 static int mipInitialized=FALSE;
1262 address save_dl_src;
1263 address save_dl_dst;
1264 address save_net_src;
1265 address save_net_dst;
1268 gboolean save_in_error_pkt;
1270 if (!mipInitialized) {
1271 mip_handle = find_dissector("mip");
1272 mipInitialized=TRUE;
1275 mip_tvb = tvb_new_subset(tvb, offset,
1276 MIN(length, tvb_length(tvb)-offset),
1279 /* The contained packet is a MIP registration request;
1280 dissect it with the MIP dissector. */
1281 col_set_writable(pinfo->cinfo, FALSE);
1283 /* Also, save the current values of the addresses, and restore
1284 them when we're finished dissecting the contained packet, so
1285 that the address columns in the summary don't reflect the
1286 contained packet, but reflect this packet instead. */
1287 save_dl_src = pinfo->dl_src;
1288 save_dl_dst = pinfo->dl_dst;
1289 save_net_src = pinfo->net_src;
1290 save_net_dst = pinfo->net_dst;
1291 save_src = pinfo->src;
1292 save_dst = pinfo->dst;
1293 save_in_error_pkt = pinfo->in_error_pkt;
1295 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1297 /* Restore the "we're inside an error packet" flag. */
1298 pinfo->in_error_pkt = save_in_error_pkt;
1299 pinfo->dl_src = save_dl_src;
1300 pinfo->dl_dst = save_dl_dst;
1301 pinfo->net_src = save_net_src;
1302 pinfo->net_dst = save_net_dst;
1303 pinfo->src = save_src;
1304 pinfo->dst = save_dst;
1307 } /* safe_dissect_mip */
1310 * This function will dissect the AVPs in a diameter packet. It handles
1311 * all normal types, and even recursively calls itself for grouped AVPs
1313 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1315 /* adds the attribute value pairs to the tree */
1317 gchar avpTypeString[64];
1318 gchar avpNameString[64];
1321 gchar vendorName[64];
1324 proto_tree *avpi_tree;
1326 tvbuff_t *group_tvb;
1327 proto_tree *group_tree;
1328 proto_item *grouptf;
1331 int BadPacket = FALSE;
1335 proto_tree *flags_tree;
1337 gint32 packetLength;
1338 size_t avpDataLength;
1340 gchar flagstr[64] = "<None>";
1341 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1345 packetLength = tvb_length(tvb);
1347 /* Check for invalid packet lengths */
1348 if (packetLength <= 0) {
1349 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1350 "No Attribute Value Pairs Found");
1354 /* Spin around until we run out of packet */
1355 while (packetLength > 0 ) {
1357 /* Check for short packet */
1358 if (packetLength < (long)MIN_AVP_SIZE) {
1359 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1360 packetLength, (long)MIN_AVP_SIZE);
1362 /* Don't even bother trying to parse a short packet. */
1366 /* Copy our header */
1367 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1369 /* Fix the byte ordering */
1370 avph.avp_code = g_ntohl(avph.avp_code);
1371 avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1373 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1374 avpLength = avph.avp_flagsLength & 0x00ffffff;
1376 /* Set up our flags string */
1377 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1379 for (i = 0; i < 8; i++) {
1383 strcat(flagstr, ", ");
1385 strcat(flagstr, fstr[i]);
1388 if (strlen(flagstr) == 0) {
1389 strcpy(flagstr,"<None>");
1393 /* Dissect our vendor id if it exists and set hdr length */
1394 if (flags & AVP_FLAGS_V) {
1395 vendorId = g_ntohl(avph.avp_vendorId);
1397 hdrLength = sizeof(e_avphdr);
1400 hdrLength = sizeof(e_avphdr) -
1407 diameter_vendor_to_str(vendorId, TRUE));
1412 /* Check for bad length */
1413 if (avpLength < MIN_AVP_SIZE ||
1414 ((long)avpLength > packetLength)) {
1415 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1416 "min: %ld bytes, packetLen: %d",
1417 (long)avpLength, (long)MIN_AVP_SIZE,
1422 /* Check for bad flags */
1423 if (flags & AVP_FLAGS_RESERVED) {
1424 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1426 flags, AVP_FLAGS_RESERVED);
1427 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1428 /* BadPacket = TRUE; */
1432 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1435 fixAmt = 4 - (avpLength % 4);
1436 if (fixAmt == 4) fixAmt = 0;
1438 /* shrink our packetLength */
1439 packetLength = packetLength - (avpLength + fixAmt);
1441 /* Check for out of bounds */
1442 if (packetLength < 0) {
1443 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1448 /* Make avp Name & type */
1449 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1451 "Unknown-Type: 0x%08x"));
1452 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1454 avptf = proto_tree_add_text(avp_tree, tvb,
1455 offset, avpLength + fixAmt,
1456 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1457 avpNameString, avpTypeString, avpLength,
1458 avpLength, avpLength+fixAmt);
1459 avpi_tree = proto_item_add_subtree(avptf,
1460 ett_diameter_avpinfo);
1462 if (avpi_tree !=NULL) {
1464 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1465 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1468 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1469 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1471 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1472 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1473 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1474 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1475 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1476 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1477 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1478 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1479 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1482 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1483 tvb, offset, 3, avpLength);
1486 if (flags & AVP_FLAGS_V) {
1487 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1488 tvb, offset, 4, vendorId, vendorName);
1492 avpDataLength = avpLength - hdrLength;
1495 * If we've got a bad packet, just highlight the data. Don't try
1496 * to parse it, and, don't move to next AVP.
1499 offset -= hdrLength;
1500 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1501 tvb, offset, tvb_length(tvb) - offset,
1502 tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1503 "Bad AVP (Suspect Data Not Dissected)");
1507 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1510 case DIAMETER_GROUPED:
1511 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1512 /* Recursively call ourselves */
1513 grouptf = proto_tree_add_text(avpi_tree,
1514 tvb, offset, tvb_length(tvb),
1517 group_tree = proto_item_add_subtree(grouptf,
1520 group_tvb = tvb_new_subset(tvb, offset,
1521 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1522 if (group_tree != NULL) {
1523 dissect_avps( group_tvb, pinfo, group_tree);
1527 case DIAMETER_IDENTITY:
1531 data = tvb_get_ptr(tvb, offset, avpDataLength);
1532 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1533 tvb, offset, avpDataLength, data,
1536 (int)avpDataLength, data);
1539 case DIAMETER_UTF8STRING:
1543 data = tvb_get_ptr(tvb, offset, avpDataLength);
1544 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1545 tvb, offset, avpDataLength, data,
1546 "UTF8String: %*.*s",
1548 (int)avpDataLength, data);
1551 case DIAMETER_IP_ADDRESS:
1552 if (avpDataLength == 4) {
1553 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1554 tvb, offset, avpDataLength, FALSE);
1555 } else if (avpDataLength == 16) {
1556 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1557 tvb, offset, avpDataLength, FALSE);
1559 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1560 tvb, offset, avpDataLength,
1561 tvb_get_ptr(tvb, offset, avpDataLength),
1562 "Error! Bad Address Length");
1566 case DIAMETER_INTEGER32:
1567 if (avpDataLength == 4) {
1568 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1569 tvb, offset, avpDataLength, FALSE);
1571 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1572 tvb, offset, avpDataLength,
1573 tvb_get_ptr(tvb, offset, avpDataLength),
1574 "Error! Bad Integer32 Length");
1578 case DIAMETER_UNSIGNED32:
1579 if (avpDataLength == 4) {
1582 data = tvb_get_ntohl(tvb, offset);
1583 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1584 tvb, offset, avpDataLength, data,
1585 "Value: 0x%08x (%u)", data, data);
1587 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1588 tvb, offset, avpDataLength,
1589 tvb_get_ptr(tvb, offset, avpDataLength),
1590 "Error! Bad Unsigned32 Length");
1594 case DIAMETER_INTEGER64:
1595 if (avpDataLength == 8) {
1596 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1597 tvb, offset, 8, FALSE);
1599 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1600 tvb, offset, avpDataLength,
1601 tvb_get_ptr(tvb, offset, avpDataLength),
1602 "Error! Bad Integer64 Length");
1606 case DIAMETER_UNSIGNED64:
1607 if (avpDataLength == 8) {
1608 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1609 tvb, offset, 8, FALSE);
1611 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1612 tvb, offset, avpDataLength,
1613 tvb_get_ptr(tvb, offset, avpDataLength),
1614 "Error! Bad Unsigned64 Length");
1619 if (avpDataLength == 4) {
1624 data.secs = tvb_get_ntohl(tvb, offset);
1625 data.secs -= NTP_TIME_DIFF;
1628 ltp = localtime(&data.secs);
1629 strftime(buffer, 64,
1630 "%a, %d %b %Y %H:%M:%S %z", ltp);
1632 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1633 tvb, offset, avpDataLength, &data,
1634 "Time: %s", buffer);
1636 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1637 tvb, offset, avpDataLength,
1638 tvb_get_ptr(tvb, offset, avpDataLength),
1639 "Error! Bad Time Length");
1643 case DIAMETER_ENUMERATED:
1644 if (avpDataLength == 4) {
1647 data = tvb_get_ntohl(tvb, offset);
1648 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1649 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1650 tvb, offset, avpDataLength, data,
1651 "Value: 0x%08x (%u): %s", data,
1654 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1655 tvb, offset, avpDataLength,
1656 tvb_get_ptr(tvb, offset, avpDataLength),
1657 "Error! Bad Enumerated Length");
1660 case DIAMETER_VENDOR_ID:
1661 if (avpDataLength == 4) {
1664 data = tvb_get_ntohl(tvb, offset);
1665 valstr = diameter_vendor_to_str(data, TRUE);
1666 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1667 tvb, offset, avpDataLength, data,
1668 "Vendor ID: %s (0x%08x)", valstr,
1671 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1672 tvb, offset, avpDataLength,
1673 tvb_get_ptr(tvb, offset, avpDataLength),
1674 "Error! Bad Vendor ID Length");
1677 case DIAMETER_APPLICATION_ID:
1678 if (avpDataLength == 4) {
1681 data = tvb_get_ntohl(tvb, offset);
1682 valstr = diameter_app_to_str(data);
1683 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1684 tvb, offset, avpDataLength, data,
1685 "Application ID: %s (0x%08x)",
1688 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1689 tvb, offset, avpDataLength,
1690 tvb_get_ptr(tvb, offset, avpDataLength),
1691 "Error! Bad Application ID Length");
1694 case DIAMETER_MIP_REG_REQ:
1695 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1699 case DIAMETER_OCTET_STRING:
1700 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1701 tvb, offset, avpDataLength,
1702 tvb_get_ptr(tvb, offset, avpDataLength),
1703 "Hex Data Highlighted Below");
1707 } /* avpi_tree != null */
1708 offset += (avpLength - hdrLength);
1709 offset += fixAmt; /* fix byte alignment */
1711 } /* dissect_avps */
1716 proto_reg_handoff_diameter(void)
1718 static int Initialized=FALSE;
1719 static int TcpPort=0;
1720 static int SctpPort=0;
1721 static dissector_handle_t diameter_tcp_handle;
1722 static dissector_handle_t diameter_sctp_handle;
1725 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1727 diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1731 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1732 dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1735 /* set port for future deletes */
1736 TcpPort=gbl_diameterTcpPort;
1737 SctpPort=gbl_diameterSctpPort;
1739 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1740 gbl_diameterTcpPort); */
1741 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1742 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1745 /* registration with the filtering engine */
1747 proto_register_diameter(void)
1749 static hf_register_info hf[] = {
1750 { &hf_diameter_version,
1751 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1753 { &hf_diameter_length,
1754 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1757 { &hf_diameter_flags,
1758 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1760 { &hf_diameter_flags_request,
1761 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1763 { &hf_diameter_flags_proxyable,
1764 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1766 { &hf_diameter_flags_error,
1767 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1769 { &hf_diameter_flags_reserved3,
1770 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1771 DIAM_FLAGS_RESERVED3, "", HFILL }},
1772 { &hf_diameter_flags_reserved4,
1773 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1774 DIAM_FLAGS_RESERVED4, "", HFILL }},
1775 { &hf_diameter_flags_reserved5,
1776 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1777 DIAM_FLAGS_RESERVED5, "", HFILL }},
1778 { &hf_diameter_flags_reserved6,
1779 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1780 DIAM_FLAGS_RESERVED6, "", HFILL }},
1781 { &hf_diameter_flags_reserved7,
1782 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1783 DIAM_FLAGS_RESERVED7, "", HFILL }},
1785 { &hf_diameter_code,
1786 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1787 NULL, 0x0, "", HFILL }},
1788 { &hf_diameter_vendor_id,
1789 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1791 { &hf_diameter_hopbyhopid,
1792 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1793 BASE_HEX, NULL, 0x0, "", HFILL }},
1794 { &hf_diameter_endtoendid,
1795 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1796 BASE_HEX, NULL, 0x0, "", HFILL }},
1798 { &hf_diameter_avp_code,
1799 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1800 NULL, 0x0, "", HFILL }},
1801 { &hf_diameter_avp_length,
1802 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1803 NULL, 0x0, "", HFILL }},
1806 { &hf_diameter_avp_flags,
1807 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1808 NULL, 0x0, "", HFILL }},
1809 { &hf_diameter_avp_flags_vendor_specific,
1810 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1812 { &hf_diameter_avp_flags_mandatory,
1813 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1815 { &hf_diameter_avp_flags_protected,
1816 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1818 { &hf_diameter_avp_flags_reserved3,
1819 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1820 AVP_FLAGS_RESERVED3, "", HFILL }},
1821 { &hf_diameter_avp_flags_reserved4,
1822 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1823 AVP_FLAGS_RESERVED4, "", HFILL }},
1824 { &hf_diameter_avp_flags_reserved5,
1825 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1826 AVP_FLAGS_RESERVED5, "", HFILL }},
1827 { &hf_diameter_avp_flags_reserved6,
1828 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1829 AVP_FLAGS_RESERVED6, "", HFILL }},
1830 { &hf_diameter_avp_flags_reserved7,
1831 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1832 AVP_FLAGS_RESERVED7, "", HFILL }},
1833 { &hf_diameter_avp_vendor_id,
1834 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1835 NULL, 0x0, "", HFILL }},
1836 { &hf_diameter_avp_data_uint64,
1837 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1838 NULL, 0x0, "", HFILL }},
1839 { &hf_diameter_avp_data_int64,
1840 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1841 NULL, 0x0, "", HFILL }},
1842 { &hf_diameter_avp_data_uint32,
1843 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1844 NULL, 0x0, "", HFILL }},
1845 { &hf_diameter_avp_data_int32,
1846 { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1847 NULL, 0x0, "", HFILL }},
1848 { &hf_diameter_avp_data_bytes,
1849 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1850 NULL, 0x0, "", HFILL }},
1851 { &hf_diameter_avp_data_string,
1852 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1853 NULL, 0x0, "", HFILL }},
1854 { &hf_diameter_avp_data_v4addr,
1855 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1856 NULL, 0x0, "", HFILL }},
1857 { &hf_diameter_avp_data_v6addr,
1858 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1859 NULL, 0x0, "", HFILL }},
1860 { &hf_diameter_avp_data_time,
1861 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1862 NULL, 0x0, "", HFILL }},
1865 static gint *ett[] = {
1867 &ett_diameter_flags,
1869 &ett_diameter_avp_flags,
1870 &ett_diameter_avpinfo
1872 module_t *diameter_module;
1873 gchar *default_diameterDictionary;
1875 proto_diameter = proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
1876 proto_register_field_array(proto_diameter, hf, array_length(hf));
1877 proto_register_subtree_array(ett, array_length(ett));
1879 /* Register a configuration option for port */
1880 diameter_module = prefs_register_protocol(proto_diameter,
1881 proto_reg_handoff_diameter);
1882 prefs_register_uint_preference(diameter_module, "tcp.port",
1883 "Diameter TCP Port",
1884 "Set the TCP port for Diameter messages",
1886 &gbl_diameterTcpPort);
1887 prefs_register_uint_preference(diameter_module, "sctp.port",
1888 "Diameter SCTP Port",
1889 "Set the SCTP port for Diameter messages",
1891 &gbl_diameterSctpPort);
1893 * Build our default dictionary filename
1895 default_diameterDictionary = get_datafile_path(DICT_FN);
1898 * Now register the dictionary filename as a preference,
1899 * so it can be changed.
1901 gbl_diameterDictionary = default_diameterDictionary;
1902 prefs_register_string_preference(diameter_module, "dictionary.name",
1903 "Diameter XML Dictionary",
1904 "Set the dictionary used for Diameter messages",
1905 &gbl_diameterDictionary);
1908 * We don't need the default dictionary, so free it (a copy was made
1909 * of it in "gbl_diameterDictionary" by
1910 * "prefs_register_string_preference()").
1912 g_free(default_diameterDictionary);
1914 /* Desegmentation */
1915 prefs_register_bool_preference(diameter_module, "desegment",
1916 "Desegment all Diameter messages spanning multiple TCP segments",
1917 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1918 &gbl_diameter_desegment);
1920 /* Register some preferences we no longer support, so we can report
1921 them as obsolete rather than just illegal. */
1922 prefs_register_obsolete_preference(diameter_module, "udp.port");
1923 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1924 } /* proto_register_diameter */