2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.50 2002/08/28 21:00:12 jmayer 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 char gbl_diameterString[200];
212 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
213 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
215 /* desegmentation of Diameter over TCP */
216 static gboolean gbl_diameter_desegment = TRUE;
218 #define DICT_FN "diameter/dictionary.xml"
219 static gchar *gbl_diameterDictionary = NULL;
221 typedef struct _e_diameterhdr {
222 guint32 versionLength;
223 guint32 flagsCmdCode;
229 typedef struct _e_avphdr {
231 guint32 avp_flagsLength;
232 guint32 avp_vendorId; /* optional */
235 /* Diameter Header Flags */
236 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
237 #define DIAM_FLAGS_R 0x80
238 #define DIAM_FLAGS_P 0x40
239 #define DIAM_FLAGS_E 0x20
240 #define DIAM_FLAGS_RESERVED3 0x10
241 #define DIAM_FLAGS_RESERVED4 0x08
242 #define DIAM_FLAGS_RESERVED5 0x04
243 #define DIAM_FLAGS_RESERVED6 0x02
244 #define DIAM_FLAGS_RESERVED7 0x01
245 #define DIAM_FLAGS_RESERVED 0x1f
247 #define DIAM_LENGTH_MASK 0x00ffffffl
248 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
249 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
250 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
251 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
252 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
254 /* Diameter AVP Flags */
255 #define AVP_FLAGS_P 0x20
256 #define AVP_FLAGS_V 0x80
257 #define AVP_FLAGS_M 0x40
258 #define AVP_FLAGS_RESERVED3 0x10
259 #define AVP_FLAGS_RESERVED4 0x08
260 #define AVP_FLAGS_RESERVED5 0x04
261 #define AVP_FLAGS_RESERVED6 0x02
262 #define AVP_FLAGS_RESERVED7 0x01
263 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
265 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
266 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
268 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
272 * This routine will do a push-parse of the passed in
273 * filename. This was taken almost verbatum from
274 * the xmlsoft examples.
277 xmlParseFilePush( char *filename, int checkValid) {
281 int res, size = 1024;
283 xmlParserCtxtPtr ctxt;
285 /* I wonder what kind of a performance hit this is? */
286 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
288 f = fopen(filename, "r");
290 g_warning("Diameter: Unable to open %s", filename);
294 res = fread(chars, 1, 4, f);
296 ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
297 chars, res, filename);
298 while ((res = fread(chars, 1, size-1, f)) > 0) {
299 XmlStub.xmlParseChunk(ctxt, chars, res, 0);
301 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
304 XmlStub.xmlFreeParserCtxt(ctxt);
310 g_warning( "Error! Invalid xml in %s! Failed DTD check!",
315 } /* xmlParseFilePush */
318 * This routine will add a static avp to the avp list. It is
319 * only called when the XML dictionary fails to load properly.
322 addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
325 ValueName *vEntry=NULL;
328 /* Parse our values array, if we have one */
330 for (i=0; values[i].strptr != NULL; i++) {
331 ValueName *ve = NULL;
333 ve = g_malloc(sizeof(ValueName));
334 ve->name = strdup(values[i].strptr);
335 ve->value = values[i].value;
341 /* And, create the entry */
342 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
343 entry->name = g_strdup(name);
345 entry->vendorName = NULL;
347 entry->values = vEntry;
349 entry->type = DIAMETER_INTEGER32;
351 /* And, add it to the list */
352 entry->next = avpListHead;
360 * This routine will parse an XML avp entry, and add it to our
361 * avp list. If any values are present in the avp, it will
365 xmlParseAVP(xmlNodePtr cur)
367 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
368 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
373 ValueName *vEntry=NULL;
376 /* First, get our properties */
377 name = XmlStub.xmlGetProp(cur, "name");
378 description = XmlStub.xmlGetProp(cur, "description");
379 code = XmlStub.xmlGetProp(cur, "code");
380 mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
381 mandatory = XmlStub.xmlGetProp(cur, "mandatory");
382 protected = XmlStub.xmlGetProp(cur, "protected");
383 vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
384 vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
385 constrained = XmlStub.xmlGetProp(cur, "constrained");
387 cur = cur->xmlChildrenNode;
389 while (cur != NULL ) {
390 if (!strcasecmp((char *)cur->name, "type")) {
391 type = XmlStub.xmlGetProp(cur, "type-name");
393 if (!strcasecmp((char *)cur->name, "enum")) {
394 char *valueName=NULL, *valueCode=NULL;
395 ValueName *ve = NULL;
396 valueName = XmlStub.xmlGetProp(cur, "name");
397 valueCode = XmlStub.xmlGetProp(cur, "code");
399 if (!valueName || !valueCode) {
400 g_warning( "Error, bad value on avp %s", name);
404 ve = g_malloc(sizeof(ValueName));
405 ve->name = strdup(valueName);
406 ve->value = atol(valueCode);
411 if (!strcasecmp((char *)cur->name, "grouped")) {
412 /* WORK Recurse here for grouped AVPs */
419 * Check for the AVP Type.
422 for (i = 0; TypeValues[i].strptr; i++) {
423 if (!strcasecmp(type, TypeValues[i].strptr)) {
424 avpType = TypeValues[i].value;
429 if (TypeValues[i].strptr == NULL) {
430 g_warning( "Invalid Type field in dictionary! avp %s (%s)", name, type);
433 } else if (!vEntry) {
434 g_warning("Missing type/enum field in dictionary avpName=%s",
439 /* WORK - Handle flags -- for validation later */
442 /* And, create the entry */
443 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
444 entry->name = g_strdup(name);
445 entry->code = atol(code);
447 entry->vendorName = g_strdup(vendorName);
449 entry->vendorName = NULL;
450 entry->type = avpType;
451 entry->values = vEntry;
453 entry->type = DIAMETER_INTEGER32;
455 /* And, add it to the list */
456 entry->next = avpListHead;
463 * This routine will add a command to the list of commands.
466 addCommand(int code, char *name, char *vendorId)
471 * Allocate the memory required for the dictionary.
473 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
476 g_warning("Unable to allocate memory");
481 * Allocate memory for the AVPName and copy the name to the
484 entry->name = g_strdup(name);
487 entry->vendorName = g_strdup(vendorId);
489 entry->vendorName = "None";
491 /* Add the entry to the list */
492 entry->next = commandListHead;
493 commandListHead = entry;
499 * This routine will parse the XML command, and add it to our
503 xmlParseCommand(xmlNodePtr cur)
505 char *name, *code, *vendorIdString;
510 name = XmlStub.xmlGetProp(cur, "name");
511 code = XmlStub.xmlGetProp(cur, "code");
512 if (!name || !code) {
513 g_warning("Invalid command. Name or code missing!");
516 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
518 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
519 vendorIdString = NULL;
522 return (addCommand(atoi(code), name, vendorIdString));
523 } /* xmlParseCommand */
525 /* This routine adds an application to the name<-> id table */
527 dictionaryAddApplication(char *name, int id)
529 ApplicationId *entry;
531 if (!name || (id <= 0)) {
532 g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
535 } /* Sanity Checks */
537 entry = g_malloc(sizeof(ApplicationId));
539 g_warning( "Unable to allocate memory");
543 entry->name = g_strdup(name);
546 /* Add it to the list */
547 entry->next = ApplicationIdHead;
548 ApplicationIdHead = entry;
551 } /* dictionaryAddApplication */
554 * This routine will add a vendor to the vendors list
557 addVendor(int id, gchar *name, gchar *longName)
562 vendor=g_malloc(sizeof(VendorId));
568 vendor->name = g_strdup(name);
569 vendor->longName = g_strdup(longName);
570 vendor->next = vendorListHead;
571 vendorListHead = vendor;
577 * This routine will pars in a XML vendor entry.
580 xmlParseVendor(xmlNodePtr cur)
582 char *name=NULL, *code=NULL, *id=NULL;
584 /* First, get our properties */
585 id = XmlStub.xmlGetProp(cur, "vendor-id");
586 name = XmlStub.xmlGetProp(cur, "name");
587 code = XmlStub.xmlGetProp(cur, "code");
589 if (!id || !name || !code) {
590 g_warning( "Invalid vendor section. vendor-id, name, and code must be specified");
594 return (addVendor(atoi(code), id, name));
598 * This routine will either parse in the base protocol, or an application.
601 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
607 /* Add our application */
608 id = XmlStub.xmlGetProp(cur, "id");
609 name = XmlStub.xmlGetProp(cur, "name");
613 g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
614 name?name:"NULL", id?id:"NULL");
618 /* Add the application */
619 if (dictionaryAddApplication(name, atol(id)) != 0) {
629 cur = cur->xmlChildrenNode;
630 while (cur != NULL) {
631 if (!strcasecmp((char *)cur->name, "avp")) {
632 /* we have an avp!!! */
634 } else if (!strcasecmp((char *)cur->name, "vendor")) {
635 /* we have a vendor */
637 /* For now, ignore typedefn and text */
638 } else if (!strcasecmp((char *)cur->name, "command")) {
639 /* Found a command */
640 xmlParseCommand(cur);
641 } else if (!strcasecmp((char *)cur->name, "text")) {
642 } else if (!strcasecmp((char *)cur->name, "comment")) {
643 } else if (!strcasecmp((char *)cur->name, "typedefn")) {
644 /* WORK -- parse in valid types . . . */
646 /* IF we got here, we're an error */
647 g_warning("Error! expecting an avp or a typedefn (got \"%s\")",
654 } /* xmlDictionaryParseSegment */
657 * The main xml parse routine. This will walk through an XML
658 * dictionary that has been parsed by libxml.
661 xmlDictionaryParse(xmlNodePtr cur)
663 /* We should expect a base protocol, followed by multiple applicaitons */
664 while (cur != NULL) {
665 if (!strcasecmp((char *)cur->name, "base")) {
666 /* Base protocol. Descend and parse */
667 xmlDictionaryParseSegment(cur, 1);
668 } else if (!strcasecmp((char *)cur->name, "application")) {
669 /* Application. Descend and parse */
670 xmlDictionaryParseSegment(cur, 0);
671 } else if (!strcasecmp((char *)cur->name, "text")) {
674 g_warning( "Diameter: XML Expecting a base or an application (got \"%s\")",
683 } /* xmlDictionaryParse */
686 * This routine will call libxml to parse in the dictionary.
695 * build an XML tree from a the file;
697 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
698 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
699 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
701 /* Check for invalid xml */
703 g_warning("Diameter: Unable to parse xmldictionary %s",
704 gbl_diameterDictionary);
709 * Check the document is of the right kind
711 cur = XmlStub.xmlDocGetRootElement(doc);
713 g_warning("Diameter: Error: \"%s\": empty document",
714 gbl_diameterDictionary);
715 XmlStub.xmlFreeDoc(doc);
718 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
719 g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
720 gbl_diameterDictionary);
721 XmlStub.xmlFreeDoc(doc);
726 * Ok, the dictionary has been parsed by libxml, and is valid.
727 * All we have to do now is read in our information.
729 if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
730 /* Error has already been printed */
734 /* Once we're done parsing, free up the xml memory */
735 XmlStub.xmlFreeDoc(doc);
739 } /* loadXMLDictionary */
742 * Fallback routine. In the event of ANY error when loading the XML
743 * dictionary, this routine will populate the new avp list structures
744 * with the old static data from packet-diameter-defs.h
747 initializeDictionaryDefaults()
751 /* Add static vendors to list */
752 for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
753 addVendor(diameter_vendor_specific_vendors[i].value,
754 diameter_vendor_specific_vendors[i].strptr,
755 diameter_vendor_specific_vendors[i].strptr);
757 /* Add static commands to list. */
758 for(i=0; diameter_command_code_vals[i].strptr; i++) {
759 addCommand(diameter_command_code_vals[i].value,
760 diameter_command_code_vals[i].strptr, NULL);
763 /* Add static AVPs to list */
764 for (i=0; old_diameter_avps[i].name; i++) {
765 addStaticAVP(old_diameter_avps[i].code,
766 old_diameter_avps[i].name,
767 old_diameter_avps[i].type,
768 old_diameter_avps[i].values);
771 } /* initializeDictionaryDefaults */
774 * This routine will attempt to load the XML dictionary, and on
775 * failure, will call initializeDictionaryDefaults to load in
776 * our static dictionary.
779 initializeDictionary()
782 * Using ugly ordering here. If loadLibXML succeeds, then
783 * loadXMLDictionary will be called. This is one of the few times when
784 * I think this is prettier than the nested if alternative.
787 (loadXMLDictionary() != 0)) {
788 /* Something failed. Use the static dictionary */
789 g_warning("Diameter: Using static dictionary! (Unable to use XML)");
790 initializeDictionaryDefaults();
792 } /* initializeDictionary */
797 * These routines manipulate the diameter structures.
800 /* return vendor string, based on the id */
802 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
804 static gchar buffer[64];
806 for (probe=vendorListHead; probe; probe=probe->next) {
807 if (vendorId == probe->id) {
809 return probe->longName;
815 snprintf(buffer, sizeof(buffer),
816 "Vendor 0x%08x", vendorId);
818 } /*diameter_vendor_to_str */
820 /* return command string, based on the code */
822 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
825 static gchar buffer[64];
826 gchar *vendorName=NULL;
829 vendorName = diameter_vendor_to_str(vendorId, FALSE);
831 for (probe=commandListHead; probe; probe=probe->next) {
832 if (commandCode == probe->code) {
834 /* g_warning("Command: Comparing \"%s\" to \"%s\"", */
835 /* vendorName?vendorName:"(null)", */
836 /* probe->vendorName?probe->vendorName:"(null)"); */
837 /* Now check the vendor name */
838 if (!strcmp(vendorName, probe->vendorName))
842 /* With no vendor id, the Command's entry should be "None" */
843 if (!strcmp(probe->vendorName, "None")) {
851 g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
852 commandCode, vendorId);
853 snprintf(buffer, sizeof(buffer),
854 "Cmd-0x%08x", commandCode);
856 }/*diameter_command_to_str */
858 /* return application string, based on the id */
860 diameter_app_to_str(guint32 vendorId) {
861 ApplicationId *probe;
862 static gchar buffer[64];
864 for (probe=ApplicationIdHead; probe; probe=probe->next) {
865 if (vendorId == probe->id) {
870 snprintf(buffer, sizeof(buffer),
871 "AppId 0x%08x", vendorId);
873 } /*diameter_app_to_str */
875 /* return an avp type, based on the code */
876 static diameterDataType
877 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
879 gchar *vendorName=NULL;
882 vendorName = diameter_vendor_to_str(vendorId, FALSE);
884 for (probe=avpListHead; probe; probe=probe->next) {
885 if (avpCode == probe->code) {
888 /* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
889 /* vendorName?vendorName:"(null)", */
890 /* probe->vendorName?probe->vendorName:"(null)"); */
891 /* Now check the vendor name */
892 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
896 /* No Vendor ID -- vendorName should be null */
897 if (!probe->vendorName)
904 /* If we don't find it, assume it's data */
905 g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
907 return DIAMETER_OCTET_STRING;
908 } /* diameter_avp_get_type */
910 /* return an avp name from the code */
912 diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
914 static gchar buffer[64];
916 gchar *vendorName=NULL;
919 vendorName = diameter_vendor_to_str(vendorId, FALSE);
921 for (probe=avpListHead; probe; probe=probe->next) {
922 if (avpCode == probe->code) {
924 /* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
925 /* vendorName?vendorName:"(null)", */
926 /* probe->vendorName?probe->vendorName:"(null)"); */
927 /* Now check the vendor name */
928 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
932 /* No Vendor ID -- vendorName should be null */
933 if (!probe->vendorName)
940 g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
943 /* If we don't find it, build a name string */
944 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
946 } /* diameter_avp_get_name */
948 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
950 static gchar buffer[64];
953 gchar *vendorName=NULL;
956 vendorName = diameter_vendor_to_str(vendorId, FALSE);
958 for (probe=avpListHead; probe; probe=probe->next) {
959 if (avpCode == probe->code) {
961 /* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
962 /* vendorName?vendorName:"(null)", */
963 /* probe->vendorName?probe->vendorName:"(null)"); */
964 /* Now check the vendor name */
965 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
967 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
968 if (avpValue == vprobe->value) {
972 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
976 if (!probe->vendorName) {
978 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
979 if (avpValue == vprobe->value) {
983 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
989 /* If we don't find the avp, build a value string */
990 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
992 } /* diameter_avp_get_value */
995 /* Code to actually dissect the packets */
1000 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
1004 /* Set up structures needed to add the protocol subtree and manage it */
1007 proto_tree *flags_tree;
1009 proto_tree *diameter_tree;
1013 proto_tree *avp_tree;
1015 int BadPacket = FALSE;
1016 guint32 commandCode, pktLength;
1017 guint8 version, flags;
1018 gchar flagstr[64] = "<None>";
1019 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1020 gchar commandString[64], vendorName[64];
1023 static int initialized=FALSE;
1025 /* set our offset */
1029 * Only parse in dictionary if there are diameter packets to
1033 /* Read in our dictionary, if it exists. */
1034 initializeDictionary();
1038 /* Make entries in Protocol column and Info column on summary display */
1039 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1040 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1041 if (check_col(pinfo->cinfo, COL_INFO))
1042 col_clear(pinfo->cinfo, COL_INFO);
1044 /* Copy our header */
1045 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1047 /* Fix byte ordering in our static structure */
1048 dh.versionLength = g_ntohl(dh.versionLength);
1049 dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
1050 dh.vendorId = g_ntohl(dh.vendorId);
1051 dh.hopByHopId = g_ntohl(dh.hopByHopId);
1052 dh.endToEndId = g_ntohl(dh.endToEndId);
1056 diameter_vendor_to_str(dh.vendorId, TRUE));
1058 strcpy(vendorName, "None");
1062 /* Do the bit twiddling */
1063 version = DIAM_GET_VERSION(dh);
1064 pktLength = DIAM_GET_LENGTH(dh);
1065 flags = DIAM_GET_FLAGS(dh);
1066 commandCode = DIAM_GET_COMMAND(dh);
1068 /* Set up our flags */
1069 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1071 for (i = 0; i < 8; i++) {
1075 strcat(flagstr, ", ");
1077 strcat(flagstr, fstr[i]);
1080 if (strlen(flagstr) == 0) {
1081 strcpy(flagstr,"<None>");
1085 /* Set up our commandString */
1086 strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1087 if (flags & DIAM_FLAGS_R)
1088 strcat(commandString, "-Request");
1090 strcat(commandString, "-Answer");
1092 /* Short packet. Should have at LEAST one avp */
1093 if (pktLength < MIN_DIAMETER_SIZE) {
1094 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1095 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1099 /* And, check our reserved flags/version */
1100 if ((flags & DIAM_FLAGS_RESERVED) ||
1102 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1107 if (check_col(pinfo->cinfo, COL_INFO)) {
1108 col_add_fstr(pinfo->cinfo, COL_INFO,
1109 "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1110 (BadPacket)?"***** Bad Packet!: ":"",
1111 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1112 (flags & DIAM_FLAGS_E)?" Error":"",
1114 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1116 commandString, vendorName,
1117 dh.hopByHopId, dh.endToEndId,
1118 (flags & DIAM_FLAGS_R)?1:0,
1119 (flags & DIAM_FLAGS_P)?1:0,
1120 (flags & DIAM_FLAGS_E)?1:0);
1124 /* In the interest of speed, if "tree" is NULL, don't do any work not
1125 necessary to generate protocol tree items. */
1128 /* create display subtree for the protocol */
1129 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1130 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1131 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1134 proto_tree_add_uint(diameter_tree,
1135 hf_diameter_version,
1142 proto_tree_add_uint(diameter_tree,
1143 hf_diameter_length, tvb,
1144 offset, 3, pktLength);
1148 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1149 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1151 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1152 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1153 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1154 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1155 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1156 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1157 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1158 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1159 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1164 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1165 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1169 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1170 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
1173 /* Hop-by-hop Identifier */
1174 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1175 tvb, offset, 4, dh.hopByHopId);
1178 /* End-to-end Identifier */
1179 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1180 tvb, offset, 4, dh.endToEndId);
1183 /* If we have a bad packet, don't bother trying to parse the AVPs */
1185 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1188 /* Start looking at the AVPS */
1189 /* Make the next tvbuff */
1191 /* Update the lengths */
1192 avplength= pktLength - sizeof(e_diameterhdr);
1194 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1195 avptf = proto_tree_add_text(diameter_tree,
1196 tvb, offset, avplength,
1197 "Attribute Value Pairs");
1199 avp_tree = proto_item_add_subtree(avptf,
1201 if (avp_tree != NULL) {
1202 dissect_avps( avp_tvb, pinfo, avp_tree);
1204 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1206 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1208 } /* dissect_diameter_common */
1211 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1213 dissect_diameter_common(tvb, 0, pinfo, tree);
1217 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1221 guint32 available_bytes;
1222 /* guint32 noffset; */
1224 /* Loop through the packet, dissecting multiple diameter messages */
1226 available_bytes = tvb_length_remaining(tvb, offset);
1227 if (available_bytes < 4) {
1228 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1230 return; /* Bail. We can't even get our length */
1233 /* get our packet length */
1234 plen = tvb_get_ntohl(tvb, offset);
1235 plen &= 0x00ffffff; /* get rid of the flags */
1238 if (gbl_diameter_desegment) {
1239 if (pinfo->can_desegment
1240 && plen > available_bytes) {
1241 pinfo->desegment_offset = offset;
1242 pinfo->desegment_len = plen - available_bytes;
1243 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1244 /* plen, available_bytes); */
1249 /* Otherwise, dissect our packet */
1250 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1252 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1253 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1254 /* offset=noffset; */
1255 } while (offset < tvb_reported_length(tvb));
1257 } /* dissect_diameter_tcp */
1260 * Call the mip_dissector, after saving our pinfo variables
1261 * so it doesn't write to our column display.
1264 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1265 size_t offset, size_t length)
1267 static dissector_handle_t mip_handle;
1268 static int mipInitialized=FALSE;
1270 address save_dl_src;
1271 address save_dl_dst;
1272 address save_net_src;
1273 address save_net_dst;
1276 gboolean save_in_error_pkt;
1278 if (!mipInitialized) {
1279 mip_handle = find_dissector("mip");
1280 mipInitialized=TRUE;
1283 mip_tvb = tvb_new_subset(tvb, offset,
1284 MIN(length, tvb_length(tvb)-offset),
1287 /* The contained packet is a MIP registration request;
1288 dissect it with the MIP dissector. */
1289 col_set_writable(pinfo->cinfo, FALSE);
1291 /* Also, save the current values of the addresses, and restore
1292 them when we're finished dissecting the contained packet, so
1293 that the address columns in the summary don't reflect the
1294 contained packet, but reflect this packet instead. */
1295 save_dl_src = pinfo->dl_src;
1296 save_dl_dst = pinfo->dl_dst;
1297 save_net_src = pinfo->net_src;
1298 save_net_dst = pinfo->net_dst;
1299 save_src = pinfo->src;
1300 save_dst = pinfo->dst;
1301 save_in_error_pkt = pinfo->in_error_pkt;
1303 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1305 /* Restore the "we're inside an error packet" flag. */
1306 pinfo->in_error_pkt = save_in_error_pkt;
1307 pinfo->dl_src = save_dl_src;
1308 pinfo->dl_dst = save_dl_dst;
1309 pinfo->net_src = save_net_src;
1310 pinfo->net_dst = save_net_dst;
1311 pinfo->src = save_src;
1312 pinfo->dst = save_dst;
1315 } /* safe_dissect_mip */
1318 * This function will dissect the AVPs in a diameter packet. It handles
1319 * all normal types, and even recursively calls itself for grouped AVPs
1321 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1323 /* adds the attribute value pairs to the tree */
1325 gchar avpTypeString[64];
1326 gchar avpNameString[64];
1329 gchar vendorName[64];
1332 proto_tree *avpi_tree;
1334 tvbuff_t *group_tvb;
1335 proto_tree *group_tree;
1336 proto_item *grouptf;
1339 int BadPacket = FALSE;
1343 proto_tree *flags_tree;
1345 gint32 packetLength;
1346 size_t avpDataLength;
1348 gchar flagstr[64] = "<None>";
1349 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1353 packetLength = tvb_length(tvb);
1355 /* Check for invalid packet lengths */
1356 if (packetLength <= 0) {
1357 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1358 "No Attribute Value Pairs Found");
1362 /* Spin around until we run out of packet */
1363 while (packetLength > 0 ) {
1365 /* Check for short packet */
1366 if (packetLength < (long)MIN_AVP_SIZE) {
1367 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1368 packetLength, (long)MIN_AVP_SIZE);
1370 /* Don't even bother trying to parse a short packet. */
1374 /* Copy our header */
1375 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1377 /* Fix the byte ordering */
1378 avph.avp_code = g_ntohl(avph.avp_code);
1379 avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1381 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1382 avpLength = avph.avp_flagsLength & 0x00ffffff;
1384 /* Set up our flags string */
1385 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1387 for (i = 0; i < 8; i++) {
1391 strcat(flagstr, ", ");
1393 strcat(flagstr, fstr[i]);
1396 if (strlen(flagstr) == 0) {
1397 strcpy(flagstr,"<None>");
1401 /* Dissect our vendor id if it exists and set hdr length */
1402 if (flags & AVP_FLAGS_V) {
1403 vendorId = g_ntohl(avph.avp_vendorId);
1405 hdrLength = sizeof(e_avphdr);
1408 hdrLength = sizeof(e_avphdr) -
1415 diameter_vendor_to_str(vendorId, TRUE));
1420 /* Check for bad length */
1421 if (avpLength < MIN_AVP_SIZE ||
1422 ((long)avpLength > packetLength)) {
1423 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1424 "min: %ld bytes, packetLen: %d",
1425 (long)avpLength, (long)MIN_AVP_SIZE,
1430 /* Check for bad flags */
1431 if (flags & AVP_FLAGS_RESERVED) {
1432 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1434 flags, AVP_FLAGS_RESERVED);
1435 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1436 /* BadPacket = TRUE; */
1440 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1443 fixAmt = 4 - (avpLength % 4);
1444 if (fixAmt == 4) fixAmt = 0;
1446 /* shrink our packetLength */
1447 packetLength = packetLength - (avpLength + fixAmt);
1449 /* Check for out of bounds */
1450 if (packetLength < 0) {
1451 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1456 /* Make avp Name & type */
1457 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1459 "Unknown-Type: 0x%08x"));
1460 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1462 avptf = proto_tree_add_text(avp_tree, tvb,
1463 offset, avpLength + fixAmt,
1464 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1465 avpNameString, avpTypeString, avpLength,
1466 avpLength, avpLength+fixAmt);
1467 avpi_tree = proto_item_add_subtree(avptf,
1468 ett_diameter_avpinfo);
1470 if (avpi_tree !=NULL) {
1472 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1473 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1476 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1477 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1479 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1480 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1481 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1482 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1483 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1484 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1485 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1486 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1487 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1490 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1491 tvb, offset, 3, avpLength);
1494 if (flags & AVP_FLAGS_V) {
1495 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1496 tvb, offset, 4, vendorId, vendorName);
1500 avpDataLength = avpLength - hdrLength;
1503 * If we've got a bad packet, just highlight the data. Don't try
1504 * to parse it, and, don't move to next AVP.
1507 offset -= hdrLength;
1508 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1509 tvb, offset, tvb_length(tvb) - offset,
1510 tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1511 "Bad AVP (Suspect Data Not Dissected)");
1515 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1518 case DIAMETER_GROUPED:
1519 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1520 /* Recursively call ourselves */
1521 grouptf = proto_tree_add_text(avpi_tree,
1522 tvb, offset, tvb_length(tvb),
1525 group_tree = proto_item_add_subtree(grouptf,
1528 group_tvb = tvb_new_subset(tvb, offset,
1529 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1530 if (group_tree != NULL) {
1531 dissect_avps( group_tvb, pinfo, group_tree);
1535 case DIAMETER_IDENTITY:
1539 data = tvb_get_ptr(tvb, offset, avpDataLength);
1540 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1541 tvb, offset, avpDataLength, data,
1544 (int)avpDataLength, data);
1547 case DIAMETER_UTF8STRING:
1551 data = tvb_get_ptr(tvb, offset, avpDataLength);
1552 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1553 tvb, offset, avpDataLength, data,
1554 "UTF8String: %*.*s",
1556 (int)avpDataLength, data);
1559 case DIAMETER_IP_ADDRESS:
1560 if (avpDataLength == 4) {
1561 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1562 tvb, offset, avpDataLength, FALSE);
1563 } else if (avpDataLength == 16) {
1564 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1565 tvb, offset, avpDataLength, FALSE);
1567 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1568 tvb, offset, avpDataLength,
1569 tvb_get_ptr(tvb, offset, avpDataLength),
1570 "Error! Bad Address Length");
1574 case DIAMETER_INTEGER32:
1575 if (avpDataLength == 4) {
1576 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1577 tvb, offset, avpDataLength, FALSE);
1579 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1580 tvb, offset, avpDataLength,
1581 tvb_get_ptr(tvb, offset, avpDataLength),
1582 "Error! Bad Integer32 Length");
1586 case DIAMETER_UNSIGNED32:
1587 if (avpDataLength == 4) {
1590 data = tvb_get_ntohl(tvb, offset);
1591 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1592 tvb, offset, avpDataLength, data,
1593 "Value: 0x%08x (%u)", data, data);
1595 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1596 tvb, offset, avpDataLength,
1597 tvb_get_ptr(tvb, offset, avpDataLength),
1598 "Error! Bad Unsigned32 Length");
1602 case DIAMETER_INTEGER64:
1603 if (avpDataLength == 8) {
1604 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1605 tvb, offset, 8, FALSE);
1607 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1608 tvb, offset, avpDataLength,
1609 tvb_get_ptr(tvb, offset, avpDataLength),
1610 "Error! Bad Integer64 Length");
1614 case DIAMETER_UNSIGNED64:
1615 if (avpDataLength == 8) {
1616 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1617 tvb, offset, 8, FALSE);
1619 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1620 tvb, offset, avpDataLength,
1621 tvb_get_ptr(tvb, offset, avpDataLength),
1622 "Error! Bad Unsigned64 Length");
1627 if (avpDataLength == 4) {
1632 data.secs = tvb_get_ntohl(tvb, offset);
1633 data.secs -= NTP_TIME_DIFF;
1636 ltp = localtime(&data.secs);
1637 strftime(buffer, 64,
1638 "%a, %d %b %Y %H:%M:%S %z", ltp);
1640 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1641 tvb, offset, avpDataLength, &data,
1642 "Time: %s", buffer);
1644 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1645 tvb, offset, avpDataLength,
1646 tvb_get_ptr(tvb, offset, avpDataLength),
1647 "Error! Bad Time Length");
1651 case DIAMETER_ENUMERATED:
1652 if (avpDataLength == 4) {
1655 data = tvb_get_ntohl(tvb, offset);
1656 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1657 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1658 tvb, offset, avpDataLength, data,
1659 "Value: 0x%08x (%u): %s", data,
1662 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1663 tvb, offset, avpDataLength,
1664 tvb_get_ptr(tvb, offset, avpDataLength),
1665 "Error! Bad Enumerated Length");
1668 case DIAMETER_VENDOR_ID:
1669 if (avpDataLength == 4) {
1672 data = tvb_get_ntohl(tvb, offset);
1673 valstr = diameter_vendor_to_str(data, TRUE);
1674 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1675 tvb, offset, avpDataLength, data,
1676 "Vendor ID: %s (0x%08x)", valstr,
1679 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1680 tvb, offset, avpDataLength,
1681 tvb_get_ptr(tvb, offset, avpDataLength),
1682 "Error! Bad Vendor ID Length");
1685 case DIAMETER_APPLICATION_ID:
1686 if (avpDataLength == 4) {
1689 data = tvb_get_ntohl(tvb, offset);
1690 valstr = diameter_app_to_str(data);
1691 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1692 tvb, offset, avpDataLength, data,
1693 "Application ID: %s (0x%08x)",
1696 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1697 tvb, offset, avpDataLength,
1698 tvb_get_ptr(tvb, offset, avpDataLength),
1699 "Error! Bad Application ID Length");
1702 case DIAMETER_MIP_REG_REQ:
1703 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1707 case DIAMETER_OCTET_STRING:
1708 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1709 tvb, offset, avpDataLength,
1710 tvb_get_ptr(tvb, offset, avpDataLength),
1711 "Hex Data Highlighted Below");
1715 } /* avpi_tree != null */
1716 offset += (avpLength - hdrLength);
1717 offset += fixAmt; /* fix byte alignment */
1719 } /* dissect_avps */
1724 proto_reg_handoff_diameter(void)
1726 static int Initialized=FALSE;
1727 static int TcpPort=0;
1728 static int SctpPort=0;
1729 static dissector_handle_t diameter_tcp_handle;
1730 static dissector_handle_t diameter_sctp_handle;
1733 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1735 diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1739 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1740 dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1743 /* set port for future deletes */
1744 TcpPort=gbl_diameterTcpPort;
1745 SctpPort=gbl_diameterSctpPort;
1747 strcpy(gbl_diameterString, "Diameter Protocol");
1749 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1750 gbl_diameterTcpPort); */
1751 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1752 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1755 /* registration with the filtering engine */
1757 proto_register_diameter(void)
1759 static hf_register_info hf[] = {
1760 { &hf_diameter_version,
1761 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1763 { &hf_diameter_length,
1764 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1767 { &hf_diameter_flags,
1768 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1770 { &hf_diameter_flags_request,
1771 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1773 { &hf_diameter_flags_proxyable,
1774 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1776 { &hf_diameter_flags_error,
1777 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1779 { &hf_diameter_flags_reserved3,
1780 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1781 DIAM_FLAGS_RESERVED3, "", HFILL }},
1782 { &hf_diameter_flags_reserved4,
1783 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1784 DIAM_FLAGS_RESERVED4, "", HFILL }},
1785 { &hf_diameter_flags_reserved5,
1786 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1787 DIAM_FLAGS_RESERVED5, "", HFILL }},
1788 { &hf_diameter_flags_reserved6,
1789 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1790 DIAM_FLAGS_RESERVED6, "", HFILL }},
1791 { &hf_diameter_flags_reserved7,
1792 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1793 DIAM_FLAGS_RESERVED7, "", HFILL }},
1795 { &hf_diameter_code,
1796 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1797 NULL, 0x0, "", HFILL }},
1798 { &hf_diameter_vendor_id,
1799 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1801 { &hf_diameter_hopbyhopid,
1802 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1803 BASE_HEX, NULL, 0x0, "", HFILL }},
1804 { &hf_diameter_endtoendid,
1805 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1806 BASE_HEX, NULL, 0x0, "", HFILL }},
1808 { &hf_diameter_avp_code,
1809 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1810 NULL, 0x0, "", HFILL }},
1811 { &hf_diameter_avp_length,
1812 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1813 NULL, 0x0, "", HFILL }},
1816 { &hf_diameter_avp_flags,
1817 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1818 NULL, 0x0, "", HFILL }},
1819 { &hf_diameter_avp_flags_vendor_specific,
1820 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1822 { &hf_diameter_avp_flags_mandatory,
1823 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1825 { &hf_diameter_avp_flags_protected,
1826 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1828 { &hf_diameter_avp_flags_reserved3,
1829 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1830 AVP_FLAGS_RESERVED3, "", HFILL }},
1831 { &hf_diameter_avp_flags_reserved4,
1832 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1833 AVP_FLAGS_RESERVED4, "", HFILL }},
1834 { &hf_diameter_avp_flags_reserved5,
1835 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1836 AVP_FLAGS_RESERVED5, "", HFILL }},
1837 { &hf_diameter_avp_flags_reserved6,
1838 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1839 AVP_FLAGS_RESERVED6, "", HFILL }},
1840 { &hf_diameter_avp_flags_reserved7,
1841 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1842 AVP_FLAGS_RESERVED7, "", HFILL }},
1843 { &hf_diameter_avp_vendor_id,
1844 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1845 NULL, 0x0, "", HFILL }},
1846 { &hf_diameter_avp_data_uint64,
1847 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1848 NULL, 0x0, "", HFILL }},
1849 { &hf_diameter_avp_data_int64,
1850 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1851 NULL, 0x0, "", HFILL }},
1852 { &hf_diameter_avp_data_uint32,
1853 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1854 NULL, 0x0, "", HFILL }},
1855 { &hf_diameter_avp_data_int32,
1856 { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1857 NULL, 0x0, "", HFILL }},
1858 { &hf_diameter_avp_data_bytes,
1859 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1860 NULL, 0x0, "", HFILL }},
1861 { &hf_diameter_avp_data_string,
1862 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1863 NULL, 0x0, "", HFILL }},
1864 { &hf_diameter_avp_data_v4addr,
1865 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1866 NULL, 0x0, "", HFILL }},
1867 { &hf_diameter_avp_data_v6addr,
1868 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1869 NULL, 0x0, "", HFILL }},
1870 { &hf_diameter_avp_data_time,
1871 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1872 NULL, 0x0, "", HFILL }},
1875 static gint *ett[] = {
1877 &ett_diameter_flags,
1879 &ett_diameter_avp_flags,
1880 &ett_diameter_avpinfo
1882 module_t *diameter_module;
1884 proto_diameter = proto_register_protocol (gbl_diameterString,
1885 "Diameter", "diameter");
1886 proto_register_field_array(proto_diameter, hf, array_length(hf));
1887 proto_register_subtree_array(ett, array_length(ett));
1889 /* Register a configuration option for port */
1890 diameter_module = prefs_register_protocol(proto_diameter,
1891 proto_reg_handoff_diameter);
1892 prefs_register_uint_preference(diameter_module, "tcp.port",
1893 "Diameter TCP Port",
1894 "Set the TCP port for Diameter messages",
1896 &gbl_diameterTcpPort);
1897 prefs_register_uint_preference(diameter_module, "sctp.port",
1898 "Diameter SCTP Port",
1899 "Set the SCTP port for Diameter messages",
1901 &gbl_diameterSctpPort);
1903 * Build our default dictionary filename
1905 if (! gbl_diameterDictionary) {
1906 gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
1907 1 + strlen(DICT_FN) + 1); /* slash + fn + null */
1908 sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
1909 get_datafile_dir(), DICT_FN );
1911 /* Now register its preferences so it can be changed. */
1912 prefs_register_string_preference(diameter_module, "dictionary.name",
1913 "Diameter XML Dictionary",
1914 "Set the dictionary used for Diameter messages",
1915 &gbl_diameterDictionary);
1917 /* Desegmentation */
1918 prefs_register_bool_preference(diameter_module, "desegment",
1919 "Desegment all Diameter messages spanning multiple TCP segments",
1920 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1921 &gbl_diameter_desegment);
1923 /* Register some preferences we no longer support, so we can report
1924 them as obsolete rather than just illegal. */
1925 prefs_register_obsolete_preference(diameter_module, "udp.port");
1926 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1927 } /* proto_register_diameter */