2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.54 2003/05/15 07:44:53 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 flags_set_truth = {
160 static const true_false_string reserved_set = {
161 "*** Error! Reserved Bit is Set",
164 static int proto_diameter = -1;
165 static int hf_diameter_length = -1;
166 static int hf_diameter_code = -1;
167 static int hf_diameter_hopbyhopid =-1;
168 static int hf_diameter_endtoendid =-1;
169 static int hf_diameter_version = -1;
170 static int hf_diameter_vendor_id = -1;
171 static int hf_diameter_flags = -1;
172 static int hf_diameter_flags_request = -1;
173 static int hf_diameter_flags_proxyable = -1;
174 static int hf_diameter_flags_error = -1;
175 static int hf_diameter_flags_reserved3 = -1;
176 static int hf_diameter_flags_reserved4 = -1;
177 static int hf_diameter_flags_reserved5 = -1;
178 static int hf_diameter_flags_reserved6 = -1;
179 static int hf_diameter_flags_reserved7 = -1;
181 static int hf_diameter_avp_code = -1;
182 static int hf_diameter_avp_length = -1;
183 static int hf_diameter_avp_flags = -1;
184 static int hf_diameter_avp_flags_vendor_specific = -1;
185 static int hf_diameter_avp_flags_mandatory = -1;
186 static int hf_diameter_avp_flags_protected = -1;
187 static int hf_diameter_avp_flags_reserved3 = -1;
188 static int hf_diameter_avp_flags_reserved4 = -1;
189 static int hf_diameter_avp_flags_reserved5 = -1;
190 static int hf_diameter_avp_flags_reserved6 = -1;
191 static int hf_diameter_avp_flags_reserved7 = -1;
192 static int hf_diameter_avp_vendor_id = -1;
195 static int hf_diameter_avp_data_uint32 = -1;
196 static int hf_diameter_avp_data_int32 = -1;
197 static int hf_diameter_avp_data_uint64 = -1;
198 static int hf_diameter_avp_data_int64 = -1;
199 static int hf_diameter_avp_data_bytes = -1;
200 static int hf_diameter_avp_data_string = -1;
201 static int hf_diameter_avp_data_v4addr = -1;
202 static int hf_diameter_avp_data_v6addr = -1;
203 static int hf_diameter_avp_data_time = -1;
205 static gint ett_diameter = -1;
206 static gint ett_diameter_flags = -1;
207 static gint ett_diameter_avp = -1;
208 static gint ett_diameter_avp_flags = -1;
209 static gint ett_diameter_avpinfo = -1;
211 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
212 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
214 /* desegmentation of Diameter over TCP */
215 static gboolean gbl_diameter_desegment = TRUE;
217 #define DICT_FN "diameter/dictionary.xml"
218 static gchar *gbl_diameterDictionary = NULL;
220 typedef struct _e_diameterhdr {
221 guint32 versionLength;
222 guint32 flagsCmdCode;
228 typedef struct _e_avphdr {
230 guint32 avp_flagsLength;
231 guint32 avp_vendorId; /* optional */
234 /* Diameter Header Flags */
235 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
236 #define DIAM_FLAGS_R 0x80
237 #define DIAM_FLAGS_P 0x40
238 #define DIAM_FLAGS_E 0x20
239 #define DIAM_FLAGS_RESERVED3 0x10
240 #define DIAM_FLAGS_RESERVED4 0x08
241 #define DIAM_FLAGS_RESERVED5 0x04
242 #define DIAM_FLAGS_RESERVED6 0x02
243 #define DIAM_FLAGS_RESERVED7 0x01
244 #define DIAM_FLAGS_RESERVED 0x1f
246 #define DIAM_LENGTH_MASK 0x00ffffffl
247 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
248 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
249 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
250 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
251 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
253 /* Diameter AVP Flags */
254 #define AVP_FLAGS_P 0x20
255 #define AVP_FLAGS_V 0x80
256 #define AVP_FLAGS_M 0x40
257 #define AVP_FLAGS_RESERVED3 0x10
258 #define AVP_FLAGS_RESERVED4 0x08
259 #define AVP_FLAGS_RESERVED5 0x04
260 #define AVP_FLAGS_RESERVED6 0x02
261 #define AVP_FLAGS_RESERVED7 0x01
262 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
264 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
265 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
267 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
271 * This routine will do a push-parse of the passed in
272 * filename. This was taken almost verbatum from
273 * the xmlsoft examples.
276 xmlParseFilePush( char *filename, int checkValid) {
280 int res, size = 1024;
282 xmlParserCtxtPtr ctxt;
284 /* I wonder what kind of a performance hit this is? */
285 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
287 f = fopen(filename, "r");
289 g_warning("Diameter: Unable to open %s", filename);
293 res = fread(chars, 1, 4, f);
295 ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
296 chars, res, filename);
297 while ((res = fread(chars, 1, size-1, f)) > 0) {
298 XmlStub.xmlParseChunk(ctxt, chars, res, 0);
300 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
303 XmlStub.xmlFreeParserCtxt(ctxt);
309 g_warning( "Error! Invalid xml in %s! Failed DTD check!",
314 } /* xmlParseFilePush */
317 * This routine will add a static avp to the avp list. It is
318 * only called when the XML dictionary fails to load properly.
321 addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
324 ValueName *vEntry=NULL;
327 /* Parse our values array, if we have one */
329 for (i=0; values[i].strptr != NULL; i++) {
330 ValueName *ve = NULL;
332 ve = g_malloc(sizeof(ValueName));
333 ve->name = strdup(values[i].strptr);
334 ve->value = values[i].value;
340 /* And, create the entry */
341 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
342 entry->name = g_strdup(name);
344 entry->vendorName = NULL;
346 entry->values = vEntry;
348 entry->type = DIAMETER_INTEGER32;
350 /* And, add it to the list */
351 entry->next = avpListHead;
359 * This routine will parse an XML avp entry, and add it to our
360 * avp list. If any values are present in the avp, it will
364 xmlParseAVP(xmlNodePtr cur)
366 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
367 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
372 ValueName *vEntry=NULL;
375 /* First, get our properties */
376 name = XmlStub.xmlGetProp(cur, "name");
377 description = XmlStub.xmlGetProp(cur, "description");
378 code = XmlStub.xmlGetProp(cur, "code");
379 mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
380 mandatory = XmlStub.xmlGetProp(cur, "mandatory");
381 protected = XmlStub.xmlGetProp(cur, "protected");
382 vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
383 vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
384 constrained = XmlStub.xmlGetProp(cur, "constrained");
386 cur = cur->xmlChildrenNode;
388 while (cur != NULL ) {
389 if (strcasecmp(cur->name, "type") == 0) {
390 type = XmlStub.xmlGetProp(cur, "type-name");
391 } else if (strcasecmp(cur->name, "enum") == 0) {
392 char *valueName=NULL, *valueCode=NULL;
393 ValueName *ve = NULL;
394 valueName = XmlStub.xmlGetProp(cur, "name");
395 valueCode = XmlStub.xmlGetProp(cur, "code");
397 if (!valueName || !valueCode) {
398 g_warning( "Error, bad value on avp %s", name);
402 ve = g_malloc(sizeof(ValueName));
403 ve->name = strdup(valueName);
404 ve->value = atol(valueCode);
408 } else if (strcasecmp(cur->name, "grouped") == 0) {
409 /* WORK Recurse here for grouped AVPs */
416 * Check for the AVP Type.
419 for (i = 0; TypeValues[i].strptr; i++) {
420 if (!strcasecmp(type, TypeValues[i].strptr)) {
421 avpType = TypeValues[i].value;
426 if (TypeValues[i].strptr == NULL) {
427 g_warning( "Invalid Type field in dictionary! avp %s (%s)", name, type);
430 } else if (!vEntry) {
431 g_warning("Missing type/enum field in dictionary avpName=%s",
436 /* WORK - Handle flags -- for validation later */
439 /* And, create the entry */
440 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
441 entry->name = g_strdup(name);
442 entry->code = atol(code);
444 entry->vendorName = g_strdup(vendorName);
446 entry->vendorName = NULL;
447 entry->type = avpType;
448 entry->values = vEntry;
450 entry->type = DIAMETER_INTEGER32;
452 /* And, add it to the list */
453 entry->next = avpListHead;
460 * This routine will add a command to the list of commands.
463 addCommand(int code, char *name, char *vendorId)
468 * Allocate the memory required for the dictionary.
470 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
473 g_warning("Unable to allocate memory");
478 * Allocate memory for the AVPName and copy the name to the
481 entry->name = g_strdup(name);
484 entry->vendorName = g_strdup(vendorId);
486 entry->vendorName = "None";
488 /* Add the entry to the list */
489 entry->next = commandListHead;
490 commandListHead = entry;
496 * This routine will parse the XML command, and add it to our
500 xmlParseCommand(xmlNodePtr cur)
502 char *name, *code, *vendorIdString;
507 name = XmlStub.xmlGetProp(cur, "name");
508 code = XmlStub.xmlGetProp(cur, "code");
509 if (!name || !code) {
510 g_warning("Invalid command. Name or code missing!");
513 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
515 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
516 vendorIdString = NULL;
519 return (addCommand(atoi(code), name, vendorIdString));
520 } /* xmlParseCommand */
522 /* This routine adds an application to the name<-> id table */
524 dictionaryAddApplication(char *name, int id)
526 ApplicationId *entry;
528 if (!name || (id <= 0)) {
529 g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
532 } /* Sanity Checks */
534 entry = g_malloc(sizeof(ApplicationId));
536 g_warning( "Unable to allocate memory");
540 entry->name = g_strdup(name);
543 /* Add it to the list */
544 entry->next = ApplicationIdHead;
545 ApplicationIdHead = entry;
548 } /* dictionaryAddApplication */
551 * This routine will add a vendor to the vendors list
554 addVendor(int id, gchar *name, gchar *longName)
559 vendor=g_malloc(sizeof(VendorId));
565 vendor->name = g_strdup(name);
566 vendor->longName = g_strdup(longName);
567 vendor->next = vendorListHead;
568 vendorListHead = vendor;
574 * This routine will pars in a XML vendor entry.
577 xmlParseVendor(xmlNodePtr cur)
579 char *name=NULL, *code=NULL, *id=NULL;
581 /* First, get our properties */
582 id = XmlStub.xmlGetProp(cur, "vendor-id");
583 name = XmlStub.xmlGetProp(cur, "name");
584 code = XmlStub.xmlGetProp(cur, "code");
586 if (!id || !name || !code) {
587 g_warning( "Invalid vendor section. vendor-id, name, and code must be specified");
591 return (addVendor(atoi(code), id, name));
595 * This routine will either parse in the base protocol, or an application.
598 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
604 /* Add our application */
605 id = XmlStub.xmlGetProp(cur, "id");
606 name = XmlStub.xmlGetProp(cur, "name");
610 g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
611 name?name:"NULL", id?id:"NULL");
615 /* Add the application */
616 if (dictionaryAddApplication(name, atol(id)) != 0) {
626 cur = cur->xmlChildrenNode;
627 while (cur != NULL) {
628 if (strcasecmp(cur->name, "avp") == 0) {
629 /* we have an avp!!! */
631 } else if (strcasecmp(cur->name, "vendor") == 0) {
632 /* we have a vendor */
634 /* For now, ignore typedefn and text */
635 } else if (strcasecmp(cur->name, "command") == 0) {
636 /* Found a command */
637 xmlParseCommand(cur);
638 } else if (strcasecmp(cur->name, "text") == 0) {
639 } else if (strcasecmp(cur->name, "comment") == 0) {
640 } else if (strcasecmp(cur->name, "typedefn") == 0) {
641 /* WORK -- parse in valid types . . . */
643 /* IF we got here, we're an error */
644 g_warning("Error! expecting an avp or a typedefn (got \"%s\")",
651 } /* xmlDictionaryParseSegment */
654 * The main xml parse routine. This will walk through an XML
655 * dictionary that has been parsed by libxml.
658 xmlDictionaryParse(xmlNodePtr cur)
660 /* We should expect a base protocol, followed by multiple applicaitons */
661 while (cur != NULL) {
662 if (strcasecmp(cur->name, "base") == 0) {
663 /* Base protocol. Descend and parse */
664 xmlDictionaryParseSegment(cur, 1);
665 } else if (strcasecmp(cur->name, "application") == 0) {
666 /* Application. Descend and parse */
667 xmlDictionaryParseSegment(cur, 0);
668 } else if (strcasecmp(cur->name, "text") == 0) {
671 g_warning( "Diameter: XML Expecting a base or an application (got \"%s\")",
680 } /* xmlDictionaryParse */
683 * This routine will call libxml to parse in the dictionary.
692 * build an XML tree from a the file;
694 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
695 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
696 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
698 /* Check for invalid xml */
700 g_warning("Diameter: Unable to parse xmldictionary %s",
701 gbl_diameterDictionary);
706 * Check the document is of the right kind
708 cur = XmlStub.xmlDocGetRootElement(doc);
710 g_warning("Diameter: Error: \"%s\": empty document",
711 gbl_diameterDictionary);
712 XmlStub.xmlFreeDoc(doc);
715 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
716 g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
717 gbl_diameterDictionary);
718 XmlStub.xmlFreeDoc(doc);
723 * Ok, the dictionary has been parsed by libxml, and is valid.
724 * All we have to do now is read in our information.
726 if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
727 /* Error has already been printed */
731 /* Once we're done parsing, free up the xml memory */
732 XmlStub.xmlFreeDoc(doc);
736 } /* loadXMLDictionary */
739 * Fallback routine. In the event of ANY error when loading the XML
740 * dictionary, this routine will populate the new avp list structures
741 * with the old static data from packet-diameter-defs.h
744 initializeDictionaryDefaults()
748 /* Add static vendors to list */
749 for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
750 addVendor(diameter_vendor_specific_vendors[i].value,
751 diameter_vendor_specific_vendors[i].strptr,
752 diameter_vendor_specific_vendors[i].strptr);
754 /* Add static commands to list. */
755 for(i=0; diameter_command_code_vals[i].strptr; i++) {
756 addCommand(diameter_command_code_vals[i].value,
757 diameter_command_code_vals[i].strptr, NULL);
760 /* Add static AVPs to list */
761 for (i=0; old_diameter_avps[i].name; i++) {
762 addStaticAVP(old_diameter_avps[i].code,
763 old_diameter_avps[i].name,
764 old_diameter_avps[i].type,
765 old_diameter_avps[i].values);
768 } /* initializeDictionaryDefaults */
771 * This routine will attempt to load the XML dictionary, and on
772 * failure, will call initializeDictionaryDefaults to load in
773 * our static dictionary.
776 initializeDictionary()
779 * Using ugly ordering here. If loadLibXML succeeds, then
780 * loadXMLDictionary will be called. This is one of the few times when
781 * I think this is prettier than the nested if alternative.
784 (loadXMLDictionary() != 0)) {
785 /* Something failed. Use the static dictionary */
786 g_warning("Diameter: Using static dictionary! (Unable to use XML)");
787 initializeDictionaryDefaults();
789 } /* initializeDictionary */
794 * These routines manipulate the diameter structures.
797 /* return vendor string, based on the id */
799 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
801 static gchar buffer[64];
803 for (probe=vendorListHead; probe; probe=probe->next) {
804 if (vendorId == probe->id) {
806 return probe->longName;
812 snprintf(buffer, sizeof(buffer),
813 "Vendor 0x%08x", vendorId);
815 } /*diameter_vendor_to_str */
817 /* return command string, based on the code */
819 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
822 static gchar buffer[64];
823 gchar *vendorName=NULL;
826 vendorName = diameter_vendor_to_str(vendorId, FALSE);
828 for (probe=commandListHead; probe; probe=probe->next) {
829 if (commandCode == probe->code) {
831 /* g_warning("Command: Comparing \"%s\" to \"%s\"", */
832 /* vendorName?vendorName:"(null)", */
833 /* probe->vendorName?probe->vendorName:"(null)"); */
834 /* Now check the vendor name */
835 if (!strcmp(vendorName, probe->vendorName))
839 /* With no vendor id, the Command's entry should be "None" */
840 if (!strcmp(probe->vendorName, "None")) {
848 g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
849 commandCode, vendorId);
850 snprintf(buffer, sizeof(buffer),
851 "Cmd-0x%08x", commandCode);
853 }/*diameter_command_to_str */
855 /* return application string, based on the id */
857 diameter_app_to_str(guint32 vendorId) {
858 ApplicationId *probe;
859 static gchar buffer[64];
861 for (probe=ApplicationIdHead; probe; probe=probe->next) {
862 if (vendorId == probe->id) {
867 snprintf(buffer, sizeof(buffer),
868 "AppId 0x%08x", vendorId);
870 } /*diameter_app_to_str */
872 /* return an avp type, based on the code */
873 static diameterDataType
874 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
876 gchar *vendorName=NULL;
879 vendorName = diameter_vendor_to_str(vendorId, FALSE);
881 for (probe=avpListHead; probe; probe=probe->next) {
882 if (avpCode == probe->code) {
885 /* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
886 /* vendorName?vendorName:"(null)", */
887 /* probe->vendorName?probe->vendorName:"(null)"); */
888 /* Now check the vendor name */
889 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
893 /* No Vendor ID -- vendorName should be null */
894 if (!probe->vendorName)
901 /* If we don't find it, assume it's data */
902 g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
904 return DIAMETER_OCTET_STRING;
905 } /* diameter_avp_get_type */
907 /* return an avp name from the code */
909 diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
911 static gchar buffer[64];
913 gchar *vendorName=NULL;
916 vendorName = diameter_vendor_to_str(vendorId, FALSE);
918 for (probe=avpListHead; probe; probe=probe->next) {
919 if (avpCode == probe->code) {
921 /* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
922 /* vendorName?vendorName:"(null)", */
923 /* probe->vendorName?probe->vendorName:"(null)"); */
924 /* Now check the vendor name */
925 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
929 /* No Vendor ID -- vendorName should be null */
930 if (!probe->vendorName)
937 g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
940 /* If we don't find it, build a name string */
941 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
943 } /* diameter_avp_get_name */
945 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
947 static gchar buffer[64];
950 gchar *vendorName=NULL;
953 vendorName = diameter_vendor_to_str(vendorId, FALSE);
955 for (probe=avpListHead; probe; probe=probe->next) {
956 if (avpCode == probe->code) {
958 /* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
959 /* vendorName?vendorName:"(null)", */
960 /* probe->vendorName?probe->vendorName:"(null)"); */
961 /* Now check the vendor name */
962 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
964 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
965 if (avpValue == vprobe->value) {
969 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
973 if (!probe->vendorName) {
975 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
976 if (avpValue == vprobe->value) {
980 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
986 /* If we don't find the avp, build a value string */
987 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
989 } /* diameter_avp_get_value */
992 /* Code to actually dissect the packets */
997 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
1001 /* Set up structures needed to add the protocol subtree and manage it */
1004 proto_tree *flags_tree;
1006 proto_tree *diameter_tree;
1010 proto_tree *avp_tree;
1012 int BadPacket = FALSE;
1013 guint32 commandCode, pktLength;
1014 guint8 version, flags;
1015 gchar flagstr[64] = "<None>";
1016 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1017 gchar commandString[64], vendorName[64];
1020 static int initialized=FALSE;
1022 /* set our offset */
1026 * Only parse in dictionary if there are diameter packets to
1030 /* Read in our dictionary, if it exists. */
1031 initializeDictionary();
1035 /* Make entries in Protocol column and Info column on summary display */
1036 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1037 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1038 if (check_col(pinfo->cinfo, COL_INFO))
1039 col_clear(pinfo->cinfo, COL_INFO);
1041 /* Copy our header */
1042 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1044 /* Fix byte ordering in our static structure */
1045 dh.versionLength = g_ntohl(dh.versionLength);
1046 dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
1047 dh.vendorId = g_ntohl(dh.vendorId);
1048 dh.hopByHopId = g_ntohl(dh.hopByHopId);
1049 dh.endToEndId = g_ntohl(dh.endToEndId);
1053 diameter_vendor_to_str(dh.vendorId, TRUE));
1055 strcpy(vendorName, "None");
1059 /* Do the bit twiddling */
1060 version = DIAM_GET_VERSION(dh);
1061 pktLength = DIAM_GET_LENGTH(dh);
1062 flags = DIAM_GET_FLAGS(dh);
1063 commandCode = DIAM_GET_COMMAND(dh);
1065 /* Set up our flags */
1066 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1068 for (i = 0; i < 8; i++) {
1072 strcat(flagstr, ", ");
1074 strcat(flagstr, fstr[i]);
1077 if (strlen(flagstr) == 0) {
1078 strcpy(flagstr,"<None>");
1082 /* Set up our commandString */
1083 strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1084 if (flags & DIAM_FLAGS_R)
1085 strcat(commandString, "-Request");
1087 strcat(commandString, "-Answer");
1089 /* Short packet. Should have at LEAST one avp */
1090 if (pktLength < MIN_DIAMETER_SIZE) {
1091 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1092 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1096 /* And, check our reserved flags/version */
1097 if ((flags & DIAM_FLAGS_RESERVED) ||
1099 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1104 if (check_col(pinfo->cinfo, COL_INFO)) {
1105 col_add_fstr(pinfo->cinfo, COL_INFO,
1106 "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1107 (BadPacket)?"***** Bad Packet!: ":"",
1108 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1109 (flags & DIAM_FLAGS_E)?" Error":"",
1111 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1113 commandString, vendorName,
1114 dh.hopByHopId, dh.endToEndId,
1115 (flags & DIAM_FLAGS_R)?1:0,
1116 (flags & DIAM_FLAGS_P)?1:0,
1117 (flags & DIAM_FLAGS_E)?1:0);
1121 /* In the interest of speed, if "tree" is NULL, don't do any work not
1122 necessary to generate protocol tree items. */
1125 /* create display subtree for the protocol */
1126 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1127 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1128 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1131 proto_tree_add_uint(diameter_tree,
1132 hf_diameter_version,
1139 proto_tree_add_uint(diameter_tree,
1140 hf_diameter_length, tvb,
1141 offset, 3, pktLength);
1145 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1146 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1148 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1149 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1150 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1151 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1152 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1153 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1154 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1155 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1156 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1161 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1162 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1166 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1167 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
1170 /* Hop-by-hop Identifier */
1171 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1172 tvb, offset, 4, dh.hopByHopId);
1175 /* End-to-end Identifier */
1176 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1177 tvb, offset, 4, dh.endToEndId);
1180 /* If we have a bad packet, don't bother trying to parse the AVPs */
1182 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1185 /* Start looking at the AVPS */
1186 /* Make the next tvbuff */
1188 /* Update the lengths */
1189 avplength= pktLength - sizeof(e_diameterhdr);
1191 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1192 avptf = proto_tree_add_text(diameter_tree,
1193 tvb, offset, avplength,
1194 "Attribute Value Pairs");
1196 avp_tree = proto_item_add_subtree(avptf,
1198 if (avp_tree != NULL) {
1199 dissect_avps( avp_tvb, pinfo, avp_tree);
1201 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1203 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1205 } /* dissect_diameter_common */
1208 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1210 dissect_diameter_common(tvb, 0, pinfo, tree);
1214 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1218 guint32 available_bytes;
1219 /* guint32 noffset; */
1221 /* Loop through the packet, dissecting multiple diameter messages */
1223 available_bytes = tvb_length_remaining(tvb, offset);
1224 if (available_bytes < 4) {
1225 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1227 return; /* Bail. We can't even get our length */
1230 /* get our packet length */
1231 plen = tvb_get_ntohl(tvb, offset);
1232 plen &= 0x00ffffff; /* get rid of the flags */
1235 if (gbl_diameter_desegment) {
1236 if (pinfo->can_desegment
1237 && plen > available_bytes) {
1238 pinfo->desegment_offset = offset;
1239 pinfo->desegment_len = plen - available_bytes;
1240 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1241 /* plen, available_bytes); */
1246 /* Otherwise, dissect our packet */
1247 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1249 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1250 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1251 /* offset=noffset; */
1252 } while (offset < tvb_reported_length(tvb));
1254 } /* dissect_diameter_tcp */
1257 * Call the mip_dissector, after saving our pinfo variables
1258 * so it doesn't write to our column display.
1261 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1262 size_t offset, size_t length)
1264 static dissector_handle_t mip_handle;
1265 static int mipInitialized=FALSE;
1267 address save_dl_src;
1268 address save_dl_dst;
1269 address save_net_src;
1270 address save_net_dst;
1273 gboolean save_in_error_pkt;
1275 if (!mipInitialized) {
1276 mip_handle = find_dissector("mip");
1277 mipInitialized=TRUE;
1280 mip_tvb = tvb_new_subset(tvb, offset,
1281 MIN(length, tvb_length(tvb)-offset),
1284 /* The contained packet is a MIP registration request;
1285 dissect it with the MIP dissector. */
1286 col_set_writable(pinfo->cinfo, FALSE);
1288 /* Also, save the current values of the addresses, and restore
1289 them when we're finished dissecting the contained packet, so
1290 that the address columns in the summary don't reflect the
1291 contained packet, but reflect this packet instead. */
1292 save_dl_src = pinfo->dl_src;
1293 save_dl_dst = pinfo->dl_dst;
1294 save_net_src = pinfo->net_src;
1295 save_net_dst = pinfo->net_dst;
1296 save_src = pinfo->src;
1297 save_dst = pinfo->dst;
1298 save_in_error_pkt = pinfo->in_error_pkt;
1300 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1302 /* Restore the "we're inside an error packet" flag. */
1303 pinfo->in_error_pkt = save_in_error_pkt;
1304 pinfo->dl_src = save_dl_src;
1305 pinfo->dl_dst = save_dl_dst;
1306 pinfo->net_src = save_net_src;
1307 pinfo->net_dst = save_net_dst;
1308 pinfo->src = save_src;
1309 pinfo->dst = save_dst;
1312 } /* safe_dissect_mip */
1315 * This function will dissect the AVPs in a diameter packet. It handles
1316 * all normal types, and even recursively calls itself for grouped AVPs
1318 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1320 /* adds the attribute value pairs to the tree */
1322 gchar avpTypeString[64];
1323 gchar avpNameString[64];
1326 gchar vendorName[64];
1329 proto_tree *avpi_tree;
1331 tvbuff_t *group_tvb;
1332 proto_tree *group_tree;
1333 proto_item *grouptf;
1336 int BadPacket = FALSE;
1340 proto_tree *flags_tree;
1342 gint32 packetLength;
1343 size_t avpDataLength;
1345 gchar flagstr[64] = "<None>";
1346 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1350 packetLength = tvb_length(tvb);
1352 /* Check for invalid packet lengths */
1353 if (packetLength <= 0) {
1354 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1355 "No Attribute Value Pairs Found");
1359 /* Spin around until we run out of packet */
1360 while (packetLength > 0 ) {
1362 /* Check for short packet */
1363 if (packetLength < (long)MIN_AVP_SIZE) {
1364 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1365 packetLength, (long)MIN_AVP_SIZE);
1367 /* Don't even bother trying to parse a short packet. */
1371 /* Copy our header */
1372 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1374 /* Fix the byte ordering */
1375 avph.avp_code = g_ntohl(avph.avp_code);
1376 avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1378 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1379 avpLength = avph.avp_flagsLength & 0x00ffffff;
1381 /* Set up our flags string */
1382 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1384 for (i = 0; i < 8; i++) {
1388 strcat(flagstr, ", ");
1390 strcat(flagstr, fstr[i]);
1393 if (strlen(flagstr) == 0) {
1394 strcpy(flagstr,"<None>");
1398 /* Dissect our vendor id if it exists and set hdr length */
1399 if (flags & AVP_FLAGS_V) {
1400 vendorId = g_ntohl(avph.avp_vendorId);
1402 hdrLength = sizeof(e_avphdr);
1405 hdrLength = sizeof(e_avphdr) -
1412 diameter_vendor_to_str(vendorId, TRUE));
1417 /* Check for bad length */
1418 if (avpLength < MIN_AVP_SIZE ||
1419 ((long)avpLength > packetLength)) {
1420 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1421 "min: %ld bytes, packetLen: %d",
1422 (long)avpLength, (long)MIN_AVP_SIZE,
1427 /* Check for bad flags */
1428 if (flags & AVP_FLAGS_RESERVED) {
1429 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1431 flags, AVP_FLAGS_RESERVED);
1432 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1433 /* BadPacket = TRUE; */
1437 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1440 fixAmt = 4 - (avpLength % 4);
1441 if (fixAmt == 4) fixAmt = 0;
1443 /* shrink our packetLength */
1444 packetLength = packetLength - (avpLength + fixAmt);
1446 /* Check for out of bounds */
1447 if (packetLength < 0) {
1448 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1453 /* Make avp Name & type */
1454 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1456 "Unknown-Type: 0x%08x"));
1457 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1459 avptf = proto_tree_add_text(avp_tree, tvb,
1460 offset, avpLength + fixAmt,
1461 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1462 avpNameString, avpTypeString, avpLength,
1463 avpLength, avpLength+fixAmt);
1464 avpi_tree = proto_item_add_subtree(avptf,
1465 ett_diameter_avpinfo);
1467 if (avpi_tree !=NULL) {
1469 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1470 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1473 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1474 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1476 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1477 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1478 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1479 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1480 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1481 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1482 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1483 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1484 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1487 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1488 tvb, offset, 3, avpLength);
1491 if (flags & AVP_FLAGS_V) {
1492 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1493 tvb, offset, 4, vendorId, vendorName);
1497 avpDataLength = avpLength - hdrLength;
1500 * If we've got a bad packet, just highlight the data. Don't try
1501 * to parse it, and, don't move to next AVP.
1504 offset -= hdrLength;
1505 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1506 tvb, offset, tvb_length(tvb) - offset,
1507 tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1508 "Bad AVP (Suspect Data Not Dissected)");
1512 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1515 case DIAMETER_GROUPED:
1516 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1517 /* Recursively call ourselves */
1518 grouptf = proto_tree_add_text(avpi_tree,
1519 tvb, offset, tvb_length(tvb),
1522 group_tree = proto_item_add_subtree(grouptf,
1525 group_tvb = tvb_new_subset(tvb, offset,
1526 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1527 if (group_tree != NULL) {
1528 dissect_avps( group_tvb, pinfo, group_tree);
1532 case DIAMETER_IDENTITY:
1536 data = tvb_get_ptr(tvb, offset, avpDataLength);
1537 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1538 tvb, offset, avpDataLength, data,
1541 (int)avpDataLength, data);
1544 case DIAMETER_UTF8STRING:
1548 data = tvb_get_ptr(tvb, offset, avpDataLength);
1549 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1550 tvb, offset, avpDataLength, data,
1551 "UTF8String: %*.*s",
1553 (int)avpDataLength, data);
1556 case DIAMETER_IP_ADDRESS:
1557 if (avpDataLength == 4) {
1558 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1559 tvb, offset, avpDataLength, FALSE);
1560 } else if (avpDataLength == 16) {
1561 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1562 tvb, offset, avpDataLength, FALSE);
1564 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1565 tvb, offset, avpDataLength,
1566 tvb_get_ptr(tvb, offset, avpDataLength),
1567 "Error! Bad Address Length");
1571 case DIAMETER_INTEGER32:
1572 if (avpDataLength == 4) {
1573 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1574 tvb, offset, avpDataLength, FALSE);
1576 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1577 tvb, offset, avpDataLength,
1578 tvb_get_ptr(tvb, offset, avpDataLength),
1579 "Error! Bad Integer32 Length");
1583 case DIAMETER_UNSIGNED32:
1584 if (avpDataLength == 4) {
1587 data = tvb_get_ntohl(tvb, offset);
1588 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1589 tvb, offset, avpDataLength, data,
1590 "Value: 0x%08x (%u)", data, data);
1592 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1593 tvb, offset, avpDataLength,
1594 tvb_get_ptr(tvb, offset, avpDataLength),
1595 "Error! Bad Unsigned32 Length");
1599 case DIAMETER_INTEGER64:
1600 if (avpDataLength == 8) {
1601 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1602 tvb, offset, 8, FALSE);
1604 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1605 tvb, offset, avpDataLength,
1606 tvb_get_ptr(tvb, offset, avpDataLength),
1607 "Error! Bad Integer64 Length");
1611 case DIAMETER_UNSIGNED64:
1612 if (avpDataLength == 8) {
1613 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1614 tvb, offset, 8, FALSE);
1616 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1617 tvb, offset, avpDataLength,
1618 tvb_get_ptr(tvb, offset, avpDataLength),
1619 "Error! Bad Unsigned64 Length");
1624 if (avpDataLength == 4) {
1629 data.secs = tvb_get_ntohl(tvb, offset);
1630 data.secs -= NTP_TIME_DIFF;
1633 ltp = localtime(&data.secs);
1634 strftime(buffer, 64,
1635 "%a, %d %b %Y %H:%M:%S %z", ltp);
1637 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1638 tvb, offset, avpDataLength, &data,
1639 "Time: %s", buffer);
1641 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1642 tvb, offset, avpDataLength,
1643 tvb_get_ptr(tvb, offset, avpDataLength),
1644 "Error! Bad Time Length");
1648 case DIAMETER_ENUMERATED:
1649 if (avpDataLength == 4) {
1652 data = tvb_get_ntohl(tvb, offset);
1653 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1654 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1655 tvb, offset, avpDataLength, data,
1656 "Value: 0x%08x (%u): %s", data,
1659 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1660 tvb, offset, avpDataLength,
1661 tvb_get_ptr(tvb, offset, avpDataLength),
1662 "Error! Bad Enumerated Length");
1665 case DIAMETER_VENDOR_ID:
1666 if (avpDataLength == 4) {
1669 data = tvb_get_ntohl(tvb, offset);
1670 valstr = diameter_vendor_to_str(data, TRUE);
1671 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1672 tvb, offset, avpDataLength, data,
1673 "Vendor ID: %s (0x%08x)", valstr,
1676 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1677 tvb, offset, avpDataLength,
1678 tvb_get_ptr(tvb, offset, avpDataLength),
1679 "Error! Bad Vendor ID Length");
1682 case DIAMETER_APPLICATION_ID:
1683 if (avpDataLength == 4) {
1686 data = tvb_get_ntohl(tvb, offset);
1687 valstr = diameter_app_to_str(data);
1688 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1689 tvb, offset, avpDataLength, data,
1690 "Application ID: %s (0x%08x)",
1693 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1694 tvb, offset, avpDataLength,
1695 tvb_get_ptr(tvb, offset, avpDataLength),
1696 "Error! Bad Application ID Length");
1699 case DIAMETER_MIP_REG_REQ:
1700 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1704 case DIAMETER_OCTET_STRING:
1705 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1706 tvb, offset, avpDataLength,
1707 tvb_get_ptr(tvb, offset, avpDataLength),
1708 "Hex Data Highlighted Below");
1712 } /* avpi_tree != null */
1713 offset += (avpLength - hdrLength);
1714 offset += fixAmt; /* fix byte alignment */
1716 } /* dissect_avps */
1721 proto_reg_handoff_diameter(void)
1723 static int Initialized=FALSE;
1724 static int TcpPort=0;
1725 static int SctpPort=0;
1726 static dissector_handle_t diameter_tcp_handle;
1727 static dissector_handle_t diameter_sctp_handle;
1730 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1732 diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1736 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1737 dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1740 /* set port for future deletes */
1741 TcpPort=gbl_diameterTcpPort;
1742 SctpPort=gbl_diameterSctpPort;
1744 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1745 gbl_diameterTcpPort); */
1746 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1747 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1750 /* registration with the filtering engine */
1752 proto_register_diameter(void)
1754 static hf_register_info hf[] = {
1755 { &hf_diameter_version,
1756 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1758 { &hf_diameter_length,
1759 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1762 { &hf_diameter_flags,
1763 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1765 { &hf_diameter_flags_request,
1766 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1768 { &hf_diameter_flags_proxyable,
1769 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1771 { &hf_diameter_flags_error,
1772 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1774 { &hf_diameter_flags_reserved3,
1775 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1776 DIAM_FLAGS_RESERVED3, "", HFILL }},
1777 { &hf_diameter_flags_reserved4,
1778 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1779 DIAM_FLAGS_RESERVED4, "", HFILL }},
1780 { &hf_diameter_flags_reserved5,
1781 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1782 DIAM_FLAGS_RESERVED5, "", HFILL }},
1783 { &hf_diameter_flags_reserved6,
1784 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1785 DIAM_FLAGS_RESERVED6, "", HFILL }},
1786 { &hf_diameter_flags_reserved7,
1787 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1788 DIAM_FLAGS_RESERVED7, "", HFILL }},
1790 { &hf_diameter_code,
1791 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1792 NULL, 0x0, "", HFILL }},
1793 { &hf_diameter_vendor_id,
1794 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1796 { &hf_diameter_hopbyhopid,
1797 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1798 BASE_HEX, NULL, 0x0, "", HFILL }},
1799 { &hf_diameter_endtoendid,
1800 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1801 BASE_HEX, NULL, 0x0, "", HFILL }},
1803 { &hf_diameter_avp_code,
1804 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1805 NULL, 0x0, "", HFILL }},
1806 { &hf_diameter_avp_length,
1807 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1808 NULL, 0x0, "", HFILL }},
1811 { &hf_diameter_avp_flags,
1812 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1813 NULL, 0x0, "", HFILL }},
1814 { &hf_diameter_avp_flags_vendor_specific,
1815 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1817 { &hf_diameter_avp_flags_mandatory,
1818 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1820 { &hf_diameter_avp_flags_protected,
1821 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1823 { &hf_diameter_avp_flags_reserved3,
1824 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1825 AVP_FLAGS_RESERVED3, "", HFILL }},
1826 { &hf_diameter_avp_flags_reserved4,
1827 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1828 AVP_FLAGS_RESERVED4, "", HFILL }},
1829 { &hf_diameter_avp_flags_reserved5,
1830 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1831 AVP_FLAGS_RESERVED5, "", HFILL }},
1832 { &hf_diameter_avp_flags_reserved6,
1833 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1834 AVP_FLAGS_RESERVED6, "", HFILL }},
1835 { &hf_diameter_avp_flags_reserved7,
1836 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1837 AVP_FLAGS_RESERVED7, "", HFILL }},
1838 { &hf_diameter_avp_vendor_id,
1839 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1840 NULL, 0x0, "", HFILL }},
1841 { &hf_diameter_avp_data_uint64,
1842 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1843 NULL, 0x0, "", HFILL }},
1844 { &hf_diameter_avp_data_int64,
1845 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1846 NULL, 0x0, "", HFILL }},
1847 { &hf_diameter_avp_data_uint32,
1848 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1849 NULL, 0x0, "", HFILL }},
1850 { &hf_diameter_avp_data_int32,
1851 { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1852 NULL, 0x0, "", HFILL }},
1853 { &hf_diameter_avp_data_bytes,
1854 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1855 NULL, 0x0, "", HFILL }},
1856 { &hf_diameter_avp_data_string,
1857 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1858 NULL, 0x0, "", HFILL }},
1859 { &hf_diameter_avp_data_v4addr,
1860 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1861 NULL, 0x0, "", HFILL }},
1862 { &hf_diameter_avp_data_v6addr,
1863 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1864 NULL, 0x0, "", HFILL }},
1865 { &hf_diameter_avp_data_time,
1866 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1867 NULL, 0x0, "", HFILL }},
1870 static gint *ett[] = {
1872 &ett_diameter_flags,
1874 &ett_diameter_avp_flags,
1875 &ett_diameter_avpinfo
1877 module_t *diameter_module;
1879 proto_diameter = proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
1880 proto_register_field_array(proto_diameter, hf, array_length(hf));
1881 proto_register_subtree_array(ett, array_length(ett));
1883 /* Register a configuration option for port */
1884 diameter_module = prefs_register_protocol(proto_diameter,
1885 proto_reg_handoff_diameter);
1886 prefs_register_uint_preference(diameter_module, "tcp.port",
1887 "Diameter TCP Port",
1888 "Set the TCP port for Diameter messages",
1890 &gbl_diameterTcpPort);
1891 prefs_register_uint_preference(diameter_module, "sctp.port",
1892 "Diameter SCTP Port",
1893 "Set the SCTP port for Diameter messages",
1895 &gbl_diameterSctpPort);
1897 * Build our default dictionary filename
1899 if (! gbl_diameterDictionary)
1900 gbl_diameterDictionary = get_datafile_path(DICT_FN);
1901 /* Now register its preferences so it can be changed. */
1902 prefs_register_string_preference(diameter_module, "dictionary.name",
1903 "Diameter XML Dictionary",
1904 "Set the dictionary used for Diameter messages",
1905 &gbl_diameterDictionary);
1907 /* Desegmentation */
1908 prefs_register_bool_preference(diameter_module, "desegment",
1909 "Desegment all Diameter messages spanning multiple TCP segments",
1910 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1911 &gbl_diameter_desegment);
1913 /* Register some preferences we no longer support, so we can report
1914 them as obsolete rather than just illegal. */
1915 prefs_register_obsolete_preference(diameter_module, "udp.port");
1916 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1917 } /* proto_register_diameter */