/* packet-diameter.c * Routines for DIAMETER packet disassembly * * $Id: packet-diameter.c,v 1.26 2001/08/04 19:50:33 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*/ /* 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 */ } diameterDataType; typedef struct avp_info { guint32 code; gchar *name; diameterDataType type; value_string *values; } avpInfo; #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 flags_set_truth = { "Set", "Not set" }; 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_reserved = -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_reserved3 = -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_reserved = -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 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 char gbl_diameterString[200]; static int gbl_diameterTcpPort=TCP_PORT_DIAMETER; static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER; 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; #define AUTHENTICATOR_LENGTH 12 /* Diameter Header Flags */ /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */ #define DIAM_FLAGS_R 0x80 #define DIAM_FLAGS_P 0x40 #define DIAM_FLAGS_E 0x20 #define DIAM_FLAGS_RESERVED3 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 0x1f #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) + MIN_AVP_SIZE) static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); /* Diameter Manipulation Routines (mess with our strucutres) */ diameterDataType diameter_avp_get_type(guint32 avpCode){ int i; for (i=0; diameter_avps[i].name; i++) { if (avpCode == diameter_avps[i].code) { /* We found it! */ return diameter_avps[i].type; } } /* If we don't find it, assume it's data */ g_warning("DIAMETER: Unable to find type for avpCode %d!", avpCode); return DIAMETER_OCTET_STRING; } /* diameter_avp_get_type */ static gchar * diameter_avp_get_name(guint32 avpCode) { static gchar buffer[64]; int i; for (i=0; diameter_avps[i].name; i++) { if (avpCode == diameter_avps[i].code) { /* We found it! */ return diameter_avps[i].name; } } /* 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 avpValue) { static gchar buffer[64]; int i; for (i=0; diameter_avps[i].name; i++) { if (avpCode == diameter_avps[i].code) { /* We found the code. Now find the value! */ if (!diameter_avps[i].values) break; return val_to_str(avpValue, diameter_avps[i].values , "Unknown Value: 0x%08x"); } } /* If we don't find the avp, build a value string */ sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue); return buffer; } /* diameter_avp_get_value */ static gchar * diameter_time_to_string(gchar *timeValue) { static gchar buffer[64]; int intval; struct tm lt; intval=pntohl(*((guint32*)timeValue)); intval -= NTP_TIME_DIFF; lt=*localtime((time_t *)&intval); strftime(buffer, 1024, "%a, %d %b %Y %H:%M:%S %z",<); return buffer; } /* diameter_time_to_string */ /* 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; proto_item *tf; proto_tree *flags_tree; tvbuff_t *avp_tvb; proto_tree *diameter_tree; e_diameterhdr dh; size_t offset=0; size_t avplength; proto_tree *avp_tree; proto_item *avptf; int BadPacket = FALSE; guint32 commandCode, pktLength; guint8 version, flags; gchar flagstr[64] = ""; gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" }; gchar commandString[64], vendorString[64]; gint i; guint bpos; /* 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.versionLength = ntohl(dh.versionLength); dh.flagsCmdCode = ntohl(dh.flagsCmdCode); dh.vendorId = ntohl(dh.vendorId); dh.hopByHopId = ntohl(dh.hopByHopId); dh.endToEndId = ntohl(dh.endToEndId); if (dh.vendorId) { strcpy(vendorString, val_to_str(dh.vendorId, diameter_vendor_specific_vendors, "Unknown Vendor: %08x")); } else { strcpy(vendorString, "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->fd, 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,""); } } /* Set up our commandString */ strcpy(commandString, val_to_str(commandCode, diameter_command_code_vals, "Unknown Command: 0x%08x")); 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) { g_warning("DIAMETER: Packet too short: %d bytes less than min size (%d bytes))", pktLength, MIN_DIAMETER_SIZE); BadPacket = TRUE; } /* And, check our reserved flags/version */ if ((flags & DIAM_FLAGS_RESERVED) || (version != 1)) { g_warning("DIAMETER: Bad packet: Bad Flags(0x%x) or Version(%u)", flags, version); BadPacket = TRUE; } if (check_col(pinfo->fd, COL_INFO)) { col_add_fstr(pinfo->fd, COL_INFO, "%s%s%s%s: %s vendor=%s (hop-id=%d) (end-id=%d) RPE=%d%d%d", (BadPacket)?"***** Bad Packet!: ":"", (flags & DIAM_FLAGS_P)?"Proxyable ":"", (flags & DIAM_FLAGS_R)?"Request":"Answer", (flags & DIAM_FLAGS_E)?" Error":"", commandString, vendorString, 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, tvb_length(tvb), 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_reserved3, 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", vendorString); 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, -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 avpTypeString[64]; gchar avpNameString[64]; gchar *valstr; guint32 vendorId=0; gchar vendorString[64]; int hdrLength; int fixAmt; proto_tree *avpi_tree; 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; guint32 avpLength; guint8 flags; proto_item *tf; proto_tree *flags_tree; gint32 packetLength; size_t avpDataLength; int avpType; gchar flagstr[64] = ""; 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) { 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, MIN((long)sizeof(avph),packetLength)); /* Fix the byte ordering */ avph.avp_code = ntohl(avph.avp_code); avph.avp_flagsLength = ntohl(avph.avp_flagsLength); flags = (avph.avp_flagsLength & 0xff000000) >> 24; avpLength = avph.avp_flagsLength & 0x00ffffff; /* Set up our flags string */ if (check_col(pinfo->fd, 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,""); } } /* Dissect our vendor id if it exists and set hdr length */ if (flags & AVP_FLAGS_V) { vendorId = ntohl(avph.avp_vendorId); /* Vendor id */ hdrLength = sizeof(e_avphdr); } else { /* No vendor */ hdrLength = sizeof(e_avphdr) - sizeof(guint32); vendorId = 0; } if (vendorId) { strcpy(vendorString, val_to_str(vendorId, diameter_vendor_specific_vendors, "Unknown Vendor: %08x")); } else { vendorString[0]='\0'; } /* Check for bad length */ if (avpLength < MIN_AVP_SIZE || ((long)avpLength > packetLength)) { g_warning("DIAMETER: AVP payload size invalid: avp_length: %d bytes, " "min: %d bytes, packetLen: %d", avpLength, MIN_AVP_SIZE, packetLength); BadPacket = TRUE; } /* Check for bad flags */ if (flags & AVP_FLAGS_RESERVED) { 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) { 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), diameter_avp_type_vals, "Unknown-Type: 0x%08x")); strcpy(avpNameString, diameter_avp_get_name(avph.avp_code)); 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, vendorString); 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, dataBuffer, "Bad AVP (Suspect Data Not Dissected)"); return; } avpType=diameter_avp_get_type(avph.avp_code); tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095,avpDataLength)); 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: proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string, tvb, offset, avpDataLength, dataBuffer, "Identity: %*.*s", (int)avpDataLength, (int)avpDataLength, dataBuffer); break; case DIAMETER_UTF8STRING: proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string, tvb, offset, avpDataLength, dataBuffer, "UTF8String: %*.*s", (int)avpDataLength, (int)avpDataLength, dataBuffer); break; case DIAMETER_IP_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: { gint32 data; memcpy(&data, dataBuffer, 4); data = ntohl(data); proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32, tvb, offset, avpDataLength, data, "Value: %d", data ); } break; case DIAMETER_UNSIGNED32: { guint32 data; memcpy(&data, dataBuffer, 4); data=ntohl(data); proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32, tvb, offset, avpDataLength, data, "Value: 0x%08x (%u)", data, data ); } break; case DIAMETER_INTEGER64: { gint64 data; memcpy(&data, dataBuffer, 8); /* data = ntohll(data); */ proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int64, tvb, offset, avpDataLength, data, "Value: 0x%016llx (%lld)", data, data ); } break; case DIAMETER_UNSIGNED64: { guint64 data; memcpy(&data, dataBuffer, 8); /* data = ntohll(data); */ proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_uint64, tvb, offset, avpDataLength, data, "Value: 0x%016llx (%llu)", data, data ); } break; case DIAMETER_TIME: valstr=diameter_time_to_string(dataBuffer); proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr); break; case DIAMETER_ENUMERATED: { guint32 data; memcpy(&data, dataBuffer, 4); data = ntohl(data); valstr = diameter_avp_get_value(avph.avp_code, 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); } break; default: case DIAMETER_OCTET_STRING: proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, tvb, offset, avpDataLength, dataBuffer, "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; 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_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_reserved3, { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set), DIAM_FLAGS_RESERVED3, "", 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, { "AVP Data","diameter.avp.data.uint64", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_int64, { "AVP Data","diameter.avp.data.int64", FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_uint32, { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_diameter_avp_data_int32, { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &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_flags, &ett_diameter_avp, &ett_diameter_avp_flags, &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); }