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_with_data(diameter_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
799 case VENDOR_ERICSSON
:
800 dissector_try_uint_with_data(diameter_ericsson_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
803 dissector_try_uint_with_data(diameter_verizon_avp_dissector_table
, code
, subtvb
, pinfo
, avp_tree
, false, diam_sub_dis_inf
);
806 dissector_try_uint_with_data(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 /* Data is empty so return now */
962 if ( len
== (uint32_t)(vendor_flag
? 12 : 8) ) {
963 /* AVP=Requested-Service-Unit(437) may be empty.
965 * RFC 4006, 8.16 (page 64):
966 * The Requested-Service-Unit AVP MAY contain the amount of requested
967 * service units or the requested monetary value. It MUST be present in
968 * the initial interrogation and within the intermediate interrogations
969 * in which new quota is requested.
971 * Command-Code = "Credit-Control" (272)
972 * ApplicationID = "Diameter Credit Control Application" (4)
975 && (diam_sub_dis_inf
->cmd_code
== 272)
976 && (diam_sub_dis_inf
->parent_message_is_request
)
977 && (diam_sub_dis_inf
->application_id
== 4))) {
978 proto_tree_add_expert(avp_tree
, c
->pinfo
, &ei_diameter_avp_no_data
, tvb
, offset
, 0);
980 /* pad_len is always 0 in this case, but kept here for consistency */
983 /* If we are dissecting a grouped AVP and find a Vendor Id AVP(266), save it */
984 if ((diam_sub_dis_inf
->dis_gouped
) && (!vendor_flag
) && (code
==266)) {
985 diam_sub_dis_inf
->vendor_id
= tvb_get_ntohl(tvb
,offset
);
988 subtvb
= tvb_new_subset_length(tvb
,offset
,len
-(8+(vendor_flag
?4:0)));
989 offset
+= len
-(8+(vendor_flag
?4:0));
994 /* The Experimental-Result-Code AVP (298) comes inside the Experimental-Result
995 * grouped AVP (297). The Vendor-ID AVP in the Experimental-Result specifies the
996 * name space of the Experimental-Result-Code. Unfortunately we don't have a way
997 * to specify, in XML, different Experimental-Result-Code enum values for different
998 * Vendor-IDs so we choose a Vendor-ID whose values get to go in XML (we chose
999 * 3GPP) and handle other Vendor-IDs through the "diameter.vnd_exp_res" dissector
1002 if ((diam_sub_dis_inf
->dis_gouped
)
1005 && (diam_sub_dis_inf
->vendor_id
!= 0)
1006 && (diam_sub_dis_inf
->vendor_id
!= VENDOR_THE3GPP
))
1008 /* call subdissector */
1009 if (!dissector_try_uint_with_data(diameter_expr_result_vnd_table
, diam_sub_dis_inf
->vendor_id
,
1010 subtvb
, c
->pinfo
, avp_tree
, false, diam_sub_dis_inf
)) {
1011 /* No subdissector for this vendor ID, use the generic one */
1012 dissect_diameter_other_vendor_exp_res(c
, subtvb
, avp_tree
, diam_sub_dis_inf
);
1015 if (diam_sub_dis_inf
->avp_str
) {
1016 proto_item_append_text(avp_item
," val=%s", diam_sub_dis_inf
->avp_str
);
1019 avp_str
= a
->dissector_rfc(c
,a
,subtvb
, diam_sub_dis_inf
);
1021 c
->tree
= save_tree
;
1023 diam_sub_dis_inf
->avp_str
= NULL
;
1024 call_avp_subdissector(vendorid
, code
, subtvb
, c
->pinfo
, avp_tree
, diam_sub_dis_inf
);
1026 /* Let the subdissector have precedence filling in the avp_item string */
1027 if (diam_sub_dis_inf
->avp_str
) {
1028 proto_item_append_text(avp_item
," val=%s", diam_sub_dis_inf
->avp_str
);
1029 } else if (avp_str
) {
1030 proto_item_append_text(avp_item
," val=%s", avp_str
);
1037 pi
= proto_tree_add_item(avp_tree
, hf_diameter_avp_pad
, tvb
, offset
, pad_len
, ENC_NA
);
1038 for (i
=0; i
< pad_len
; i
++) {
1039 if (tvb_get_uint8(tvb
, offset
++) != 0) {
1040 expert_add_info(c
->pinfo
, pi
, &ei_diameter_avp_pad
);
1045 if ((len
+ pad_len
) % 4) {
1046 proto_tree_add_expert(avp_tree
, c
->pinfo
, &ei_diameter_avp_pad_missing
, tvb
, offset
, pad_len
);
1053 address_rfc_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1056 address_avp_t
*t
= (address_avp_t
*)a
->type_data
;
1057 int len
= tvb_reported_length(tvb
);
1058 proto_item
*pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, len
, ENC_BIG_ENDIAN
);
1059 proto_tree
*pt
= proto_item_add_subtree(pi
,t
->ett
);
1063 proto_tree_add_item_ret_uint(pt
, t
->hf_address_type
, tvb
, 0, 2, ENC_NA
, &addr_type
);
1064 /* See afn.h and https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml */
1065 switch (addr_type
) {
1068 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
);
1069 return "[Malformed]";
1071 pi
= proto_tree_add_item(pt
,t
->hf_ipv4
,tvb
,2,4,ENC_BIG_ENDIAN
);
1075 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
);
1076 return "[Malformed]";
1078 pi
= proto_tree_add_item(pt
,t
->hf_ipv6
,tvb
,2,16,ENC_NA
);
1081 /* It's unclear what format the e164 address would be encoded in but AVP 3GPP 2008 has
1082 * ...value 8, E.164, and the address information is UTF8 encoded.
1084 if (tvb_ascii_isprint(tvb
, 2, len
)) {
1085 pi
= proto_tree_add_item(pt
, t
->hf_e164_str
, tvb
, 2, len
, ENC_ASCII
| ENC_NA
);
1087 pi
= proto_tree_add_item(pt
, t
->hf_other
, tvb
, 2, -1, ENC_BIG_ENDIAN
);
1091 pi
= proto_tree_add_item(pt
,t
->hf_other
,tvb
,2,-1,ENC_BIG_ENDIAN
);
1096 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1097 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1098 label
= strstr(label
,": ")+2;
1105 proto_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
1107 proto_avp_t
*t
= (proto_avp_t
*)a
->type_data
;
1109 col_set_writable(c
->pinfo
->cinfo
, COL_PROTOCOL
, false);
1110 col_set_writable(c
->pinfo
->cinfo
, COL_INFO
, false);
1113 t
->handle
= find_dissector(t
->name
);
1114 if (!t
->handle
) t
->handle
= data_handle
;
1118 call_dissector_with_data(t
->handle
, tvb
, c
->pinfo
, c
->tree
, diam_sub_dis_inf
);
1120 CATCH_NONFATAL_ERRORS
{
1121 show_exception(tvb
, c
->pinfo
, c
->tree
, EXCEPT_CODE
, GET_MESSAGE
);
1129 time_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1131 int len
= tvb_reported_length(tvb
);
1136 proto_tree_add_expert_format(c
->tree
, c
->pinfo
, &ei_diameter_avp_len
, tvb
, 0, 4,
1137 "Bad Timestamp Length: %d instead of 4", len
);
1138 return "[Malformed]";
1142 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1143 pi
= proto_tree_add_item(c
->tree
, (a
->hf_value
), tvb
, 0, 4, ENC_TIME_SECS_NTP
|ENC_BIG_ENDIAN
);
1144 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1145 label
= strstr(label
,": ")+2;
1152 address_radius_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1156 address_avp_t
*t
= (address_avp_t
*)a
->type_data
;
1157 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_reported_length(tvb
),ENC_BIG_ENDIAN
);
1158 proto_tree
*pt
= proto_item_add_subtree(pi
,t
->ett
);
1159 uint32_t len
= tvb_reported_length(tvb
);
1163 pi
= proto_tree_add_item(pt
,t
->hf_ipv4
,tvb
,0,4,ENC_BIG_ENDIAN
);
1166 pi
= proto_tree_add_item(pt
,t
->hf_ipv6
,tvb
,0,16,ENC_NA
);
1169 pi
= proto_tree_add_item(pt
,t
->hf_other
,tvb
,0,len
,ENC_BIG_ENDIAN
);
1170 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1171 "Bad Address Length (%u)", len
);
1177 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1178 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1179 label
= strstr(label
,": ")+2;
1186 simple_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1191 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_reported_length(tvb
),ENC_BIG_ENDIAN
);
1192 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1193 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1194 label
= strstr(label
,": ")+2;
1201 utf8_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1206 proto_item
*pi
= proto_tree_add_item(c
->tree
,a
->hf_value
,tvb
,0,tvb_reported_length(tvb
),ENC_UTF_8
|ENC_BIG_ENDIAN
);
1207 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1208 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1209 label
= strstr(label
,": ")+2;
1216 integer32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1221 /* Verify length before adding */
1222 int length
= tvb_reported_length(tvb
);
1225 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1226 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1227 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1228 label
= strstr(label
,": ")+2;
1232 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1233 tvb
, 0, length
, NULL
,
1234 "Error! Bad Integer32 Length");
1235 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1236 "Bad Integer32 Length (%u)", length
);
1237 proto_item_set_generated(pi
);
1244 integer64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1249 /* Verify length before adding */
1250 int length
= tvb_reported_length(tvb
);
1253 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1254 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1255 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1256 label
= strstr(label
,": ")+2;
1260 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1261 tvb
, 0, length
, NULL
,
1262 "Error! Bad Integer64 Length");
1263 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1264 "Bad Integer64 Length (%u)", length
);
1265 proto_item_set_generated(pi
);
1272 unsigned32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
1277 /* Verify length before adding */
1278 int length
= tvb_reported_length(tvb
);
1281 diam_sub_dis_inf
->item
= pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1282 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1283 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1284 label
= strstr(label
,": ")+2;
1288 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1289 tvb
, 0, length
, NULL
,
1290 "Error! Bad Unsigned32 Length");
1291 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1292 "Bad Unsigned32 Length (%u)", length
);
1293 proto_item_set_generated(pi
);
1300 unsigned64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1305 /* Verify length before adding */
1306 int length
= tvb_reported_length(tvb
);
1309 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1310 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1311 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1312 label
= strstr(label
,": ")+2;
1316 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1317 tvb
, 0, length
, NULL
,
1318 "Error! Bad Unsigned64 Length");
1319 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1320 "Bad Unsigned64 Length (%u)", length
);
1321 proto_item_set_generated(pi
);
1328 float32_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1333 /* Verify length before adding */
1334 int length
= tvb_reported_length(tvb
);
1337 pi
= proto_tree_add_item(c
->tree
,a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1338 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1339 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1340 label
= strstr(label
,": ")+2;
1344 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1345 tvb
, 0, length
, NULL
,
1346 "Error! Bad Float32 Length");
1347 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1348 "Bad Float32 Length (%u)", length
);
1349 proto_item_set_generated(pi
);
1356 float64_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf _U_
)
1361 /* Verify length before adding */
1362 int length
= tvb_reported_length(tvb
);
1365 pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0, length
, ENC_BIG_ENDIAN
);
1366 label
= (char *)wmem_alloc(c
->pinfo
->pool
, ITEM_LABEL_LENGTH
+1);
1367 proto_item_fill_label(PITEM_FINFO(pi
), label
, NULL
);
1368 label
= strstr(label
,": ")+2;
1372 pi
= proto_tree_add_bytes_format(c
->tree
, hf_diameter_avp_data_wrong_length
,
1373 tvb
, 0, length
, NULL
,
1374 "Error! Bad Float64 Length");
1375 expert_add_info_format(c
->pinfo
, pi
, &ei_diameter_avp_len
,
1376 "Bad Float64 Length (%u)", length
);
1377 proto_item_set_generated(pi
);
1384 grouped_avp(diam_ctx_t
*c
, diam_avp_t
*a
, tvbuff_t
*tvb
, diam_sub_dis_t
*diam_sub_dis_inf
)
1387 int len
= tvb_reported_length(tvb
);
1388 proto_item
*pi
= proto_tree_add_item(c
->tree
, a
->hf_value
, tvb
, 0 , -1, ENC_BIG_ENDIAN
);
1389 proto_tree
*pt
= c
->tree
;
1391 c
->tree
= proto_item_add_subtree(pi
,a
->ett
);
1393 /* Set the flag that we are dissecting a grouped AVP */
1394 diam_sub_dis_inf
->dis_gouped
= true;
1395 while (offset
< len
) {
1396 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
, false);
1398 /* Clear info collected in grouped AVP */
1399 diam_sub_dis_inf
->vendor_id
= 0;
1400 diam_sub_dis_inf
->dis_gouped
= false;
1401 diam_sub_dis_inf
->avp_str
= NULL
;
1408 static const char *msgflags_str
[] = {
1409 "----", "---T", "--E-", "--ET",
1410 "-P--", "-P-T", "-PE-", "-PET",
1411 "R---", "R--T", "R-E-", "R-ET",
1412 "RP--", "RP-T", "RPE-", "RPET"
1415 static int * const diameter_flags_fields
[] = {
1416 &hf_diameter_flags_request
,
1417 &hf_diameter_flags_proxyable
,
1418 &hf_diameter_flags_error
,
1419 &hf_diameter_flags_T
,
1420 &hf_diameter_flags_reserved4
,
1421 &hf_diameter_flags_reserved5
,
1422 &hf_diameter_flags_reserved6
,
1423 &hf_diameter_flags_reserved7
,
1428 dissect_diameter_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1431 uint64_t flags_bits
;
1433 proto_item
*pi
, *cmd_item
, *app_item
, *version_item
;
1434 proto_tree
*diam_tree
;
1435 diam_ctx_t
*c
= wmem_new0(pinfo
->pool
, diam_ctx_t
);
1437 const char *cmd_str
;
1439 uint32_t hop_by_hop_id
, end_to_end_id
;
1440 conversation_t
*conversation
;
1441 diameter_conv_info_t
*diameter_conv_info
;
1442 diameter_req_ans_pair_t
*diameter_pair
= NULL
;
1443 wmem_tree_t
*pdus_tree
;
1446 diam_sub_dis_t
*diam_sub_dis_inf
= wmem_new0(pinfo
->pool
, diam_sub_dis_t
);
1448 /* Set default value Subscription-Id-Type and User-Equipment-Info-Type as XXX_UNKNOWN */
1449 diam_sub_dis_inf
->subscription_id_type
= SUBSCRIPTION_ID_TYPE_UNKNOWN
;
1450 diam_sub_dis_inf
->user_equipment_info_type
= USER_EQUIPMENT_INFO_TYPE_UNKNOWN
;
1452 /* Load header fields if not already done */
1453 if (hf_diameter_code
<= 0)
1454 proto_registrar_get_byname("diameter.code");
1455 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1458 if (have_tap_listener(exported_pdu_tap
)){
1459 export_diameter_pdu(pinfo
,tvb
);
1462 pi
= proto_tree_add_item(tree
,proto_diameter
,tvb
,0,-1,ENC_NA
);
1463 diam_tree
= proto_item_add_subtree(pi
,ett_diameter
);
1465 c
->tree
= diam_tree
;
1468 version_item
= proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_version
, tvb
, 0, 1, ENC_BIG_ENDIAN
, &version
);
1469 if (version
!= DIAMETER_RFC
) {
1470 expert_add_info(c
->pinfo
, version_item
, &ei_diameter_version
);
1472 proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_length
, tvb
, 1, 3, ENC_BIG_ENDIAN
, &packet_len
);
1474 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
);
1475 if (flags_bits
& 0x0f) {
1476 expert_add_info(c
->pinfo
, pi
, &ei_diameter_reserved_bit_set
);
1479 diam_sub_dis_inf
->parent_message_is_request
= (flags_bits
& DIAM_FLAGS_R
) ? true : false;
1481 cmd_item
= proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_code
, tvb
, 5, 3, ENC_BIG_ENDIAN
, &cmd
);
1482 diam_sub_dis_inf
->cmd_code
= cmd
;
1484 app_item
= proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_application_id
, tvb
, 8, 4,
1485 ENC_BIG_ENDIAN
, &diam_sub_dis_inf
->application_id
);
1487 if (try_val_to_str_ext(diam_sub_dis_inf
->application_id
, dictionary
.applications
) == NULL
) {
1488 proto_tree
*tu
= proto_item_add_subtree(app_item
,ett_unknown
);
1489 proto_tree_add_expert_format(tu
, c
->pinfo
, &ei_diameter_application_id
, tvb
, 8, 4,
1490 "Unknown Application Id (%u), if you know what this is you can add it to dictionary.xml", diam_sub_dis_inf
->application_id
);
1493 cmd_str
= val_to_str_const(cmd
, cmd_vs
, "Unknown");
1494 if (strcmp(cmd_str
, "Unknown") == 0) {
1495 expert_add_info(c
->pinfo
, cmd_item
, &ei_diameter_code
);
1499 proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_hopbyhopid
, tvb
, 12, 4, ENC_BIG_ENDIAN
, &hop_by_hop_id
);
1500 proto_tree_add_item_ret_uint(diam_tree
, hf_diameter_endtoendid
, tvb
, 16, 4, ENC_BIG_ENDIAN
, &end_to_end_id
);
1502 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
1503 "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
1505 ((flags_bits
>>4)&0x08) ? " Request" : " Answer",
1507 msgflags_str
[((flags_bits
>>4)&0x0f)],
1509 val_to_str_ext_const(diam_sub_dis_inf
->application_id
, dictionary
.applications
, "Unknown"),
1510 diam_sub_dis_inf
->application_id
,
1514 col_append_str(pinfo
->cinfo
, COL_INFO
, " | ");
1515 col_set_fence(pinfo
->cinfo
, COL_INFO
);
1518 /* Conversation tracking stuff */
1520 * FIXME: Looking at epan/conversation.c it seems unlikely that this will work properly in
1521 * multi-homed SCTP connections. This will probably need to be fixed at some point.
1524 conversation
= find_or_create_conversation(pinfo
);
1526 diameter_conv_info
= (diameter_conv_info_t
*)conversation_get_proto_data(conversation
, proto_diameter
);
1527 if (!diameter_conv_info
) {
1528 diameter_conv_info
= wmem_new(wmem_file_scope(), diameter_conv_info_t
);
1529 diameter_conv_info
->pdu_trees
= wmem_map_new(wmem_file_scope(), g_direct_hash
, g_direct_equal
);
1531 conversation_add_proto_data(conversation
, proto_diameter
, diameter_conv_info
);
1534 /* pdus_tree is an wmem_tree keyed by frame number (in order to handle hop-by-hop collisions */
1535 pdus_tree
= (wmem_tree_t
*)wmem_map_lookup(diameter_conv_info
->pdu_trees
, GUINT_TO_POINTER(hop_by_hop_id
));
1537 if (pdus_tree
== NULL
&& (flags_bits
& DIAM_FLAGS_R
)) {
1538 /* This is the first request we've seen with this hop-by-hop id */
1539 pdus_tree
= wmem_tree_new(wmem_file_scope());
1540 wmem_map_insert(diameter_conv_info
->pdu_trees
, GUINT_TO_POINTER(hop_by_hop_id
), pdus_tree
);
1544 if (!pinfo
->fd
->visited
) {
1545 if (flags_bits
& DIAM_FLAGS_R
) {
1546 /* This is a request */
1547 diameter_pair
= wmem_new(wmem_file_scope(), diameter_req_ans_pair_t
);
1548 diameter_pair
->hop_by_hop_id
= hop_by_hop_id
;
1549 diameter_pair
->end_to_end_id
= end_to_end_id
;
1550 diameter_pair
->cmd_code
= cmd
;
1551 diameter_pair
->result_code
= 0;
1552 diameter_pair
->cmd_str
= cmd_str
;
1553 diameter_pair
->req_frame
= pinfo
->num
;
1554 diameter_pair
->ans_frame
= 0;
1555 diameter_pair
->req_time
= pinfo
->abs_ts
;
1556 wmem_tree_insert32(pdus_tree
, pinfo
->num
, (void *)diameter_pair
);
1558 /* Look for a request which occurs earlier in the trace than this answer. */
1559 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_tree_lookup32_le(pdus_tree
, pinfo
->num
);
1561 /* Verify the end-to-end-id matches before declaring a match */
1562 if (diameter_pair
&& diameter_pair
->end_to_end_id
== end_to_end_id
) {
1563 diameter_pair
->ans_frame
= pinfo
->num
;
1567 /* Look for a request which occurs earlier in the trace than this answer. */
1568 diameter_pair
= (diameter_req_ans_pair_t
*)wmem_tree_lookup32_le(pdus_tree
, pinfo
->num
);
1570 /* If the end-to-end ID doesn't match then this is not the request we were
1573 if (diameter_pair
&& diameter_pair
->end_to_end_id
!= end_to_end_id
)
1574 diameter_pair
= NULL
;
1578 if (!diameter_pair
) {
1579 /* create a "fake" diameter_pair structure */
1580 diameter_pair
= wmem_new(pinfo
->pool
, diameter_req_ans_pair_t
);
1581 diameter_pair
->hop_by_hop_id
= hop_by_hop_id
;
1582 diameter_pair
->cmd_code
= cmd
;
1583 diameter_pair
->result_code
= 0;
1584 diameter_pair
->cmd_str
= cmd_str
;
1585 diameter_pair
->req_frame
= 0;
1586 diameter_pair
->ans_frame
= 0;
1587 diameter_pair
->req_time
= pinfo
->abs_ts
;
1589 diameter_pair
->processing_request
=(flags_bits
& DIAM_FLAGS_R
)!= 0;
1591 /* print state tracking info in the tree */
1592 if (flags_bits
& DIAM_FLAGS_R
) {
1593 /* This is a request */
1594 if (diameter_pair
->ans_frame
) {
1595 it
= proto_tree_add_uint(diam_tree
, hf_diameter_answer_in
,
1596 tvb
, 0, 0, diameter_pair
->ans_frame
);
1597 proto_item_set_generated(it
);
1600 /* This is an answer */
1601 if (diameter_pair
->req_frame
) {
1602 it
= proto_tree_add_uint(diam_tree
, hf_diameter_answer_to
,
1603 tvb
, 0, 0, diameter_pair
->req_frame
);
1604 proto_item_set_generated(it
);
1606 nstime_delta(&ns
, &pinfo
->abs_ts
, &diameter_pair
->req_time
);
1607 diameter_pair
->srt_time
= ns
;
1608 it
= proto_tree_add_time(diam_tree
, hf_diameter_answer_time
, tvb
, 0, 0, &ns
);
1609 proto_item_set_generated(it
);
1610 /* TODO: Populate result_code in tap record from AVP 268 */
1616 /* Dissect AVPs until the end of the packet is reached */
1617 while (offset
< packet_len
) {
1618 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
, false);
1621 /* Handle requests for which no answers were found and
1622 * answers for which no requests were found in the tap listener.
1623 * In case if you don't need unpaired requests/answers use:
1624 * if (diameter_pair->processing_request || !diameter_pair->req_frame)
1627 tap_queue_packet(diameter_tap
, pinfo
, diameter_pair
);
1629 return tvb_reported_length(tvb
);
1633 get_diameter_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
1634 int offset
, void *data _U_
)
1636 /* Get the length of the Diameter packet. */
1637 return tvb_get_ntoh24(tvb
, offset
+ 1);
1640 #define NOT_DIAMETER 0
1641 #define IS_DIAMETER 1
1642 #define NOT_ENOUGH_DATA 2
1644 check_diameter(tvbuff_t
*tvb
)
1649 /* Ensure we don't throw an exception trying to do these heuristics */
1650 if (tvb_captured_length(tvb
) < 5)
1651 return NOT_ENOUGH_DATA
;
1653 /* Check if the Diameter version is 1 */
1654 if (tvb_get_uint8(tvb
, 0) != 1)
1655 return NOT_DIAMETER
;
1657 /* Diameter minimum message length:
1659 * Version+Length - 4 bytes
1660 * Flags+CC - 4 bytes
1664 * 2 AVPs (Orig-Host, Orig-Realm), each including:
1665 * * AVP code - 4 bytes
1666 * * AVP flags + length - 4 bytes
1667 * * (no data - what would a reasonable minimum be?)
1671 msg_len
= tvb_get_ntoh24(tvb
, 1);
1672 /* Diameter message length field must be a multiple of 4.
1673 * This is implicit in RFC 3588 (based on the header and that each
1674 * AVP must align on a 32-bit boundary) and explicit in RFC 6733.
1676 if ((msg_len
< 36) || (msg_len
& 0x3))
1677 return NOT_DIAMETER
;
1679 flags
= tvb_get_uint8(tvb
, 4);
1681 /* Check if any of the Reserved flag bits are set */
1683 return NOT_DIAMETER
;
1685 /* Check if both the R- and E-bits are set */
1686 if ((flags
& DIAM_FLAGS_R
) && (flags
& DIAM_FLAGS_E
))
1687 return NOT_DIAMETER
;
1692 /*****************************************************************/
1693 /* Main dissection function */
1694 /* Checks if the message looks like Diameter before accepting it */
1695 /*****************************************************************/
1697 dissect_diameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1699 if (check_diameter(tvb
) != IS_DIAMETER
)
1701 return dissect_diameter_common(tvb
, pinfo
, tree
, data
);
1705 dissect_diameter_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1707 int is_diam
= check_diameter(tvb
);
1709 if (is_diam
== NOT_DIAMETER
) {
1710 /* We've probably been given a frame that's not the start of
1713 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1714 col_set_str(pinfo
->cinfo
, COL_INFO
, "Continuation");
1715 call_dissector(data_handle
, tvb
, pinfo
, tree
);
1716 } else if (is_diam
== NOT_ENOUGH_DATA
) {
1717 /* Since we're doing our heuristic checks before
1718 * tcp_dissect_pdus() (since we can't do heuristics once
1719 * we're in there) we sometimes have to ask for more data...
1721 pinfo
->desegment_offset
= 0;
1722 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
1724 tcp_dissect_pdus(tvb
, pinfo
, tree
, gbl_diameter_desegment
, 4,
1725 get_diameter_pdu_len
, dissect_diameter_common
, data
);
1728 return tvb_reported_length(tvb
);
1732 dissect_diameter_tcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1734 if (check_diameter(tvb
) != IS_DIAMETER
) {
1738 conversation_set_dissector(find_or_create_conversation(pinfo
), diameter_tcp_handle
);
1740 tcp_dissect_pdus(tvb
, pinfo
, tree
, gbl_diameter_desegment
, 4,
1741 get_diameter_pdu_len
, dissect_diameter_common
, data
);
1747 dissect_diameter_avps(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1750 proto_tree
*diam_tree
;
1752 diam_ctx_t
*c
= wmem_new0(pinfo
->pool
, diam_ctx_t
);
1753 diam_sub_dis_t
*diam_sub_dis_inf
= wmem_new0(pinfo
->pool
, diam_sub_dis_t
);
1755 /* Load header fields if not already done */
1756 if (hf_diameter_code
<= 0)
1757 proto_registrar_get_byname("diameter.code");
1759 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DIAMETER");
1760 col_set_str(pinfo
->cinfo
, COL_INFO
, "AVPs:");
1762 pi
= proto_tree_add_item(tree
, proto_diameter
, tvb
, 0, -1, ENC_NA
);
1763 diam_tree
= proto_item_add_subtree(pi
, ett_diameter
);
1764 c
->tree
= diam_tree
;
1767 /* Dissect AVPs until the end of the packet is reached */
1768 while (tvb_reported_length_remaining(tvb
, offset
)) {
1769 offset
+= dissect_diameter_avp(c
, tvb
, offset
, diam_sub_dis_inf
, true);
1771 return tvb_reported_length(tvb
);
1775 alnumerize(char *name
)
1781 for (;(c
= *r
); r
++) {
1782 if (g_ascii_isalnum(c
) || c
== '_' || c
== '-' || c
== '.') {
1794 reginfo(int *hf_ptr
, const char *name
, const char *abbr
, const char *desc
,
1795 enum ftenum ft
, field_display_e base
, value_string_ext
*vs_ext
,
1798 hf_register_info hf
;
1801 hf
.hfinfo
.name
= name
;
1802 hf
.hfinfo
.abbrev
= abbr
;
1803 hf
.hfinfo
.type
= ft
;
1804 hf
.hfinfo
.display
= base
;
1805 hf
.hfinfo
.strings
= NULL
;
1806 hf
.hfinfo
.bitmask
= mask
;
1807 hf
.hfinfo
.blurb
= desc
;
1812 hf
.hfinfo
.strings
= vs_ext
;
1815 wmem_array_append_one(build_dict
.hf
,hf
);
1816 return wmem_array_get_count(build_dict
.hf
);
1820 basic_avp_reginfo(diam_avp_t
*a
, const char *name
, enum ftenum ft
,
1821 field_display_e base
, value_string_ext
*vs_ext
)
1823 hf_register_info hf
;
1824 int *ettp
= &(a
->ett
);
1826 hf
.p_id
= &(a
->hf_value
);
1827 hf
.hfinfo
.name
= NULL
;
1828 hf
.hfinfo
.abbrev
= NULL
;
1829 hf
.hfinfo
.type
= ft
;
1830 hf
.hfinfo
.display
= base
;
1831 hf
.hfinfo
.strings
= NULL
;
1832 hf
.hfinfo
.bitmask
= 0x0;
1833 hf
.hfinfo
.blurb
= a
->vendor
->code
?
1834 wmem_strdup_printf(wmem_epan_scope(), "vendor=%d code=%d", a
->vendor
->code
, a
->code
)
1835 : wmem_strdup_printf(wmem_epan_scope(), "code=%d", a
->code
);
1839 hf
.hfinfo
.name
= wmem_strdup(wmem_epan_scope(), name
);
1840 hf
.hfinfo
.abbrev
= alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, NULL
));
1842 hf
.hfinfo
.strings
= vs_ext
;
1845 wmem_array_append(build_dict
.hf
,&hf
,1);
1846 g_ptr_array_add(build_dict
.ett
,ettp
);
1850 build_gen_address_avp(diam_avp_t
*a
, address_avp_t
*t
, const char *name
)
1852 int *ettp
= &(t
->ett
);
1859 t
->hf_address_type
= -1;
1862 t
->hf_e164_str
= -1;
1865 basic_avp_reginfo(a
, name
, FT_BYTES
, BASE_NONE
, NULL
);
1867 reginfo(&(t
->hf_address_type
), wmem_strconcat(wmem_epan_scope(), name
, " Address Family", NULL
),
1868 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".addr_family", NULL
)),
1869 NULL
, FT_UINT16
, (field_display_e
)(BASE_DEC
|BASE_EXT_STRING
), &diameter_avp_data_addrfamily_vals_ext
, 0);
1871 reginfo(&(t
->hf_ipv4
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1872 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".IPv4", NULL
)),
1873 NULL
, FT_IPv4
, BASE_NONE
, NULL
, 0);
1875 reginfo(&(t
->hf_ipv6
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1876 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".IPv6", NULL
)),
1877 NULL
, FT_IPv6
, BASE_NONE
, NULL
, 0);
1879 reginfo(&(t
->hf_e164_str
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1880 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".E164", NULL
)),
1881 NULL
, FT_STRING
, BASE_NONE
, NULL
, 0);
1883 reginfo(&(t
->hf_other
), wmem_strconcat(wmem_epan_scope(), name
, " Address", NULL
),
1884 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name
, ".Bytes", NULL
)),
1885 NULL
, FT_BYTES
, BASE_NONE
, NULL
, 0);
1887 g_ptr_array_add(build_dict
.ett
,ettp
);
1894 * > AVP numbers 1 through 255 are reserved for reuse of RADIUS attributes,
1895 * > without setting the Vendor-Id field.
1897 * This clearly applies not to vendor dictionaries. However, some vendors seem to have
1898 * translated their RADIUS dictionaries to Diameter with that assumption in mind, while
1901 * To make this work universally, the type `ipaddress` is assumed to be using the RADIUS
1902 * encoding for AVP < 256 and Diameter for AVPs >= 256, while the `address` type will
1903 * use Diameter encoding for all AVPs
1906 build_ipaddress_avp(const avp_type_t
*type _U_
, uint32_t code
,
1907 diam_vnd_t
*vendor
, const char *name
,
1908 const value_string
*vs _U_
, void *data _U_
)
1910 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1911 address_avp_t
*t
= wmem_new(wmem_epan_scope(), address_avp_t
);
1916 * It seems like the radius AVPs 1-255 will use the defs from RADIUS in which case:
1917 * https://tools.ietf.org/html/rfc2685
1919 * The Address field is four octets. The value 0xFFFFFFFF indicates
1920 * that the NAS Should allow the user to select an address (e.g.
1921 * Negotiated). The value 0xFFFFFFFE indicates that the NAS should
1922 * select an address for the user (e.g. Assigned from a pool of
1923 * addresses kept by the NAS). Other valid values indicate that the
1924 * NAS should use that value as the user's IP address.
1926 * Where as in Diameter:
1929 * The Address format is derived from the OctetString AVP Base
1930 * Format. It is a discriminated union, representing, for example a
1931 * 32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1932 * significant octet first. The first two octets of the Address
1933 * AVP represents the AddressType, which contains an Address Family
1934 * defined in [IANAADFAM]. The AddressType is used to discriminate
1935 * the content and format of the remaining octets.
1938 a
->dissector_rfc
= address_radius_avp
;
1940 a
->dissector_rfc
= address_rfc_avp
;
1942 return build_gen_address_avp(a
, t
, name
);
1946 build_address_avp(const avp_type_t
*type _U_
, uint32_t code
,
1947 diam_vnd_t
*vendor
, const char *name
,
1948 const value_string
*vs _U_
, void *data _U_
)
1950 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1951 address_avp_t
*t
= wmem_new(wmem_epan_scope(), address_avp_t
);
1955 a
->dissector_rfc
= address_rfc_avp
;
1957 return build_gen_address_avp(a
, t
, name
);
1961 build_proto_avp(const avp_type_t
*type _U_
, uint32_t code
,
1962 diam_vnd_t
*vendor
, const char *name _U_
,
1963 const value_string
*vs _U_
, void *data
)
1965 diam_avp_t
*a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
1966 proto_avp_t
*t
= wmem_new0(wmem_epan_scope(), proto_avp_t
);
1967 int *ettp
= &(a
->ett
);
1971 a
->dissector_rfc
= proto_avp
;
1976 t
->name
= (char *)data
;
1978 t
->reassemble_mode
= REASEMBLE_NEVER
;
1980 g_ptr_array_add(build_dict
.ett
,ettp
);
1986 build_simple_avp(const avp_type_t
*type
, uint32_t code
, diam_vnd_t
*vendor
,
1987 const char *name
, const value_string
*vs
, void *data _U_
)
1990 value_string_ext
*vs_ext
= NULL
;
1991 field_display_e base
;
1995 * Only 32-bit or shorter integral types can have a list of values.
1997 base
= (field_display_e
)type
->base
;
2010 report_failure("Diameter Dictionary: AVP '%s' has a list of values but isn't of a 32-bit or shorter integral type (%s)\n",
2011 name
, ftype_name(type
->ft
));
2014 while (vs
[i
].strptr
) {
2017 vs_ext
= value_string_ext_new(vs
, i
+1, wmem_strconcat(wmem_epan_scope(), name
, "_vals_ext", NULL
));
2018 base
= (field_display_e
)(base
|BASE_EXT_STRING
);
2021 a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
2024 a
->dissector_rfc
= type
->rfc
;
2028 basic_avp_reginfo(a
, name
, type
->ft
, base
, vs_ext
);
2034 build_appid_avp(const avp_type_t
*type
, uint32_t code
, diam_vnd_t
*vendor
,
2035 const char *name
, const value_string
*vs
, void *data _U_
)
2038 field_display_e base
;
2040 a
= wmem_new0(wmem_epan_scope(), diam_avp_t
);
2043 a
->dissector_rfc
= type
->rfc
;
2048 report_failure("Diameter Dictionary: AVP '%s' (of type AppId) has a list of values but the list won't be used\n",
2052 base
= (field_display_e
)(type
->base
|BASE_EXT_STRING
);
2054 basic_avp_reginfo(a
, name
, type
->ft
, base
, dictionary
.applications
);
2058 static const avp_type_t basic_types
[] = {
2059 {"octetstring" , simple_avp
, FT_BYTES
, BASE_NONE
, build_simple_avp
},
2060 {"octetstringorutf8" , simple_avp
, FT_BYTES
, BASE_SHOW_ASCII_PRINTABLE
, build_simple_avp
},
2061 {"utf8string" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2062 {"grouped" , grouped_avp
, FT_BYTES
, BASE_NONE
, build_simple_avp
},
2063 {"integer32" , integer32_avp
, FT_INT32
, BASE_DEC
, build_simple_avp
},
2064 {"unsigned32" , unsigned32_avp
, FT_UINT32
, BASE_DEC
, build_simple_avp
},
2065 {"integer64" , integer64_avp
, FT_INT64
, BASE_DEC
, build_simple_avp
},
2066 {"unsigned64" , unsigned64_avp
, FT_UINT64
, BASE_DEC
, build_simple_avp
},
2067 {"float32" , float32_avp
, FT_FLOAT
, BASE_NONE
, build_simple_avp
},
2068 {"float64" , float64_avp
, FT_DOUBLE
, BASE_NONE
, build_simple_avp
},
2069 {"ipaddress" , NULL
, FT_NONE
, BASE_NONE
, build_ipaddress_avp
},
2070 {"address" , NULL
, FT_NONE
, BASE_NONE
, build_address_avp
},
2071 {"diameteruri" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2072 {"diameteridentity" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2073 {"ipfilterrule" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2074 {"qosfilterrule" , utf8_avp
, FT_STRING
, BASE_NONE
, build_simple_avp
},
2075 {"time" , time_avp
, FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_UTC
, build_simple_avp
},
2076 {"AppId" , simple_avp
, FT_UINT32
, BASE_DEC
, build_appid_avp
},
2077 {NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
}
2083 * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
2084 * upper-case ASCII characters to their ASCII lower-case equivalents.
2085 * We can't use g_strdown(), as that doesn't do an ASCII mapping;
2086 * in Turkish locales, for example, there are two lower-case "i"s
2087 * and two upper-case "I"s, with and without dots - the ones with
2088 * dots map between each other, as do the ones without dots, so "I"
2089 * doesn't map to "i".
2092 strcase_hash(const void *key
)
2094 const char *p
= (const char *)key
;
2099 if (h
>= 'A' && h
<= 'Z')
2101 for (p
+= 1; *p
!= '\0'; p
++) {
2103 if (c
>= 'A' && c
<= 'Z')
2105 h
= (h
<< 5) - h
+ c
;
2113 * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
2114 * letters are mapped, and they're mapped to the lower-case ASCII
2118 strcase_equal(const void *ka
, const void *kb
)
2120 const char *a
= (const char *)ka
;
2121 const char *b
= (const char *)kb
;
2122 return g_ascii_strcasecmp(a
,b
) == 0;
2126 ddict_cleanup_cb(wmem_allocator_t
* allocator _U_
, wmem_cb_event_t event _U_
, void *user_data
)
2128 ddict_t
*d
= (ddict_t
*)user_data
;
2134 /* Note: Dynamic "value string arrays" (e.g., vs_avps, ...) are constructed using */
2135 /* "zero-terminated" GArrays so that they will have the same form as standard */
2136 /* value_string arrays created at compile time. Since the last entry in a */
2137 /* value_string array must be {0, NULL}, we are assuming that NULL == 0 (hackish). */
2140 dictionary_load(void)
2143 ddict_application_t
*p
;
2146 ddict_typedefn_t
*t
;
2148 bool do_debug_parser
= getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? true : false;
2149 bool do_dump_dict
= getenv("WIRESHARK_DUMP_DIAM_DICT") ? true : false;
2151 const avp_type_t
*type
;
2152 const avp_type_t
*octetstring
= &basic_types
[0];
2154 GHashTable
*vendors
= g_hash_table_new(strcase_hash
,strcase_equal
);
2156 GArray
*vnd_shrt_arr
= g_array_new(true,true,sizeof(value_string
));
2157 GArray
*all_cmds
= g_array_new(true,true,sizeof(value_string
));
2159 /* Pre allocate the arrays big enough to hold the hf:s and etts:s*/
2160 build_dict
.hf
= wmem_array_sized_new(wmem_epan_scope(), sizeof(hf_register_info
), 4096);
2161 build_dict
.ett
= g_ptr_array_sized_new(4096);
2162 build_dict
.types
= g_hash_table_new(strcase_hash
,strcase_equal
);
2163 build_dict
.avps
= g_hash_table_new(strcase_hash
,strcase_equal
);
2165 dictionary
.vnds
= wmem_tree_new(wmem_epan_scope());
2166 dictionary
.avps
= wmem_tree_new(wmem_epan_scope());
2168 unknown_vendor
.vs_avps
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2169 wmem_array_set_null_terminator(unknown_vendor
.vs_avps
);
2170 wmem_array_bzero(unknown_vendor
.vs_avps
);
2171 no_vnd
.vs_avps
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2172 wmem_array_set_null_terminator(no_vnd
.vs_avps
);
2173 wmem_array_bzero(no_vnd
.vs_avps
);
2175 wmem_tree_insert32(dictionary
.vnds
,0,&no_vnd
);
2176 g_hash_table_insert(vendors
,"None",&no_vnd
);
2178 /* initialize the types hash with the known basic types */
2179 for (type
= basic_types
; type
->name
; type
++) {
2180 g_hash_table_insert(build_dict
.types
,(char *)type
->name
,(void *)type
);
2183 /* load the dictionary */
2184 dir
= wmem_strdup_printf(NULL
, "%s" G_DIR_SEPARATOR_S
"diameter" G_DIR_SEPARATOR_S
, get_datafile_dir());
2185 d
= ddict_scan(dir
,"dictionary.xml",do_debug_parser
);
2186 wmem_free(NULL
, dir
);
2188 g_hash_table_destroy(vendors
);
2189 g_array_free(vnd_shrt_arr
, true);
2192 wmem_register_callback(wmem_epan_scope(), ddict_cleanup_cb
, d
);
2194 if (do_dump_dict
) ddict_print(stdout
, d
);
2196 /* populate the types */
2197 for (t
= d
->typedefns
; t
; t
= t
->next
) {
2198 const avp_type_t
*parent
= NULL
;
2199 /* try to get the parent type */
2201 if (t
->name
== NULL
) {
2202 report_failure("Diameter Dictionary: Invalid Type (empty name): parent==%s\n",
2203 t
->parent
? t
->parent
: "(null)");
2208 if (g_hash_table_lookup(build_dict
.types
,t
->name
))
2212 parent
= (avp_type_t
*)g_hash_table_lookup(build_dict
.types
,t
->parent
);
2215 if (!parent
) parent
= octetstring
;
2217 /* insert the parent type for this type */
2218 g_hash_table_insert(build_dict
.types
,t
->name
,(void *)parent
);
2221 /* populate the applications */
2222 if ((p
= d
->applications
)) {
2223 wmem_array_t
*arr
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2224 value_string term
[1];
2227 term
[0].strptr
= NULL
;
2229 for (; p
; p
= p
->next
) {
2230 value_string item
[1];
2232 item
[0].value
= p
->code
;
2233 item
[0].strptr
= p
->name
;
2235 report_failure("Diameter Dictionary: Invalid Application (empty name): id=%d\n", p
->code
);
2239 wmem_array_append_one(arr
,item
);
2242 wmem_array_sort(arr
, compare_avps
);
2243 wmem_array_append_one(arr
,term
);
2245 /* TODO: Remove duplicates */
2247 dictionary
.applications
= value_string_ext_new((value_string
*)wmem_array_get_raw(arr
),
2248 wmem_array_get_count(arr
),
2249 wmem_strdup(wmem_epan_scope(), "applications_vals_ext"));
2252 if ((v
= d
->vendors
)) {
2253 for ( ; v
; v
= v
->next
) {
2254 value_string item
[1];
2256 item
[0].value
= v
->code
;
2257 item
[0].strptr
= v
->name
;
2259 if (v
->name
== NULL
) {
2260 report_failure("Diameter Dictionary: Invalid Vendor (empty name): code==%d\n", v
->code
);
2264 if (g_hash_table_lookup(vendors
,v
->name
))
2267 g_array_append_val(vnd_shrt_arr
,item
);
2269 vnd
= wmem_new(wmem_epan_scope(), diam_vnd_t
);
2270 vnd
->code
= v
->code
;
2271 vnd
->vs_avps
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2272 wmem_array_set_null_terminator(vnd
->vs_avps
);
2273 wmem_array_bzero(vnd
->vs_avps
);
2274 vnd
->vs_avps_ext
= NULL
;
2275 wmem_tree_insert32(dictionary
.vnds
,vnd
->code
,vnd
);
2276 g_hash_table_insert(vendors
,v
->name
,vnd
);
2280 vnd_short_vs
= (value_string
*)g_array_free(vnd_shrt_arr
, false);
2282 if ((c
= d
->cmds
)) {
2283 for (; c
; c
= c
->next
) {
2284 if (c
->vendor
== NULL
) {
2285 report_failure("Diameter Dictionary: Invalid Vendor (empty name) for command %s\n",
2286 c
->name
? c
->name
: "(null)");
2290 if ((diam_vnd_t
*)g_hash_table_lookup(vendors
,c
->vendor
)) {
2291 value_string item
[1];
2293 item
[0].value
= c
->code
;
2294 item
[0].strptr
= c
->name
;
2296 g_array_append_val(all_cmds
,item
);
2298 report_failure("Diameter Dictionary: No Vendor: %s\n",c
->vendor
);
2304 for (a
= d
->avps
; a
; a
= a
->next
) {
2306 value_string
*vs
= NULL
;
2307 const char *vend
= a
->vendor
? a
->vendor
: "None";
2309 void *avp_data
= NULL
;
2311 if (a
->name
== NULL
) {
2312 report_failure("Diameter Dictionary: Invalid AVP (empty name)\n");
2316 if ((vnd
= (diam_vnd_t
*)g_hash_table_lookup(vendors
,vend
))) {
2317 value_string vndvs
[1];
2319 vndvs
[0].value
= a
->code
;
2320 vndvs
[0].strptr
= a
->name
;
2323 wmem_array_append_one(vnd
->vs_avps
,vndvs
);
2325 report_failure("Diameter Dictionary: No Vendor: %s\n",vend
);
2326 vnd
= &unknown_vendor
;
2329 if ((e
= a
->enums
)) {
2330 wmem_array_t
*arr
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2331 value_string term
[1];
2334 term
[0].strptr
= NULL
;
2336 for (; e
; e
= e
->next
) {
2337 value_string item
[1];
2339 item
[0].value
= e
->code
;
2340 item
[0].strptr
= e
->name
;
2341 wmem_array_append_one(arr
,item
);
2343 wmem_array_sort(arr
, compare_avps
);
2344 wmem_array_append_one(arr
,term
);
2345 vs
= (value_string
*)wmem_array_get_raw(arr
);
2350 for( x
= d
->xmlpis
; x
; x
= x
->next
) {
2351 if ( (strcase_equal(x
->name
,"avp-proto") && strcase_equal(x
->key
,a
->name
))
2352 || (a
->type
&& strcase_equal(x
->name
,"type-proto") && strcase_equal(x
->key
,a
->type
))
2354 static avp_type_t proto_type
= {"proto", proto_avp
, FT_UINT32
, BASE_HEX
, build_proto_avp
};
2357 avp_data
= x
->value
;
2362 if ( (!type
) && a
->type
)
2363 type
= (avp_type_t
*)g_hash_table_lookup(build_dict
.types
,a
->type
);
2365 if (!type
) type
= octetstring
;
2367 avp
= type
->build( type
, a
->code
, vnd
, a
->name
, vs
, avp_data
);
2369 g_hash_table_insert(build_dict
.avps
, a
->name
, avp
);
2372 wmem_tree_key_t k
[3];
2375 k
[0].key
= &(a
->code
);
2377 k
[1].key
= &(vnd
->code
);
2381 wmem_tree_insert32_array(dictionary
.avps
,k
,avp
);
2385 g_hash_table_destroy(build_dict
.types
);
2386 g_hash_table_destroy(build_dict
.avps
);
2387 g_hash_table_destroy(vendors
);
2389 cmd_vs
= (const value_string
*)g_array_free(all_cmds
, false);
2395 * This does most of the registration work; see register_diameter_fields()
2396 * for the reason why we split it off.
2399 real_register_diameter_fields(void)
2401 expert_module_t
* expert_diameter
;
2402 unsigned i
, ett_length
;
2404 hf_register_info hf_base
[] = {
2405 { &hf_diameter_version
,
2406 { "Version", "diameter.version", FT_UINT8
, BASE_HEX
, NULL
, 0x00,
2408 { &hf_diameter_length
,
2409 { "Length","diameter.length", FT_UINT24
, BASE_DEC
, NULL
, 0x0,
2411 { &hf_diameter_flags
,
2412 { "Flags", "diameter.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
2414 { &hf_diameter_flags_request
,
2415 { "Request", "diameter.flags.request", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_R
,
2417 { &hf_diameter_flags_proxyable
,
2418 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_P
,
2420 { &hf_diameter_flags_error
,
2421 { "Error","diameter.flags.error", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_E
,
2423 { &hf_diameter_flags_T
,
2424 { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DIAM_FLAGS_T
,
2426 { &hf_diameter_flags_reserved4
,
2427 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2428 DIAM_FLAGS_RESERVED4
, NULL
, HFILL
}},
2429 { &hf_diameter_flags_reserved5
,
2430 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2431 DIAM_FLAGS_RESERVED5
, NULL
, HFILL
}},
2432 { &hf_diameter_flags_reserved6
,
2433 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2434 DIAM_FLAGS_RESERVED6
, NULL
, HFILL
}},
2435 { &hf_diameter_flags_reserved7
,
2436 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2437 DIAM_FLAGS_RESERVED7
, NULL
, HFILL
}},
2438 { &hf_diameter_vendor_id
,
2439 { "VendorId", "diameter.vendorId", FT_UINT32
, BASE_ENTERPRISES
, STRINGS_ENTERPRISES
,
2440 0x0, NULL
, HFILL
}},
2441 { &hf_diameter_application_id
,
2442 { "ApplicationId", "diameter.applicationId", FT_UINT32
, BASE_DEC
|BASE_EXT_STRING
, VALS_EXT_PTR(dictionary
.applications
),
2443 0x0, NULL
, HFILL
}},
2444 { &hf_diameter_hopbyhopid
,
2445 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32
,
2446 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2447 { &hf_diameter_endtoendid
,
2448 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32
,
2449 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2451 { "AVP","diameter.avp", FT_BYTES
, BASE_NONE
,
2452 NULL
, 0x0, NULL
, HFILL
}},
2453 { &hf_diameter_avp_len
,
2454 { "AVP Length","diameter.avp.len", FT_UINT24
, BASE_DEC
,
2455 NULL
, 0x0, NULL
, HFILL
}},
2456 { &hf_diameter_avp_code
,
2457 { "AVP Code", "diameter.avp.code", FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2458 { &hf_diameter_avp_flags
,
2459 { "AVP Flags","diameter.avp.flags", FT_UINT8
, BASE_HEX
,
2460 NULL
, 0x0, NULL
, HFILL
}},
2461 { &hf_diameter_avp_flags_vendor_specific
,
2462 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_V
,
2464 { &hf_diameter_avp_flags_mandatory
,
2465 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_M
,
2467 { &hf_diameter_avp_flags_protected
,
2468 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), AVP_FLAGS_P
,
2470 { &hf_diameter_avp_flags_reserved3
,
2471 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2472 AVP_FLAGS_RESERVED3
, NULL
, HFILL
}},
2473 { &hf_diameter_avp_flags_reserved4
,
2474 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2475 AVP_FLAGS_RESERVED4
, NULL
, HFILL
}},
2476 { &hf_diameter_avp_flags_reserved5
,
2477 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2478 AVP_FLAGS_RESERVED5
, NULL
, HFILL
}},
2479 { &hf_diameter_avp_flags_reserved6
,
2480 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2481 AVP_FLAGS_RESERVED6
, NULL
, HFILL
}},
2482 { &hf_diameter_avp_flags_reserved7
,
2483 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
),
2484 AVP_FLAGS_RESERVED7
, NULL
, HFILL
}},
2485 { &hf_diameter_avp_vendor_id
,
2486 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32
, BASE_ENTERPRISES
, STRINGS_ENTERPRISES
,
2487 0x0, NULL
, HFILL
}},
2488 { &(unknown_avp
.hf_value
),
2489 { "Value","diameter.avp.unknown", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2490 { &hf_diameter_avp_data_wrong_length
,
2491 { "Data","diameter.avp.invalid-data", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2492 { &hf_diameter_avp_pad
,
2493 { "Padding","diameter.avp.pad", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2494 { &hf_diameter_code
,
2495 { "Command Code", "diameter.cmd.code", FT_UINT32
, BASE_DEC
, VALS(cmd_vs
), 0, NULL
, HFILL
}},
2496 { &hf_diameter_answer_in
,
2497 { "Answer In", "diameter.answer_in", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0x0,
2498 "The answer to this diameter request is in this frame", HFILL
}},
2499 { &hf_diameter_answer_to
,
2500 { "Request In", "diameter.answer_to", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0x0,
2501 "This is an answer to the diameter request in this frame", HFILL
}},
2502 { &hf_diameter_answer_time
,
2503 { "Response Time", "diameter.resp_time", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
2504 "The time between the request and the answer", HFILL
}},
2505 { &hf_framed_ipv6_prefix_reserved
,
2506 { "Framed IPv6 Prefix Reserved byte", "diameter.framed_ipv6_prefix_reserved",
2507 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
2508 { &hf_framed_ipv6_prefix_length
,
2509 { "Framed IPv6 Prefix length (in bits)", "diameter.framed_ipv6_prefix_length",
2510 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
2511 { &hf_framed_ipv6_prefix_bytes
,
2512 { "Framed IPv6 Prefix as a bytestring", "diameter.framed_ipv6_prefix_bytes",
2513 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
2514 { &hf_framed_ipv6_prefix_ipv6
,
2515 { "Framed IPv6 Prefix as an IPv6 address", "diameter.framed_ipv6_prefix_ipv6",
2516 FT_IPv6
, BASE_NONE
, NULL
, 0, "This field is present only if the prefix length is 128", HFILL
}},
2517 { &hf_diameter_3gpp2_exp_res
,
2518 { "Experimental-Result-Code", "diameter.3gpp2.exp_res",
2519 FT_UINT32
, BASE_DEC
, VALS(diameter_3gpp2_exp_res_vals
), 0x0, NULL
, HFILL
}},
2520 { &hf_diameter_other_vendor_exp_res
,
2521 { "Experimental-Result-Code", "diameter.other_vendor.Experimental-Result-Code",
2522 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
2523 { &hf_diameter_mip6_feature_vector
,
2524 { "MIP6-Feature-Vector", "diameter.mip6_feature_vector",
2525 FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2526 { &hf_diameter_mip6_feature_vector_mip6_integrated
,
2527 { "MIP6_INTEGRATED", "diameter.mip6_feature_vector.mip6_integrated.mip6_integrated",
2528 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000000000000001, NULL
, HFILL
}},
2529 { &hf_diameter_mip6_feature_vector_local_home_agent_assignment
,
2530 { "LOCAL_HOME_AGENT_ASSIGNMENT", "diameter.mip6_feature_vector.local_home_agent_assignment",
2531 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000000000000002, NULL
, HFILL
}},
2532 { &hf_diameter_mip6_feature_vector_pmip6_supported
,
2533 { "PMIP6_SUPPORTED", "diameter.mip6_feature_vector.pmip6_supported",
2534 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000010000000000, NULL
, HFILL
}},
2535 { &hf_diameter_mip6_feature_vector_ip4_hoa_supported
,
2536 { "IP4_HOA_SUPPORTED", "diameter.mip6_feature_vector.ip4_hoa_supported",
2537 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000020000000000, NULL
, HFILL
}},
2538 { &hf_diameter_mip6_feature_vector_local_mag_routing_supported
,
2539 { "LOCAL_MAG_ROUTING_SUPPORTED", "diameter.mip6_feature_vector.local_mag_routing_supported",
2540 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000040000000000,NULL
, HFILL
}},
2541 { &hf_diameter_3gpp_mip6_feature_vector
,
2542 { "MIP6-Feature-Vector [3GPP]", "diameter.3gpp.mip6_feature_vector",
2543 FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
2544 { &hf_diameter_3gpp_mip6_feature_vector_assign_local_ip
,
2545 { "MIP6_INTEGRATED", "diameter.3gpp.mip6_feature_vector.assign_local_ip",
2546 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000080000000000, NULL
, HFILL
}},
2547 { &hf_diameter_3gpp_mip6_feature_vector_mip4_supported
,
2548 { "PMIP6_SUPPORTED", "diameter.3gpp.mip6_feature_vector.mip4_supported",
2549 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000100000000000, NULL
, HFILL
}},
2550 { &hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility
,
2551 { "OPTIMIZED_IDLE_MODE_MOBILITY", "diameter.3gpp.mip6_feature_vector.optimized_idle_mode_mobility",
2552 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000200000000000, NULL
, HFILL
}},
2553 { &hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported
,
2554 { "GTPv2_SUPPORTED", "diameter.3gpp.mip6_feature_vector.gtpv2_supported",
2555 FT_BOOLEAN
, 64, TFS(&tfs_set_notset
), 0x0000400000000000, NULL
, HFILL
}},
2556 { &hf_diameter_user_equipment_info_imeisv
,
2557 { "IMEISV","diameter.user_equipment_info.imeisv", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2558 { &hf_diameter_user_equipment_info_mac
,
2559 { "MAC","diameter.user_equipment_info.mac", FT_ETHER
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2560 { &hf_diameter_user_equipment_info_eui64
,
2561 { "EUI64","diameter.user_equipment_info.eui64", FT_EUI64
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2562 { &hf_diameter_user_equipment_info_modified_eui64
,
2563 { "Modified EUI64","diameter.user_equipment_info.modified_eui64", FT_EUI64
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}}
2568 &ett_diameter_flags
,
2569 &ett_diameter_avp_flags
,
2570 &ett_diameter_avpinfo
,
2572 &ett_diameter_mip6_feature_vector
,
2573 &ett_diameter_3gpp_mip6_feature_vector
,
2577 static ei_register_info ei
[] = {
2578 { &ei_diameter_reserved_bit_set
, { "diameter.reserved_bit_set", PI_MALFORMED
, PI_WARN
, "Reserved bit set", EXPFILL
}},
2579 { &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
}},
2580 { &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
}},
2581 { &ei_diameter_avp_no_data
, { "diameter.avp.no_data", PI_UNDECODED
, PI_WARN
, "Data is empty", EXPFILL
}},
2582 { &ei_diameter_avp_pad
, { "diameter.avp.pad.non_zero", PI_MALFORMED
, PI_NOTE
, "Padding is non-zero", EXPFILL
}},
2583 { &ei_diameter_avp_pad_missing
, { "diameter.avp.pad.missing", PI_MALFORMED
, PI_NOTE
, "Padding is missing", EXPFILL
}},
2584 { &ei_diameter_avp_len
, { "diameter.avp.invalid-len", PI_MALFORMED
, PI_WARN
, "Wrong length", EXPFILL
}},
2585 { &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
}},
2586 { &ei_diameter_version
, { "diameter.version.unknown", PI_UNDECODED
, PI_WARN
, "Unknown Diameter Version (decoding as RFC 3588)", EXPFILL
}},
2587 { &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
}},
2588 { &ei_diameter_invalid_ipv6_prefix_len
, { "diameter.invalid_ipv6_prefix_len", PI_MALFORMED
, PI_ERROR
, "Invalid IPv6 Prefix length", EXPFILL
}},
2589 { &ei_diameter_invalid_avp_len
,{ "diameter.invalid_avp_len", PI_MALFORMED
, PI_ERROR
, "Invalid AVP length", EXPFILL
}},
2590 { &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
}},
2591 { &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
}},
2594 wmem_array_append(build_dict
.hf
, hf_base
, array_length(hf_base
));
2595 ett_length
= array_length(ett_base
);
2596 for (i
= 0; i
< ett_length
; i
++) {
2597 g_ptr_array_add(build_dict
.ett
, ett_base
[i
]);
2600 proto_register_field_array(proto_diameter
, (hf_register_info
*)wmem_array_get_raw(build_dict
.hf
), wmem_array_get_count(build_dict
.hf
));
2601 proto_register_subtree_array((int **)build_dict
.ett
->pdata
, build_dict
.ett
->len
);
2602 expert_diameter
= expert_register_protocol(proto_diameter
);
2603 expert_register_field_array(expert_diameter
, ei
, array_length(ei
));
2605 g_ptr_array_free(build_dict
.ett
,true);
2610 register_diameter_fields(const char *unused _U_
)
2613 * The hf_base[] array for Diameter refers to a variable
2614 * that is set by dictionary_load(), so we need to call
2615 * dictionary_load() before hf_base[] is initialized.
2617 * To ensure that, we call dictionary_load() and then
2618 * call a routine that defines hf_base[] and does all
2619 * the registration work.
2622 real_register_diameter_fields();
2626 proto_register_diameter(void)
2628 module_t
*diameter_module
;
2630 proto_diameter
= proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
2632 /* Allow dissector to find be found by name. */
2633 diameter_sctp_handle
= register_dissector("diameter", dissect_diameter
, proto_diameter
);
2634 diameter_udp_handle
= create_dissector_handle(dissect_diameter
, proto_diameter
);
2635 diameter_tcp_handle
= register_dissector("diameter.tcp", dissect_diameter_tcp
, proto_diameter
);
2636 /* Diameter AVPs without Diameter header, for EAP-TTLS (RFC 5281, Section 10) */
2637 register_dissector("diameter_avps", dissect_diameter_avps
, proto_diameter
);
2639 /* Delay registration of Diameter fields */
2640 proto_register_prefix("diameter", register_diameter_fields
);
2642 /* Register dissector table(s) to do sub dissection of AVPs (OctetStrings) */
2643 diameter_dissector_table
= register_dissector_table("diameter.base", "Diameter Base AVP", proto_diameter
, FT_UINT32
, BASE_DEC
);
2644 diameter_3gpp_avp_dissector_table
= register_dissector_table("diameter.3gpp", "Diameter 3GPP AVP", proto_diameter
, FT_UINT32
, BASE_DEC
);
2645 diameter_ericsson_avp_dissector_table
= register_dissector_table("diameter.ericsson", "Diameter Ericsson AVP", proto_diameter
, FT_UINT32
, BASE_DEC
);
2646 diameter_verizon_avp_dissector_table
= register_dissector_table("diameter.verizon", "DIAMETER_VERIZON_AVPS", proto_diameter
, FT_UINT32
, BASE_DEC
);
2648 diameter_expr_result_vnd_table
= register_dissector_table("diameter.vnd_exp_res", "Diameter Experimental-Result-Code", proto_diameter
, FT_UINT32
, BASE_DEC
);
2650 /* Register configuration options */
2651 diameter_module
= prefs_register_protocol(proto_diameter
, NULL
);
2652 /* For reading older preference files with "Diameter." preferences */
2653 prefs_register_module_alias("Diameter", diameter_module
);
2655 /* Desegmentation */
2656 prefs_register_bool_preference(diameter_module
, "desegment",
2657 "Reassemble Diameter messages spanning multiple TCP segments",
2658 "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
2659 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2660 &gbl_diameter_desegment
);
2662 /* Register some preferences we no longer support, so we can report
2663 * them as obsolete rather than just illegal.
2665 prefs_register_obsolete_preference(diameter_module
, "version");
2666 prefs_register_obsolete_preference(diameter_module
, "command_in_header");
2667 prefs_register_obsolete_preference(diameter_module
, "dictionary.name");
2668 prefs_register_obsolete_preference(diameter_module
, "dictionary.use");
2669 prefs_register_obsolete_preference(diameter_module
, "allow_zero_as_app_id");
2670 prefs_register_obsolete_preference(diameter_module
, "suppress_console_output");
2673 diameter_tap
= register_tap("diameter");
2675 register_srt_table(proto_diameter
, NULL
, 1, diameterstat_packet
, diameterstat_init
, NULL
);
2677 } /* proto_register_diameter */
2680 proto_reg_handoff_diameter(void)
2682 data_handle
= find_dissector("data");
2683 eap_handle
= find_dissector_add_dependency("eap", proto_diameter
);
2685 dissector_add_uint("sctp.ppi", DIAMETER_PROTOCOL_ID
, diameter_sctp_handle
);
2687 heur_dissector_add("tcp", dissect_diameter_tcp_heur
, "Diameter over TCP", "diameter_tcp", proto_diameter
, HEURISTIC_DISABLE
);
2689 ssl_dissector_add(DEFAULT_DIAMETER_TLS_PORT
, diameter_tcp_handle
);
2690 dtls_dissector_add(DEFAULT_DIAMETER_TLS_PORT
, diameter_sctp_handle
);
2692 /* Register special decoding for some AVPs */
2694 /* AVP Code: 1 User-Name */
2695 dissector_add_uint("diameter.base", 1, create_dissector_handle(dissect_diameter_user_name
, proto_diameter
));
2697 /* AVP Code: 79 EAP-Message (defined in RFC 2869, but used for EAP-TTLS, RFC 5281) */
2698 dissector_add_uint("diameter.base", 79, create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
2700 /* AVP Code: 97 Framed-IPv6-Address */
2701 dissector_add_uint("diameter.base", 97, create_dissector_handle(dissect_diameter_base_framed_ipv6_prefix
, proto_diameter
));
2703 /* AVP Code: 124 MIP6-Feature-Vector */
2704 dissector_add_uint("diameter.base", 124, create_dissector_handle(dissect_diameter_mip6_feature_vector
, proto_diameter
));
2706 /* AVP Code: 265 Supported-Vendor-Id */
2707 dissector_add_uint("diameter.base", 265, create_dissector_handle(dissect_diameter_vendor_id
, proto_diameter
));
2709 /* AVP Code: 266 Vendor-Id */
2710 dissector_add_uint("diameter.base", 266, create_dissector_handle(dissect_diameter_vendor_id
, proto_diameter
));
2712 /* AVP Code: 443 Subscription-Id */
2713 dissector_add_uint("diameter.base", 443, create_dissector_handle(dissect_diameter_subscription_id
, proto_diameter
));
2715 /* AVP Code: 450 Subscription-Id-Type */
2716 dissector_add_uint("diameter.base", 450, create_dissector_handle(dissect_diameter_subscription_id_type
, proto_diameter
));
2718 /* AVP Code: 444 Subscription-Id-Data */
2719 dissector_add_uint("diameter.base", 444, create_dissector_handle(dissect_diameter_subscription_id_data
, proto_diameter
));
2721 /* AVP Code: 458 User-Equipment-Info */
2722 dissector_add_uint("diameter.base", 458, create_dissector_handle(dissect_diameter_user_equipment_info
, proto_diameter
));
2724 /* AVP Code: 459 User-Equipment-Info-Type */
2725 dissector_add_uint("diameter.base", 459, create_dissector_handle(dissect_diameter_user_equipment_info_type
, proto_diameter
));
2727 /* AVP Code: 460 User-Equipment-Info-Value */
2728 dissector_add_uint("diameter.base", 460, create_dissector_handle(dissect_diameter_user_equipment_info_value
, proto_diameter
));
2730 /* AVP Code: 462 EAP-Payload */
2731 dissector_add_uint("diameter.base", 462, create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
2732 /* AVP Code: 463 EAP-Reissued-Payload */
2733 dissector_add_uint("diameter.base", 463, create_dissector_handle(dissect_diameter_eap_payload
, proto_diameter
));
2735 /* Register dissector for Experimental result code, with 3GPP2's vendor Id */
2736 dissector_add_uint("diameter.vnd_exp_res", VENDOR_THE3GPP2
, create_dissector_handle(dissect_diameter_3gpp2_exp_res
, proto_diameter
));
2738 dissector_add_uint_range_with_preference("tcp.port", DEFAULT_DIAMETER_PORT_RANGE
, diameter_tcp_handle
);
2739 dissector_add_uint_range_with_preference("udp.port", "", diameter_udp_handle
);
2740 dissector_add_uint_range_with_preference("sctp.port", DEFAULT_DIAMETER_PORT_RANGE
, diameter_sctp_handle
);
2742 exported_pdu_tap
= find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7
);
2748 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2753 * indent-tabs-mode: t
2756 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2757 * :indentSize=8:tabSize=8:noTabs=false: