2 * Routines for DIAMETER packet disassembly
4 * $Id: packet-diameter.c,v 1.26 2001/08/04 19:50:33 guy Exp $
6 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
49 /* This must be defined before we include packet-diameter-defs.h s*/
51 /* Valid data types */
54 DIAMETER_OCTET_STRING = 1,
65 DIAMETER_IP_ADDRESS, /* OctetString */
66 DIAMETER_TIME, /* Integer 32 */
67 DIAMETER_UTF8STRING, /* OctetString */
68 DIAMETER_IDENTITY, /* OctetString */
69 DIAMETER_ENUMERATED, /* Integer 32 */
70 DIAMETER_IP_FILTER_RULE, /* OctetString */
71 DIAMETER_QOS_FILTER_RULE /* OctetString */
75 typedef struct avp_info {
78 diameterDataType type;
82 #include "packet-diameter-defs.h"
84 #define NTP_TIME_DIFF (2208988800UL)
86 #define TCP_PORT_DIAMETER 1812
87 #define SCTP_PORT_DIAMETER 1812
89 static const true_false_string flags_set_truth = {
94 static const true_false_string reserved_set = {
95 "*** Error! Reserved Bit is Set",
98 static int proto_diameter = -1;
99 static int hf_diameter_length = -1;
100 static int hf_diameter_code = -1;
101 static int hf_diameter_hopbyhopid =-1;
102 static int hf_diameter_endtoendid =-1;
103 static int hf_diameter_reserved = -1;
104 static int hf_diameter_version = -1;
105 static int hf_diameter_vendor_id = -1;
106 static int hf_diameter_flags = -1;
107 static int hf_diameter_flags_request = -1;
108 static int hf_diameter_flags_proxyable = -1;
109 static int hf_diameter_flags_error = -1;
110 static int hf_diameter_flags_reserved3 = -1;
111 static int hf_diameter_flags_reserved4 = -1;
112 static int hf_diameter_flags_reserved5 = -1;
113 static int hf_diameter_flags_reserved6 = -1;
114 static int hf_diameter_flags_reserved7 = -1;
116 static int hf_diameter_avp_code = -1;
117 static int hf_diameter_avp_length = -1;
118 static int hf_diameter_avp_reserved = -1;
119 static int hf_diameter_avp_flags = -1;
120 static int hf_diameter_avp_flags_vendor_specific = -1;
121 static int hf_diameter_avp_flags_mandatory = -1;
122 static int hf_diameter_avp_flags_protected = -1;
123 static int hf_diameter_avp_flags_reserved3 = -1;
124 static int hf_diameter_avp_flags_reserved4 = -1;
125 static int hf_diameter_avp_flags_reserved5 = -1;
126 static int hf_diameter_avp_flags_reserved6 = -1;
127 static int hf_diameter_avp_flags_reserved7 = -1;
128 static int hf_diameter_avp_vendor_id = -1;
131 static int hf_diameter_avp_data_uint32 = -1;
132 static int hf_diameter_avp_data_int32 = -1;
133 static int hf_diameter_avp_data_uint64 = -1;
134 static int hf_diameter_avp_data_int64 = -1;
135 static int hf_diameter_avp_data_bytes = -1;
136 static int hf_diameter_avp_data_string = -1;
137 static int hf_diameter_avp_data_v4addr = -1;
138 static int hf_diameter_avp_data_v6addr = -1;
139 static int hf_diameter_avp_data_time = -1;
141 static gint ett_diameter = -1;
142 static gint ett_diameter_flags = -1;
143 static gint ett_diameter_avp = -1;
144 static gint ett_diameter_avp_flags = -1;
145 static gint ett_diameter_avpinfo = -1;
147 static char gbl_diameterString[200];
148 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
149 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
151 typedef struct _e_diameterhdr {
152 guint32 versionLength;
153 guint32 flagsCmdCode;
159 typedef struct _e_avphdr {
161 guint32 avp_flagsLength;
162 guint32 avp_vendorId; /* optional */
165 #define AUTHENTICATOR_LENGTH 12
167 /* Diameter Header Flags */
168 /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
169 #define DIAM_FLAGS_R 0x80
170 #define DIAM_FLAGS_P 0x40
171 #define DIAM_FLAGS_E 0x20
172 #define DIAM_FLAGS_RESERVED3 0x10
173 #define DIAM_FLAGS_RESERVED4 0x08
174 #define DIAM_FLAGS_RESERVED5 0x04
175 #define DIAM_FLAGS_RESERVED6 0x02
176 #define DIAM_FLAGS_RESERVED7 0x01
177 #define DIAM_FLAGS_RESERVED 0x1f
179 #define DIAM_LENGTH_MASK 0x00ffffffl
180 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
181 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
182 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
183 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
184 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
186 /* Diameter AVP Flags */
187 #define AVP_FLAGS_P 0x20
188 #define AVP_FLAGS_V 0x80
189 #define AVP_FLAGS_M 0x40
190 #define AVP_FLAGS_RESERVED3 0x10
191 #define AVP_FLAGS_RESERVED4 0x08
192 #define AVP_FLAGS_RESERVED5 0x04
193 #define AVP_FLAGS_RESERVED6 0x02
194 #define AVP_FLAGS_RESERVED7 0x01
195 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
197 #define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32))
198 #define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr) + MIN_AVP_SIZE)
200 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
205 /* Diameter Manipulation Routines (mess with our strucutres) */
208 diameter_avp_get_type(guint32 avpCode){
210 for (i=0; diameter_avps[i].name; i++) {
211 if (avpCode == diameter_avps[i].code) {
213 return diameter_avps[i].type;
216 /* If we don't find it, assume it's data */
217 g_warning("DIAMETER: Unable to find type for avpCode %d!", avpCode);
218 return DIAMETER_OCTET_STRING;
219 } /* diameter_avp_get_type */
222 diameter_avp_get_name(guint32 avpCode)
224 static gchar buffer[64];
227 for (i=0; diameter_avps[i].name; i++) {
228 if (avpCode == diameter_avps[i].code) {
230 return diameter_avps[i].name;
233 /* If we don't find it, build a name string */
234 sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
236 } /* diameter_avp_get_name */
238 diameter_avp_get_value(guint32 avpCode, guint32 avpValue)
240 static gchar buffer[64];
243 for (i=0; diameter_avps[i].name; i++) {
244 if (avpCode == diameter_avps[i].code) {
245 /* We found the code. Now find the value! */
246 if (!diameter_avps[i].values)
248 return val_to_str(avpValue, diameter_avps[i].values , "Unknown Value: 0x%08x");
251 /* If we don't find the avp, build a value string */
252 sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
254 } /* diameter_avp_get_value */
257 diameter_time_to_string(gchar *timeValue)
259 static gchar buffer[64];
263 intval=pntohl(*((guint32*)timeValue));
264 intval -= NTP_TIME_DIFF;
265 lt=*localtime((time_t *)&intval);
266 strftime(buffer, 1024,
267 "%a, %d %b %Y %H:%M:%S %z",<);
269 } /* diameter_time_to_string */
272 /* Code to actually dissect the packets */
277 static void dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
280 /* Set up structures needed to add the protocol subtree and manage it */
283 proto_tree *flags_tree;
285 proto_tree *diameter_tree;
289 proto_tree *avp_tree;
291 int BadPacket = FALSE;
292 guint32 commandCode, pktLength;
293 guint8 version, flags;
294 gchar flagstr[64] = "<None>";
295 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
296 gchar commandString[64], vendorString[64];
300 /* Make entries in Protocol column and Info column on summary display */
301 if (check_col(pinfo->fd, COL_PROTOCOL))
302 col_add_str(pinfo->fd, COL_PROTOCOL, "Diameter");
303 if (check_col(pinfo->fd, COL_INFO))
304 col_clear(pinfo->fd, COL_INFO);
306 /* Copy our header */
307 tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
309 /* Fix byte ordering in our static structure */
310 dh.versionLength = ntohl(dh.versionLength);
311 dh.flagsCmdCode = ntohl(dh.flagsCmdCode);
312 dh.vendorId = ntohl(dh.vendorId);
313 dh.hopByHopId = ntohl(dh.hopByHopId);
314 dh.endToEndId = ntohl(dh.endToEndId);
318 val_to_str(dh.vendorId, diameter_vendor_specific_vendors, "Unknown Vendor: %08x"));
320 strcpy(vendorString, "None");
324 /* Do the bit twiddling */
325 version = DIAM_GET_VERSION(dh);
326 pktLength = DIAM_GET_LENGTH(dh);
327 flags = DIAM_GET_FLAGS(dh);
328 commandCode = DIAM_GET_COMMAND(dh);
330 /* Set up our flags */
331 if (check_col(pinfo->fd, COL_INFO) || tree) {
333 for (i = 0; i < 8; i++) {
337 strcat(flagstr, ", ");
339 strcat(flagstr, fstr[i]);
342 if (strlen(flagstr) == 0) {
343 strcpy(flagstr,"<None>");
347 /* Set up our commandString */
348 strcpy(commandString, val_to_str(commandCode, diameter_command_code_vals, "Unknown Command: 0x%08x"));
349 if (flags & DIAM_FLAGS_R)
350 strcat(commandString, "-Request");
352 strcat(commandString, "-Answer");
354 /* Short packet. Should have at LEAST one avp */
355 if (pktLength < MIN_DIAMETER_SIZE) {
356 g_warning("DIAMETER: Packet too short: %d bytes less than min size (%d bytes))",
357 pktLength, MIN_DIAMETER_SIZE);
361 /* And, check our reserved flags/version */
362 if ((flags & DIAM_FLAGS_RESERVED) ||
364 g_warning("DIAMETER: Bad packet: Bad Flags(0x%x) or Version(%u)",
369 if (check_col(pinfo->fd, COL_INFO)) {
370 col_add_fstr(pinfo->fd, COL_INFO,
371 "%s%s%s%s: %s vendor=%s (hop-id=%d) (end-id=%d) RPE=%d%d%d",
372 (BadPacket)?"***** Bad Packet!: ":"",
373 (flags & DIAM_FLAGS_P)?"Proxyable ":"",
374 (flags & DIAM_FLAGS_R)?"Request":"Answer",
375 (flags & DIAM_FLAGS_E)?" Error":"",
376 commandString, vendorString,
377 dh.hopByHopId, dh.endToEndId,
378 (flags & DIAM_FLAGS_R)?1:0,
379 (flags & DIAM_FLAGS_P)?1:0,
380 (flags & DIAM_FLAGS_E)?1:0);
384 /* In the interest of speed, if "tree" is NULL, don't do any work not
385 necessary to generate protocol tree items. */
388 /* create display subtree for the protocol */
389 ti = proto_tree_add_item(tree, proto_diameter, tvb, offset, tvb_length(tvb), FALSE);
390 diameter_tree = proto_item_add_subtree(ti, ett_diameter);
393 proto_tree_add_uint(diameter_tree,
401 proto_tree_add_uint(diameter_tree,
402 hf_diameter_length, tvb,
403 offset, 3, pktLength);
407 tf = proto_tree_add_uint_format(diameter_tree, hf_diameter_flags, tvb,
408 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
410 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
411 proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags);
412 proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags);
413 proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags);
414 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved3, tvb, offset, 1, flags);
415 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags);
416 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags);
417 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags);
418 proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags);
423 proto_tree_add_uint_format(diameter_tree, hf_diameter_code,
424 tvb, offset, 3, commandCode, "Command Code: %s", commandString);
428 proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
429 tvb, offset, 4, dh.vendorId, "Vendor-Id: %s", vendorString);
432 /* Hop-by-hop Identifier */
433 proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid,
434 tvb, offset, 4, dh.hopByHopId);
437 /* End-to-end Identifier */
438 proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid,
439 tvb, offset, 4, dh.endToEndId);
442 /* If we have a bad packet, don't bother trying to parse the AVPs */
447 /* Start looking at the AVPS */
448 /* Make the next tvbuff */
450 /* Update the lengths */
451 avplength= pktLength - sizeof(e_diameterhdr);
453 avp_tvb = tvb_new_subset(tvb, offset, -1, avplength);
454 avptf = proto_tree_add_text(diameter_tree,
455 tvb, offset, tvb_length(tvb),
456 "Attribute Value Pairs");
458 avp_tree = proto_item_add_subtree(avptf,
460 if (avp_tree != NULL) {
461 dissect_avps( avp_tvb, pinfo, avp_tree);
464 } /* dissect_diameter */
467 * This function will dissect the AVPs in a diameter packet. It handles
468 * all normal types, and even recursively calls itself for grouped AVPs
470 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
472 /* adds the attribute value pairs to the tree */
474 gchar avpTypeString[64];
475 gchar avpNameString[64];
478 gchar vendorString[64];
481 proto_tree *avpi_tree;
483 char dataBuffer[4096];
485 proto_tree *group_tree;
489 int BadPacket = FALSE;
493 proto_tree *flags_tree;
496 size_t avpDataLength;
498 gchar flagstr[64] = "<None>";
499 gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
503 packetLength = tvb_length(tvb);
505 /* Check for invalid packet lengths */
506 if (packetLength <= 0) {
507 proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
508 "No Attribute Value Pairs Found");
512 /* Spin around until we run out of packet */
513 while (packetLength > 0 ) {
515 /* Check for short packet */
516 if (packetLength < (long)MIN_AVP_SIZE) {
517 g_warning("DIAMETER: AVP Payload too short: %d bytes less than min size (%d bytes))",
518 packetLength, MIN_AVP_SIZE);
520 /* Don't even bother trying to parse a short packet. */
524 /* Copy our header */
525 tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
527 /* Fix the byte ordering */
528 avph.avp_code = ntohl(avph.avp_code);
529 avph.avp_flagsLength = ntohl(avph.avp_flagsLength);
531 flags = (avph.avp_flagsLength & 0xff000000) >> 24;
532 avpLength = avph.avp_flagsLength & 0x00ffffff;
534 /* Set up our flags string */
535 if (check_col(pinfo->fd, COL_INFO) || avp_tree) {
537 for (i = 0; i < 8; i++) {
541 strcat(flagstr, ", ");
543 strcat(flagstr, fstr[i]);
546 if (strlen(flagstr) == 0) {
547 strcpy(flagstr,"<None>");
551 /* Dissect our vendor id if it exists and set hdr length */
552 if (flags & AVP_FLAGS_V) {
553 vendorId = ntohl(avph.avp_vendorId);
555 hdrLength = sizeof(e_avphdr);
558 hdrLength = sizeof(e_avphdr) -
565 val_to_str(vendorId, diameter_vendor_specific_vendors, "Unknown Vendor: %08x"));
567 vendorString[0]='\0';
570 /* Check for bad length */
571 if (avpLength < MIN_AVP_SIZE ||
572 ((long)avpLength > packetLength)) {
573 g_warning("DIAMETER: AVP payload size invalid: avp_length: %d bytes, "
574 "min: %d bytes, packetLen: %d",
575 avpLength, MIN_AVP_SIZE, packetLength);
579 /* Check for bad flags */
580 if (flags & AVP_FLAGS_RESERVED) {
581 g_warning("DIAMETER: Invalid AVP: Reserved bit set. flags = 0x%x,"
583 flags, AVP_FLAGS_RESERVED);
584 /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
589 * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
592 fixAmt = 4 - (avpLength % 4);
593 if (fixAmt == 4) fixAmt = 0;
595 /* shrink our packetLength */
596 packetLength = packetLength - (avpLength + fixAmt);
598 /* Check for out of bounds */
599 if (packetLength < 0) {
600 g_warning("DIAMETER: Bad AVP: Bad new length (%d bytes) ",
605 /* Make avp Name & type */
606 strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code), diameter_avp_type_vals,
607 "Unknown-Type: 0x%08x"));
608 strcpy(avpNameString, diameter_avp_get_name(avph.avp_code));
610 avptf = proto_tree_add_text(avp_tree, tvb,
611 offset, avpLength + fixAmt,
612 "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
613 avpNameString, avpTypeString, avpLength,
614 avpLength, avpLength+fixAmt);
615 avpi_tree = proto_item_add_subtree(avptf,
616 ett_diameter_avpinfo);
618 if (avpi_tree !=NULL) {
620 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
621 tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
624 tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
625 offset , 1, flags, "Flags: 0x%02x (%s)", flags,
627 flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
628 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
629 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
630 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
631 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
632 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
633 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
634 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
635 proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
638 proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
639 tvb, offset, 3, avpLength);
642 if (flags & AVP_FLAGS_V) {
643 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
644 tvb, offset, 4, vendorId, vendorString);
648 avpDataLength = avpLength - hdrLength;
651 * If we've got a bad packet, just highlight the data. Don't try
652 * to parse it, and, don't move to next AVP.
656 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
657 tvb, offset, tvb_length(tvb) - offset, dataBuffer,
658 "Bad AVP (Suspect Data Not Dissected)");
662 avpType=diameter_avp_get_type(avph.avp_code);
663 tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095,avpDataLength));
667 case DIAMETER_GROUPED:
668 sprintf(buffer, "%s Grouped AVPs", avpNameString);
669 /* Recursively call ourselves */
670 grouptf = proto_tree_add_text(avpi_tree,
671 tvb, offset, tvb_length(tvb),
674 group_tree = proto_item_add_subtree(grouptf,
677 group_tvb = tvb_new_subset(tvb, offset,
678 MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
679 if (group_tree != NULL) {
680 dissect_avps( group_tvb, pinfo, group_tree);
684 case DIAMETER_IDENTITY:
685 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
686 tvb, offset, avpDataLength, dataBuffer,
687 "Identity: %*.*s", (int)avpDataLength, (int)avpDataLength,
690 case DIAMETER_UTF8STRING:
691 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
692 tvb, offset, avpDataLength, dataBuffer,
693 "UTF8String: %*.*s", (int)avpDataLength, (int)avpDataLength,
696 case DIAMETER_IP_ADDRESS:
697 if (avpDataLength == 4) {
698 guint32 ipv4Address = ntohl((*(guint32*)dataBuffer));
699 proto_tree_add_ipv4_format(avpi_tree, hf_diameter_avp_data_v4addr,
700 tvb, offset, avpDataLength, ipv4Address,
701 "IPv4 Address: %u.%u.%u.%u",
702 (ipv4Address&0xff000000)>>24,
703 (ipv4Address&0xff0000)>>16,
704 (ipv4Address&0xff00)>>8,
706 } else if (avpDataLength == 16) {
707 proto_tree_add_ipv6_format(avpi_tree, hf_diameter_avp_data_v6addr,
708 tvb, offset, avpDataLength, dataBuffer,
709 "IPv6 Address: %04x:%04x:%04x:%04x",
710 *((guint32*)dataBuffer),
711 *((guint32*)&dataBuffer[4]),
712 *((guint32*)&dataBuffer[8]),
713 *((guint32*)&dataBuffer[12]));
715 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
716 tvb, offset, avpDataLength, dataBuffer,
717 "Error! Bad Address Length");
721 case DIAMETER_INTEGER32:
724 memcpy(&data, dataBuffer, 4);
726 proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32,
727 tvb, offset, avpDataLength, data,
732 case DIAMETER_UNSIGNED32:
736 memcpy(&data, dataBuffer, 4);
738 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
739 tvb, offset, avpDataLength, data,
740 "Value: 0x%08x (%u)", data,
745 case DIAMETER_INTEGER64:
748 memcpy(&data, dataBuffer, 8);
749 /* data = ntohll(data); */
750 proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int64,
751 tvb, offset, avpDataLength, data,
752 "Value: 0x%016llx (%lld)", data, data );
755 case DIAMETER_UNSIGNED64:
758 memcpy(&data, dataBuffer, 8);
759 /* data = ntohll(data); */
760 proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_uint64,
761 tvb, offset, avpDataLength, data,
762 "Value: 0x%016llx (%llu)", data, data );
767 valstr=diameter_time_to_string(dataBuffer);
769 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
770 tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr);
773 case DIAMETER_ENUMERATED:
777 memcpy(&data, dataBuffer, 4);
779 valstr = diameter_avp_get_value(avph.avp_code, data);
780 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
781 tvb, offset, avpDataLength, data,
782 "Value: 0x%08x (%u): %s", data, data, valstr);
786 case DIAMETER_OCTET_STRING:
787 proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
788 tvb, offset, avpDataLength, dataBuffer,
789 "Hex Data Highlighted Below");
793 } /* avpi_tree != null */
794 offset += (avpLength - hdrLength);
795 offset += fixAmt; /* fix byte alignment */
802 proto_reg_handoff_diameter(void)
804 static int Initialized=FALSE;
805 static int TcpPort=0;
806 static int SctpPort=0;
809 dissector_delete("tcp.port", TcpPort, dissect_diameter);
810 dissector_delete("sctp.port", SctpPort, dissect_diameter);
815 /* set port for future deletes */
816 TcpPort=gbl_diameterTcpPort;
817 SctpPort=gbl_diameterSctpPort;
819 strcpy(gbl_diameterString, "Diameter Protocol");
821 /* g_warning ("Diameter: Adding tcp dissector to port %d",
822 gbl_diameterTcpPort); */
823 dissector_add("tcp.port", gbl_diameterTcpPort, dissect_diameter,
825 dissector_add("sctp.port", gbl_diameterSctpPort,
826 dissect_diameter, proto_diameter);
829 /* registration with the filtering engine */
831 proto_register_diameter(void)
834 static hf_register_info hf[] = {
835 { &hf_diameter_version,
836 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
838 { &hf_diameter_length,
839 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
842 { &hf_diameter_flags,
843 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
845 { &hf_diameter_flags_request,
846 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
848 { &hf_diameter_flags_proxyable,
849 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
851 { &hf_diameter_flags_error,
852 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
854 { &hf_diameter_flags_reserved3,
855 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
856 DIAM_FLAGS_RESERVED3, "", HFILL }},
857 { &hf_diameter_flags_reserved4,
858 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
859 DIAM_FLAGS_RESERVED4, "", HFILL }},
860 { &hf_diameter_flags_reserved5,
861 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
862 DIAM_FLAGS_RESERVED5, "", HFILL }},
863 { &hf_diameter_flags_reserved6,
864 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
865 DIAM_FLAGS_RESERVED6, "", HFILL }},
866 { &hf_diameter_flags_reserved7,
867 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
868 DIAM_FLAGS_RESERVED7, "", HFILL }},
871 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
872 NULL, 0x0, "", HFILL }},
873 { &hf_diameter_vendor_id,
874 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
876 { &hf_diameter_hopbyhopid,
877 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
878 BASE_HEX, NULL, 0x0, "", HFILL }},
879 { &hf_diameter_endtoendid,
880 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
881 BASE_HEX, NULL, 0x0, "", HFILL }},
883 { &hf_diameter_avp_code,
884 { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
885 NULL, 0x0, "", HFILL }},
886 { &hf_diameter_avp_length,
887 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
888 NULL, 0x0, "", HFILL }},
891 { &hf_diameter_avp_flags,
892 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
893 NULL, 0x0, "", HFILL }},
894 { &hf_diameter_avp_flags_vendor_specific,
895 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V,
897 { &hf_diameter_avp_flags_mandatory,
898 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
900 { &hf_diameter_avp_flags_protected,
901 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P,
903 { &hf_diameter_avp_flags_reserved3,
904 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
905 AVP_FLAGS_RESERVED3, "", HFILL }},
906 { &hf_diameter_avp_flags_reserved4,
907 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
908 AVP_FLAGS_RESERVED4, "", HFILL }},
909 { &hf_diameter_avp_flags_reserved5,
910 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
911 AVP_FLAGS_RESERVED5, "", HFILL }},
912 { &hf_diameter_avp_flags_reserved6,
913 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
914 AVP_FLAGS_RESERVED6, "", HFILL }},
915 { &hf_diameter_avp_flags_reserved7,
916 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
917 AVP_FLAGS_RESERVED7, "", HFILL }},
918 { &hf_diameter_avp_vendor_id,
919 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
920 NULL, 0x0, "", HFILL }},
921 { &hf_diameter_avp_data_uint64,
922 { "AVP Data","diameter.avp.data.uint64", FT_UINT32, BASE_DEC,
923 NULL, 0x0, "", HFILL }},
924 { &hf_diameter_avp_data_int64,
925 { "AVP Data","diameter.avp.data.int64", FT_INT32, BASE_DEC,
926 NULL, 0x0, "", HFILL }},
927 { &hf_diameter_avp_data_uint32,
928 { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
929 NULL, 0x0, "", HFILL }},
930 { &hf_diameter_avp_data_int32,
931 { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC,
932 NULL, 0x0, "", HFILL }},
933 { &hf_diameter_avp_data_bytes,
934 { "AVP Data","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
935 NULL, 0x0, "", HFILL }},
937 { &hf_diameter_avp_data_string,
938 { "AVP Data","diameter.avp.data.string", FT_STRING, BASE_NONE,
939 NULL, 0x0, "", HFILL }},
940 { &hf_diameter_avp_data_v4addr,
941 { "AVP Data","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
942 NULL, 0x0, "", HFILL }},
943 { &hf_diameter_avp_data_v6addr,
944 { "AVP Data","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
945 NULL, 0x0, "", HFILL }},
946 { &hf_diameter_avp_data_time,
947 { "AVP Data","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
948 NULL, 0x0, "", HFILL }},
951 static gint *ett[] = {
955 &ett_diameter_avp_flags,
956 &ett_diameter_avpinfo
958 module_t *diameter_module;
960 proto_diameter = proto_register_protocol (gbl_diameterString,
961 "DIAMETER", "diameter");
962 proto_register_field_array(proto_diameter, hf, array_length(hf));
963 proto_register_subtree_array(ett, array_length(ett));
965 /* Register a configuration option for port */
966 diameter_module = prefs_register_protocol(proto_diameter,
967 proto_reg_handoff_diameter);
968 prefs_register_uint_preference(diameter_module, "tcp.port",
970 "Set the TCP port for DIAMETER messages",
972 &gbl_diameterTcpPort);
973 prefs_register_uint_preference(diameter_module, "sctp.port",
974 "DIAMETER SCTP Port",
975 "Set the SCTP port for DIAMETER messages",
977 &gbl_diameterSctpPort);