aboutsummaryrefslogtreecommitdiffstats
path: root/packet-diameter.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2000-07-30 07:16:11 +0000
committerGuy Harris <guy@alum.mit.edu>2000-07-30 07:16:11 +0000
commit888b5a1cdb8172c5d059c7b0aa7ff6b9f3f77088 (patch)
tree8cab84dcbd9fbc88687cacea37efb333fcbbbf6f /packet-diameter.c
parent838b254defdc57a7a57d47875196d1f6531253e9 (diff)
David Frascone's DIAMETER dissector.
svn path=/trunk/; revision=2176
Diffstat (limited to 'packet-diameter.c')
-rw-r--r--packet-diameter.c752
1 files changed, 752 insertions, 0 deletions
diff --git a/packet-diameter.c b/packet-diameter.c
new file mode 100644
index 0000000000..20cf4f07a7
--- /dev/null
+++ b/packet-diameter.c
@@ -0,0 +1,752 @@
+/* packet-diameter.c
+ * Routines for DIAMETER packet disassembly
+ *
+ * $Id: packet-diameter.c,v 1.1 2000/07/30 07:16:03 guy Exp $
+ *
+ * Copyright (c) 2000 by David Frascone <chaos@mindspring.com>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Johan Feyaerts
+ * Copyright 1999 Johan Feyaerts
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <glib.h>
+#include "packet.h"
+#include "resolv.h"
+#include "prefs.h"
+
+/* This must be defined before we include our dictionary defs */
+
+typedef struct _value_value_pair {
+ guint16 val1;
+ guint16 val2;
+} value_value_pair;
+
+typedef enum {
+ DIAMETER_DATA=1,
+ DIAMETER_STRING,
+ DIAMETER_ADDRESS,
+ DIAMETER_INTEGER32,
+ DIAMETER_INTEGER64,
+ DIAMETER_TIME,
+ DIAMETER_COMPLEX
+} diameterDataTypes;
+
+#include "packet-diameter.h"
+#include "packet-diameter-defs.h"
+
+#define COMMAND_CODE_OFFSET 20
+#define NTP_TIME_DIFF (2208988800UL)
+
+#undef SCTP_DISSECTORS_ENABLED
+
+#define UDP_PORT_DIAMETER 2645
+#define TCP_PORT_DIAMETER 2645
+#ifdef SCTP_DISSECTORS_ENABLED
+#define SCTP_PORT_DIAMETER 2645
+#endif
+/* #define UDP_PORT_DIAMETER 1812 -- Compiling this in breaks RADIUS */
+
+static int proto_diameter = -1;
+static int hf_diameter_length = -1;
+static int hf_diameter_code = -1;
+static int hf_diameter_id =-1;
+static int hf_diameter_flags = -1;
+static int hf_diameter_ns = -1;
+static int hf_diameter_nr = -1;
+
+static gint ett_diameter = -1;
+static gint ett_diameter_avp = -1;
+static gint ett_diameter_avpinfo = -1;
+
+static char gbl_diameterString[200];
+static int gbl_diameterUdpPort=UDP_PORT_DIAMETER;
+static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
+#ifdef SCTP_DISSECTORS_ENABLED
+static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
+#endif
+gboolean gbl_commandCodeInHeader = FALSE;
+
+typedef struct _e_diameterhdr {
+ guint8 code; /* Must be 254 for diameter */
+ guint8 flagsVer;
+ guint16 pktLength;
+ guint32 identifier;
+ union {
+ struct {
+ guint16 nextSend;
+ guint16 nextReceived;
+ } old;
+ struct {
+ guint32 commandCode;
+ guint32 vendorId;
+ guint16 nextSend;
+ guint16 nextReceived;
+ } new;
+ } u;
+} e_diameterhdr;
+
+typedef struct _e_avphdr {
+ guint32 avp_type;
+ guint16 avp_length;
+ guint16 avp_flags;
+ guint32 avp_vendorId; /* optional */
+ guint32 avp_tag; /* optional */
+
+} e_avphdr;
+
+#define AUTHENTICATOR_LENGTH 12
+
+#define DIAM_FLAGS_A 0x10
+#define DIAM_FLAGS_W 0x08
+#define AVP_FLAGS_P 0x0010
+#define AVP_FLAGS_T 0x0008
+#define AVP_FLAGS_V 0x0004
+#define AVP_FLAGS_R 0x0002
+#define AVP_FLAGS_M 0x0001
+
+void proto_reg_handoff_diameter(void);
+
+static guint32 match_numval(guint32 val, const value_value_pair *vs)
+{
+ guint32 i = 0;
+
+ while (vs[i].val1) {
+ if (vs[i].val1 == val)
+ return(vs[i].val2);
+ i++;
+ }
+
+ return(0);
+}
+
+static gchar *rdconvertbufftostr(gchar *dest,guint8 length,const guint8 *pd)
+{
+/*converts the raw buffer into printable text */
+guint32 i;
+guint32 totlen=0;
+
+ dest[0]='"';
+ dest[1]=0;
+ totlen=1;
+ for (i=0; i < (guint32)length; i++)
+ {
+ if( isalnum((int)pd[i])||ispunct((int)pd[i])
+ ||((int)pd[i]==' ')) {
+ dest[totlen]=(gchar)pd[i];
+ totlen++;
+ }
+ else
+ {
+ sprintf(&(dest[totlen]), "\\%03u", pd[i]);
+ totlen=totlen+strlen(&(dest[totlen]));
+ }
+ }
+ dest[totlen]='"';
+ dest[totlen+1]=0;
+ return dest;
+}
+
+static gchar *rd_match_strval(guint32 val, const value_string *vs) {
+ gchar *result;
+ result=match_strval(val,vs);
+ if (result == NULL ) {
+ result="Undefined";
+ }
+ return result;
+}
+static char *complexValCheck(e_avphdr *avp, const char *data, size_t dataLen)
+{
+ const char *rawData;
+ static char returnStr[1024];
+
+ switch (avp->avp_type) {
+ case DIAMETER_ATT_INTEGRITY_CHECK_VALUE:
+ {
+ struct {
+ guint32 transform;
+ guint32 keyid;
+ } icv;
+
+ memcpy(&icv, data, 8);
+ icv.transform=ntohl(icv.transform);
+ icv.keyid=ntohl(icv.keyid);
+ rawData = &data[8];
+
+ sprintf(returnStr,
+ "transform: 0x%08x (%d) keyid: 0x%08x (%d) Hash: ",
+ icv.transform, icv.transform, icv.keyid, icv.keyid);
+
+ rdconvertbufftostr(&returnStr[strlen(returnStr)],
+ dataLen-8,
+ rawData);
+ return returnStr;
+ }
+ }
+
+ return NULL;;
+} /* complexValCheck */
+static char *customValCheck(int code, int value)
+{
+ switch (code) {
+ case DIAMETER_ATT_QOS_SERVICE_TYPE:
+ return rd_match_strval(value, diameter_qos_service_type_vals);
+ break;
+ case DIAMETER_ATT_SERVICE_TYPE:
+ return rd_match_strval(value, diameter_service_type_vals);
+ break;
+ case DIAMETER_ATT_PROHIBIT:
+ return rd_match_strval(value, diameter_prohibit_vals);
+ break;
+ case DIAMETER_ATT_PROMPT:
+ return rd_match_strval(value, diameter_prompt_vals);
+ break;
+ case DIAMETER_ATT_SOURCE_PORT:
+ return rd_match_strval(value, diameter_source_port_vals);
+ break;
+ case DIAMETER_ATT_NAS_PORT_TYPE:
+ return rd_match_strval(value, diameter_nas_port_type_vals);
+ break;
+ case DIAMETER_ATT_INTERFACE_ADDRESS:
+ return rd_match_strval(value, diameter_interface_address_vals);
+ break;
+ case DIAMETER_ATT_FRAMED_ROUTING:
+ return rd_match_strval(value, diameter_framed_routing_vals);
+ break;
+ case DIAMETER_ATT_COMMAND_CODE:
+ return rd_match_strval(value, diameter_command_code_vals);
+ break;
+ case DIAMETER_ATT_FRAMED_IP_ADDRESS:
+ return rd_match_strval(value, diameter_framed_ip_address_vals);
+ break;
+ case DIAMETER_ATT_ARAP_ZONE_ACCESS:
+ return rd_match_strval(value, diameter_arap_zone_access_vals);
+ break;
+ case DIAMETER_ATT_ACCT_AUTHENTIC:
+ return rd_match_strval(value, diameter_acct_authentic_vals);
+ break;
+ case DIAMETER_ATT_FRAMED_PROTOCOL:
+ return rd_match_strval(value, diameter_framed_protocol_vals);
+ break;
+ case DIAMETER_ATT_FRAMED_COMPRESSION:
+ return rd_match_strval(value, diameter_framed_compression_vals);
+ break;
+ case DIAMETER_ATT_AUTHENTICATION_TYPE:
+ return rd_match_strval(value, diameter_authentication_type_vals);
+ break;
+ case DIAMETER_ATT_ACCT_TERMINATE_CAUSE:
+ return rd_match_strval(value, diameter_acct_terminate_cause_vals);
+ break;
+ case DIAMETER_ATT_PROTOCOL:
+ return rd_match_strval(value, diameter_protocol_vals);
+ break;
+ case DIAMETER_ATT_DESTINATION_PORT:
+ return rd_match_strval(value, diameter_destination_port_vals);
+ break;
+ case DIAMETER_ATT_TERMINATION_ACTION:
+ return rd_match_strval(value, diameter_termination_action_vals);
+ break;
+ case DIAMETER_ATT_EXTENSION_ID:
+ return rd_match_strval(value, diameter_extension_id_vals);
+ break;
+ case DIAMETER_ATT_MERIT_LAS_CODE:
+ return rd_match_strval(value, diameter_merit_las_code_vals);
+ break;
+ case DIAMETER_ATT_LOGIN_SERVICE:
+ return rd_match_strval(value, diameter_login_service_vals);
+ break;
+ case DIAMETER_ATT_RSVP_SERVICE_TYPE:
+ return rd_match_strval(value, diameter_rsvp_service_type_vals);
+ break;
+ case DIAMETER_ATT_REBOOT_TYPE:
+ return rd_match_strval(value, diameter_reboot_type_vals);
+ break;
+ case DIAMETER_ATT_ACCT_STATUS_TYPE:
+ return rd_match_strval(value, diameter_acct_status_type_vals);
+ break;
+ }
+
+ return NULL;
+}
+
+static gchar *rd_value_to_str(e_avphdr *avph,const u_char *pd, int offset)
+{
+ int print_type;
+ gchar *cont;
+ guint32 intval;
+ int dataLen;
+ char *valstr;
+ static char buffer[1024];
+
+ dataLen = avph->avp_length - sizeof(e_avphdr);
+
+ if (!(avph->avp_flags & AVP_FLAGS_V))
+ dataLen += 4;
+ if (!(avph->avp_flags & AVP_FLAGS_T))
+ dataLen += 4;
+
+/* prints the values of the attribute value pairs into a text buffer */
+
+ print_type=match_numval(avph->avp_type,diameter_printinfo);
+ /* Default begin */
+ sprintf(buffer,"Value: ");
+ cont=&buffer[strlen(buffer)];
+ switch(print_type)
+ {
+ case DIAMETER_COMPLEX:
+ valstr=complexValCheck(avph, &(pd[offset]), dataLen);
+ if (valstr) {
+ strcpy(cont, valstr);
+ break;
+ }
+
+ /* Intentional fall through */
+ case DIAMETER_DATA:
+ case DIAMETER_STRING:
+ rdconvertbufftostr(cont,dataLen,
+ &(pd[offset]));
+ break;
+ case DIAMETER_ADDRESS:
+ sprintf(cont,"%u.%u.%u.%u",(guint8)pd[offset],
+ (guint8)pd[offset+1],(guint8)pd[offset+2],
+ (guint8)pd[offset+3]);
+ break;
+ case DIAMETER_INTEGER32:
+ /* Check for custom values */
+ intval=pntohl(&(pd[offset]));
+ valstr=customValCheck(avph->avp_type, intval);
+ if (valstr) {
+ sprintf(cont,"%s (%u)", valstr, intval);
+ } else {
+ sprintf(cont,"%u", intval);
+ }
+ break;
+ case DIAMETER_INTEGER64:
+ sprintf(cont,"Unsupported Conversion");
+ break;
+ case DIAMETER_TIME:
+ {
+ struct tm lt;
+ intval=pntohl(&(pd[offset]));
+ intval -= NTP_TIME_DIFF;
+ lt=*localtime((time_t *)&intval);
+ strftime(cont, 1024,
+ "%a, %d %b %Y %H:%M:%S %z",&lt);
+ }
+ break;
+
+ default:
+ rdconvertbufftostr(cont,dataLen,
+ &(pd[offset]));
+ break;
+ }
+ if (cont == buffer) {
+ strcpy(cont,"Unknown Value");
+ }
+ return buffer;
+}
+
+
+static void dissect_attribute_value_pairs(const u_char *pd, int offset,
+ frame_data *fd, proto_tree *tree, int avplength) {
+/* adds the attribute value pairs to the tree */
+ e_avphdr avph;
+ gchar *avptpstrval;
+ gchar *valstr;
+ guint32 tag=0;
+ guint32 vendorId=0;
+ int dataOffset;
+ int fixAmt;
+ proto_item *avptf;
+ proto_tree *avptree;
+ int vendorOffset, tagOffset;
+
+ if (avplength==0) {
+ proto_tree_add_text(tree, NullTVB,offset,0,
+ "No Attribute Value Pairs Found");
+ return;
+ }
+
+ while (avplength > 0 ) {
+ vendorOffset = tagOffset = 0;
+ memcpy(&avph,&pd[offset],sizeof(e_avphdr));
+ avph.avp_type = ntohl(avph.avp_type);
+ avph.avp_length = ntohs(avph.avp_length);
+ avph.avp_flags = ntohs(avph.avp_flags);
+
+ if (avph.avp_flags & AVP_FLAGS_V) {
+ vendorId = ntohl(avph.avp_vendorId);
+ vendorOffset = 8;
+ if (avph.avp_flags & AVP_FLAGS_T) {
+ tag = ntohl(avph.avp_tag);
+ tagOffset = 12;
+ dataOffset = sizeof(e_avphdr);
+ } else {
+ /* only a vendor id */
+ dataOffset = sizeof(e_avphdr) - sizeof(guint32);
+ }
+ } else {
+ if (avph.avp_flags & AVP_FLAGS_T) {
+ /* tag in vendor field */
+ tag = ntohl(avph.avp_vendorId);
+ tagOffset = 8;
+ dataOffset = sizeof(e_avphdr) - sizeof(guint32);
+ } else {
+ /* No vendor or tag info */
+ dataOffset = sizeof(e_avphdr) -
+ (2*sizeof(guint32));
+ }
+ }
+
+ /*
+ * Fix byte-alignment
+ */
+ fixAmt = 4 - (avph.avp_length % 4);
+ if (fixAmt == 4) fixAmt = 0;
+ avplength=avplength - (avph.avp_length + fixAmt);
+ avptpstrval=match_strval(avph.avp_type, diameter_attrib_type_vals);
+ if (avptpstrval == NULL) avptpstrval="Unknown Type";
+ if (!BYTES_ARE_IN_FRAME(offset, avph.avp_length)) {
+ break;
+ }
+ avptf = proto_tree_add_text(tree,NullTVB,
+ offset, avph.avp_length,
+ "%s(%d) l:0x%x (%d bytes)",
+ avptpstrval,avph.avp_type,avph.avp_length,
+ avph.avp_length);
+ avptree = proto_item_add_subtree(avptf,
+ ett_diameter_avpinfo);
+ if (avptree !=NULL) {
+ proto_tree_add_text(avptree,NullTVB,
+ offset, 4,
+ "AVP Code: %s(%d)",
+ avptpstrval,avph.avp_type);
+ proto_tree_add_text(avptree,NullTVB,
+ offset+4 , 2,
+ "Length: 0x%x(%d bytes)",
+ avph.avp_length, avph.avp_length);
+ proto_tree_add_text(avptree,NullTVB,
+ offset+6, 2,
+ "Flags: P:%d T:%d V:%d R:%d M:%d",
+ (avph.avp_flags & AVP_FLAGS_P)?1:0,
+ (avph.avp_flags & AVP_FLAGS_T)?1:0,
+ (avph.avp_flags & AVP_FLAGS_V)?1:0,
+ (avph.avp_flags & AVP_FLAGS_R)?1:0,
+ (avph.avp_flags & AVP_FLAGS_M)?1:0);
+ if (vendorOffset) {
+ proto_tree_add_text(avptree,NullTVB,
+ offset+vendorOffset, 4,
+ "VendorId: 0x%08x (%d)",
+ vendorId, vendorId);
+ }
+ if (tagOffset) {
+ proto_tree_add_text(avptree,NullTVB,
+ offset+tagOffset, 4,
+ "Tag: 0x%08x (%d)",
+ tag, tag);
+ }
+ valstr=rd_value_to_str(&avph, pd, offset+dataOffset);
+ proto_tree_add_text(avptree,NullTVB,
+ offset+dataOffset, avph.avp_length - dataOffset,
+ "Data: (%d bytes) %s",
+ avph.avp_length - dataOffset, valstr);
+ }
+ offset=offset+avph.avp_length + fixAmt;
+ if (avph.avp_length == 0) {
+ break;
+ }
+ }
+}
+
+void dissect_diameter(const u_char *pd, int offset, frame_data *fd,
+ proto_tree *tree)
+{
+ proto_tree *diameter_tree,*avptree;
+ proto_item *ti,*avptf;
+ int avplength,hdrlength, offsetavp;
+ e_diameterhdr dh;
+ int commandCode;
+ char buffer[2000];
+ int nextSend=0, nextReceived=0;
+
+ gchar *codestrval;
+
+
+ if (gbl_commandCodeInHeader)
+ hdrlength=sizeof(e_diameterhdr);
+ else
+ hdrlength = sizeof(e_diameterhdr) - (2 * sizeof(uint32_t));
+
+ memcpy(&dh,&pd[offset],hdrlength);
+ /* Fix byte ordering in our static structure */
+ dh.pktLength = ntohs(dh.pktLength);
+ dh.identifier = ntohl(dh.identifier);
+
+ /* Our code is in first avp */
+ if (gbl_commandCodeInHeader) {
+ dh.u.new.commandCode = ntohl(dh.u.new.commandCode);
+ dh.u.new.vendorId = ntohl(dh.u.new.vendorId);
+
+ if ((DIAM_FLAGS_W & dh.flagsVer)) {
+ dh.u.new.nextSend = ntohs(dh.u.new.nextSend);
+ dh.u.new.nextReceived = ntohs(dh.u.new.nextReceived);
+ nextSend = dh.u.new.nextSend;
+ nextReceived = dh.u.new.nextReceived;
+ }
+ commandCode = dh.u.new.commandCode;
+ } else {
+ if ((DIAM_FLAGS_W & dh.flagsVer)) {
+ dh.u.old.nextSend = ntohs(dh.u.old.nextSend);
+ dh.u.old.nextReceived = ntohs(dh.u.old.nextReceived);
+ nextSend = dh.u.old.nextSend;
+ nextReceived = dh.u.old.nextReceived;
+ }
+ memcpy(&commandCode, &pd[offset+COMMAND_CODE_OFFSET], 4);
+ commandCode = ntohl(commandCode);
+ }
+
+ codestrval= match_strval(commandCode,diameter_command_code_vals);
+ if (codestrval==NULL) {
+ codestrval="Unknown Packet";
+ }
+ if (check_col(fd, COL_PROTOCOL))
+ col_add_str(fd, COL_PROTOCOL, "DIAMETER");
+ if (check_col(fd, COL_INFO)) {
+ if (DIAM_FLAGS_A & dh.flagsVer) {
+ sprintf(buffer,"ACK (id=%d, l=%d, s=%d, r=%d)",
+ dh.identifier, dh.pktLength, nextSend,
+ nextReceived);
+ } else {
+ sprintf(buffer,"%s(%d) (id=%d, l=%d, s=%d, r=%d)",
+ codestrval,commandCode, dh.identifier, dh.pktLength,
+ nextSend, nextReceived);
+ }
+ col_add_fstr(fd,COL_INFO,buffer);
+ }
+
+ if (tree) {
+
+ ti = proto_tree_add_protocol_format(tree, proto_diameter, NullTVB,
+ offset, dh.pktLength, "%s",
+ gbl_diameterString);
+ diameter_tree = proto_item_add_subtree(ti, ett_diameter);
+
+ if (!(DIAM_FLAGS_A & dh.flagsVer)) {
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_code,
+ NullTVB,
+ offset+0,
+ 1, dh.code, "Packet code:0x%02x",
+ dh.code);
+ }
+
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_flags,
+ NullTVB, offset+1, 1,
+ dh.flagsVer,
+ "Packet flags/Version: 0x%02x (Flags:0x%x,"
+ " A:%d W:%d Version=0x%1x (%d)",
+ dh.flagsVer, (dh.flagsVer&0xf8)>>3,
+ (DIAM_FLAGS_A & dh.flagsVer)?1:0,
+ (DIAM_FLAGS_W & dh.flagsVer)?1:0,
+ dh.flagsVer&0x07, dh.flagsVer&0x07);
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_length, NullTVB,
+ offset+2, 2,
+ dh.pktLength,
+ "Packet length: 0x%04x (%d)",dh.pktLength,
+ dh.pktLength);
+ proto_tree_add_uint_format(diameter_tree,hf_diameter_id,
+ NullTVB, offset+4, 4,
+ dh.identifier, "Packet identifier: 0x%08x (%d)",
+ dh.identifier, dh.identifier);
+ if (gbl_commandCodeInHeader) {
+ proto_tree_add_uint_format(diameter_tree,hf_diameter_id,
+ NullTVB, offset+8, 4,
+ dh.identifier, "Command Code: 0x%08x (%d:%s)",
+ dh.u.new.commandCode, dh.u.new.commandCode,
+ codestrval);
+ proto_tree_add_uint_format(diameter_tree,hf_diameter_id,
+ NullTVB, offset+12, 4,
+ dh.identifier, "VendorId: 0x%08x (%d)",
+ dh.u.new.vendorId, dh.u.new.vendorId);
+ if (DIAM_FLAGS_W & dh.flagsVer) {
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_ns, NullTVB,
+ offset+16, 2,
+ nextSend,
+ "Ns: 0x%02x(%d)",nextSend, nextSend);
+
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_nr, NullTVB,
+ offset+20, 2,
+ nextReceived,
+ "Nr: 0x%02x(%d)", nextReceived,
+ nextReceived);
+ }
+ } else {
+ if (DIAM_FLAGS_W & dh.flagsVer) {
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_ns, NullTVB,
+ offset+8, 2,
+ nextSend,
+ "Ns: 0x%02x(%d)",nextSend, nextSend);
+
+ proto_tree_add_uint_format(diameter_tree,
+ hf_diameter_nr, NullTVB,
+ offset+10, 2,
+ nextReceived,
+ "Nr: 0x%02x(%d)", nextReceived,
+ nextReceived);
+ }
+ }
+
+ /* Update the lengths */
+ avplength= dh.pktLength -hdrlength;
+ offsetavp=offset+hdrlength;
+
+ /* list the attribute value pairs */
+
+ avptf = proto_tree_add_text(diameter_tree,
+ NullTVB,offset+hdrlength,avplength,
+ "Attribute value pairs");
+ avptree = proto_item_add_subtree(avptf,
+ ett_diameter_avp);
+ if (avptree !=NULL) {
+ dissect_attribute_value_pairs( pd,
+ offsetavp,fd,avptree,avplength);
+ }
+ }
+}
+
+/* registration with the filtering engine */
+void
+proto_register_diameter(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_diameter_code,
+ { "Code","diameter.code", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_diameter_flags,
+ { "Flags+Version", "diameter.flags", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_diameter_length,
+ { "Length","diameter.length", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_diameter_id,
+ { "Identifier", "diameter.id", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_diameter_ns,
+ { "Next Send", "diameter.ns", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "" }},
+ { &hf_diameter_nr,
+ { "Next Received", "diameter.nr", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ };
+ static gint *ett[] = {
+ &ett_diameter,
+ &ett_diameter_avp,
+ &ett_diameter_avpinfo
+ };
+ module_t *diameter_module;
+
+ /* Register a configuration option for port */
+ diameter_module = prefs_register_module("Diameter", "Diameter",
+ proto_reg_handoff_diameter);
+ prefs_register_uint_preference(diameter_module, "udp.port",
+ "DIAMETER UDP Port",
+ "Set the port for DIAMETER messages (if"
+ " other than RADIUS port)",
+ 10,
+ &gbl_diameterUdpPort);
+ prefs_register_uint_preference(diameter_module, "tcp.port",
+ "DIAMETER UDP Port",
+ "Set the TCP port for DIAMETER messages",
+ 10,
+ &gbl_diameterTcpPort);
+#ifdef SCTP_DISSECTORS_ENABLED
+ prefs_register_uint_preference(diameter_module, "sctp.port",
+ "DIAMETER SCTP Port",
+ "Set the SCTP port for DIAMETER messages",
+ 10,
+ &gbl_diameterSctpPort);
+#endif
+ prefs_register_bool_preference(diameter_module, "command_in_header",
+ "Command code in header",
+ "Whether the command code is in the header, or in the first AVP",
+ &gbl_commandCodeInHeader);
+
+ proto_diameter = proto_register_protocol (gbl_diameterString, "diameter");
+ proto_register_field_array(proto_diameter, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_diameter(void)
+{
+ static int Initialized=FALSE;
+ static int UdpPort=0;
+ static int TcpPort=0;
+#ifdef SCTP_DISSECTORS_ENABLED
+ static int SctpPort=0;
+#endif
+ if (Initialized) {
+ dissector_delete("udp.port", UdpPort, dissect_diameter);
+ dissector_delete("tcp.port", TcpPort, dissect_diameter);
+#ifdef SCTP_DISSECTORS_ENABLED
+ dissector_delete("sctp.srcport", SctpPort, dissect_diameter);
+ dissector_delete("sctp.destport", SctpPort, dissect_diameter);
+#endif
+ } else {
+ Initialized=TRUE;
+ }
+
+ /* set port for future deletes */
+ UdpPort=gbl_diameterUdpPort;
+ TcpPort=gbl_diameterTcpPort;
+#ifdef SCTP_DISSECTORS_ENABLED
+ SctpPort=gbl_diameterSctpPort;
+#endif
+
+ strcpy(gbl_diameterString, "Diameter Protocol");
+
+ dissector_add("udp.port", gbl_diameterUdpPort, dissect_diameter);
+ dissector_add("tcp.port", gbl_diameterTcpPort, dissect_diameter);
+#ifdef SCTP_DISSECTORS_ENABLED
+ dissector_add("sctp.srcport", gbl_diameterSctpPort, dissect_diameter);
+ dissector_add("sctp.destport", gbl_diameterSctpPort, dissect_diameter);
+#endif
+}