2 * Routines for Diameter packet disassembly
6 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
7 * Copyright (c) 2007 by Luis E. Garcia Ontanon <luis@ontanon.org>
9 * Support for Request-Answer tracking and Tapping
10 * introduced by Abhik Sarkar
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 * http://www.ietf.org/rfc/rfc3588.txt
32 * http://www.iana.org/assignments/radius-types
33 * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-cc-03.txt
34 * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-nasreq-14.txt
35 * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-mobileip-16.txt
36 * http://www.ietf.org/internet-drafts/draft-ietf-aaa-diameter-sip-app-01.txt
37 * http://www.ietf.org/html.charters/aaa-charter.html
38 * http://www.iana.org/assignments/address-family-numbers
39 * http://www.iana.org/assignments/enterprise-numbers
40 * http://www.iana.org/assignments/aaa-parameters
53 #include <epan/packet.h>
54 #include <epan/exceptions.h>
55 #include <epan/filesystem.h>
56 #include <epan/prefs.h>
57 #include <epan/sminmpec.h>
58 #include <epan/wmem/wmem.h>
59 #include <epan/expert.h>
60 #include <epan/conversation.h>
62 #include <epan/exported_pdu.h>
63 #include <epan/diam_dict.h>
64 #include <epan/sctpppids.h>
65 #include <epan/show_exception.h>
66 #include "packet-tcp.h"
67 #include "packet-diameter.h"
69 /* Diameter Header Flags */
70 /* RPETrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
71 #define DIAM_FLAGS_R 0x80
72 #define DIAM_FLAGS_P 0x40
73 #define DIAM_FLAGS_E 0x20
74 #define DIAM_FLAGS_T 0x10
75 #define DIAM_FLAGS_RESERVED4 0x08
76 #define DIAM_FLAGS_RESERVED5 0x04
77 #define DIAM_FLAGS_RESERVED6 0x02
78 #define DIAM_FLAGS_RESERVED7 0x01
79 #define DIAM_FLAGS_RESERVED 0x0f
81 #define DIAM_LENGTH_MASK 0x00ffffffl
82 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
83 #define DIAM_GET_FLAGS(dh) ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
84 #define DIAM_GET_VERSION(dh) ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
85 #define DIAM_GET_COMMAND(dh) (dh.flagsCmdCode & DIAM_COMMAND_MASK)
86 #define DIAM_GET_LENGTH(dh) (dh.versionLength & DIAM_LENGTH_MASK)
88 /* Diameter AVP Flags */
89 #define AVP_FLAGS_P 0x20
90 #define AVP_FLAGS_V 0x80
91 #define AVP_FLAGS_M 0x40
92 #define AVP_FLAGS_RESERVED3 0x10
93 #define AVP_FLAGS_RESERVED4 0x08
94 #define AVP_FLAGS_RESERVED5 0x04
95 #define AVP_FLAGS_RESERVED6 0x02
96 #define AVP_FLAGS_RESERVED7 0x01
97 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
99 #define DIAMETER_V16 16
100 #define DIAMETER_RFC 1
102 static gint exported_pdu_tap
= -1;
104 /* Conversation Info */
105 typedef struct _diameter_conv_info_t
{
106 wmem_tree_t
*pdus_tree
;
107 } diameter_conv_info_t
;
109 typedef struct _diam_ctx_t
{
113 gboolean version_rfc
;
116 typedef struct _diam_avp_t diam_avp_t
;
117 typedef struct _avp_type_t avp_type_t
;
119 typedef const char *(*diam_avp_dissector_t
)(diam_ctx_t
*, diam_avp_t
*, tvbuff_t
*, diam_sub_dis_t
*);
122 typedef struct _diam_vnd_t
{
125 value_string_ext
*vs_avps_ext
;
131 const diam_vnd_t
*vendor
;
132 diam_avp_dissector_t dissector_v16
;
133 diam_avp_dissector_t dissector_rfc
;
140 #define VND_AVP_VS(v) ((value_string *)(void *)((v)->vs_avps->data))
141 #define VND_AVP_VS_LEN(v) ((v)->vs_avps->len)
142 #define VND_CMD_VS(v) ((value_string *)(void *)((v)->vs_cmds->data))
144 typedef struct _diam_dictionary_t
{
147 value_string
*applications
;
148 value_string
*commands
;
151 typedef diam_avp_t
*(*avp_constructor_t
)(const avp_type_t
*, guint32
, const diam_vnd_t
*, const char *, const value_string
*, void *);
155 diam_avp_dissector_t v16
;
156 diam_avp_dissector_t rfc
;
159 avp_constructor_t build
;
170 typedef struct _address_avp_t
{
182 } avp_reassemble_mode_t
;
184 typedef struct _proto_avp_t
{
186 dissector_handle_t handle
;
187 avp_reassemble_mode_t reassemble_mode
;
190 static const char *simple_avp(diam_ctx_t
*, diam_avp_t
*, tvbuff_t
*, diam_sub_dis_t
*);
192 static diam_vnd_t unknown_vendor
= { 0xffffffff, NULL
, NULL
, NULL
};
193 static diam_vnd_t no_vnd
= { 0, NULL
, NULL
, NULL
};
194 static diam_avp_t unknown_avp
= {0, &unknown_vendor
, simple_avp
, simple_avp
, -1, -1, NULL
};
195 static GArray
*all_cmds
;
196 static diam_dictionary_t dictionary
= { NULL
, NULL
, NULL
, NULL
};
197 static struct _build_dict build_dict
;
198 static const value_string
*vnd_short_vs
;
199 static dissector_handle_t data_handle
;
200 static dissector_handle_t eap_handle
;
202 static const value_string diameter_avp_data_addrfamily_vals
[]= {
219 {17,"DistinguishedName"},
224 {22,"FibrePortName"},
225 {23,"FibreNodeName"},
229 static value_string_ext diameter_avp_data_addrfamily_vals_ext
= VALUE_STRING_EXT_INIT(diameter_avp_data_addrfamily_vals
);
231 static int proto_diameter
= -1;
232 static int hf_diameter_length
= -1;
233 static int hf_diameter_code
= -1;
234 static int hf_diameter_hopbyhopid
=-1;
235 static int hf_diameter_endtoendid
=-1;
236 static int hf_diameter_version
= -1;
237 static int hf_diameter_vendor_id
= -1;
238 static int hf_diameter_application_id
= -1;
239 static int hf_diameter_flags
= -1;
240 static int hf_diameter_flags_request
= -1;
241 static int hf_diameter_flags_proxyable
= -1;
242 static int hf_diameter_flags_error
= -1;
243 static int hf_diameter_flags_T
= -1;
244 static int hf_diameter_flags_reserved4
= -1;
245 static int hf_diameter_flags_reserved5
= -1;
246 static int hf_diameter_flags_reserved6
= -1;
247 static int hf_diameter_flags_reserved7
= -1;
249 static int hf_diameter_avp
= -1;
250 static int hf_diameter_avp_len
= -1;
251 static int hf_diameter_avp_code
= -1;
252 static int hf_diameter_avp_flags
= -1;
253 static int hf_diameter_avp_flags_vendor_specific
= -1;
254 static int hf_diameter_avp_flags_mandatory
= -1;
255 static int hf_diameter_avp_flags_protected
= -1;
256 static int hf_diameter_avp_flags_reserved3
= -1;
257 static int hf_diameter_avp_flags_reserved4
= -1;
258 static int hf_diameter_avp_flags_reserved5
= -1;
259 static int hf_diameter_avp_flags_reserved6
= -1;
260 static int hf_diameter_avp_flags_reserved7
= -1;
261 static int hf_diameter_avp_vendor_id
= -1;
262 static int hf_diameter_avp_data_wrong_length
= -1;
263 static int hf_diameter_avp_pad
= -1;
265 static int hf_diameter_answer_in
= -1;
266 static int hf_diameter_answer_to
= -1;
267 static int hf_diameter_answer_time
= -1;
269 /* AVPs with special/extra decoding */
270 static int hf_framed_ipv6_prefix_reserved
= -1;
271 static int hf_framed_ipv6_prefix_length
= -1;
272 static int hf_framed_ipv6_prefix_bytes
= -1;
273 static int hf_framed_ipv6_prefix_ipv6
= -1;
275 static gint ett_diameter
= -1;
276 static gint ett_diameter_flags
= -1;
277 static gint ett_diameter_avp_flags
= -1;
278 static gint ett_diameter_avpinfo
= -1;
279 static gint ett_unknown
= -1;
280 static gint ett_err
= -1;
283 static expert_field ei_diameter_reserved_bit_set
= EI_INIT
;
284 static expert_field ei_diameter_avp_len
= EI_INIT
;
285 static expert_field ei_diameter_avp_no_data
= EI_INIT
;
286 static expert_field ei_diameter_application_id
= EI_INIT
;
287 static expert_field ei_diameter_version
= EI_INIT
;
288 static expert_field ei_diameter_avp_pad
= EI_INIT
;
289 static expert_field ei_diameter_code
= EI_INIT
;
290 static expert_field ei_diameter_avp_code
= EI_INIT
;
291 static expert_field ei_diameter_avp_vendor_id
= EI_INIT
;
293 /* Tap for Diameter */
294 static int diameter_tap
= -1;
296 /* For conversations */
298 static dissector_handle_t diameter_udp_handle
;
299 static dissector_handle_t diameter_tcp_handle
;
300 static dissector_handle_t diameter_sctp_handle
;
301 static range_t
*global_diameter_tcp_port_range
;
302 static range_t
*global_diameter_sctp_port_range
;
303 static range_t
*global_diameter_udp_port_range
;
304 /* This is used for TCP and SCTP */
305 #define DEFAULT_DIAMETER_PORT_RANGE "3868"
307 /* desegmentation of Diameter over TCP */
308 static gboolean gbl_diameter_desegment
= TRUE
;
310 /* Dissector tables */
311 static dissector_table_t diameter_dissector_table
;
312 static dissector_table_t diameter_3gpp_avp_dissector_table
;
313 static dissector_table_t diameter_ericsson_avp_dissector_table
;
315 static const char *avpflags_str
[] = {
327 export_diameter_pdu(packet_info
*pinfo
, tvbuff_t
*tvb
)
329 exp_pdu_data_t
*exp_pdu_data
;
330 guint32 tags_bit_field
;
332 tags_bit_field
= EXP_PDU_TAG_IP_SRC_BIT
+ EXP_PDU_TAG_IP_DST_BIT
+ EXP_PDU_TAG_SRC_PORT_BIT
+
333 EXP_PDU_TAG_DST_PORT_BIT
+ EXP_PDU_TAG_ORIG_FNO_BIT
;
335 exp_pdu_data
= load_export_pdu_tags(pinfo
, "diameter", -1, tags_bit_field
);
337 exp_pdu_data
->tvb_length
= tvb_length(tvb
);
338 exp_pdu_data
->pdu_tvb
= tvb
;
340 tap_queue_packet(exported_pdu_tap
, pinfo
, exp_pdu_data
);
345 compare_avps(const void *a
, const void *b
)
347 const value_string
*vsa
= (const value_string
*)a
;
348 const value_string
*vsb
= (const value_string
*)b
;
350 if(vsa
->value
> vsb
->value
)
352 if(vsa
->value
< vsb
->value
)
358 /* Special decoding of some AVPs */
361 dissect_diameter_vendor_id(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
365 proto_tree_add_item(tree
, hf_diameter_vendor_id
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
372 dissect_diameter_eap_payload(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
374 gboolean save_writable
;
376 /* Ensure the packet is displayed as Diameter, not EAP */
377 save_writable
= col_get_writable(pinfo
->cinfo
);
378 col_set_writable(pinfo
->cinfo
, FALSE
);
380 call_dissector(eap_handle
, tvb
, pinfo
, tree
);
382 col_set_writable(pinfo
->cinfo
, save_writable
);
383 return tvb_length(tvb
);
386 /* From RFC 3162 section 2.3 */
388 dissect_diameter_base_framed_ipv6_prefix(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
390 guint8 prefix_len
, prefix_len_bytes
;
392 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_reserved
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
393 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_length
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
395 prefix_len
= tvb_get_guint8(tvb
, 1);
396 prefix_len_bytes
= prefix_len
/ 8;
400 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_bytes
, tvb
, 2, prefix_len_bytes
, ENC_NA
);
402 /* If we have a fully IPv6 address, display it as such */
403 if (prefix_len_bytes
== 16)
404 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_ipv6
, tvb
, 2, prefix_len_bytes
, ENC_NA
);
406 return(prefix_len_bytes
+2);
409 /* Call subdissectors for AVPs.
410 * This is a separate function to avoid having any local variables that might
411 * get clobbered by the exception longjmp() (without having to declare the
412 * variables as volatile and deal with casting them).
415 call_avp_subdissector(guint32 vendorid
, guint32 code
, tvbuff_t
*subtvb
, packet_info
*pinfo
, proto_tree
*avp_tree
, diam_sub_dis_t
*diam_sub_dis_inf
)
420 dissector_try_uint(diameter_dissector_table
, code
, subtvb
, pinfo
, avp_tree
);
422 case VENDOR_ERICSSON
:
423 dissector_try_uint(diameter_ericsson_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
);
426 dissector_try_uint_new(diameter_3gpp_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, FALSE
, diam_sub_dis_inf
);
433 proto_tree_add_text(avp_tree, subtvb, 0, -1, "AVP %u data, Vendor Id %u ",code,vendorid);
436 CATCH_NONFATAL_ERRORS
{
437 show_exception(subtvb
, pinfo
, avp_tree
, EXCEPT_CODE
, GET_MESSAGE
);
442 /* Dissect an AVP at offset */
444 dissect_diameter_avp(diam_ctx_t
*c
, tvbuff_t
*tvb
, int offset
, diam_sub_dis_t
*diam_sub_dis_inf
)
446 guint32 code
= tvb_get_ntohl(tvb
,offset
);
447 guint32 len
= tvb_get_ntohl(tvb
,offset
+4);
448 guint32 vendor_flag
= len
& 0x80000000;
449 guint32 flags_bits_idx
= (len
& 0xE0000000) >> 29;
450 guint32 flags_bits
= (len
& 0xFF000000) >> 24;
451 guint32 vendorid
= vendor_flag
? tvb_get_ntohl(tvb
,offset
+8) : 0 ;
452 wmem_tree_key_t k
[] = {
457 diam_avp_t
*a
= (diam_avp_t
*)wmem_tree_lookup32_array(dictionary
.avps
,k
);
458 proto_item
*pi
, *avp_item
;
459 proto_tree
*avp_tree
, *save_tree
;
462 const char *code_str
;
467 pad_len
= (len
% 4) ? 4 - (len
% 4) : 0 ;
473 if (! (vendor
= (diam_vnd_t
*)wmem_tree_lookup32(dictionary
.vnds
,vendorid
) ))
474 vendor
= &unknown_vendor
;
479 vendor
= (diam_vnd_t
*)a
->vendor
;
482 if(vendor
->vs_avps_ext
== NULL
) {
483 g_array_sort(vendor
->vs_avps
, compare_avps
);
484 vendor
->vs_avps_ext
= value_string_ext_new(VND_AVP_VS(vendor
), VND_AVP_VS_LEN(vendor
)+1,
485 g_strdup_printf("diameter_vendor_%s",val_to_str_ext_const(vendorid
, &sminmpec_values_ext
, "Unknown")));
488 value_string
*vendor_avp_vs
=VALUE_STRING_EXT_VS_P(vendor
->vs_avps_ext
);
490 while(vendor_avp_vs
[i
].strptr
!=NULL
) {
491 g_warning("%u %s",vendor_avp_vs
[i
].value
,vendor_avp_vs
[i
].strptr
);
498 /* Add root of tree for this AVP */
499 avp_item
= proto_tree_add_item(c
->tree
, hf_diameter_avp
, tvb
, offset
, len
+ pad_len
, ENC_NA
);
500 avp_tree
= proto_item_add_subtree(avp_item
, a
->ett
);
502 pi
= proto_tree_add_item(avp_tree
,hf_diameter_avp_code
,tvb
,offset
,4,ENC_BIG_ENDIAN
);
503 code_str
= val_to_str_ext_const(code
, vendor
->vs_avps_ext
, "Unknown");
504 proto_item_append_text(pi
," %s", code_str
);
507 if (a
== &unknown_avp
) {
508 proto_tree
*tu
= proto_item_add_subtree(pi
,ett_unknown
);
509 proto_tree_add_expert_format(tu
, c
->pinfo
, &ei_diameter_avp_code
, tvb
, offset
, 4,
510 "Unknown AVP %u (vendor=%s), if you know what this is you can add it to dictionary.xml", code
,
511 val_to_str_ext_const(vendorid
, &sminmpec_values_ext
, "Unknown"));
516 proto_item_set_text(avp_item
,"AVP: %s(%u) l=%u f=%s", code_str
, code
, len
, avpflags_str
[flags_bits_idx
]);
519 pi
= proto_tree_add_item(avp_tree
,hf_diameter_avp_flags
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
521 proto_tree
*flags_tree
= proto_item_add_subtree(pi
,ett_diameter_avp_flags
);
522 proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_vendor_specific
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
523 proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_mandatory
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
524 proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_protected
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
525 pi
= proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_reserved3
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
526 if(flags_bits
& 0x10) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
527 pi
= proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_reserved4
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
528 if(flags_bits
& 0x08) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
529 pi
= proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_reserved5
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
530 if(flags_bits
& 0x04) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
531 proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_reserved6
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
532 if(flags_bits
& 0x02) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
533 proto_tree_add_item(flags_tree
,hf_diameter_avp_flags_reserved7
,tvb
,offset
,1,ENC_BIG_ENDIAN
);
534 if(flags_bits
& 0x01) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
539 proto_tree_add_item(avp_tree
,hf_diameter_avp_len
,tvb
,offset
,3,ENC_BIG_ENDIAN
);
544 proto_item_append_text(avp_item
," vnd=%s", val_to_str(vendorid
, vnd_short_vs
, "%d"));
545 pi
= proto_tree_add_item(avp_tree
,hf_diameter_avp_vendor_id
,tvb
,offset
,4,ENC_BIG_ENDIAN
);
546 if (vendor
== &unknown_vendor
) {
547 proto_tree
*tu
= proto_item_add_subtree(pi
,ett_unknown
);
548 proto_tree_add_expert(tu
, c
->pinfo
, &ei_diameter_avp_vendor_id
, tvb
, offset
, 4);
553 if ( len
== (guint32
)(vendor_flag
? 12 : 8) ) {
554 /* Data is empty so return now */
555 proto_tree_add_expert(avp_tree
, c
->pinfo
, &ei_diameter_avp_no_data
, tvb
, offset
, 0);
556 /* pad_len is always 0 in this case, but kept here for consistency */
560 subtvb
= tvb_new_subset(tvb
,offset
,len
-(8+(vendor_flag
?4:0)),len
-(8+(vendor_flag
?4:0)));
561 offset
+= len
-(8+(vendor_flag
?4:0));
565 if (c
->version_rfc
) {
566 avp_str
= a
->dissector_rfc(c
,a
,subtvb
, diam_sub_dis_inf
);
568 avp_str
= a
->dissector_v16(c
,a
,subtvb
, diam_sub_dis_inf
);
572 if (avp_str
) proto_item_append_text(avp_item
," val=%s", avp_str
);
574 call_avp_subdissector(vendorid
, code
, subtvb
, c
->pinfo
, avp_tree
, diam_sub_dis_inf
);
579 pi
= proto_tree_add_item(avp_tree
, hf_diameter_avp_pad
, tvb
, offset
, pad_len
, ENC_NA
);
580 for (i
=0; i
< pad_len
; i
++) {
581 if (tvb_get_guint8(tvb
, offset
++) != 0) {
582 expert_add_info(c
->pinfo
, pi
, &ei_diameter_avp_pad
);
592 address_rfc_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
594 char *label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
595 address_avp_t
*t
= (address_avp_t
*)a
->type_data
;
596 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length(tvb
),ENC_BIG_ENDIAN
);
597 proto_tree
*pt
= proto_item_add_subtree(pi
,t
->ett
);
598 guint32 addr_type
= tvb_get_ntohs(tvb
,0);
599 gint len
= tvb_length_remaining(tvb
,2);
601 proto_tree_add_item(pt
,t
->hf_address_type
,tvb
,0,2,ENC_NA
);
602 switch (addr_type
) {
605 proto_tree_add_expert_format(pt
, c
->pinfo
, &ei_diameter_avp_len
, tvb
, 2, len
, "Wrong length for IPv4 Address: %d instead of 4", len
);
606 return "[Malformed]";
608 pi
= proto_tree_add_item(pt
,t
->hf_ipv4
,tvb
,2,4,ENC_BIG_ENDIAN
);
612 proto_tree_add_expert_format(pt
, c
->pinfo
, &ei_diameter_avp_len
, tvb
, 2, len
, "Wrong length for IPv6 Address: %d instead of 16", len
);
613 return "[Malformed]";
615 pi
= proto_tree_add_item(pt
,t
->hf_ipv6
,tvb
,2,16,ENC_NA
);
618 pi
= proto_tree_add_item(pt
,t
->hf_other
,tvb
,2,-1,ENC_BIG_ENDIAN
);
622 proto_item_fill_label(PITEM_FINFO(pi
), label
);
623 label
= strstr(label
,": ")+2;
628 proto_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
630 proto_avp_t
*t
= (proto_avp_t
*)a
->type_data
;
632 col_set_writable(c
->pinfo
->cinfo
, FALSE
);
635 t
->handle
= find_dissector(t
->name
);
636 if(!t
->handle
) t
->handle
= data_handle
;
640 call_dissector_with_data(t
->handle
, tvb
, c
->pinfo
, c
->tree
, diam_sub_dis_inf
);
642 CATCH_NONFATAL_ERRORS
{
643 show_exception(tvb
, c
->pinfo
, c
->tree
, EXCEPT_CODE
, GET_MESSAGE
);
651 time_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
653 int len
= tvb_length(tvb
);
654 char *label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
658 proto_tree_add_expert_format(c
->tree
, c
->pinfo
, &ei_diameter_avp_len
, tvb
, 0, 4,
659 "Bad Timestamp Length: %d instead of 4", len
);
660 return "[Malformed]";
663 pi
= proto_tree_add_item(c
->tree
, (a
->hf_value
), tvb
, 0, 4, ENC_TIME_NTP
|ENC_BIG_ENDIAN
);
664 proto_item_fill_label(PITEM_FINFO(pi
), label
);
665 label
= strstr(label
,": ")+2;
670 address_v16_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
672 char *label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
673 address_avp_t
*t
= (address_avp_t
*)a
->type_data
;
674 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length(tvb
),ENC_BIG_ENDIAN
);
675 proto_tree
*pt
= proto_item_add_subtree(pi
,t
->ett
);
676 guint32 len
= tvb_length(tvb
);
680 pi
= proto_tree_add_item(pt
,t
->hf_ipv4
,tvb
,0,4,ENC_BIG_ENDIAN
);
683 pi
= proto_tree_add_item(pt
,t
->hf_ipv6
,tvb
,0,16,ENC_NA
);
686 pi
= proto_tree_add_item(pt
,t
->hf_other
,tvb
,0,len
,ENC_BIG_ENDIAN
);
687 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
688 "Bad Address Length (%u)", len
);
693 proto_item_fill_label(PITEM_FINFO(pi
), label
);
694 label
= strstr(label
,": ")+2;
699 simple_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
701 char *label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
702 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length(tvb
),ENC_BIG_ENDIAN
);
703 proto_item_fill_label(PITEM_FINFO(pi
), label
);
704 label
= strstr(label
,": ")+2;
709 utf8_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
711 char *label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
712 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length(tvb
),ENC_UTF_8
|ENC_BIG_ENDIAN
);
713 proto_item_fill_label(PITEM_FINFO(pi
), label
);
714 label
= strstr(label
,": ")+2;
719 integer32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
724 /* Verify length before adding */
725 gint length
= tvb_length_remaining(tvb
,0);
727 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length_remaining(tvb
,0),ENC_BIG_ENDIAN
);
728 label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
729 proto_item_fill_label(PITEM_FINFO(pi
), label
);
730 label
= strstr(label
,": ")+2;
733 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
734 tvb
, 0, length
, NULL
,
735 "Error! Bad Integer32 Length");
736 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
737 "Bad Integer32 Length (%u)", length
);
738 PROTO_ITEM_SET_GENERATED(pi
);
745 integer64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
750 /* Verify length before adding */
751 gint length
= tvb_length_remaining(tvb
,0);
753 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length_remaining(tvb
,0),ENC_BIG_ENDIAN
);
754 label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
755 proto_item_fill_label(PITEM_FINFO(pi
), label
);
756 label
= strstr(label
,": ")+2;
759 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
760 tvb
, 0, length
, NULL
,
761 "Error! Bad Integer64 Length");
762 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
763 "Bad Integer64 Length (%u)", length
);
764 PROTO_ITEM_SET_GENERATED(pi
);
771 unsigned32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
776 /* Verify length before adding */
777 gint length
= tvb_length_remaining(tvb
,0);
779 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length_remaining(tvb
,0),ENC_BIG_ENDIAN
);
780 label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
781 proto_item_fill_label(PITEM_FINFO(pi
), label
);
782 label
= strstr(label
,": ")+2;
785 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
786 tvb
, 0, length
, NULL
,
787 "Error! Bad Unsigned32 Length");
788 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
789 "Bad Unsigned32 Length (%u)", length
);
790 PROTO_ITEM_SET_GENERATED(pi
);
797 unsigned64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
802 /* Verify length before adding */
803 gint length
= tvb_length_remaining(tvb
,0);
805 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length_remaining(tvb
,0),ENC_BIG_ENDIAN
);
806 label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
807 proto_item_fill_label(PITEM_FINFO(pi
), label
);
808 label
= strstr(label
,": ")+2;
811 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
812 tvb
, 0, length
, NULL
,
813 "Error! Bad Unsigned64 Length");
814 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
815 "Bad Unsigned64 Length (%u)", length
);
816 PROTO_ITEM_SET_GENERATED(pi
);
823 float32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
828 /* Verify length before adding */
829 gint length
= tvb_length_remaining(tvb
,0);
831 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length_remaining(tvb
,0),ENC_BIG_ENDIAN
);
832 label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
833 proto_item_fill_label(PITEM_FINFO(pi
), label
);
834 label
= strstr(label
,": ")+2;
837 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
838 tvb
, 0, length
, NULL
,
839 "Error! Bad Float32 Length");
840 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
841 "Bad Float32 Length (%u)", length
);
842 PROTO_ITEM_SET_GENERATED(pi
);
849 float64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
854 /* Verify length before adding */
855 gint length
= tvb_length_remaining(tvb
,0);
857 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_length_remaining(tvb
,0),ENC_BIG_ENDIAN
);
858 label
= (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH
+1);
859 proto_item_fill_label(PITEM_FINFO(pi
), label
);
860 label
= strstr(label
,": ")+2;
863 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
864 tvb
, 0, length
, NULL
,
865 "Error! Bad Float64 Length");
866 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
867 "Bad Float64 Length (%u)", length
);
868 PROTO_ITEM_SET_GENERATED(pi
);
875 grouped_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
878 int len
= tvb_length(tvb
);
879 proto_item
*pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0 , -1, ENC_BIG_ENDIAN
);
880 proto_tree
*pt
= c
->tree
;
882 c
->tree
= proto_item_add_subtree(pi
,a
->ett
);
884 while (offset
< len
) {
885 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
);
893 static const char *msgflags_str
[] = {
894 "----", "---T", "--E-", "--ET",
895 "-P--", "-P-T", "-PE-", "-PET",
896 "R---", "R--T", "R-E-", "R-ET",
897 "RP--", "RP-T", "RPE-", "RPET"
901 dissect_diameter_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
903 guint32 first_word
= tvb_get_ntohl(tvb
,0);
904 guint32 version
= (first_word
& 0xff000000) >> 24;
905 guint32 flags_bits
= (tvb_get_ntohl(tvb
,4) & 0xff000000) >> 24;
906 int packet_len
= first_word
& 0x00ffffff;
907 proto_item
*pi
, *cmd_item
, *app_item
, *version_item
;
908 proto_tree
*diam_tree
;
909 diam_ctx_t
*c
= (diam_ctx_t
*)wmem_alloc0(wmem_packet_scope(), sizeof(diam_ctx_t
));
911 value_string
*cmd_vs
;
913 guint32 cmd
= tvb_get_ntoh24(tvb
,5);
914 guint32 hop_by_hop_id
, end_to_end_id
;
915 conversation_t
*conversation
;
916 diameter_conv_info_t
*diameter_conv_info
;
917 diameter_req_ans_pair_t
*diameter_pair
= NULL
;
918 wmem_tree_t
*pdus_tree
;
921 diam_sub_dis_t
*diam_sub_dis_inf
= wmem_new0(wmem_packet_scope(), diam_sub_dis_t
);
924 diam_sub_dis_inf
->application_id
= tvb_get_ntohl(tvb
,8);
926 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
928 pi
= proto_tree_add_item(tree
,proto_diameter
,tvb
,0,-1,ENC_NA
);
929 diam_tree
= proto_item_add_subtree(pi
,ett_diameter
);
934 version_item
= proto_tree_add_item(diam_tree
,hf_diameter_version
,tvb
,0,1,ENC_BIG_ENDIAN
);
935 proto_tree_add_item(diam_tree
,hf_diameter_length
,tvb
,1,3,ENC_BIG_ENDIAN
);
937 pi
= proto_tree_add_item(diam_tree
,hf_diameter_flags
,tvb
,4,1,ENC_BIG_ENDIAN
);
939 proto_tree
*pt
= proto_item_add_subtree(pi
,ett_diameter_flags
);
940 proto_tree_add_item(pt
,hf_diameter_flags_request
,tvb
,4,1,ENC_BIG_ENDIAN
);
941 proto_tree_add_item(pt
,hf_diameter_flags_proxyable
,tvb
,4,1,ENC_BIG_ENDIAN
);
942 proto_tree_add_item(pt
,hf_diameter_flags_error
,tvb
,4,1,ENC_BIG_ENDIAN
);
943 proto_tree_add_item(pt
,hf_diameter_flags_T
,tvb
,4,1,ENC_BIG_ENDIAN
);
944 proto_tree_add_item(pt
,hf_diameter_flags_reserved4
,tvb
,4,1,ENC_BIG_ENDIAN
);
945 if(flags_bits
& 0x08) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
946 pi
= proto_tree_add_item(pt
,hf_diameter_flags_reserved5
,tvb
,4,1,ENC_BIG_ENDIAN
);
947 if(flags_bits
& 0x04) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
948 pi
= proto_tree_add_item(pt
,hf_diameter_flags_reserved6
,tvb
,4,1,ENC_BIG_ENDIAN
);
949 if(flags_bits
& 0x02) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
950 pi
= proto_tree_add_item(pt
,hf_diameter_flags_reserved7
,tvb
,4,1,ENC_BIG_ENDIAN
);
951 if(flags_bits
& 0x01) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
954 cmd_item
= proto_tree_add_item(diam_tree
,hf_diameter_code
,tvb
,5,3,ENC_BIG_ENDIAN
);
958 guint32 vendorid
= tvb_get_ntohl(tvb
,8);
961 if (! ( vendor
= (diam_vnd_t
*)wmem_tree_lookup32(dictionary
.vnds
,vendorid
) ) ) {
962 vendor
= &unknown_vendor
;
965 cmd_vs
= VND_CMD_VS(vendor
);
966 proto_tree_add_item(diam_tree
, hf_diameter_vendor_id
,tvb
,8,4,ENC_BIG_ENDIAN
);
968 c
->version_rfc
= FALSE
;
973 cmd_vs
= (value_string
*)(void *)all_cmds
->data
;
975 app_item
= proto_tree_add_item(diam_tree
, hf_diameter_application_id
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
977 if (try_val_to_str(diam_sub_dis_inf
->application_id
, dictionary
.applications
) == NULL
) {
978 proto_tree
*tu
= proto_item_add_subtree(app_item
,ett_unknown
);
979 proto_tree_add_expert_format(tu
, c
->pinfo
, &ei_diameter_application_id
, tvb
, 8, 4,
980 "Unknown Application Id (%u), if you know what this is you can add it to dictionary.xml", diam_sub_dis_inf
->application_id
);
983 c
->version_rfc
= TRUE
;
988 proto_tree
*pt
= proto_item_add_subtree(version_item
,ett_err
);
989 proto_tree_add_expert(pt
, pinfo
, &ei_diameter_version
, tvb
, 0, 1);
990 c
->version_rfc
= TRUE
;
991 cmd_vs
= VND_CMD_VS(&no_vnd
);
995 cmd_str
= val_to_str_const(cmd
, cmd_vs
, "Unknown");
997 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
998 "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
1000 ((flags_bits
>>4)&0x08) ? " Request" : " Answer",
1002 msgflags_str
[((flags_bits
>>4)&0x0f)],
1003 c
->version_rfc
? "appl" : "vend",
1004 val_to_str_const(diam_sub_dis_inf
->application_id
, c
->version_rfc
? dictionary
.applications
: vnd_short_vs
, "Unknown"),
1005 diam_sub_dis_inf
->application_id
,
1006 tvb_get_ntohl(tvb
,12),
1007 tvb_get_ntohl(tvb
,16));
1009 col_append_str(pinfo
->cinfo
, COL_INFO
, " | ");
1010 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1012 /* Append name to command item, warn if unknown */
1013 proto_item_append_text(cmd_item
," %s", cmd_str
);
1014 if (strcmp(cmd_str
, "Unknown") == 0) {
1015 proto_tree
*tu
= proto_item_add_subtree(cmd_item
,ett_unknown
);
1016 proto_tree_add_expert(tu
, c
->pinfo
, &ei_diameter_code
, tvb
, 5, 3);
1020 hop_by_hop_id
= tvb_get_ntohl(tvb
, 12);
1021 proto_tree_add_item(diam_tree
,hf_diameter_hopbyhopid
,tvb
,12,4,ENC_BIG_ENDIAN
);
1022 end_to_end_id
= tvb_get_ntohl(tvb
, 16);
1023 proto_tree_add_item(diam_tree
,hf_diameter_endtoendid
,tvb
,16,4,ENC_BIG_ENDIAN
);
1025 /* Conversation tracking stuff */
1027 * FIXME: Looking at epan/conversation.c it seems unlikely that this will work properly in
1028 * multi-homed SCTP connections. This will probably need to be fixed at some point.
1031 conversation
= find_or_create_conversation(pinfo
);
1033 diameter_conv_info
= (diameter_conv_info_t
*)conversation_get_proto_data(conversation
, proto_diameter
);
1034 if (!diameter_conv_info
) {
1035 diameter_conv_info
= wmem_new(wmem_file_scope(), diameter_conv_info_t
);
1036 diameter_conv_info
->pdus_tree
= wmem_tree_new(wmem_file_scope());
1038 conversation_add_proto_data(conversation
, proto_diameter
, diameter_conv_info
);
1041 /* pdus_tree is an wmem_tree keyed by frame number (in order to handle hop-by-hop collisions */
1042 pdus_tree
= (wmem_tree_t
*)wmem_tree_lookup32(diameter_conv_info
->pdus_tree
, hop_by_hop_id
);
1044 if (pdus_tree
== NULL
&& (flags_bits
& DIAM_FLAGS_R
)) {
1045 /* This is the first request we've seen with this hop-by-hop id */
1046 pdus_tree
= wmem_tree_new(wmem_file_scope());
1047 wmem_tree_insert32(diameter_conv_info
->pdus_tree
, hop_by_hop_id
, pdus_tree
);
1051 if (!pinfo
->fd
->flags
.visited
) {
1052 if (flags_bits
& DIAM_FLAGS_R
) {
1053 /* This is a request */
1054 diameter_pair
= wmem_new(wmem_file_scope(), diameter_req_ans_pair_t
);
1055 diameter_pair
->hop_by_hop_id
= hop_by_hop_id
;
1056 diameter_pair
->end_to_end_id
= end_to_end_id
;
1057 diameter_pair
->cmd_code
= cmd
;
1058 diameter_pair
->result_code
= 0;
1059 diameter_pair
->cmd_str
= cmd_str
;
1060 diameter_pair
->req_frame
= PINFO_FD_NUM(pinfo
);
1061 diameter_pair
->ans_frame
= 0;
1062 diameter_pair
->req_time
= pinfo
->fd
->abs_ts
;
1063 wmem_tree_insert32(pdus_tree
, PINFO_FD_NUM(pinfo
), (void *)diameter_pair
);
1065 /* Look for a request which occurs earlier in the trace than this answer. */
1066 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_tree_lookup32_le(pdus_tree
, PINFO_FD_NUM(pinfo
));
1068 /* Verify the end-to-end-id matches before declaring a match */
1069 if (diameter_pair
&& diameter_pair
->end_to_end_id
== end_to_end_id
) {
1070 diameter_pair
->ans_frame
= PINFO_FD_NUM(pinfo
);
1074 /* Look for a request which occurs earlier in the trace than this answer. */
1075 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_tree_lookup32_le(pdus_tree
, PINFO_FD_NUM(pinfo
));
1077 /* If the end-to-end ID doesn't match then this is not the request we were
1080 if (diameter_pair
&& diameter_pair
->end_to_end_id
!= end_to_end_id
)
1081 diameter_pair
= NULL
;
1085 if (!diameter_pair
) {
1086 /* create a "fake" diameter_pair structure */
1087 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_alloc(wmem_packet_scope(), sizeof(diameter_req_ans_pair_t
));
1088 diameter_pair
->hop_by_hop_id
= hop_by_hop_id
;
1089 diameter_pair
->cmd_code
= cmd
;
1090 diameter_pair
->result_code
= 0;
1091 diameter_pair
->cmd_str
= cmd_str
;
1092 diameter_pair
->req_frame
= 0;
1093 diameter_pair
->ans_frame
= 0;
1094 diameter_pair
->req_time
= pinfo
->fd
->abs_ts
;
1096 diameter_pair
->processing_request
=(flags_bits
& DIAM_FLAGS_R
)!=0;
1099 /* print state tracking info in the tree */
1100 if (flags_bits
& DIAM_FLAGS_R
) {
1101 /* This is a request */
1102 if (diameter_pair
->ans_frame
) {
1103 it
= proto_tree_add_uint(diam_tree
, hf_diameter_answer_in
,
1104 tvb
, 0, 0, diameter_pair
->ans_frame
);
1105 PROTO_ITEM_SET_GENERATED(it
);
1108 /* This is an answer */
1109 if (diameter_pair
->req_frame
) {
1110 it
= proto_tree_add_uint(diam_tree
, hf_diameter_answer_to
,
1111 tvb
, 0, 0, diameter_pair
->req_frame
);
1112 PROTO_ITEM_SET_GENERATED(it
);
1114 nstime_delta(&ns
, &pinfo
->fd
->abs_ts
, &diameter_pair
->req_time
);
1115 diameter_pair
->srt_time
= ns
;
1116 it
= proto_tree_add_time(diam_tree
, hf_diameter_answer_time
, tvb
, 0, 0, &ns
);
1117 PROTO_ITEM_SET_GENERATED(it
);
1118 /* TODO: Populate result_code in tap record from AVP 268 */
1124 /* Dissect AVPs until the end of the packet is reached */
1125 while (offset
< packet_len
) {
1126 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
);
1130 /* Handle requests for which no answers were found and
1131 * anawers for which no requests were found in the tap listener.
1132 * In case if you don't need unpaired requests/answers use:
1133 * if(diameter_pair->processing_request || !diameter_pair->req_frame)
1136 tap_queue_packet(diameter_tap
, pinfo
, diameter_pair
);
1138 if(have_tap_listener(exported_pdu_tap
)){
1139 export_diameter_pdu(pinfo
,tvb
);
1142 return tvb_length(tvb
);
1146 get_diameter_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
)
1148 /* Get the length of the Diameter packet. */
1149 return tvb_get_ntoh24(tvb
, offset
+ 1);
1153 check_diameter(tvbuff_t
*tvb
)
1155 if (tvb_length(tvb
) < 1)
1156 return FALSE
; /* not enough bytes to check the version */
1158 if (tvb_get_guint8(tvb
, 0) != 1)
1159 return FALSE
; /* not version 1 */
1162 * XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE?
1163 * Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits
1169 /************************************************/
1170 /* Main dissection function */
1172 dissect_diameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1174 if (!check_diameter(tvb
))
1176 return dissect_diameter_common(tvb
, pinfo
, tree
, data
);
1180 dissect_diameter_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
1182 /* Check if we have the start of a PDU or if this is segment */
1183 if (!check_diameter(tvb
)) {
1184 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1185 col_set_str(pinfo
->cinfo
, COL_INFO
, "Continuation");
1186 call_dissector(data_handle
, tvb
, pinfo
, tree
);
1188 tcp_dissect_pdus(tvb
, pinfo
, tree
, gbl_diameter_desegment
, 4,
1189 get_diameter_pdu_len
, dissect_diameter_common
, data
);
1192 return tvb_length(tvb
);
1197 alnumerize(char *name
)
1203 for (;(c
= *r
); r
++) {
1204 if (isalnum((unsigned char)c
) || c
== '_' || c
== '-' || c
== '.') {
1216 reginfo(int *hf_ptr
, const char *name
, const char *abbr
, const char *desc
,
1217 enum ftenum ft
, base_display_e base
, value_string_ext
*vs_ext
,
1220 hf_register_info hf
= { hf_ptr
, {
1221 name
? wmem_strdup(wmem_epan_scope(), name
) : wmem_strdup(wmem_epan_scope(), abbr
),
1222 wmem_strdup(wmem_epan_scope(), abbr
),
1227 wmem_strdup(wmem_epan_scope(), desc
),
1231 hf
.hfinfo
.strings
= vs_ext
;
1234 wmem_array_append_one(build_dict
.hf
,hf
);
1235 return wmem_array_get_count(build_dict
.hf
);
1239 basic_avp_reginfo(diam_avp_t
*a
, const char *name
, enum ftenum ft
,
1240 base_display_e base
, value_string_ext
*vs_ext
)
1242 hf_register_info hf
[] = { { &(a
->hf_value
),
1243 { NULL
, NULL
, ft
, base
, NULL
, 0x0,
1245 wmem_strdup_printf(wmem_epan_scope(), "vendor=%d code=%d", a
->vendor
->code
, a
->code
)
1246 : wmem_strdup_printf(wmem_epan_scope(), "code=%d", a
->code
),
1249 gint
*ettp
= &(a
->ett
);
1251 hf
->hfinfo
.name
= wmem_strdup_printf(wmem_epan_scope(), "%s",name
);
1252 hf
->hfinfo
.abbrev
= alnumerize(wmem_strdup_printf(wmem_epan_scope(), "diameter.%s",name
));
1254 hf
->hfinfo
.strings
= vs_ext
;
1257 wmem_array_append(build_dict
.hf
,hf
,1);
1258 g_ptr_array_add(build_dict
.ett
,ettp
);
1262 build_address_avp(const avp_type_t
*type _U_
, guint32 code
,
1263 const diam_vnd_t
*vendor
, const char *name
,
1264 const value_string
*vs _U_
, void *data _U_
)
1266 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1267 address_avp_t
*t
= wmem_new(wmem_epan_scope(), address_avp_t
);
1268 gint
*ettp
= &(t
->ett
);
1273 * It seems like the radius AVPs 1-255 will use the defs from RADIUS in which case:
1274 * http://www.ietf.org/rfc/rfc2865.txt?number=2865
1276 * The Address field is four octets. The value 0xFFFFFFFF indicates
1277 * that the NAS Should allow the user to select an address (e.g.
1278 * Negotiated). The value 0xFFFFFFFE indicates that the NAS should
1279 * select an address for the user (e.g. Assigned from a pool of
1280 * addresses kept by the NAS). Other valid values indicate that the
1281 * NAS should use that value as the user's IP address.
1283 * Where as in Diameter:
1286 * The Address format is derived from the OctetString AVP Base
1287 * Format. It is a discriminated union, representing, for example a
1288 * 32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1289 * significant octet first. The first two octets of the Address
1290 * AVP represents the AddressType, which contains an Address Family
1291 * defined in [IANAADFAM]. The AddressType is used to discriminate
1292 * the content and format of the remaining octets.
1294 a
->dissector_v16
= address_v16_avp
;
1296 a
->dissector_rfc
= address_v16_avp
;
1298 a
->dissector_rfc
= address_rfc_avp
;
1305 t
->hf_address_type
= -1;
1310 basic_avp_reginfo(a
,name
,FT_BYTES
,BASE_NONE
,NULL
);
1312 reginfo(&(t
->hf_address_type
), ep_strdup_printf("%s Address Family",name
),
1313 alnumerize(ep_strdup_printf("diameter.%s.addr_family",name
)),
1314 NULL
, FT_UINT16
, (base_display_e
)(BASE_DEC
|BASE_EXT_STRING
), &diameter_avp_data_addrfamily_vals_ext
, 0);
1316 reginfo(&(t
->hf_ipv4
), ep_strdup_printf("%s Address",name
),
1317 alnumerize(ep_strdup_printf("diameter.%s.IPv4",name
)),
1318 NULL
, FT_IPv4
, BASE_NONE
, NULL
, 0);
1320 reginfo(&(t
->hf_ipv6
), ep_strdup_printf("%s Address",name
),
1321 alnumerize(ep_strdup_printf("diameter.%s.IPv6",name
)),
1322 NULL
, FT_IPv6
, BASE_NONE
, NULL
, 0);
1324 reginfo(&(t
->hf_other
), ep_strdup_printf("%s Address",name
),
1325 alnumerize(ep_strdup_printf("diameter.%s.Bytes",name
)),
1326 NULL
, FT_BYTES
, BASE_NONE
, NULL
, 0);
1328 g_ptr_array_add(build_dict
.ett
,ettp
);
1334 build_proto_avp(const avp_type_t
*type _U_
, guint32 code
,
1335 const diam_vnd_t
*vendor
, const char *name _U_
,
1336 const value_string
*vs _U_
, void *data
)
1338 diam_avp_t
*a
= (diam_avp_t
*)g_malloc0(sizeof(diam_avp_t
));
1339 proto_avp_t
*t
= (proto_avp_t
*)g_malloc0(sizeof(proto_avp_t
));
1340 gint
*ettp
= &(a
->ett
);
1344 a
->dissector_v16
= proto_avp
;
1345 a
->dissector_rfc
= proto_avp
;
1350 t
->name
= (char *)data
;
1352 t
->reassemble_mode
= REASEMBLE_NEVER
;
1354 g_ptr_array_add(build_dict
.ett
,ettp
);
1360 build_simple_avp(const avp_type_t
*type
, guint32 code
, const diam_vnd_t
*vendor
,
1361 const char *name
, const value_string
*vs
, void *data _U_
)
1364 value_string_ext
*vs_ext
= NULL
;
1365 base_display_e base
;
1369 * Only 32-bit or shorter integral types can have a list of values.
1371 base
= (base_display_e
)type
->base
;
1384 fprintf(stderr
,"Diameter Dictionary: AVP '%s' has a list of values but isn't of a 32-bit or shorter integral type\n",
1388 while (vs
[i
].strptr
) {
1391 vs_ext
= value_string_ext_new((value_string
*)vs
, i
+1, wmem_strdup_printf(wmem_epan_scope(), "%s_vals_ext",name
));
1392 base
= (base_display_e
)(base
|BASE_EXT_STRING
);
1395 a
= (diam_avp_t
*)wmem_alloc0(wmem_epan_scope(), sizeof(diam_avp_t
));
1398 a
->dissector_v16
= type
->v16
;
1399 a
->dissector_rfc
= type
->rfc
;
1403 basic_avp_reginfo(a
,name
,type
->ft
,base
,vs_ext
);
1410 static const avp_type_t basic_types
[] = {
1411 {"octetstring" , simple_avp
, simple_avp
, FT_BYTES
, BASE_NONE
, build_simple_avp
},
1412 {"utf8string" , utf8_avp
, utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
1413 {"grouped" , grouped_avp
, grouped_avp
, FT_BYTES
, BASE_NONE
, build_simple_avp
},
1414 {"integer32" , integer32_avp
, integer32_avp
, FT_INT32
, BASE_DEC
, build_simple_avp
},
1415 {"unsigned32" , unsigned32_avp
, unsigned32_avp
, FT_UINT32
, BASE_DEC
, build_simple_avp
},
1416 {"integer64" , integer64_avp
, integer64_avp
, FT_INT64
, BASE_DEC
, build_simple_avp
},
1417 {"unsigned64" , unsigned64_avp
, unsigned64_avp
, FT_UINT64
, BASE_DEC
, build_simple_avp
},
1418 {"float32" , float32_avp
, float32_avp
, FT_FLOAT
, BASE_NONE
, build_simple_avp
},
1419 {"float64" , float64_avp
, float64_avp
, FT_DOUBLE
, BASE_NONE
, build_simple_avp
},
1420 {"ipaddress" , NULL
, NULL
, FT_NONE
, BASE_NONE
, build_address_avp
},
1421 {"diameteruri" , utf8_avp
, utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
1422 {"diameteridentity" , utf8_avp
, utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
1423 {"ipfilterrule" , utf8_avp
, utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
1424 {"qosfilterrule" , utf8_avp
, utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
1425 {"time" , time_avp
, time_avp
, FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_UTC
, build_simple_avp
},
1426 {NULL
, NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
}
1432 * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
1433 * upper-case ASCII characters to their ASCII lower-case equivalents.
1434 * We can't use g_strdown(), as that doesn't do an ASCII mapping;
1435 * in Turkish locales, for example, there are two lower-case "i"s
1436 * and two upper-case "I"s, with and without dots - the ones with
1437 * dots map between each other, as do the ones without dots, so "I"
1438 * doesn't map to "i".
1441 strcase_hash(gconstpointer key
)
1443 const char *p
= (const char *)key
;
1448 if (h
>= 'A' && h
<= 'Z')
1450 for (p
+= 1; *p
!= '\0'; p
++) {
1452 if (c
>= 'A' && c
<= 'Z')
1454 h
= (h
<< 5) - h
+ c
;
1462 * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
1463 * letters are mapped, and they're mapped to the lower-case ASCII
1467 strcase_equal(gconstpointer ka
, gconstpointer kb
)
1469 const char *a
= (const char *)ka
;
1470 const char *b
= (const char *)kb
;
1471 return g_ascii_strcasecmp(a
,b
) == 0;
1475 /* Note: Dynamic "value string arrays" (e.g., vs_cmds, vs_avps, ...) are constructed using */
1476 /* "zero-terminated" GArrays so that they will have the same form as standard */
1477 /* value_string arrays created at compile time. Since the last entry in a */
1478 /* value_string array must be {0, NULL}, we are assuming that NULL == 0 (hackish). */
1481 dictionary_load(void)
1484 ddict_application_t
*p
;
1487 ddict_typedefn_t
*t
;
1489 gboolean do_debug_parser
= getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? TRUE
: FALSE
;
1490 gboolean do_dump_dict
= getenv("WIRESHARK_DUMP_DIAM_DICT") ? TRUE
: FALSE
;
1491 char *dir
= ep_strdup_printf("%s" G_DIR_SEPARATOR_S
"diameter" G_DIR_SEPARATOR_S
, get_datafile_dir());
1492 const avp_type_t
*type
;
1493 const avp_type_t
*octetstring
= &basic_types
[0];
1495 GHashTable
*vendors
= g_hash_table_new(strcase_hash
,strcase_equal
);
1497 GArray
*vnd_shrt_arr
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1499 build_dict
.hf
= wmem_array_new(wmem_epan_scope(),sizeof(hf_register_info
));
1500 build_dict
.ett
= g_ptr_array_new();
1501 build_dict
.types
= g_hash_table_new(strcase_hash
,strcase_equal
);
1502 build_dict
.avps
= g_hash_table_new(strcase_hash
,strcase_equal
);
1504 dictionary
.vnds
= wmem_tree_new(wmem_epan_scope());
1505 dictionary
.avps
= wmem_tree_new(wmem_epan_scope());
1507 unknown_vendor
.vs_cmds
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1508 unknown_vendor
.vs_avps
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1509 no_vnd
.vs_cmds
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1510 no_vnd
.vs_avps
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1512 all_cmds
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1514 wmem_tree_insert32(dictionary
.vnds
,0,&no_vnd
);
1515 g_hash_table_insert(vendors
,(gchar
*)"None",&no_vnd
);
1517 /* initialize the types hash with the known basic types */
1518 for (type
= basic_types
; type
->name
; type
++) {
1519 g_hash_table_insert(build_dict
.types
,(gchar
*)type
->name
,(void *)type
);
1522 /* load the dictionary */
1523 d
= ddict_scan(dir
,"dictionary.xml",do_debug_parser
);
1528 if (do_dump_dict
) ddict_print(stdout
, d
);
1530 /* populate the types */
1531 for (t
= d
->typedefns
; t
; t
= t
->next
) {
1532 const avp_type_t
*parent
= NULL
;
1533 /* try to get the parent type */
1535 if (t
->name
== NULL
) {
1536 fprintf(stderr
,"Diameter Dictionary: Invalid Type (empty name): parent==%s\n",
1537 t
->parent
? t
->parent
: "(null)");
1542 if (g_hash_table_lookup(build_dict
.types
,t
->name
))
1546 parent
= (avp_type_t
*)g_hash_table_lookup(build_dict
.types
,t
->parent
);
1549 if (!parent
) parent
= octetstring
;
1551 /* insert the parent type for this type */
1552 g_hash_table_insert(build_dict
.types
,t
->name
,(void *)parent
);
1555 /* populate the applications */
1556 if ((p
= d
->applications
)) {
1557 GArray
*arr
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1559 for (; p
; p
= p
->next
) {
1560 value_string item
= {p
->code
,p
->name
};
1561 g_array_append_val(arr
,item
);
1564 dictionary
.applications
= (value_string
*)arr
->data
;
1565 g_array_free(arr
,FALSE
);
1568 if ((v
= d
->vendors
)) {
1569 for ( ; v
; v
= v
->next
) {
1570 value_string item
= {v
->code
,v
->name
};
1572 if (v
->name
== NULL
) {
1573 fprintf(stderr
,"Diameter Dictionary: Invalid Vendor (empty name): code==%d\n",v
->code
);
1577 if (g_hash_table_lookup(vendors
,v
->name
))
1580 g_array_append_val(vnd_shrt_arr
,item
);
1582 vnd
= wmem_new(wmem_epan_scope(), diam_vnd_t
);
1583 vnd
->code
= v
->code
;
1584 vnd
->vs_cmds
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1585 vnd
->vs_avps
= g_array_new(TRUE
,TRUE
,sizeof(value_string
));
1586 vnd
->vs_avps_ext
= NULL
;
1587 wmem_tree_insert32(dictionary
.vnds
,vnd
->code
,vnd
);
1588 g_hash_table_insert(vendors
,v
->name
,vnd
);
1592 vnd_short_vs
= (value_string
*)vnd_shrt_arr
->data
;
1593 g_array_free(vnd_shrt_arr
,FALSE
);
1595 if ((c
= d
->cmds
)) {
1596 for (; c
; c
= c
->next
) {
1597 if (c
->vendor
== NULL
) {
1598 fprintf(stderr
,"Diameter Dictionary: Invalid Vendor (empty name) for command %s\n",
1599 c
->name
? c
->name
: "(null)");
1603 if ((vnd
= (diam_vnd_t
*)g_hash_table_lookup(vendors
,c
->vendor
))) {
1604 value_string item
= {c
->code
,c
->name
};
1605 g_array_append_val(vnd
->vs_cmds
,item
);
1606 /* Also add to all_cmds as used by RFC version */
1607 g_array_append_val(all_cmds
,item
);
1609 fprintf(stderr
,"Diameter Dictionary: No Vendor: %s\n",c
->vendor
);
1615 for (a
= d
->avps
; a
; a
= a
->next
) {
1617 value_string
*vs
= NULL
;
1618 const char *vend
= a
->vendor
? a
->vendor
: "None";
1620 void *avp_data
= NULL
;
1622 if (a
->name
== NULL
) {
1623 fprintf(stderr
,"Diameter Dictionary: Invalid AVP (empty name)\n");
1627 if ((vnd
= (diam_vnd_t
*)g_hash_table_lookup(vendors
,vend
))) {
1628 value_string vndvs
= {a
->code
,a
->name
};
1629 g_array_append_val(vnd
->vs_avps
,vndvs
);
1631 fprintf(stderr
,"Diameter Dictionary: No Vendor: %s\n",vend
);
1632 vnd
= &unknown_vendor
;
1635 if ((e
= a
->enums
)) {
1636 wmem_array_t
*arr
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
1637 value_string term
= {0, NULL
};
1639 for (; e
; e
= e
->next
) {
1640 value_string item
= {e
->code
,e
->name
};
1641 wmem_array_append_one(arr
,item
);
1643 wmem_array_sort(arr
, compare_avps
);
1644 wmem_array_append_one(arr
,term
);
1645 vs
= (value_string
*)wmem_array_get_raw(arr
);
1650 for( x
= d
->xmlpis
; x
; x
= x
->next
) {
1651 if ( (strcase_equal(x
->name
,"avp-proto") && strcase_equal(x
->key
,a
->name
))
1652 || (a
->type
&& strcase_equal(x
->name
,"type-proto") && strcase_equal(x
->key
,a
->type
))
1654 static avp_type_t proto_type
= {"proto", proto_avp
, proto_avp
, FT_UINT32
, BASE_HEX
, build_proto_avp
};
1657 avp_data
= x
->value
;
1662 if ( (!type
) && a
->type
)
1663 type
= (avp_type_t
*)g_hash_table_lookup(build_dict
.types
,a
->type
);
1665 if (!type
) type
= octetstring
;
1667 avp
= type
->build( type
, a
->code
, vnd
, a
->name
, vs
, avp_data
);
1669 g_hash_table_insert(build_dict
.avps
, a
->name
, avp
);
1672 wmem_tree_key_t k
[] = {
1674 { 1, &(vnd
->code
) },
1677 wmem_tree_insert32_array(dictionary
.avps
,k
,avp
);
1681 g_hash_table_destroy(build_dict
.types
);
1682 g_hash_table_destroy(build_dict
.avps
);
1683 g_hash_table_destroy(vendors
);
1688 /* registration with the filtering engine */
1689 void proto_reg_handoff_diameter(void);
1692 * This does most of the registration work; see proto_register_diameter()
1693 * for the reason why we split it off.
1696 real_proto_register_diameter(void)
1698 module_t
*diameter_module
;
1699 expert_module_t
* expert_diameter
;
1700 guint i
, ett_length
;
1702 hf_register_info hf_base
[] = {
1703 { &hf_diameter_version
,
1704 { "Version", "diameter.version", FT_UINT8
, BASE_HEX
, NULL
, 0x00,
1706 { &hf_diameter_length
,
1707 { "Length","diameter.length", FT_UINT24
, BASE_DEC
, NULL
, 0x0,
1709 { &hf_diameter_flags
,
1710 { "Flags", "diameter.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1712 { &hf_diameter_flags_request
,
1713 { "Request", "diameter.flags.request", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_R
,
1715 { &hf_diameter_flags_proxyable
,
1716 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_P
,
1718 { &hf_diameter_flags_error
,
1719 { "Error","diameter.flags.error", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_E
,
1721 { &hf_diameter_flags_T
,
1722 { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_T
,
1724 { &hf_diameter_flags_reserved4
,
1725 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1726 DIAM_FLAGS_RESERVED4
, NULL
, HFILL
}},
1727 { &hf_diameter_flags_reserved5
,
1728 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1729 DIAM_FLAGS_RESERVED5
, NULL
, HFILL
}},
1730 { &hf_diameter_flags_reserved6
,
1731 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1732 DIAM_FLAGS_RESERVED6
, NULL
, HFILL
}},
1733 { &hf_diameter_flags_reserved7
,
1734 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1735 DIAM_FLAGS_RESERVED7
, NULL
, HFILL
}},
1736 { &hf_diameter_vendor_id
,
1737 { "VendorId", "diameter.vendorId", FT_UINT32
, BASE_DEC
|BASE_EXT_STRING
, &sminmpec_values_ext
,
1738 0x0, NULL
, HFILL
}},
1739 { &hf_diameter_application_id
,
1740 { "ApplicationId", "diameter.applicationId", FT_UINT32
, BASE_DEC
, VALS(dictionary
.applications
),
1741 0x0, NULL
, HFILL
}},
1742 { &hf_diameter_hopbyhopid
,
1743 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32
,
1744 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1745 { &hf_diameter_endtoendid
,
1746 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32
,
1747 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1749 { "AVP","diameter.avp", FT_BYTES
, BASE_NONE
,
1750 NULL
, 0x0, NULL
, HFILL
}},
1751 { &hf_diameter_avp_len
,
1752 { "AVP Length","diameter.avp.len", FT_UINT24
, BASE_DEC
,
1753 NULL
, 0x0, NULL
, HFILL
}},
1754 { &hf_diameter_avp_code
,
1755 { "AVP Code", "diameter.avp.code", FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
1756 { &hf_diameter_avp_flags
,
1757 { "AVP Flags","diameter.avp.flags", FT_UINT8
, BASE_HEX
,
1758 NULL
, 0x0, NULL
, HFILL
}},
1759 { &hf_diameter_avp_flags_vendor_specific
,
1760 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_V
,
1762 { &hf_diameter_avp_flags_mandatory
,
1763 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_M
,
1765 { &hf_diameter_avp_flags_protected
,
1766 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_P
,
1768 { &hf_diameter_avp_flags_reserved3
,
1769 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1770 AVP_FLAGS_RESERVED3
, NULL
, HFILL
}},
1771 { &hf_diameter_avp_flags_reserved4
,
1772 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1773 AVP_FLAGS_RESERVED4
, NULL
, HFILL
}},
1774 { &hf_diameter_avp_flags_reserved5
,
1775 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1776 AVP_FLAGS_RESERVED5
, NULL
, HFILL
}},
1777 { &hf_diameter_avp_flags_reserved6
,
1778 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1779 AVP_FLAGS_RESERVED6
, NULL
, HFILL
}},
1780 { &hf_diameter_avp_flags_reserved7
,
1781 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
1782 AVP_FLAGS_RESERVED7
, NULL
, HFILL
}},
1783 { &hf_diameter_avp_vendor_id
,
1784 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32
, BASE_DEC
|BASE_EXT_STRING
,
1785 &sminmpec_values_ext
, 0x0, NULL
, HFILL
}},
1786 { &(unknown_avp
.hf_value
),
1787 { "Value","diameter.avp.unknown", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1788 { &hf_diameter_avp_data_wrong_length
,
1789 { "Data","diameter.avp.invalid-data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1790 { &hf_diameter_avp_pad
,
1791 { "Padding","diameter.avp.pad", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1792 { &hf_diameter_code
,
1793 { "Command Code", "diameter.cmd.code", FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
1794 { &hf_diameter_answer_in
,
1795 { "Answer In", "diameter.answer_in", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1796 "The answer to this diameter request is in this frame", HFILL
}},
1797 { &hf_diameter_answer_to
,
1798 { "Request In", "diameter.answer_to", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1799 "This is an answer to the diameter request in this frame", HFILL
}},
1800 { &hf_diameter_answer_time
,
1801 { "Response Time", "diameter.resp_time", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
1802 "The time between the request and the answer", HFILL
}},
1803 { &hf_framed_ipv6_prefix_reserved
,
1804 { "Framed IPv6 Prefix Reserved byte", "diameter.framed_ipv6_prefix_reserved",
1805 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1806 { &hf_framed_ipv6_prefix_length
,
1807 { "Framed IPv6 Prefix length (in bits)", "diameter.framed_ipv6_prefix_length",
1808 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
1809 { &hf_framed_ipv6_prefix_bytes
,
1810 { "Framed IPv6 Prefix as a bytestring", "diameter.framed_ipv6_prefix_bytes",
1811 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1812 { &hf_framed_ipv6_prefix_ipv6
,
1813 { "Framed IPv6 Prefix as an IPv6 address", "diameter.framed_ipv6_prefix_ipv6",
1814 FT_IPv6
, BASE_NONE
, NULL
, 0, "This field is present only if the prefix length is 128", HFILL
}}
1817 gint
*ett_base
[] = {
1819 &ett_diameter_flags
,
1820 &ett_diameter_avp_flags
,
1821 &ett_diameter_avpinfo
,
1827 static ei_register_info ei
[] = {
1828 { &ei_diameter_reserved_bit_set
, { "diameter.reserved_bit_set", PI_MALFORMED
, PI_WARN
, "Reserved bit set", EXPFILL
}},
1829 { &ei_diameter_avp_code
, { "diameter.avp.code.unknown", PI_UNDECODED
, PI_WARN
, "Unknown AVP, if you know what this is you can add it to dictionary.xml", EXPFILL
}},
1830 { &ei_diameter_avp_vendor_id
, { "diameter.unknown_vendor", PI_UNDECODED
, PI_WARN
, "Unknown Vendor, if you know whose this is you can add it to dictionary.xml", EXPFILL
}},
1831 { &ei_diameter_avp_no_data
, { "diameter.avp.no_data", PI_UNDECODED
, PI_WARN
, "Data is empty", EXPFILL
}},
1832 { &ei_diameter_avp_pad
, { "diameter.avp.pad.non_zero", PI_MALFORMED
, PI_NOTE
, "Padding is non-zero", EXPFILL
}},
1833 { &ei_diameter_avp_len
, { "diameter.avp.invalid-len", PI_MALFORMED
, PI_WARN
, "Wrong length", EXPFILL
}},
1834 { &ei_diameter_application_id
, { "diameter.applicationId.unknown", PI_UNDECODED
, PI_WARN
, "Unknown Application Id, if you know what this is you can add it to dictionary.xml", EXPFILL
}},
1835 { &ei_diameter_version
, { "diameter.version.unknown", PI_UNDECODED
, PI_WARN
, "Unknown Diameter Version (decoding as RFC 3588)", EXPFILL
}},
1836 { &ei_diameter_code
, { "diameter.cmd.code.unknown", PI_UNDECODED
, PI_WARN
, "Unknown command, if you know what this is you can add it to dictionary.xml", EXPFILL
}},
1839 wmem_array_append(build_dict
.hf
, hf_base
, array_length(hf_base
));
1840 ett_length
= array_length(ett_base
);
1841 for (i
= 0; i
< ett_length
; i
++) {
1842 g_ptr_array_add(build_dict
.ett
, ett_base
[i
]);
1845 proto_diameter
= proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter");
1847 proto_register_field_array(proto_diameter
, (hf_register_info
*)wmem_array_get_raw(build_dict
.hf
), wmem_array_get_count(build_dict
.hf
));
1848 proto_register_subtree_array((gint
**)build_dict
.ett
->pdata
, build_dict
.ett
->len
);
1849 expert_diameter
= expert_register_protocol(proto_diameter
);
1850 expert_register_field_array(expert_diameter
, ei
, array_length(ei
));
1852 g_ptr_array_free(build_dict
.ett
,TRUE
);
1854 /* Allow dissector to find be found by name. */
1855 new_register_dissector("diameter", dissect_diameter
, proto_diameter
);
1857 /* Register dissector table(s) to do sub dissection of AVPs (OctetStrings) */
1858 diameter_dissector_table
= register_dissector_table("diameter.base", "DIAMETER_BASE_AVPS", FT_UINT32
, BASE_DEC
);
1859 diameter_3gpp_avp_dissector_table
= register_dissector_table("diameter.3gpp", "DIAMETER_3GPP_AVPS", FT_UINT32
, BASE_DEC
);
1860 diameter_ericsson_avp_dissector_table
= register_dissector_table("diameter.ericsson", "DIAMETER_ERICSSON_AVPS", FT_UINT32
, BASE_DEC
);
1862 /* Set default TCP ports */
1863 range_convert_str(&global_diameter_tcp_port_range
, DEFAULT_DIAMETER_PORT_RANGE
, MAX_UDP_PORT
);
1864 range_convert_str(&global_diameter_sctp_port_range
, DEFAULT_DIAMETER_PORT_RANGE
, MAX_SCTP_PORT
);
1865 range_convert_str(&global_diameter_udp_port_range
, "", MAX_UDP_PORT
);
1867 /* Register configuration options for ports */
1868 diameter_module
= prefs_register_protocol(proto_diameter
,
1869 proto_reg_handoff_diameter
);
1871 prefs_register_range_preference(diameter_module
, "tcp.ports", "Diameter TCP ports",
1872 "TCP ports to be decoded as Diameter (default: "
1873 DEFAULT_DIAMETER_PORT_RANGE
")",
1874 &global_diameter_tcp_port_range
, MAX_UDP_PORT
);
1876 prefs_register_range_preference(diameter_module
, "sctp.ports",
1877 "Diameter SCTP Ports",
1878 "SCTP ports to be decoded as Diameter (default: "
1879 DEFAULT_DIAMETER_PORT_RANGE
")",
1880 &global_diameter_sctp_port_range
, MAX_SCTP_PORT
);
1882 /* Desegmentation */
1883 prefs_register_bool_preference(diameter_module
, "desegment",
1884 "Reassemble Diameter messages\nspanning multiple TCP segments",
1885 "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
1886 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1887 &gbl_diameter_desegment
);
1889 prefs_register_range_preference(diameter_module
, "udp.ports", "Diameter UDP ports",
1890 "UDP ports to be decoded as Diameter (default: 0 as Diameter over UDP is nonstandard)",
1891 &global_diameter_udp_port_range
, MAX_UDP_PORT
);
1894 /* Register some preferences we no longer support, so we can report
1895 * them as obsolete rather than just illegal.
1897 prefs_register_obsolete_preference(diameter_module
, "version");
1898 prefs_register_obsolete_preference(diameter_module
, "tcp.port");
1899 prefs_register_obsolete_preference(diameter_module
, "sctp.port");
1900 prefs_register_obsolete_preference(diameter_module
, "command_in_header");
1901 prefs_register_obsolete_preference(diameter_module
, "dictionary.name");
1902 prefs_register_obsolete_preference(diameter_module
, "dictionary.use");
1903 prefs_register_obsolete_preference(diameter_module
, "allow_zero_as_app_id");
1904 prefs_register_obsolete_preference(diameter_module
, "suppress_console_output");
1907 diameter_tap
= register_tap("diameter");
1911 proto_register_diameter(void)
1914 * The hf_base[] array for Diameter refers to a variable
1915 * that is set by dictionary_load(), so we need to call
1916 * dictionary_load() before hf_base[] is initialized.
1918 * To ensure that, we call dictionary_load() and then
1919 * call a routine that defines hf_base[] and does all
1920 * the registration work.
1923 real_proto_register_diameter();
1924 } /* proto_register_diameter */
1927 proto_reg_handoff_diameter(void)
1929 static gboolean Initialized
=FALSE
;
1930 static range_t
*diameter_tcp_port_range
;
1931 static range_t
*diameter_sctp_port_range
;
1932 static range_t
*diameter_udp_port_range
;
1935 diameter_sctp_handle
= find_dissector("diameter");
1936 diameter_tcp_handle
= new_create_dissector_handle(dissect_diameter_tcp
,
1938 diameter_udp_handle
= new_create_dissector_handle(dissect_diameter
, proto_diameter
);
1939 data_handle
= find_dissector("data");
1940 eap_handle
= find_dissector("eap");
1942 dissector_add_uint("sctp.ppi", DIAMETER_PROTOCOL_ID
, diameter_sctp_handle
);
1944 /* Register special decoding for some AVPs */
1945 /* AVP Code: 97 Framed-IPv6-Address */
1946 dissector_add_uint("diameter.base", 97,
1947 new_create_dissector_handle(dissect_diameter_base_framed_ipv6_prefix
, proto_diameter
));
1948 /* AVP Code: 266 Vendor-Id */
1949 dissector_add_uint("diameter.base", 266,
1950 new_create_dissector_handle(dissect_diameter_vendor_id
, proto_diameter
));
1951 /* AVP Code: 462 EAP-Payload */
1952 dissector_add_uint("diameter.base", 462,
1953 new_create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
1954 /* AVP Code: 463 EAP-Reissued-Payload */
1955 dissector_add_uint("diameter.base", 463,
1956 new_create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
1960 dissector_delete_uint_range("tcp.port", diameter_tcp_port_range
, diameter_tcp_handle
);
1961 dissector_delete_uint_range("sctp.port", diameter_sctp_port_range
, diameter_sctp_handle
);
1962 dissector_delete_uint_range("udp.port", diameter_udp_port_range
, diameter_udp_handle
);
1963 g_free(diameter_tcp_port_range
);
1964 g_free(diameter_sctp_port_range
);
1965 g_free(diameter_udp_port_range
);
1968 /* set port for future deletes */
1969 diameter_tcp_port_range
= range_copy(global_diameter_tcp_port_range
);
1970 diameter_sctp_port_range
= range_copy(global_diameter_sctp_port_range
);
1971 diameter_udp_port_range
= range_copy(global_diameter_udp_port_range
);
1972 dissector_add_uint_range("tcp.port", diameter_tcp_port_range
, diameter_tcp_handle
);
1973 dissector_add_uint_range("sctp.port", diameter_sctp_port_range
, diameter_sctp_handle
);
1974 dissector_add_uint_range("udp.port", diameter_udp_port_range
, diameter_udp_handle
);
1976 exported_pdu_tap
= find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7
);