epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-diameter.c
blob68535d92c1821a6f8fedbdea5610d841b2b01830
1 /* packet-diameter.c
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
16 * References:
18 * RFC 3588, "Diameter Base Protocol" (now RFC 6733)
19 * draft-ietf-aaa-diameter-mobileip-16, "Diameter Mobile IPv4 Application"
20 * (now RFC 4004)
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
37 #include "config.h"
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>
45 #include <epan/tap.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>
53 #include <epan/afn.h>
54 #include <epan/tfs.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
80 #if 0
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)
87 #endif
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 {
110 proto_tree *tree;
111 packet_info *pinfo;
112 wmem_tree_t *avps;
113 } 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 {
122 uint32_t code;
123 wmem_array_t *vs_avps;
124 value_string_ext *vs_avps_ext;
125 } diam_vnd_t;
127 struct _diam_avp_t {
128 uint32_t code;
129 diam_vnd_t *vendor;
130 diam_avp_dissector_t dissector_rfc;
132 int ett;
133 int hf_value;
134 void *type_data;
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 {
141 wmem_tree_t *avps;
142 wmem_tree_t *vnds;
143 value_string_ext *applications;
144 value_string *commands;
145 } diam_dictionary_t;
147 typedef diam_avp_t *(*avp_constructor_t)(const avp_type_t *, uint32_t, diam_vnd_t *, const char *, const value_string *, void *);
149 struct _avp_type_t {
150 const char *name;
151 diam_avp_dissector_t rfc;
152 enum ftenum ft;
153 int base;
154 avp_constructor_t build;
157 struct _build_dict {
158 wmem_array_t *hf;
159 GPtrArray *ett;
160 GHashTable *types;
161 GHashTable *avps;
165 typedef struct _address_avp_t {
166 int ett;
167 int hf_address_type;
168 int hf_ipv4;
169 int hf_ipv6;
170 int hf_e164_str;
171 int hf_other;
172 } address_avp_t;
174 typedef enum {
175 REASEMBLE_NEVER = 0,
176 REASEMBLE_AT_END,
177 REASEMBLE_BY_LENGTH
178 } avp_reassemble_mode_t;
180 typedef struct _proto_avp_t {
181 char *name;
182 dissector_handle_t handle;
183 avp_reassemble_mode_t reassemble_mode;
184 } proto_avp_t;
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[]= {
199 {1,"IPv4"},
200 {2,"IPv6"},
201 {3,"NSAP"},
202 {4,"HDLC"},
203 {5,"BBN"},
204 {6,"IEEE-802"},
205 {7,"E-163"},
206 {8,"E-164"},
207 {9,"F-69"},
208 {10,"X-121"},
209 {11,"IPX"},
210 {12,"Appletalk"},
211 {13,"Decnet4"},
212 {14,"Vines"},
213 {15,"E-164-NSAP"},
214 {16,"DNS"},
215 {17,"DistinguishedName"},
216 {18,"AS"},
217 {19,"XTPoIPv4"},
218 {20,"XTPoIPv6"},
219 {21,"XTPNative"},
220 {22,"FibrePortName"},
221 {23,"FibreNodeName"},
222 {24,"GWID"},
223 {0,NULL}
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[] = {
335 "---",
336 "--P",
337 "-M-",
338 "-MP",
339 "V--",
340 "V-P",
341 "VM-",
342 "VMP",
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
358 static void
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);
371 static int
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)
378 return 1;
379 if (vsa->value < vsb->value)
380 return -1;
382 return 0;
385 static GHashTable* diameterstat_cmd_str_hash;
386 #define DIAMETER_NUM_PROCEDURES 1
388 static void
389 diameterstat_init(struct register_srt* srt _U_, GArray* srt_array)
391 srt_stat_table *diameter_srt_table;
392 int* idx;
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
408 * index.
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_)
417 unsigned i = 0;
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;
421 int* idx = NULL;
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);
432 if (idx == NULL) {
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 */
447 static int
448 dissect_diameter_vendor_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
450 int offset = 0;
452 proto_tree_add_item(tree, hf_diameter_vendor_id, tvb, 0, 4, ENC_BIG_ENDIAN);
454 offset++;
455 return offset;
458 static int
459 dissect_diameter_eap_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
461 bool save_writable;
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"},
478 {0,NULL}
481 static int
482 dissect_diameter_3gpp2_exp_res(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
484 proto_item *pi;
485 diam_sub_dis_t *diam_sub_dis;
487 /* Reject the packet if data is NULL */
488 if (data == NULL)
489 return 0;
490 diam_sub_dis = (diam_sub_dis_t*)data;
492 if (tree) {
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;
499 return 4;
502 static void
503 dissect_diameter_other_vendor_exp_res(diam_ctx_t *c, tvbuff_t *tvb, proto_tree *tree, diam_sub_dis_t *diam_sub_dis)
505 proto_item *pi;
507 if (tree) {
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 */
516 static int
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;
521 proto_item *pi;
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;
530 if (prefix_len % 8)
531 prefix_len_bytes++;
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) {
539 ws_in6_addr value;
540 address addr;
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 */
555 static int
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;
561 if (diam_sub_dis) {
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);
573 return 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);
578 return 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.
585 break;
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);
605 return str_len;
607 break;
610 return 0;
613 /* AVP Code: 124 MIP6-Feature-Vector */
614 /* RFC 5447, 5779 */
615 /* 3GPP TS 29.273, V15.2.0 */
616 static int
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,
625 NULL
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,
633 NULL
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);
655 break;
658 return 8;
661 /* AVP Code: 443 Subscription-Id */
662 static int
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;
669 return 0;
672 /* AVP Code: 450 Subscription-Id-Type */
673 static int
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);
679 return 0;
682 /* AVP Code: 444 Subscription-Id-Data */
683 static int
684 dissect_diameter_subscription_id_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
686 uint32_t str_len;
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);
694 return 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);
698 return str_len;
701 return 0;
704 /* AVP Code: 458 User-Equipment-Info */
705 static int
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;
712 return 0;
715 /* AVP Code: 459 User-Equipment-Info-Type */
716 /* RFC 8506 section 8.50 */
717 static int
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);
723 return 0;
726 /* AVP Code: 460 User-Equipment-Info-Value */
727 /* RFC 8506 section 8.51 */
728 static int
729 dissect_diameter_user_equipment_info_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
731 uint32_t len;
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 */
741 if (len == 8) {
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);
743 return len;
744 } else if (len == 16) {
745 proto_tree_add_item(tree, hf_diameter_user_equipment_info_imeisv, tvb, 0, len, ENC_ASCII);
746 return len;
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);
750 return len;
752 proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
753 break;
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);
759 return len;
761 proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
762 break;
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);
768 return len;
770 proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
771 break;
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);
777 return len;
779 proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
780 break;
783 return 0;
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).
791 static void
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)
794 TRY {
795 switch (vendorid) {
796 case 0:
797 dissector_try_uint_new(diameter_dissector_table, code, subtvb, pinfo, avp_tree, false, diam_sub_dis_inf);
798 break;
799 case VENDOR_ERICSSON:
800 dissector_try_uint_new(diameter_ericsson_avp_dissector_table, code, subtvb, pinfo, avp_tree, false, diam_sub_dis_inf);
801 break;
802 case VENDOR_VERIZON:
803 dissector_try_uint_new(diameter_verizon_avp_dissector_table, code, subtvb, pinfo, avp_tree, false, diam_sub_dis_inf);
804 break;
805 case VENDOR_THE3GPP:
806 dissector_try_uint_new(diameter_3gpp_avp_dissector_table, code, subtvb, pinfo, avp_tree, false, diam_sub_dis_inf);
807 break;
808 default:
809 break;
812 /* Debug
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);
819 ENDTRY;
822 /* Dissect an AVP at offset */
823 static int
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];
833 diam_avp_t *a;
834 proto_item *pi, *avp_item;
835 proto_tree *avp_tree, *save_tree;
836 tvbuff_t *subtvb;
837 diam_vnd_t *vendor;
838 const char *code_str;
839 const char *avp_str = NULL;
840 uint8_t pad_len;
842 k[0].length = 1;
843 k[0].key = &code;
845 k[1].length = 1;
846 k[1].key = &vendorid;
848 k[2].length = 0;
849 k[2].key = NULL;
851 a = (diam_avp_t *)wmem_tree_lookup32_array(dictionary.avps,k);
853 len &= 0x00ffffff;
854 pad_len = (len % 4) ? 4 - (len % 4) : 0 ;
856 if (!a) {
857 a = &unknown_avp;
859 if (vendor_flag) {
860 if (! (vendor = (diam_vnd_t *)wmem_tree_lookup32(dictionary.vnds,vendorid) ))
861 vendor = &unknown_vendor;
862 } else {
863 vendor = &no_vnd;
865 } else {
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")));
875 #if 0
876 { /* Debug code */
877 value_string *vendor_avp_vs = VALUE_STRING_EXT_VS_P(vendor->vs_avps_ext);
878 int i = 0;
879 while (vendor_avp_vs[i].strptr != NULL) {
880 ws_warning("%u %s", vendor_avp_vs[i].value, vendor_avp_vs[i].strptr);
881 i++;
884 #endif
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",
890 code,
891 len);
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);
910 /* Code */
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"));
918 offset += 4;
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);
925 /* Flags */
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,
936 NULL
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);
944 offset += 1;
946 /* Length */
947 proto_tree_add_item(avp_tree,hf_diameter_avp_len,tvb,offset,3,ENC_BIG_ENDIAN);
948 offset += 3;
950 /* Vendor flag */
951 if (vendor_flag) {
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);
958 offset += 4;
961 if ( len == (uint32_t)(vendor_flag ? 12 : 8) ) {
962 /* Data is empty so return now */
963 proto_tree_add_expert(avp_tree, c->pinfo, &ei_diameter_avp_no_data, tvb, offset, 0);
964 /* pad_len is always 0 in this case, but kept here for consistency */
965 return len+pad_len;
967 /* If we are dissecting a grouped AVP and find a Vendor Id AVP(266), save it */
968 if ((diam_sub_dis_inf->dis_gouped) && (!vendor_flag) && (code==266)) {
969 diam_sub_dis_inf->vendor_id = tvb_get_ntohl(tvb,offset);
972 subtvb = tvb_new_subset_length(tvb,offset,len-(8+(vendor_flag?4:0)));
973 offset += len-(8+(vendor_flag?4:0));
975 save_tree = c->tree;
976 c->tree = avp_tree;
978 /* The Experimental-Result-Code AVP (298) comes inside the Experimental-Result
979 * grouped AVP (297). The Vendor-ID AVP in the Experimental-Result specifies the
980 * name space of the Experimental-Result-Code. Unfortunately we don't have a way
981 * to specify, in XML, different Experimental-Result-Code enum values for different
982 * Vendor-IDs so we choose a Vendor-ID whose values get to go in XML (we chose
983 * 3GPP) and handle other Vendor-IDs through the "diameter.vnd_exp_res" dissector
984 * table.
986 if ((diam_sub_dis_inf->dis_gouped)
987 && (!vendor_flag)
988 && (code==298)
989 && (diam_sub_dis_inf->vendor_id != 0)
990 && (diam_sub_dis_inf->vendor_id != VENDOR_THE3GPP))
992 /* call subdissector */
993 if (!dissector_try_uint_new(diameter_expr_result_vnd_table, diam_sub_dis_inf->vendor_id,
994 subtvb, c->pinfo, avp_tree, false, diam_sub_dis_inf)) {
995 /* No subdissector for this vendor ID, use the generic one */
996 dissect_diameter_other_vendor_exp_res(c, subtvb, avp_tree, diam_sub_dis_inf);
999 if (diam_sub_dis_inf->avp_str) {
1000 proto_item_append_text(avp_item," val=%s", diam_sub_dis_inf->avp_str);
1002 } else {
1003 avp_str = a->dissector_rfc(c,a,subtvb, diam_sub_dis_inf);
1005 c->tree = save_tree;
1007 diam_sub_dis_inf->avp_str = NULL;
1008 call_avp_subdissector(vendorid, code, subtvb, c->pinfo, avp_tree, diam_sub_dis_inf);
1010 /* Let the subdissector have precedence filling in the avp_item string */
1011 if (diam_sub_dis_inf->avp_str) {
1012 proto_item_append_text(avp_item," val=%s", diam_sub_dis_inf->avp_str);
1013 } else if (avp_str) {
1014 proto_item_append_text(avp_item," val=%s", avp_str);
1018 if (pad_len) {
1019 uint8_t i;
1021 pi = proto_tree_add_item(avp_tree, hf_diameter_avp_pad, tvb, offset, pad_len, ENC_NA);
1022 for (i=0; i < pad_len; i++) {
1023 if (tvb_get_uint8(tvb, offset++) != 0) {
1024 expert_add_info(c->pinfo, pi, &ei_diameter_avp_pad);
1025 break;
1029 if ((len + pad_len) % 4) {
1030 proto_tree_add_expert(avp_tree, c->pinfo, &ei_diameter_avp_pad_missing, tvb, offset, pad_len);
1033 return len+pad_len;
1036 static const char *
1037 address_rfc_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1039 char *label = NULL;
1040 address_avp_t *t = (address_avp_t *)a->type_data;
1041 int len = tvb_reported_length(tvb);
1042 proto_item *pi = proto_tree_add_item(c->tree, a->hf_value, tvb, 0, len, ENC_BIG_ENDIAN);
1043 proto_tree *pt = proto_item_add_subtree(pi,t->ett);
1044 uint32_t addr_type;
1045 len = len-2;
1047 proto_tree_add_item_ret_uint(pt, t->hf_address_type, tvb, 0, 2, ENC_NA, &addr_type);
1048 /* See afn.h and https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml */
1049 switch (addr_type ) {
1050 case AFNUM_INET:
1051 if (len != 4) {
1052 proto_tree_add_expert_format(pt, c->pinfo, &ei_diameter_avp_len, tvb, 2, len, "Wrong length for IPv4 Address: %d instead of 4", len);
1053 return "[Malformed]";
1055 pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,2,4,ENC_BIG_ENDIAN);
1056 break;
1057 case AFNUM_INET6:
1058 if (len != 16) {
1059 proto_tree_add_expert_format(pt, c->pinfo, &ei_diameter_avp_len, tvb, 2, len, "Wrong length for IPv6 Address: %d instead of 16", len);
1060 return "[Malformed]";
1062 pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,2,16,ENC_NA);
1063 break;
1064 case AFNUM_E164:
1065 /* It's unclear what format the e164 address would be encoded in but AVP 3GPP 2008 has
1066 * ...value 8, E.164, and the address information is UTF8 encoded.
1068 if (tvb_ascii_isprint(tvb, 2, len)) {
1069 pi = proto_tree_add_item(pt, t->hf_e164_str, tvb, 2, len, ENC_ASCII | ENC_NA);
1070 } else {
1071 pi = proto_tree_add_item(pt, t->hf_other, tvb, 2, -1, ENC_BIG_ENDIAN);
1073 break;
1074 default:
1075 pi = proto_tree_add_item(pt,t->hf_other,tvb,2,-1,ENC_BIG_ENDIAN);
1076 break;
1079 if (c->tree) {
1080 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1081 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1082 label = strstr(label,": ")+2;
1085 return label;
1088 static const char *
1089 proto_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf)
1091 proto_avp_t *t = (proto_avp_t *)a->type_data;
1093 col_set_writable(c->pinfo->cinfo, COL_PROTOCOL, false);
1094 col_set_writable(c->pinfo->cinfo, COL_INFO, false);
1096 if (!t->handle) {
1097 t->handle = find_dissector(t->name);
1098 if (!t->handle) t->handle = data_handle;
1101 TRY {
1102 call_dissector_with_data(t->handle, tvb, c->pinfo, c->tree, diam_sub_dis_inf);
1104 CATCH_NONFATAL_ERRORS {
1105 show_exception(tvb, c->pinfo, c->tree, EXCEPT_CODE, GET_MESSAGE);
1107 ENDTRY;
1109 return "";
1112 static const char *
1113 time_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1115 int len = tvb_reported_length(tvb);
1116 char *label = NULL;
1117 proto_item *pi;
1119 if ( len != 4 ) {
1120 proto_tree_add_expert_format(c->tree, c->pinfo, &ei_diameter_avp_len, tvb, 0, 4,
1121 "Bad Timestamp Length: %d instead of 4", len);
1122 return "[Malformed]";
1125 if (c->tree) {
1126 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1127 pi = proto_tree_add_item(c->tree, (a->hf_value), tvb, 0, 4, ENC_TIME_SECS_NTP|ENC_BIG_ENDIAN);
1128 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1129 label = strstr(label,": ")+2;
1132 return label;
1135 static const char *
1136 address_radius_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1138 char *label = NULL;
1140 address_avp_t *t = (address_avp_t *)a->type_data;
1141 proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_reported_length(tvb),ENC_BIG_ENDIAN);
1142 proto_tree *pt = proto_item_add_subtree(pi,t->ett);
1143 uint32_t len = tvb_reported_length(tvb);
1145 switch (len) {
1146 case 4:
1147 pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,0,4,ENC_BIG_ENDIAN);
1148 break;
1149 case 16:
1150 pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,0,16,ENC_NA);
1151 break;
1152 default:
1153 pi = proto_tree_add_item(pt,t->hf_other,tvb,0,len,ENC_BIG_ENDIAN);
1154 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1155 "Bad Address Length (%u)", len);
1157 break;
1160 if (c->tree) {
1161 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1162 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1163 label = strstr(label,": ")+2;
1166 return label;
1169 static const char *
1170 simple_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1172 char *label = NULL;
1174 if (c->tree) {
1175 proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_reported_length(tvb),ENC_BIG_ENDIAN);
1176 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1177 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1178 label = strstr(label,": ")+2;
1181 return label;
1184 static const char *
1185 utf8_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1187 char *label = NULL;
1189 if (c->tree) {
1190 proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_reported_length(tvb),ENC_UTF_8|ENC_BIG_ENDIAN);
1191 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1192 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1193 label = strstr(label,": ")+2;
1196 return label;
1199 static const char *
1200 integer32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1202 char *label = NULL;
1203 proto_item *pi;
1205 /* Verify length before adding */
1206 int length = tvb_reported_length(tvb);
1207 if (length == 4) {
1208 if (c->tree) {
1209 pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1210 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1211 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1212 label = strstr(label,": ")+2;
1215 else {
1216 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1217 tvb, 0, length, NULL,
1218 "Error! Bad Integer32 Length");
1219 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1220 "Bad Integer32 Length (%u)", length);
1221 proto_item_set_generated(pi);
1224 return label;
1227 static const char *
1228 integer64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1230 char *label = NULL;
1231 proto_item *pi;
1233 /* Verify length before adding */
1234 int length = tvb_reported_length(tvb);
1235 if (length == 8) {
1236 if (c->tree) {
1237 pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1238 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1239 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1240 label = strstr(label,": ")+2;
1243 else {
1244 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1245 tvb, 0, length, NULL,
1246 "Error! Bad Integer64 Length");
1247 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1248 "Bad Integer64 Length (%u)", length);
1249 proto_item_set_generated(pi);
1252 return label;
1255 static const char *
1256 unsigned32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf)
1258 char *label = NULL;
1259 proto_item *pi;
1261 /* Verify length before adding */
1262 int length = tvb_reported_length(tvb);
1263 if (length == 4) {
1264 if (c->tree) {
1265 diam_sub_dis_inf->item = pi = proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1266 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1267 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1268 label = strstr(label,": ")+2;
1271 else {
1272 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1273 tvb, 0, length, NULL,
1274 "Error! Bad Unsigned32 Length");
1275 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1276 "Bad Unsigned32 Length (%u)", length);
1277 proto_item_set_generated(pi);
1280 return label;
1283 static const char *
1284 unsigned64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1286 char *label = NULL;
1287 proto_item *pi;
1289 /* Verify length before adding */
1290 int length = tvb_reported_length(tvb);
1291 if (length == 8) {
1292 if (c->tree) {
1293 pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1294 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1295 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1296 label = strstr(label,": ")+2;
1299 else {
1300 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1301 tvb, 0, length, NULL,
1302 "Error! Bad Unsigned64 Length");
1303 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1304 "Bad Unsigned64 Length (%u)", length);
1305 proto_item_set_generated(pi);
1308 return label;
1311 static const char *
1312 float32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1314 char *label = NULL;
1315 proto_item *pi;
1317 /* Verify length before adding */
1318 int length = tvb_reported_length(tvb);
1319 if (length == 4) {
1320 if (c->tree) {
1321 pi= proto_tree_add_item(c->tree,a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1322 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1323 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1324 label = strstr(label,": ")+2;
1327 else {
1328 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1329 tvb, 0, length, NULL,
1330 "Error! Bad Float32 Length");
1331 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1332 "Bad Float32 Length (%u)", length);
1333 proto_item_set_generated(pi);
1336 return label;
1339 static const char *
1340 float64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1342 char *label = NULL;
1343 proto_item *pi;
1345 /* Verify length before adding */
1346 int length = tvb_reported_length(tvb);
1347 if (length == 8) {
1348 if (c->tree) {
1349 pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1350 label = (char *)wmem_alloc(c->pinfo->pool, ITEM_LABEL_LENGTH+1);
1351 proto_item_fill_label(PITEM_FINFO(pi), label, NULL);
1352 label = strstr(label,": ")+2;
1355 else {
1356 pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1357 tvb, 0, length, NULL,
1358 "Error! Bad Float64 Length");
1359 expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1360 "Bad Float64 Length (%u)", length);
1361 proto_item_set_generated(pi);
1364 return label;
1367 static const char *
1368 grouped_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf)
1370 int offset = 0;
1371 int len = tvb_reported_length(tvb);
1372 proto_item *pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, ENC_BIG_ENDIAN);
1373 proto_tree *pt = c->tree;
1375 c->tree = proto_item_add_subtree(pi,a->ett);
1377 /* Set the flag that we are dissecting a grouped AVP */
1378 diam_sub_dis_inf->dis_gouped = true;
1379 while (offset < len) {
1380 offset += dissect_diameter_avp(c, tvb, offset, diam_sub_dis_inf, false);
1382 /* Clear info collected in grouped AVP */
1383 diam_sub_dis_inf->vendor_id = 0;
1384 diam_sub_dis_inf->dis_gouped = false;
1385 diam_sub_dis_inf->avp_str = NULL;
1387 c->tree = pt;
1389 return NULL;
1392 static const char *msgflags_str[] = {
1393 "----", "---T", "--E-", "--ET",
1394 "-P--", "-P-T", "-PE-", "-PET",
1395 "R---", "R--T", "R-E-", "R-ET",
1396 "RP--", "RP-T", "RPE-", "RPET"
1399 static int * const diameter_flags_fields[] = {
1400 &hf_diameter_flags_request,
1401 &hf_diameter_flags_proxyable,
1402 &hf_diameter_flags_error,
1403 &hf_diameter_flags_T,
1404 &hf_diameter_flags_reserved4,
1405 &hf_diameter_flags_reserved5,
1406 &hf_diameter_flags_reserved6,
1407 &hf_diameter_flags_reserved7,
1408 NULL
1411 static int
1412 dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1414 uint32_t version;
1415 uint64_t flags_bits;
1416 int packet_len;
1417 proto_item *pi, *cmd_item, *app_item, *version_item;
1418 proto_tree *diam_tree;
1419 diam_ctx_t *c = wmem_new0(pinfo->pool, diam_ctx_t);
1420 int offset;
1421 const char *cmd_str;
1422 uint32_t cmd;
1423 uint32_t hop_by_hop_id, end_to_end_id;
1424 conversation_t *conversation;
1425 diameter_conv_info_t *diameter_conv_info;
1426 diameter_req_ans_pair_t *diameter_pair = NULL;
1427 wmem_tree_t *pdus_tree;
1428 proto_item *it;
1429 nstime_t ns;
1430 diam_sub_dis_t *diam_sub_dis_inf = wmem_new0(pinfo->pool, diam_sub_dis_t);
1432 /* Set default value Subscription-Id-Type and User-Equipment-Info-Type as XXX_UNKNOWN */
1433 diam_sub_dis_inf->subscription_id_type = SUBSCRIPTION_ID_TYPE_UNKNOWN;
1434 diam_sub_dis_inf->user_equipment_info_type = USER_EQUIPMENT_INFO_TYPE_UNKNOWN;
1436 /* Load header fields if not already done */
1437 if (hf_diameter_code <= 0)
1438 proto_registrar_get_byname("diameter.code");
1439 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1442 if (have_tap_listener(exported_pdu_tap)){
1443 export_diameter_pdu(pinfo,tvb);
1446 pi = proto_tree_add_item(tree,proto_diameter,tvb,0,-1,ENC_NA);
1447 diam_tree = proto_item_add_subtree(pi,ett_diameter);
1449 c->tree = diam_tree;
1450 c->pinfo = pinfo;
1452 version_item = proto_tree_add_item_ret_uint(diam_tree, hf_diameter_version, tvb, 0, 1, ENC_BIG_ENDIAN, &version);
1453 if (version != DIAMETER_RFC) {
1454 expert_add_info(c->pinfo, version_item, &ei_diameter_version);
1456 proto_tree_add_item_ret_uint(diam_tree, hf_diameter_length, tvb, 1, 3, ENC_BIG_ENDIAN, &packet_len);
1458 pi = proto_tree_add_bitmask_ret_uint64(diam_tree, tvb, 4, hf_diameter_flags, ett_diameter_flags, diameter_flags_fields, ENC_BIG_ENDIAN, &flags_bits);
1459 if (flags_bits & 0x0f) {
1460 expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
1463 diam_sub_dis_inf->parent_message_is_request = (flags_bits & DIAM_FLAGS_R) ? true : false;
1465 cmd_item = proto_tree_add_item_ret_uint(diam_tree, hf_diameter_code, tvb, 5, 3, ENC_BIG_ENDIAN, &cmd);
1466 diam_sub_dis_inf->cmd_code = cmd;
1468 app_item = proto_tree_add_item_ret_uint(diam_tree, hf_diameter_application_id, tvb, 8, 4,
1469 ENC_BIG_ENDIAN, &diam_sub_dis_inf->application_id);
1471 if (try_val_to_str_ext(diam_sub_dis_inf->application_id, dictionary.applications) == NULL) {
1472 proto_tree *tu = proto_item_add_subtree(app_item,ett_unknown);
1473 proto_tree_add_expert_format(tu, c->pinfo, &ei_diameter_application_id, tvb, 8, 4,
1474 "Unknown Application Id (%u), if you know what this is you can add it to dictionary.xml", diam_sub_dis_inf->application_id);
1477 cmd_str = val_to_str_const(cmd, cmd_vs, "Unknown");
1478 if (strcmp(cmd_str, "Unknown") == 0) {
1479 expert_add_info(c->pinfo, cmd_item, &ei_diameter_code);
1483 proto_tree_add_item_ret_uint(diam_tree, hf_diameter_hopbyhopid, tvb, 12, 4, ENC_BIG_ENDIAN, &hop_by_hop_id);
1484 proto_tree_add_item_ret_uint(diam_tree, hf_diameter_endtoendid, tvb, 16, 4, ENC_BIG_ENDIAN, &end_to_end_id);
1486 col_add_fstr(pinfo->cinfo, COL_INFO,
1487 "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
1488 cmd_str,
1489 ((flags_bits>>4)&0x08) ? " Request" : " Answer",
1490 cmd,
1491 msgflags_str[((flags_bits>>4)&0x0f)],
1492 "appl",
1493 val_to_str_ext_const(diam_sub_dis_inf->application_id, dictionary.applications, "Unknown"),
1494 diam_sub_dis_inf->application_id,
1495 hop_by_hop_id,
1496 end_to_end_id);
1498 col_append_str(pinfo->cinfo, COL_INFO, " | ");
1499 col_set_fence(pinfo->cinfo, COL_INFO);
1502 /* Conversation tracking stuff */
1504 * FIXME: Looking at epan/conversation.c it seems unlikely that this will work properly in
1505 * multi-homed SCTP connections. This will probably need to be fixed at some point.
1508 conversation = find_or_create_conversation(pinfo);
1510 diameter_conv_info = (diameter_conv_info_t *)conversation_get_proto_data(conversation, proto_diameter);
1511 if (!diameter_conv_info) {
1512 diameter_conv_info = wmem_new(wmem_file_scope(), diameter_conv_info_t);
1513 diameter_conv_info->pdu_trees = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
1515 conversation_add_proto_data(conversation, proto_diameter, diameter_conv_info);
1518 /* pdus_tree is an wmem_tree keyed by frame number (in order to handle hop-by-hop collisions */
1519 pdus_tree = (wmem_tree_t *)wmem_map_lookup(diameter_conv_info->pdu_trees, GUINT_TO_POINTER(hop_by_hop_id));
1521 if (pdus_tree == NULL && (flags_bits & DIAM_FLAGS_R)) {
1522 /* This is the first request we've seen with this hop-by-hop id */
1523 pdus_tree = wmem_tree_new(wmem_file_scope());
1524 wmem_map_insert(diameter_conv_info->pdu_trees, GUINT_TO_POINTER(hop_by_hop_id), pdus_tree);
1527 if (pdus_tree) {
1528 if (!pinfo->fd->visited) {
1529 if (flags_bits & DIAM_FLAGS_R) {
1530 /* This is a request */
1531 diameter_pair = wmem_new(wmem_file_scope(), diameter_req_ans_pair_t);
1532 diameter_pair->hop_by_hop_id = hop_by_hop_id;
1533 diameter_pair->end_to_end_id = end_to_end_id;
1534 diameter_pair->cmd_code = cmd;
1535 diameter_pair->result_code = 0;
1536 diameter_pair->cmd_str = cmd_str;
1537 diameter_pair->req_frame = pinfo->num;
1538 diameter_pair->ans_frame = 0;
1539 diameter_pair->req_time = pinfo->abs_ts;
1540 wmem_tree_insert32(pdus_tree, pinfo->num, (void *)diameter_pair);
1541 } else {
1542 /* Look for a request which occurs earlier in the trace than this answer. */
1543 diameter_pair = (diameter_req_ans_pair_t *)wmem_tree_lookup32_le(pdus_tree, pinfo->num);
1545 /* Verify the end-to-end-id matches before declaring a match */
1546 if (diameter_pair && diameter_pair->end_to_end_id == end_to_end_id) {
1547 diameter_pair->ans_frame = pinfo->num;
1550 } else {
1551 /* Look for a request which occurs earlier in the trace than this answer. */
1552 diameter_pair = (diameter_req_ans_pair_t *)wmem_tree_lookup32_le(pdus_tree, pinfo->num);
1554 /* If the end-to-end ID doesn't match then this is not the request we were
1555 * looking for.
1557 if (diameter_pair && diameter_pair->end_to_end_id != end_to_end_id)
1558 diameter_pair = NULL;
1562 if (!diameter_pair) {
1563 /* create a "fake" diameter_pair structure */
1564 diameter_pair = wmem_new(pinfo->pool, diameter_req_ans_pair_t);
1565 diameter_pair->hop_by_hop_id = hop_by_hop_id;
1566 diameter_pair->cmd_code = cmd;
1567 diameter_pair->result_code = 0;
1568 diameter_pair->cmd_str = cmd_str;
1569 diameter_pair->req_frame = 0;
1570 diameter_pair->ans_frame = 0;
1571 diameter_pair->req_time = pinfo->abs_ts;
1573 diameter_pair->processing_request=(flags_bits & DIAM_FLAGS_R)!= 0;
1575 /* print state tracking info in the tree */
1576 if (flags_bits & DIAM_FLAGS_R) {
1577 /* This is a request */
1578 if (diameter_pair->ans_frame) {
1579 it = proto_tree_add_uint(diam_tree, hf_diameter_answer_in,
1580 tvb, 0, 0, diameter_pair->ans_frame);
1581 proto_item_set_generated(it);
1583 } else {
1584 /* This is an answer */
1585 if (diameter_pair->req_frame) {
1586 it = proto_tree_add_uint(diam_tree, hf_diameter_answer_to,
1587 tvb, 0, 0, diameter_pair->req_frame);
1588 proto_item_set_generated(it);
1590 nstime_delta(&ns, &pinfo->abs_ts, &diameter_pair->req_time);
1591 diameter_pair->srt_time = ns;
1592 it = proto_tree_add_time(diam_tree, hf_diameter_answer_time, tvb, 0, 0, &ns);
1593 proto_item_set_generated(it);
1594 /* TODO: Populate result_code in tap record from AVP 268 */
1598 offset = 20;
1600 /* Dissect AVPs until the end of the packet is reached */
1601 while (offset < packet_len) {
1602 offset += dissect_diameter_avp(c, tvb, offset, diam_sub_dis_inf, false);
1605 /* Handle requests for which no answers were found and
1606 * answers for which no requests were found in the tap listener.
1607 * In case if you don't need unpaired requests/answers use:
1608 * if (diameter_pair->processing_request || !diameter_pair->req_frame)
1609 * return;
1611 tap_queue_packet(diameter_tap, pinfo, diameter_pair);
1613 return tvb_reported_length(tvb);
1616 static unsigned
1617 get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
1618 int offset, void *data _U_)
1620 /* Get the length of the Diameter packet. */
1621 return tvb_get_ntoh24(tvb, offset + 1);
1624 #define NOT_DIAMETER 0
1625 #define IS_DIAMETER 1
1626 #define NOT_ENOUGH_DATA 2
1627 static int
1628 check_diameter(tvbuff_t *tvb)
1630 uint8_t flags;
1631 uint32_t msg_len;
1633 /* Ensure we don't throw an exception trying to do these heuristics */
1634 if (tvb_captured_length(tvb) < 5)
1635 return NOT_ENOUGH_DATA;
1637 /* Check if the Diameter version is 1 */
1638 if (tvb_get_uint8(tvb, 0) != 1)
1639 return NOT_DIAMETER;
1641 /* Diameter minimum message length:
1643 * Version+Length - 4 bytes
1644 * Flags+CC - 4 bytes
1645 * AppID - 4 bytes
1646 * HbH - 4 bytes
1647 * E2E - 4 bytes
1648 * 2 AVPs (Orig-Host, Orig-Realm), each including:
1649 * * AVP code - 4 bytes
1650 * * AVP flags + length - 4 bytes
1651 * * (no data - what would a reasonable minimum be?)
1653 * --> 36 bytes
1655 msg_len = tvb_get_ntoh24(tvb, 1);
1656 /* Diameter message length field must be a multiple of 4.
1657 * This is implicit in RFC 3588 (based on the header and that each
1658 * AVP must align on a 32-bit boundary) and explicit in RFC 6733.
1660 if ((msg_len < 36) || (msg_len & 0x3))
1661 return NOT_DIAMETER;
1663 flags = tvb_get_uint8(tvb, 4);
1665 /* Check if any of the Reserved flag bits are set */
1666 if (flags & 0x0f)
1667 return NOT_DIAMETER;
1669 /* Check if both the R- and E-bits are set */
1670 if ((flags & DIAM_FLAGS_R) && (flags & DIAM_FLAGS_E))
1671 return NOT_DIAMETER;
1673 return IS_DIAMETER;
1676 /*****************************************************************/
1677 /* Main dissection function */
1678 /* Checks if the message looks like Diameter before accepting it */
1679 /*****************************************************************/
1680 static int
1681 dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1683 if (check_diameter(tvb) != IS_DIAMETER)
1684 return 0;
1685 return dissect_diameter_common(tvb, pinfo, tree, data);
1688 static int
1689 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1691 int is_diam = check_diameter(tvb);
1693 if (is_diam == NOT_DIAMETER) {
1694 /* We've probably been given a frame that's not the start of
1695 * a PDU.
1697 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1698 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1699 call_dissector(data_handle, tvb, pinfo, tree);
1700 } else if (is_diam == NOT_ENOUGH_DATA) {
1701 /* Since we're doing our heuristic checks before
1702 * tcp_dissect_pdus() (since we can't do heuristics once
1703 * we're in there) we sometimes have to ask for more data...
1705 pinfo->desegment_offset = 0;
1706 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1707 } else {
1708 tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
1709 get_diameter_pdu_len, dissect_diameter_common, data);
1712 return tvb_reported_length(tvb);
1715 static bool
1716 dissect_diameter_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1718 if (check_diameter(tvb) != IS_DIAMETER) {
1719 return false;
1722 conversation_set_dissector(find_or_create_conversation(pinfo), diameter_tcp_handle);
1724 tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
1725 get_diameter_pdu_len, dissect_diameter_common, data);
1727 return true;
1730 static int
1731 dissect_diameter_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1733 proto_item *pi;
1734 proto_tree *diam_tree;
1735 int offset = 0;
1736 diam_ctx_t *c = wmem_new0(pinfo->pool, diam_ctx_t);
1737 diam_sub_dis_t *diam_sub_dis_inf = wmem_new0(pinfo->pool, diam_sub_dis_t);
1739 /* Load header fields if not already done */
1740 if (hf_diameter_code <= 0)
1741 proto_registrar_get_byname("diameter.code");
1743 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1744 col_set_str(pinfo->cinfo, COL_INFO, "AVPs:");
1746 pi = proto_tree_add_item(tree, proto_diameter, tvb, 0, -1, ENC_NA);
1747 diam_tree = proto_item_add_subtree(pi, ett_diameter);
1748 c->tree = diam_tree;
1749 c->pinfo = pinfo;
1751 /* Dissect AVPs until the end of the packet is reached */
1752 while (tvb_reported_length_remaining(tvb, offset)) {
1753 offset += dissect_diameter_avp(c, tvb, offset, diam_sub_dis_inf, true);
1755 return tvb_reported_length(tvb);
1758 static char *
1759 alnumerize(char *name)
1761 char *r = name;
1762 char *w = name;
1763 char c;
1765 for (;(c = *r); r++) {
1766 if (g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.') {
1767 *(w++) = c;
1771 *w = '\0';
1773 return name;
1777 static unsigned
1778 reginfo(int *hf_ptr, const char *name, const char *abbr, const char *desc,
1779 enum ftenum ft, field_display_e base, value_string_ext *vs_ext,
1780 uint32_t mask)
1782 hf_register_info hf;
1784 hf.p_id = hf_ptr;
1785 hf.hfinfo.name = name;
1786 hf.hfinfo.abbrev = abbr;
1787 hf.hfinfo.type = ft;
1788 hf.hfinfo.display = base;
1789 hf.hfinfo.strings = NULL;
1790 hf.hfinfo.bitmask = mask;
1791 hf.hfinfo.blurb = desc;
1792 /* HFILL */
1793 HFILL_INIT(hf);
1795 if (vs_ext) {
1796 hf.hfinfo.strings = vs_ext;
1799 wmem_array_append_one(build_dict.hf,hf);
1800 return wmem_array_get_count(build_dict.hf);
1803 static void
1804 basic_avp_reginfo(diam_avp_t *a, const char *name, enum ftenum ft,
1805 field_display_e base, value_string_ext *vs_ext)
1807 hf_register_info hf;
1808 int *ettp = &(a->ett);
1810 hf.p_id = &(a->hf_value);
1811 hf.hfinfo.name = NULL;
1812 hf.hfinfo.abbrev = NULL;
1813 hf.hfinfo.type = ft;
1814 hf.hfinfo.display = base;
1815 hf.hfinfo.strings = NULL;
1816 hf.hfinfo.bitmask = 0x0;
1817 hf.hfinfo.blurb = a->vendor->code ?
1818 wmem_strdup_printf(wmem_epan_scope(), "vendor=%d code=%d", a->vendor->code, a->code)
1819 : wmem_strdup_printf(wmem_epan_scope(), "code=%d", a->code);
1820 /* HFILL */
1821 HFILL_INIT(hf);
1823 hf.hfinfo.name = wmem_strdup(wmem_epan_scope(), name);
1824 hf.hfinfo.abbrev = alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, NULL));
1825 if (vs_ext) {
1826 hf.hfinfo.strings = vs_ext;
1829 wmem_array_append(build_dict.hf,&hf,1);
1830 g_ptr_array_add(build_dict.ett,ettp);
1833 static diam_avp_t *
1834 build_gen_address_avp(diam_avp_t *a, address_avp_t *t, const char *name)
1836 int *ettp = &(t->ett);
1838 a->ett = -1;
1839 a->hf_value = -1;
1840 a->type_data = t;
1842 t->ett = -1;
1843 t->hf_address_type = -1;
1844 t->hf_ipv4 = -1;
1845 t->hf_ipv6 = -1;
1846 t->hf_e164_str = -1;
1847 t->hf_other = -1;
1849 basic_avp_reginfo(a, name, FT_BYTES, BASE_NONE, NULL);
1851 reginfo(&(t->hf_address_type), wmem_strconcat(wmem_epan_scope(), name, " Address Family", NULL),
1852 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".addr_family", NULL)),
1853 NULL, FT_UINT16, (field_display_e)(BASE_DEC|BASE_EXT_STRING), &diameter_avp_data_addrfamily_vals_ext, 0);
1855 reginfo(&(t->hf_ipv4), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1856 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".IPv4", NULL)),
1857 NULL, FT_IPv4, BASE_NONE, NULL, 0);
1859 reginfo(&(t->hf_ipv6), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1860 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".IPv6", NULL)),
1861 NULL, FT_IPv6, BASE_NONE, NULL, 0);
1863 reginfo(&(t->hf_e164_str), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1864 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".E164", NULL)),
1865 NULL, FT_STRING, BASE_NONE, NULL, 0);
1867 reginfo(&(t->hf_other), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1868 alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".Bytes", NULL)),
1869 NULL, FT_BYTES, BASE_NONE, NULL, 0);
1871 g_ptr_array_add(build_dict.ett,ettp);
1873 return a;
1877 * RFC 6733 says:
1878 * > AVP numbers 1 through 255 are reserved for reuse of RADIUS attributes,
1879 * > without setting the Vendor-Id field.
1881 * This clearly applies not to vendor dictionaries. However, some vendors seem to have
1882 * translated their RADIUS dictionaries to Diameter with that assumption in mind, while
1883 * others have not.
1885 * To make this work universally, the type `ipaddress` is assumed to be using the RADIUS
1886 * encoding for AVP < 256 and Diameter for AVPs >= 256, while the `address` type will
1887 * use Diameter encoding for all AVPs
1889 static diam_avp_t *
1890 build_ipaddress_avp(const avp_type_t *type _U_, uint32_t code,
1891 diam_vnd_t *vendor, const char *name,
1892 const value_string *vs _U_, void *data _U_)
1894 diam_avp_t *a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1895 address_avp_t *t = wmem_new(wmem_epan_scope(), address_avp_t);
1897 a->code = code;
1898 a->vendor = vendor;
1900 * It seems like the radius AVPs 1-255 will use the defs from RADIUS in which case:
1901 * https://tools.ietf.org/html/rfc2685
1902 * Address
1903 * The Address field is four octets. The value 0xFFFFFFFF indicates
1904 * that the NAS Should allow the user to select an address (e.g.
1905 * Negotiated). The value 0xFFFFFFFE indicates that the NAS should
1906 * select an address for the user (e.g. Assigned from a pool of
1907 * addresses kept by the NAS). Other valid values indicate that the
1908 * NAS should use that value as the user's IP address.
1910 * Where as in Diameter:
1911 * RFC3588
1912 * Address
1913 * The Address format is derived from the OctetString AVP Base
1914 * Format. It is a discriminated union, representing, for example a
1915 * 32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1916 * significant octet first. The first two octets of the Address
1917 * AVP represents the AddressType, which contains an Address Family
1918 * defined in [IANAADFAM]. The AddressType is used to discriminate
1919 * the content and format of the remaining octets.
1921 if (code<256) {
1922 a->dissector_rfc = address_radius_avp;
1923 } else {
1924 a->dissector_rfc = address_rfc_avp;
1926 return build_gen_address_avp(a, t, name);
1929 static diam_avp_t *
1930 build_address_avp(const avp_type_t *type _U_, uint32_t code,
1931 diam_vnd_t *vendor, const char *name,
1932 const value_string *vs _U_, void *data _U_)
1934 diam_avp_t *a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1935 address_avp_t *t = wmem_new(wmem_epan_scope(), address_avp_t);
1937 a->code = code;
1938 a->vendor = vendor;
1939 a->dissector_rfc = address_rfc_avp;
1941 return build_gen_address_avp(a, t, name);
1944 static diam_avp_t *
1945 build_proto_avp(const avp_type_t *type _U_, uint32_t code,
1946 diam_vnd_t *vendor, const char *name _U_,
1947 const value_string *vs _U_, void *data)
1949 diam_avp_t *a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1950 proto_avp_t *t = wmem_new0(wmem_epan_scope(), proto_avp_t);
1951 int *ettp = &(a->ett);
1953 a->code = code;
1954 a->vendor = vendor;
1955 a->dissector_rfc = proto_avp;
1956 a->ett = -1;
1957 a->hf_value = -2;
1958 a->type_data = t;
1960 t->name = (char *)data;
1961 t->handle = NULL;
1962 t->reassemble_mode = REASEMBLE_NEVER;
1964 g_ptr_array_add(build_dict.ett,ettp);
1966 return a;
1969 static diam_avp_t *
1970 build_simple_avp(const avp_type_t *type, uint32_t code, diam_vnd_t *vendor,
1971 const char *name, const value_string *vs, void *data _U_)
1973 diam_avp_t *a;
1974 value_string_ext *vs_ext = NULL;
1975 field_display_e base;
1976 unsigned i = 0;
1979 * Only 32-bit or shorter integral types can have a list of values.
1981 base = (field_display_e)type->base;
1982 if (vs != NULL) {
1983 switch (type->ft) {
1985 case FT_UINT8:
1986 case FT_UINT16:
1987 case FT_UINT32:
1988 case FT_INT8:
1989 case FT_INT16:
1990 case FT_INT32:
1991 break;
1993 default:
1994 report_failure("Diameter Dictionary: AVP '%s' has a list of values but isn't of a 32-bit or shorter integral type (%s)\n",
1995 name, ftype_name(type->ft));
1996 return NULL;
1998 while (vs[i].strptr) {
1999 i++;
2001 vs_ext = value_string_ext_new(vs, i+1, wmem_strconcat(wmem_epan_scope(), name, "_vals_ext", NULL));
2002 base = (field_display_e)(base|BASE_EXT_STRING);
2005 a = wmem_new0(wmem_epan_scope(), diam_avp_t);
2006 a->code = code;
2007 a->vendor = vendor;
2008 a->dissector_rfc = type->rfc;
2009 a->ett = -1;
2010 a->hf_value = -1;
2012 basic_avp_reginfo(a, name, type->ft, base, vs_ext);
2014 return a;
2017 static diam_avp_t *
2018 build_appid_avp(const avp_type_t *type, uint32_t code, diam_vnd_t *vendor,
2019 const char *name, const value_string *vs, void *data _U_)
2021 diam_avp_t *a;
2022 field_display_e base;
2024 a = wmem_new0(wmem_epan_scope(), diam_avp_t);
2025 a->code = code;
2026 a->vendor = vendor;
2027 a->dissector_rfc = type->rfc;
2028 a->ett = -1;
2029 a->hf_value = -1;
2031 if (vs != NULL) {
2032 report_failure("Diameter Dictionary: AVP '%s' (of type AppId) has a list of values but the list won't be used\n",
2033 name);
2036 base = (field_display_e)(type->base|BASE_EXT_STRING);
2038 basic_avp_reginfo(a, name, type->ft, base, dictionary.applications);
2039 return a;
2042 static const avp_type_t basic_types[] = {
2043 {"octetstring" , simple_avp , FT_BYTES , BASE_NONE , build_simple_avp },
2044 {"octetstringorutf8" , simple_avp , FT_BYTES , BASE_SHOW_ASCII_PRINTABLE , build_simple_avp },
2045 {"utf8string" , utf8_avp , FT_STRING , BASE_NONE , build_simple_avp },
2046 {"grouped" , grouped_avp , FT_BYTES , BASE_NONE , build_simple_avp },
2047 {"integer32" , integer32_avp , FT_INT32 , BASE_DEC , build_simple_avp },
2048 {"unsigned32" , unsigned32_avp , FT_UINT32 , BASE_DEC , build_simple_avp },
2049 {"integer64" , integer64_avp , FT_INT64 , BASE_DEC , build_simple_avp },
2050 {"unsigned64" , unsigned64_avp , FT_UINT64 , BASE_DEC , build_simple_avp },
2051 {"float32" , float32_avp , FT_FLOAT , BASE_NONE , build_simple_avp },
2052 {"float64" , float64_avp , FT_DOUBLE , BASE_NONE , build_simple_avp },
2053 {"ipaddress" , NULL , FT_NONE , BASE_NONE , build_ipaddress_avp },
2054 {"address" , NULL , FT_NONE , BASE_NONE , build_address_avp },
2055 {"diameteruri" , utf8_avp , FT_STRING , BASE_NONE , build_simple_avp },
2056 {"diameteridentity" , utf8_avp , FT_STRING , BASE_NONE , build_simple_avp },
2057 {"ipfilterrule" , utf8_avp , FT_STRING , BASE_NONE , build_simple_avp },
2058 {"qosfilterrule" , utf8_avp , FT_STRING , BASE_NONE , build_simple_avp },
2059 {"time" , time_avp , FT_ABSOLUTE_TIME , ABSOLUTE_TIME_UTC , build_simple_avp },
2060 {"AppId" , simple_avp , FT_UINT32 , BASE_DEC , build_appid_avp },
2061 {NULL, NULL, FT_NONE, BASE_NONE, NULL }
2067 * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
2068 * upper-case ASCII characters to their ASCII lower-case equivalents.
2069 * We can't use g_strdown(), as that doesn't do an ASCII mapping;
2070 * in Turkish locales, for example, there are two lower-case "i"s
2071 * and two upper-case "I"s, with and without dots - the ones with
2072 * dots map between each other, as do the ones without dots, so "I"
2073 * doesn't map to "i".
2075 static unsigned
2076 strcase_hash(const void *key)
2078 const char *p = (const char *)key;
2079 unsigned h = *p;
2080 char c;
2082 if (h) {
2083 if (h >= 'A' && h <= 'Z')
2084 h = h - 'A' + 'a';
2085 for (p += 1; *p != '\0'; p++) {
2086 c = *p;
2087 if (c >= 'A' && c <= 'Z')
2088 c = c - 'A' + 'a';
2089 h = (h << 5) - h + c;
2093 return h;
2097 * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
2098 * letters are mapped, and they're mapped to the lower-case ASCII
2099 * equivalents.
2101 static gboolean
2102 strcase_equal(const void *ka, const void *kb)
2104 const char *a = (const char *)ka;
2105 const char *b = (const char *)kb;
2106 return g_ascii_strcasecmp(a,b) == 0;
2109 static bool
2110 ddict_cleanup_cb(wmem_allocator_t* allocator _U_, wmem_cb_event_t event _U_, void *user_data)
2112 ddict_t *d = (ddict_t *)user_data;
2113 ddict_free(d);
2114 return false;
2118 /* Note: Dynamic "value string arrays" (e.g., vs_avps, ...) are constructed using */
2119 /* "zero-terminated" GArrays so that they will have the same form as standard */
2120 /* value_string arrays created at compile time. Since the last entry in a */
2121 /* value_string array must be {0, NULL}, we are assuming that NULL == 0 (hackish). */
2123 static int
2124 dictionary_load(void)
2126 ddict_t *d;
2127 ddict_application_t *p;
2128 ddict_vendor_t *v;
2129 ddict_cmd_t *c;
2130 ddict_typedefn_t *t;
2131 ddict_avp_t *a;
2132 bool do_debug_parser = getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? true : false;
2133 bool do_dump_dict = getenv("WIRESHARK_DUMP_DIAM_DICT") ? true : false;
2134 char *dir;
2135 const avp_type_t *type;
2136 const avp_type_t *octetstring = &basic_types[0];
2137 diam_avp_t *avp;
2138 GHashTable *vendors = g_hash_table_new(strcase_hash,strcase_equal);
2139 diam_vnd_t *vnd;
2140 GArray *vnd_shrt_arr = g_array_new(true,true,sizeof(value_string));
2141 GArray *all_cmds = g_array_new(true,true,sizeof(value_string));
2143 /* Pre allocate the arrays big enough to hold the hf:s and etts:s*/
2144 build_dict.hf = wmem_array_sized_new(wmem_epan_scope(), sizeof(hf_register_info), 4096);
2145 build_dict.ett = g_ptr_array_sized_new(4096);
2146 build_dict.types = g_hash_table_new(strcase_hash,strcase_equal);
2147 build_dict.avps = g_hash_table_new(strcase_hash,strcase_equal);
2149 dictionary.vnds = wmem_tree_new(wmem_epan_scope());
2150 dictionary.avps = wmem_tree_new(wmem_epan_scope());
2152 unknown_vendor.vs_avps = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2153 wmem_array_set_null_terminator(unknown_vendor.vs_avps);
2154 wmem_array_bzero(unknown_vendor.vs_avps);
2155 no_vnd.vs_avps = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2156 wmem_array_set_null_terminator(no_vnd.vs_avps);
2157 wmem_array_bzero(no_vnd.vs_avps);
2159 wmem_tree_insert32(dictionary.vnds,0,&no_vnd);
2160 g_hash_table_insert(vendors,"None",&no_vnd);
2162 /* initialize the types hash with the known basic types */
2163 for (type = basic_types; type->name; type++) {
2164 g_hash_table_insert(build_dict.types,(char *)type->name,(void *)type);
2167 /* load the dictionary */
2168 dir = wmem_strdup_printf(NULL, "%s" G_DIR_SEPARATOR_S "diameter" G_DIR_SEPARATOR_S, get_datafile_dir());
2169 d = ddict_scan(dir,"dictionary.xml",do_debug_parser);
2170 wmem_free(NULL, dir);
2171 if (d == NULL) {
2172 g_hash_table_destroy(vendors);
2173 g_array_free(vnd_shrt_arr, true);
2174 return 0;
2176 wmem_register_callback(wmem_epan_scope(), ddict_cleanup_cb, d);
2178 if (do_dump_dict) ddict_print(stdout, d);
2180 /* populate the types */
2181 for (t = d->typedefns; t; t = t->next) {
2182 const avp_type_t *parent = NULL;
2183 /* try to get the parent type */
2185 if (t->name == NULL) {
2186 report_failure("Diameter Dictionary: Invalid Type (empty name): parent==%s\n",
2187 t->parent ? t->parent : "(null)");
2188 continue;
2192 if (g_hash_table_lookup(build_dict.types,t->name))
2193 continue;
2195 if (t->parent) {
2196 parent = (avp_type_t *)g_hash_table_lookup(build_dict.types,t->parent);
2199 if (!parent) parent = octetstring;
2201 /* insert the parent type for this type */
2202 g_hash_table_insert(build_dict.types,t->name,(void *)parent);
2205 /* populate the applications */
2206 if ((p = d->applications)) {
2207 wmem_array_t *arr = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2208 value_string term[1];
2210 term[0].value = 0;
2211 term[0].strptr = NULL;
2213 for (; p; p = p->next) {
2214 value_string item[1];
2216 item[0].value = p->code;
2217 item[0].strptr = p->name;
2218 if (!p->name) {
2219 report_failure("Diameter Dictionary: Invalid Application (empty name): id=%d\n", p->code);
2220 continue;
2223 wmem_array_append_one(arr,item);
2226 wmem_array_sort(arr, compare_avps);
2227 wmem_array_append_one(arr,term);
2229 /* TODO: Remove duplicates */
2231 dictionary.applications = value_string_ext_new((value_string *)wmem_array_get_raw(arr),
2232 wmem_array_get_count(arr),
2233 wmem_strdup(wmem_epan_scope(), "applications_vals_ext"));
2236 if ((v = d->vendors)) {
2237 for ( ; v; v = v->next) {
2238 value_string item[1];
2240 item[0].value = v->code;
2241 item[0].strptr = v->name;
2243 if (v->name == NULL) {
2244 report_failure("Diameter Dictionary: Invalid Vendor (empty name): code==%d\n", v->code);
2245 continue;
2248 if (g_hash_table_lookup(vendors,v->name))
2249 continue;
2251 g_array_append_val(vnd_shrt_arr,item);
2253 vnd = wmem_new(wmem_epan_scope(), diam_vnd_t);
2254 vnd->code = v->code;
2255 vnd->vs_avps = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2256 wmem_array_set_null_terminator(vnd->vs_avps);
2257 wmem_array_bzero(vnd->vs_avps);
2258 vnd->vs_avps_ext = NULL;
2259 wmem_tree_insert32(dictionary.vnds,vnd->code,vnd);
2260 g_hash_table_insert(vendors,v->name,vnd);
2264 vnd_short_vs = (value_string *)g_array_free(vnd_shrt_arr, false);
2266 if ((c = d->cmds)) {
2267 for (; c; c = c->next) {
2268 if (c->vendor == NULL) {
2269 report_failure("Diameter Dictionary: Invalid Vendor (empty name) for command %s\n",
2270 c->name ? c->name : "(null)");
2271 continue;
2274 if ((diam_vnd_t *)g_hash_table_lookup(vendors,c->vendor)) {
2275 value_string item[1];
2277 item[0].value = c->code;
2278 item[0].strptr = c->name;
2280 g_array_append_val(all_cmds,item);
2281 } else {
2282 report_failure("Diameter Dictionary: No Vendor: %s\n",c->vendor);
2288 for (a = d->avps; a; a = a->next) {
2289 ddict_enum_t *e;
2290 value_string *vs = NULL;
2291 const char *vend = a->vendor ? a->vendor : "None";
2292 ddict_xmlpi_t *x;
2293 void *avp_data = NULL;
2295 if (a->name == NULL) {
2296 report_failure("Diameter Dictionary: Invalid AVP (empty name)\n");
2297 continue;
2300 if ((vnd = (diam_vnd_t *)g_hash_table_lookup(vendors,vend))) {
2301 value_string vndvs[1];
2303 vndvs[0].value = a->code;
2304 vndvs[0].strptr = a->name;
2307 wmem_array_append_one(vnd->vs_avps,vndvs);
2308 } else {
2309 report_failure("Diameter Dictionary: No Vendor: %s\n",vend);
2310 vnd = &unknown_vendor;
2313 if ((e = a->enums)) {
2314 wmem_array_t *arr = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2315 value_string term[1];
2317 term[0].value = 0;
2318 term[0].strptr = NULL;
2320 for (; e; e = e->next) {
2321 value_string item[1];
2323 item[0].value = e->code;
2324 item[0].strptr = e->name;
2325 wmem_array_append_one(arr,item);
2327 wmem_array_sort(arr, compare_avps);
2328 wmem_array_append_one(arr,term);
2329 vs = (value_string *)wmem_array_get_raw(arr);
2332 type = NULL;
2334 for( x = d->xmlpis; x; x = x->next ) {
2335 if ( (strcase_equal(x->name,"avp-proto") && strcase_equal(x->key,a->name))
2336 || (a->type && strcase_equal(x->name,"type-proto") && strcase_equal(x->key,a->type))
2338 static avp_type_t proto_type = {"proto", proto_avp, FT_UINT32, BASE_HEX, build_proto_avp};
2339 type = &proto_type;
2341 avp_data = x->value;
2342 break;
2346 if ( (!type) && a->type )
2347 type = (avp_type_t *)g_hash_table_lookup(build_dict.types,a->type);
2349 if (!type) type = octetstring;
2351 avp = type->build( type, a->code, vnd, a->name, vs, avp_data);
2352 if (avp != NULL) {
2353 g_hash_table_insert(build_dict.avps, a->name, avp);
2356 wmem_tree_key_t k[3];
2358 k[0].length = 1;
2359 k[0].key = &(a->code);
2360 k[1].length = 1;
2361 k[1].key = &(vnd->code);
2362 k[2].length = 0;
2363 k[2].key = NULL;
2365 wmem_tree_insert32_array(dictionary.avps,k,avp);
2369 g_hash_table_destroy(build_dict.types);
2370 g_hash_table_destroy(build_dict.avps);
2371 g_hash_table_destroy(vendors);
2373 cmd_vs = (const value_string *)g_array_free(all_cmds, false);
2375 return 1;
2379 * This does most of the registration work; see register_diameter_fields()
2380 * for the reason why we split it off.
2382 static void
2383 real_register_diameter_fields(void)
2385 expert_module_t* expert_diameter;
2386 unsigned i, ett_length;
2388 hf_register_info hf_base[] = {
2389 { &hf_diameter_version,
2390 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
2391 NULL, HFILL }},
2392 { &hf_diameter_length,
2393 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
2394 NULL, HFILL }},
2395 { &hf_diameter_flags,
2396 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
2397 NULL, HFILL }},
2398 { &hf_diameter_flags_request,
2399 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_R,
2400 NULL, HFILL }},
2401 { &hf_diameter_flags_proxyable,
2402 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_P,
2403 NULL, HFILL }},
2404 { &hf_diameter_flags_error,
2405 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_E,
2406 NULL, HFILL }},
2407 { &hf_diameter_flags_T,
2408 { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_T,
2409 NULL, HFILL }},
2410 { &hf_diameter_flags_reserved4,
2411 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2412 DIAM_FLAGS_RESERVED4, NULL, HFILL }},
2413 { &hf_diameter_flags_reserved5,
2414 { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2415 DIAM_FLAGS_RESERVED5, NULL, HFILL }},
2416 { &hf_diameter_flags_reserved6,
2417 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2418 DIAM_FLAGS_RESERVED6, NULL, HFILL }},
2419 { &hf_diameter_flags_reserved7,
2420 { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2421 DIAM_FLAGS_RESERVED7, NULL, HFILL }},
2422 { &hf_diameter_vendor_id,
2423 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_ENTERPRISES, STRINGS_ENTERPRISES,
2424 0x0, NULL, HFILL }},
2425 { &hf_diameter_application_id,
2426 { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC|BASE_EXT_STRING, VALS_EXT_PTR(dictionary.applications),
2427 0x0, NULL, HFILL }},
2428 { &hf_diameter_hopbyhopid,
2429 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
2430 BASE_HEX, NULL, 0x0, NULL, HFILL }},
2431 { &hf_diameter_endtoendid,
2432 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
2433 BASE_HEX, NULL, 0x0, NULL, HFILL }},
2434 { &hf_diameter_avp,
2435 { "AVP","diameter.avp", FT_BYTES, BASE_NONE,
2436 NULL, 0x0, NULL, HFILL }},
2437 { &hf_diameter_avp_len,
2438 { "AVP Length","diameter.avp.len", FT_UINT24, BASE_DEC,
2439 NULL, 0x0, NULL, HFILL }},
2440 { &hf_diameter_avp_code,
2441 { "AVP Code", "diameter.avp.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
2442 { &hf_diameter_avp_flags,
2443 { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
2444 NULL, 0x0, NULL, HFILL }},
2445 { &hf_diameter_avp_flags_vendor_specific,
2446 { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_V,
2447 NULL, HFILL }},
2448 { &hf_diameter_avp_flags_mandatory,
2449 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_M,
2450 NULL, HFILL }},
2451 { &hf_diameter_avp_flags_protected,
2452 { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_P,
2453 NULL, HFILL }},
2454 { &hf_diameter_avp_flags_reserved3,
2455 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2456 AVP_FLAGS_RESERVED3, NULL, HFILL }},
2457 { &hf_diameter_avp_flags_reserved4,
2458 { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2459 AVP_FLAGS_RESERVED4, NULL, HFILL }},
2460 { &hf_diameter_avp_flags_reserved5,
2461 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2462 AVP_FLAGS_RESERVED5, NULL, HFILL }},
2463 { &hf_diameter_avp_flags_reserved6,
2464 { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2465 AVP_FLAGS_RESERVED6, NULL, HFILL }},
2466 { &hf_diameter_avp_flags_reserved7,
2467 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2468 AVP_FLAGS_RESERVED7, NULL, HFILL }},
2469 { &hf_diameter_avp_vendor_id,
2470 { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_ENTERPRISES, STRINGS_ENTERPRISES,
2471 0x0, NULL, HFILL }},
2472 { &(unknown_avp.hf_value),
2473 { "Value","diameter.avp.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2474 { &hf_diameter_avp_data_wrong_length,
2475 { "Data","diameter.avp.invalid-data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2476 { &hf_diameter_avp_pad,
2477 { "Padding","diameter.avp.pad", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2478 { &hf_diameter_code,
2479 { "Command Code", "diameter.cmd.code", FT_UINT32, BASE_DEC, VALS(cmd_vs), 0, NULL, HFILL }},
2480 { &hf_diameter_answer_in,
2481 { "Answer In", "diameter.answer_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
2482 "The answer to this diameter request is in this frame", HFILL }},
2483 { &hf_diameter_answer_to,
2484 { "Request In", "diameter.answer_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
2485 "This is an answer to the diameter request in this frame", HFILL }},
2486 { &hf_diameter_answer_time,
2487 { "Response Time", "diameter.resp_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2488 "The time between the request and the answer", HFILL }},
2489 { &hf_framed_ipv6_prefix_reserved,
2490 { "Framed IPv6 Prefix Reserved byte", "diameter.framed_ipv6_prefix_reserved",
2491 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
2492 { &hf_framed_ipv6_prefix_length,
2493 { "Framed IPv6 Prefix length (in bits)", "diameter.framed_ipv6_prefix_length",
2494 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
2495 { &hf_framed_ipv6_prefix_bytes,
2496 { "Framed IPv6 Prefix as a bytestring", "diameter.framed_ipv6_prefix_bytes",
2497 FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
2498 { &hf_framed_ipv6_prefix_ipv6,
2499 { "Framed IPv6 Prefix as an IPv6 address", "diameter.framed_ipv6_prefix_ipv6",
2500 FT_IPv6, BASE_NONE, NULL, 0, "This field is present only if the prefix length is 128", HFILL }},
2501 { &hf_diameter_3gpp2_exp_res,
2502 { "Experimental-Result-Code", "diameter.3gpp2.exp_res",
2503 FT_UINT32, BASE_DEC, VALS(diameter_3gpp2_exp_res_vals), 0x0, NULL, HFILL }},
2504 { &hf_diameter_other_vendor_exp_res,
2505 { "Experimental-Result-Code", "diameter.other_vendor.Experimental-Result-Code",
2506 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2507 { &hf_diameter_mip6_feature_vector,
2508 { "MIP6-Feature-Vector", "diameter.mip6_feature_vector",
2509 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2510 { &hf_diameter_mip6_feature_vector_mip6_integrated,
2511 { "MIP6_INTEGRATED", "diameter.mip6_feature_vector.mip6_integrated.mip6_integrated",
2512 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000000000000001, NULL, HFILL }},
2513 { &hf_diameter_mip6_feature_vector_local_home_agent_assignment,
2514 { "LOCAL_HOME_AGENT_ASSIGNMENT", "diameter.mip6_feature_vector.local_home_agent_assignment",
2515 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000000000000002, NULL, HFILL }},
2516 { &hf_diameter_mip6_feature_vector_pmip6_supported,
2517 { "PMIP6_SUPPORTED", "diameter.mip6_feature_vector.pmip6_supported",
2518 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000010000000000, NULL, HFILL }},
2519 { &hf_diameter_mip6_feature_vector_ip4_hoa_supported,
2520 { "IP4_HOA_SUPPORTED", "diameter.mip6_feature_vector.ip4_hoa_supported",
2521 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000020000000000, NULL, HFILL }},
2522 { &hf_diameter_mip6_feature_vector_local_mag_routing_supported,
2523 { "LOCAL_MAG_ROUTING_SUPPORTED", "diameter.mip6_feature_vector.local_mag_routing_supported",
2524 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000040000000000,NULL, HFILL }},
2525 { &hf_diameter_3gpp_mip6_feature_vector,
2526 { "MIP6-Feature-Vector [3GPP]", "diameter.3gpp.mip6_feature_vector",
2527 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2528 { &hf_diameter_3gpp_mip6_feature_vector_assign_local_ip,
2529 { "MIP6_INTEGRATED", "diameter.3gpp.mip6_feature_vector.assign_local_ip",
2530 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000080000000000, NULL, HFILL }},
2531 { &hf_diameter_3gpp_mip6_feature_vector_mip4_supported,
2532 { "PMIP6_SUPPORTED", "diameter.3gpp.mip6_feature_vector.mip4_supported",
2533 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000100000000000, NULL, HFILL }},
2534 { &hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility,
2535 { "OPTIMIZED_IDLE_MODE_MOBILITY", "diameter.3gpp.mip6_feature_vector.optimized_idle_mode_mobility",
2536 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000200000000000, NULL, HFILL }},
2537 { &hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported,
2538 { "GTPv2_SUPPORTED", "diameter.3gpp.mip6_feature_vector.gtpv2_supported",
2539 FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000400000000000, NULL, HFILL }},
2540 { &hf_diameter_user_equipment_info_imeisv,
2541 { "IMEISV","diameter.user_equipment_info.imeisv", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2542 { &hf_diameter_user_equipment_info_mac,
2543 { "MAC","diameter.user_equipment_info.mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2544 { &hf_diameter_user_equipment_info_eui64,
2545 { "EUI64","diameter.user_equipment_info.eui64", FT_EUI64, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2546 { &hf_diameter_user_equipment_info_modified_eui64,
2547 { "Modified EUI64","diameter.user_equipment_info.modified_eui64", FT_EUI64, BASE_NONE, NULL, 0x0, NULL, HFILL }}
2550 int *ett_base[] = {
2551 &ett_diameter,
2552 &ett_diameter_flags,
2553 &ett_diameter_avp_flags,
2554 &ett_diameter_avpinfo,
2555 &ett_unknown,
2556 &ett_diameter_mip6_feature_vector,
2557 &ett_diameter_3gpp_mip6_feature_vector,
2558 &(unknown_avp.ett)
2561 static ei_register_info ei[] = {
2562 { &ei_diameter_reserved_bit_set, { "diameter.reserved_bit_set", PI_MALFORMED, PI_WARN, "Reserved bit set", EXPFILL }},
2563 { &ei_diameter_avp_code, { "diameter.avp.code.unknown", PI_UNDECODED, PI_WARN, "Unknown AVP, if you know what this is you can add it to dictionary.xml", EXPFILL }},
2564 { &ei_diameter_avp_vendor_id, { "diameter.unknown_vendor", PI_UNDECODED, PI_WARN, "Unknown Vendor, if you know whose this is you can add it to dictionary.xml", EXPFILL }},
2565 { &ei_diameter_avp_no_data, { "diameter.avp.no_data", PI_UNDECODED, PI_WARN, "Data is empty", EXPFILL }},
2566 { &ei_diameter_avp_pad, { "diameter.avp.pad.non_zero", PI_MALFORMED, PI_NOTE, "Padding is non-zero", EXPFILL }},
2567 { &ei_diameter_avp_pad_missing, { "diameter.avp.pad.missing", PI_MALFORMED, PI_NOTE, "Padding is missing", EXPFILL }},
2568 { &ei_diameter_avp_len, { "diameter.avp.invalid-len", PI_MALFORMED, PI_WARN, "Wrong length", EXPFILL }},
2569 { &ei_diameter_application_id, { "diameter.applicationId.unknown", PI_UNDECODED, PI_WARN, "Unknown Application Id, if you know what this is you can add it to dictionary.xml", EXPFILL }},
2570 { &ei_diameter_version, { "diameter.version.unknown", PI_UNDECODED, PI_WARN, "Unknown Diameter Version (decoding as RFC 3588)", EXPFILL }},
2571 { &ei_diameter_code, { "diameter.cmd.code.unknown", PI_UNDECODED, PI_WARN, "Unknown command, if you know what this is you can add it to dictionary.xml", EXPFILL }},
2572 { &ei_diameter_invalid_ipv6_prefix_len, { "diameter.invalid_ipv6_prefix_len", PI_MALFORMED, PI_ERROR, "Invalid IPv6 Prefix length", EXPFILL }},
2573 { &ei_diameter_invalid_avp_len,{ "diameter.invalid_avp_len", PI_MALFORMED, PI_ERROR, "Invalid AVP length", EXPFILL }},
2574 { &ei_diameter_invalid_user_equipment_info_value_len,{ "diameter.invalid_user_equipment_info_value_len", PI_MALFORMED, PI_ERROR, "Invalid User-Equipment-Info-Value length", EXPFILL }},
2575 { &ei_diameter_unexpected_imei_as_user_equipment_info,{ "diameter.unexpected_imei_as_user_equipment_info", PI_MALFORMED, PI_ERROR, "Found IMEI as User-Equipment-Info-Value but IMEISV was expected", EXPFILL }},
2578 wmem_array_append(build_dict.hf, hf_base, array_length(hf_base));
2579 ett_length = array_length(ett_base);
2580 for (i = 0; i < ett_length; i++) {
2581 g_ptr_array_add(build_dict.ett, ett_base[i]);
2584 proto_register_field_array(proto_diameter, (hf_register_info *)wmem_array_get_raw(build_dict.hf), wmem_array_get_count(build_dict.hf));
2585 proto_register_subtree_array((int **)build_dict.ett->pdata, build_dict.ett->len);
2586 expert_diameter = expert_register_protocol(proto_diameter);
2587 expert_register_field_array(expert_diameter, ei, array_length(ei));
2589 g_ptr_array_free(build_dict.ett,true);
2593 static void
2594 register_diameter_fields(const char *unused _U_)
2597 * The hf_base[] array for Diameter refers to a variable
2598 * that is set by dictionary_load(), so we need to call
2599 * dictionary_load() before hf_base[] is initialized.
2601 * To ensure that, we call dictionary_load() and then
2602 * call a routine that defines hf_base[] and does all
2603 * the registration work.
2605 dictionary_load();
2606 real_register_diameter_fields();
2609 void
2610 proto_register_diameter(void)
2612 module_t *diameter_module;
2614 proto_diameter = proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
2616 /* Allow dissector to find be found by name. */
2617 diameter_sctp_handle = register_dissector("diameter", dissect_diameter, proto_diameter);
2618 diameter_udp_handle = create_dissector_handle(dissect_diameter, proto_diameter);
2619 diameter_tcp_handle = register_dissector("diameter.tcp", dissect_diameter_tcp, proto_diameter);
2620 /* Diameter AVPs without Diameter header, for EAP-TTLS (RFC 5281, Section 10) */
2621 register_dissector("diameter_avps", dissect_diameter_avps, proto_diameter);
2623 /* Delay registration of Diameter fields */
2624 proto_register_prefix("diameter", register_diameter_fields);
2626 /* Register dissector table(s) to do sub dissection of AVPs (OctetStrings) */
2627 diameter_dissector_table = register_dissector_table("diameter.base", "Diameter Base AVP", proto_diameter, FT_UINT32, BASE_DEC);
2628 diameter_3gpp_avp_dissector_table = register_dissector_table("diameter.3gpp", "Diameter 3GPP AVP", proto_diameter, FT_UINT32, BASE_DEC);
2629 diameter_ericsson_avp_dissector_table = register_dissector_table("diameter.ericsson", "Diameter Ericsson AVP", proto_diameter, FT_UINT32, BASE_DEC);
2630 diameter_verizon_avp_dissector_table = register_dissector_table("diameter.verizon", "DIAMETER_VERIZON_AVPS", proto_diameter, FT_UINT32, BASE_DEC);
2632 diameter_expr_result_vnd_table = register_dissector_table("diameter.vnd_exp_res", "Diameter Experimental-Result-Code", proto_diameter, FT_UINT32, BASE_DEC);
2634 /* Register configuration options */
2635 diameter_module = prefs_register_protocol(proto_diameter, NULL);
2636 /* For reading older preference files with "Diameter." preferences */
2637 prefs_register_module_alias("Diameter", diameter_module);
2639 /* Desegmentation */
2640 prefs_register_bool_preference(diameter_module, "desegment",
2641 "Reassemble Diameter messages spanning multiple TCP segments",
2642 "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
2643 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2644 &gbl_diameter_desegment);
2646 /* Register some preferences we no longer support, so we can report
2647 * them as obsolete rather than just illegal.
2649 prefs_register_obsolete_preference(diameter_module, "version");
2650 prefs_register_obsolete_preference(diameter_module, "command_in_header");
2651 prefs_register_obsolete_preference(diameter_module, "dictionary.name");
2652 prefs_register_obsolete_preference(diameter_module, "dictionary.use");
2653 prefs_register_obsolete_preference(diameter_module, "allow_zero_as_app_id");
2654 prefs_register_obsolete_preference(diameter_module, "suppress_console_output");
2656 /* Register tap */
2657 diameter_tap = register_tap("diameter");
2659 register_srt_table(proto_diameter, NULL, 1, diameterstat_packet, diameterstat_init, NULL);
2661 } /* proto_register_diameter */
2663 void
2664 proto_reg_handoff_diameter(void)
2666 data_handle = find_dissector("data");
2667 eap_handle = find_dissector_add_dependency("eap", proto_diameter);
2669 dissector_add_uint("sctp.ppi", DIAMETER_PROTOCOL_ID, diameter_sctp_handle);
2671 heur_dissector_add("tcp", dissect_diameter_tcp_heur, "Diameter over TCP", "diameter_tcp", proto_diameter, HEURISTIC_DISABLE);
2673 ssl_dissector_add(DEFAULT_DIAMETER_TLS_PORT, diameter_tcp_handle);
2674 dtls_dissector_add(DEFAULT_DIAMETER_TLS_PORT, diameter_sctp_handle);
2676 /* Register special decoding for some AVPs */
2678 /* AVP Code: 1 User-Name */
2679 dissector_add_uint("diameter.base", 1, create_dissector_handle(dissect_diameter_user_name, proto_diameter));
2681 /* AVP Code: 79 EAP-Message (defined in RFC 2869, but used for EAP-TTLS, RFC 5281) */
2682 dissector_add_uint("diameter.base", 79, create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
2684 /* AVP Code: 97 Framed-IPv6-Address */
2685 dissector_add_uint("diameter.base", 97, create_dissector_handle(dissect_diameter_base_framed_ipv6_prefix, proto_diameter));
2687 /* AVP Code: 124 MIP6-Feature-Vector */
2688 dissector_add_uint("diameter.base", 124, create_dissector_handle(dissect_diameter_mip6_feature_vector, proto_diameter));
2690 /* AVP Code: 265 Supported-Vendor-Id */
2691 dissector_add_uint("diameter.base", 265, create_dissector_handle(dissect_diameter_vendor_id, proto_diameter));
2693 /* AVP Code: 266 Vendor-Id */
2694 dissector_add_uint("diameter.base", 266, create_dissector_handle(dissect_diameter_vendor_id, proto_diameter));
2696 /* AVP Code: 443 Subscription-Id */
2697 dissector_add_uint("diameter.base", 443, create_dissector_handle(dissect_diameter_subscription_id, proto_diameter));
2699 /* AVP Code: 450 Subscription-Id-Type */
2700 dissector_add_uint("diameter.base", 450, create_dissector_handle(dissect_diameter_subscription_id_type, proto_diameter));
2702 /* AVP Code: 444 Subscription-Id-Data */
2703 dissector_add_uint("diameter.base", 444, create_dissector_handle(dissect_diameter_subscription_id_data, proto_diameter));
2705 /* AVP Code: 458 User-Equipment-Info */
2706 dissector_add_uint("diameter.base", 458, create_dissector_handle(dissect_diameter_user_equipment_info, proto_diameter));
2708 /* AVP Code: 459 User-Equipment-Info-Type */
2709 dissector_add_uint("diameter.base", 459, create_dissector_handle(dissect_diameter_user_equipment_info_type, proto_diameter));
2711 /* AVP Code: 460 User-Equipment-Info-Value */
2712 dissector_add_uint("diameter.base", 460, create_dissector_handle(dissect_diameter_user_equipment_info_value, proto_diameter));
2714 /* AVP Code: 462 EAP-Payload */
2715 dissector_add_uint("diameter.base", 462, create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
2716 /* AVP Code: 463 EAP-Reissued-Payload */
2717 dissector_add_uint("diameter.base", 463, create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
2719 /* Register dissector for Experimental result code, with 3GPP2's vendor Id */
2720 dissector_add_uint("diameter.vnd_exp_res", VENDOR_THE3GPP2, create_dissector_handle(dissect_diameter_3gpp2_exp_res, proto_diameter));
2722 dissector_add_uint_range_with_preference("tcp.port", DEFAULT_DIAMETER_PORT_RANGE, diameter_tcp_handle);
2723 dissector_add_uint_range_with_preference("udp.port", "", diameter_udp_handle);
2724 dissector_add_uint_range_with_preference("sctp.port", DEFAULT_DIAMETER_PORT_RANGE, diameter_sctp_handle);
2726 exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
2732 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2734 * Local variables:
2735 * c-basic-offset: 8
2736 * tab-width: 8
2737 * indent-tabs-mode: t
2738 * End:
2740 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2741 * :indentSize=8:tabSize=8:noTabs=false: