2 * Routines for Diameter packet disassembly
4 * Copyright (c) 2001 by David Frascone <dave@frascone.com>
5 * Copyright (c) 2007 by Luis E. Garcia Ontanon <luis@ontanon.org>
7 * Support for Request-Answer tracking and Tapping
8 * introduced by Abhik Sarkar
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
18 * RFC 3588, "Diameter Base Protocol" (now RFC 6733)
19 * draft-ietf-aaa-diameter-mobileip-16, "Diameter Mobile IPv4 Application"
21 * draft-ietf-aaa-diameter-nasreq-14, "Diameter Network Access Server
22 * Application" (now RFC 4005)
23 * drafts/draft-ietf-aaa-diameter-cc-03, "Diameter Credit-Control
24 * Application" (now RFC 4006)
25 * draft-ietf-aaa-diameter-sip-app-01, "Diameter Session Initiation
26 * Protocol (SIP) Application" (now RFC 4740)
27 * RFC 5779, "Diameter Proxy Mobile IPv6: Mobile Access Gateway and
28 * Local Mobility Anchor Interaction with Diameter Server"
29 * 3GPP TS 29.273, V15.2.0
30 * http://www.ietf.org/html.charters/aaa-charter.html
31 * http://www.iana.org/assignments/radius-types
32 * http://www.iana.org/assignments/address-family-numbers
33 * http://www.iana.org/assignments/enterprise-numbers
34 * http://www.iana.org/assignments/aaa-parameters
39 #include <epan/packet.h>
40 #include <epan/exceptions.h>
41 #include <epan/prefs.h>
42 #include <epan/sminmpec.h>
43 #include <epan/addr_resolv.h>
44 #include <epan/expert.h>
46 #include <epan/srt_table.h>
47 #include <epan/exported_pdu.h>
48 #include <epan/diam_dict.h>
49 #include <epan/sctpppids.h>
50 #include <epan/show_exception.h>
51 #include <epan/to_str.h>
52 #include <epan/strutil.h>
55 #include <wsutil/filesystem.h>
56 #include <wsutil/report_message.h>
57 #include "packet-tcp.h"
58 #include "packet-diameter.h"
59 #include "packet-tls.h"
60 #include "packet-dtls.h"
61 #include "packet-e212.h"
62 #include "packet-e164.h"
63 #include "packet-eap.h"
65 void proto_register_diameter(void);
66 void proto_reg_handoff_diameter(void);
68 /* Diameter Header Flags */
69 /* RPETrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
70 #define DIAM_FLAGS_R 0x80
71 #define DIAM_FLAGS_P 0x40
72 #define DIAM_FLAGS_E 0x20
73 #define DIAM_FLAGS_T 0x10
74 #define DIAM_FLAGS_RESERVED4 0x08
75 #define DIAM_FLAGS_RESERVED5 0x04
76 #define DIAM_FLAGS_RESERVED6 0x02
77 #define DIAM_FLAGS_RESERVED7 0x01
78 #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)
89 /* Diameter AVP Flags */
90 #define AVP_FLAGS_P 0x20
91 #define AVP_FLAGS_V 0x80
92 #define AVP_FLAGS_M 0x40
93 #define AVP_FLAGS_RESERVED3 0x10
94 #define AVP_FLAGS_RESERVED4 0x08
95 #define AVP_FLAGS_RESERVED5 0x04
96 #define AVP_FLAGS_RESERVED6 0x02
97 #define AVP_FLAGS_RESERVED7 0x01
98 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */
100 #define DIAMETER_RFC 1
102 static int exported_pdu_tap
= -1;
104 /* Conversation Info */
105 typedef struct _diameter_conv_info_t
{
106 wmem_map_t
*pdu_trees
;
107 } diameter_conv_info_t
;
109 typedef struct _diam_ctx_t
{
115 typedef struct _diam_avp_t diam_avp_t
;
116 typedef struct _avp_type_t avp_type_t
;
118 typedef const char *(*diam_avp_dissector_t
)(diam_ctx_t
*, diam_avp_t
*, tvbuff_t
*, diam_sub_dis_t
*);
121 typedef struct _diam_vnd_t
{
123 wmem_array_t
*vs_avps
;
124 value_string_ext
*vs_avps_ext
;
130 diam_avp_dissector_t dissector_rfc
;
137 #define VND_AVP_VS(v) ((value_string *)(void *)(wmem_array_get_raw((v)->vs_avps)))
138 #define VND_AVP_VS_LEN(v) (wmem_array_get_count((v)->vs_avps))
140 typedef struct _diam_dictionary_t
{
143 value_string_ext
*applications
;
144 value_string
*commands
;
147 typedef diam_avp_t
*(*avp_constructor_t
)(const avp_type_t
*, uint32_t, diam_vnd_t
*, const char *, const value_string
*, void *);
151 diam_avp_dissector_t rfc
;
154 avp_constructor_t build
;
165 typedef struct _address_avp_t
{
178 } avp_reassemble_mode_t
;
180 typedef struct _proto_avp_t
{
182 dissector_handle_t handle
;
183 avp_reassemble_mode_t reassemble_mode
;
186 static const char *simple_avp(diam_ctx_t
*, diam_avp_t
*, tvbuff_t
*, diam_sub_dis_t
*);
188 static diam_vnd_t unknown_vendor
= { 0xffffffff, NULL
, NULL
};
189 static diam_vnd_t no_vnd
= { 0, NULL
, NULL
};
190 static diam_avp_t unknown_avp
= {0, &unknown_vendor
, simple_avp
, -1, -1, NULL
};
191 static const value_string
*cmd_vs
;
192 static diam_dictionary_t dictionary
= { NULL
, NULL
, NULL
, NULL
};
193 static struct _build_dict build_dict
;
194 static const value_string
*vnd_short_vs
;
195 static dissector_handle_t data_handle
;
196 static dissector_handle_t eap_handle
;
198 static const value_string diameter_avp_data_addrfamily_vals
[]= {
215 {17,"DistinguishedName"},
220 {22,"FibrePortName"},
221 {23,"FibreNodeName"},
225 static value_string_ext diameter_avp_data_addrfamily_vals_ext
= VALUE_STRING_EXT_INIT(diameter_avp_data_addrfamily_vals
);
227 static int proto_diameter
;
228 static int hf_diameter_length
;
229 static int hf_diameter_code
;
230 static int hf_diameter_hopbyhopid
;
231 static int hf_diameter_endtoendid
;
232 static int hf_diameter_version
;
233 static int hf_diameter_vendor_id
;
234 static int hf_diameter_application_id
;
235 static int hf_diameter_flags
;
236 static int hf_diameter_flags_request
;
237 static int hf_diameter_flags_proxyable
;
238 static int hf_diameter_flags_error
;
239 static int hf_diameter_flags_T
;
240 static int hf_diameter_flags_reserved4
;
241 static int hf_diameter_flags_reserved5
;
242 static int hf_diameter_flags_reserved6
;
243 static int hf_diameter_flags_reserved7
;
245 static int hf_diameter_avp
;
246 static int hf_diameter_avp_len
;
247 static int hf_diameter_avp_code
;
248 static int hf_diameter_avp_flags
;
249 static int hf_diameter_avp_flags_vendor_specific
;
250 static int hf_diameter_avp_flags_mandatory
;
251 static int hf_diameter_avp_flags_protected
;
252 static int hf_diameter_avp_flags_reserved3
;
253 static int hf_diameter_avp_flags_reserved4
;
254 static int hf_diameter_avp_flags_reserved5
;
255 static int hf_diameter_avp_flags_reserved6
;
256 static int hf_diameter_avp_flags_reserved7
;
257 static int hf_diameter_avp_vendor_id
;
258 static int hf_diameter_avp_data_wrong_length
;
259 static int hf_diameter_avp_pad
;
261 static int hf_diameter_answer_in
;
262 static int hf_diameter_answer_to
;
263 static int hf_diameter_answer_time
;
265 /* AVPs with special/extra decoding */
266 static int hf_framed_ipv6_prefix_reserved
;
267 static int hf_framed_ipv6_prefix_length
;
268 static int hf_framed_ipv6_prefix_bytes
;
269 static int hf_framed_ipv6_prefix_ipv6
;
270 static int hf_diameter_3gpp2_exp_res
;
271 static int hf_diameter_other_vendor_exp_res
;
272 static int hf_diameter_mip6_feature_vector
;
273 static int hf_diameter_mip6_feature_vector_mip6_integrated
;
274 static int hf_diameter_mip6_feature_vector_local_home_agent_assignment
;
275 static int hf_diameter_mip6_feature_vector_pmip6_supported
;
276 static int hf_diameter_mip6_feature_vector_ip4_hoa_supported
;
277 static int hf_diameter_mip6_feature_vector_local_mag_routing_supported
;
278 static int hf_diameter_3gpp_mip6_feature_vector
;
279 static int hf_diameter_3gpp_mip6_feature_vector_assign_local_ip
;
280 static int hf_diameter_3gpp_mip6_feature_vector_mip4_supported
;
281 static int hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility
;
282 static int hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported
;
283 static int hf_diameter_user_equipment_info_imeisv
;
284 static int hf_diameter_user_equipment_info_mac
;
285 static int hf_diameter_user_equipment_info_eui64
;
286 static int hf_diameter_user_equipment_info_modified_eui64
;
288 static int ett_diameter
;
289 static int ett_diameter_flags
;
290 static int ett_diameter_avp_flags
;
291 static int ett_diameter_avpinfo
;
292 static int ett_unknown
;
293 static int ett_diameter_mip6_feature_vector
;
294 static int ett_diameter_3gpp_mip6_feature_vector
;
296 static expert_field ei_diameter_reserved_bit_set
;
297 static expert_field ei_diameter_avp_len
;
298 static expert_field ei_diameter_avp_no_data
;
299 static expert_field ei_diameter_application_id
;
300 static expert_field ei_diameter_version
;
301 static expert_field ei_diameter_avp_pad
;
302 static expert_field ei_diameter_avp_pad_missing
;
303 static expert_field ei_diameter_code
;
304 static expert_field ei_diameter_avp_code
;
305 static expert_field ei_diameter_avp_vendor_id
;
306 static expert_field ei_diameter_invalid_ipv6_prefix_len
;
307 static expert_field ei_diameter_invalid_avp_len
;
308 static expert_field ei_diameter_invalid_user_equipment_info_value_len
;
309 static expert_field ei_diameter_unexpected_imei_as_user_equipment_info
;
311 /* Tap for Diameter */
312 static int diameter_tap
;
314 /* For conversations */
316 static dissector_handle_t diameter_udp_handle
;
317 static dissector_handle_t diameter_tcp_handle
;
318 static dissector_handle_t diameter_sctp_handle
;
319 /* This is IANA registered for TCP and SCTP (and reserved for UDP) */
320 #define DEFAULT_DIAMETER_PORT_RANGE "3868"
321 /* This is IANA registered for TLS/TCP and DTLS/SCTP (and reserved for UDP) */
322 #define DEFAULT_DIAMETER_TLS_PORT 5868
324 /* desegmentation of Diameter over TCP */
325 static bool gbl_diameter_desegment
= true;
327 /* Dissector tables */
328 static dissector_table_t diameter_dissector_table
;
329 static dissector_table_t diameter_3gpp_avp_dissector_table
;
330 static dissector_table_t diameter_ericsson_avp_dissector_table
;
331 static dissector_table_t diameter_verizon_avp_dissector_table
;
332 static dissector_table_t diameter_expr_result_vnd_table
;
334 static const char *avpflags_str
[] = {
345 #define SUBSCRIPTION_ID_TYPE_E164 0
346 #define SUBSCRIPTION_ID_TYPE_IMSI 1
347 #define SUBSCRIPTION_ID_TYPE_SIP_URI 2
348 #define SUBSCRIPTION_ID_TYPE_NAI 3
349 #define SUBSCRIPTION_ID_TYPE_PRIVATE 4
350 #define SUBSCRIPTION_ID_TYPE_UNKNOWN (uint32_t)-1
352 #define USER_EQUIPMENT_INFO_TYPE_IMEISV 0
353 #define USER_EQUIPMENT_INFO_TYPE_MAC 1
354 #define USER_EQUIPMENT_INFO_TYPE_EUI64 2
355 #define USER_EQUIPMENT_INFO_TYPE_MODIFIED_EUI64 3
356 #define USER_EQUIPMENT_INFO_TYPE_UNKNOWN (uint32_t)-1
359 export_diameter_pdu(packet_info
*pinfo
, tvbuff_t
*tvb
)
361 exp_pdu_data_t
*exp_pdu_data
= export_pdu_create_common_tags(pinfo
, "diameter", EXP_PDU_TAG_DISSECTOR_NAME
);
363 exp_pdu_data
->tvb_captured_length
= tvb_captured_length(tvb
);
364 exp_pdu_data
->tvb_reported_length
= tvb_reported_length(tvb
);
365 exp_pdu_data
->pdu_tvb
= tvb
;
367 tap_queue_packet(exported_pdu_tap
, pinfo
, exp_pdu_data
);
372 compare_avps(const void *a
, const void *b
)
374 const value_string
*vsa
= (const value_string
*)a
;
375 const value_string
*vsb
= (const value_string
*)b
;
377 if (vsa
->value
> vsb
->value
)
379 if (vsa
->value
< vsb
->value
)
385 static GHashTable
* diameterstat_cmd_str_hash
;
386 #define DIAMETER_NUM_PROCEDURES 1
389 diameterstat_init(struct register_srt
* srt _U_
, GArray
* srt_array
)
391 srt_stat_table
*diameter_srt_table
;
394 /* XXX - This is a hack/workaround support so resetting/freeing parameters at the dissector
395 level doesn't need to be supported. */
396 if (diameterstat_cmd_str_hash
!= NULL
)
398 g_hash_table_destroy(diameterstat_cmd_str_hash
);
401 idx
= wmem_new0(wmem_epan_scope(), int);
402 diameterstat_cmd_str_hash
= g_hash_table_new(g_str_hash
,g_str_equal
);
403 g_hash_table_insert(diameterstat_cmd_str_hash
, "Unknown", idx
);
405 /** @todo the filter to use in stead of NULL is "diameter.cmd.code"
406 * to enable the filter popup in the service response time dialogue
407 * Note to make it work the command code must be stored rather than the
410 diameter_srt_table
= init_srt_table("Diameter Requests", NULL
, srt_array
, DIAMETER_NUM_PROCEDURES
, NULL
, NULL
, NULL
);
411 init_srt_table_row(diameter_srt_table
, 0, "Unknown");
414 static tap_packet_status
415 diameterstat_packet(void *pss
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *prv
, tap_flags_t flags _U_
)
418 srt_stat_table
*diameter_srt_table
;
419 srt_data_t
*data
= (srt_data_t
*)pss
;
420 const diameter_req_ans_pair_t
*diameter
=(const diameter_req_ans_pair_t
*)prv
;
423 /* Process only answers where corresponding request is found.
424 * Unpaired diameter messages are currently not supported by statistics.
425 * Return 0, since redraw is not needed. */
426 if(!diameter
|| diameter
->processing_request
|| !diameter
->req_frame
)
427 return TAP_PACKET_DONT_REDRAW
;
429 diameter_srt_table
= g_array_index(data
->srt_array
, srt_stat_table
*, i
);
431 idx
= (int*) g_hash_table_lookup(diameterstat_cmd_str_hash
, diameter
->cmd_str
);
433 idx
= wmem_new(wmem_epan_scope(), int);
434 *idx
= (int) g_hash_table_size(diameterstat_cmd_str_hash
);
435 g_hash_table_insert(diameterstat_cmd_str_hash
, (char*) diameter
->cmd_str
, idx
);
436 init_srt_table_row(diameter_srt_table
, *idx
, (const char*) diameter
->cmd_str
);
439 add_srt_table_data(diameter_srt_table
, *idx
, &diameter
->req_time
, pinfo
);
441 return TAP_PACKET_REDRAW
;
445 /* Special decoding of some AVPs */
448 dissect_diameter_vendor_id(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
452 proto_tree_add_item(tree
, hf_diameter_vendor_id
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
459 dissect_diameter_eap_payload(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
463 /* Ensure the packet is displayed as Diameter, not EAP */
464 save_writable
= col_get_writable(pinfo
->cinfo
, COL_PROTOCOL
);
465 col_set_writable(pinfo
->cinfo
, COL_PROTOCOL
, false);
467 call_dissector(eap_handle
, tvb
, pinfo
, tree
);
469 col_set_writable(pinfo
->cinfo
, COL_PROTOCOL
, save_writable
);
470 return tvb_reported_length(tvb
);
473 /* https://www.3gpp2.org/Public_html/X/VSA-VSE.cfm */
474 static const value_string diameter_3gpp2_exp_res_vals
[]= {
475 { 5001, "Diameter_Error_User_No_WLAN_Subscription"},
476 { 5002, "Diameter_Error_Roaming_Not_Allowed(Obsoleted)"},
477 { 5003, "Diameter_Error_User_No_FAP_Subscription"},
482 dissect_diameter_3gpp2_exp_res(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
485 diam_sub_dis_t
*diam_sub_dis
;
487 /* Reject the packet if data is NULL */
490 diam_sub_dis
= (diam_sub_dis_t
*)data
;
493 pi
= proto_tree_add_item(tree
, hf_diameter_3gpp2_exp_res
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
494 diam_sub_dis
->avp_str
= (char *)wmem_alloc(pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
495 proto_item_fill_label(PITEM_FINFO(pi
), diam_sub_dis
->avp_str
, NULL
);
496 diam_sub_dis
->avp_str
= strstr(diam_sub_dis
->avp_str
,": ")+2;
503 dissect_diameter_other_vendor_exp_res(diam_ctx_t
*c
, tvbuff_t
*tvb
, proto_tree
*tree
, diam_sub_dis_t
*diam_sub_dis
)
508 pi
= proto_tree_add_item(tree
, hf_diameter_other_vendor_exp_res
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
509 diam_sub_dis
->avp_str
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
510 proto_item_fill_label(PITEM_FINFO(pi
), diam_sub_dis
->avp_str
, NULL
);
511 diam_sub_dis
->avp_str
= strstr(diam_sub_dis
->avp_str
,": ")+2;
515 /* From RFC 3162 section 2.3 */
517 dissect_diameter_base_framed_ipv6_prefix(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
519 diam_sub_dis_t
*diam_sub_dis
= (diam_sub_dis_t
*)data
;
520 uint32_t prefix_len
, prefix_len_bytes
;
523 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_reserved
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
524 pi
= proto_tree_add_item_ret_uint(tree
, hf_framed_ipv6_prefix_length
, tvb
, 1, 1, ENC_BIG_ENDIAN
, &prefix_len
);
526 if (prefix_len
> 128) {
527 expert_add_info(pinfo
, pi
, &ei_diameter_invalid_ipv6_prefix_len
);
529 prefix_len_bytes
= prefix_len
/ 8;
533 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_bytes
, tvb
, 2, prefix_len_bytes
, ENC_NA
);
535 /* If we have a fully IPv6 address, display it as such */
536 if (prefix_len_bytes
== 16) {
537 proto_tree_add_item(tree
, hf_framed_ipv6_prefix_ipv6
, tvb
, 2, prefix_len_bytes
, ENC_NA
);
538 } else if (prefix_len_bytes
< 16) {
542 memset(&value
.bytes
, 0, sizeof(value
));
543 tvb_memcpy(tvb
, (uint8_t *)&value
.bytes
, 2, prefix_len_bytes
);
544 value
.bytes
[prefix_len_bytes
] = value
.bytes
[prefix_len_bytes
] & (0xff<<(prefix_len
% 8));
545 proto_tree_add_ipv6(tree
, hf_framed_ipv6_prefix_ipv6
, tvb
, 2, prefix_len_bytes
, &value
);
546 set_address(&addr
, AT_IPv6
, 16, value
.bytes
);
547 diam_sub_dis
->avp_str
= wmem_strdup_printf(pinfo
->pool
, "%s/%u", address_to_str(pinfo
->pool
, &addr
), prefix_len
);
550 return prefix_len_bytes
+2;
553 /* AVP Code: 1 User-Name */
554 /* Do special decoding of the User-Name depending on the interface */
556 dissect_diameter_user_name(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
558 diam_sub_dis_t
*diam_sub_dis
= (diam_sub_dis_t
*)data
;
559 uint32_t application_id
= 0, cmd_code
= 0, str_len
;
562 application_id
= diam_sub_dis
->application_id
;
563 cmd_code
= diam_sub_dis
->cmd_code
;
566 switch (application_id
) {
567 case DIAM_APPID_3GPP_S6A_S6D
:
568 case DIAM_APPID_3GPP_SLH
:
569 case DIAM_APPID_3GPP_S7A
:
570 case DIAM_APPID_3GPP_S13
:
571 str_len
= tvb_reported_length(tvb
);
572 dissect_e212_utf8_imsi(tvb
, pinfo
, tree
, 0, str_len
);
574 case DIAM_APPID_3GPP_SWX
:
575 if (cmd_code
!= 305) {
576 str_len
= tvb_reported_length(tvb
);
577 dissect_e212_utf8_imsi(tvb
, pinfo
, tree
, 0, str_len
);
580 // cmd_code 305 (Push-Profile), can be either a User Profile
581 // Update (8.1.2.3), in which case User-Name is an IMSI as
582 // above, or an HSS Reset Indication (8.1.2.4.1), in which
583 // case User-Name is a User List containing a wild card
584 // or leading digits of IMSI series.
586 case DIAM_APPID_3GPP_SWM
:
587 case DIAM_APPID_3GPP_STA
:
588 case DIAM_APPID_3GPP_S6B
:
589 if (cmd_code
== 268) {
590 // 3GPP TS 29.273 - For cmd_code 268 (Diameter-EAP),
591 // "The identity shall be represented in NAI form as
592 // specified in IETF RFC 4282 [15] and shall be formatted
593 // as defined in clause 19 of 3GPP TS 23.003 [14]. This
594 // IE shall include the leading digit used to
595 // differentiate between authentication schemes."
597 // Note that SWa uses the STa application ID, and
598 // SWd uses the application ID associated with
599 // the proxied command (STa here as well).
601 // For other command codes, the User-Name is different
602 // and does *not* include the leading digit as in EAP.
603 str_len
= tvb_reported_length(tvb
);
604 dissect_eap_identity_3gpp(tvb
, pinfo
, tree
, 0, str_len
);
613 /* AVP Code: 124 MIP6-Feature-Vector */
615 /* 3GPP TS 29.273, V15.2.0 */
617 dissect_diameter_mip6_feature_vector(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data
)
619 static int * const flags_rfc
[] = {
620 &hf_diameter_mip6_feature_vector_mip6_integrated
,
621 &hf_diameter_mip6_feature_vector_local_home_agent_assignment
,
622 &hf_diameter_mip6_feature_vector_pmip6_supported
,
623 &hf_diameter_mip6_feature_vector_ip4_hoa_supported
,
624 &hf_diameter_mip6_feature_vector_local_mag_routing_supported
,
628 static int * const flags_3gpp
[] = {
629 &hf_diameter_3gpp_mip6_feature_vector_assign_local_ip
,
630 &hf_diameter_3gpp_mip6_feature_vector_mip4_supported
,
631 &hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility
,
632 &hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported
,
636 uint32_t application_id
= 0;
637 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
638 DISSECTOR_ASSERT(diam_sub_dis_inf
);
640 application_id
= diam_sub_dis_inf
->application_id
;
642 /* Hide the item created in packet-diameter.c and only show the one created here */
643 proto_item_set_hidden(diam_sub_dis_inf
->item
);
645 /* Dissect values defined in RFC 5447, 5779 */
646 proto_tree_add_bitmask(tree
, tvb
, 0, hf_diameter_mip6_feature_vector
, ett_diameter_mip6_feature_vector
, flags_rfc
, ENC_BIG_ENDIAN
);
648 switch (application_id
) {
649 case DIAM_APPID_3GPP_STA
:
650 case DIAM_APPID_3GPP_SWM
:
651 case DIAM_APPID_3GPP_SWX
:
652 case DIAM_APPID_3GPP_S6B
:
653 /* Dissect values defined in TGPP TS 29.273, V15.2.0 */
654 proto_tree_add_bitmask(tree
, tvb
, 0, hf_diameter_3gpp_mip6_feature_vector
, ett_diameter_3gpp_mip6_feature_vector
, flags_3gpp
, ENC_BIG_ENDIAN
);
661 /* AVP Code: 443 Subscription-Id */
663 dissect_diameter_subscription_id(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data
)
665 /* Just reset our global subscription-id-type variable */
666 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
667 diam_sub_dis_inf
->subscription_id_type
= SUBSCRIPTION_ID_TYPE_UNKNOWN
;
672 /* AVP Code: 450 Subscription-Id-Type */
674 dissect_diameter_subscription_id_type(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data
)
676 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
677 diam_sub_dis_inf
->subscription_id_type
= tvb_get_ntohl(tvb
, 0);
682 /* AVP Code: 444 Subscription-Id-Data */
684 dissect_diameter_subscription_id_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
687 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
688 uint32_t subscription_id_type
= diam_sub_dis_inf
->subscription_id_type
;
690 switch (subscription_id_type
) {
691 case SUBSCRIPTION_ID_TYPE_IMSI
:
692 str_len
= tvb_reported_length(tvb
);
693 dissect_e212_utf8_imsi(tvb
, pinfo
, tree
, 0, str_len
);
695 case SUBSCRIPTION_ID_TYPE_E164
:
696 str_len
= tvb_reported_length(tvb
);
697 dissect_e164_msisdn(tvb
, tree
, 0, str_len
, E164_ENC_UTF8
);
704 /* AVP Code: 458 User-Equipment-Info */
706 dissect_diameter_user_equipment_info(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data
)
708 /* Just reset our global subscription-id-type variable */
709 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
710 diam_sub_dis_inf
->user_equipment_info_type
= USER_EQUIPMENT_INFO_TYPE_UNKNOWN
;
715 /* AVP Code: 459 User-Equipment-Info-Type */
716 /* RFC 8506 section 8.50 */
718 dissect_diameter_user_equipment_info_type(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data
)
720 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
721 diam_sub_dis_inf
->user_equipment_info_type
= tvb_get_ntohl(tvb
, 0);
726 /* AVP Code: 460 User-Equipment-Info-Value */
727 /* RFC 8506 section 8.51 */
729 dissect_diameter_user_equipment_info_value(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
732 diam_sub_dis_t
*diam_sub_dis_inf
= (diam_sub_dis_t
*)data
;
733 uint32_t user_equipment_info_type
= diam_sub_dis_inf
->user_equipment_info_type
;
735 switch (user_equipment_info_type
) {
736 case USER_EQUIPMENT_INFO_TYPE_IMEISV
:
737 /* RFC 8506 section 8.53, 3GPP TS 23.003 */
738 len
= tvb_reported_length(tvb
);
739 /* IMEISV is 16 digits, but often transmitted BCD coded in 8 octets.
740 Some implementations use IMEI (15 digits) instead of IMEISV */
742 proto_tree_add_item(tree
, hf_diameter_user_equipment_info_imeisv
, tvb
, 0, len
, ENC_BCD_DIGITS_0_9
|ENC_LITTLE_ENDIAN
|ENC_NA
);
744 } else if (len
== 16) {
745 proto_tree_add_item(tree
, hf_diameter_user_equipment_info_imeisv
, tvb
, 0, len
, ENC_ASCII
);
747 } else if (len
== 15) {
748 proto_tree_add_item(tree
, hf_diameter_user_equipment_info_imeisv
, tvb
, 0, len
, ENC_ASCII
);
749 proto_tree_add_expert(tree
, pinfo
, &ei_diameter_unexpected_imei_as_user_equipment_info
, tvb
, 0, len
);
752 proto_tree_add_expert(tree
, pinfo
, &ei_diameter_invalid_user_equipment_info_value_len
, tvb
, 0, len
);
754 case USER_EQUIPMENT_INFO_TYPE_MAC
:
755 /* RFC 8506 section 8.54, RFC 5777 section 4.1.7.8 */
756 len
= tvb_reported_length(tvb
);
757 if (len
== FT_ETHER_LEN
) {
758 proto_tree_add_item(tree
, hf_diameter_user_equipment_info_mac
, tvb
, 0, len
, ENC_NA
);
761 proto_tree_add_expert(tree
, pinfo
, &ei_diameter_invalid_user_equipment_info_value_len
, tvb
, 0, len
);
763 case USER_EQUIPMENT_INFO_TYPE_EUI64
:
764 /* RFC 8506 section 8.55 */
765 len
= tvb_reported_length(tvb
);
766 if (len
== FT_EUI64_LEN
) {
767 proto_tree_add_item(tree
, hf_diameter_user_equipment_info_eui64
, tvb
, 0, len
, ENC_BIG_ENDIAN
);
770 proto_tree_add_expert(tree
, pinfo
, &ei_diameter_invalid_user_equipment_info_value_len
, tvb
, 0, len
);
772 case USER_EQUIPMENT_INFO_TYPE_MODIFIED_EUI64
:
773 /* RFC 8506 section 8.56, RFC 4291 */
774 len
= tvb_reported_length(tvb
);
775 if (len
== FT_EUI64_LEN
) {
776 proto_tree_add_item(tree
, hf_diameter_user_equipment_info_modified_eui64
, tvb
, 0, len
, ENC_BIG_ENDIAN
);
779 proto_tree_add_expert(tree
, pinfo
, &ei_diameter_invalid_user_equipment_info_value_len
, tvb
, 0, len
);
786 /* Call subdissectors for AVPs.
787 * This is a separate function to avoid having any local variables that might
788 * get clobbered by the exception longjmp() (without having to declare the
789 * variables as volatile and deal with casting them).
792 call_avp_subdissector(uint32_t vendorid
, uint32_t code
, tvbuff_t
*subtvb
, packet_info
*pinfo
, proto_tree
*avp_tree
, diam_sub_dis_t
*diam_sub_dis_inf
)
797 dissector_try_uint_new(diameter_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
799 case VENDOR_ERICSSON
:
800 dissector_try_uint_new(diameter_ericsson_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
803 dissector_try_uint_new(diameter_verizon_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
806 dissector_try_uint_new(diameter_3gpp_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
813 proto_tree_add_subtree(avp_tree, subtvb, 0, -1, "AVP %u data, Vendor Id %u ",code,vendorid);
816 CATCH_NONFATAL_ERRORS
{
817 show_exception(subtvb
, pinfo
, avp_tree
, EXCEPT_CODE
, GET_MESSAGE
);
822 /* Dissect an AVP at offset */
824 dissect_diameter_avp(diam_ctx_t
*c
, tvbuff_t
*tvb
, int offset
, diam_sub_dis_t
*diam_sub_dis_inf
, bool update_col_info
)
826 uint32_t code
= tvb_get_ntohl(tvb
,offset
);
827 uint32_t len
= tvb_get_ntohl(tvb
,offset
+4);
828 uint32_t vendor_flag
= len
& 0x80000000;
829 uint32_t flags_bits_idx
= (len
& 0xE0000000) >> 29;
830 uint32_t flags_bits
= (len
& 0xFF000000) >> 24;
831 uint32_t vendorid
= vendor_flag
? tvb_get_ntohl(tvb
,offset
+8) : 0 ;
832 wmem_tree_key_t k
[3];
834 proto_item
*pi
, *avp_item
;
835 proto_tree
*avp_tree
, *save_tree
;
838 const char *code_str
;
839 const char *avp_str
= NULL
;
846 k
[1].key
= &vendorid
;
851 a
= (diam_avp_t
*)wmem_tree_lookup32_array(dictionary
.avps
,k
);
854 pad_len
= (len
% 4) ? 4 - (len
% 4) : 0 ;
860 if (! (vendor
= (diam_vnd_t
*)wmem_tree_lookup32(dictionary
.vnds
,vendorid
) ))
861 vendor
= &unknown_vendor
;
866 vendor
= (diam_vnd_t
*)a
->vendor
;
869 if (vendor
->vs_avps_ext
== NULL
) {
870 wmem_array_sort(vendor
->vs_avps
, compare_avps
);
871 vendor
->vs_avps_ext
= value_string_ext_new(VND_AVP_VS(vendor
),
872 VND_AVP_VS_LEN(vendor
)+1,
873 wmem_strdup_printf(wmem_epan_scope(), "diameter_vendor_%s",
874 enterprises_lookup(vendorid
, "Unknown")));
877 value_string
*vendor_avp_vs
= VALUE_STRING_EXT_VS_P(vendor
->vs_avps_ext
);
879 while (vendor_avp_vs
[i
].strptr
!= NULL
) {
880 ws_warning("%u %s", vendor_avp_vs
[i
].value
, vendor_avp_vs
[i
].strptr
);
886 /* Check if the length is sane */
887 if (len
> (uint32_t)tvb_reported_length_remaining(tvb
, offset
)) {
888 proto_tree_add_expert_format(c
->tree
, c
->pinfo
, &ei_diameter_invalid_avp_len
, tvb
, offset
+ 4, 4,
889 "Wrong AVP(%u) length %u",
892 return tvb_reported_length(tvb
);
896 * Workaround for a MS-CHAPv2 capture from Bug 15603 that lacks padding.
898 if (tvb_reported_length_remaining(tvb
, offset
+ len
) < pad_len
) {
899 pad_len
= (uint32_t)tvb_reported_length_remaining(tvb
, offset
+ len
);
902 /* Add root of tree for this AVP */
903 avp_item
= proto_tree_add_item(c
->tree
, hf_diameter_avp
, tvb
, offset
, len
+ pad_len
, ENC_NA
);
904 avp_tree
= proto_item_add_subtree(avp_item
, a
->ett
);
906 pi
= proto_tree_add_item(avp_tree
,hf_diameter_avp_code
,tvb
,offset
,4,ENC_BIG_ENDIAN
);
907 code_str
= val_to_str_ext_const(code
, vendor
->vs_avps_ext
, "Unknown");
908 proto_item_append_text(pi
," %s", code_str
);
911 if (a
== &unknown_avp
) {
912 proto_tree
*tu
= proto_item_add_subtree(pi
,ett_unknown
);
913 proto_tree_add_expert_format(tu
, c
->pinfo
, &ei_diameter_avp_code
, tvb
, offset
, 4,
914 "Unknown AVP %u (vendor=%s), if you know what this is you can add it to dictionary.xml", code
,
915 enterprises_lookup(vendorid
, "Unknown"));
920 proto_item_set_text(avp_item
,"AVP: %s(%u) l=%u f=%s", code_str
, code
, len
, avpflags_str
[flags_bits_idx
]);
921 if (update_col_info
) {
922 col_append_fstr(c
->pinfo
->cinfo
, COL_INFO
, " %s", code_str
);
927 static int * const diameter_avp_flags
[] = {
928 &hf_diameter_avp_flags_vendor_specific
,
929 &hf_diameter_avp_flags_mandatory
,
930 &hf_diameter_avp_flags_protected
,
931 &hf_diameter_avp_flags_reserved3
,
932 &hf_diameter_avp_flags_reserved4
,
933 &hf_diameter_avp_flags_reserved5
,
934 &hf_diameter_avp_flags_reserved6
,
935 &hf_diameter_avp_flags_reserved7
,
939 pi
= proto_tree_add_bitmask_with_flags(avp_tree
, tvb
, offset
, hf_diameter_avp_flags
,
940 ett_diameter_avp_flags
, diameter_avp_flags
, ENC_BIG_ENDIAN
, BMT_NO_FALSE
| BMT_NO_INT
);
941 if (flags_bits
& 0x1f) expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
947 proto_tree_add_item(avp_tree
,hf_diameter_avp_len
,tvb
,offset
,3,ENC_BIG_ENDIAN
);
952 proto_item_append_text(avp_item
," vnd=%s", val_to_str(vendorid
, vnd_short_vs
, "%d"));
953 pi
= proto_tree_add_item(avp_tree
,hf_diameter_avp_vendor_id
,tvb
,offset
,4,ENC_BIG_ENDIAN
);
954 if (vendor
== &unknown_vendor
) {
955 proto_tree
*tu
= proto_item_add_subtree(pi
,ett_unknown
);
956 proto_tree_add_expert(tu
, c
->pinfo
, &ei_diameter_avp_vendor_id
, tvb
, offset
, 4);
961 if ( len
== (uint32_t)(vendor_flag
? 12 : 8) ) {
962 /* Data is empty so return now */
963 proto_tree_add_expert(avp_tree
, c
->pinfo
, &ei_diameter_avp_no_data
, tvb
, offset
, 0);
964 /* pad_len is always 0 in this case, but kept here for consistency */
967 /* If we are dissecting a grouped AVP and find a Vendor Id AVP(266), save it */
968 if ((diam_sub_dis_inf
->dis_gouped
) && (!vendor_flag
) && (code
==266)) {
969 diam_sub_dis_inf
->vendor_id
= tvb_get_ntohl(tvb
,offset
);
972 subtvb
= tvb_new_subset_length(tvb
,offset
,len
-(8+(vendor_flag
?4:0)));
973 offset
+= len
-(8+(vendor_flag
?4:0));
978 /* The Experimental-Result-Code AVP (298) comes inside the Experimental-Result
979 * grouped AVP (297). The Vendor-ID AVP in the Experimental-Result specifies the
980 * name space of the Experimental-Result-Code. Unfortunately we don't have a way
981 * to specify, in XML, different Experimental-Result-Code enum values for different
982 * Vendor-IDs so we choose a Vendor-ID whose values get to go in XML (we chose
983 * 3GPP) and handle other Vendor-IDs through the "diameter.vnd_exp_res" dissector
986 if ((diam_sub_dis_inf
->dis_gouped
)
989 && (diam_sub_dis_inf
->vendor_id
!= 0)
990 && (diam_sub_dis_inf
->vendor_id
!= VENDOR_THE3GPP
))
992 /* call subdissector */
993 if (!dissector_try_uint_new(diameter_expr_result_vnd_table
, diam_sub_dis_inf
->vendor_id
,
994 subtvb
, c
->pinfo
, avp_tree
, false, diam_sub_dis_inf
)) {
995 /* No subdissector for this vendor ID, use the generic one */
996 dissect_diameter_other_vendor_exp_res(c
, subtvb
, avp_tree
, diam_sub_dis_inf
);
999 if (diam_sub_dis_inf
->avp_str
) {
1000 proto_item_append_text(avp_item
," val=%s", diam_sub_dis_inf
->avp_str
);
1003 avp_str
= a
->dissector_rfc(c
,a
,subtvb
, diam_sub_dis_inf
);
1005 c
->tree
= save_tree
;
1007 diam_sub_dis_inf
->avp_str
= NULL
;
1008 call_avp_subdissector(vendorid
, code
, subtvb
, c
->pinfo
, avp_tree
, diam_sub_dis_inf
);
1010 /* Let the subdissector have precedence filling in the avp_item string */
1011 if (diam_sub_dis_inf
->avp_str
) {
1012 proto_item_append_text(avp_item
," val=%s", diam_sub_dis_inf
->avp_str
);
1013 } else if (avp_str
) {
1014 proto_item_append_text(avp_item
," val=%s", avp_str
);
1021 pi
= proto_tree_add_item(avp_tree
, hf_diameter_avp_pad
, tvb
, offset
, pad_len
, ENC_NA
);
1022 for (i
=0; i
< pad_len
; i
++) {
1023 if (tvb_get_uint8(tvb
, offset
++) != 0) {
1024 expert_add_info(c
->pinfo
, pi
, &ei_diameter_avp_pad
);
1029 if ((len
+ pad_len
) % 4) {
1030 proto_tree_add_expert(avp_tree
, c
->pinfo
, &ei_diameter_avp_pad_missing
, tvb
, offset
, pad_len
);
1037 address_rfc_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1040 address_avp_t
*t
= (address_avp_t
*)a
->type_data
;
1041 int len
= tvb_reported_length(tvb
);
1042 proto_item
*pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, len
, ENC_BIG_ENDIAN
);
1043 proto_tree
*pt
= proto_item_add_subtree(pi
,t
->ett
);
1047 proto_tree_add_item_ret_uint(pt
, t
->hf_address_type
, tvb
, 0, 2, ENC_NA
, &addr_type
);
1048 /* See afn.h and https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml */
1049 switch (addr_type
) {
1052 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
);
1053 return "[Malformed]";
1055 pi
= proto_tree_add_item(pt
,t
->hf_ipv4
,tvb
,2,4,ENC_BIG_ENDIAN
);
1059 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
);
1060 return "[Malformed]";
1062 pi
= proto_tree_add_item(pt
,t
->hf_ipv6
,tvb
,2,16,ENC_NA
);
1065 /* It's unclear what format the e164 address would be encoded in but AVP 3GPP 2008 has
1066 * ...value 8, E.164, and the address information is UTF8 encoded.
1068 if (tvb_ascii_isprint(tvb
, 2, len
)) {
1069 pi
= proto_tree_add_item(pt
, t
->hf_e164_str
, tvb
, 2, len
, ENC_ASCII
| ENC_NA
);
1071 pi
= proto_tree_add_item(pt
, t
->hf_other
, tvb
, 2, -1, ENC_BIG_ENDIAN
);
1075 pi
= proto_tree_add_item(pt
,t
->hf_other
,tvb
,2,-1,ENC_BIG_ENDIAN
);
1080 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1081 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1082 label
= strstr(label
,": ")+2;
1089 proto_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
1091 proto_avp_t
*t
= (proto_avp_t
*)a
->type_data
;
1093 col_set_writable(c
->pinfo
->cinfo
, COL_PROTOCOL
, false);
1094 col_set_writable(c
->pinfo
->cinfo
, COL_INFO
, false);
1097 t
->handle
= find_dissector(t
->name
);
1098 if (!t
->handle
) t
->handle
= data_handle
;
1102 call_dissector_with_data(t
->handle
, tvb
, c
->pinfo
, c
->tree
, diam_sub_dis_inf
);
1104 CATCH_NONFATAL_ERRORS
{
1105 show_exception(tvb
, c
->pinfo
, c
->tree
, EXCEPT_CODE
, GET_MESSAGE
);
1113 time_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1115 int len
= tvb_reported_length(tvb
);
1120 proto_tree_add_expert_format(c
->tree
, c
->pinfo
, &ei_diameter_avp_len
, tvb
, 0, 4,
1121 "Bad Timestamp Length: %d instead of 4", len
);
1122 return "[Malformed]";
1126 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1127 pi
= proto_tree_add_item(c
->tree
, (a
->hf_value
), tvb
, 0, 4, ENC_TIME_SECS_NTP
|ENC_BIG_ENDIAN
);
1128 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1129 label
= strstr(label
,": ")+2;
1136 address_radius_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1140 address_avp_t
*t
= (address_avp_t
*)a
->type_data
;
1141 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_reported_length(tvb
),ENC_BIG_ENDIAN
);
1142 proto_tree
*pt
= proto_item_add_subtree(pi
,t
->ett
);
1143 uint32_t len
= tvb_reported_length(tvb
);
1147 pi
= proto_tree_add_item(pt
,t
->hf_ipv4
,tvb
,0,4,ENC_BIG_ENDIAN
);
1150 pi
= proto_tree_add_item(pt
,t
->hf_ipv6
,tvb
,0,16,ENC_NA
);
1153 pi
= proto_tree_add_item(pt
,t
->hf_other
,tvb
,0,len
,ENC_BIG_ENDIAN
);
1154 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1155 "Bad Address Length (%u)", len
);
1161 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1162 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1163 label
= strstr(label
,": ")+2;
1170 simple_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1175 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_reported_length(tvb
),ENC_BIG_ENDIAN
);
1176 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1177 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1178 label
= strstr(label
,": ")+2;
1185 utf8_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1190 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_reported_length(tvb
),ENC_UTF_8
|ENC_BIG_ENDIAN
);
1191 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1192 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1193 label
= strstr(label
,": ")+2;
1200 integer32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1205 /* Verify length before adding */
1206 int length
= tvb_reported_length(tvb
);
1209 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1210 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1211 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1212 label
= strstr(label
,": ")+2;
1216 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1217 tvb
, 0, length
, NULL
,
1218 "Error! Bad Integer32 Length");
1219 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1220 "Bad Integer32 Length (%u)", length
);
1221 proto_item_set_generated(pi
);
1228 integer64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1233 /* Verify length before adding */
1234 int length
= tvb_reported_length(tvb
);
1237 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1238 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1239 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1240 label
= strstr(label
,": ")+2;
1244 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1245 tvb
, 0, length
, NULL
,
1246 "Error! Bad Integer64 Length");
1247 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1248 "Bad Integer64 Length (%u)", length
);
1249 proto_item_set_generated(pi
);
1256 unsigned32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
1261 /* Verify length before adding */
1262 int length
= tvb_reported_length(tvb
);
1265 diam_sub_dis_inf
->item
= pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1266 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1267 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1268 label
= strstr(label
,": ")+2;
1272 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1273 tvb
, 0, length
, NULL
,
1274 "Error! Bad Unsigned32 Length");
1275 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1276 "Bad Unsigned32 Length (%u)", length
);
1277 proto_item_set_generated(pi
);
1284 unsigned64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1289 /* Verify length before adding */
1290 int length
= tvb_reported_length(tvb
);
1293 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1294 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1295 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1296 label
= strstr(label
,": ")+2;
1300 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1301 tvb
, 0, length
, NULL
,
1302 "Error! Bad Unsigned64 Length");
1303 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1304 "Bad Unsigned64 Length (%u)", length
);
1305 proto_item_set_generated(pi
);
1312 float32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1317 /* Verify length before adding */
1318 int length
= tvb_reported_length(tvb
);
1321 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1322 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1323 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1324 label
= strstr(label
,": ")+2;
1328 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1329 tvb
, 0, length
, NULL
,
1330 "Error! Bad Float32 Length");
1331 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1332 "Bad Float32 Length (%u)", length
);
1333 proto_item_set_generated(pi
);
1340 float64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1345 /* Verify length before adding */
1346 int length
= tvb_reported_length(tvb
);
1349 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1350 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1351 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1352 label
= strstr(label
,": ")+2;
1356 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1357 tvb
, 0, length
, NULL
,
1358 "Error! Bad Float64 Length");
1359 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1360 "Bad Float64 Length (%u)", length
);
1361 proto_item_set_generated(pi
);
1368 grouped_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
1371 int len
= tvb_reported_length(tvb
);
1372 proto_item
*pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0 , -1, ENC_BIG_ENDIAN
);
1373 proto_tree
*pt
= c
->tree
;
1375 c
->tree
= proto_item_add_subtree(pi
,a
->ett
);
1377 /* Set the flag that we are dissecting a grouped AVP */
1378 diam_sub_dis_inf
->dis_gouped
= true;
1379 while (offset
< len
) {
1380 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
, false);
1382 /* Clear info collected in grouped AVP */
1383 diam_sub_dis_inf
->vendor_id
= 0;
1384 diam_sub_dis_inf
->dis_gouped
= false;
1385 diam_sub_dis_inf
->avp_str
= NULL
;
1392 static const char *msgflags_str
[] = {
1393 "----", "---T", "--E-", "--ET",
1394 "-P--", "-P-T", "-PE-", "-PET",
1395 "R---", "R--T", "R-E-", "R-ET",
1396 "RP--", "RP-T", "RPE-", "RPET"
1399 static int * const diameter_flags_fields
[] = {
1400 &hf_diameter_flags_request
,
1401 &hf_diameter_flags_proxyable
,
1402 &hf_diameter_flags_error
,
1403 &hf_diameter_flags_T
,
1404 &hf_diameter_flags_reserved4
,
1405 &hf_diameter_flags_reserved5
,
1406 &hf_diameter_flags_reserved6
,
1407 &hf_diameter_flags_reserved7
,
1412 dissect_diameter_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1415 uint64_t flags_bits
;
1417 proto_item
*pi
, *cmd_item
, *app_item
, *version_item
;
1418 proto_tree
*diam_tree
;
1419 diam_ctx_t
*c
= wmem_new0(pinfo
->pool
, diam_ctx_t
);
1421 const char *cmd_str
;
1423 uint32_t hop_by_hop_id
, end_to_end_id
;
1424 conversation_t
*conversation
;
1425 diameter_conv_info_t
*diameter_conv_info
;
1426 diameter_req_ans_pair_t
*diameter_pair
= NULL
;
1427 wmem_tree_t
*pdus_tree
;
1430 diam_sub_dis_t
*diam_sub_dis_inf
= wmem_new0(pinfo
->pool
, diam_sub_dis_t
);
1432 /* Set default value Subscription-Id-Type and User-Equipment-Info-Type as XXX_UNKNOWN */
1433 diam_sub_dis_inf
->subscription_id_type
= SUBSCRIPTION_ID_TYPE_UNKNOWN
;
1434 diam_sub_dis_inf
->user_equipment_info_type
= USER_EQUIPMENT_INFO_TYPE_UNKNOWN
;
1436 /* Load header fields if not already done */
1437 if (hf_diameter_code
<= 0)
1438 proto_registrar_get_byname("diameter.code");
1439 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1442 if (have_tap_listener(exported_pdu_tap
)){
1443 export_diameter_pdu(pinfo
,tvb
);
1446 pi
= proto_tree_add_item(tree
,proto_diameter
,tvb
,0,-1,ENC_NA
);
1447 diam_tree
= proto_item_add_subtree(pi
,ett_diameter
);
1449 c
->tree
= diam_tree
;
1452 version_item
= proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_version
, tvb
, 0, 1, ENC_BIG_ENDIAN
, &version
);
1453 if (version
!= DIAMETER_RFC
) {
1454 expert_add_info(c
->pinfo
, version_item
, &ei_diameter_version
);
1456 proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_length
, tvb
, 1, 3, ENC_BIG_ENDIAN
, &packet_len
);
1458 pi
= proto_tree_add_bitmask_ret_uint64(diam_tree
, tvb
, 4, hf_diameter_flags
, ett_diameter_flags
, diameter_flags_fields
, ENC_BIG_ENDIAN
, &flags_bits
);
1459 if (flags_bits
& 0x0f) {
1460 expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
1463 diam_sub_dis_inf
->parent_message_is_request
= (flags_bits
& DIAM_FLAGS_R
) ? true : false;
1465 cmd_item
= proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_code
, tvb
, 5, 3, ENC_BIG_ENDIAN
, &cmd
);
1466 diam_sub_dis_inf
->cmd_code
= cmd
;
1468 app_item
= proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_application_id
, tvb
, 8, 4,
1469 ENC_BIG_ENDIAN
, &diam_sub_dis_inf
->application_id
);
1471 if (try_val_to_str_ext(diam_sub_dis_inf
->application_id
, dictionary
.applications
) == NULL
) {
1472 proto_tree
*tu
= proto_item_add_subtree(app_item
,ett_unknown
);
1473 proto_tree_add_expert_format(tu
, c
->pinfo
, &ei_diameter_application_id
, tvb
, 8, 4,
1474 "Unknown Application Id (%u), if you know what this is you can add it to dictionary.xml", diam_sub_dis_inf
->application_id
);
1477 cmd_str
= val_to_str_const(cmd
, cmd_vs
, "Unknown");
1478 if (strcmp(cmd_str
, "Unknown") == 0) {
1479 expert_add_info(c
->pinfo
, cmd_item
, &ei_diameter_code
);
1483 proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_hopbyhopid
, tvb
, 12, 4, ENC_BIG_ENDIAN
, &hop_by_hop_id
);
1484 proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_endtoendid
, tvb
, 16, 4, ENC_BIG_ENDIAN
, &end_to_end_id
);
1486 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
1487 "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
1489 ((flags_bits
>>4)&0x08) ? " Request" : " Answer",
1491 msgflags_str
[((flags_bits
>>4)&0x0f)],
1493 val_to_str_ext_const(diam_sub_dis_inf
->application_id
, dictionary
.applications
, "Unknown"),
1494 diam_sub_dis_inf
->application_id
,
1498 col_append_str(pinfo
->cinfo
, COL_INFO
, " | ");
1499 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1502 /* Conversation tracking stuff */
1504 * FIXME: Looking at epan/conversation.c it seems unlikely that this will work properly in
1505 * multi-homed SCTP connections. This will probably need to be fixed at some point.
1508 conversation
= find_or_create_conversation(pinfo
);
1510 diameter_conv_info
= (diameter_conv_info_t
*)conversation_get_proto_data(conversation
, proto_diameter
);
1511 if (!diameter_conv_info
) {
1512 diameter_conv_info
= wmem_new(wmem_file_scope(), diameter_conv_info_t
);
1513 diameter_conv_info
->pdu_trees
= wmem_map_new(wmem_file_scope(), g_direct_hash
, g_direct_equal
);
1515 conversation_add_proto_data(conversation
, proto_diameter
, diameter_conv_info
);
1518 /* pdus_tree is an wmem_tree keyed by frame number (in order to handle hop-by-hop collisions */
1519 pdus_tree
= (wmem_tree_t
*)wmem_map_lookup(diameter_conv_info
->pdu_trees
, GUINT_TO_POINTER(hop_by_hop_id
));
1521 if (pdus_tree
== NULL
&& (flags_bits
& DIAM_FLAGS_R
)) {
1522 /* This is the first request we've seen with this hop-by-hop id */
1523 pdus_tree
= wmem_tree_new(wmem_file_scope());
1524 wmem_map_insert(diameter_conv_info
->pdu_trees
, GUINT_TO_POINTER(hop_by_hop_id
), pdus_tree
);
1528 if (!pinfo
->fd
->visited
) {
1529 if (flags_bits
& DIAM_FLAGS_R
) {
1530 /* This is a request */
1531 diameter_pair
= wmem_new(wmem_file_scope(), diameter_req_ans_pair_t
);
1532 diameter_pair
->hop_by_hop_id
= hop_by_hop_id
;
1533 diameter_pair
->end_to_end_id
= end_to_end_id
;
1534 diameter_pair
->cmd_code
= cmd
;
1535 diameter_pair
->result_code
= 0;
1536 diameter_pair
->cmd_str
= cmd_str
;
1537 diameter_pair
->req_frame
= pinfo
->num
;
1538 diameter_pair
->ans_frame
= 0;
1539 diameter_pair
->req_time
= pinfo
->abs_ts
;
1540 wmem_tree_insert32(pdus_tree
, pinfo
->num
, (void *)diameter_pair
);
1542 /* Look for a request which occurs earlier in the trace than this answer. */
1543 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_tree_lookup32_le(pdus_tree
, pinfo
->num
);
1545 /* Verify the end-to-end-id matches before declaring a match */
1546 if (diameter_pair
&& diameter_pair
->end_to_end_id
== end_to_end_id
) {
1547 diameter_pair
->ans_frame
= pinfo
->num
;
1551 /* Look for a request which occurs earlier in the trace than this answer. */
1552 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_tree_lookup32_le(pdus_tree
, pinfo
->num
);
1554 /* If the end-to-end ID doesn't match then this is not the request we were
1557 if (diameter_pair
&& diameter_pair
->end_to_end_id
!= end_to_end_id
)
1558 diameter_pair
= NULL
;
1562 if (!diameter_pair
) {
1563 /* create a "fake" diameter_pair structure */
1564 diameter_pair
= wmem_new(pinfo
->pool
, diameter_req_ans_pair_t
);
1565 diameter_pair
->hop_by_hop_id
= hop_by_hop_id
;
1566 diameter_pair
->cmd_code
= cmd
;
1567 diameter_pair
->result_code
= 0;
1568 diameter_pair
->cmd_str
= cmd_str
;
1569 diameter_pair
->req_frame
= 0;
1570 diameter_pair
->ans_frame
= 0;
1571 diameter_pair
->req_time
= pinfo
->abs_ts
;
1573 diameter_pair
->processing_request
=(flags_bits
& DIAM_FLAGS_R
)!= 0;
1575 /* print state tracking info in the tree */
1576 if (flags_bits
& DIAM_FLAGS_R
) {
1577 /* This is a request */
1578 if (diameter_pair
->ans_frame
) {
1579 it
= proto_tree_add_uint(diam_tree
, hf_diameter_answer_in
,
1580 tvb
, 0, 0, diameter_pair
->ans_frame
);
1581 proto_item_set_generated(it
);
1584 /* This is an answer */
1585 if (diameter_pair
->req_frame
) {
1586 it
= proto_tree_add_uint(diam_tree
, hf_diameter_answer_to
,
1587 tvb
, 0, 0, diameter_pair
->req_frame
);
1588 proto_item_set_generated(it
);
1590 nstime_delta(&ns
, &pinfo
->abs_ts
, &diameter_pair
->req_time
);
1591 diameter_pair
->srt_time
= ns
;
1592 it
= proto_tree_add_time(diam_tree
, hf_diameter_answer_time
, tvb
, 0, 0, &ns
);
1593 proto_item_set_generated(it
);
1594 /* TODO: Populate result_code in tap record from AVP 268 */
1600 /* Dissect AVPs until the end of the packet is reached */
1601 while (offset
< packet_len
) {
1602 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
, false);
1605 /* Handle requests for which no answers were found and
1606 * answers for which no requests were found in the tap listener.
1607 * In case if you don't need unpaired requests/answers use:
1608 * if (diameter_pair->processing_request || !diameter_pair->req_frame)
1611 tap_queue_packet(diameter_tap
, pinfo
, diameter_pair
);
1613 return tvb_reported_length(tvb
);
1617 get_diameter_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
1618 int offset
, void *data _U_
)
1620 /* Get the length of the Diameter packet. */
1621 return tvb_get_ntoh24(tvb
, offset
+ 1);
1624 #define NOT_DIAMETER 0
1625 #define IS_DIAMETER 1
1626 #define NOT_ENOUGH_DATA 2
1628 check_diameter(tvbuff_t
*tvb
)
1633 /* Ensure we don't throw an exception trying to do these heuristics */
1634 if (tvb_captured_length(tvb
) < 5)
1635 return NOT_ENOUGH_DATA
;
1637 /* Check if the Diameter version is 1 */
1638 if (tvb_get_uint8(tvb
, 0) != 1)
1639 return NOT_DIAMETER
;
1641 /* Diameter minimum message length:
1643 * Version+Length - 4 bytes
1644 * Flags+CC - 4 bytes
1648 * 2 AVPs (Orig-Host, Orig-Realm), each including:
1649 * * AVP code - 4 bytes
1650 * * AVP flags + length - 4 bytes
1651 * * (no data - what would a reasonable minimum be?)
1655 msg_len
= tvb_get_ntoh24(tvb
, 1);
1656 /* Diameter message length field must be a multiple of 4.
1657 * This is implicit in RFC 3588 (based on the header and that each
1658 * AVP must align on a 32-bit boundary) and explicit in RFC 6733.
1660 if ((msg_len
< 36) || (msg_len
& 0x3))
1661 return NOT_DIAMETER
;
1663 flags
= tvb_get_uint8(tvb
, 4);
1665 /* Check if any of the Reserved flag bits are set */
1667 return NOT_DIAMETER
;
1669 /* Check if both the R- and E-bits are set */
1670 if ((flags
& DIAM_FLAGS_R
) && (flags
& DIAM_FLAGS_E
))
1671 return NOT_DIAMETER
;
1676 /*****************************************************************/
1677 /* Main dissection function */
1678 /* Checks if the message looks like Diameter before accepting it */
1679 /*****************************************************************/
1681 dissect_diameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1683 if (check_diameter(tvb
) != IS_DIAMETER
)
1685 return dissect_diameter_common(tvb
, pinfo
, tree
, data
);
1689 dissect_diameter_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1691 int is_diam
= check_diameter(tvb
);
1693 if (is_diam
== NOT_DIAMETER
) {
1694 /* We've probably been given a frame that's not the start of
1697 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1698 col_set_str(pinfo
->cinfo
, COL_INFO
, "Continuation");
1699 call_dissector(data_handle
, tvb
, pinfo
, tree
);
1700 } else if (is_diam
== NOT_ENOUGH_DATA
) {
1701 /* Since we're doing our heuristic checks before
1702 * tcp_dissect_pdus() (since we can't do heuristics once
1703 * we're in there) we sometimes have to ask for more data...
1705 pinfo
->desegment_offset
= 0;
1706 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
1708 tcp_dissect_pdus(tvb
, pinfo
, tree
, gbl_diameter_desegment
, 4,
1709 get_diameter_pdu_len
, dissect_diameter_common
, data
);
1712 return tvb_reported_length(tvb
);
1716 dissect_diameter_tcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1718 if (check_diameter(tvb
) != IS_DIAMETER
) {
1722 conversation_set_dissector(find_or_create_conversation(pinfo
), diameter_tcp_handle
);
1724 tcp_dissect_pdus(tvb
, pinfo
, tree
, gbl_diameter_desegment
, 4,
1725 get_diameter_pdu_len
, dissect_diameter_common
, data
);
1731 dissect_diameter_avps(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1734 proto_tree
*diam_tree
;
1736 diam_ctx_t
*c
= wmem_new0(pinfo
->pool
, diam_ctx_t
);
1737 diam_sub_dis_t
*diam_sub_dis_inf
= wmem_new0(pinfo
->pool
, diam_sub_dis_t
);
1739 /* Load header fields if not already done */
1740 if (hf_diameter_code
<= 0)
1741 proto_registrar_get_byname("diameter.code");
1743 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1744 col_set_str(pinfo
->cinfo
, COL_INFO
, "AVPs:");
1746 pi
= proto_tree_add_item(tree
, proto_diameter
, tvb
, 0, -1, ENC_NA
);
1747 diam_tree
= proto_item_add_subtree(pi
, ett_diameter
);
1748 c
->tree
= diam_tree
;
1751 /* Dissect AVPs until the end of the packet is reached */
1752 while (tvb_reported_length_remaining(tvb
, offset
)) {
1753 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
, true);
1755 return tvb_reported_length(tvb
);
1759 alnumerize(char *name
)
1765 for (;(c
= *r
); r
++) {
1766 if (g_ascii_isalnum(c
) || c
== '_' || c
== '-' || c
== '.') {
1778 reginfo(int *hf_ptr
, const char *name
, const char *abbr
, const char *desc
,
1779 enum ftenum ft
, field_display_e base
, value_string_ext
*vs_ext
,
1782 hf_register_info hf
;
1785 hf
.hfinfo
.name
= name
;
1786 hf
.hfinfo
.abbrev
= abbr
;
1787 hf
.hfinfo
.type
= ft
;
1788 hf
.hfinfo
.display
= base
;
1789 hf
.hfinfo
.strings
= NULL
;
1790 hf
.hfinfo
.bitmask
= mask
;
1791 hf
.hfinfo
.blurb
= desc
;
1796 hf
.hfinfo
.strings
= vs_ext
;
1799 wmem_array_append_one(build_dict
.hf
,hf
);
1800 return wmem_array_get_count(build_dict
.hf
);
1804 basic_avp_reginfo(diam_avp_t
*a
, const char *name
, enum ftenum ft
,
1805 field_display_e base
, value_string_ext
*vs_ext
)
1807 hf_register_info hf
;
1808 int *ettp
= &(a
->ett
);
1810 hf
.p_id
= &(a
->hf_value
);
1811 hf
.hfinfo
.name
= NULL
;
1812 hf
.hfinfo
.abbrev
= NULL
;
1813 hf
.hfinfo
.type
= ft
;
1814 hf
.hfinfo
.display
= base
;
1815 hf
.hfinfo
.strings
= NULL
;
1816 hf
.hfinfo
.bitmask
= 0x0;
1817 hf
.hfinfo
.blurb
= a
->vendor
->code
?
1818 wmem_strdup_printf(wmem_epan_scope(), "vendor=%d code=%d", a
->vendor
->code
, a
->code
)
1819 : wmem_strdup_printf(wmem_epan_scope(), "code=%d", a
->code
);
1823 hf
.hfinfo
.name
= wmem_strdup(wmem_epan_scope(), name
);
1824 hf
.hfinfo
.abbrev
= alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, NULL
));
1826 hf
.hfinfo
.strings
= vs_ext
;
1829 wmem_array_append(build_dict
.hf
,&hf
,1);
1830 g_ptr_array_add(build_dict
.ett
,ettp
);
1834 build_gen_address_avp(diam_avp_t
*a
, address_avp_t
*t
, const char *name
)
1836 int *ettp
= &(t
->ett
);
1843 t
->hf_address_type
= -1;
1846 t
->hf_e164_str
= -1;
1849 basic_avp_reginfo(a
, name
, FT_BYTES
, BASE_NONE
, NULL
);
1851 reginfo(&(t
->hf_address_type
), wmem_strconcat(wmem_epan_scope(), name
, " Address Family", NULL
),
1852 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".addr_family", NULL
)),
1853 NULL
, FT_UINT16
, (field_display_e
)(BASE_DEC
|BASE_EXT_STRING
), &diameter_avp_data_addrfamily_vals_ext
, 0);
1855 reginfo(&(t
->hf_ipv4
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1856 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".IPv4", NULL
)),
1857 NULL
, FT_IPv4
, BASE_NONE
, NULL
, 0);
1859 reginfo(&(t
->hf_ipv6
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1860 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".IPv6", NULL
)),
1861 NULL
, FT_IPv6
, BASE_NONE
, NULL
, 0);
1863 reginfo(&(t
->hf_e164_str
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1864 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".E164", NULL
)),
1865 NULL
, FT_STRING
, BASE_NONE
, NULL
, 0);
1867 reginfo(&(t
->hf_other
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1868 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".Bytes", NULL
)),
1869 NULL
, FT_BYTES
, BASE_NONE
, NULL
, 0);
1871 g_ptr_array_add(build_dict
.ett
,ettp
);
1878 * > AVP numbers 1 through 255 are reserved for reuse of RADIUS attributes,
1879 * > without setting the Vendor-Id field.
1881 * This clearly applies not to vendor dictionaries. However, some vendors seem to have
1882 * translated their RADIUS dictionaries to Diameter with that assumption in mind, while
1885 * To make this work universally, the type `ipaddress` is assumed to be using the RADIUS
1886 * encoding for AVP < 256 and Diameter for AVPs >= 256, while the `address` type will
1887 * use Diameter encoding for all AVPs
1890 build_ipaddress_avp(const avp_type_t
*type _U_
, uint32_t code
,
1891 diam_vnd_t
*vendor
, const char *name
,
1892 const value_string
*vs _U_
, void *data _U_
)
1894 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1895 address_avp_t
*t
= wmem_new(wmem_epan_scope(), address_avp_t
);
1900 * It seems like the radius AVPs 1-255 will use the defs from RADIUS in which case:
1901 * https://tools.ietf.org/html/rfc2685
1903 * The Address field is four octets. The value 0xFFFFFFFF indicates
1904 * that the NAS Should allow the user to select an address (e.g.
1905 * Negotiated). The value 0xFFFFFFFE indicates that the NAS should
1906 * select an address for the user (e.g. Assigned from a pool of
1907 * addresses kept by the NAS). Other valid values indicate that the
1908 * NAS should use that value as the user's IP address.
1910 * Where as in Diameter:
1913 * The Address format is derived from the OctetString AVP Base
1914 * Format. It is a discriminated union, representing, for example a
1915 * 32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1916 * significant octet first. The first two octets of the Address
1917 * AVP represents the AddressType, which contains an Address Family
1918 * defined in [IANAADFAM]. The AddressType is used to discriminate
1919 * the content and format of the remaining octets.
1922 a
->dissector_rfc
= address_radius_avp
;
1924 a
->dissector_rfc
= address_rfc_avp
;
1926 return build_gen_address_avp(a
, t
, name
);
1930 build_address_avp(const avp_type_t
*type _U_
, uint32_t code
,
1931 diam_vnd_t
*vendor
, const char *name
,
1932 const value_string
*vs _U_
, void *data _U_
)
1934 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1935 address_avp_t
*t
= wmem_new(wmem_epan_scope(), address_avp_t
);
1939 a
->dissector_rfc
= address_rfc_avp
;
1941 return build_gen_address_avp(a
, t
, name
);
1945 build_proto_avp(const avp_type_t
*type _U_
, uint32_t code
,
1946 diam_vnd_t
*vendor
, const char *name _U_
,
1947 const value_string
*vs _U_
, void *data
)
1949 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1950 proto_avp_t
*t
= wmem_new0(wmem_epan_scope(), proto_avp_t
);
1951 int *ettp
= &(a
->ett
);
1955 a
->dissector_rfc
= proto_avp
;
1960 t
->name
= (char *)data
;
1962 t
->reassemble_mode
= REASEMBLE_NEVER
;
1964 g_ptr_array_add(build_dict
.ett
,ettp
);
1970 build_simple_avp(const avp_type_t
*type
, uint32_t code
, diam_vnd_t
*vendor
,
1971 const char *name
, const value_string
*vs
, void *data _U_
)
1974 value_string_ext
*vs_ext
= NULL
;
1975 field_display_e base
;
1979 * Only 32-bit or shorter integral types can have a list of values.
1981 base
= (field_display_e
)type
->base
;
1994 report_failure("Diameter Dictionary: AVP '%s' has a list of values but isn't of a 32-bit or shorter integral type (%s)\n",
1995 name
, ftype_name(type
->ft
));
1998 while (vs
[i
].strptr
) {
2001 vs_ext
= value_string_ext_new(vs
, i
+1, wmem_strconcat(wmem_epan_scope(), name
, "_vals_ext", NULL
));
2002 base
= (field_display_e
)(base
|BASE_EXT_STRING
);
2005 a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
2008 a
->dissector_rfc
= type
->rfc
;
2012 basic_avp_reginfo(a
, name
, type
->ft
, base
, vs_ext
);
2018 build_appid_avp(const avp_type_t
*type
, uint32_t code
, diam_vnd_t
*vendor
,
2019 const char *name
, const value_string
*vs
, void *data _U_
)
2022 field_display_e base
;
2024 a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
2027 a
->dissector_rfc
= type
->rfc
;
2032 report_failure("Diameter Dictionary: AVP '%s' (of type AppId) has a list of values but the list won't be used\n",
2036 base
= (field_display_e
)(type
->base
|BASE_EXT_STRING
);
2038 basic_avp_reginfo(a
, name
, type
->ft
, base
, dictionary
.applications
);
2042 static const avp_type_t basic_types
[] = {
2043 {"octetstring" , simple_avp
, FT_BYTES
, BASE_NONE
, build_simple_avp
},
2044 {"octetstringorutf8" , simple_avp
, FT_BYTES
, BASE_SHOW_ASCII_PRINTABLE
, build_simple_avp
},
2045 {"utf8string" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2046 {"grouped" , grouped_avp
, FT_BYTES
, BASE_NONE
, build_simple_avp
},
2047 {"integer32" , integer32_avp
, FT_INT32
, BASE_DEC
, build_simple_avp
},
2048 {"unsigned32" , unsigned32_avp
, FT_UINT32
, BASE_DEC
, build_simple_avp
},
2049 {"integer64" , integer64_avp
, FT_INT64
, BASE_DEC
, build_simple_avp
},
2050 {"unsigned64" , unsigned64_avp
, FT_UINT64
, BASE_DEC
, build_simple_avp
},
2051 {"float32" , float32_avp
, FT_FLOAT
, BASE_NONE
, build_simple_avp
},
2052 {"float64" , float64_avp
, FT_DOUBLE
, BASE_NONE
, build_simple_avp
},
2053 {"ipaddress" , NULL
, FT_NONE
, BASE_NONE
, build_ipaddress_avp
},
2054 {"address" , NULL
, FT_NONE
, BASE_NONE
, build_address_avp
},
2055 {"diameteruri" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2056 {"diameteridentity" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2057 {"ipfilterrule" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2058 {"qosfilterrule" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2059 {"time" , time_avp
, FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_UTC
, build_simple_avp
},
2060 {"AppId" , simple_avp
, FT_UINT32
, BASE_DEC
, build_appid_avp
},
2061 {NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
}
2067 * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
2068 * upper-case ASCII characters to their ASCII lower-case equivalents.
2069 * We can't use g_strdown(), as that doesn't do an ASCII mapping;
2070 * in Turkish locales, for example, there are two lower-case "i"s
2071 * and two upper-case "I"s, with and without dots - the ones with
2072 * dots map between each other, as do the ones without dots, so "I"
2073 * doesn't map to "i".
2076 strcase_hash(const void *key
)
2078 const char *p
= (const char *)key
;
2083 if (h
>= 'A' && h
<= 'Z')
2085 for (p
+= 1; *p
!= '\0'; p
++) {
2087 if (c
>= 'A' && c
<= 'Z')
2089 h
= (h
<< 5) - h
+ c
;
2097 * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
2098 * letters are mapped, and they're mapped to the lower-case ASCII
2102 strcase_equal(const void *ka
, const void *kb
)
2104 const char *a
= (const char *)ka
;
2105 const char *b
= (const char *)kb
;
2106 return g_ascii_strcasecmp(a
,b
) == 0;
2110 ddict_cleanup_cb(wmem_allocator_t
* allocator _U_
, wmem_cb_event_t event _U_
, void *user_data
)
2112 ddict_t
*d
= (ddict_t
*)user_data
;
2118 /* Note: Dynamic "value string arrays" (e.g., vs_avps, ...) are constructed using */
2119 /* "zero-terminated" GArrays so that they will have the same form as standard */
2120 /* value_string arrays created at compile time. Since the last entry in a */
2121 /* value_string array must be {0, NULL}, we are assuming that NULL == 0 (hackish). */
2124 dictionary_load(void)
2127 ddict_application_t
*p
;
2130 ddict_typedefn_t
*t
;
2132 bool do_debug_parser
= getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? true : false;
2133 bool do_dump_dict
= getenv("WIRESHARK_DUMP_DIAM_DICT") ? true : false;
2135 const avp_type_t
*type
;
2136 const avp_type_t
*octetstring
= &basic_types
[0];
2138 GHashTable
*vendors
= g_hash_table_new(strcase_hash
,strcase_equal
);
2140 GArray
*vnd_shrt_arr
= g_array_new(true,true,sizeof(value_string
));
2141 GArray
*all_cmds
= g_array_new(true,true,sizeof(value_string
));
2143 /* Pre allocate the arrays big enough to hold the hf:s and etts:s*/
2144 build_dict
.hf
= wmem_array_sized_new(wmem_epan_scope(), sizeof(hf_register_info
), 4096);
2145 build_dict
.ett
= g_ptr_array_sized_new(4096);
2146 build_dict
.types
= g_hash_table_new(strcase_hash
,strcase_equal
);
2147 build_dict
.avps
= g_hash_table_new(strcase_hash
,strcase_equal
);
2149 dictionary
.vnds
= wmem_tree_new(wmem_epan_scope());
2150 dictionary
.avps
= wmem_tree_new(wmem_epan_scope());
2152 unknown_vendor
.vs_avps
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2153 wmem_array_set_null_terminator(unknown_vendor
.vs_avps
);
2154 wmem_array_bzero(unknown_vendor
.vs_avps
);
2155 no_vnd
.vs_avps
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2156 wmem_array_set_null_terminator(no_vnd
.vs_avps
);
2157 wmem_array_bzero(no_vnd
.vs_avps
);
2159 wmem_tree_insert32(dictionary
.vnds
,0,&no_vnd
);
2160 g_hash_table_insert(vendors
,"None",&no_vnd
);
2162 /* initialize the types hash with the known basic types */
2163 for (type
= basic_types
; type
->name
; type
++) {
2164 g_hash_table_insert(build_dict
.types
,(char *)type
->name
,(void *)type
);
2167 /* load the dictionary */
2168 dir
= wmem_strdup_printf(NULL
, "%s" G_DIR_SEPARATOR_S
"diameter" G_DIR_SEPARATOR_S
, get_datafile_dir());
2169 d
= ddict_scan(dir
,"dictionary.xml",do_debug_parser
);
2170 wmem_free(NULL
, dir
);
2172 g_hash_table_destroy(vendors
);
2173 g_array_free(vnd_shrt_arr
, true);
2176 wmem_register_callback(wmem_epan_scope(), ddict_cleanup_cb
, d
);
2178 if (do_dump_dict
) ddict_print(stdout
, d
);
2180 /* populate the types */
2181 for (t
= d
->typedefns
; t
; t
= t
->next
) {
2182 const avp_type_t
*parent
= NULL
;
2183 /* try to get the parent type */
2185 if (t
->name
== NULL
) {
2186 report_failure("Diameter Dictionary: Invalid Type (empty name): parent==%s\n",
2187 t
->parent
? t
->parent
: "(null)");
2192 if (g_hash_table_lookup(build_dict
.types
,t
->name
))
2196 parent
= (avp_type_t
*)g_hash_table_lookup(build_dict
.types
,t
->parent
);
2199 if (!parent
) parent
= octetstring
;
2201 /* insert the parent type for this type */
2202 g_hash_table_insert(build_dict
.types
,t
->name
,(void *)parent
);
2205 /* populate the applications */
2206 if ((p
= d
->applications
)) {
2207 wmem_array_t
*arr
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2208 value_string term
[1];
2211 term
[0].strptr
= NULL
;
2213 for (; p
; p
= p
->next
) {
2214 value_string item
[1];
2216 item
[0].value
= p
->code
;
2217 item
[0].strptr
= p
->name
;
2219 report_failure("Diameter Dictionary: Invalid Application (empty name): id=%d\n", p
->code
);
2223 wmem_array_append_one(arr
,item
);
2226 wmem_array_sort(arr
, compare_avps
);
2227 wmem_array_append_one(arr
,term
);
2229 /* TODO: Remove duplicates */
2231 dictionary
.applications
= value_string_ext_new((value_string
*)wmem_array_get_raw(arr
),
2232 wmem_array_get_count(arr
),
2233 wmem_strdup(wmem_epan_scope(), "applications_vals_ext"));
2236 if ((v
= d
->vendors
)) {
2237 for ( ; v
; v
= v
->next
) {
2238 value_string item
[1];
2240 item
[0].value
= v
->code
;
2241 item
[0].strptr
= v
->name
;
2243 if (v
->name
== NULL
) {
2244 report_failure("Diameter Dictionary: Invalid Vendor (empty name): code==%d\n", v
->code
);
2248 if (g_hash_table_lookup(vendors
,v
->name
))
2251 g_array_append_val(vnd_shrt_arr
,item
);
2253 vnd
= wmem_new(wmem_epan_scope(), diam_vnd_t
);
2254 vnd
->code
= v
->code
;
2255 vnd
->vs_avps
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2256 wmem_array_set_null_terminator(vnd
->vs_avps
);
2257 wmem_array_bzero(vnd
->vs_avps
);
2258 vnd
->vs_avps_ext
= NULL
;
2259 wmem_tree_insert32(dictionary
.vnds
,vnd
->code
,vnd
);
2260 g_hash_table_insert(vendors
,v
->name
,vnd
);
2264 vnd_short_vs
= (value_string
*)g_array_free(vnd_shrt_arr
, false);
2266 if ((c
= d
->cmds
)) {
2267 for (; c
; c
= c
->next
) {
2268 if (c
->vendor
== NULL
) {
2269 report_failure("Diameter Dictionary: Invalid Vendor (empty name) for command %s\n",
2270 c
->name
? c
->name
: "(null)");
2274 if ((diam_vnd_t
*)g_hash_table_lookup(vendors
,c
->vendor
)) {
2275 value_string item
[1];
2277 item
[0].value
= c
->code
;
2278 item
[0].strptr
= c
->name
;
2280 g_array_append_val(all_cmds
,item
);
2282 report_failure("Diameter Dictionary: No Vendor: %s\n",c
->vendor
);
2288 for (a
= d
->avps
; a
; a
= a
->next
) {
2290 value_string
*vs
= NULL
;
2291 const char *vend
= a
->vendor
? a
->vendor
: "None";
2293 void *avp_data
= NULL
;
2295 if (a
->name
== NULL
) {
2296 report_failure("Diameter Dictionary: Invalid AVP (empty name)\n");
2300 if ((vnd
= (diam_vnd_t
*)g_hash_table_lookup(vendors
,vend
))) {
2301 value_string vndvs
[1];
2303 vndvs
[0].value
= a
->code
;
2304 vndvs
[0].strptr
= a
->name
;
2307 wmem_array_append_one(vnd
->vs_avps
,vndvs
);
2309 report_failure("Diameter Dictionary: No Vendor: %s\n",vend
);
2310 vnd
= &unknown_vendor
;
2313 if ((e
= a
->enums
)) {
2314 wmem_array_t
*arr
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2315 value_string term
[1];
2318 term
[0].strptr
= NULL
;
2320 for (; e
; e
= e
->next
) {
2321 value_string item
[1];
2323 item
[0].value
= e
->code
;
2324 item
[0].strptr
= e
->name
;
2325 wmem_array_append_one(arr
,item
);
2327 wmem_array_sort(arr
, compare_avps
);
2328 wmem_array_append_one(arr
,term
);
2329 vs
= (value_string
*)wmem_array_get_raw(arr
);
2334 for( x
= d
->xmlpis
; x
; x
= x
->next
) {
2335 if ( (strcase_equal(x
->name
,"avp-proto") && strcase_equal(x
->key
,a
->name
))
2336 || (a
->type
&& strcase_equal(x
->name
,"type-proto") && strcase_equal(x
->key
,a
->type
))
2338 static avp_type_t proto_type
= {"proto", proto_avp
, FT_UINT32
, BASE_HEX
, build_proto_avp
};
2341 avp_data
= x
->value
;
2346 if ( (!type
) && a
->type
)
2347 type
= (avp_type_t
*)g_hash_table_lookup(build_dict
.types
,a
->type
);
2349 if (!type
) type
= octetstring
;
2351 avp
= type
->build( type
, a
->code
, vnd
, a
->name
, vs
, avp_data
);
2353 g_hash_table_insert(build_dict
.avps
, a
->name
, avp
);
2356 wmem_tree_key_t k
[3];
2359 k
[0].key
= &(a
->code
);
2361 k
[1].key
= &(vnd
->code
);
2365 wmem_tree_insert32_array(dictionary
.avps
,k
,avp
);
2369 g_hash_table_destroy(build_dict
.types
);
2370 g_hash_table_destroy(build_dict
.avps
);
2371 g_hash_table_destroy(vendors
);
2373 cmd_vs
= (const value_string
*)g_array_free(all_cmds
, false);
2379 * This does most of the registration work; see register_diameter_fields()
2380 * for the reason why we split it off.
2383 real_register_diameter_fields(void)
2385 expert_module_t
* expert_diameter
;
2386 unsigned i
, ett_length
;
2388 hf_register_info hf_base
[] = {
2389 { &hf_diameter_version
,
2390 { "Version", "diameter.version", FT_UINT8
, BASE_HEX
, NULL
, 0x00,
2392 { &hf_diameter_length
,
2393 { "Length","diameter.length", FT_UINT24
, BASE_DEC
, NULL
, 0x0,
2395 { &hf_diameter_flags
,
2396 { "Flags", "diameter.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
2398 { &hf_diameter_flags_request
,
2399 { "Request", "diameter.flags.request", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_R
,
2401 { &hf_diameter_flags_proxyable
,
2402 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_P
,
2404 { &hf_diameter_flags_error
,
2405 { "Error","diameter.flags.error", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_E
,
2407 { &hf_diameter_flags_T
,
2408 { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_T
,
2410 { &hf_diameter_flags_reserved4
,
2411 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2412 DIAM_FLAGS_RESERVED4
, NULL
, HFILL
}},
2413 { &hf_diameter_flags_reserved5
,
2414 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2415 DIAM_FLAGS_RESERVED5
, NULL
, HFILL
}},
2416 { &hf_diameter_flags_reserved6
,
2417 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2418 DIAM_FLAGS_RESERVED6
, NULL
, HFILL
}},
2419 { &hf_diameter_flags_reserved7
,
2420 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2421 DIAM_FLAGS_RESERVED7
, NULL
, HFILL
}},
2422 { &hf_diameter_vendor_id
,
2423 { "VendorId", "diameter.vendorId", FT_UINT32
, BASE_ENTERPRISES
, STRINGS_ENTERPRISES
,
2424 0x0, NULL
, HFILL
}},
2425 { &hf_diameter_application_id
,
2426 { "ApplicationId", "diameter.applicationId", FT_UINT32
, BASE_DEC
|BASE_EXT_STRING
, VALS_EXT_PTR(dictionary
.applications
),
2427 0x0, NULL
, HFILL
}},
2428 { &hf_diameter_hopbyhopid
,
2429 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32
,
2430 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2431 { &hf_diameter_endtoendid
,
2432 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32
,
2433 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2435 { "AVP","diameter.avp", FT_BYTES
, BASE_NONE
,
2436 NULL
, 0x0, NULL
, HFILL
}},
2437 { &hf_diameter_avp_len
,
2438 { "AVP Length","diameter.avp.len", FT_UINT24
, BASE_DEC
,
2439 NULL
, 0x0, NULL
, HFILL
}},
2440 { &hf_diameter_avp_code
,
2441 { "AVP Code", "diameter.avp.code", FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2442 { &hf_diameter_avp_flags
,
2443 { "AVP Flags","diameter.avp.flags", FT_UINT8
, BASE_HEX
,
2444 NULL
, 0x0, NULL
, HFILL
}},
2445 { &hf_diameter_avp_flags_vendor_specific
,
2446 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_V
,
2448 { &hf_diameter_avp_flags_mandatory
,
2449 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_M
,
2451 { &hf_diameter_avp_flags_protected
,
2452 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_P
,
2454 { &hf_diameter_avp_flags_reserved3
,
2455 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2456 AVP_FLAGS_RESERVED3
, NULL
, HFILL
}},
2457 { &hf_diameter_avp_flags_reserved4
,
2458 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2459 AVP_FLAGS_RESERVED4
, NULL
, HFILL
}},
2460 { &hf_diameter_avp_flags_reserved5
,
2461 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2462 AVP_FLAGS_RESERVED5
, NULL
, HFILL
}},
2463 { &hf_diameter_avp_flags_reserved6
,
2464 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2465 AVP_FLAGS_RESERVED6
, NULL
, HFILL
}},
2466 { &hf_diameter_avp_flags_reserved7
,
2467 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2468 AVP_FLAGS_RESERVED7
, NULL
, HFILL
}},
2469 { &hf_diameter_avp_vendor_id
,
2470 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32
, BASE_ENTERPRISES
, STRINGS_ENTERPRISES
,
2471 0x0, NULL
, HFILL
}},
2472 { &(unknown_avp
.hf_value
),
2473 { "Value","diameter.avp.unknown", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2474 { &hf_diameter_avp_data_wrong_length
,
2475 { "Data","diameter.avp.invalid-data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2476 { &hf_diameter_avp_pad
,
2477 { "Padding","diameter.avp.pad", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2478 { &hf_diameter_code
,
2479 { "Command Code", "diameter.cmd.code", FT_UINT32
, BASE_DEC
, VALS(cmd_vs
), 0, NULL
, HFILL
}},
2480 { &hf_diameter_answer_in
,
2481 { "Answer In", "diameter.answer_in", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0x0,
2482 "The answer to this diameter request is in this frame", HFILL
}},
2483 { &hf_diameter_answer_to
,
2484 { "Request In", "diameter.answer_to", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0x0,
2485 "This is an answer to the diameter request in this frame", HFILL
}},
2486 { &hf_diameter_answer_time
,
2487 { "Response Time", "diameter.resp_time", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
2488 "The time between the request and the answer", HFILL
}},
2489 { &hf_framed_ipv6_prefix_reserved
,
2490 { "Framed IPv6 Prefix Reserved byte", "diameter.framed_ipv6_prefix_reserved",
2491 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
2492 { &hf_framed_ipv6_prefix_length
,
2493 { "Framed IPv6 Prefix length (in bits)", "diameter.framed_ipv6_prefix_length",
2494 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2495 { &hf_framed_ipv6_prefix_bytes
,
2496 { "Framed IPv6 Prefix as a bytestring", "diameter.framed_ipv6_prefix_bytes",
2497 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
2498 { &hf_framed_ipv6_prefix_ipv6
,
2499 { "Framed IPv6 Prefix as an IPv6 address", "diameter.framed_ipv6_prefix_ipv6",
2500 FT_IPv6
, BASE_NONE
, NULL
, 0, "This field is present only if the prefix length is 128", HFILL
}},
2501 { &hf_diameter_3gpp2_exp_res
,
2502 { "Experimental-Result-Code", "diameter.3gpp2.exp_res",
2503 FT_UINT32
, BASE_DEC
, VALS(diameter_3gpp2_exp_res_vals
), 0x0, NULL
, HFILL
}},
2504 { &hf_diameter_other_vendor_exp_res
,
2505 { "Experimental-Result-Code", "diameter.other_vendor.Experimental-Result-Code",
2506 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
2507 { &hf_diameter_mip6_feature_vector
,
2508 { "MIP6-Feature-Vector", "diameter.mip6_feature_vector",
2509 FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2510 { &hf_diameter_mip6_feature_vector_mip6_integrated
,
2511 { "MIP6_INTEGRATED", "diameter.mip6_feature_vector.mip6_integrated.mip6_integrated",
2512 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000000000000001, NULL
, HFILL
}},
2513 { &hf_diameter_mip6_feature_vector_local_home_agent_assignment
,
2514 { "LOCAL_HOME_AGENT_ASSIGNMENT", "diameter.mip6_feature_vector.local_home_agent_assignment",
2515 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000000000000002, NULL
, HFILL
}},
2516 { &hf_diameter_mip6_feature_vector_pmip6_supported
,
2517 { "PMIP6_SUPPORTED", "diameter.mip6_feature_vector.pmip6_supported",
2518 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000010000000000, NULL
, HFILL
}},
2519 { &hf_diameter_mip6_feature_vector_ip4_hoa_supported
,
2520 { "IP4_HOA_SUPPORTED", "diameter.mip6_feature_vector.ip4_hoa_supported",
2521 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000020000000000, NULL
, HFILL
}},
2522 { &hf_diameter_mip6_feature_vector_local_mag_routing_supported
,
2523 { "LOCAL_MAG_ROUTING_SUPPORTED", "diameter.mip6_feature_vector.local_mag_routing_supported",
2524 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000040000000000,NULL
, HFILL
}},
2525 { &hf_diameter_3gpp_mip6_feature_vector
,
2526 { "MIP6-Feature-Vector [3GPP]", "diameter.3gpp.mip6_feature_vector",
2527 FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2528 { &hf_diameter_3gpp_mip6_feature_vector_assign_local_ip
,
2529 { "MIP6_INTEGRATED", "diameter.3gpp.mip6_feature_vector.assign_local_ip",
2530 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000080000000000, NULL
, HFILL
}},
2531 { &hf_diameter_3gpp_mip6_feature_vector_mip4_supported
,
2532 { "PMIP6_SUPPORTED", "diameter.3gpp.mip6_feature_vector.mip4_supported",
2533 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000100000000000, NULL
, HFILL
}},
2534 { &hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility
,
2535 { "OPTIMIZED_IDLE_MODE_MOBILITY", "diameter.3gpp.mip6_feature_vector.optimized_idle_mode_mobility",
2536 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000200000000000, NULL
, HFILL
}},
2537 { &hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported
,
2538 { "GTPv2_SUPPORTED", "diameter.3gpp.mip6_feature_vector.gtpv2_supported",
2539 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000400000000000, NULL
, HFILL
}},
2540 { &hf_diameter_user_equipment_info_imeisv
,
2541 { "IMEISV","diameter.user_equipment_info.imeisv", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2542 { &hf_diameter_user_equipment_info_mac
,
2543 { "MAC","diameter.user_equipment_info.mac", FT_ETHER
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2544 { &hf_diameter_user_equipment_info_eui64
,
2545 { "EUI64","diameter.user_equipment_info.eui64", FT_EUI64
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2546 { &hf_diameter_user_equipment_info_modified_eui64
,
2547 { "Modified EUI64","diameter.user_equipment_info.modified_eui64", FT_EUI64
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}}
2552 &ett_diameter_flags
,
2553 &ett_diameter_avp_flags
,
2554 &ett_diameter_avpinfo
,
2556 &ett_diameter_mip6_feature_vector
,
2557 &ett_diameter_3gpp_mip6_feature_vector
,
2561 static ei_register_info ei
[] = {
2562 { &ei_diameter_reserved_bit_set
, { "diameter.reserved_bit_set", PI_MALFORMED
, PI_WARN
, "Reserved bit set", EXPFILL
}},
2563 { &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
}},
2564 { &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
}},
2565 { &ei_diameter_avp_no_data
, { "diameter.avp.no_data", PI_UNDECODED
, PI_WARN
, "Data is empty", EXPFILL
}},
2566 { &ei_diameter_avp_pad
, { "diameter.avp.pad.non_zero", PI_MALFORMED
, PI_NOTE
, "Padding is non-zero", EXPFILL
}},
2567 { &ei_diameter_avp_pad_missing
, { "diameter.avp.pad.missing", PI_MALFORMED
, PI_NOTE
, "Padding is missing", EXPFILL
}},
2568 { &ei_diameter_avp_len
, { "diameter.avp.invalid-len", PI_MALFORMED
, PI_WARN
, "Wrong length", EXPFILL
}},
2569 { &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
}},
2570 { &ei_diameter_version
, { "diameter.version.unknown", PI_UNDECODED
, PI_WARN
, "Unknown Diameter Version (decoding as RFC 3588)", EXPFILL
}},
2571 { &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
}},
2572 { &ei_diameter_invalid_ipv6_prefix_len
, { "diameter.invalid_ipv6_prefix_len", PI_MALFORMED
, PI_ERROR
, "Invalid IPv6 Prefix length", EXPFILL
}},
2573 { &ei_diameter_invalid_avp_len
,{ "diameter.invalid_avp_len", PI_MALFORMED
, PI_ERROR
, "Invalid AVP length", EXPFILL
}},
2574 { &ei_diameter_invalid_user_equipment_info_value_len
,{ "diameter.invalid_user_equipment_info_value_len", PI_MALFORMED
, PI_ERROR
, "Invalid User-Equipment-Info-Value length", EXPFILL
}},
2575 { &ei_diameter_unexpected_imei_as_user_equipment_info
,{ "diameter.unexpected_imei_as_user_equipment_info", PI_MALFORMED
, PI_ERROR
, "Found IMEI as User-Equipment-Info-Value but IMEISV was expected", EXPFILL
}},
2578 wmem_array_append(build_dict
.hf
, hf_base
, array_length(hf_base
));
2579 ett_length
= array_length(ett_base
);
2580 for (i
= 0; i
< ett_length
; i
++) {
2581 g_ptr_array_add(build_dict
.ett
, ett_base
[i
]);
2584 proto_register_field_array(proto_diameter
, (hf_register_info
*)wmem_array_get_raw(build_dict
.hf
), wmem_array_get_count(build_dict
.hf
));
2585 proto_register_subtree_array((int **)build_dict
.ett
->pdata
, build_dict
.ett
->len
);
2586 expert_diameter
= expert_register_protocol(proto_diameter
);
2587 expert_register_field_array(expert_diameter
, ei
, array_length(ei
));
2589 g_ptr_array_free(build_dict
.ett
,true);
2594 register_diameter_fields(const char *unused _U_
)
2597 * The hf_base[] array for Diameter refers to a variable
2598 * that is set by dictionary_load(), so we need to call
2599 * dictionary_load() before hf_base[] is initialized.
2601 * To ensure that, we call dictionary_load() and then
2602 * call a routine that defines hf_base[] and does all
2603 * the registration work.
2606 real_register_diameter_fields();
2610 proto_register_diameter(void)
2612 module_t
*diameter_module
;
2614 proto_diameter
= proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
2616 /* Allow dissector to find be found by name. */
2617 diameter_sctp_handle
= register_dissector("diameter", dissect_diameter
, proto_diameter
);
2618 diameter_udp_handle
= create_dissector_handle(dissect_diameter
, proto_diameter
);
2619 diameter_tcp_handle
= register_dissector("diameter.tcp", dissect_diameter_tcp
, proto_diameter
);
2620 /* Diameter AVPs without Diameter header, for EAP-TTLS (RFC 5281, Section 10) */
2621 register_dissector("diameter_avps", dissect_diameter_avps
, proto_diameter
);
2623 /* Delay registration of Diameter fields */
2624 proto_register_prefix("diameter", register_diameter_fields
);
2626 /* Register dissector table(s) to do sub dissection of AVPs (OctetStrings) */
2627 diameter_dissector_table
= register_dissector_table("diameter.base", "Diameter Base AVP", proto_diameter
, FT_UINT32
, BASE_DEC
);
2628 diameter_3gpp_avp_dissector_table
= register_dissector_table("diameter.3gpp", "Diameter 3GPP AVP", proto_diameter
, FT_UINT32
, BASE_DEC
);
2629 diameter_ericsson_avp_dissector_table
= register_dissector_table("diameter.ericsson", "Diameter Ericsson AVP", proto_diameter
, FT_UINT32
, BASE_DEC
);
2630 diameter_verizon_avp_dissector_table
= register_dissector_table("diameter.verizon", "DIAMETER_VERIZON_AVPS", proto_diameter
, FT_UINT32
, BASE_DEC
);
2632 diameter_expr_result_vnd_table
= register_dissector_table("diameter.vnd_exp_res", "Diameter Experimental-Result-Code", proto_diameter
, FT_UINT32
, BASE_DEC
);
2634 /* Register configuration options */
2635 diameter_module
= prefs_register_protocol(proto_diameter
, NULL
);
2636 /* For reading older preference files with "Diameter." preferences */
2637 prefs_register_module_alias("Diameter", diameter_module
);
2639 /* Desegmentation */
2640 prefs_register_bool_preference(diameter_module
, "desegment",
2641 "Reassemble Diameter messages spanning multiple TCP segments",
2642 "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
2643 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2644 &gbl_diameter_desegment
);
2646 /* Register some preferences we no longer support, so we can report
2647 * them as obsolete rather than just illegal.
2649 prefs_register_obsolete_preference(diameter_module
, "version");
2650 prefs_register_obsolete_preference(diameter_module
, "command_in_header");
2651 prefs_register_obsolete_preference(diameter_module
, "dictionary.name");
2652 prefs_register_obsolete_preference(diameter_module
, "dictionary.use");
2653 prefs_register_obsolete_preference(diameter_module
, "allow_zero_as_app_id");
2654 prefs_register_obsolete_preference(diameter_module
, "suppress_console_output");
2657 diameter_tap
= register_tap("diameter");
2659 register_srt_table(proto_diameter
, NULL
, 1, diameterstat_packet
, diameterstat_init
, NULL
);
2661 } /* proto_register_diameter */
2664 proto_reg_handoff_diameter(void)
2666 data_handle
= find_dissector("data");
2667 eap_handle
= find_dissector_add_dependency("eap", proto_diameter
);
2669 dissector_add_uint("sctp.ppi", DIAMETER_PROTOCOL_ID
, diameter_sctp_handle
);
2671 heur_dissector_add("tcp", dissect_diameter_tcp_heur
, "Diameter over TCP", "diameter_tcp", proto_diameter
, HEURISTIC_DISABLE
);
2673 ssl_dissector_add(DEFAULT_DIAMETER_TLS_PORT
, diameter_tcp_handle
);
2674 dtls_dissector_add(DEFAULT_DIAMETER_TLS_PORT
, diameter_sctp_handle
);
2676 /* Register special decoding for some AVPs */
2678 /* AVP Code: 1 User-Name */
2679 dissector_add_uint("diameter.base", 1, create_dissector_handle(dissect_diameter_user_name
, proto_diameter
));
2681 /* AVP Code: 79 EAP-Message (defined in RFC 2869, but used for EAP-TTLS, RFC 5281) */
2682 dissector_add_uint("diameter.base", 79, create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
2684 /* AVP Code: 97 Framed-IPv6-Address */
2685 dissector_add_uint("diameter.base", 97, create_dissector_handle(dissect_diameter_base_framed_ipv6_prefix
, proto_diameter
));
2687 /* AVP Code: 124 MIP6-Feature-Vector */
2688 dissector_add_uint("diameter.base", 124, create_dissector_handle(dissect_diameter_mip6_feature_vector
, proto_diameter
));
2690 /* AVP Code: 265 Supported-Vendor-Id */
2691 dissector_add_uint("diameter.base", 265, create_dissector_handle(dissect_diameter_vendor_id
, proto_diameter
));
2693 /* AVP Code: 266 Vendor-Id */
2694 dissector_add_uint("diameter.base", 266, create_dissector_handle(dissect_diameter_vendor_id
, proto_diameter
));
2696 /* AVP Code: 443 Subscription-Id */
2697 dissector_add_uint("diameter.base", 443, create_dissector_handle(dissect_diameter_subscription_id
, proto_diameter
));
2699 /* AVP Code: 450 Subscription-Id-Type */
2700 dissector_add_uint("diameter.base", 450, create_dissector_handle(dissect_diameter_subscription_id_type
, proto_diameter
));
2702 /* AVP Code: 444 Subscription-Id-Data */
2703 dissector_add_uint("diameter.base", 444, create_dissector_handle(dissect_diameter_subscription_id_data
, proto_diameter
));
2705 /* AVP Code: 458 User-Equipment-Info */
2706 dissector_add_uint("diameter.base", 458, create_dissector_handle(dissect_diameter_user_equipment_info
, proto_diameter
));
2708 /* AVP Code: 459 User-Equipment-Info-Type */
2709 dissector_add_uint("diameter.base", 459, create_dissector_handle(dissect_diameter_user_equipment_info_type
, proto_diameter
));
2711 /* AVP Code: 460 User-Equipment-Info-Value */
2712 dissector_add_uint("diameter.base", 460, create_dissector_handle(dissect_diameter_user_equipment_info_value
, proto_diameter
));
2714 /* AVP Code: 462 EAP-Payload */
2715 dissector_add_uint("diameter.base", 462, create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
2716 /* AVP Code: 463 EAP-Reissued-Payload */
2717 dissector_add_uint("diameter.base", 463, create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
2719 /* Register dissector for Experimental result code, with 3GPP2's vendor Id */
2720 dissector_add_uint("diameter.vnd_exp_res", VENDOR_THE3GPP2
, create_dissector_handle(dissect_diameter_3gpp2_exp_res
, proto_diameter
));
2722 dissector_add_uint_range_with_preference("tcp.port", DEFAULT_DIAMETER_PORT_RANGE
, diameter_tcp_handle
);
2723 dissector_add_uint_range_with_preference("udp.port", "", diameter_udp_handle
);
2724 dissector_add_uint_range_with_preference("sctp.port", DEFAULT_DIAMETER_PORT_RANGE
, diameter_sctp_handle
);
2726 exported_pdu_tap
= find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7
);
2732 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2737 * indent-tabs-mode: t
2740 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2741 * :indentSize=8:tabSize=8:noTabs=false: