2 * Routines for Diameter packet disassembly
4 * $Id: packet-diameter.c,v 1.51 2002/12/02 23:43:26 guy Exp $
6 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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(cur->name, "type") == 0) {
391 type = XmlStub.xmlGetProp(cur, "type-name");
392 } else if (strcasecmp(cur->name, "enum") == 0) {
393 char *valueName=NULL, *valueCode=NULL;
394 ValueName *ve = NULL;
395 valueName = XmlStub.xmlGetProp(cur, "name");
396 valueCode = XmlStub.xmlGetProp(cur, "code");
398 if (!valueName || !valueCode) {
399 g_warning( "Error, bad value on avp %s", name);
403 ve = g_malloc(sizeof(ValueName));
404 ve->name = strdup(valueName);
405 ve->value = atol(valueCode);
409 } else if (strcasecmp(cur->name, "grouped") == 0) {
410 /* WORK Recurse here for grouped AVPs */
417 * Check for the AVP Type.
420 for (i = 0; TypeValues[i].strptr; i++) {
421 if (!strcasecmp(type, TypeValues[i].strptr)) {
422 avpType = TypeValues[i].value;
427 if (TypeValues[i].strptr == NULL) {
428 g_warning( "Invalid Type field in dictionary! avp %s (%s)", name, type);
431 } else if (!vEntry) {
432 g_warning("Missing type/enum field in dictionary avpName=%s",
437 /* WORK - Handle flags -- for validation later */
440 /* And, create the entry */
441 entry = (avpInfo *)g_malloc(sizeof(avpInfo));
442 entry->name = g_strdup(name);
443 entry->code = atol(code);
445 entry->vendorName = g_strdup(vendorName);
447 entry->vendorName = NULL;
448 entry->type = avpType;
449 entry->values = vEntry;
451 entry->type = DIAMETER_INTEGER32;
453 /* And, add it to the list */
454 entry->next = avpListHead;
461 * This routine will add a command to the list of commands.
464 addCommand(int code, char *name, char *vendorId)
469 * Allocate the memory required for the dictionary.
471 entry = (CommandCode *) g_malloc(sizeof (CommandCode));
474 g_warning("Unable to allocate memory");
479 * Allocate memory for the AVPName and copy the name to the
482 entry->name = g_strdup(name);
485 entry->vendorName = g_strdup(vendorId);
487 entry->vendorName = "None";
489 /* Add the entry to the list */
490 entry->next = commandListHead;
491 commandListHead = entry;
497 * This routine will parse the XML command, and add it to our
501 xmlParseCommand(xmlNodePtr cur)
503 char *name, *code, *vendorIdString;
508 name = XmlStub.xmlGetProp(cur, "name");
509 code = XmlStub.xmlGetProp(cur, "code");
510 if (!name || !code) {
511 g_warning("Invalid command. Name or code missing!");
514 vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
516 if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
517 vendorIdString = NULL;
520 return (addCommand(atoi(code), name, vendorIdString));
521 } /* xmlParseCommand */
523 /* This routine adds an application to the name<-> id table */
525 dictionaryAddApplication(char *name, int id)
527 ApplicationId *entry;
529 if (!name || (id <= 0)) {
530 g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
533 } /* Sanity Checks */
535 entry = g_malloc(sizeof(ApplicationId));
537 g_warning( "Unable to allocate memory");
541 entry->name = g_strdup(name);
544 /* Add it to the list */
545 entry->next = ApplicationIdHead;
546 ApplicationIdHead = entry;
549 } /* dictionaryAddApplication */
552 * This routine will add a vendor to the vendors list
555 addVendor(int id, gchar *name, gchar *longName)
560 vendor=g_malloc(sizeof(VendorId));
566 vendor->name = g_strdup(name);
567 vendor->longName = g_strdup(longName);
568 vendor->next = vendorListHead;
569 vendorListHead = vendor;
575 * This routine will pars in a XML vendor entry.
578 xmlParseVendor(xmlNodePtr cur)
580 char *name=NULL, *code=NULL, *id=NULL;
582 /* First, get our properties */
583 id = XmlStub.xmlGetProp(cur, "vendor-id");
584 name = XmlStub.xmlGetProp(cur, "name");
585 code = XmlStub.xmlGetProp(cur, "code");
587 if (!id || !name || !code) {
588 g_warning( "Invalid vendor section. vendor-id, name, and code must be specified");
592 return (addVendor(atoi(code), id, name));
596 * This routine will either parse in the base protocol, or an application.
599 xmlDictionaryParseSegment(xmlNodePtr cur, int base)
605 /* Add our application */
606 id = XmlStub.xmlGetProp(cur, "id");
607 name = XmlStub.xmlGetProp(cur, "name");
611 g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
612 name?name:"NULL", id?id:"NULL");
616 /* Add the application */
617 if (dictionaryAddApplication(name, atol(id)) != 0) {
627 cur = cur->xmlChildrenNode;
628 while (cur != NULL) {
629 if (strcasecmp(cur->name, "avp") == 0) {
630 /* we have an avp!!! */
632 } else if (strcasecmp(cur->name, "vendor") == 0) {
633 /* we have a vendor */
635 /* For now, ignore typedefn and text */
636 } else if (strcasecmp(cur->name, "command") == 0) {
637 /* Found a command */
638 xmlParseCommand(cur);
639 } else if (strcasecmp(cur->name, "text") == 0) {
640 } else if (strcasecmp(cur->name, "comment") == 0) {
641 } else if (strcasecmp(cur->name, "typedefn") == 0) {
642 /* WORK -- parse in valid types . . . */
644 /* IF we got here, we're an error */
645 g_warning("Error! expecting an avp or a typedefn (got \"%s\")",
652 } /* xmlDictionaryParseSegment */
655 * The main xml parse routine. This will walk through an XML
656 * dictionary that has been parsed by libxml.
659 xmlDictionaryParse(xmlNodePtr cur)
661 /* We should expect a base protocol, followed by multiple applicaitons */
662 while (cur != NULL) {
663 if (strcasecmp(cur->name, "base") == 0) {
664 /* Base protocol. Descend and parse */
665 xmlDictionaryParseSegment(cur, 1);
666 } else if (strcasecmp(cur->name, "application") == 0) {
667 /* Application. Descend and parse */
668 xmlDictionaryParseSegment(cur, 0);
669 } else if (strcasecmp(cur->name, "text") == 0) {
672 g_warning( "Diameter: XML Expecting a base or an application (got \"%s\")",
681 } /* xmlDictionaryParse */
684 * This routine will call libxml to parse in the dictionary.
693 * build an XML tree from a the file;
695 XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
696 XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
697 doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
699 /* Check for invalid xml */
701 g_warning("Diameter: Unable to parse xmldictionary %s",
702 gbl_diameterDictionary);
707 * Check the document is of the right kind
709 cur = XmlStub.xmlDocGetRootElement(doc);
711 g_warning("Diameter: Error: \"%s\": empty document",
712 gbl_diameterDictionary);
713 XmlStub.xmlFreeDoc(doc);
716 if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
717 g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
718 gbl_diameterDictionary);
719 XmlStub.xmlFreeDoc(doc);
724 * Ok, the dictionary has been parsed by libxml, and is valid.
725 * All we have to do now is read in our information.
727 if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
728 /* Error has already been printed */
732 /* Once we're done parsing, free up the xml memory */
733 XmlStub.xmlFreeDoc(doc);
737 } /* loadXMLDictionary */
740 * Fallback routine. In the event of ANY error when loading the XML
741 * dictionary, this routine will populate the new avp list structures
742 * with the old static data from packet-diameter-defs.h
745 initializeDictionaryDefaults()
749 /* Add static vendors to list */
750 for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
751 addVendor(diameter_vendor_specific_vendors[i].value,
752 diameter_vendor_specific_vendors[i].strptr,
753 diameter_vendor_specific_vendors[i].strptr);
755 /* Add static commands to list. */
756 for(i=0; diameter_command_code_vals[i].strptr; i++) {
757 addCommand(diameter_command_code_vals[i].value,
758 diameter_command_code_vals[i].strptr, NULL);
761 /* Add static AVPs to list */
762 for (i=0; old_diameter_avps[i].name; i++) {
763 addStaticAVP(old_diameter_avps[i].code,
764 old_diameter_avps[i].name,
765 old_diameter_avps[i].type,
766 old_diameter_avps[i].values);
769 } /* initializeDictionaryDefaults */
772 * This routine will attempt to load the XML dictionary, and on
773 * failure, will call initializeDictionaryDefaults to load in
774 * our static dictionary.
777 initializeDictionary()
780 * Using ugly ordering here. If loadLibXML succeeds, then
781 * loadXMLDictionary will be called. This is one of the few times when
782 * I think this is prettier than the nested if alternative.
785 (loadXMLDictionary() != 0)) {
786 /* Something failed. Use the static dictionary */
787 g_warning("Diameter: Using static dictionary! (Unable to use XML)");
788 initializeDictionaryDefaults();
790 } /* initializeDictionary */
795 * These routines manipulate the diameter structures.
798 /* return vendor string, based on the id */
800 diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
802 static gchar buffer[64];
804 for (probe=vendorListHead; probe; probe=probe->next) {
805 if (vendorId == probe->id) {
807 return probe->longName;
813 snprintf(buffer, sizeof(buffer),
814 "Vendor 0x%08x", vendorId);
816 } /*diameter_vendor_to_str */
818 /* return command string, based on the code */
820 diameter_command_to_str(guint32 commandCode, guint32 vendorId)
823 static gchar buffer[64];
824 gchar *vendorName=NULL;
827 vendorName = diameter_vendor_to_str(vendorId, FALSE);
829 for (probe=commandListHead; probe; probe=probe->next) {
830 if (commandCode == probe->code) {
832 /* g_warning("Command: Comparing \"%s\" to \"%s\"", */
833 /* vendorName?vendorName:"(null)", */
834 /* probe->vendorName?probe->vendorName:"(null)"); */
835 /* Now check the vendor name */
836 if (!strcmp(vendorName, probe->vendorName))
840 /* With no vendor id, the Command's entry should be "None" */
841 if (!strcmp(probe->vendorName, "None")) {
849 g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
850 commandCode, vendorId);
851 snprintf(buffer, sizeof(buffer),
852 "Cmd-0x%08x", commandCode);
854 }/*diameter_command_to_str */
856 /* return application string, based on the id */
858 diameter_app_to_str(guint32 vendorId) {
859 ApplicationId *probe;
860 static gchar buffer[64];
862 for (probe=ApplicationIdHead; probe; probe=probe->next) {
863 if (vendorId == probe->id) {
868 snprintf(buffer, sizeof(buffer),
869 "AppId 0x%08x", vendorId);
871 } /*diameter_app_to_str */
873 /* return an avp type, based on the code */
874 static diameterDataType
875 diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
877 gchar *vendorName=NULL;
880 vendorName = diameter_vendor_to_str(vendorId, FALSE);
882 for (probe=avpListHead; probe; probe=probe->next) {
883 if (avpCode == probe->code) {
886 /* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
887 /* vendorName?vendorName:"(null)", */
888 /* probe->vendorName?probe->vendorName:"(null)"); */
889 /* Now check the vendor name */
890 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
894 /* No Vendor ID -- vendorName should be null */
895 if (!probe->vendorName)
902 /* If we don't find it, assume it's data */
903 g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
905 return DIAMETER_OCTET_STRING;
906 } /* diameter_avp_get_type */
908 /* return an avp name from the code */
910 diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
912 static gchar buffer[64];
914 gchar *vendorName=NULL;
917 vendorName = diameter_vendor_to_str(vendorId, FALSE);
919 for (probe=avpListHead; probe; probe=probe->next) {
920 if (avpCode == probe->code) {
922 /* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
923 /* vendorName?vendorName:"(null)", */
924 /* probe->vendorName?probe->vendorName:"(null)"); */
925 /* Now check the vendor name */
926 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
930 /* No Vendor ID -- vendorName should be null */
931 if (!probe->vendorName)
938 g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
941 /* If we don't find it, build a name string */
942 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
944 } /* diameter_avp_get_name */
946 diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
948 static gchar buffer[64];
951 gchar *vendorName=NULL;
954 vendorName = diameter_vendor_to_str(vendorId, FALSE);
956 for (probe=avpListHead; probe; probe=probe->next) {
957 if (avpCode == probe->code) {
959 /* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
960 /* vendorName?vendorName:"(null)", */
961 /* probe->vendorName?probe->vendorName:"(null)"); */
962 /* Now check the vendor name */
963 if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
965 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
966 if (avpValue == vprobe->value) {
970 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
974 if (!probe->vendorName) {
976 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
977 if (avpValue == vprobe->value) {
981 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
987 /* If we don't find the avp, build a value string */
988 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
990 } /* diameter_avp_get_value */
993 /* Code to actually dissect the packets */
998 static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
1002 /* Set up structures needed to add the protocol subtree and manage it */
1005 proto_tree *flags_tree;
1007 proto_tree *diameter_tree;
1011 proto_tree *avp_tree;
1013 int BadPacket = FALSE;
1014 guint32 commandCode, pktLength;
1015 guint8 version, flags;
1016 gchar flagstr[64] = "<None>";
1017 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
1018 gchar commandString[64], vendorName[64];
1021 static int initialized=FALSE;
1023 /* set our offset */
1027 * Only parse in dictionary if there are diameter packets to
1031 /* Read in our dictionary, if it exists. */
1032 initializeDictionary();
1036 /* Make entries in Protocol column and Info column on summary display */
1037 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1038 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
1039 if (check_col(pinfo->cinfo, COL_INFO))
1040 col_clear(pinfo->cinfo, COL_INFO);
1042 /* Copy our header */
1043 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
1045 /* Fix byte ordering in our static structure */
1046 dh.versionLength = g_ntohl(dh.versionLength);
1047 dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
1048 dh.vendorId = g_ntohl(dh.vendorId);
1049 dh.hopByHopId = g_ntohl(dh.hopByHopId);
1050 dh.endToEndId = g_ntohl(dh.endToEndId);
1054 diameter_vendor_to_str(dh.vendorId, TRUE));
1056 strcpy(vendorName, "None");
1060 /* Do the bit twiddling */
1061 version = DIAM_GET_VERSION(dh);
1062 pktLength = DIAM_GET_LENGTH(dh);
1063 flags = DIAM_GET_FLAGS(dh);
1064 commandCode = DIAM_GET_COMMAND(dh);
1066 /* Set up our flags */
1067 if (check_col(pinfo->cinfo, COL_INFO) || tree) {
1069 for (i = 0; i < 8; i++) {
1073 strcat(flagstr, ", ");
1075 strcat(flagstr, fstr[i]);
1078 if (strlen(flagstr) == 0) {
1079 strcpy(flagstr,"<None>");
1083 /* Set up our commandString */
1084 strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
1085 if (flags & DIAM_FLAGS_R)
1086 strcat(commandString, "-Request");
1088 strcat(commandString, "-Answer");
1090 /* Short packet. Should have at LEAST one avp */
1091 if (pktLength < MIN_DIAMETER_SIZE) {
1092 g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
1093 pktLength, (unsigned long)MIN_DIAMETER_SIZE);
1097 /* And, check our reserved flags/version */
1098 if ((flags & DIAM_FLAGS_RESERVED) ||
1100 g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
1105 if (check_col(pinfo->cinfo, COL_INFO)) {
1106 col_add_fstr(pinfo->cinfo, COL_INFO,
1107 "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
1108 (BadPacket)?"***** Bad Packet!: ":"",
1109 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
1110 (flags & DIAM_FLAGS_E)?" Error":"",
1112 (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
1114 commandString, vendorName,
1115 dh.hopByHopId, dh.endToEndId,
1116 (flags & DIAM_FLAGS_R)?1:0,
1117 (flags & DIAM_FLAGS_P)?1:0,
1118 (flags & DIAM_FLAGS_E)?1:0);
1122 /* In the interest of speed, if "tree" is NULL, don't do any work not
1123 necessary to generate protocol tree items. */
1126 /* create display subtree for the protocol */
1127 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
1128 MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
1129 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
1132 proto_tree_add_uint(diameter_tree,
1133 hf_diameter_version,
1140 proto_tree_add_uint(diameter_tree,
1141 hf_diameter_length, tvb,
1142 offset, 3, pktLength);
1146 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
1147 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1149 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1150 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
1151 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
1152 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
1153 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
1154 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
1155 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
1156 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
1157 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
1162 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
1163 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
1167 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
1168 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
1171 /* Hop-by-hop Identifier */
1172 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
1173 tvb, offset, 4, dh.hopByHopId);
1176 /* End-to-end Identifier */
1177 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
1178 tvb, offset, 4, dh.endToEndId);
1181 /* If we have a bad packet, don't bother trying to parse the AVPs */
1183 return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
1186 /* Start looking at the AVPS */
1187 /* Make the next tvbuff */
1189 /* Update the lengths */
1190 avplength= pktLength - sizeof(e_diameterhdr);
1192 avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
1193 avptf = proto_tree_add_text(diameter_tree,
1194 tvb, offset, avplength,
1195 "Attribute Value Pairs");
1197 avp_tree = proto_item_add_subtree(avptf,
1199 if (avp_tree != NULL) {
1200 dissect_avps( avp_tvb, pinfo, avp_tree);
1202 return MAX((offset + avplength), MIN_DIAMETER_SIZE);
1204 return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
1206 } /* dissect_diameter_common */
1209 dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1211 dissect_diameter_common(tvb, 0, pinfo, tree);
1215 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1219 guint32 available_bytes;
1220 /* guint32 noffset; */
1222 /* Loop through the packet, dissecting multiple diameter messages */
1224 available_bytes = tvb_length_remaining(tvb, offset);
1225 if (available_bytes < 4) {
1226 g_warning("Diameter: Bailing because only %d bytes of packet are available",
1228 return; /* Bail. We can't even get our length */
1231 /* get our packet length */
1232 plen = tvb_get_ntohl(tvb, offset);
1233 plen &= 0x00ffffff; /* get rid of the flags */
1236 if (gbl_diameter_desegment) {
1237 if (pinfo->can_desegment
1238 && plen > available_bytes) {
1239 pinfo->desegment_offset = offset;
1240 pinfo->desegment_len = plen - available_bytes;
1241 /* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
1242 /* plen, available_bytes); */
1247 /* Otherwise, dissect our packet */
1248 offset = dissect_diameter_common(tvb, offset, pinfo, tree);
1250 /* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
1251 /* offset, noffset, tvb_length(tvb), available_bytes, plen); */
1252 /* offset=noffset; */
1253 } while (offset < tvb_reported_length(tvb));
1255 } /* dissect_diameter_tcp */
1258 * Call the mip_dissector, after saving our pinfo variables
1259 * so it doesn't write to our column display.
1262 safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1263 size_t offset, size_t length)
1265 static dissector_handle_t mip_handle;
1266 static int mipInitialized=FALSE;
1268 address save_dl_src;
1269 address save_dl_dst;
1270 address save_net_src;
1271 address save_net_dst;
1274 gboolean save_in_error_pkt;
1276 if (!mipInitialized) {
1277 mip_handle = find_dissector("mip");
1278 mipInitialized=TRUE;
1281 mip_tvb = tvb_new_subset(tvb, offset,
1282 MIN(length, tvb_length(tvb)-offset),
1285 /* The contained packet is a MIP registration request;
1286 dissect it with the MIP dissector. */
1287 col_set_writable(pinfo->cinfo, FALSE);
1289 /* Also, save the current values of the addresses, and restore
1290 them when we're finished dissecting the contained packet, so
1291 that the address columns in the summary don't reflect the
1292 contained packet, but reflect this packet instead. */
1293 save_dl_src = pinfo->dl_src;
1294 save_dl_dst = pinfo->dl_dst;
1295 save_net_src = pinfo->net_src;
1296 save_net_dst = pinfo->net_dst;
1297 save_src = pinfo->src;
1298 save_dst = pinfo->dst;
1299 save_in_error_pkt = pinfo->in_error_pkt;
1301 call_dissector(mip_handle, mip_tvb, pinfo, tree);
1303 /* Restore the "we're inside an error packet" flag. */
1304 pinfo->in_error_pkt = save_in_error_pkt;
1305 pinfo->dl_src = save_dl_src;
1306 pinfo->dl_dst = save_dl_dst;
1307 pinfo->net_src = save_net_src;
1308 pinfo->net_dst = save_net_dst;
1309 pinfo->src = save_src;
1310 pinfo->dst = save_dst;
1313 } /* safe_dissect_mip */
1316 * This function will dissect the AVPs in a diameter packet. It handles
1317 * all normal types, and even recursively calls itself for grouped AVPs
1319 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
1321 /* adds the attribute value pairs to the tree */
1323 gchar avpTypeString[64];
1324 gchar avpNameString[64];
1327 gchar vendorName[64];
1330 proto_tree *avpi_tree;
1332 tvbuff_t *group_tvb;
1333 proto_tree *group_tree;
1334 proto_item *grouptf;
1337 int BadPacket = FALSE;
1341 proto_tree *flags_tree;
1343 gint32 packetLength;
1344 size_t avpDataLength;
1346 gchar flagstr[64] = "<None>";
1347 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
1351 packetLength = tvb_length(tvb);
1353 /* Check for invalid packet lengths */
1354 if (packetLength <= 0) {
1355 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
1356 "No Attribute Value Pairs Found");
1360 /* Spin around until we run out of packet */
1361 while (packetLength > 0 ) {
1363 /* Check for short packet */
1364 if (packetLength < (long)MIN_AVP_SIZE) {
1365 g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
1366 packetLength, (long)MIN_AVP_SIZE);
1368 /* Don't even bother trying to parse a short packet. */
1372 /* Copy our header */
1373 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
1375 /* Fix the byte ordering */
1376 avph.avp_code = g_ntohl(avph.avp_code);
1377 avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
1379 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
1380 avpLength = avph.avp_flagsLength & 0x00ffffff;
1382 /* Set up our flags string */
1383 if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
1385 for (i = 0; i < 8; i++) {
1389 strcat(flagstr, ", ");
1391 strcat(flagstr, fstr[i]);
1394 if (strlen(flagstr) == 0) {
1395 strcpy(flagstr,"<None>");
1399 /* Dissect our vendor id if it exists and set hdr length */
1400 if (flags & AVP_FLAGS_V) {
1401 vendorId = g_ntohl(avph.avp_vendorId);
1403 hdrLength = sizeof(e_avphdr);
1406 hdrLength = sizeof(e_avphdr) -
1413 diameter_vendor_to_str(vendorId, TRUE));
1418 /* Check for bad length */
1419 if (avpLength < MIN_AVP_SIZE ||
1420 ((long)avpLength > packetLength)) {
1421 g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
1422 "min: %ld bytes, packetLen: %d",
1423 (long)avpLength, (long)MIN_AVP_SIZE,
1428 /* Check for bad flags */
1429 if (flags & AVP_FLAGS_RESERVED) {
1430 g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
1432 flags, AVP_FLAGS_RESERVED);
1433 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
1434 /* BadPacket = TRUE; */
1438 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
1441 fixAmt = 4 - (avpLength % 4);
1442 if (fixAmt == 4) fixAmt = 0;
1444 /* shrink our packetLength */
1445 packetLength = packetLength - (avpLength + fixAmt);
1447 /* Check for out of bounds */
1448 if (packetLength < 0) {
1449 g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
1454 /* Make avp Name & type */
1455 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
1457 "Unknown-Type: 0x%08x"));
1458 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
1460 avptf = proto_tree_add_text(avp_tree, tvb,
1461 offset, avpLength + fixAmt,
1462 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
1463 avpNameString, avpTypeString, avpLength,
1464 avpLength, avpLength+fixAmt);
1465 avpi_tree = proto_item_add_subtree(avptf,
1466 ett_diameter_avpinfo);
1468 if (avpi_tree !=NULL) {
1470 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
1471 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
1474 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
1475 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
1477 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
1478 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
1479 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
1480 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
1481 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
1482 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
1483 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
1484 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
1485 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
1488 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
1489 tvb, offset, 3, avpLength);
1492 if (flags & AVP_FLAGS_V) {
1493 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
1494 tvb, offset, 4, vendorId, vendorName);
1498 avpDataLength = avpLength - hdrLength;
1501 * If we've got a bad packet, just highlight the data. Don't try
1502 * to parse it, and, don't move to next AVP.
1505 offset -= hdrLength;
1506 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1507 tvb, offset, tvb_length(tvb) - offset,
1508 tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
1509 "Bad AVP (Suspect Data Not Dissected)");
1513 avpType=diameter_avp_get_type(avph.avp_code,vendorId);
1516 case DIAMETER_GROUPED:
1517 sprintf(buffer, "%s Grouped AVPs", avpNameString);
1518 /* Recursively call ourselves */
1519 grouptf = proto_tree_add_text(avpi_tree,
1520 tvb, offset, tvb_length(tvb),
1523 group_tree = proto_item_add_subtree(grouptf,
1526 group_tvb = tvb_new_subset(tvb, offset,
1527 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
1528 if (group_tree != NULL) {
1529 dissect_avps( group_tvb, pinfo, group_tree);
1533 case DIAMETER_IDENTITY:
1537 data = tvb_get_ptr(tvb, offset, avpDataLength);
1538 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1539 tvb, offset, avpDataLength, data,
1542 (int)avpDataLength, data);
1545 case DIAMETER_UTF8STRING:
1549 data = tvb_get_ptr(tvb, offset, avpDataLength);
1550 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
1551 tvb, offset, avpDataLength, data,
1552 "UTF8String: %*.*s",
1554 (int)avpDataLength, data);
1557 case DIAMETER_IP_ADDRESS:
1558 if (avpDataLength == 4) {
1559 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
1560 tvb, offset, avpDataLength, FALSE);
1561 } else if (avpDataLength == 16) {
1562 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
1563 tvb, offset, avpDataLength, FALSE);
1565 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1566 tvb, offset, avpDataLength,
1567 tvb_get_ptr(tvb, offset, avpDataLength),
1568 "Error! Bad Address Length");
1572 case DIAMETER_INTEGER32:
1573 if (avpDataLength == 4) {
1574 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
1575 tvb, offset, avpDataLength, FALSE);
1577 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1578 tvb, offset, avpDataLength,
1579 tvb_get_ptr(tvb, offset, avpDataLength),
1580 "Error! Bad Integer32 Length");
1584 case DIAMETER_UNSIGNED32:
1585 if (avpDataLength == 4) {
1588 data = tvb_get_ntohl(tvb, offset);
1589 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1590 tvb, offset, avpDataLength, data,
1591 "Value: 0x%08x (%u)", data, data);
1593 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1594 tvb, offset, avpDataLength,
1595 tvb_get_ptr(tvb, offset, avpDataLength),
1596 "Error! Bad Unsigned32 Length");
1600 case DIAMETER_INTEGER64:
1601 if (avpDataLength == 8) {
1602 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
1603 tvb, offset, 8, FALSE);
1605 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1606 tvb, offset, avpDataLength,
1607 tvb_get_ptr(tvb, offset, avpDataLength),
1608 "Error! Bad Integer64 Length");
1612 case DIAMETER_UNSIGNED64:
1613 if (avpDataLength == 8) {
1614 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
1615 tvb, offset, 8, FALSE);
1617 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1618 tvb, offset, avpDataLength,
1619 tvb_get_ptr(tvb, offset, avpDataLength),
1620 "Error! Bad Unsigned64 Length");
1625 if (avpDataLength == 4) {
1630 data.secs = tvb_get_ntohl(tvb, offset);
1631 data.secs -= NTP_TIME_DIFF;
1634 ltp = localtime(&data.secs);
1635 strftime(buffer, 64,
1636 "%a, %d %b %Y %H:%M:%S %z", ltp);
1638 proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
1639 tvb, offset, avpDataLength, &data,
1640 "Time: %s", buffer);
1642 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1643 tvb, offset, avpDataLength,
1644 tvb_get_ptr(tvb, offset, avpDataLength),
1645 "Error! Bad Time Length");
1649 case DIAMETER_ENUMERATED:
1650 if (avpDataLength == 4) {
1653 data = tvb_get_ntohl(tvb, offset);
1654 valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
1655 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1656 tvb, offset, avpDataLength, data,
1657 "Value: 0x%08x (%u): %s", data,
1660 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1661 tvb, offset, avpDataLength,
1662 tvb_get_ptr(tvb, offset, avpDataLength),
1663 "Error! Bad Enumerated Length");
1666 case DIAMETER_VENDOR_ID:
1667 if (avpDataLength == 4) {
1670 data = tvb_get_ntohl(tvb, offset);
1671 valstr = diameter_vendor_to_str(data, TRUE);
1672 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1673 tvb, offset, avpDataLength, data,
1674 "Vendor ID: %s (0x%08x)", valstr,
1677 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1678 tvb, offset, avpDataLength,
1679 tvb_get_ptr(tvb, offset, avpDataLength),
1680 "Error! Bad Vendor ID Length");
1683 case DIAMETER_APPLICATION_ID:
1684 if (avpDataLength == 4) {
1687 data = tvb_get_ntohl(tvb, offset);
1688 valstr = diameter_app_to_str(data);
1689 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
1690 tvb, offset, avpDataLength, data,
1691 "Application ID: %s (0x%08x)",
1694 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1695 tvb, offset, avpDataLength,
1696 tvb_get_ptr(tvb, offset, avpDataLength),
1697 "Error! Bad Application ID Length");
1700 case DIAMETER_MIP_REG_REQ:
1701 safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
1705 case DIAMETER_OCTET_STRING:
1706 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
1707 tvb, offset, avpDataLength,
1708 tvb_get_ptr(tvb, offset, avpDataLength),
1709 "Hex Data Highlighted Below");
1713 } /* avpi_tree != null */
1714 offset += (avpLength - hdrLength);
1715 offset += fixAmt; /* fix byte alignment */
1717 } /* dissect_avps */
1722 proto_reg_handoff_diameter(void)
1724 static int Initialized=FALSE;
1725 static int TcpPort=0;
1726 static int SctpPort=0;
1727 static dissector_handle_t diameter_tcp_handle;
1728 static dissector_handle_t diameter_sctp_handle;
1731 diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
1733 diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
1737 dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
1738 dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
1741 /* set port for future deletes */
1742 TcpPort=gbl_diameterTcpPort;
1743 SctpPort=gbl_diameterSctpPort;
1745 strcpy(gbl_diameterString, "Diameter Protocol");
1747 /* g_warning ("Diameter: Adding tcp dissector to port %d",
1748 gbl_diameterTcpPort); */
1749 dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
1750 dissector_add("sctp.port", gbl_diameterSctpPort, diameter_sctp_handle);
1753 /* registration with the filtering engine */
1755 proto_register_diameter(void)
1757 static hf_register_info hf[] = {
1758 { &hf_diameter_version,
1759 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
1761 { &hf_diameter_length,
1762 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
1765 { &hf_diameter_flags,
1766 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1768 { &hf_diameter_flags_request,
1769 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
1771 { &hf_diameter_flags_proxyable,
1772 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
1774 { &hf_diameter_flags_error,
1775 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
1777 { &hf_diameter_flags_reserved3,
1778 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1779 DIAM_FLAGS_RESERVED3, "", HFILL }},
1780 { &hf_diameter_flags_reserved4,
1781 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1782 DIAM_FLAGS_RESERVED4, "", HFILL }},
1783 { &hf_diameter_flags_reserved5,
1784 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1785 DIAM_FLAGS_RESERVED5, "", HFILL }},
1786 { &hf_diameter_flags_reserved6,
1787 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1788 DIAM_FLAGS_RESERVED6, "", HFILL }},
1789 { &hf_diameter_flags_reserved7,
1790 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1791 DIAM_FLAGS_RESERVED7, "", HFILL }},
1793 { &hf_diameter_code,
1794 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
1795 NULL, 0x0, "", HFILL }},
1796 { &hf_diameter_vendor_id,
1797 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
1799 { &hf_diameter_hopbyhopid,
1800 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
1801 BASE_HEX, NULL, 0x0, "", HFILL }},
1802 { &hf_diameter_endtoendid,
1803 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
1804 BASE_HEX, NULL, 0x0, "", HFILL }},
1806 { &hf_diameter_avp_code,
1807 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
1808 NULL, 0x0, "", HFILL }},
1809 { &hf_diameter_avp_length,
1810 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
1811 NULL, 0x0, "", HFILL }},
1814 { &hf_diameter_avp_flags,
1815 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
1816 NULL, 0x0, "", HFILL }},
1817 { &hf_diameter_avp_flags_vendor_specific,
1818 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
1820 { &hf_diameter_avp_flags_mandatory,
1821 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
1823 { &hf_diameter_avp_flags_protected,
1824 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
1826 { &hf_diameter_avp_flags_reserved3,
1827 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
1828 AVP_FLAGS_RESERVED3, "", HFILL }},
1829 { &hf_diameter_avp_flags_reserved4,
1830 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
1831 AVP_FLAGS_RESERVED4, "", HFILL }},
1832 { &hf_diameter_avp_flags_reserved5,
1833 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
1834 AVP_FLAGS_RESERVED5, "", HFILL }},
1835 { &hf_diameter_avp_flags_reserved6,
1836 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
1837 AVP_FLAGS_RESERVED6, "", HFILL }},
1838 { &hf_diameter_avp_flags_reserved7,
1839 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
1840 AVP_FLAGS_RESERVED7, "", HFILL }},
1841 { &hf_diameter_avp_vendor_id,
1842 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
1843 NULL, 0x0, "", HFILL }},
1844 { &hf_diameter_avp_data_uint64,
1845 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
1846 NULL, 0x0, "", HFILL }},
1847 { &hf_diameter_avp_data_int64,
1848 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
1849 NULL, 0x0, "", HFILL }},
1850 { &hf_diameter_avp_data_uint32,
1851 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
1852 NULL, 0x0, "", HFILL }},
1853 { &hf_diameter_avp_data_int32,
1854 { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
1855 NULL, 0x0, "", HFILL }},
1856 { &hf_diameter_avp_data_bytes,
1857 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
1858 NULL, 0x0, "", HFILL }},
1859 { &hf_diameter_avp_data_string,
1860 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
1861 NULL, 0x0, "", HFILL }},
1862 { &hf_diameter_avp_data_v4addr,
1863 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
1864 NULL, 0x0, "", HFILL }},
1865 { &hf_diameter_avp_data_v6addr,
1866 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
1867 NULL, 0x0, "", HFILL }},
1868 { &hf_diameter_avp_data_time,
1869 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
1870 NULL, 0x0, "", HFILL }},
1873 static gint *ett[] = {
1875 &ett_diameter_flags,
1877 &ett_diameter_avp_flags,
1878 &ett_diameter_avpinfo
1880 module_t *diameter_module;
1882 proto_diameter = proto_register_protocol (gbl_diameterString,
1883 "Diameter", "diameter");
1884 proto_register_field_array(proto_diameter, hf, array_length(hf));
1885 proto_register_subtree_array(ett, array_length(ett));
1887 /* Register a configuration option for port */
1888 diameter_module = prefs_register_protocol(proto_diameter,
1889 proto_reg_handoff_diameter);
1890 prefs_register_uint_preference(diameter_module, "tcp.port",
1891 "Diameter TCP Port",
1892 "Set the TCP port for Diameter messages",
1894 &gbl_diameterTcpPort);
1895 prefs_register_uint_preference(diameter_module, "sctp.port",
1896 "Diameter SCTP Port",
1897 "Set the SCTP port for Diameter messages",
1899 &gbl_diameterSctpPort);
1901 * Build our default dictionary filename
1903 if (! gbl_diameterDictionary) {
1904 gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
1905 1 + strlen(DICT_FN) + 1); /* slash + fn + null */
1906 sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
1907 get_datafile_dir(), DICT_FN );
1909 /* Now register its preferences so it can be changed. */
1910 prefs_register_string_preference(diameter_module, "dictionary.name",
1911 "Diameter XML Dictionary",
1912 "Set the dictionary used for Diameter messages",
1913 &gbl_diameterDictionary);
1915 /* Desegmentation */
1916 prefs_register_bool_preference(diameter_module, "desegment",
1917 "Desegment all Diameter messages spanning multiple TCP segments",
1918 "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
1919 &gbl_diameter_desegment);
1921 /* Register some preferences we no longer support, so we can report
1922 them as obsolete rather than just illegal. */
1923 prefs_register_obsolete_preference(diameter_module, "udp.port");
1924 prefs_register_obsolete_preference(diameter_module, "command_in_header");
1925 } /* proto_register_diameter */