aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-diameter.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-diameter.c')
-rw-r--r--epan/dissectors/packet-diameter.c1965
1 files changed, 1965 insertions, 0 deletions
diff --git a/epan/dissectors/packet-diameter.c b/epan/dissectors/packet-diameter.c
new file mode 100644
index 0000000000..acb9466014
--- /dev/null
+++ b/epan/dissectors/packet-diameter.c
@@ -0,0 +1,1965 @@
+/* packet-diameter.c
+ * Routines for Diameter packet disassembly
+ *
+ * $Id$
+ *
+ * Copyright (c) 2001 by David Frascone <dave@frascone.com>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * References:
+ * 2004-03-11
+ * http://www.ietf.org/rfc/rfc3588.txt
+ * http://www.iana.org/assignments/radius-types
+ * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-cc-03.txt
+ * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-nasreq-14.txt
+ * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-mobileip-16.txt
+ * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-sip-app-01.txt
+ * http://www.ietf.org/html.charters/aaa-charter.html
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <glib.h>
+#include <epan/filesystem.h>
+#include "xmlstub.h"
+#include <epan/packet.h>
+#include <epan/resolv.h>
+#include <epan/report_err.h>
+#include "prefs.h"
+#include "packet-tcp.h"
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+/* This must be defined before we include packet-diameter-defs.h */
+
+/* Valid data types */
+typedef enum {
+ /* Base Types */
+ DIAMETER_OCTET_STRING = 1,
+ DIAMETER_INTEGER32,
+ DIAMETER_INTEGER64,
+ DIAMETER_UNSIGNED32,
+ DIAMETER_UNSIGNED64,
+ DIAMETER_FLOAT32,
+ DIAMETER_FLOAT64,
+ DIAMETER_FLOAT128,
+ DIAMETER_GROUPED,
+
+ /* Derived Types */
+ DIAMETER_IP_ADDRESS, /* OctetString */
+ DIAMETER_TIME, /* Integer 32 */
+ DIAMETER_UTF8STRING, /* OctetString */
+ DIAMETER_IDENTITY, /* OctetString */
+ DIAMETER_ENUMERATED, /* Integer 32 */
+ DIAMETER_IP_FILTER_RULE, /* OctetString */
+ DIAMETER_QOS_FILTER_RULE, /* OctetString */
+ DIAMETER_MIP_REG_REQ, /* OctetString */
+ DIAMETER_VENDOR_ID, /* Integer32 */
+ DIAMETER_APPLICATION_ID,
+ DIAMETER_URI, /* OctetString */
+ DIAMETER_SESSION_ID /* OctetString */
+
+} diameterDataType;
+
+
+static value_string TypeValues[]={
+ { DIAMETER_OCTET_STRING, "OctetString" },
+ { DIAMETER_INTEGER32, "Integer32" },
+ { DIAMETER_INTEGER64, "Integer64" },
+ { DIAMETER_UNSIGNED32, "Unsigned32" },
+ { DIAMETER_UNSIGNED64, "Unsigned64" },
+ { DIAMETER_FLOAT32, "Float32" },
+ { DIAMETER_FLOAT64, "Float64" },
+ { DIAMETER_FLOAT128, "Float128" },
+ { DIAMETER_GROUPED, "Grouped" },
+ { DIAMETER_IP_ADDRESS, "IpAddress" },
+ { DIAMETER_TIME, "Time" },
+ { DIAMETER_UTF8STRING, "UTF8String" },
+ { DIAMETER_IDENTITY, "DiameterIdentity" },
+ { DIAMETER_ENUMERATED, "Enumerated" },
+ { DIAMETER_IP_FILTER_RULE, "IPFilterRule" },
+ { DIAMETER_QOS_FILTER_RULE, "QOSFilterRule" },
+ { DIAMETER_MIP_REG_REQ, "MIPRegistrationRequest"},
+ { DIAMETER_VENDOR_ID, "VendorId"},
+ { DIAMETER_APPLICATION_ID, "AppId"},
+ { DIAMETER_URI, "DiameterURI"},
+ { DIAMETER_SESSION_ID, "Session-Id"},
+
+ {0, (char *)NULL}
+};
+
+typedef struct value_name {
+ guint32 value;
+ gchar *name;
+ struct value_name *next;
+} ValueName;
+
+typedef struct old_avp_info {
+ guint32 code;
+ gchar *name;
+ diameterDataType type;
+ value_string *values;
+} oldAvpInfo;
+
+typedef struct avp_info {
+ guint32 code;
+ gchar *name;
+ gchar *vendorName;
+ diameterDataType type;
+ ValueName *values;
+ struct avp_info *next;
+} avpInfo;
+
+typedef struct command_code {
+ guint32 code;
+ gchar *name;
+ gchar *vendorName;
+ struct command_code *next;
+} CommandCode;
+
+typedef struct vendor_id {
+ guint32 id;
+ gchar *name;
+ gchar *longName;
+ struct vendor_id *next;
+} VendorId;
+
+typedef struct application_id {
+ guint32 id;
+ gchar *name;
+ struct application_id *next;
+} ApplicationId;
+
+static avpInfo *avpListHead=NULL;
+static VendorId *vendorListHead=NULL;
+static CommandCode *commandListHead=NULL;
+static ApplicationId *ApplicationIdHead=NULL;
+
+
+#include "packet-diameter-defs.h"
+
+#define NTP_TIME_DIFF (2208988800UL)
+
+#define TCP_PORT_DIAMETER 1812
+#define SCTP_PORT_DIAMETER 1812
+
+static const true_false_string reserved_set = {
+ "*** Error! Reserved Bit is Set",
+ "Ok"
+};
+
+static int proto_diameter = -1;
+static int hf_diameter_length = -1;
+static int hf_diameter_code = -1;
+static int hf_diameter_hopbyhopid =-1;
+static int hf_diameter_endtoendid =-1;
+static int hf_diameter_version = -1;
+static int hf_diameter_vendor_id = -1;
+static int hf_diameter_flags = -1;
+static int hf_diameter_flags_request = -1;
+static int hf_diameter_flags_proxyable = -1;
+static int hf_diameter_flags_error = -1;
+static int hf_diameter_flags_T = -1;
+static int hf_diameter_flags_reserved4 = -1;
+static int hf_diameter_flags_reserved5 = -1;
+static int hf_diameter_flags_reserved6 = -1;
+static int hf_diameter_flags_reserved7 = -1;
+
+static int hf_diameter_avp_code = -1;
+static int hf_diameter_avp_length = -1;
+static int hf_diameter_avp_flags = -1;
+static int hf_diameter_avp_flags_vendor_specific = -1;
+static int hf_diameter_avp_flags_mandatory = -1;
+static int hf_diameter_avp_flags_protected = -1;
+static int hf_diameter_avp_flags_reserved3 = -1;
+static int hf_diameter_avp_flags_reserved4 = -1;
+static int hf_diameter_avp_flags_reserved5 = -1;
+static int hf_diameter_avp_flags_reserved6 = -1;
+static int hf_diameter_avp_flags_reserved7 = -1;
+static int hf_diameter_avp_vendor_id = -1;
+
+
+static int hf_diameter_avp_data_uint32 = -1;
+static int hf_diameter_avp_data_int32 = -1;
+static int hf_diameter_avp_data_uint64 = -1;
+static int hf_diameter_avp_data_int64 = -1;
+static int hf_diameter_avp_data_bytes = -1;
+static int hf_diameter_avp_data_string = -1;
+static int hf_diameter_avp_data_v4addr = -1;
+static int hf_diameter_avp_data_v6addr = -1;
+static int hf_diameter_avp_data_time = -1;
+static int hf_diameter_avp_session_id = -1;
+static gint ett_diameter = -1;
+static gint ett_diameter_flags = -1;
+static gint ett_diameter_avp = -1;
+static gint ett_diameter_avp_flags = -1;
+static gint ett_diameter_avpinfo = -1;
+
+static guint gbl_diameterTcpPort=TCP_PORT_DIAMETER;
+static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
+
+/* desegmentation of Diameter over TCP */
+static gboolean gbl_diameter_desegment = TRUE;
+
+/* Allow zero as a valid application ID */
+static gboolean allow_zero_as_app_id = FALSE;
+
+/* Supress console output at unknown AVP:s,Flags etc */
+static gboolean suppress_console_output = TRUE;
+
+#define DICT_FN "diameter/dictionary.xml"
+static gchar *gbl_diameterDictionary;
+
+typedef struct _e_diameterhdr {
+ guint32 versionLength;
+ guint32 flagsCmdCode;
+ guint32 vendorId;
+ guint32 hopByHopId;
+ guint32 endToEndId;
+} e_diameterhdr;
+
+typedef struct _e_avphdr {
+ guint32 avp_code;
+ guint32 avp_flagsLength;
+ guint32 avp_vendorId; /* optional */
+} e_avphdr;
+
+/* Diameter Header Flags */
+/* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
+#define DIAM_FLAGS_R 0x80
+#define DIAM_FLAGS_P 0x40
+#define DIAM_FLAGS_E 0x20
+#define DIAM_FLAGS_T 0x10
+#define DIAM_FLAGS_RESERVED4 0x08
+#define DIAM_FLAGS_RESERVED5 0x04
+#define DIAM_FLAGS_RESERVED6 0x02
+#define DIAM_FLAGS_RESERVED7 0x01
+#define DIAM_FLAGS_RESERVED 0x0f
+
+#define DIAM_LENGTH_MASK 0x00ffffffl
+#define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
+#define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
+#define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
+#define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
+#define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
+
+/* Diameter AVP Flags */
+#define AVP_FLAGS_P 0x20
+#define AVP_FLAGS_V 0x80
+#define AVP_FLAGS_M 0x40
+#define AVP_FLAGS_RESERVED3 0x10
+#define AVP_FLAGS_RESERVED4 0x08
+#define AVP_FLAGS_RESERVED5 0x04
+#define AVP_FLAGS_RESERVED6 0x02
+#define AVP_FLAGS_RESERVED7 0x01
+#define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
+
+#define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
+#define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
+
+static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+
+/*
+ * This routine will do a push-parse of the passed in
+ * filename. This was taken almost verbatum from
+ * the xmlsoft examples.
+ */
+static xmlDocPtr
+xmlParseFilePush( char *filename, int checkValid) {
+ FILE *f;
+ xmlDocPtr doc=NULL;
+ int valid=0;
+ int res, size = 1024;
+ char chars[1024];
+ xmlParserCtxtPtr ctxt;
+
+ /* I wonder what kind of a performance hit this is? */
+ *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ report_open_failure(filename, errno, FALSE);
+ return NULL;
+ }
+
+ res = fread(chars, 1, 4, f);
+ if (res > 0) {
+ ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL,
+ chars, res, filename);
+ while ((res = fread(chars, 1, size-1, f)) > 0) {
+ XmlStub.xmlParseChunk(ctxt, chars, res, 0);
+ }
+ XmlStub.xmlParseChunk(ctxt, chars, 0, 1);
+ doc = ctxt->myDoc;
+ valid=ctxt->valid;
+ XmlStub.xmlFreeParserCtxt(ctxt);
+ }
+ fclose(f);
+
+ /* Check valid */
+ if (!valid) {
+ report_failure( "Error! Invalid xml in %s! Failed DTD check!",
+ filename);
+ return NULL;
+ }
+ return doc;
+} /* xmlParseFilePush */
+
+/*
+ * This routine will add a static avp to the avp list. It is
+ * only called when the XML dictionary fails to load properly.
+ */
+static int
+addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
+{
+ avpInfo *entry;
+ ValueName *vEntry=NULL;
+ int i;
+
+ /* Parse our values array, if we have one */
+ if (values) {
+ for (i=0; values[i].strptr != NULL; i++) {
+ ValueName *ve = NULL;
+
+ ve = g_malloc(sizeof(ValueName));
+ ve->name = strdup(values[i].strptr);
+ ve->value = values[i].value;
+ ve->next = vEntry;
+ vEntry = ve;
+ }
+ } /* if values */
+
+ /* And, create the entry */
+ entry = (avpInfo *)g_malloc(sizeof(avpInfo));
+ entry->name = g_strdup(name);
+ entry->code = code;
+ entry->vendorName = NULL;
+ entry->type = type;
+ entry->values = vEntry;
+ if (vEntry)
+ entry->type = DIAMETER_ENUMERATED;
+
+ /* And, add it to the list */
+ entry->next = avpListHead;
+ avpListHead = entry;
+
+ return (0);
+
+} /* addStaticAVP */
+
+/*
+ * This routine will parse an XML avp entry, and add it to our
+ * avp list. If any values are present in the avp, it will
+ * add them too.
+ */
+static int
+xmlParseAVP(xmlNodePtr cur)
+{
+ char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
+ *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
+ *constrained=NULL;
+ char *type=NULL;
+ avpInfo *entry;
+ guint32 avpType=0;
+ ValueName *vEntry=NULL;
+ int i;
+
+ /* First, get our properties */
+ name = XmlStub.xmlGetProp(cur, "name");
+ description = XmlStub.xmlGetProp(cur, "description");
+ code = XmlStub.xmlGetProp(cur, "code");
+ mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt");
+ mandatory = XmlStub.xmlGetProp(cur, "mandatory");
+ protected = XmlStub.xmlGetProp(cur, "protected");
+ vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit");
+ vendorName = XmlStub.xmlGetProp(cur, "vendor-id");
+ constrained = XmlStub.xmlGetProp(cur, "constrained");
+
+ cur = cur->xmlChildrenNode;
+
+ while (cur != NULL ) {
+ if (strcasecmp(cur->name, "type") == 0) {
+ type = XmlStub.xmlGetProp(cur, "type-name");
+ } else if (strcasecmp(cur->name, "enum") == 0) {
+ char *valueName=NULL, *valueCode=NULL;
+ ValueName *ve = NULL;
+ valueName = XmlStub.xmlGetProp(cur, "name");
+ valueCode = XmlStub.xmlGetProp(cur, "code");
+
+ if (!valueName || !valueCode) {
+ report_failure( "Error, bad value on avp %s", name);
+ return (-1);
+ }
+
+ ve = g_malloc(sizeof(ValueName));
+ ve->name = strdup(valueName);
+ ve->value = atol(valueCode);
+
+ ve->next = vEntry;
+ vEntry = ve;
+ } else if (strcasecmp(cur->name, "grouped") == 0) {
+ /* WORK Recurse here for grouped AVPs */
+ type = "grouped";
+ }
+ cur=cur->next;
+ } /* while */
+
+ /*
+ * Check for the AVP Type.
+ */
+ if (type) {
+ for (i = 0; TypeValues[i].strptr; i++) {
+ if (!strcasecmp(type, TypeValues[i].strptr)) {
+ avpType = TypeValues[i].value;
+ break;
+ }
+ }
+
+ if (TypeValues[i].strptr == NULL) {
+ report_failure( "Invalid Type field in dictionary! avp %s (%s)", name, type);
+ return (-1);
+ }
+ } else if (!vEntry) {
+ report_failure("Missing type/enum field in dictionary avpName=%s",
+ name);
+ return (-1);
+ }
+
+ /* WORK - Handle flags -- for validation later */
+
+
+ /* And, create the entry */
+ entry = (avpInfo *)g_malloc(sizeof(avpInfo));
+ entry->name = g_strdup(name);
+ entry->code = atol(code);
+ if (vendorName)
+ entry->vendorName = g_strdup(vendorName);
+ else
+ entry->vendorName = NULL;
+ entry->type = avpType;
+ entry->values = vEntry;
+ if (vEntry)
+ entry->type = DIAMETER_INTEGER32;
+
+ /* And, add it to the list */
+ entry->next = avpListHead;
+ avpListHead = entry;
+
+ return (0);
+} /* xmlParseAVP */
+
+/*
+ * This routine will add a command to the list of commands.
+ */
+static int
+addCommand(int code, char *name, char *vendorId)
+{
+ CommandCode *entry;
+
+ /*
+ * Allocate the memory required for the dictionary.
+ */
+ entry = (CommandCode *) g_malloc(sizeof (CommandCode));
+
+ if (entry == NULL) {
+ report_failure("Unable to allocate memory");
+ return (-1);
+ }
+
+ /*
+ * Allocate memory for the AVPName and copy the name to the
+ * structure
+ */
+ entry->name = g_strdup(name);
+ entry->code = code;
+ if (vendorId)
+ entry->vendorName = g_strdup(vendorId);
+ else
+ entry->vendorName = "None";
+
+ /* Add the entry to the list */
+ entry->next = commandListHead;
+ commandListHead = entry;
+
+ return 0;
+} /* addCommand */
+
+/*
+ * This routine will parse the XML command, and add it to our
+ * list of commands.
+ */
+static int
+xmlParseCommand(xmlNodePtr cur)
+{
+ char *name, *code, *vendorIdString;
+
+ /*
+ * Get the Attributes
+ */
+ name = XmlStub.xmlGetProp(cur, "name");
+ code = XmlStub.xmlGetProp(cur, "code");
+ if (!name || !code) {
+ report_failure("Invalid command. Name or code missing!");
+ return -1;
+ }
+ vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id");
+
+ if (!vendorIdString || !strcasecmp(vendorIdString, "None")) {
+ vendorIdString = NULL;
+ }
+
+ return (addCommand(atoi(code), name, vendorIdString));
+} /* xmlParseCommand */
+
+/* This routine adds an application to the name<-> id table */
+static int
+dictionaryAddApplication(char *name, int id)
+{
+ ApplicationId *entry;
+
+ if (!name || (id < 0) || (id == 0 && !allow_zero_as_app_id)) {
+ report_failure( "Diameter Error: Invalid application (name=%p, id=%d)",
+ name, id);
+ return (-1);
+ } /* Sanity Checks */
+
+ entry = g_malloc(sizeof(ApplicationId));
+ if (!entry) {
+ report_failure( "Unable to allocate memory");
+ return (-1);
+ }
+
+ entry->name = g_strdup(name);
+ entry->id = id;
+
+ /* Add it to the list */
+ entry->next = ApplicationIdHead;
+ ApplicationIdHead = entry;
+
+ return 0;
+} /* dictionaryAddApplication */
+
+/*
+ * This routine will add a vendor to the vendors list
+ */
+static int
+addVendor(int id, gchar *name, gchar *longName)
+{
+ VendorId *vendor;
+
+ /* add entry */
+ vendor=g_malloc(sizeof(VendorId));
+ if (!vendor) {
+ return (-1);
+ }
+
+ vendor->id = id;
+ vendor->name = g_strdup(name);
+ vendor->longName = g_strdup(longName);
+ vendor->next = vendorListHead;
+ vendorListHead = vendor;
+
+ return 0;
+} /* addVendor */
+
+/*
+ * This routine will pars in a XML vendor entry.
+ */
+static int
+xmlParseVendor(xmlNodePtr cur)
+{
+ char *name=NULL, *code=NULL, *id=NULL;
+
+ /* First, get our properties */
+ id = XmlStub.xmlGetProp(cur, "vendor-id");
+ name = XmlStub.xmlGetProp(cur, "name");
+ code = XmlStub.xmlGetProp(cur, "code");
+
+ if (!id || !name || !code) {
+ report_failure( "Invalid vendor section. vendor-id, name, and code must be specified");
+ return -1;
+ }
+
+ return (addVendor(atoi(code), id, name));
+} /* addVendor */
+
+/*
+ * This routine will either parse in the base protocol, or an application.
+ */
+static int
+xmlDictionaryParseSegment(xmlNodePtr cur, int base)
+{
+ if (!base) {
+ char *name;
+ char *id;
+
+ /* Add our application */
+ id = XmlStub.xmlGetProp(cur, "id");
+ name = XmlStub.xmlGetProp(cur, "name");
+
+ if (!name || !id) {
+ /* ERROR!!! */
+ report_failure("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
+ name?name:"NULL", id?id:"NULL");
+ return -1;
+ }
+
+ /* Add the application */
+ if (dictionaryAddApplication(name, atol(id)) != 0) {
+ /* ERROR! */
+ return -1;
+ }
+ }
+
+
+ /*
+ * Get segment values
+ */
+ cur = cur->xmlChildrenNode;
+ while (cur != NULL) {
+ if (strcasecmp(cur->name, "avp") == 0) {
+ /* we have an avp!!! */
+ xmlParseAVP(cur);
+ } else if (strcasecmp(cur->name, "vendor") == 0) {
+ /* we have a vendor */
+ xmlParseVendor(cur);
+ /* For now, ignore typedefn and text */
+ } else if (strcasecmp(cur->name, "command") == 0) {
+ /* Found a command */
+ xmlParseCommand(cur);
+ } else if (strcasecmp(cur->name, "text") == 0) {
+ } else if (strcasecmp(cur->name, "comment") == 0) {
+ } else if (strcasecmp(cur->name, "typedefn") == 0) {
+ /* WORK -- parse in valid types . . . */
+ } else {
+ /* IF we got here, we're an error */
+ report_failure("Error! expecting an avp or a typedefn (got \"%s\")",
+ cur->name);
+ return (-1);
+ }
+ cur = cur->next;
+ } /* while */
+ return 0;
+} /* xmlDictionaryParseSegment */
+
+/*
+ * The main xml parse routine. This will walk through an XML
+ * dictionary that has been parsed by libxml.
+ */
+static int
+xmlDictionaryParse(xmlNodePtr cur)
+{
+ /* We should expect a base protocol, followed by multiple applications */
+ while (cur != NULL) {
+ if (strcasecmp(cur->name, "base") == 0) {
+ /* Base protocol. Descend and parse */
+ xmlDictionaryParseSegment(cur, 1);
+ } else if (strcasecmp(cur->name, "application") == 0) {
+ /* Application. Descend and parse */
+ xmlDictionaryParseSegment(cur, 0);
+ } else if (strcasecmp(cur->name, "text") == 0) {
+ /* Ignore text */
+ } else if (strcasecmp(cur->name, "comment") == 0) {
+ /* Ignore text */
+ } else {
+ report_failure( "Diameter: XML Expecting a base or an application (got \"%s\")",
+ cur->name);
+ return (-1);
+ }
+ cur = cur->next;
+ }
+
+ return 0;
+
+} /* xmlDictionaryParse */
+
+/*
+ * This routine will call libxml to parse in the dictionary.
+ */
+static int
+loadXMLDictionary(void)
+{
+ xmlDocPtr doc;
+ xmlNodePtr cur;
+
+ /*
+ * build an XML tree from a the file;
+ */
+ XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */
+ XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */
+ doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/
+
+ /* Check for invalid xml */
+ if (doc == NULL) {
+ report_failure("Diameter: Unable to parse xmldictionary %s",
+ gbl_diameterDictionary);
+ return -1;
+ }
+
+ /*
+ * Check the document is of the right kind
+ */
+ cur = XmlStub.xmlDocGetRootElement(doc);
+ if (cur == NULL) {
+ report_failure("Diameter: Error: \"%s\": empty document",
+ gbl_diameterDictionary);
+ XmlStub.xmlFreeDoc(doc);
+ return -1;
+ }
+ if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
+ report_failure("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
+ gbl_diameterDictionary);
+ XmlStub.xmlFreeDoc(doc);
+ return -1;
+ }
+
+ /*
+ * Ok, the dictionary has been parsed by libxml, and is valid.
+ * All we have to do now is read in our information.
+ */
+ if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
+ /* Error has already been printed */
+ return -1;
+ }
+
+ /* Once we're done parsing, free up the xml memory */
+ XmlStub.xmlFreeDoc(doc);
+
+ return 0;
+
+} /* loadXMLDictionary */
+
+/*
+ * Fallback routine. In the event of ANY error when loading the XML
+ * dictionary, this routine will populate the new avp list structures
+ * with the old static data from packet-diameter-defs.h
+ */
+static void
+initializeDictionaryDefaults(void)
+{
+ int i;
+
+ /* Add static vendors to list */
+ for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
+ addVendor(diameter_vendor_specific_vendors[i].value,
+ diameter_vendor_specific_vendors[i].strptr,
+ diameter_vendor_specific_vendors[i].strptr);
+ }
+ /* Add static commands to list. */
+ for(i=0; diameter_command_code_vals[i].strptr; i++) {
+ addCommand(diameter_command_code_vals[i].value,
+ diameter_command_code_vals[i].strptr, NULL);
+ }
+
+ /* Add static AVPs to list */
+ for (i=0; old_diameter_avps[i].name; i++) {
+ addStaticAVP(old_diameter_avps[i].code,
+ old_diameter_avps[i].name,
+ old_diameter_avps[i].type,
+ old_diameter_avps[i].values);
+ }
+
+} /* initializeDictionaryDefaults */
+
+/*
+ * This routine will attempt to load the XML dictionary, and on
+ * failure, will call initializeDictionaryDefaults to load in
+ * our static dictionary.
+ */
+static void
+initializeDictionary(void)
+{
+ /*
+ * Using ugly ordering here. If loadLibXML succeeds, then
+ * loadXMLDictionary will be called. This is one of the few times when
+ * I think this is prettier than the nested if alternative.
+ */
+ if (loadLibXML() ||
+ (loadXMLDictionary() != 0)) {
+ /* Something failed. Use the static dictionary */
+ report_failure("Diameter: Using static dictionary! (Unable to use XML)");
+ initializeDictionaryDefaults();
+ }
+} /* initializeDictionary */
+
+
+
+/*
+ * These routines manipulate the diameter structures.
+ */
+
+/* return vendor string, based on the id */
+static gchar *
+diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
+ VendorId *probe;
+ static gchar buffer[64];
+
+ for (probe=vendorListHead; probe; probe=probe->next) {
+ if (vendorId == probe->id) {
+ if (longName)
+ return probe->longName;
+ else
+ return probe->name;
+ }
+ }
+
+ snprintf(buffer, sizeof(buffer),
+ "Vendor 0x%08x", vendorId);
+ return buffer;
+} /*diameter_vendor_to_str */
+
+/* return command string, based on the code */
+static gchar *
+diameter_command_to_str(guint32 commandCode, guint32 vendorId)
+{
+ CommandCode *probe;
+ static gchar buffer[64];
+ gchar *vendorName=NULL;
+
+ if (vendorId)
+ vendorName = diameter_vendor_to_str(vendorId, FALSE);
+
+ for (probe=commandListHead; probe; probe=probe->next) {
+ if (commandCode == probe->code) {
+ if (vendorId) {
+/* g_warning("Command: Comparing \"%s\" to \"%s\"", */
+/* vendorName?vendorName:"(null)", */
+/* probe->vendorName?probe->vendorName:"(null)"); */
+ /* Now check the vendor name */
+ if (!strcmp(vendorName, probe->vendorName))
+ /* We found it */
+ return probe->name;
+ } else {
+ /* With no vendor id, the Command's entry should be "None" */
+ if (!strcmp(probe->vendorName, "None")) {
+ /* We found it */
+ return probe->name;
+ }
+ }
+ }
+ }
+
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
+ commandCode, vendorId);
+ snprintf(buffer, sizeof(buffer),
+ "Cmd-0x%08x", commandCode);
+
+ return buffer;
+}/*diameter_command_to_str */
+
+/* return application string, based on the id */
+static gchar *
+diameter_app_to_str(guint32 vendorId) {
+ ApplicationId *probe;
+ static gchar buffer[64];
+
+ for (probe=ApplicationIdHead; probe; probe=probe->next) {
+ if (vendorId == probe->id) {
+ return probe->name;
+ }
+ }
+
+ snprintf(buffer, sizeof(buffer),
+ "AppId 0x%08x", vendorId);
+ return buffer;
+} /*diameter_app_to_str */
+
+/* return an avp type, based on the code */
+static diameterDataType
+diameter_avp_get_type(guint32 avpCode, guint32 vendorId){
+ avpInfo *probe;
+ gchar *vendorName=NULL;
+
+ if (vendorId)
+ vendorName = diameter_vendor_to_str(vendorId, FALSE);
+
+ for (probe=avpListHead; probe; probe=probe->next) {
+ if (avpCode == probe->code) {
+
+ if (vendorId) {
+/* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */
+/* vendorName?vendorName:"(null)", */
+/* probe->vendorName?probe->vendorName:"(null)"); */
+ /* Now check the vendor name */
+ if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
+ /* We found it! */
+ return probe->type;
+ } else {
+ /* No Vendor ID -- vendorName should be null */
+ if (!probe->vendorName)
+ /* We found it! */
+ return probe->type;
+ }
+ }
+ }
+
+ /* If we don't find it, assume it's data */
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode,
+ vendorId);
+ return DIAMETER_OCTET_STRING;
+} /* diameter_avp_get_type */
+
+/* return an avp name from the code */
+static gchar *
+diameter_avp_get_name(guint32 avpCode, guint32 vendorId)
+{
+ static gchar buffer[64];
+ avpInfo *probe;
+ gchar *vendorName=NULL;
+
+ if (vendorId)
+ vendorName = diameter_vendor_to_str(vendorId, FALSE);
+
+ for (probe=avpListHead; probe; probe=probe->next) {
+ if (avpCode == probe->code) {
+ if (vendorId) {
+/* g_warning("AvpName: Comparing \"%s\" to \"%s\"", */
+/* vendorName?vendorName:"(null)", */
+/* probe->vendorName?probe->vendorName:"(null)"); */
+ /* Now check the vendor name */
+ if (probe->vendorName && (!strcmp(vendorName, probe->vendorName)))
+ /* We found it! */
+ return probe->name;
+ } else {
+ /* No Vendor ID -- vendorName should be null */
+ if (!probe->vendorName)
+ /* We found it! */
+ return probe->name;
+ }
+ }
+ }
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
+ avpCode, vendorId);
+
+ /* If we don't find it, build a name string */
+ sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
+ return buffer;
+} /* diameter_avp_get_name */
+static gchar *
+diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
+{
+ avpInfo *probe;
+ gchar *vendorName=NULL;
+
+ if (vendorId)
+ vendorName = diameter_vendor_to_str(vendorId, FALSE);
+
+ for (probe=avpListHead; probe; probe=probe->next) {
+ if (avpCode == probe->code) {
+ if (vendorId) {
+/* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */
+/* vendorName?vendorName:"(null)", */
+/* probe->vendorName?probe->vendorName:"(null)"); */
+ /* Now check the vendor name */
+ if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) {
+ ValueName *vprobe;
+ for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
+ if (avpValue == vprobe->value) {
+ return vprobe->name;
+ }
+ }
+ return "(Unknown value)";
+ }
+ } else {
+ if (!probe->vendorName) {
+ ValueName *vprobe;
+ for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
+ if (avpValue == vprobe->value) {
+ return vprobe->name;
+ }
+ }
+ return "(Unknown value)";
+ }
+ }
+ }
+ }
+ /* We didn't find the avp */
+ return "(Unknown AVP)";
+} /* diameter_avp_get_value */
+
+
+/* Code to actually dissect the packets */
+
+static gboolean
+check_diameter(tvbuff_t *tvb)
+{
+ if (!tvb_bytes_exist(tvb, 0, 1))
+ return FALSE; /* not enough bytes to check the version */
+ if (tvb_get_guint8(tvb, 0) != 1)
+ return FALSE; /* not version 1 */
+
+ /* XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE?
+ Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits
+ are set? */
+ return TRUE;
+}
+
+/*
+ * Main dissector
+ */
+static void
+dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_item *tf;
+ proto_tree *flags_tree;
+ tvbuff_t *avp_tvb;
+ proto_tree *diameter_tree;
+ e_diameterhdr dh;
+ int offset=0;
+ size_t avplength;
+ proto_tree *avp_tree;
+ proto_item *avptf;
+ int BadPacket = FALSE;
+ guint32 commandCode, pktLength;
+ guint8 version, flags;
+ gchar flagstr[64] = "<None>";
+ gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
+ gchar commandString[64], vendorName[64];
+ gint i;
+ guint bpos;
+ static int initialized=FALSE;
+
+ /*
+ * Only parse in dictionary if there are diameter packets to
+ * dissect.
+ */
+ if (!initialized) {
+ /* Read in our dictionary, if it exists. */
+ initializeDictionary();
+ initialized=TRUE;
+ }
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ /* Copy our header */
+ tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
+
+ /* Fix byte ordering in our static structure */
+ dh.versionLength = g_ntohl(dh.versionLength);
+ dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode);
+ dh.vendorId = g_ntohl(dh.vendorId);
+ dh.hopByHopId = g_ntohl(dh.hopByHopId);
+ dh.endToEndId = g_ntohl(dh.endToEndId);
+
+ if (dh.vendorId) {
+ strcpy(vendorName,
+ diameter_vendor_to_str(dh.vendorId, TRUE));
+ } else {
+ strcpy(vendorName, "None");
+ }
+
+
+ /* Do the bit twiddling */
+ version = DIAM_GET_VERSION(dh);
+ pktLength = DIAM_GET_LENGTH(dh);
+ flags = DIAM_GET_FLAGS(dh);
+ commandCode = DIAM_GET_COMMAND(dh);
+
+ /* Set up our flags */
+ if (check_col(pinfo->cinfo, COL_INFO) || tree) {
+ flagstr[0]=0;
+ for (i = 0; i < 8; i++) {
+ bpos = 1 << i;
+ if (flags & bpos) {
+ if (flagstr[0]) {
+ strcat(flagstr, ", ");
+ }
+ strcat(flagstr, fstr[i]);
+ }
+ }
+ if (strlen(flagstr) == 0) {
+ strcpy(flagstr,"<None>");
+ }
+ }
+
+ /* Set up our commandString */
+ strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
+ if (flags & DIAM_FLAGS_R)
+ strcat(commandString, "-Request");
+ else
+ strcat(commandString, "-Answer");
+
+ /* Short packet. Should have at LEAST one avp */
+ if (pktLength < MIN_DIAMETER_SIZE) {
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
+ pktLength, (unsigned long)MIN_DIAMETER_SIZE);
+ BadPacket = TRUE;
+ }
+
+ /* And, check our reserved flags/version */
+ if ((flags & DIAM_FLAGS_RESERVED) ||
+ (version != 1)) {
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
+ flags, version);
+ BadPacket = TRUE;
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "%s%s%s%s%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d",
+ (BadPacket)?"***** Bad Packet!: ":"",
+ (flags & DIAM_FLAGS_P)?"Proxyable ":"",
+ (flags & DIAM_FLAGS_E)?" Error":"",
+ ((BadPacket ||
+ (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ?
+ ": " : ""),
+ commandString, vendorName,
+ dh.hopByHopId, dh.endToEndId,
+ (flags & DIAM_FLAGS_R)?1:0,
+ (flags & DIAM_FLAGS_P)?1:0,
+ (flags & DIAM_FLAGS_E)?1:0);
+ }
+
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ necessary to generate protocol tree items. */
+ if (tree) {
+
+ /* create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_diameter, tvb, offset,
+ MAX(pktLength,MIN_DIAMETER_SIZE), FALSE);
+ diameter_tree = proto_item_add_subtree(ti, ett_diameter);
+
+ /* Version */
+ proto_tree_add_uint(diameter_tree,
+ hf_diameter_version,
+ tvb, offset, 1,
+ version);
+
+ offset+=1;
+
+ /* Length */
+ proto_tree_add_uint(diameter_tree,
+ hf_diameter_length, tvb,
+ offset, 3, pktLength);
+ offset += 3;
+
+ /* Flags */
+ tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
+ offset , 1, flags, "Flags: 0x%02x (%s)", flags,
+ flagstr);
+ flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_T, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
+
+ offset += 1;
+
+ /* Command Code */
+ proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
+ tvb, offset, 3, commandCode, "Command Code: %s", commandString);
+ offset += 3;
+
+ /* Vendor Id */
+ proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
+ tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorName);
+ offset += 4;
+
+ /* Hop-by-hop Identifier */
+ proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
+ tvb, offset, 4, dh.hopByHopId);
+ offset += 4;
+
+ /* End-to-end Identifier */
+ proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
+ tvb, offset, 4, dh.endToEndId);
+ offset += 4;
+
+ /* If we have a bad packet, don't bother trying to parse the AVPs */
+ if (BadPacket) {
+ return;
+ }
+
+ /* Start looking at the AVPS */
+ /* Make the next tvbuff */
+
+ /* Update the lengths */
+ avplength= pktLength - sizeof(e_diameterhdr);
+
+ avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength);
+ avptf = proto_tree_add_text(diameter_tree,
+ tvb, offset, avplength,
+ "Attribute Value Pairs");
+
+ avp_tree = proto_item_add_subtree(avptf,
+ ett_diameter_avp);
+ if (avp_tree != NULL) {
+ dissect_avps( avp_tvb, pinfo, avp_tree);
+ }
+ return;
+ }
+} /* dissect_diameter_common */
+
+
+static guint
+get_diameter_pdu_len(tvbuff_t *tvb, int offset)
+{
+ /* Get the length of the Diameter packet. */
+ return tvb_get_ntoh24(tvb, offset + 1);
+}
+
+static int
+dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ if (!check_diameter(tvb))
+ return 0;
+ dissect_diameter_common(tvb, pinfo, tree);
+ return tvb_length(tvb);
+}
+
+static int
+dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ if (!check_diameter(tvb))
+ return 0;
+ tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
+ get_diameter_pdu_len, dissect_diameter_common);
+ return tvb_length(tvb);
+} /* dissect_diameter_tcp */
+
+/*
+ * Call the mip_dissector, after saving our pinfo variables
+ * so it doesn't write to our column display.
+ */
+static void
+safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ size_t offset, size_t length)
+{
+ static dissector_handle_t mip_handle;
+ static int mipInitialized=FALSE;
+ tvbuff_t *mip_tvb;
+ address save_dl_src;
+ address save_dl_dst;
+ address save_net_src;
+ address save_net_dst;
+ address save_src;
+ address save_dst;
+ gboolean save_in_error_pkt;
+
+ if (!mipInitialized) {
+ mip_handle = find_dissector("mip");
+ mipInitialized=TRUE;
+ }
+
+ mip_tvb = tvb_new_subset(tvb, offset,
+ MIN(length, tvb_length(tvb)-offset),
+ length);
+
+ /* The contained packet is a MIP registration request;
+ dissect it with the MIP dissector. */
+ col_set_writable(pinfo->cinfo, FALSE);
+
+ /* Also, save the current values of the addresses, and restore
+ them when we're finished dissecting the contained packet, so
+ that the address columns in the summary don't reflect the
+ contained packet, but reflect this packet instead. */
+ save_dl_src = pinfo->dl_src;
+ save_dl_dst = pinfo->dl_dst;
+ save_net_src = pinfo->net_src;
+ save_net_dst = pinfo->net_dst;
+ save_src = pinfo->src;
+ save_dst = pinfo->dst;
+ save_in_error_pkt = pinfo->in_error_pkt;
+
+ call_dissector(mip_handle, mip_tvb, pinfo, tree);
+
+ /* Restore the "we're inside an error packet" flag. */
+ pinfo->in_error_pkt = save_in_error_pkt;
+ pinfo->dl_src = save_dl_src;
+ pinfo->dl_dst = save_dl_dst;
+ pinfo->net_src = save_net_src;
+ pinfo->net_dst = save_net_dst;
+ pinfo->src = save_src;
+ pinfo->dst = save_dst;
+
+
+} /* safe_dissect_mip */
+
+/*
+ * This function will dissect the AVPs in a diameter packet. It handles
+ * all normal types, and even recursively calls itself for grouped AVPs
+ */
+static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
+{
+ /* adds the attribute value pairs to the tree */
+ e_avphdr avph;
+ gchar avpTypeString[64];
+ gchar avpNameString[64];
+ gchar *valstr;
+ guint32 vendorId=0;
+ gchar vendorName[64];
+ int hdrLength;
+ int fixAmt;
+ proto_tree *avpi_tree;
+ size_t offset = 0;
+ tvbuff_t *group_tvb;
+ proto_tree *group_tree;
+ proto_item *grouptf;
+ proto_item *avptf;
+ char buffer[1024];
+ int BadPacket = FALSE;
+ guint32 avpLength;
+ guint8 flags;
+ proto_item *tf;
+ proto_tree *flags_tree;
+
+ gint32 packetLength;
+ size_t avpDataLength;
+ int avpType;
+ gchar flagstr[64] = "<None>";
+ gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
+ gint i;
+ guint bpos;
+
+ packetLength = tvb_length(tvb);
+
+ /* Check for invalid packet lengths */
+ if (packetLength <= 0) {
+ proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
+ "No Attribute Value Pairs Found");
+ return;
+ }
+
+ /* Spin around until we run out of packet */
+ while (packetLength > 0 ) {
+
+ /* Check for short packet */
+ if (packetLength < (long)MIN_AVP_SIZE) {
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
+ packetLength, (long)MIN_AVP_SIZE);
+ BadPacket = TRUE;
+ /* Don't even bother trying to parse a short packet. */
+ return;
+ }
+
+ /* Copy our header */
+ tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
+
+ /* Fix the byte ordering */
+ avph.avp_code = g_ntohl(avph.avp_code);
+ avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
+
+ flags = (avph.avp_flagsLength & 0xff000000) >> 24;
+ avpLength = avph.avp_flagsLength & 0x00ffffff;
+
+ /* Set up our flags string */
+ if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
+ flagstr[0]=0;
+ for (i = 0; i < 8; i++) {
+ bpos = 1 << i;
+ if (flags & bpos) {
+ if (flagstr[0]) {
+ strcat(flagstr, ", ");
+ }
+ strcat(flagstr, fstr[i]);
+ }
+ }
+ if (strlen(flagstr) == 0) {
+ strcpy(flagstr,"<None>");
+ }
+ }
+
+ /* Dissect our vendor id if it exists and set hdr length */
+ if (flags & AVP_FLAGS_V) {
+ vendorId = g_ntohl(avph.avp_vendorId);
+ /* Vendor id */
+ hdrLength = sizeof(e_avphdr);
+ } else {
+ /* No vendor */
+ hdrLength = sizeof(e_avphdr) -
+ sizeof(guint32);
+ vendorId = 0;
+ }
+
+ if (vendorId) {
+ strcpy(vendorName,
+ diameter_vendor_to_str(vendorId, TRUE));
+ } else {
+ vendorName[0]='\0';
+ }
+
+ /* Check for bad length */
+ if (avpLength < MIN_AVP_SIZE ||
+ ((long)avpLength > packetLength)) {
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
+ "min: %ld bytes, packetLen: %d",
+ (long)avpLength, (long)MIN_AVP_SIZE,
+ packetLength);
+ BadPacket = TRUE;
+ }
+
+ /* Check for bad flags */
+ if (flags & AVP_FLAGS_RESERVED) {
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
+ " resFl=0x%x",
+ flags, AVP_FLAGS_RESERVED);
+ /* For now, don't set bad packet, since I'm accidentally setting a wrong bit
+ BadPacket = TRUE;
+ */
+ }
+
+ /*
+ * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
+ * boundries)
+ */
+ fixAmt = 4 - (avpLength % 4);
+ if (fixAmt == 4) fixAmt = 0;
+
+ /* shrink our packetLength */
+ packetLength = packetLength - (avpLength + fixAmt);
+
+ /* Check for out of bounds */
+ if (packetLength < 0) {
+ if ( suppress_console_output == FALSE )
+ g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
+ packetLength);
+ BadPacket = TRUE;
+ }
+
+ /* Make avp Name & type */
+ strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
+ TypeValues,
+ "Unknown-Type: 0x%08x"));
+ strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
+
+ avptf = proto_tree_add_text(avp_tree, tvb,
+ offset, avpLength + fixAmt,
+ "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
+ avpNameString, avpTypeString, avpLength,
+ avpLength, avpLength+fixAmt);
+ avpi_tree = proto_item_add_subtree(avptf,
+ ett_diameter_avpinfo);
+
+ if (avpi_tree !=NULL) {
+ /* Command Code */
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
+ tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
+ offset += 4;
+
+ tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
+ offset , 1, flags, "Flags: 0x%02x (%s)", flags,
+ flagstr);
+ flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
+ offset += 1;
+
+ proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
+ tvb, offset, 3, avpLength);
+ offset += 3;
+
+ if (flags & AVP_FLAGS_V) {
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
+ tvb, offset, 4, vendorId, vendorName);
+ offset += 4;
+ }
+
+ avpDataLength = avpLength - hdrLength;
+
+ /*
+ * If we've got a bad packet, just highlight the data. Don't try
+ * to parse it, and, don't move to next AVP.
+ */
+ if (BadPacket) {
+ offset -= hdrLength;
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, tvb_length(tvb) - offset,
+ tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
+ "Bad AVP (Suspect Data Not Dissected)");
+ return;
+ }
+
+ avpType=diameter_avp_get_type(avph.avp_code,vendorId);
+
+ switch(avpType) {
+ case DIAMETER_GROUPED:
+ sprintf(buffer, "%s Grouped AVPs", avpNameString);
+ /* Recursively call ourselves */
+ grouptf = proto_tree_add_text(avpi_tree,
+ tvb, offset, tvb_length(tvb),
+ buffer);
+
+ group_tree = proto_item_add_subtree(grouptf,
+ ett_diameter_avp);
+
+ group_tvb = tvb_new_subset(tvb, offset,
+ MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
+ if (group_tree != NULL) {
+ dissect_avps( group_tvb, pinfo, group_tree);
+ }
+ break;
+
+ case DIAMETER_IDENTITY:
+ {
+ const guint8 *data;
+
+ data = tvb_get_ptr(tvb, offset, avpDataLength);
+ proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
+ tvb, offset, avpDataLength, data,
+ "Identity: %*.*s",
+ (int)avpDataLength,
+ (int)avpDataLength, data);
+ }
+ break;
+ case DIAMETER_UTF8STRING:
+ {
+ const guint8 *data;
+
+ data = tvb_get_ptr(tvb, offset, avpDataLength);
+ proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
+ tvb, offset, avpDataLength, data,
+ "UTF8String: %*.*s",
+ (int)avpDataLength,
+ (int)avpDataLength, data);
+ }
+ break;
+ case DIAMETER_IP_ADDRESS:
+ if (avpDataLength == 4) {
+ proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
+ tvb, offset, avpDataLength, FALSE);
+ } else if (avpDataLength == 16) {
+ proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr,
+ tvb, offset, avpDataLength, FALSE);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Address Length");
+ }
+ break;
+
+ case DIAMETER_INTEGER32:
+ if (avpDataLength == 4) {
+ proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
+ tvb, offset, avpDataLength, FALSE);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Integer32 Length");
+ }
+ break;
+
+ case DIAMETER_UNSIGNED32:
+ if (avpDataLength == 4) {
+ guint32 data;
+
+ data = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
+ tvb, offset, avpDataLength, data,
+ "Value: 0x%08x (%u)", data, data);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Unsigned32 Length");
+ }
+ break;
+
+ case DIAMETER_INTEGER64:
+ if (avpDataLength == 8) {
+ proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
+ tvb, offset, 8, FALSE);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Integer64 Length");
+ }
+ break;
+
+ case DIAMETER_UNSIGNED64:
+ if (avpDataLength == 8) {
+ proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
+ tvb, offset, 8, FALSE);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Unsigned64 Length");
+ }
+ break;
+
+ case DIAMETER_TIME:
+ if (avpDataLength == 4) {
+ nstime_t data;
+ gchar buffer[64];
+ struct tm *ltp;
+
+ data.secs = tvb_get_ntohl(tvb, offset);
+ data.secs -= NTP_TIME_DIFF;
+ data.nsecs = 0;
+
+ ltp = localtime(&data.secs);
+ strftime(buffer, 64,
+ "%a, %d %b %Y %H:%M:%S %z", ltp);
+
+ proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time,
+ tvb, offset, avpDataLength, &data,
+ "Time: %s", buffer);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Time Length");
+ }
+ break;
+
+ case DIAMETER_ENUMERATED:
+ if (avpDataLength == 4) {
+ guint32 data;
+
+ data = tvb_get_ntohl(tvb, offset);
+ valstr = diameter_avp_get_value(avph.avp_code, vendorId, data);
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
+ tvb, offset, avpDataLength, data,
+ "Value: 0x%08x (%u): %s", data,
+ data, valstr);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Enumerated Length");
+ }
+ break;
+
+ case DIAMETER_VENDOR_ID:
+ if (avpDataLength == 4) {
+ guint32 data;
+
+ data = tvb_get_ntohl(tvb, offset);
+ valstr = diameter_vendor_to_str(data, TRUE);
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
+ tvb, offset, avpDataLength, data,
+ "Vendor ID: %s (0x%08x)", valstr,
+ data);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Vendor ID Length");
+ }
+ break;
+
+ case DIAMETER_APPLICATION_ID:
+ if (avpDataLength == 4) {
+ guint32 data;
+
+ data = tvb_get_ntohl(tvb, offset);
+ valstr = diameter_app_to_str(data);
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
+ tvb, offset, avpDataLength, data,
+ "Application ID: %s (0x%08x)",
+ valstr, data);
+ } else {
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Error! Bad Application ID Length");
+ }
+ break;
+
+ case DIAMETER_MIP_REG_REQ:
+ safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
+ break;
+
+ case DIAMETER_SESSION_ID:
+ proto_tree_add_item(avpi_tree, hf_diameter_avp_session_id,
+ tvb, offset, avpDataLength, FALSE);
+ break;
+
+ default:
+ case DIAMETER_OCTET_STRING:
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, avpDataLength,
+ tvb_get_ptr(tvb, offset, avpDataLength),
+ "Hex Data Highlighted Below");
+ break;
+
+ } /* switch type */
+ } /* avpi_tree != null */
+ offset += (avpLength - hdrLength);
+ offset += fixAmt; /* fix byte alignment */
+ } /* loop */
+} /* dissect_avps */
+
+
+
+void
+proto_reg_handoff_diameter(void)
+{
+ static int Initialized=FALSE;
+ static int TcpPort=0;
+ static int SctpPort=0;
+ static dissector_handle_t diameter_tcp_handle;
+ static dissector_handle_t diameter_handle;
+
+ if (!Initialized) {
+ diameter_tcp_handle = new_create_dissector_handle(dissect_diameter_tcp,
+ proto_diameter);
+ diameter_handle = new_create_dissector_handle(dissect_diameter,
+ proto_diameter);
+ Initialized=TRUE;
+ } else {
+ dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
+ dissector_delete("sctp.port", SctpPort, diameter_handle);
+ }
+
+ /* set port for future deletes */
+ TcpPort=gbl_diameterTcpPort;
+ SctpPort=gbl_diameterSctpPort;
+
+ /* g_warning ("Diameter: Adding tcp dissector to port %d",
+ gbl_diameterTcpPort); */
+ dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle);
+ dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
+}
+
+/* registration with the filtering engine */
+void
+proto_register_diameter(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_diameter_version,
+ { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
+ "", HFILL }},
+ { &hf_diameter_length,
+ { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_diameter_flags,
+ { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL }},
+ { &hf_diameter_flags_request,
+ { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
+ "", HFILL }},
+ { &hf_diameter_flags_proxyable,
+ { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
+ "", HFILL }},
+ { &hf_diameter_flags_error,
+ { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
+ "", HFILL }},
+ { &hf_diameter_flags_T,
+ { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&flags_set_truth),DIAM_FLAGS_T,
+ "", HFILL }},
+ { &hf_diameter_flags_reserved4,
+ { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
+ DIAM_FLAGS_RESERVED4, "", HFILL }},
+ { &hf_diameter_flags_reserved5,
+ { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
+ DIAM_FLAGS_RESERVED5, "", HFILL }},
+ { &hf_diameter_flags_reserved6,
+ { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
+ DIAM_FLAGS_RESERVED6, "", HFILL }},
+ { &hf_diameter_flags_reserved7,
+ { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
+ DIAM_FLAGS_RESERVED7, "", HFILL }},
+
+ { &hf_diameter_code,
+ { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_vendor_id,
+ { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
+ 0x0,"", HFILL }},
+ { &hf_diameter_hopbyhopid,
+ { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
+ BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_diameter_endtoendid,
+ { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
+ BASE_HEX, NULL, 0x0, "", HFILL }},
+
+ { &hf_diameter_avp_code,
+ { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_length,
+ { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+
+
+ { &hf_diameter_avp_flags,
+ { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_flags_vendor_specific,
+ { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
+ "", HFILL }},
+ { &hf_diameter_avp_flags_mandatory,
+ { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
+ "", HFILL }},
+ { &hf_diameter_avp_flags_protected,
+ { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
+ "", HFILL }},
+ { &hf_diameter_avp_flags_reserved3,
+ { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
+ AVP_FLAGS_RESERVED3, "", HFILL }},
+ { &hf_diameter_avp_flags_reserved4,
+ { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
+ AVP_FLAGS_RESERVED4, "", HFILL }},
+ { &hf_diameter_avp_flags_reserved5,
+ { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
+ AVP_FLAGS_RESERVED5, "", HFILL }},
+ { &hf_diameter_avp_flags_reserved6,
+ { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
+ AVP_FLAGS_RESERVED6, "", HFILL }},
+ { &hf_diameter_avp_flags_reserved7,
+ { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
+ AVP_FLAGS_RESERVED7, "", HFILL }},
+ { &hf_diameter_avp_vendor_id,
+ { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_uint64,
+ { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_int64,
+ { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_uint32,
+ { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_int32,
+ { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_bytes,
+ { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_string,
+ { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_v4addr,
+ { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_v6addr,
+ { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_data_time,
+ { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
+ NULL, 0x0, "", HFILL }},
+ { &hf_diameter_avp_session_id,
+ { "Session ID","diameter.avp.session_id", FT_STRING, BASE_NONE,
+ NULL, 0x0, "", HFILL }},
+
+ };
+ static gint *ett[] = {
+ &ett_diameter,
+ &ett_diameter_flags,
+ &ett_diameter_avp,
+ &ett_diameter_avp_flags,
+ &ett_diameter_avpinfo
+ };
+ module_t *diameter_module;
+ gchar *default_diameterDictionary;
+
+ proto_diameter = proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
+ proto_register_field_array(proto_diameter, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ /* Register a configuration option for port */
+ diameter_module = prefs_register_protocol(proto_diameter,
+ proto_reg_handoff_diameter);
+ prefs_register_uint_preference(diameter_module, "tcp.port",
+ "Diameter TCP Port",
+ "Set the TCP port for Diameter messages",
+ 10,
+ &gbl_diameterTcpPort);
+ prefs_register_uint_preference(diameter_module, "sctp.port",
+ "Diameter SCTP Port",
+ "Set the SCTP port for Diameter messages",
+ 10,
+ &gbl_diameterSctpPort);
+ /*
+ * Build our default dictionary filename
+ */
+ default_diameterDictionary = get_datafile_path(DICT_FN);
+
+ /*
+ * Now register the dictionary filename as a preference,
+ * so it can be changed.
+ */
+ gbl_diameterDictionary = default_diameterDictionary;
+ prefs_register_string_preference(diameter_module, "dictionary.name",
+ "Diameter XML Dictionary",
+ "Set the dictionary used for Diameter messages",
+ &gbl_diameterDictionary);
+
+ /*
+ * We don't need the default dictionary, so free it (a copy was made
+ * of it in "gbl_diameterDictionary" by
+ * "prefs_register_string_preference()").
+ */
+ g_free(default_diameterDictionary);
+
+ /* Desegmentation */
+ prefs_register_bool_preference(diameter_module, "desegment",
+ "Desegment all Diameter messages\nspanning multiple TCP segments",
+ "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
+ &gbl_diameter_desegment);
+ /* Allow zero as valid application ID */
+ prefs_register_bool_preference(diameter_module, "allow_zero_as_app_id",
+ "Allow 0 as valid application ID",
+ "If set, the value 0 (zero) can be used as a valid "
+ "application ID. This is used in experimental cases.",
+ &allow_zero_as_app_id);
+ /* Register some preferences we no longer support, so we can report
+ them as obsolete rather than just illegal. */
+ /* Supress console output or not */
+ prefs_register_bool_preference(diameter_module, "suppress_console_output",
+ "Suppress console output for unknown AVP:s Flags etc.",
+ "If console output for errors should be suppressed or not",
+ &suppress_console_output);
+ /* Register some preferences we no longer support, so we can report
+ them as obsolete rather than just illegal. */
+ prefs_register_obsolete_preference(diameter_module, "udp.port");
+ prefs_register_obsolete_preference(diameter_module, "command_in_header");
+} /* proto_register_diameter */