/* packet-diameter.c * Routines for DIAMETER packet disassembly * * $Id: packet-diameter.c,v 1.23 2001/06/18 02:17:45 guy Exp $ * * Copyright (c) 2001 by David Frascone * * Ethereal - Network traffic analyzer * By Gerald Combs * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include #include #include #include #include #include #include "packet.h" #include "resolv.h" #include "prefs.h" /* This must be defined before we include packet-diameter-defs.h s*/ typedef struct _value_value_pair { guint32 val1; guint32 val2; } value_value_pair; /* Valid data types */ typedef enum { DIAMETER_DATA=1, DIAMETER_STRING, DIAMETER_ADDRESS, DIAMETER_INTEGER32, DIAMETER_INTEGER64, DIAMETER_UNSIGNED32, DIAMETER_UNSIGNED64, DIAMETER_FLOAT32, DIAMETER_FLOAT64, DIAMETER_FLOAT128, DIAMETER_TIME, DIAMETER_GROUPED } diameterDataTypes; #include "packet-diameter-defs.h" #define NTP_TIME_DIFF (2208988800UL) #define TCP_PORT_DIAMETER 1812 #define SCTP_PORT_DIAMETER 1812 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_reserved = -1; static int hf_diameter_flags = -1; static int hf_diameter_version = -1; static int hf_diameter_vendor_id = -1; static int hf_diameter_avp_code = -1; static int hf_diameter_avp_length = -1; static int hf_diameter_avp_reserved = -1; static int hf_diameter_avp_flags = -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; #if 0 static int hf_diameter_avp_data_uint64 = -1; static int hf_diameter_avp_data_int64 = -1; #endif 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 gint ett_diameter = -1; static gint ett_diameter_avp = -1; static gint ett_diameter_avpinfo = -1; static char gbl_diameterString[200]; static int gbl_diameterTcpPort=TCP_PORT_DIAMETER; static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER; typedef struct _e_diameterhdr { guint8 reserved; guint8 flagsVer; guint16 pktLength; guint32 hopByHopId; guint32 endToEndId; guint32 commandCode; guint32 vendorId; } e_diameterhdr; typedef struct _e_avphdr { guint32 avp_code; guint16 avp_length; guint8 avp_reserved; guint8 avp_flags; guint32 avp_vendorId; /* optional */ } e_avphdr; #define AUTHENTICATOR_LENGTH 12 /* Diameter Header Flags */ #define DIAM_FLAGS_E 0x20 #define DIAM_FLAGS_I 0x10 #define DIAM_FLAGS_R 0x08 #define DIAM_FLAGS_RESERVED 0xc0 /* 11000000 -- X X E I R V V V */ /* Diameter AVP Flags */ #define AVP_FLAGS_P 0x0020 #define AVP_FLAGS_V 0x0004 #define AVP_FLAGS_M 0x0001 #define AVP_FLAGS_RESERVED 0xea /* 11101010 -- X X X P X V X M */ #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32)) #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr) + MIN_AVP_SIZE) static gchar *rd_value_to_str(e_avphdr *avph,const u_char *input, int length); static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); static guint32 match_numval(guint32 val, const value_value_pair *vs); static gchar *DetermineMessageType(char flagsVer); /* Code to actually dissect the packets */ /* * Main dissector */ static void dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; tvbuff_t *avp_tvb; proto_tree *diameter_tree; e_diameterhdr dh; char *codestrval; size_t offset=0; size_t avplength; proto_tree *avp_tree; proto_item *avptf; int BadPacket = FALSE; /* Make entries in Protocol column and Info column on summary display */ if (check_col(pinfo->fd, COL_PROTOCOL)) col_add_str(pinfo->fd, COL_PROTOCOL, "Diameter"); if (check_col(pinfo->fd, COL_INFO)) col_clear(pinfo->fd, COL_INFO); /* Copy our header */ tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh)); /* Fix byte ordering in our static structure */ dh.pktLength = ntohs(dh.pktLength); dh.hopByHopId = ntohl(dh.hopByHopId); dh.endToEndId = ntohl(dh.endToEndId); dh.commandCode = ntohl(dh.commandCode); dh.vendorId = ntohl(dh.vendorId); codestrval= match_strval(dh.commandCode,diameter_command_code_vals); if (codestrval==NULL) { codestrval="Unknown Command Code"; } /* Short packet. Should have at LEAST one avp */ if (dh.pktLength < MIN_DIAMETER_SIZE) { g_warning("DIAMETER: Packet too short: %d bytes less than min size (%d bytes))", dh.pktLength, MIN_DIAMETER_SIZE); BadPacket = TRUE; } /* And, check our reserved flags/version */ if (dh.reserved || (dh.flagsVer & DIAM_FLAGS_RESERVED) || ((dh.flagsVer & 0x7) != 1)) { g_warning("DIAMETER: Bad packet: Bad Flags or Version"); BadPacket = TRUE; } if (check_col(pinfo->fd, COL_INFO)) { col_add_fstr(pinfo->fd, COL_INFO, "%s%s: %s(%d) vendor=%d (hop-id=%d) (end-id=%d) EIR=%d%d%d", (BadPacket)?"***** Bad Packet!: ":"", DetermineMessageType(dh.flagsVer), codestrval, dh.commandCode, dh.vendorId, dh.hopByHopId, dh.endToEndId, (dh.flagsVer & DIAM_FLAGS_E)?1:0, (dh.flagsVer & DIAM_FLAGS_I)?1:0, (dh.flagsVer & DIAM_FLAGS_R)?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, tvb_length(tvb), FALSE); diameter_tree = proto_item_add_subtree(ti, ett_diameter); /* Reserved */ proto_tree_add_uint(diameter_tree, hf_diameter_reserved, tvb, offset, 1, dh.reserved); offset +=1; /* Flags */ proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb, offset, 1, dh.flagsVer, "Packet flags: 0x%02x E:%d I:%d R:%d (%s)", (dh.flagsVer&0xf8)>>3, (dh.flagsVer & DIAM_FLAGS_E)?1:0, (dh.flagsVer & DIAM_FLAGS_I)?1:0, (dh.flagsVer & DIAM_FLAGS_R)?1:0, DetermineMessageType(dh.flagsVer)); /* Version */ proto_tree_add_uint(diameter_tree, hf_diameter_version, tvb, offset, 1, dh.flagsVer); offset+=1; /* Length */ proto_tree_add_uint(diameter_tree, hf_diameter_length, tvb, offset, 2, dh.pktLength); offset +=2; /* 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; /* Command Code */ proto_tree_add_uint(diameter_tree, hf_diameter_code, tvb, offset, 4, dh.commandCode); offset += 4; /* Vendor Id */ proto_tree_add_uint(diameter_tree,hf_diameter_vendor_id, tvb, offset, 4, dh.vendorId); 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= dh.pktLength - sizeof(e_diameterhdr); avp_tvb = tvb_new_subset(tvb, offset, -1, avplength); avptf = proto_tree_add_text(diameter_tree, tvb, offset, tvb_length(tvb), "Attribute Value Pairs"); avp_tree = proto_item_add_subtree(avptf, ett_diameter_avp); if (avp_tree != NULL) { dissect_avps( avp_tvb, pinfo, avp_tree); } } } /* dissect_diameter */ /* * 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 *avptpstrval; gchar *valstr; guint32 vendorId=0; int hdrLength; int fixAmt; proto_tree *avpi_tree; int vendorOffset; size_t offset = 0 ; char dataBuffer[4096]; tvbuff_t *group_tvb; proto_tree *group_tree; proto_item *grouptf; proto_item *avptf; char buffer[1024]; int BadPacket = FALSE; size_t packetLength; size_t avpDataLength; int avpType; 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 ) { vendorOffset = 0; /* Check for short packet */ if (packetLength < MIN_AVP_SIZE) { g_warning("DIAMETER: AVP Payload too short: %d bytes less than min size (%d bytes))", packetLength, 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, sizeof(avph)); /* Fix the byte ordering */ avph.avp_code = ntohl(avph.avp_code); avph.avp_length = ntohs(avph.avp_length); /* Dissect our vendor id if it exists and set hdr length*/ if (avph.avp_flags & AVP_FLAGS_V) { vendorId = ntohl(avph.avp_vendorId); /* Vendor id */ hdrLength = sizeof(e_avphdr); } else { /* No vendor */ hdrLength = sizeof(e_avphdr) - sizeof(guint32); } /* Check for bad length */ if (avph.avp_length < MIN_AVP_SIZE || (avph.avp_length > packetLength)) { g_warning("DIAMETER: AVP payload size invalid: avp_length: %d bytes, min: %d bytes, packetLen: %d", avph.avp_length, MIN_AVP_SIZE, packetLength); BadPacket = TRUE; } /* Check for bad flags */ if (avph.avp_reserved || (avph.avp_flags & AVP_FLAGS_RESERVED)) { g_warning("DIAMETER: Invalid AVP: avph.avp_reserved = 0x%x, avph.avp_flags = 0x%x, resFl=0x%x", avph.avp_reserved, avph.avp_flags, AVP_FLAGS_RESERVED); BadPacket = TRUE; } /* * Fix byte-alignment (Diameter AVPs are sent on 4 byte * boundries) */ fixAmt = 4 - (avph.avp_length % 4); if (fixAmt == 4) fixAmt = 0; packetLength = packetLength - (avph.avp_length + fixAmt); /* Check for out of bounds */ if (packetLength < 0) { g_warning("DIAMETER: Bad AVP: Bad new length (%d bytes)", packetLength); BadPacket = TRUE; } avptpstrval = match_strval(avph.avp_code, diameter_attrib_type_vals); if (avptpstrval == NULL) avptpstrval="Unknown Type"; avptf = proto_tree_add_text(avp_tree, tvb, offset, avph.avp_length, "%s(%d) l:0x%x (%d bytes)", avptpstrval, avph.avp_code, avph.avp_length, avph.avp_length); avpi_tree = proto_item_add_subtree(avptf, ett_diameter_avpinfo); if (avpi_tree !=NULL) { /* Command Code */ proto_tree_add_uint(avpi_tree, hf_diameter_avp_code, tvb, offset, 4, avph.avp_code); offset += 4; proto_tree_add_uint(avpi_tree, hf_diameter_avp_length, tvb, offset, 2, avph.avp_length); offset += 2; proto_tree_add_uint(avpi_tree, hf_diameter_avp_reserved, tvb, offset, 1, avph.avp_reserved); offset += 1; proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb, offset, 1, avph.avp_flags, "Flags: P:%d V:%d M:%d", (avph.avp_flags & AVP_FLAGS_P)?1:0, (avph.avp_flags & AVP_FLAGS_V)?1:0, (avph.avp_flags & AVP_FLAGS_M)?1:0); offset += 1; if (avph.avp_flags & AVP_FLAGS_V) { proto_tree_add_uint(avpi_tree, hf_diameter_avp_vendor_id, tvb, offset, 4, avph.avp_vendorId); offset += 4; } avpDataLength = avph.avp_length - 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, dataBuffer, "Bad AVP (Suspect Data Not Dissected)"); return; } avpType=match_numval(avph.avp_code, diameter_printinfo); tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095, avph.avp_length - hdrLength)); switch(avpType) { case DIAMETER_GROUPED: sprintf(buffer, "%s Grouped AVPs", avptpstrval); /* 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_STRING: proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string, tvb, offset, avpDataLength, dataBuffer, "String: %*.*s", (int)avpDataLength, (int)avpDataLength, dataBuffer); break; case DIAMETER_ADDRESS: if (avpDataLength == 4) { guint32 ipv4Address = ntohl((*(guint32*)dataBuffer)); proto_tree_add_ipv4_format(avpi_tree, hf_diameter_avp_data_v4addr, tvb, offset, avpDataLength, ipv4Address, "IPv4 Address: %u.%u.%u.%u", (ipv4Address&0xff000000)>>24, (ipv4Address&0xff0000)>>16, (ipv4Address&0xff00)>>8, (ipv4Address&0xff)); } else if (avpDataLength == 16) { proto_tree_add_ipv6_format(avpi_tree, hf_diameter_avp_data_v6addr, tvb, offset, avpDataLength, dataBuffer, "IPv6 Address: %04x:%04x:%04x:%04x", *((guint32*)dataBuffer), *((guint32*)&dataBuffer[4]), *((guint32*)&dataBuffer[8]), *((guint32*)&dataBuffer[12])); } else { proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, tvb, offset, avpDataLength, dataBuffer, "Error! Bad Address Length"); } break; case DIAMETER_INTEGER32: case DIAMETER_UNSIGNED32: case DIAMETER_INTEGER64: case DIAMETER_UNSIGNED64: valstr=rd_value_to_str(&avph, dataBuffer, offset); proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32, tvb, offset, avpDataLength, (*(guint32*)dataBuffer), "Value: %s", valstr); break; case DIAMETER_TIME: valstr=rd_value_to_str(&avph, dataBuffer, offset); proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr); break; default: case DIAMETER_DATA: proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, tvb, offset, avpDataLength, dataBuffer, "Data"); break; } offset += avph.avp_length - hdrLength; } offset += fixAmt; /* fix byte alignment */ } } /* dissect_avps */ /* Generic routine to work with value value pairs */ 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 *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 *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_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_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 *input, int length) { int print_type; guint32 intval; char *valstr; static char buffer[1024]; /* prints the values of the attribute value pairs into a text buffer */ print_type=match_numval(avph->avp_code,diameter_printinfo); /* Set the Default */ strcpy(buffer, "Unknown Value"); /* Default begin */ switch(print_type) { case DIAMETER_INTEGER32: /* Check for custom values */ intval=pntohl(input); valstr=customValCheck(avph->avp_code, intval); if (valstr) { sprintf(buffer,"%s (%u)", valstr, intval); } else { sprintf(buffer,"%d", intval); } break; case DIAMETER_UNSIGNED32: /* Check for custom values */ intval=pntohl(input); valstr=customValCheck(avph->avp_code, intval); if (valstr) { sprintf(buffer,"%s (%u)", valstr, intval); } else { sprintf(buffer,"%u", intval); } break; #ifdef G_HAVE_GINT64 /* XXX - have to handle platforms without 64-bit integral types. Have to handle platforms where "%lld" and "%llu" aren't the right formats to use to print 64-bit integral types. */ case DIAMETER_INTEGER64: { gint64 llval; llval = pntohll(input); sprintf(buffer,"%lld", llval); } break; case DIAMETER_UNSIGNED64: { guint64 llval; llval = pntohll(input); sprintf(buffer,"%llu", llval); } break; #endif case DIAMETER_TIME: { struct tm lt; intval=pntohl(input); intval -= NTP_TIME_DIFF; lt=*localtime((time_t *)&intval); strftime(buffer, 1024, "%a, %d %b %Y %H:%M:%S %z",<); } default: /* Do nothing */ ; } return buffer; } /* rd value to str */ static gchar * DetermineMessageType(char flagsVer) { /* Get rid of version */ flagsVer = flagsVer >> 3; /* Mask out reserved bits */ flagsVer = flagsVer & 0x7; switch (flagsVer) { case 0x0: /* Indication */ return "Indication"; case 0x4: /* Request */ return "Request"; case 0x1: /* Answer */ return "Answer"; case 0x6: /* Query */ return "Query"; case 0x3: /* Reply */ return "Reply"; default: return "Illegal Command Type"; } } /* DetermineMessageType */ void proto_reg_handoff_diameter(void) { static int Initialized=FALSE; static int TcpPort=0; static int SctpPort=0; if (Initialized) { dissector_delete("tcp.port", TcpPort, dissect_diameter); dissector_delete("sctp.port", SctpPort, dissect_diameter); } else { Initialized=TRUE; } /* set port for future deletes */ TcpPort=gbl_diameterTcpPort; SctpPort=gbl_diameterSctpPort; strcpy(gbl_diameterString, "Diameter Protocol"); /* g_warning ("Diameter: Adding tcp dissector to port %d", gbl_diameterTcpPort); */ dissector_add("tcp.port", gbl_diameterTcpPort, dissect_diameter, proto_diameter); dissector_add("sctp.port", gbl_diameterSctpPort, dissect_diameter, proto_diameter); } /* registration with the filtering engine */ void proto_register_diameter(void) { static hf_register_info hf[] = { { &hf_diameter_reserved, { "Reserved", "diameter.reserved", FT_UINT8, BASE_HEX, NULL, 0x0, "Should be zero", HFILL }}, { &hf_diameter_flags, { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0xf8, "", HFILL }}, { &hf_diameter_version, { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x07, "", HFILL }}, { &hf_diameter_length, { "Length","diameter.length", FT_UINT16, 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_code, { "Command Code","diameter.code", FT_UINT32, BASE_DEC, VALS(diameter_command_code_vals), 0x0, "", HFILL }}, { &hf_diameter_vendor_id, { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_code, { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC, VALS(diameter_attrib_type_vals), 0x0, "", HFILL }}, { &hf_diameter_avp_length, { "AVP length","diameter.avp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_reserved, { "AVP Reserved","diameter.avp.reserved", FT_UINT8, BASE_HEX, NULL, 0x0, "Should be Zero", HFILL }}, { &hf_diameter_avp_flags, { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX, NULL, 0x1f, "", HFILL }}, { &hf_diameter_avp_vendor_id, { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_uint32, { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, #if 0 { &hf_diameter_avp_data_uint64, { "AVP Data","diameter.avp.data.uint64", FT_UINT64, BASE_DEC, NULL, 0x0, "", HFILL }}, #endif { &hf_diameter_avp_data_int32, { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }}, #if 0 { &hf_diameter_avp_data_int64, { "AVP Data","diameter.avp.data.int64", FT_INT_64, BASE_DEC, NULL, 0x0, "", HFILL }}, #endif { &hf_diameter_avp_data_bytes, { "AVP Data","diameter.avp.data.bytes", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_string, { "AVP Data","diameter.avp.data.string", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_v4addr, { "AVP Data","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_v6addr, { "AVP Data","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_time, { "AVP Data","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }}, }; static gint *ett[] = { &ett_diameter, &ett_diameter_avp, &ett_diameter_avpinfo }; module_t *diameter_module; proto_diameter = proto_register_protocol (gbl_diameterString, "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); }