2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.33 2001/11/04 02:50:19 guy Exp $
6 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
45 #include <filesystem.h>
51 /* This must be defined before we include packet-diameter-defs.h */
53 /* Valid data types */
56 DIAMETER_OCTET_STRING = 1,
67 DIAMETER_IP_ADDRESS, /* OctetString */
68 DIAMETER_TIME, /* Integer 32 */
69 DIAMETER_UTF8STRING, /* OctetString */
70 DIAMETER_IDENTITY, /* OctetString */
71 DIAMETER_ENUMERATED, /* Integer 32 */
72 DIAMETER_IP_FILTER_RULE, /* OctetString */
73 DIAMETER_QOS_FILTER_RULE, /* OctetString */
74 DIAMETER_MIP_REG_REQ, /* OctetString */
75 DIAMETER_VENDOR_ID, /* Integer32 */
76 DIAMETER_APPLICATION_ID
81 static value_string TypeValues[]={
82 { DIAMETER_OCTET_STRING, "OctetString" },
83 { DIAMETER_INTEGER32, "Integer32" },
84 { DIAMETER_INTEGER64, "Integer64" },
85 { DIAMETER_UNSIGNED32, "Unsigned32" },
86 { DIAMETER_UNSIGNED64, "Unsigned64" },
87 { DIAMETER_FLOAT32, "Float32" },
88 { DIAMETER_FLOAT64, "Float64" },
89 { DIAMETER_FLOAT128, "Float128" },
90 { DIAMETER_GROUPED, "Grouped" },
91 { DIAMETER_IP_ADDRESS, "IpAddress" },
92 { DIAMETER_TIME, "Time" },
93 { DIAMETER_UTF8STRING, "UTF8String" },
94 { DIAMETER_IDENTITY, "DiameterIdentity" },
95 { DIAMETER_ENUMERATED, "Enumerated" },
96 { DIAMETER_IP_FILTER_RULE, "IPFilterRule" },
97 { DIAMETER_QOS_FILTER_RULE, "QOSFilterRule" },
98 { DIAMETER_MIP_REG_REQ, "MIPRegistrationRequest"},
99 { DIAMETER_VENDOR_ID, "VendorId"},
100 { DIAMETER_APPLICATION_ID, "AppId"},
104 typedef struct value_name {
107 struct value_name *next;
110 typedef struct old_avp_info {
113 diameterDataType type;
114 value_string *values;
117 typedef struct avp_info {
121 diameterDataType type;
123 struct avp_info *next;
126 typedef struct command_code {
130 struct command_code *next;
133 typedef struct vendor_id {
137 struct vendor_id *next;
140 typedef struct application_id {
143 struct application_id *next;
146 static avpInfo *avpListHead=NULL;
147 static VendorId *vendorListHead=NULL;
148 static CommandCode *commandListHead=NULL;
149 static ApplicationId *ApplicationIdHead=NULL;
152 #include "packet-diameter-defs.h"
154 #define NTP_TIME_DIFF (2208988800UL)
156 #define TCP_PORT_DIAMETER 1812
157 #define SCTP_PORT_DIAMETER 1812
159 static const true_false_string flags_set_truth = {
164 static const true_false_string reserved_set = {
165 "*** Error! Reserved Bit is Set",
168 static int proto_diameter = -1;
169 static int hf_diameter_length = -1;
170 static int hf_diameter_code = -1;
171 static int hf_diameter_hopbyhopid =-1;
172 static int hf_diameter_endtoendid =-1;
173 static int hf_diameter_reserved = -1;
174 static int hf_diameter_version = -1;
175 static int hf_diameter_vendor_id = -1;
176 static int hf_diameter_flags = -1;
177 static int hf_diameter_flags_request = -1;
178 static int hf_diameter_flags_proxyable = -1;
179 static int hf_diameter_flags_error = -1;
180 static int hf_diameter_flags_reserved3 = -1;
181 static int hf_diameter_flags_reserved4 = -1;
182 static int hf_diameter_flags_reserved5 = -1;
183 static int hf_diameter_flags_reserved6 = -1;
184 static int hf_diameter_flags_reserved7 = -1;
186 static int hf_diameter_avp_code = -1;
187 static int hf_diameter_avp_length = -1;
188 static int hf_diameter_avp_reserved = -1;
189 static int hf_diameter_avp_flags = -1;
190 static int hf_diameter_avp_flags_vendor_specific = -1;
191 static int hf_diameter_avp_flags_mandatory = -1;
192 static int hf_diameter_avp_flags_protected = -1;
193 static int hf_diameter_avp_flags_reserved3 = -1;
194 static int hf_diameter_avp_flags_reserved4 = -1;
195 static int hf_diameter_avp_flags_reserved5 = -1;
196 static int hf_diameter_avp_flags_reserved6 = -1;
197 static int hf_diameter_avp_flags_reserved7 = -1;
198 static int hf_diameter_avp_vendor_id = -1;
201 static int hf_diameter_avp_data_uint32 = -1;
202 static int hf_diameter_avp_data_int32 = -1;
203 static int hf_diameter_avp_data_uint64 = -1;
204 static int hf_diameter_avp_data_int64 = -1;
205 static int hf_diameter_avp_data_bytes = -1;
206 static int hf_diameter_avp_data_string = -1;
207 static int hf_diameter_avp_data_v4addr = -1;
208 static int hf_diameter_avp_data_v6addr = -1;
209 static int hf_diameter_avp_data_time = -1;
211 static gint ett_diameter = -1;
212 static gint ett_diameter_flags = -1;
213 static gint ett_diameter_avp = -1;
214 static gint ett_diameter_avp_flags = -1;
215 static gint ett_diameter_avpinfo = -1;
217 static char gbl_diameterString[200];
218 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
219 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
221 /* desegmentation of Diameter over TCP */
222 static gboolean gbl_diameter_desegment = TRUE;
224 #define DIAMETER_DIR "diameter"
225 #define DICT_FN "dictionary.xml"
226 static gchar *gbl_diameterDictionary = NULL;
228 typedef struct _e_diameterhdr {
229 guint32 versionLength;
230 guint32 flagsCmdCode;
236 typedef struct _e_avphdr {
238 guint32 avp_flagsLength;
239 guint32 avp_vendorId; /* optional */
242 /* Diameter Header Flags */
243 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
244 #define DIAM_FLAGS_R 0x80
245 #define DIAM_FLAGS_P 0x40
246 #define DIAM_FLAGS_E 0x20
247 #define DIAM_FLAGS_RESERVED3 0x10
248 #define DIAM_FLAGS_RESERVED4 0x08
249 #define DIAM_FLAGS_RESERVED5 0x04
250 #define DIAM_FLAGS_RESERVED6 0x02
251 #define DIAM_FLAGS_RESERVED7 0x01
252 #define DIAM_FLAGS_RESERVED 0x1f
254 #define DIAM_LENGTH_MASK 0x00ffffffl
255 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
256 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
257 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
258 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
259 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
261 /* Diameter AVP Flags */
262 #define AVP_FLAGS_P 0x20
263 #define AVP_FLAGS_V 0x80
264 #define AVP_FLAGS_M 0x40
265 #define AVP_FLAGS_RESERVED3 0x10
266 #define AVP_FLAGS_RESERVED4 0x08
267 #define AVP_FLAGS_RESERVED5 0x04
268 #define AVP_FLAGS_RESERVED6 0x02
269 #define AVP_FLAGS_RESERVED7 0x01
270 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
272 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
273 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
275 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
279 * This routine will do a push-parse of the passed in
280 * filename. This was taken almost verbatum from
281 * the xmlsoft examples.
284 xmlParseFilePush( char *filename, int checkValid) {
288 int res, size = 1024;
290 xmlParserCtxtPtr ctxt;
292 /* I wonder what kind of a performance hit this is? */
293 *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
295 f = fopen(filename, "r");
297 g_warning("Diameter: Unable to open %s", filename);
301 res = fread(chars, 1, 4, f);
303 ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
304 chars, res, filename);
305 while ((res = fread(chars, 1, size-1, f)) > 0) {
306 XmlStub.xmlParseChunk(ctxt, chars, res, 0);
308 XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
311 XmlStub.xmlFreeParserCtxt(ctxt);
317 g_warning( "Error! Invalid xml in %s! Failed DTD check!",
322 } /* xmlParseFilePush */
325 * This routine will add a static avp to the avp list. It is
326 * only called when the XML dictionary fails to load properly.
329 addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
332 ValueName *vEntry=NULL;
335 /* Parse our values array, if we have one */
337 for (i=0; values[i].strptr != NULL; i++) {
338 char *valueName=NULL, *valueCode=NULL;
339 ValueName *ve = NULL;
341 ve = g_malloc(sizeof(ValueName));
342 ve->name = strdup(values[i].strptr);
343 ve->value = values[i].value;
349 /* And, create the entry */
350 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
351 entry->name = g_strdup(name);
353 entry->vendorName = NULL;
355 entry->values = vEntry;
357 entry->type = DIAMETER_INTEGER32;
359 /* And, add it to the list */
360 entry->next = avpListHead;
368 * This routine will parse an XML avp entry, and add it to our
369 * avp list. If any values are present in the avp, it will
373 xmlParseAVP(xmlDocPtr doc, xmlNodePtr cur)
375 char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
376 *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
381 ValueName *vEntry=NULL;
384 /* First, get our properties */
385 name = XmlStub.xmlGetProp(cur, "name");
386 description = XmlStub.xmlGetProp(cur, "description");
387 code = XmlStub.xmlGetProp(cur, "code");
388 mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
389 mandatory = XmlStub.xmlGetProp(cur, "mandatory");
390 protected = XmlStub.xmlGetProp(cur, "protected");
391 vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
392 vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
393 constrained = XmlStub.xmlGetProp(cur, "constrained");
395 cur = cur->xmlChildrenNode;
397 while (cur != NULL ) {
398 if (!strcasecmp((char *)cur->name, "type")) {
399 type = XmlStub.xmlGetProp(cur, "type-name");
401 if (!strcasecmp((char *)cur->name, "enum")) {
402 char *valueName=NULL, *valueCode=NULL;
403 ValueName *ve = NULL;
404 valueName = XmlStub.xmlGetProp(cur, "name");
405 valueCode = XmlStub.xmlGetProp(cur, "code");
407 if (!valueName || !valueCode) {
408 g_warning( "Error, bad value on avp %s", name);
412 ve = g_malloc(sizeof(ValueName));
413 ve->name = strdup(valueName);
414 ve->value = atol(valueCode);
419 if (!strcasecmp((char *)cur->name, "grouped")) {
420 /* WORK Recurse here for grouped AVPs */
427 * Check for the AVP Type.
430 for (i = 0; TypeValues[i].strptr; i++) {
431 if (!strcasecmp(type, TypeValues[i].strptr)) {
432 avpType = TypeValues[i].value;
437 if (TypeValues[i].strptr == NULL) {
438 g_warning( "Invalid Type field in dictionary! avp %s (%s)", name, type);
441 } else if (!vEntry) {
442 g_warning("Missing type/enum field in dictionary avpName=%s",
447 /* WORK - Handle flags -- for validation later */
450 /* And, create the entry */
451 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
452 entry->name = g_strdup(name);
453 entry->code = atol(code);
455 entry->vendorName = g_strdup(vendorName);
457 entry->vendorName = NULL;
458 entry->type = avpType;
459 entry->values = vEntry;
461 entry->type = DIAMETER_INTEGER32;
463 /* And, add it to the list */
464 entry->next = avpListHead;
471 * This routine will add a command to the list of commands.
474 addCommand(int code, char *name, char *vendorId)
479 * Allocate the memory required for the dictionary.
481 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
484 g_warning("Unable to allocate memory");
489 * Allocate memory for the AVPName and copy the name to the
492 entry->name = g_strdup(name);
495 entry->vendorString = g_strdup(vendorId);
497 entry->vendorString = NULL;
499 /* Add the entry to the list */
500 entry->next = commandListHead;
501 commandListHead = entry;
507 * This routine will parse the XML command, and add it to our
511 xmlParseCommand(xmlDocPtr doc, xmlNodePtr cur)
513 guint32 vendorId = 0;
514 char *name, *code, *vendorIdString;
519 name = XmlStub.xmlGetProp(cur, "name");
520 code = XmlStub.xmlGetProp(cur, "code");
521 if (!name || !code) {
522 g_warning("Invalid command. Name or code missing!");
525 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
527 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
528 vendorIdString = NULL;
531 return (addCommand(atoi(code), name, vendorIdString));
532 } /* xmlParseCommand */
534 /* This routine adds an application to the name<-> id table */
536 dictionaryAddApplication(char *name, int id)
538 ApplicationId *entry;
540 if (!name || (id <= 0)) {
541 g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
544 } /* Sanity Checks */
546 entry = g_malloc(sizeof(ApplicationId));
548 g_warning( "Unable to allocate memory");
552 entry->name = g_strdup(name);
555 /* Add it to the list */
556 entry->next = ApplicationIdHead;
557 ApplicationIdHead = entry;
560 } /* dictionaryAddApplication */
563 * This routine will add a vendor to the vendors list
566 addVendor(int id, gchar *name, gchar *longName)
571 vendor=g_malloc(sizeof(VendorId));
577 vendor->name = g_strdup(name);
578 vendor->longName = g_strdup(longName);
579 vendor->next = vendorListHead;
580 vendorListHead = vendor;
586 * This routine will pars in a XML vendor entry.
589 xmlParseVendor(xmlDocPtr doc, xmlNodePtr cur)
591 char *name=NULL, *code=NULL, *id=NULL;
593 /* First, get our properties */
594 id = XmlStub.xmlGetProp(cur, "vendor-id");
595 name = XmlStub.xmlGetProp(cur, "name");
596 code = XmlStub.xmlGetProp(cur, "code");
598 if (!id || !name || !code) {
599 g_warning( "Invalid vendor section. vendor-id, name, and code must be specified");
603 return (addVendor(atoi(code), id, name));
607 * This routine will either parse in the base protocol, or an application.
610 xmlDictionaryParseSegment(xmlDocPtr doc, xmlNodePtr cur, int base)
616 /* Add our application */
617 id = XmlStub.xmlGetProp(cur, "id");
618 name = XmlStub.xmlGetProp(cur, "name");
622 g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
623 name?name:"NULL", id?id:"NULL");
627 /* Add the application */
628 if (dictionaryAddApplication(name, atol(id)) != 0) {
638 cur = cur->xmlChildrenNode;
639 while (cur != NULL) {
640 if (!strcasecmp((char *)cur->name, "avp")) {
641 /* we have an avp!!! */
642 xmlParseAVP(doc, cur);
643 } else if (!strcasecmp((char *)cur->name, "vendor")) {
644 /* we have a vendor */
645 xmlParseVendor(doc, cur);
646 /* For now, ignore typedefn and text */
647 } else if (!strcasecmp((char *)cur->name, "command")) {
648 /* Found a command */
649 xmlParseCommand(doc,cur);
650 } else if (!strcasecmp((char *)cur->name, "text")) {
651 } else if (!strcasecmp((char *)cur->name, "comment")) {
652 } else if (!strcasecmp((char *)cur->name, "typedefn")) {
653 /* WORK -- parse in valid types . . . */
655 /* IF we got here, we're an error */
656 g_warning("Error! expecting an avp or a typedefn (got \"%s\")",
663 } /* xmlDictionaryParseSegment */
666 * The main xml parse routine. This will walk through an XML
667 * dictionary that has been parsed by libxml.
670 xmlDictionaryParse(xmlDocPtr doc, xmlNodePtr cur)
672 /* We should expect a base protocol, followed by multiple applicaitons */
673 while (cur != NULL) {
674 if (!strcasecmp((char *)cur->name, "base")) {
675 /* Base protocol. Descend and parse */
676 xmlDictionaryParseSegment(doc, cur, 1);
677 } else if (!strcasecmp((char *)cur->name, "application")) {
678 /* Application. Descend and parse */
679 xmlDictionaryParseSegment(doc, cur, 0);
680 } else if (!strcasecmp((char *)cur->name, "text")) {
683 g_warning( "Diameter: XML Expecting a base or an application (got \"%s\")",
692 } /* xmlDictionaryParse */
695 * This routine will call libxml to parse in the dictionary.
704 * build an XML tree from a the file;
706 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
707 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
708 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
710 /* Check for invalid xml */
712 g_warning("Diameter: Unable to parse xmldictionary %s",
713 gbl_diameterDictionary);
718 * Check the document is of the right kind
720 cur = XmlStub.xmlDocGetRootElement(doc);
722 g_warning("Diameter: Error: \"%s\": empty document",
723 gbl_diameterDictionary);
724 XmlStub.xmlFreeDoc(doc);
727 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
728 g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
729 gbl_diameterDictionary);
730 XmlStub.xmlFreeDoc(doc);
735 * Ok, the dictionary has been parsed by libxml, and is valid.
736 * All we have to do now is read in our information.
738 if (xmlDictionaryParse(doc, cur->xmlChildrenNode) != 0) {
739 /* Error has already been printed */
743 /* Once we're done parsing, free up the xml memory */
744 XmlStub.xmlFreeDoc(doc);
748 } /* loadXMLDictionary */
751 * Fallback routine. In the event of ANY error when loading the XML
752 * dictionary, this routine will populate the new avp list structures
753 * with the old static data from packet-diameter-defs.h
756 initializeDictionaryDefaults()
760 /* Add static vendors to list */
761 for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
762 addVendor(diameter_vendor_specific_vendors[i].value,
763 diameter_vendor_specific_vendors[i].strptr,
764 diameter_vendor_specific_vendors[i].strptr);
766 /* Add static commands to list. */
767 for(i=0; diameter_command_code_vals[i].strptr; i++) {
768 addCommand(diameter_command_code_vals[i].value,
769 diameter_command_code_vals[i].strptr, NULL);
772 /* Add static AVPs to list */
773 for (i=0; old_diameter_avps[i].name; i++) {
774 addStaticAVP(old_diameter_avps[i].code,
775 old_diameter_avps[i].name,
776 old_diameter_avps[i].type,
777 old_diameter_avps[i].values);
780 } /* initializeDictionaryDefaults */
783 * This routine will attempt to load the XML dictionary, and on
784 * failure, will call initializeDictionaryDefaults to load in
785 * our static dictionary.
788 initializeDictionary()
791 * Using ugly ordering here. If loadLibXML succeeds, then
792 * loadXMLDictionary will be called. This is one of the few times when
793 * I think this is prettier than the nested if alternative.
796 (loadXMLDictionary() != 0)) {
797 /* Something failed. Use the static dictionary */
798 g_warning("Diameter: Using static dictionary! (Unable to use XML)");
799 initializeDictionaryDefaults();
801 } /* initializeDictionary */
806 * These routines manipulate the diameter structures.
809 /* return command string, based on the code */
811 diameter_command_to_str(guint32 commandCode)
814 static gchar buffer[64];
816 for (probe=commandListHead; probe; probe=probe->next) {
817 if (commandCode == probe->code) {
822 snprintf(buffer, sizeof(buffer),
823 "Cmd-0x%08x", commandCode);
825 }/*diameter_command_to_str */
826 /* return vendor string, based on the id */
828 diameter_vendor_to_str(guint32 vendorId) {
830 static gchar buffer[64];
832 for (probe=vendorListHead; probe; probe=probe->next) {
833 if (vendorId == probe->id) {
834 return probe->longName;
838 snprintf(buffer, sizeof(buffer),
839 "Vendor 0x%08x", vendorId);
841 } /*diameter_vendor_to_str */
842 /* return application string, based on the id */
844 diameter_app_to_str(guint32 vendorId) {
845 ApplicationId *probe;
846 static gchar buffer[64];
848 for (probe=ApplicationIdHead; probe; probe=probe->next) {
849 if (vendorId == probe->id) {
854 snprintf(buffer, sizeof(buffer),
855 "AppId 0x%08x", vendorId);
857 } /*diameter_app_to_str */
859 /* return an avp type, based on the code */
861 diameter_avp_get_type(guint32 avpCode){
864 for (probe=avpListHead; probe; probe=probe->next) {
865 if (avpCode == probe->code) {
871 /* If we don't find it, assume it's data */
872 g_warning("Diameter: Unable to find type for avpCode %d!", avpCode);
873 return DIAMETER_OCTET_STRING;
874 } /* diameter_avp_get_type */
876 /* return an avp name from the code */
878 diameter_avp_get_name(guint32 avpCode)
880 static gchar buffer[64];
883 for (probe=avpListHead; probe; probe=probe->next) {
884 if (avpCode == probe->code) {
889 /* If we don't find it, build a name string */
890 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
892 } /* diameter_avp_get_name */
894 diameter_avp_get_value(guint32 avpCode, guint32 avpValue)
896 static gchar buffer[64];
900 for (probe=avpListHead; probe; probe=probe->next) {
901 if (avpCode == probe->code) {
903 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
904 if (avpValue == vprobe->value) {
908 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
912 /* If we don't find the avp, build a value string */
913 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
915 } /* diameter_avp_get_value */
918 diameter_time_to_string(gchar *timeValue)
920 static gchar buffer[64];
924 intval=pntohl(*((guint32*)timeValue));
925 intval -= NTP_TIME_DIFF;
926 lt=*localtime((time_t *)&intval);
927 strftime(buffer, 1024,
928 "%a, %d %b %Y %H:%M:%S %z",<);
930 } /* diameter_time_to_string */
933 /* Code to actually dissect the packets */
938 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
942 /* Set up structures needed to add the protocol subtree and manage it */
945 proto_tree *flags_tree;
947 proto_tree *diameter_tree;
951 proto_tree *avp_tree;
953 int BadPacket = FALSE;
954 guint32 commandCode, pktLength;
955 guint8 version, flags;
956 gchar flagstr[64] = "<None>";
957 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
958 gchar commandString[64], vendorString[64];
961 static int initialized=FALSE;
967 * Only parse in dictionary if there are diameter packets to
971 /* Read in our dictionary, if it exists. */
972 initializeDictionary();
976 /* Make entries in Protocol column and Info column on summary display */
977 if (check_col(pinfo->fd, COL_PROTOCOL))
978 col_add_str(pinfo->fd, COL_PROTOCOL, "Diameter");
979 if (check_col(pinfo->fd, COL_INFO))
980 col_clear(pinfo->fd, COL_INFO);
982 /* Copy our header */
983 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
985 /* Fix byte ordering in our static structure */
986 dh.versionLength = ntohl(dh.versionLength);
987 dh.flagsCmdCode = ntohl(dh.flagsCmdCode);
988 dh.vendorId = ntohl(dh.vendorId);
989 dh.hopByHopId = ntohl(dh.hopByHopId);
990 dh.endToEndId = ntohl(dh.endToEndId);
994 diameter_vendor_to_str(dh.vendorId));
996 strcpy(vendorString, "None");
1000 /* Do the bit twiddling */
1001 version = DIAM_GET_VERSION(dh);
1002 pktLength = DIAM_GET_LENGTH(dh);
1003 flags = DIAM_GET_FLAGS(dh);
1004 commandCode = DIAM_GET_COMMAND(dh);
1006 /* Set up our flags */
1007 if (check_col(pinfo->fd, COL_INFO) || tree) {
1009 for (i = 0; i < 8; i++) {
1013 strcat(flagstr, ", ");
1015 strcat(flagstr, fstr[i]);
1018 if (strlen(flagstr) == 0) {
1019 strcpy(flagstr,"<None>");
1023 /* Set up our commandString */
1024 strcpy(commandString, diameter_command_to_str(commandCode));
1025 if (flags & DIAM_FLAGS_R)
1026 strcat(commandString, "-Request");
1028 strcat(commandString, "-Answer");
1030 /* Short packet. Should have at LEAST one avp */
1031 if (pktLength < MIN_DIAMETER_SIZE) {
1032 g_warning("Diameter: Packet too short: %d bytes less than min size (%d bytes))",
1033 pktLength, MIN_DIAMETER_SIZE);
1037 /* And, check our reserved flags/version */
1038 if ((flags & DIAM_FLAGS_RESERVED) ||
1040 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1045 if (check_col(pinfo->fd, COL_INFO)) {
1046 col_add_fstr(pinfo->fd, COL_INFO,
1047 "%s%s%s%s%s vendor=%s (hop-id=%d) (end-id=%d) RPE=%d%d%d",
1048 (BadPacket)?"***** Bad Packet!: ":"",
1049 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1050 (flags & DIAM_FLAGS_E)?" Error":"",
1052 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1054 commandString, vendorString,
1055 dh.hopByHopId, dh.endToEndId,
1056 (flags & DIAM_FLAGS_R)?1:0,
1057 (flags & DIAM_FLAGS_P)?1:0,
1058 (flags & DIAM_FLAGS_E)?1:0);
1062 /* In the interest of speed, if "tree" is NULL, don't do any work not
1063 necessary to generate protocol tree items. */
1066 /* create display subtree for the protocol */
1067 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1068 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1069 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1072 proto_tree_add_uint(diameter_tree,
1073 hf_diameter_version,
1080 proto_tree_add_uint(diameter_tree,
1081 hf_diameter_length, tvb,
1082 offset, 3, pktLength);
1086 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1087 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1089 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1090 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1091 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1092 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1093 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1094 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1095 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1096 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1097 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1102 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1103 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1107 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1108 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorString);
1111 /* Hop-by-hop Identifier */
1112 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1113 tvb, offset, 4, dh.hopByHopId);
1116 /* End-to-end Identifier */
1117 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1118 tvb, offset, 4, dh.endToEndId);
1121 /* If we have a bad packet, don't bother trying to parse the AVPs */
1123 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1126 /* Start looking at the AVPS */
1127 /* Make the next tvbuff */
1129 /* Update the lengths */
1130 avplength= pktLength - sizeof(e_diameterhdr);
1132 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1133 avptf = proto_tree_add_text(diameter_tree,
1134 tvb, offset, avplength,
1135 "Attribute Value Pairs");
1137 avp_tree = proto_item_add_subtree(avptf,
1139 if (avp_tree != NULL) {
1140 dissect_avps( avp_tvb, pinfo, avp_tree);
1142 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1144 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1146 } /* dissect_diameter_common */
1149 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1151 dissect_diameter_common(tvb, 0, pinfo, tree);
1155 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1159 guint32 available_bytes;
1160 /* guint32 noffset; */
1162 /* Loop through the packet, dissecting multiple diameter messages */
1164 available_bytes = tvb_length_remaining(tvb, offset);
1165 if (available_bytes < 4) {
1166 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1168 return; /* Bail. We can't even get our length */
1171 /* get our packet length */
1172 plen = tvb_get_ntohl(tvb, offset);
1173 plen &= 0x00ffffff; /* get rid of the flags */
1176 if (gbl_diameter_desegment) {
1177 if (pinfo->can_desegment
1178 && plen > available_bytes) {
1179 pinfo->desegment_offset = offset;
1180 pinfo->desegment_len = plen - available_bytes;
1181 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1182 /* plen, available_bytes); */
1187 /* Otherwise, dissect our packet */
1188 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1190 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1191 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1192 /* offset=noffset; */
1193 } while (offset < tvb_reported_length(tvb));
1195 } /* dissect_diameter_tcp */
1198 * Call the mip_dissector, after saving our pinfo variables
1199 * so it doesn't write to our column display.
1202 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1203 size_t offset, size_t length)
1205 static dissector_handle_t mip_handle;
1206 static int mipInitialized=FALSE;
1208 address save_dl_src;
1209 address save_dl_dst;
1210 address save_net_src;
1211 address save_net_dst;
1214 gboolean save_in_error_pkt;
1216 if (!mipInitialized) {
1217 mip_handle = find_dissector("mip");
1218 mipInitialized=TRUE;
1221 mip_tvb = tvb_new_subset(tvb, offset,
1222 MIN(length, tvb_length(tvb)-offset),
1225 /* The contained packet is a MIP registration request;
1226 dissect it with the MIP dissector. */
1227 col_set_writable(pinfo->fd, FALSE);
1229 /* Also, save the current values of the addresses, and restore
1230 them when we're finished dissecting the contained packet, so
1231 that the address columns in the summary don't reflect the
1232 contained packet, but reflect this packet instead. */
1233 save_dl_src = pinfo->dl_src;
1234 save_dl_dst = pinfo->dl_dst;
1235 save_net_src = pinfo->net_src;
1236 save_net_dst = pinfo->net_dst;
1237 save_src = pinfo->src;
1238 save_dst = pinfo->dst;
1239 save_in_error_pkt = pinfo->in_error_pkt;
1241 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1243 /* Restore the "we're inside an error packet" flag. */
1244 pinfo->in_error_pkt = save_in_error_pkt;
1245 pinfo->dl_src = save_dl_src;
1246 pinfo->dl_dst = save_dl_dst;
1247 pinfo->net_src = save_net_src;
1248 pinfo->net_dst = save_net_dst;
1249 pinfo->src = save_src;
1250 pinfo->dst = save_dst;
1253 } /* safe_dissect_mip */
1256 * This function will dissect the AVPs in a diameter packet. It handles
1257 * all normal types, and even recursively calls itself for grouped AVPs
1259 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1261 /* adds the attribute value pairs to the tree */
1263 gchar avpTypeString[64];
1264 gchar avpNameString[64];
1267 gchar vendorString[64];
1270 proto_tree *avpi_tree;
1272 char dataBuffer[4096];
1273 tvbuff_t *group_tvb;
1275 proto_tree *group_tree;
1276 proto_item *grouptf;
1279 int BadPacket = FALSE;
1283 proto_tree *flags_tree;
1285 gint32 packetLength;
1286 size_t avpDataLength;
1288 gchar flagstr[64] = "<None>";
1289 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1293 packetLength = tvb_length(tvb);
1295 /* Check for invalid packet lengths */
1296 if (packetLength <= 0) {
1297 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1298 "No Attribute Value Pairs Found");
1302 /* Spin around until we run out of packet */
1303 while (packetLength > 0 ) {
1305 /* Check for short packet */
1306 if (packetLength < (long)MIN_AVP_SIZE) {
1307 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%d bytes))",
1308 packetLength, MIN_AVP_SIZE);
1310 /* Don't even bother trying to parse a short packet. */
1314 /* Copy our header */
1315 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1317 /* Fix the byte ordering */
1318 avph.avp_code = ntohl(avph.avp_code);
1319 avph.avp_flagsLength = ntohl(avph.avp_flagsLength);
1321 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1322 avpLength = avph.avp_flagsLength & 0x00ffffff;
1324 /* Set up our flags string */
1325 if (check_col(pinfo->fd, COL_INFO) || avp_tree) {
1327 for (i = 0; i < 8; i++) {
1331 strcat(flagstr, ", ");
1333 strcat(flagstr, fstr[i]);
1336 if (strlen(flagstr) == 0) {
1337 strcpy(flagstr,"<None>");
1341 /* Dissect our vendor id if it exists and set hdr length */
1342 if (flags & AVP_FLAGS_V) {
1343 vendorId = ntohl(avph.avp_vendorId);
1345 hdrLength = sizeof(e_avphdr);
1348 hdrLength = sizeof(e_avphdr) -
1354 strcpy(vendorString,
1355 diameter_vendor_to_str(vendorId));
1357 vendorString[0]='\0';
1360 /* Check for bad length */
1361 if (avpLength < MIN_AVP_SIZE ||
1362 ((long)avpLength > packetLength)) {
1363 g_warning("Diameter: AVP payload size invalid: avp_length: %d bytes, "
1364 "min: %d bytes, packetLen: %d",
1365 avpLength, MIN_AVP_SIZE, packetLength);
1369 /* Check for bad flags */
1370 if (flags & AVP_FLAGS_RESERVED) {
1371 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1373 flags, AVP_FLAGS_RESERVED);
1374 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1375 // BadPacket = TRUE;
1379 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1382 fixAmt = 4 - (avpLength % 4);
1383 if (fixAmt == 4) fixAmt = 0;
1385 /* shrink our packetLength */
1386 packetLength = packetLength - (avpLength + fixAmt);
1388 /* Check for out of bounds */
1389 if (packetLength < 0) {
1390 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1395 /* Make avp Name & type */
1396 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code), TypeValues,
1397 "Unknown-Type: 0x%08x"));
1398 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code));
1400 avptf = proto_tree_add_text(avp_tree, tvb,
1401 offset, avpLength + fixAmt,
1402 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1403 avpNameString, avpTypeString, avpLength,
1404 avpLength, avpLength+fixAmt);
1405 avpi_tree = proto_item_add_subtree(avptf,
1406 ett_diameter_avpinfo);
1408 if (avpi_tree !=NULL) {
1410 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1411 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1414 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1415 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1417 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1418 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1419 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1420 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1421 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1422 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1423 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1424 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1425 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1428 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1429 tvb, offset, 3, avpLength);
1432 if (flags & AVP_FLAGS_V) {
1433 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1434 tvb, offset, 4, vendorId, vendorString);
1438 avpDataLength = avpLength - hdrLength;
1441 * If we've got a bad packet, just highlight the data. Don't try
1442 * to parse it, and, don't move to next AVP.
1445 offset -= hdrLength;
1446 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1447 tvb, offset, tvb_length(tvb) - offset, dataBuffer,
1448 "Bad AVP (Suspect Data Not Dissected)");
1452 avpType=diameter_avp_get_type(avph.avp_code);
1453 tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095,avpDataLength));
1457 case DIAMETER_GROUPED:
1458 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1459 /* Recursively call ourselves */
1460 grouptf = proto_tree_add_text(avpi_tree,
1461 tvb, offset, tvb_length(tvb),
1464 group_tree = proto_item_add_subtree(grouptf,
1467 group_tvb = tvb_new_subset(tvb, offset,
1468 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1469 if (group_tree != NULL) {
1470 dissect_avps( group_tvb, pinfo, group_tree);
1474 case DIAMETER_IDENTITY:
1475 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1476 tvb, offset, avpDataLength, dataBuffer,
1477 "Identity: %*.*s", (int)avpDataLength, (int)avpDataLength,
1480 case DIAMETER_UTF8STRING:
1481 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1482 tvb, offset, avpDataLength, dataBuffer,
1483 "UTF8String: %*.*s", (int)avpDataLength, (int)avpDataLength,
1486 case DIAMETER_IP_ADDRESS:
1487 if (avpDataLength == 4) {
1488 guint32 ipv4Address = ntohl((*(guint32*)dataBuffer));
1489 proto_tree_add_ipv4_format(avpi_tree, hf_diameter_avp_data_v4addr,
1490 tvb, offset, avpDataLength, ipv4Address,
1491 "IPv4 Address: %u.%u.%u.%u",
1492 (ipv4Address&0xff000000)>>24,
1493 (ipv4Address&0xff0000)>>16,
1494 (ipv4Address&0xff00)>>8,
1495 (ipv4Address&0xff));
1496 } else if (avpDataLength == 16) {
1497 proto_tree_add_ipv6_format(avpi_tree, hf_diameter_avp_data_v6addr,
1498 tvb, offset, avpDataLength, dataBuffer,
1499 "IPv6 Address: %04x:%04x:%04x:%04x",
1500 *((guint32*)dataBuffer),
1501 *((guint32*)&dataBuffer[4]),
1502 *((guint32*)&dataBuffer[8]),
1503 *((guint32*)&dataBuffer[12]));
1505 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1506 tvb, offset, avpDataLength, dataBuffer,
1507 "Error! Bad Address Length");
1511 case DIAMETER_INTEGER32:
1514 memcpy(&data, dataBuffer, 4);
1516 proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32,
1517 tvb, offset, avpDataLength, data,
1518 "Value: %d", data );
1522 case DIAMETER_UNSIGNED32:
1526 memcpy(&data, dataBuffer, 4);
1528 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1529 tvb, offset, avpDataLength, data,
1530 "Value: 0x%08x (%u)", data,
1535 case DIAMETER_INTEGER64:
1536 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64, tvb, offset, 8, FALSE);
1539 case DIAMETER_UNSIGNED64:
1540 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64, tvb, offset, 8, FALSE);
1544 valstr=diameter_time_to_string(dataBuffer);
1546 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1547 tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr);
1550 case DIAMETER_ENUMERATED:
1554 memcpy(&data, dataBuffer, 4);
1556 valstr = diameter_avp_get_value(avph.avp_code, data);
1557 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1558 tvb, offset, avpDataLength, data,
1559 "Value: 0x%08x (%u): %s", data, data, valstr);
1562 case DIAMETER_VENDOR_ID:
1566 memcpy(&data, dataBuffer, 4);
1568 valstr = diameter_vendor_to_str(data);
1569 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1570 tvb, offset, avpDataLength, data,
1571 "%s (0x%08x)", valstr, data);
1574 case DIAMETER_APPLICATION_ID:
1578 memcpy(&data, dataBuffer, 4);
1580 valstr = diameter_app_to_str(data);
1581 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1582 tvb, offset, avpDataLength, data,
1583 "%s (0x%08x)", valstr, data);
1586 case DIAMETER_MIP_REG_REQ:
1588 /* Make a new tvb */
1589 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1593 case DIAMETER_OCTET_STRING:
1594 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1595 tvb, offset, avpDataLength, dataBuffer,
1596 "Hex Data Highlighted Below");
1600 } /* avpi_tree != null */
1601 offset += (avpLength - hdrLength);
1602 offset += fixAmt; /* fix byte alignment */
1604 } /* dissect_avps */
1609 proto_reg_handoff_diameter(void)
1611 static int Initialized=FALSE;
1612 static int TcpPort=0;
1613 static int SctpPort=0;
1616 dissector_delete("tcp.port", TcpPort, dissect_diameter_tcp);
1617 dissector_delete("sctp.port", SctpPort, dissect_diameter_sctp);
1622 /* set port for future deletes */
1623 TcpPort=gbl_diameterTcpPort;
1624 SctpPort=gbl_diameterSctpPort;
1626 strcpy(gbl_diameterString, "Diameter Protocol");
1628 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1629 gbl_diameterTcpPort); */
1630 dissector_add("tcp.port", gbl_diameterTcpPort, dissect_diameter_tcp,
1632 dissector_add("sctp.port", gbl_diameterSctpPort,
1633 dissect_diameter_sctp, proto_diameter);
1636 /* registration with the filtering engine */
1638 proto_register_diameter(void)
1640 static hf_register_info hf[] = {
1641 { &hf_diameter_version,
1642 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1644 { &hf_diameter_length,
1645 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1648 { &hf_diameter_flags,
1649 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1651 { &hf_diameter_flags_request,
1652 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1654 { &hf_diameter_flags_proxyable,
1655 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1657 { &hf_diameter_flags_error,
1658 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1660 { &hf_diameter_flags_reserved3,
1661 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1662 DIAM_FLAGS_RESERVED3, "", HFILL }},
1663 { &hf_diameter_flags_reserved4,
1664 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1665 DIAM_FLAGS_RESERVED4, "", HFILL }},
1666 { &hf_diameter_flags_reserved5,
1667 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1668 DIAM_FLAGS_RESERVED5, "", HFILL }},
1669 { &hf_diameter_flags_reserved6,
1670 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1671 DIAM_FLAGS_RESERVED6, "", HFILL }},
1672 { &hf_diameter_flags_reserved7,
1673 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1674 DIAM_FLAGS_RESERVED7, "", HFILL }},
1676 { &hf_diameter_code,
1677 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1678 NULL, 0x0, "", HFILL }},
1679 { &hf_diameter_vendor_id,
1680 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1682 { &hf_diameter_hopbyhopid,
1683 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1684 BASE_HEX, NULL, 0x0, "", HFILL }},
1685 { &hf_diameter_endtoendid,
1686 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1687 BASE_HEX, NULL, 0x0, "", HFILL }},
1689 { &hf_diameter_avp_code,
1690 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1691 NULL, 0x0, "", HFILL }},
1692 { &hf_diameter_avp_length,
1693 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1694 NULL, 0x0, "", HFILL }},
1697 { &hf_diameter_avp_flags,
1698 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1699 NULL, 0x0, "", HFILL }},
1700 { &hf_diameter_avp_flags_vendor_specific,
1701 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1703 { &hf_diameter_avp_flags_mandatory,
1704 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1706 { &hf_diameter_avp_flags_protected,
1707 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1709 { &hf_diameter_avp_flags_reserved3,
1710 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1711 AVP_FLAGS_RESERVED3, "", HFILL }},
1712 { &hf_diameter_avp_flags_reserved4,
1713 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1714 AVP_FLAGS_RESERVED4, "", HFILL }},
1715 { &hf_diameter_avp_flags_reserved5,
1716 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1717 AVP_FLAGS_RESERVED5, "", HFILL }},
1718 { &hf_diameter_avp_flags_reserved6,
1719 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1720 AVP_FLAGS_RESERVED6, "", HFILL }},
1721 { &hf_diameter_avp_flags_reserved7,
1722 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1723 AVP_FLAGS_RESERVED7, "", HFILL }},
1724 { &hf_diameter_avp_vendor_id,
1725 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1726 NULL, 0x0, "", HFILL }},
1727 { &hf_diameter_avp_data_uint64,
1728 { "AVP Data","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1729 NULL, 0x0, "", HFILL }},
1730 { &hf_diameter_avp_data_int64,
1731 { "AVP Data","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1732 NULL, 0x0, "", HFILL }},
1733 { &hf_diameter_avp_data_uint32,
1734 { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1735 NULL, 0x0, "", HFILL }},
1736 { &hf_diameter_avp_data_int32,
1737 { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1738 NULL, 0x0, "", HFILL }},
1739 { &hf_diameter_avp_data_bytes,
1740 { "AVP Data","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1741 NULL, 0x0, "", HFILL }},
1743 { &hf_diameter_avp_data_string,
1744 { "AVP Data","diameter.avp.data.string", FT_STRING, BASE_NONE,
1745 NULL, 0x0, "", HFILL }},
1746 { &hf_diameter_avp_data_v4addr,
1747 { "AVP Data","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1748 NULL, 0x0, "", HFILL }},
1749 { &hf_diameter_avp_data_v6addr,
1750 { "AVP Data","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1751 NULL, 0x0, "", HFILL }},
1752 { &hf_diameter_avp_data_time,
1753 { "AVP Data","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1754 NULL, 0x0, "", HFILL }},
1757 static gint *ett[] = {
1759 &ett_diameter_flags,
1761 &ett_diameter_avp_flags,
1762 &ett_diameter_avpinfo
1764 module_t *diameter_module;
1766 proto_diameter = proto_register_protocol (gbl_diameterString,
1767 "Diameter", "diameter");
1768 proto_register_field_array(proto_diameter, hf, array_length(hf));
1769 proto_register_subtree_array(ett, array_length(ett));
1771 /* Register a configuration option for port */
1772 diameter_module = prefs_register_protocol(proto_diameter,
1773 proto_reg_handoff_diameter);
1774 prefs_register_uint_preference(diameter_module, "tcp.port",
1775 "Diameter TCP Port",
1776 "Set the TCP port for Diameter messages",
1778 &gbl_diameterTcpPort);
1779 prefs_register_uint_preference(diameter_module, "sctp.port",
1780 "Diameter SCTP Port",
1781 "Set the SCTP port for Diameter messages",
1783 &gbl_diameterSctpPort);
1785 * Build our default dictionary filename
1787 if (! gbl_diameterDictionary) {
1788 gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
1789 1 + strlen(DICT_FN) + 1); /* slash + fn + null */
1790 sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
1791 get_datafile_dir(), DICT_FN );
1793 /* Now register its preferences so it can be changed. */
1794 prefs_register_string_preference(diameter_module, "dictionary.name",
1795 "Diameter XML Dictionary",
1796 "Set the dictionary used for Diameter messages",
1797 &gbl_diameterDictionary);
1799 /* Desegmentation */
1800 prefs_register_bool_preference(diameter_module, "diameter.desegment",
1801 "Desegment all Diameter messages spanning multiple TCP segments",
1802 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1803 &gbl_diameter_desegment);
1805 /* Register some preferences we no longer support, so we can report
1806 them as obsolete rather than just illegal. */
1807 prefs_register_obsolete_preference(diameter_module, "udp.port");
1808 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1809 } /* proto_register_diameter */