1 /* packet-diameter.c
2  * Routines for Diameter packet disassembly
3  *
4  * Copyright (c) 2001 by David Frascone <dave@frascone.com>
5  * Copyright (c) 2007 by Luis E. Garcia Ontanon <luis@ontanon.org>
6  *
7  * Support for Request-Answer tracking and Tapping
8  * introduced by Abhik Sarkar
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * SPDX-License-Identifier: GPL-2.0-or-later
15  *
16  * References:
17  *
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
35 */
36 
37 #include "config.h"
38 
39 #include <stdio.h>
40 
41 #include <epan/packet.h>
42 #include <epan/exceptions.h>
43 #include <epan/prefs.h>
44 #include <epan/sminmpec.h>
45 #include <epan/addr_resolv.h>
46 #include <epan/expert.h>
47 #include <epan/tap.h>
48 #include <epan/srt_table.h>
49 #include <epan/exported_pdu.h>
50 #include <epan/diam_dict.h>
51 #include <epan/sctpppids.h>
52 #include <epan/show_exception.h>
53 #include <epan/to_str.h>
54 #include <epan/afn.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-e212.h"
60 #include "packet-e164.h"
61 
62 void proto_register_diameter(void);
63 void proto_reg_handoff_diameter(void);
64 
65 /* Diameter Header Flags */
66 /* RPETrrrrCCCCCCCCCCCCCCCCCCCCCCCC  */
67 #define DIAM_FLAGS_R 0x80
68 #define DIAM_FLAGS_P 0x40
69 #define DIAM_FLAGS_E 0x20
70 #define DIAM_FLAGS_T 0x10
71 #define DIAM_FLAGS_RESERVED4 0x08
72 #define DIAM_FLAGS_RESERVED5 0x04
73 #define DIAM_FLAGS_RESERVED6 0x02
74 #define DIAM_FLAGS_RESERVED7 0x01
75 #define DIAM_FLAGS_RESERVED  0x0f
76 
77 #if 0
78 #define DIAM_LENGTH_MASK  0x00ffffffl
79 #define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
80 #define DIAM_GET_FLAGS(dh)                ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
81 #define DIAM_GET_VERSION(dh)              ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
82 #define DIAM_GET_COMMAND(dh)              (dh.flagsCmdCode & DIAM_COMMAND_MASK)
83 #define DIAM_GET_LENGTH(dh)               (dh.versionLength & DIAM_LENGTH_MASK)
84 #endif
85 
86 /* Diameter AVP Flags */
87 #define AVP_FLAGS_P 0x20
88 #define AVP_FLAGS_V 0x80
89 #define AVP_FLAGS_M 0x40
90 #define AVP_FLAGS_RESERVED3 0x10
91 #define AVP_FLAGS_RESERVED4 0x08
92 #define AVP_FLAGS_RESERVED5 0x04
93 #define AVP_FLAGS_RESERVED6 0x02
94 #define AVP_FLAGS_RESERVED7 0x01
95 #define AVP_FLAGS_RESERVED 0x1f          /* 00011111  -- V M P X X X X X */
96 
97 #define DIAMETER_V16 16
98 #define DIAMETER_RFC 1
99 
100 static gint exported_pdu_tap = -1;
101 
102 /* Conversation Info */
103 typedef struct _diameter_conv_info_t {
104 	wmem_map_t *pdu_trees;
105 } diameter_conv_info_t;
106 
107 typedef struct _diam_ctx_t {
108 	proto_tree *tree;
109 	packet_info *pinfo;
110 	wmem_tree_t *avps;
111 	gboolean version_rfc;
112 } diam_ctx_t;
113 
114 typedef struct _diam_avp_t diam_avp_t;
115 typedef struct _avp_type_t avp_type_t;
116 
117 typedef const char *(*diam_avp_dissector_t)(diam_ctx_t *, diam_avp_t *, tvbuff_t *, diam_sub_dis_t *);
118 
119 
120 typedef struct _diam_vnd_t {
121 	guint32  code;
122 	wmem_array_t *vs_avps;
123 	value_string_ext *vs_avps_ext;
124 	wmem_array_t *vs_cmds;
125 } diam_vnd_t;
126 
127 struct _diam_avp_t {
128 	guint32 code;
129 	diam_vnd_t *vendor;
130 	diam_avp_dissector_t dissector_v16;
131 	diam_avp_dissector_t dissector_rfc;
132 
133 	gint ett;
134 	int hf_value;
135 	void *type_data;
136 };
137 
138 #define VND_AVP_VS(v)      ((value_string *)(void *)(wmem_array_get_raw((v)->vs_avps)))
139 #define VND_AVP_VS_LEN(v)  (wmem_array_get_count((v)->vs_avps))
140 #define VND_CMD_VS(v)      ((value_string *)(void *)(wmem_array_get_raw((v)->vs_cmds)))
141 
142 typedef struct _diam_dictionary_t {
143 	wmem_tree_t *avps;
144 	wmem_tree_t *vnds;
145 	value_string_ext *applications;
146 	value_string *commands;
147 } diam_dictionary_t;
148 
149 typedef diam_avp_t *(*avp_constructor_t)(const avp_type_t *, guint32, diam_vnd_t *, const char *,  const value_string *, void *);
150 
151 struct _avp_type_t {
152 	const char *name;
153 	diam_avp_dissector_t v16;
154 	diam_avp_dissector_t rfc;
155 	enum ftenum ft;
156 	int base;
157 	avp_constructor_t build;
158 };
159 
160 struct _build_dict {
161 	wmem_array_t *hf;
162 	GPtrArray    *ett;
163 	GHashTable   *types;
164 	GHashTable   *avps;
165 };
166 
167 
168 typedef struct _address_avp_t {
169 	gint ett;
170 	int hf_address_type;
171 	int hf_ipv4;
172 	int hf_ipv6;
173 	int hf_e164_str;
174 	int hf_other;
175 } address_avp_t;
176 
177 typedef enum {
178 	REASEMBLE_NEVER = 0,
179 	REASEMBLE_AT_END,
180 	REASEMBLE_BY_LENGTH
181 } avp_reassemble_mode_t;
182 
183 typedef struct _proto_avp_t {
184 	char *name;
185 	dissector_handle_t handle;
186 	avp_reassemble_mode_t reassemble_mode;
187 } proto_avp_t;
188 
189 static const char *simple_avp(diam_ctx_t *, diam_avp_t *, tvbuff_t *, diam_sub_dis_t *);
190 
191 static diam_vnd_t unknown_vendor = { 0xffffffff, NULL, NULL, NULL };
192 static diam_vnd_t no_vnd = { 0, NULL, NULL, NULL };
193 static diam_avp_t unknown_avp = {0, &unknown_vendor, simple_avp, simple_avp, -1, -1, NULL };
194 static GArray *all_cmds;
195 static diam_dictionary_t dictionary = { NULL, NULL, NULL, NULL };
196 static struct _build_dict build_dict;
197 static const value_string *vnd_short_vs;
198 static dissector_handle_t data_handle;
199 static dissector_handle_t eap_handle;
200 
201 static const value_string diameter_avp_data_addrfamily_vals[]= {
202 	{1,"IPv4"},
203 	{2,"IPv6"},
204 	{3,"NSAP"},
205 	{4,"HDLC"},
206 	{5,"BBN"},
207 	{6,"IEEE-802"},
208 	{7,"E-163"},
209 	{8,"E-164"},
210 	{9,"F-69"},
211 	{10,"X-121"},
212 	{11,"IPX"},
213 	{12,"Appletalk"},
214 	{13,"Decnet4"},
215 	{14,"Vines"},
216 	{15,"E-164-NSAP"},
217 	{16,"DNS"},
218 	{17,"DistinguishedName"},
219 	{18,"AS"},
220 	{19,"XTPoIPv4"},
221 	{20,"XTPoIPv6"},
222 	{21,"XTPNative"},
223 	{22,"FibrePortName"},
224 	{23,"FibreNodeName"},
225 	{24,"GWID"},
226 	{0,NULL}
227 };
228 static value_string_ext diameter_avp_data_addrfamily_vals_ext = VALUE_STRING_EXT_INIT(diameter_avp_data_addrfamily_vals);
229 
230 static int proto_diameter = -1;
231 static int hf_diameter_length = -1;
232 static int hf_diameter_code = -1;
233 static int hf_diameter_hopbyhopid =-1;
234 static int hf_diameter_endtoendid =-1;
235 static int hf_diameter_version = -1;
236 static int hf_diameter_vendor_id = -1;
237 static int hf_diameter_application_id = -1;
238 static int hf_diameter_flags = -1;
239 static int hf_diameter_flags_request = -1;
240 static int hf_diameter_flags_proxyable = -1;
241 static int hf_diameter_flags_error = -1;
242 static int hf_diameter_flags_T		= -1;
243 static int hf_diameter_flags_reserved4 = -1;
244 static int hf_diameter_flags_reserved5 = -1;
245 static int hf_diameter_flags_reserved6 = -1;
246 static int hf_diameter_flags_reserved7 = -1;
247 
248 static int hf_diameter_avp = -1;
249 static int hf_diameter_avp_len = -1;
250 static int hf_diameter_avp_code = -1;
251 static int hf_diameter_avp_flags = -1;
252 static int hf_diameter_avp_flags_vendor_specific = -1;
253 static int hf_diameter_avp_flags_mandatory = -1;
254 static int hf_diameter_avp_flags_protected = -1;
255 static int hf_diameter_avp_flags_reserved3 = -1;
256 static int hf_diameter_avp_flags_reserved4 = -1;
257 static int hf_diameter_avp_flags_reserved5 = -1;
258 static int hf_diameter_avp_flags_reserved6 = -1;
259 static int hf_diameter_avp_flags_reserved7 = -1;
260 static int hf_diameter_avp_vendor_id = -1;
261 static int hf_diameter_avp_data_wrong_length = -1;
262 static int hf_diameter_avp_pad = -1;
263 
264 static int hf_diameter_answer_in = -1;
265 static int hf_diameter_answer_to = -1;
266 static int hf_diameter_answer_time = -1;
267 
268 /* AVPs with special/extra decoding */
269 static int hf_framed_ipv6_prefix_reserved = -1;
270 static int hf_framed_ipv6_prefix_length = -1;
271 static int hf_framed_ipv6_prefix_bytes = -1;
272 static int hf_framed_ipv6_prefix_ipv6 = -1;
273 static int hf_diameter_3gpp2_exp_res = -1;
274 static int hf_diameter_other_vendor_exp_res = -1;
275 static int hf_diameter_mip6_feature_vector = -1;
276 static int hf_diameter_mip6_feature_vector_mip6_integrated = -1;
277 static int hf_diameter_mip6_feature_vector_local_home_agent_assignment = -1;
278 static int hf_diameter_mip6_feature_vector_pmip6_supported = -1;
279 static int hf_diameter_mip6_feature_vector_ip4_hoa_supported = -1;
280 static int hf_diameter_mip6_feature_vector_local_mag_routing_supported = -1;
281 static int hf_diameter_3gpp_mip6_feature_vector = -1;
282 static int hf_diameter_3gpp_mip6_feature_vector_assign_local_ip = -1;
283 static int hf_diameter_3gpp_mip6_feature_vector_mip4_supported = -1;
284 static int hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility = -1;
285 static int hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported = -1;
286 static int hf_diameter_user_equipment_info_imeisv = -1;
287 static int hf_diameter_user_equipment_info_mac = -1;
288 static int hf_diameter_user_equipment_info_eui64 = -1;
289 static int hf_diameter_user_equipment_info_modified_eui64 = -1;
290 
291 static gint ett_diameter = -1;
292 static gint ett_diameter_flags = -1;
293 static gint ett_diameter_avp_flags = -1;
294 static gint ett_diameter_avpinfo = -1;
295 static gint ett_unknown = -1;
296 static gint ett_err = -1;
297 static gint ett_diameter_mip6_feature_vector = -1;
298 static gint ett_diameter_3gpp_mip6_feature_vector = -1;
299 
300 static expert_field ei_diameter_reserved_bit_set = EI_INIT;
301 static expert_field ei_diameter_avp_len = EI_INIT;
302 static expert_field ei_diameter_avp_no_data = EI_INIT;
303 static expert_field ei_diameter_application_id = EI_INIT;
304 static expert_field ei_diameter_version = EI_INIT;
305 static expert_field ei_diameter_avp_pad = EI_INIT;
306 static expert_field ei_diameter_avp_pad_missing = EI_INIT;
307 static expert_field ei_diameter_code = EI_INIT;
308 static expert_field ei_diameter_avp_code = EI_INIT;
309 static expert_field ei_diameter_avp_vendor_id = EI_INIT;
310 static expert_field ei_diameter_invalid_ipv6_prefix_len = EI_INIT;
311 static expert_field ei_diameter_invalid_avp_len = EI_INIT;
312 static expert_field ei_diameter_invalid_user_equipment_info_value_len = EI_INIT;
313 
314 /* Tap for Diameter */
315 static int diameter_tap = -1;
316 
317 /* For conversations */
318 
319 static dissector_handle_t diameter_udp_handle;
320 static dissector_handle_t diameter_tcp_handle;
321 static dissector_handle_t diameter_sctp_handle;
322 static range_t *global_diameter_sctp_port_range;
323 /* This is used for TCP and SCTP */
324 #define DEFAULT_DIAMETER_PORT_RANGE "3868"
325 
326 /* desegmentation of Diameter over TCP */
327 static gboolean gbl_diameter_desegment = TRUE;
328 
329 /* Dissector tables */
330 static dissector_table_t diameter_dissector_table;
331 static dissector_table_t diameter_3gpp_avp_dissector_table;
332 static dissector_table_t diameter_ericsson_avp_dissector_table;
333 static dissector_table_t diameter_verizon_avp_dissector_table;
334 static dissector_table_t diameter_expr_result_vnd_table;
335 
336 static const char *avpflags_str[] = {
337 	"---",
338 	"--P",
339 	"-M-",
340 	"-MP",
341 	"V--",
342 	"V-P",
343 	"VM-",
344 	"VMP",
345 };
346 
347 #define SUBSCRIPTION_ID_TYPE_E164	0
348 #define SUBSCRIPTION_ID_TYPE_IMSI	1
349 #define SUBSCRIPTION_ID_TYPE_SIP_URI	2
350 #define SUBSCRIPTION_ID_TYPE_NAI	3
351 #define SUBSCRIPTION_ID_TYPE_PRIVATE	4
352 #define SUBSCRIPTION_ID_TYPE_UNKNOWN (guint32)-1
353 
354 #define USER_EQUIPMENT_INFO_TYPE_IMEISV			0
355 #define USER_EQUIPMENT_INFO_TYPE_MAC			1
356 #define USER_EQUIPMENT_INFO_TYPE_EUI64			2
357 #define USER_EQUIPMENT_INFO_TYPE_MODIFIED_EUI64	3
358 #define USER_EQUIPMENT_INFO_TYPE_UNKNOWN (guint32)-1
359 
360 static void
export_diameter_pdu(packet_info * pinfo,tvbuff_t * tvb)361 export_diameter_pdu(packet_info *pinfo, tvbuff_t *tvb)
362 {
363 	exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, "diameter", EXP_PDU_TAG_PROTO_NAME);
364 
365 	exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
366 	exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
367 	exp_pdu_data->pdu_tvb = tvb;
368 
369 	tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
370 
371 }
372 
373 static int
compare_avps(const void * a,const void * b)374 compare_avps(const void *a, const void *b)
375 {
376 	const value_string *vsa = (const value_string *)a;
377 	const value_string *vsb = (const value_string *)b;
378 
379 	if (vsa->value > vsb->value)
380 		return 1;
381 	if (vsa->value < vsb->value)
382 		return -1;
383 
384 	return 0;
385 }
386 
387 static GHashTable* diameterstat_cmd_str_hash = NULL;
388 #define DIAMETER_NUM_PROCEDURES     1
389 
390 static void
diameterstat_init(struct register_srt * srt _U_,GArray * srt_array)391 diameterstat_init(struct register_srt* srt _U_, GArray* srt_array)
392 {
393 	srt_stat_table *diameter_srt_table;
394 	int* idx;
395 
396     /* XXX - This is a hack/workaround support so resetting/freeing parameters at the dissector
397        level doesn't need to be supported. */
398 	if (diameterstat_cmd_str_hash != NULL)
399 	{
400 		g_hash_table_destroy(diameterstat_cmd_str_hash);
401 	}
402 
403 	idx = wmem_new0(wmem_epan_scope(), int);
404 	diameterstat_cmd_str_hash = g_hash_table_new(g_str_hash,g_str_equal);
405 	g_hash_table_insert(diameterstat_cmd_str_hash, "Unknown", idx);
406 
407 	/** @todo the filter to use in stead of NULL is "diameter.cmd.code"
408 	 * to enable the filter popup in the service response time dialogue
409 	 * Note to make it work the command code must be stored rather than the
410 	 * index.
411 	 */
412 	diameter_srt_table = init_srt_table("Diameter Requests", NULL, srt_array, DIAMETER_NUM_PROCEDURES, NULL, NULL, NULL);
413 	init_srt_table_row(diameter_srt_table, 0, "Unknown");
414 }
415 
416 static tap_packet_status
diameterstat_packet(void * pss,packet_info * pinfo,epan_dissect_t * edt _U_,const void * prv)417 diameterstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
418 {
419 	guint i = 0;
420 	srt_stat_table *diameter_srt_table;
421 	srt_data_t *data = (srt_data_t *)pss;
422 	const diameter_req_ans_pair_t *diameter=(const diameter_req_ans_pair_t *)prv;
423 	int* idx = NULL;
424 
425 	/* Process only answers where corresponding request is found.
426 	 * Unpaired diameter messages are currently not supported by statistics.
427 	 * Return 0, since redraw is not needed. */
428 	if(!diameter || diameter->processing_request || !diameter->req_frame)
429 		return TAP_PACKET_DONT_REDRAW;
430 
431 	diameter_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
432 
433 	idx = (int*) g_hash_table_lookup(diameterstat_cmd_str_hash, diameter->cmd_str);
434 	if (idx == NULL) {
435 		idx = wmem_new(wmem_epan_scope(), int);
436 		*idx = (int) g_hash_table_size(diameterstat_cmd_str_hash);
437 		g_hash_table_insert(diameterstat_cmd_str_hash, (gchar*) diameter->cmd_str, idx);
438 		init_srt_table_row(diameter_srt_table, *idx,  (const char*) diameter->cmd_str);
439 	}
440 
441 	add_srt_table_data(diameter_srt_table, *idx, &diameter->req_time, pinfo);
442 
443 	return TAP_PACKET_REDRAW;
444 }
445 
446 
447 /* Special decoding of some AVPs */
448 
449 static int
dissect_diameter_vendor_id(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,void * data _U_)450 dissect_diameter_vendor_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
451 {
452 	int offset = 0;
453 
454 	proto_tree_add_item(tree, hf_diameter_vendor_id, tvb, 0, 4, ENC_BIG_ENDIAN);
455 
456 	offset++;
457 	return offset;
458 }
459 
460 static int
dissect_diameter_eap_payload(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)461 dissect_diameter_eap_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
462 {
463 	gboolean save_writable;
464 
465 	/* Ensure the packet is displayed as Diameter, not EAP */
466 	save_writable = col_get_writable(pinfo->cinfo, COL_PROTOCOL);
467 	col_set_writable(pinfo->cinfo, COL_PROTOCOL, FALSE);
468 
469 	call_dissector(eap_handle, tvb, pinfo, tree);
470 
471 	col_set_writable(pinfo->cinfo, COL_PROTOCOL, save_writable);
472 	return tvb_reported_length(tvb);
473 }
474 
475 /* https://www.3gpp2.org/Public_html/X/VSA-VSE.cfm */
476 static const value_string diameter_3gpp2_exp_res_vals[]= {
477 	{ 5001,	"Diameter_Error_User_No_WLAN_Subscription"},
478 	{ 5002,	"Diameter_Error_Roaming_Not_Allowed(Obsoleted)"},
479 	{ 5003,	"Diameter_Error_User_No_FAP_Subscription"},
480 	{0,NULL}
481 };
482 
483 static int
dissect_diameter_3gpp2_exp_res(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,void * data)484 dissect_diameter_3gpp2_exp_res(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
485 {
486 	proto_item *pi;
487 	diam_sub_dis_t *diam_sub_dis;
488 
489 	/* Reject the packet if data is NULL */
490 	if (data == NULL)
491 		return 0;
492 	diam_sub_dis = (diam_sub_dis_t*)data;
493 
494 	if (tree) {
495 		pi = proto_tree_add_item(tree, hf_diameter_3gpp2_exp_res, tvb, 0, 4, ENC_BIG_ENDIAN);
496 		diam_sub_dis->avp_str = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
497 		proto_item_fill_label(PITEM_FINFO(pi), diam_sub_dis->avp_str);
498 		diam_sub_dis->avp_str = strstr(diam_sub_dis->avp_str,": ")+2;
499 	}
500 
501 	return 4;
502 }
503 
504 static void
dissect_diameter_other_vendor_exp_res(tvbuff_t * tvb,proto_tree * tree,diam_sub_dis_t * diam_sub_dis)505 dissect_diameter_other_vendor_exp_res(tvbuff_t *tvb, proto_tree *tree, diam_sub_dis_t *diam_sub_dis)
506 {
507 	proto_item *pi;
508 
509 	if (tree) {
510 		pi = proto_tree_add_item(tree, hf_diameter_other_vendor_exp_res, tvb, 0, 4, ENC_BIG_ENDIAN);
511 		diam_sub_dis->avp_str = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
512 		proto_item_fill_label(PITEM_FINFO(pi), diam_sub_dis->avp_str);
513 		diam_sub_dis->avp_str = strstr(diam_sub_dis->avp_str,": ")+2;
514 	}
515 }
516 
517 /* From RFC 3162 section 2.3 */
518 static int
dissect_diameter_base_framed_ipv6_prefix(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)519 dissect_diameter_base_framed_ipv6_prefix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
520 {
521 	diam_sub_dis_t *diam_sub_dis = (diam_sub_dis_t*)data;
522 	guint32 prefix_len, prefix_len_bytes;
523 	proto_item *pi;
524 
525 	proto_tree_add_item(tree, hf_framed_ipv6_prefix_reserved, tvb, 0, 1, ENC_BIG_ENDIAN);
526 	pi = proto_tree_add_item_ret_uint(tree, hf_framed_ipv6_prefix_length, tvb, 1, 1, ENC_BIG_ENDIAN, &prefix_len);
527 
528 	if (prefix_len > 128) {
529 		expert_add_info(pinfo, pi, &ei_diameter_invalid_ipv6_prefix_len);
530 	}
531 	prefix_len_bytes = prefix_len / 8;
532 	if (prefix_len % 8)
533 		prefix_len_bytes++;
534 
535 	proto_tree_add_item(tree, hf_framed_ipv6_prefix_bytes, tvb, 2, prefix_len_bytes, ENC_NA);
536 
537 	/* If we have a fully IPv6 address, display it as such */
538 	if (prefix_len_bytes == 16) {
539 		proto_tree_add_item(tree, hf_framed_ipv6_prefix_ipv6, tvb, 2, prefix_len_bytes, ENC_NA);
540 	} else if (prefix_len_bytes < 16) {
541 		ws_in6_addr value;
542 		address addr;
543 
544 		memset(&value.bytes, 0, sizeof(value));
545 		tvb_memcpy(tvb, (guint8 *)&value.bytes, 2, prefix_len_bytes);
546 		value.bytes[prefix_len_bytes] = value.bytes[prefix_len_bytes] & (0xff<<(prefix_len % 8));
547 		proto_tree_add_ipv6(tree, hf_framed_ipv6_prefix_ipv6, tvb, 2, prefix_len_bytes, &value);
548 		set_address(&addr, AT_IPv6, 16, value.bytes);
549 		diam_sub_dis->avp_str = wmem_strdup_printf(wmem_packet_scope(), "%s/%u", address_to_str(wmem_packet_scope(), &addr), prefix_len);
550 	}
551 
552 	return(prefix_len_bytes+2);
553 }
554 
555 /* AVP Code: 1 User-Name */
556 /* Do special decoding of the User-Name depending on the interface */
557 static int
dissect_diameter_user_name(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)558 dissect_diameter_user_name(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
559 {
560 	diam_sub_dis_t *diam_sub_dis = (diam_sub_dis_t*)data;
561 	guint32 application_id = 0, str_len;
562 
563 	if (diam_sub_dis) {
564 		application_id = diam_sub_dis->application_id;
565 	}
566 
567 	switch (application_id) {
568 	case DIAM_APPID_3GPP_S6A_S6D:
569 	case DIAM_APPID_3GPP_SLH:
570 	case DIAM_APPID_3GPP_S7A:
571 		str_len = tvb_reported_length(tvb);
572 		dissect_e212_utf8_imsi(tvb, pinfo, tree, 0, str_len);
573 		return str_len;
574 	}
575 
576 	return 0;
577 }
578 
579 /* AVP Code: 124 MIP6-Feature-Vector */
580 /* RFC 5447, 5779 */
581 /* 3GPP TS 29.273, V15.2.0 */
582 static int
dissect_diameter_mip6_feature_vector(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,void * data)583 dissect_diameter_mip6_feature_vector(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
584 {
585 	static int * const flags_rfc[] = {
586 		&hf_diameter_mip6_feature_vector_mip6_integrated,
587 		&hf_diameter_mip6_feature_vector_local_home_agent_assignment,
588 		&hf_diameter_mip6_feature_vector_pmip6_supported,
589 		&hf_diameter_mip6_feature_vector_ip4_hoa_supported,
590 		&hf_diameter_mip6_feature_vector_local_mag_routing_supported,
591 		NULL
592 	};
593 
594 	static int * const flags_3gpp[] = {
595 	    &hf_diameter_3gpp_mip6_feature_vector_assign_local_ip,
596 	    &hf_diameter_3gpp_mip6_feature_vector_mip4_supported,
597 	    &hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility,
598 	    &hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported,
599 	    NULL
600 	};
601 
602 	guint32 application_id = 0;
603 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
604 	DISSECTOR_ASSERT(diam_sub_dis_inf);
605 
606 	application_id = diam_sub_dis_inf->application_id;
607 
608 	/* Hide the item created in packet-diameter.c and only show the one created here */
609 	proto_item_set_hidden(diam_sub_dis_inf->item);
610 
611 	/* Dissect values defined in RFC 5447, 5779 */
612 	proto_tree_add_bitmask(tree, tvb, 0, hf_diameter_mip6_feature_vector, ett_diameter_mip6_feature_vector, flags_rfc, ENC_BIG_ENDIAN);
613 
614 	switch (application_id) {
615 	case DIAM_APPID_3GPP_STA:
616 	case DIAM_APPID_3GPP_SWM:
617 	case DIAM_APPID_3GPP_SWX:
618 	case DIAM_APPID_3GPP_S6B:
619 		/* Dissect values defined in TGPP TS 29.273, V15.2.0 */
620 		proto_tree_add_bitmask(tree, tvb, 0, hf_diameter_3gpp_mip6_feature_vector, ett_diameter_3gpp_mip6_feature_vector, flags_3gpp, ENC_BIG_ENDIAN);
621 		break;
622 	}
623 
624 	return 8;
625 }
626 
627 /* AVP Code: 443 Subscription-Id */
628 static int
dissect_diameter_subscription_id(tvbuff_t * tvb _U_,packet_info * pinfo _U_,proto_tree * tree _U_,void * data)629 dissect_diameter_subscription_id(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data)
630 {
631 	/* Just reset our global subscription-id-type variable */
632 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
633 	diam_sub_dis_inf->subscription_id_type = SUBSCRIPTION_ID_TYPE_UNKNOWN;
634 
635 	return 0;
636 }
637 
638 /* AVP Code: 450 Subscription-Id-Type */
639 static int
dissect_diameter_subscription_id_type(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree _U_,void * data)640 dissect_diameter_subscription_id_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data)
641 {
642 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
643 	diam_sub_dis_inf->subscription_id_type = tvb_get_ntohl(tvb, 0);
644 
645 	return 0;
646 }
647 
648 /* AVP Code: 444 Subscription-Id-Data */
649 static int
dissect_diameter_subscription_id_data(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)650 dissect_diameter_subscription_id_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
651 {
652 	guint32 str_len;
653 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
654 	guint32 subscription_id_type = diam_sub_dis_inf->subscription_id_type;
655 
656 	switch (subscription_id_type) {
657 	case SUBSCRIPTION_ID_TYPE_IMSI:
658 		str_len = tvb_reported_length(tvb);
659 		dissect_e212_utf8_imsi(tvb, pinfo, tree, 0, str_len);
660 		return str_len;
661 	case SUBSCRIPTION_ID_TYPE_E164:
662 		str_len = tvb_reported_length(tvb);
663 		dissect_e164_msisdn(tvb, tree, 0, str_len, E164_ENC_UTF8);
664 		return str_len;
665 	}
666 
667 	return 0;
668 }
669 
670 /* AVP Code: 458 User-Equipment-Info */
671 static int
dissect_diameter_user_equipment_info(tvbuff_t * tvb _U_,packet_info * pinfo _U_,proto_tree * tree _U_,void * data)672 dissect_diameter_user_equipment_info(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data)
673 {
674 	/* Just reset our global subscription-id-type variable */
675 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
676 	diam_sub_dis_inf->user_equipment_info_type = USER_EQUIPMENT_INFO_TYPE_UNKNOWN;
677 
678 	return 0;
679 }
680 
681 /* AVP Code: 459 User-Equipment-Info-Type */
682 /* RFC 8506 section 8.50 */
683 static int
dissect_diameter_user_equipment_info_type(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree _U_,void * data)684 dissect_diameter_user_equipment_info_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data)
685 {
686 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
687 	diam_sub_dis_inf->user_equipment_info_type = tvb_get_ntohl(tvb, 0);
688 
689 	return 0;
690 }
691 
692 /* AVP Code: 460 User-Equipment-Info-Value */
693 /* RFC 8506 section 8.51 */
694 static int
dissect_diameter_user_equipment_info_value(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)695 dissect_diameter_user_equipment_info_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
696 {
697 	guint32 len;
698 	diam_sub_dis_t *diam_sub_dis_inf = (diam_sub_dis_t*)data;
699 	guint32 user_equipment_info_type = diam_sub_dis_inf->user_equipment_info_type;
700 
701 	switch (user_equipment_info_type) {
702 	case USER_EQUIPMENT_INFO_TYPE_IMEISV:
703 		/* RFC 8506 section 8.53, 3GPP TS 23.003 */
704 		len = tvb_reported_length(tvb);
705 		/* IMEISV is 16 digits, but often transmitted BCD coded in 8 octets. */
706 		if (len == 8) {
707 			proto_tree_add_item(tree, hf_diameter_user_equipment_info_imeisv, tvb, 0, len, ENC_BCD_DIGITS_0_9|ENC_NA);
708 			return len;
709 		} else if (len == 16) {
710 			proto_tree_add_item(tree, hf_diameter_user_equipment_info_imeisv, tvb, 0, len, ENC_ASCII|ENC_NA);
711 			return len;
712 		}
713 		proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
714 		break;
715 	case USER_EQUIPMENT_INFO_TYPE_MAC:
716 		/* RFC 8506 section 8.54, RFC 5777 section 4.1.7.8 */
717 		len = tvb_reported_length(tvb);
718 		if (len == FT_ETHER_LEN) {
719 			proto_tree_add_item(tree, hf_diameter_user_equipment_info_mac, tvb, 0, len, ENC_NA);
720 			return len;
721 		}
722 		proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
723 		break;
724 	case USER_EQUIPMENT_INFO_TYPE_EUI64:
725 		/* RFC 8506 section 8.55 */
726 		len = tvb_reported_length(tvb);
727 		if (len == FT_EUI64_LEN) {
728 			proto_tree_add_item(tree, hf_diameter_user_equipment_info_eui64, tvb, 0, len, ENC_BIG_ENDIAN);
729 			return len;
730 		}
731 		proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
732 		break;
733 	case USER_EQUIPMENT_INFO_TYPE_MODIFIED_EUI64:
734 		/* RFC 8506 section 8.56, RFC 4291 */
735 		len = tvb_reported_length(tvb);
736 		if (len == FT_EUI64_LEN) {
737 			proto_tree_add_item(tree, hf_diameter_user_equipment_info_modified_eui64, tvb, 0, len,  ENC_BIG_ENDIAN);
738 			return len;
739 		}
740 		proto_tree_add_expert(tree, pinfo, &ei_diameter_invalid_user_equipment_info_value_len, tvb, 0, len);
741 		break;
742 	}
743 
744 	return 0;
745 }
746 
747 /* Call subdissectors for AVPs.
748  * This is a separate function to avoid having any local variables that might
749  * get clobbered by the exception longjmp() (without having to declare the
750  * variables as volatile and deal with casting them).
751  */
752 static void
call_avp_subdissector(guint32 vendorid,guint32 code,tvbuff_t * subtvb,packet_info * pinfo,proto_tree * avp_tree,diam_sub_dis_t * diam_sub_dis_inf)753 call_avp_subdissector(guint32 vendorid, guint32 code, tvbuff_t *subtvb, packet_info *pinfo, proto_tree *avp_tree, diam_sub_dis_t *diam_sub_dis_inf)
754 {
755 	TRY {
756 		switch (vendorid) {
757 		case 0:
758 			dissector_try_uint_new(diameter_dissector_table, code, subtvb, pinfo, avp_tree, FALSE, diam_sub_dis_inf);
759 			break;
760 		case VENDOR_ERICSSON:
761 			dissector_try_uint_new(diameter_ericsson_avp_dissector_table, code, subtvb, pinfo, avp_tree, FALSE, diam_sub_dis_inf);
762 			break;
763 		case VENDOR_VERIZON:
764 			dissector_try_uint_new(diameter_verizon_avp_dissector_table, code, subtvb, pinfo, avp_tree, FALSE, diam_sub_dis_inf);
765 			break;
766 		case VENDOR_THE3GPP:
767 			dissector_try_uint_new(diameter_3gpp_avp_dissector_table, code, subtvb, pinfo, avp_tree, FALSE, diam_sub_dis_inf);
768 			break;
769 		default:
770 			break;
771 		}
772 
773 		/* Debug
774 		proto_tree_add_subtree(avp_tree, subtvb, 0, -1, "AVP %u data, Vendor Id %u ",code,vendorid);
775 		*/
776 	}
777 	CATCH_NONFATAL_ERRORS {
778 		show_exception(subtvb, pinfo, avp_tree, EXCEPT_CODE, GET_MESSAGE);
779 	}
780 	ENDTRY;
781 }
782 
783 /* Dissect an AVP at offset */
784 static int
dissect_diameter_avp(diam_ctx_t * c,tvbuff_t * tvb,int offset,diam_sub_dis_t * diam_sub_dis_inf,gboolean update_col_info)785 dissect_diameter_avp(diam_ctx_t *c, tvbuff_t *tvb, int offset, diam_sub_dis_t *diam_sub_dis_inf, gboolean update_col_info)
786 {
787 	guint32 code           = tvb_get_ntohl(tvb,offset);
788 	guint32 len            = tvb_get_ntohl(tvb,offset+4);
789 	guint32 vendor_flag    = len & 0x80000000;
790 	guint32 flags_bits_idx = (len & 0xE0000000) >> 29;
791 	guint32 flags_bits     = (len & 0xFF000000) >> 24;
792 	guint32 vendorid       = vendor_flag ? tvb_get_ntohl(tvb,offset+8) : 0 ;
793 	wmem_tree_key_t k[3];
794 	diam_avp_t *a;
795 	proto_item *pi, *avp_item;
796 	proto_tree *avp_tree, *save_tree;
797 	tvbuff_t *subtvb;
798 	diam_vnd_t *vendor;
799 	const char *code_str;
800 	const char *avp_str = NULL;
801 	guint8 pad_len;
802 
803 	k[0].length = 1;
804 	k[0].key = &code;
805 
806 	k[1].length = 1;
807 	k[1].key = &vendorid;
808 
809 	k[2].length = 0;
810 	k[2].key = NULL;
811 
812 	a = (diam_avp_t *)wmem_tree_lookup32_array(dictionary.avps,k);
813 
814 	len &= 0x00ffffff;
815 	pad_len =  (len % 4) ? 4 - (len % 4) : 0 ;
816 
817 	if (!a) {
818 		a = &unknown_avp;
819 
820 		if (vendor_flag) {
821 			if (! (vendor = (diam_vnd_t *)wmem_tree_lookup32(dictionary.vnds,vendorid) ))
822 				vendor = &unknown_vendor;
823 		} else {
824 			vendor = &no_vnd;
825 		}
826 	} else {
827 		vendor = (diam_vnd_t *)a->vendor;
828 	}
829 
830 	if (vendor->vs_avps_ext == NULL) {
831 		wmem_array_sort(vendor->vs_avps, compare_avps);
832 		vendor->vs_avps_ext = value_string_ext_new(VND_AVP_VS(vendor),
833 							   VND_AVP_VS_LEN(vendor)+1,
834 							   wmem_strdup_printf(wmem_epan_scope(), "diameter_vendor_%s",
835 									   enterprises_lookup(vendorid, "Unknown")));
836 #if 0
837 		{ /* Debug code */
838 			value_string *vendor_avp_vs = VALUE_STRING_EXT_VS_P(vendor->vs_avps_ext);
839 			gint i = 0;
840 			while (vendor_avp_vs[i].strptr != NULL) {
841 				ws_warning("%u %s", vendor_avp_vs[i].value, vendor_avp_vs[i].strptr);
842 				i++;
843 			}
844 		}
845 #endif
846 	}
847 	/* Check if the length is sane */
848 	if (len > (guint32)tvb_reported_length_remaining(tvb, offset)) {
849 		proto_tree_add_expert_format(c->tree, c->pinfo, &ei_diameter_invalid_avp_len, tvb, offset + 4, 4,
850 			"Wrong AVP(%u) length %u",
851 			code,
852 			len);
853 		return tvb_reported_length(tvb);
854 	}
855 
856 	/*
857 	 * Workaround for a MS-CHAPv2 capture from Bug 15603 that lacks padding.
858 	 */
859 	if (tvb_reported_length_remaining(tvb, offset + len) < pad_len) {
860 		pad_len = (guint32)tvb_reported_length_remaining(tvb, offset + len);
861 	}
862 
863 	/* Add root of tree for this AVP */
864 	avp_item = proto_tree_add_item(c->tree, hf_diameter_avp, tvb, offset, len + pad_len, ENC_NA);
865 	avp_tree = proto_item_add_subtree(avp_item, a->ett);
866 
867 	pi = proto_tree_add_item(avp_tree,hf_diameter_avp_code,tvb,offset,4,ENC_BIG_ENDIAN);
868 	code_str = val_to_str_ext_const(code, vendor->vs_avps_ext, "Unknown");
869 	proto_item_append_text(pi," %s", code_str);
870 
871 	/* Code */
872 	if (a == &unknown_avp) {
873 		proto_tree *tu = proto_item_add_subtree(pi,ett_unknown);
874 		proto_tree_add_expert_format(tu, c->pinfo, &ei_diameter_avp_code, tvb, offset, 4,
875 			"Unknown AVP %u (vendor=%s), if you know what this is you can add it to dictionary.xml", code,
876 			enterprises_lookup(vendorid, "Unknown"));
877 	}
878 
879 	offset += 4;
880 
881 	proto_item_set_text(avp_item,"AVP: %s(%u) l=%u f=%s", code_str, code, len, avpflags_str[flags_bits_idx]);
882 	if (update_col_info) {
883 		col_append_fstr(c->pinfo->cinfo, COL_INFO, " %s", code_str);
884 	}
885 
886 	/* Flags */
887 	{
888 		static int * const diameter_avp_flags[] = {
889 			&hf_diameter_avp_flags_vendor_specific,
890 			&hf_diameter_avp_flags_mandatory,
891 			&hf_diameter_avp_flags_protected,
892 			&hf_diameter_avp_flags_reserved3,
893 			&hf_diameter_avp_flags_reserved4,
894 			&hf_diameter_avp_flags_reserved5,
895 			&hf_diameter_avp_flags_reserved6,
896 			&hf_diameter_avp_flags_reserved7,
897 			NULL
898 		};
899 
900 		pi = proto_tree_add_bitmask_with_flags(avp_tree, tvb, offset, hf_diameter_avp_flags,
901 			ett_diameter_avp_flags, diameter_avp_flags, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_INT);
902 		if (flags_bits & 0x1f) expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
903 
904 	}
905 	offset += 1;
906 
907 	/* Length */
908 	proto_tree_add_item(avp_tree,hf_diameter_avp_len,tvb,offset,3,ENC_BIG_ENDIAN);
909 	offset += 3;
910 
911 	/* Vendor flag */
912 	if (vendor_flag) {
913 		proto_item_append_text(avp_item," vnd=%s", val_to_str(vendorid, vnd_short_vs, "%d"));
914 		pi = proto_tree_add_item(avp_tree,hf_diameter_avp_vendor_id,tvb,offset,4,ENC_BIG_ENDIAN);
915 		if (vendor == &unknown_vendor) {
916 			proto_tree *tu = proto_item_add_subtree(pi,ett_unknown);
917 			proto_tree_add_expert(tu, c->pinfo, &ei_diameter_avp_vendor_id, tvb, offset, 4);
918 		}
919 		offset += 4;
920 	}
921 
922 	if ( len == (guint32)(vendor_flag ? 12 : 8) ) {
923 		/* Data is empty so return now */
924 		proto_tree_add_expert(avp_tree, c->pinfo, &ei_diameter_avp_no_data, tvb, offset, 0);
925 		/* pad_len is always 0 in this case, but kept here for consistency */
926 		return len+pad_len;
927 	}
928 	/* If we are dissecting a grouped AVP and find a Vendor Id AVP(266), save it */
929 	if ((diam_sub_dis_inf->dis_gouped) && (!vendor_flag) && (code==266)) {
930 		diam_sub_dis_inf->vendor_id = tvb_get_ntohl(tvb,offset);
931 	}
932 
933 	subtvb = tvb_new_subset_length(tvb,offset,len-(8+(vendor_flag?4:0)));
934 	offset += len-(8+(vendor_flag?4:0));
935 
936 	save_tree = c->tree;
937 	c->tree = avp_tree;
938 
939 	/* The Experimental-Result-Code AVP (298) comes inside the Experimental-Result
940 	 * grouped AVP (297).  The Vendor-ID AVP in the Experimental-Result specifies the
941 	 * name space of the Experimental-Result-Code.  Unfortunately we don't have a way
942 	 * to specify, in XML, different Experimental-Result-Code enum values for different
943 	 * Vendor-IDs so we choose a Vendor-ID whose values get to go in XML (we chose
944 	 * 3GPP) and handle other Vendor-IDs through the "diameter.vnd_exp_res" dissector
945 	 * table.
946 	 */
947 	if ((diam_sub_dis_inf->dis_gouped)
948 		&& (!vendor_flag)
949 		&& (code==298)
950 		&& (diam_sub_dis_inf->vendor_id != 0)
951 		&& (diam_sub_dis_inf->vendor_id != VENDOR_THE3GPP))
952 	{
953 		/* call subdissector */
954 		if (!dissector_try_uint_new(diameter_expr_result_vnd_table, diam_sub_dis_inf->vendor_id,
955 					    subtvb, c->pinfo, avp_tree, FALSE, diam_sub_dis_inf)) {
956 			/* No subdissector for this vendor ID, use the generic one */
957 			dissect_diameter_other_vendor_exp_res(subtvb, avp_tree, diam_sub_dis_inf);
958 		}
959 
960 		if (diam_sub_dis_inf->avp_str) {
961 			proto_item_append_text(avp_item," val=%s", diam_sub_dis_inf->avp_str);
962 		}
963 	} else if (c->version_rfc) {
964 		avp_str = a->dissector_rfc(c,a,subtvb, diam_sub_dis_inf);
965 	} else {
966 		avp_str = a->dissector_v16(c,a,subtvb, diam_sub_dis_inf);
967 	}
968 	c->tree = save_tree;
969 
970 	diam_sub_dis_inf->avp_str = NULL;
971 	call_avp_subdissector(vendorid, code, subtvb, c->pinfo, avp_tree, diam_sub_dis_inf);
972 
973 	/* Let the subdissector have precedence filling in the avp_item string */
974 	if (diam_sub_dis_inf->avp_str) {
975 		proto_item_append_text(avp_item," val=%s", diam_sub_dis_inf->avp_str);
976 	} else if (avp_str) {
977 		proto_item_append_text(avp_item," val=%s", avp_str);
978 	}
979 
980 
981 	if (pad_len) {
982 		guint8 i;
983 
984 		pi = proto_tree_add_item(avp_tree, hf_diameter_avp_pad, tvb, offset, pad_len, ENC_NA);
985 		for (i=0; i < pad_len; i++) {
986 			if (tvb_get_guint8(tvb, offset++) != 0) {
987 				expert_add_info(c->pinfo, pi, &ei_diameter_avp_pad);
988 				break;
989 			}
990 		}
991 	}
992 	if ((len + pad_len) % 4) {
993 		proto_tree_add_expert(avp_tree, c->pinfo, &ei_diameter_avp_pad_missing, tvb, offset, pad_len);
994 	}
995 
996 	return len+pad_len;
997 }
998 
999 static const char *
address_rfc_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1000 address_rfc_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1001 {
1002 	char *label = NULL;
1003 	address_avp_t *t = (address_avp_t *)a->type_data;
1004 	gint len = tvb_reported_length(tvb);
1005 	proto_item *pi = proto_tree_add_item(c->tree, a->hf_value, tvb, 0, len, ENC_BIG_ENDIAN);
1006 	proto_tree *pt = proto_item_add_subtree(pi,t->ett);
1007 	guint32 addr_type;
1008 	len = len-2;
1009 
1010 	proto_tree_add_item_ret_uint(pt, t->hf_address_type, tvb, 0, 2, ENC_NA, &addr_type);
1011 	/* See afn.h and https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml */
1012 	switch (addr_type ) {
1013 		case AFNUM_INET:
1014 			if (len != 4) {
1015 				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);
1016 				return "[Malformed]";
1017 			}
1018 			pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,2,4,ENC_BIG_ENDIAN);
1019 			break;
1020 		case AFNUM_INET6:
1021 			if (len != 16) {
1022 				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);
1023 				return "[Malformed]";
1024 			}
1025 			pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,2,16,ENC_NA);
1026 			break;
1027 		case AFNUM_E164:
1028 			/* It's unclear what format the e164 address would be encoded in but AVP 3GPP 2008 has
1029 			 * ...value 8, E.164, and the address information is UTF8 encoded.
1030 			 */
1031 			if (tvb_ascii_isprint(tvb, 2, len)) {
1032 				pi = proto_tree_add_item(pt, t->hf_e164_str, tvb, 2, len, ENC_ASCII | ENC_NA);
1033 			} else {
1034 				pi = proto_tree_add_item(pt, t->hf_other, tvb, 2, -1, ENC_BIG_ENDIAN);
1035 			}
1036 			break;
1037 		default:
1038 			pi = proto_tree_add_item(pt,t->hf_other,tvb,2,-1,ENC_BIG_ENDIAN);
1039 			break;
1040 	}
1041 
1042 	if (c->tree) {
1043 		label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1044 		proto_item_fill_label(PITEM_FINFO(pi), label);
1045 		label = strstr(label,": ")+2;
1046 	}
1047 
1048 	return label;
1049 }
1050 
1051 static const char *
proto_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf)1052 proto_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf)
1053 {
1054 	proto_avp_t *t = (proto_avp_t *)a->type_data;
1055 
1056 	col_set_writable(c->pinfo->cinfo, COL_PROTOCOL, FALSE);
1057 	col_set_writable(c->pinfo->cinfo, COL_INFO, FALSE);
1058 
1059 	if (!t->handle) {
1060 		t->handle = find_dissector(t->name);
1061 		if (!t->handle) t->handle = data_handle;
1062 	}
1063 
1064 	TRY {
1065 		call_dissector_with_data(t->handle, tvb, c->pinfo, c->tree, diam_sub_dis_inf);
1066 	}
1067 	CATCH_NONFATAL_ERRORS {
1068 		show_exception(tvb, c->pinfo, c->tree, EXCEPT_CODE, GET_MESSAGE);
1069 	}
1070 	ENDTRY;
1071 
1072 	return "";
1073 }
1074 
1075 static const char *
time_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1076 time_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1077 {
1078 	int len = tvb_reported_length(tvb);
1079 	char *label = NULL;
1080 	proto_item *pi;
1081 
1082 	if ( len != 4 ) {
1083 		proto_tree_add_expert_format(c->tree, c->pinfo, &ei_diameter_avp_len, tvb, 0, 4,
1084 				"Bad Timestamp Length: %d instead of 4", len);
1085 		return "[Malformed]";
1086 	}
1087 
1088 	if (c->tree) {
1089 		label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1090 		pi = proto_tree_add_item(c->tree, (a->hf_value), tvb, 0, 4, ENC_TIME_SECS_NTP|ENC_BIG_ENDIAN);
1091 		proto_item_fill_label(PITEM_FINFO(pi), label);
1092 		label = strstr(label,": ")+2;
1093 	}
1094 
1095 	return label;
1096 }
1097 
1098 static const char *
address_v16_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1099 address_v16_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1100 {
1101 	char *label = NULL;
1102 
1103 	address_avp_t *t = (address_avp_t *)a->type_data;
1104 	proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_reported_length(tvb),ENC_BIG_ENDIAN);
1105 	proto_tree *pt = proto_item_add_subtree(pi,t->ett);
1106 	guint32 len = tvb_reported_length(tvb);
1107 
1108 	switch (len) {
1109 		case 4:
1110 			pi = proto_tree_add_item(pt,t->hf_ipv4,tvb,0,4,ENC_BIG_ENDIAN);
1111 			break;
1112 		case 16:
1113 			pi = proto_tree_add_item(pt,t->hf_ipv6,tvb,0,16,ENC_NA);
1114 			break;
1115 		default:
1116 			pi = proto_tree_add_item(pt,t->hf_other,tvb,0,len,ENC_BIG_ENDIAN);
1117 			expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1118 					"Bad Address Length (%u)", len);
1119 
1120 			break;
1121 	}
1122 
1123 	if (c->tree) {
1124 		label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1125 		proto_item_fill_label(PITEM_FINFO(pi), label);
1126 		label = strstr(label,": ")+2;
1127 	}
1128 
1129 	return label;
1130 }
1131 
1132 static const char *
simple_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1133 simple_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1134 {
1135 	char *label = NULL;
1136 
1137 	if (c->tree) {
1138 		proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_reported_length(tvb),ENC_BIG_ENDIAN);
1139 		label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1140 		proto_item_fill_label(PITEM_FINFO(pi), label);
1141 		label = strstr(label,": ")+2;
1142 	}
1143 
1144 	return label;
1145 }
1146 
1147 static const char *
utf8_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1148 utf8_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1149 {
1150 	char *label = NULL;
1151 
1152 	if (c->tree) {
1153 		proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_reported_length(tvb),ENC_UTF_8|ENC_BIG_ENDIAN);
1154 		label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1155 		proto_item_fill_label(PITEM_FINFO(pi), label);
1156 		label = strstr(label,": ")+2;
1157 	}
1158 
1159 	return label;
1160 }
1161 
1162 static const char *
integer32_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1163 integer32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1164 {
1165 	char *label = NULL;
1166 	proto_item *pi;
1167 
1168 	/* Verify length before adding */
1169 	gint length = tvb_reported_length(tvb);
1170 	if (length == 4) {
1171 		if (c->tree) {
1172 			pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1173 			label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1174 			proto_item_fill_label(PITEM_FINFO(pi), label);
1175 			label = strstr(label,": ")+2;
1176 		}
1177 	}
1178 	else {
1179 		pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1180 						 tvb, 0, length, NULL,
1181 						"Error!  Bad Integer32 Length");
1182 		expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1183 					"Bad Integer32 Length (%u)", length);
1184 		proto_item_set_generated(pi);
1185 	}
1186 
1187 	return label;
1188 }
1189 
1190 static const char *
integer64_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1191 integer64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1192 {
1193 	char *label = NULL;
1194 	proto_item *pi;
1195 
1196 	/* Verify length before adding */
1197 	gint length = tvb_reported_length(tvb);
1198 	if (length == 8) {
1199 		if (c->tree) {
1200 			pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1201 			label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1202 			proto_item_fill_label(PITEM_FINFO(pi), label);
1203 			label = strstr(label,": ")+2;
1204 		}
1205 	}
1206 	else {
1207 		pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1208 						 tvb, 0, length, NULL,
1209 						"Error!  Bad Integer64 Length");
1210 		expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1211 				"Bad Integer64 Length (%u)", length);
1212 		proto_item_set_generated(pi);
1213 	}
1214 
1215 	return label;
1216 }
1217 
1218 static const char *
unsigned32_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf)1219 unsigned32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf)
1220 {
1221 	char *label = NULL;
1222 	proto_item *pi;
1223 
1224 	/* Verify length before adding */
1225 	gint length = tvb_reported_length(tvb);
1226 	if (length == 4) {
1227 		if (c->tree) {
1228 			diam_sub_dis_inf->item = pi = proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1229 			label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1230 			proto_item_fill_label(PITEM_FINFO(pi), label);
1231 			label = strstr(label,": ")+2;
1232 		}
1233 	}
1234 	else {
1235 		pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1236 						 tvb, 0, length, NULL,
1237 						"Error!  Bad Unsigned32 Length");
1238 		expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1239 					"Bad Unsigned32 Length (%u)", length);
1240 		proto_item_set_generated(pi);
1241 	}
1242 
1243 	return label;
1244 }
1245 
1246 static const char *
unsigned64_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1247 unsigned64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1248 {
1249 	char *label = NULL;
1250 	proto_item *pi;
1251 
1252 	/* Verify length before adding */
1253 	gint length = tvb_reported_length(tvb);
1254 	if (length == 8) {
1255 		if (c->tree) {
1256 			pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1257 			label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1258 			proto_item_fill_label(PITEM_FINFO(pi), label);
1259 			label = strstr(label,": ")+2;
1260 		}
1261 	}
1262 	else {
1263 		pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1264 						 tvb, 0, length, NULL,
1265 						"Error!  Bad Unsigned64 Length");
1266 		expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1267 				"Bad Unsigned64 Length (%u)", length);
1268 		proto_item_set_generated(pi);
1269 	}
1270 
1271 	return label;
1272 }
1273 
1274 static const char *
float32_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1275 float32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1276 {
1277 	char *label = NULL;
1278 	proto_item *pi;
1279 
1280 	/* Verify length before adding */
1281 	gint length = tvb_reported_length(tvb);
1282 	if (length == 4) {
1283 		if (c->tree) {
1284 			pi= proto_tree_add_item(c->tree,a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1285 			label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1286 			proto_item_fill_label(PITEM_FINFO(pi), label);
1287 			label = strstr(label,": ")+2;
1288 		}
1289 	}
1290 	else {
1291 		pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1292 						 tvb, 0, length, NULL,
1293 						"Error!  Bad Float32 Length");
1294 		expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1295 				"Bad Float32 Length (%u)", length);
1296 		proto_item_set_generated(pi);
1297 	}
1298 
1299 	return label;
1300 }
1301 
1302 static const char *
float64_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf _U_)1303 float64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf _U_)
1304 {
1305 	char *label = NULL;
1306 	proto_item *pi;
1307 
1308 	/* Verify length before adding */
1309 	gint length = tvb_reported_length(tvb);
1310 	if (length == 8) {
1311 		if (c->tree) {
1312 			pi= proto_tree_add_item(c->tree, a->hf_value, tvb, 0, length, ENC_BIG_ENDIAN);
1313 			label = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1);
1314 			proto_item_fill_label(PITEM_FINFO(pi), label);
1315 			label = strstr(label,": ")+2;
1316 		}
1317 	}
1318 	else {
1319 		pi = proto_tree_add_bytes_format(c->tree, hf_diameter_avp_data_wrong_length,
1320 						 tvb, 0, length, NULL,
1321 						"Error!  Bad Float64 Length");
1322 		expert_add_info_format(c->pinfo, pi, &ei_diameter_avp_len,
1323 				"Bad Float64 Length (%u)", length);
1324 		proto_item_set_generated(pi);
1325 	}
1326 
1327 	return label;
1328 }
1329 
1330 static const char *
grouped_avp(diam_ctx_t * c,diam_avp_t * a,tvbuff_t * tvb,diam_sub_dis_t * diam_sub_dis_inf)1331 grouped_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb, diam_sub_dis_t *diam_sub_dis_inf)
1332 {
1333 	int offset = 0;
1334 	int len = tvb_reported_length(tvb);
1335 	proto_item *pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, ENC_BIG_ENDIAN);
1336 	proto_tree *pt = c->tree;
1337 
1338 	c->tree = proto_item_add_subtree(pi,a->ett);
1339 
1340 	/* Set the flag that we are dissecting a grouped AVP */
1341 	diam_sub_dis_inf->dis_gouped = TRUE;
1342 	while (offset < len) {
1343 		offset += dissect_diameter_avp(c, tvb, offset, diam_sub_dis_inf, FALSE);
1344 	}
1345 	/* Clear info collected in grouped AVP */
1346 	diam_sub_dis_inf->vendor_id  = 0;
1347 	diam_sub_dis_inf->dis_gouped = FALSE;
1348 	diam_sub_dis_inf->avp_str = NULL;
1349 
1350 	c->tree = pt;
1351 
1352 	return NULL;
1353 }
1354 
1355 static const char *msgflags_str[] = {
1356 	"----", "---T", "--E-", "--ET",
1357 	"-P--", "-P-T", "-PE-", "-PET",
1358 	"R---", "R--T", "R-E-", "R-ET",
1359 	"RP--", "RP-T", "RPE-", "RPET"
1360 };
1361 
1362 static int * const diameter_flags_fields[] = {
1363 	&hf_diameter_flags_request,
1364 	&hf_diameter_flags_proxyable,
1365 	&hf_diameter_flags_error,
1366 	&hf_diameter_flags_T,
1367 	&hf_diameter_flags_reserved4,
1368 	&hf_diameter_flags_reserved5,
1369 	&hf_diameter_flags_reserved6,
1370 	&hf_diameter_flags_reserved7,
1371 	NULL
1372 };
1373 
1374 static int
dissect_diameter_common(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1375 dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1376 {
1377 	guint32 version;
1378 	guint64 flags_bits;
1379 	int packet_len;
1380 	proto_item *pi, *cmd_item, *app_item, *version_item;
1381 	proto_tree *diam_tree;
1382 	diam_ctx_t *c = wmem_new0(wmem_packet_scope(), diam_ctx_t);
1383 	int offset;
1384 	value_string *cmd_vs;
1385 	const char *cmd_str;
1386 	guint32 cmd;
1387 	guint32 hop_by_hop_id, end_to_end_id;
1388 	conversation_t *conversation;
1389 	diameter_conv_info_t *diameter_conv_info;
1390 	diameter_req_ans_pair_t *diameter_pair = NULL;
1391 	wmem_tree_t *pdus_tree;
1392 	proto_item *it;
1393 	nstime_t ns;
1394 	diam_sub_dis_t *diam_sub_dis_inf = wmem_new0(wmem_packet_scope(), diam_sub_dis_t);
1395 
1396 	/* Set default value Subscription-Id-Type and User-Equipment-Info-Type as XXX_UNKNOWN */
1397 	diam_sub_dis_inf->subscription_id_type = SUBSCRIPTION_ID_TYPE_UNKNOWN;
1398 	diam_sub_dis_inf->user_equipment_info_type = USER_EQUIPMENT_INFO_TYPE_UNKNOWN;
1399 
1400 	/* Load header fields if not already done */
1401 	if (hf_diameter_code == -1)
1402 		proto_registrar_get_byname("diameter.code");
1403 
1404 	col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1405 
1406 	if (have_tap_listener(exported_pdu_tap)){
1407 		export_diameter_pdu(pinfo,tvb);
1408 	}
1409 
1410 	pi = proto_tree_add_item(tree,proto_diameter,tvb,0,-1,ENC_NA);
1411 	diam_tree = proto_item_add_subtree(pi,ett_diameter);
1412 
1413 	c->tree = diam_tree;
1414 	c->pinfo = pinfo;
1415 
1416 	version_item = proto_tree_add_item_ret_uint(diam_tree, hf_diameter_version, tvb, 0, 1, ENC_BIG_ENDIAN, &version);
1417 	proto_tree_add_item_ret_uint(diam_tree, hf_diameter_length, tvb, 1, 3, ENC_BIG_ENDIAN, &packet_len);
1418 
1419 	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);
1420 	if (flags_bits & 0x0f) {
1421 		expert_add_info(c->pinfo, pi, &ei_diameter_reserved_bit_set);
1422 	}
1423 
1424 	cmd_item = proto_tree_add_item_ret_uint(diam_tree, hf_diameter_code, tvb, 5, 3, ENC_BIG_ENDIAN, &cmd);
1425 	diam_sub_dis_inf->cmd_code = cmd;
1426 
1427 
1428 	switch (version) {
1429 		case DIAMETER_V16: {
1430 			guint32 vendorid;
1431 			diam_vnd_t *vendor;
1432 
1433 			proto_tree_add_item_ret_uint(diam_tree, hf_diameter_vendor_id, tvb, 8, 4, ENC_BIG_ENDIAN, &vendorid);
1434 			diam_sub_dis_inf->application_id = vendorid;
1435 			if (! ( vendor = (diam_vnd_t *)wmem_tree_lookup32(dictionary.vnds,vendorid) ) ) {
1436 				vendor = &unknown_vendor;
1437 			}
1438 
1439 			cmd_vs = VND_CMD_VS(vendor);
1440 
1441 			c->version_rfc = FALSE;
1442 			break;
1443 		}
1444 		case DIAMETER_RFC: {
1445 
1446 			cmd_vs = (value_string *)(void *)all_cmds->data;
1447 
1448 			app_item = proto_tree_add_item_ret_uint(diam_tree, hf_diameter_application_id, tvb, 8, 4,
1449 				ENC_BIG_ENDIAN, &diam_sub_dis_inf->application_id);
1450 
1451 			if (try_val_to_str_ext(diam_sub_dis_inf->application_id, dictionary.applications) == NULL) {
1452 				proto_tree *tu = proto_item_add_subtree(app_item,ett_unknown);
1453 				proto_tree_add_expert_format(tu, c->pinfo, &ei_diameter_application_id, tvb, 8, 4,
1454 					"Unknown Application Id (%u), if you know what this is you can add it to dictionary.xml", diam_sub_dis_inf->application_id);
1455 			}
1456 
1457 			c->version_rfc = TRUE;
1458 			break;
1459 		}
1460 		default:
1461 		{
1462 			proto_tree *pt = proto_item_add_subtree(version_item,ett_err);
1463 			proto_tree_add_expert(pt, pinfo, &ei_diameter_version, tvb, 0, 1);
1464 			c->version_rfc = TRUE;
1465 			cmd_vs = VND_CMD_VS(&no_vnd);
1466 			break;
1467 		}
1468 	}
1469 	cmd_str = val_to_str_const(cmd, cmd_vs, "Unknown");
1470 
1471 	/* Append name to command item, warn if unknown */
1472 	proto_item_append_text(cmd_item," %s", cmd_str);
1473 	if (strcmp(cmd_str, "Unknown") == 0) {
1474 		proto_tree *tu = proto_item_add_subtree(cmd_item,ett_unknown);
1475 		proto_tree_add_expert(tu, c->pinfo, &ei_diameter_code, tvb, 5, 3);
1476 	}
1477 
1478 
1479 	proto_tree_add_item_ret_uint(diam_tree, hf_diameter_hopbyhopid, tvb, 12, 4, ENC_BIG_ENDIAN, &hop_by_hop_id);
1480 	proto_tree_add_item_ret_uint(diam_tree, hf_diameter_endtoendid, tvb, 16, 4, ENC_BIG_ENDIAN, &end_to_end_id);
1481 
1482 	col_add_fstr(pinfo->cinfo, COL_INFO,
1483 			 "cmd=%s%s(%d) flags=%s %s=%s(%d) h2h=%x e2e=%x",
1484 			 cmd_str,
1485 			 ((flags_bits>>4)&0x08) ? " Request" : " Answer",
1486 			 cmd,
1487 			 msgflags_str[((flags_bits>>4)&0x0f)],
1488 			 c->version_rfc ? "appl" : "vend",
1489 			 c->version_rfc ? val_to_str_ext_const(diam_sub_dis_inf->application_id, dictionary.applications, "Unknown") :
1490 					  val_to_str_const(diam_sub_dis_inf->application_id, vnd_short_vs, "Unknown"),
1491 			 diam_sub_dis_inf->application_id,
1492 			 hop_by_hop_id,
1493 			 end_to_end_id);
1494 
1495 	col_append_str(pinfo->cinfo, COL_INFO, " | ");
1496 	col_set_fence(pinfo->cinfo, COL_INFO);
1497 
1498 
1499 	/* Conversation tracking stuff */
1500 	/*
1501 	 * FIXME: Looking at epan/conversation.c it seems unlikely that this will work properly in
1502 	 * multi-homed SCTP connections. This will probably need to be fixed at some point.
1503 	 */
1504 
1505 	conversation = find_or_create_conversation(pinfo);
1506 
1507 	diameter_conv_info = (diameter_conv_info_t *)conversation_get_proto_data(conversation, proto_diameter);
1508 	if (!diameter_conv_info) {
1509 		diameter_conv_info = wmem_new(wmem_file_scope(), diameter_conv_info_t);
1510 		diameter_conv_info->pdu_trees = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
1511 
1512 		conversation_add_proto_data(conversation, proto_diameter, diameter_conv_info);
1513 	}
1514 
1515 	/* pdus_tree is an wmem_tree keyed by frame number (in order to handle hop-by-hop collisions */
1516 	pdus_tree = (wmem_tree_t *)wmem_map_lookup(diameter_conv_info->pdu_trees, GUINT_TO_POINTER(hop_by_hop_id));
1517 
1518 	if (pdus_tree == NULL && (flags_bits & DIAM_FLAGS_R)) {
1519 		/* This is the first request we've seen with this hop-by-hop id */
1520 		pdus_tree = wmem_tree_new(wmem_file_scope());
1521 		wmem_map_insert(diameter_conv_info->pdu_trees, GUINT_TO_POINTER(hop_by_hop_id), pdus_tree);
1522 	}
1523 
1524 	if (pdus_tree) {
1525 		if (!pinfo->fd->visited) {
1526 			if (flags_bits & DIAM_FLAGS_R) {
1527 				/* This is a request */
1528 				diameter_pair = wmem_new(wmem_file_scope(), diameter_req_ans_pair_t);
1529 				diameter_pair->hop_by_hop_id = hop_by_hop_id;
1530 				diameter_pair->end_to_end_id = end_to_end_id;
1531 				diameter_pair->cmd_code = cmd;
1532 				diameter_pair->result_code = 0;
1533 				diameter_pair->cmd_str = cmd_str;
1534 				diameter_pair->req_frame = pinfo->num;
1535 				diameter_pair->ans_frame = 0;
1536 				diameter_pair->req_time = pinfo->abs_ts;
1537 				wmem_tree_insert32(pdus_tree, pinfo->num, (void *)diameter_pair);
1538 			} else {
1539 				/* Look for a request which occurs earlier in the trace than this answer. */
1540 				diameter_pair = (diameter_req_ans_pair_t *)wmem_tree_lookup32_le(pdus_tree, pinfo->num);
1541 
1542 				/* Verify the end-to-end-id matches before declaring a match */
1543 				if (diameter_pair && diameter_pair->end_to_end_id == end_to_end_id) {
1544 					diameter_pair->ans_frame = pinfo->num;
1545 				}
1546 			}
1547 		} else {
1548 			/* Look for a request which occurs earlier in the trace than this answer. */
1549 			diameter_pair = (diameter_req_ans_pair_t *)wmem_tree_lookup32_le(pdus_tree, pinfo->num);
1550 
1551 			/* If the end-to-end ID doesn't match then this is not the request we were
1552 			 * looking for.
1553 			 */
1554 			if (diameter_pair && diameter_pair->end_to_end_id != end_to_end_id)
1555 				diameter_pair = NULL;
1556 		}
1557 	}
1558 
1559 	if (!diameter_pair) {
1560 		/* create a "fake" diameter_pair structure */
1561 		diameter_pair = wmem_new(wmem_packet_scope(), diameter_req_ans_pair_t);
1562 		diameter_pair->hop_by_hop_id = hop_by_hop_id;
1563 		diameter_pair->cmd_code = cmd;
1564 		diameter_pair->result_code = 0;
1565 		diameter_pair->cmd_str = cmd_str;
1566 		diameter_pair->req_frame = 0;
1567 		diameter_pair->ans_frame = 0;
1568 		diameter_pair->req_time = pinfo->abs_ts;
1569 	}
1570 	diameter_pair->processing_request=(flags_bits & DIAM_FLAGS_R)!= 0;
1571 
1572 	/* print state tracking info in the tree */
1573 	if (flags_bits & DIAM_FLAGS_R) {
1574 		/* This is a request */
1575 		if (diameter_pair->ans_frame) {
1576 			it = proto_tree_add_uint(diam_tree, hf_diameter_answer_in,
1577 					tvb, 0, 0, diameter_pair->ans_frame);
1578 			proto_item_set_generated(it);
1579 		}
1580 	} else {
1581 		/* This is an answer */
1582 		if (diameter_pair->req_frame) {
1583 			it = proto_tree_add_uint(diam_tree, hf_diameter_answer_to,
1584 					tvb, 0, 0, diameter_pair->req_frame);
1585 			proto_item_set_generated(it);
1586 
1587 			nstime_delta(&ns, &pinfo->abs_ts, &diameter_pair->req_time);
1588 			diameter_pair->srt_time = ns;
1589 			it = proto_tree_add_time(diam_tree, hf_diameter_answer_time, tvb, 0, 0, &ns);
1590 			proto_item_set_generated(it);
1591 			/* TODO: Populate result_code in tap record from AVP 268 */
1592 		}
1593 	}
1594 
1595 	offset = 20;
1596 
1597 	/* Dissect AVPs until the end of the packet is reached */
1598 	while (offset < packet_len) {
1599 		offset += dissect_diameter_avp(c, tvb, offset, diam_sub_dis_inf, FALSE);
1600 	}
1601 
1602 	/* Handle requests for which no answers were found and
1603 	 * answers for which no requests were found in the tap listener.
1604 	 * In case if you don't need unpaired requests/answers use:
1605 	 * if (diameter_pair->processing_request || !diameter_pair->req_frame)
1606 	 *   return;
1607 	 */
1608 	tap_queue_packet(diameter_tap, pinfo, diameter_pair);
1609 
1610 	return tvb_reported_length(tvb);
1611 }
1612 
1613 static guint
get_diameter_pdu_len(packet_info * pinfo _U_,tvbuff_t * tvb,int offset,void * data _U_)1614 get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
1615                      int offset, void *data _U_)
1616 {
1617 	/* Get the length of the Diameter packet. */
1618 	return tvb_get_ntoh24(tvb, offset + 1);
1619 }
1620 
1621 #define NOT_DIAMETER	0
1622 #define IS_DIAMETER	1
1623 #define NOT_ENOUGH_DATA 2
1624 static gint
check_diameter(tvbuff_t * tvb)1625 check_diameter(tvbuff_t *tvb)
1626 {
1627 	guint8 flags;
1628 
1629 	/* Ensure we don't throw an exception trying to do these heuristics */
1630 	if (tvb_captured_length(tvb) < 5)
1631 		return NOT_ENOUGH_DATA;
1632 
1633 	/* Check if the Diameter version is 1 */
1634 	if (tvb_get_guint8(tvb, 0) != 1)
1635 		return NOT_DIAMETER;
1636 
1637 	/* Diameter minimum message length:
1638 	 *
1639 	 * Version+Length - 4 bytes
1640 	 * Flags+CC - 4 bytes
1641 	 * AppID - 4 bytes
1642 	 * HbH - 4 bytes
1643 	 * E2E - 4 bytes
1644 	 * 2 AVPs (Orig-Host, Orig-Realm), each including:
1645 	 *  * AVP code - 4 bytes
1646 	 *  * AVP flags + length - 4 bytes
1647 	 *  * (no data - what would a reasonable minimum be?)
1648 	 *
1649 	 * --> 36 bytes
1650 	 */
1651 	if (tvb_get_ntoh24(tvb, 1) < 36)
1652 		return NOT_DIAMETER;
1653 
1654 	flags = tvb_get_guint8(tvb, 4);
1655 
1656 	/* Check if any of the Reserved flag bits are set */
1657 	if (flags & 0x0f)
1658 		return NOT_DIAMETER;
1659 
1660 	/* Check if both the R- and E-bits are set */
1661 	if ((flags & DIAM_FLAGS_R) && (flags & DIAM_FLAGS_E))
1662 		return NOT_DIAMETER;
1663 
1664 	return IS_DIAMETER;
1665 }
1666 
1667 /*****************************************************************/
1668 /* Main dissection function                                      */
1669 /* Checks if the message looks like Diameter before accepting it */
1670 /*****************************************************************/
1671 static int
dissect_diameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1672 dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1673 {
1674 	if (check_diameter(tvb) != IS_DIAMETER)
1675 		return 0;
1676 	return dissect_diameter_common(tvb, pinfo, tree, data);
1677 }
1678 
1679 static int
dissect_diameter_tcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1680 dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1681 {
1682 	gint is_diam = check_diameter(tvb);
1683 
1684 	if (is_diam == NOT_DIAMETER) {
1685 		/* We've probably been given a frame that's not the start of
1686 		 * a PDU.
1687 		 */
1688 		col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1689 		col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1690 		call_dissector(data_handle, tvb, pinfo, tree);
1691 	} else if (is_diam == NOT_ENOUGH_DATA) {
1692 		/* Since we're doing our heuristic checks before
1693 		 * tcp_dissect_pdus() (since we we can't do heuristics once
1694 		 * we're in there) we sometimes have to ask for more data...
1695 		 */
1696                 pinfo->desegment_offset = 0;
1697                 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1698 	} else {
1699 		tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
1700 				 get_diameter_pdu_len, dissect_diameter_common, data);
1701 	}
1702 
1703 	return tvb_reported_length(tvb);
1704 }
1705 
1706 static int
dissect_diameter_avps(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1707 dissect_diameter_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1708 {
1709 	proto_item *pi;
1710 	proto_tree *diam_tree;
1711 	int offset = 0;
1712 	diam_ctx_t *c = wmem_new0(wmem_packet_scope(), diam_ctx_t);
1713 	diam_sub_dis_t *diam_sub_dis_inf = wmem_new0(wmem_packet_scope(), diam_sub_dis_t);
1714 
1715 	/* Load header fields if not already done */
1716 	if (hf_diameter_code == -1)
1717 		proto_registrar_get_byname("diameter.code");
1718 
1719 	col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER");
1720 	col_set_str(pinfo->cinfo, COL_INFO, "AVPs:");
1721 
1722 	pi = proto_tree_add_item(tree, proto_diameter, tvb, 0, -1, ENC_NA);
1723 	diam_tree = proto_item_add_subtree(pi, ett_diameter);
1724 	c->tree = diam_tree;
1725 	c->pinfo = pinfo;
1726 	c->version_rfc = TRUE;
1727 
1728 	/* Dissect AVPs until the end of the packet is reached */
1729 	while (tvb_reported_length_remaining(tvb, offset)) {
1730 		offset += dissect_diameter_avp(c, tvb, offset, diam_sub_dis_inf, TRUE);
1731 	}
1732 	return tvb_reported_length(tvb);
1733 }
1734 
1735 static char *
alnumerize(char * name)1736 alnumerize(char *name)
1737 {
1738 	char *r = name;
1739 	char *w = name;
1740 	char c;
1741 
1742 	for (;(c = *r); r++) {
1743 		if (g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.') {
1744 			*(w++) = c;
1745 		}
1746 	}
1747 
1748 	*w = '\0';
1749 
1750 	return name;
1751 }
1752 
1753 
1754 static guint
reginfo(int * hf_ptr,const char * name,const char * abbr,const char * desc,enum ftenum ft,field_display_e base,value_string_ext * vs_ext,guint32 mask)1755 reginfo(int *hf_ptr, const char *name, const char *abbr, const char *desc,
1756 	enum ftenum ft, field_display_e base, value_string_ext *vs_ext,
1757 	guint32 mask)
1758 {
1759 	hf_register_info hf;
1760 
1761 	hf.p_id					= hf_ptr;
1762 	hf.hfinfo.name				= name;
1763 	hf.hfinfo.abbrev			= abbr;
1764 	hf.hfinfo.type				= ft;
1765 	hf.hfinfo.display			= base;
1766 	hf.hfinfo.strings			= NULL;
1767 	hf.hfinfo.bitmask			= mask;
1768 	hf.hfinfo.blurb				= desc;
1769 	/* HFILL */
1770 	HFILL_INIT(hf);
1771 
1772 	if (vs_ext) {
1773 		hf.hfinfo.strings = vs_ext;
1774 	}
1775 
1776 	wmem_array_append_one(build_dict.hf,hf);
1777 	return wmem_array_get_count(build_dict.hf);
1778 }
1779 
1780 static void
basic_avp_reginfo(diam_avp_t * a,const char * name,enum ftenum ft,field_display_e base,value_string_ext * vs_ext)1781 basic_avp_reginfo(diam_avp_t *a, const char *name, enum ftenum ft,
1782 		  field_display_e base, value_string_ext *vs_ext)
1783 {
1784 	hf_register_info hf;
1785 	gint *ettp = &(a->ett);
1786 
1787 	hf.p_id					= &(a->hf_value);
1788 	hf.hfinfo.name				= NULL;
1789 	hf.hfinfo.abbrev			= NULL;
1790 	hf.hfinfo.type				= ft;
1791 	hf.hfinfo.display			= base;
1792 	hf.hfinfo.strings			= NULL;
1793 	hf.hfinfo.bitmask			= 0x0;
1794 	hf.hfinfo.blurb				= a->vendor->code ?
1795 						    wmem_strdup_printf(wmem_epan_scope(), "vendor=%d code=%d", a->vendor->code, a->code)
1796 						  : wmem_strdup_printf(wmem_epan_scope(), "code=%d", a->code);
1797 	/* HFILL */
1798 	HFILL_INIT(hf);
1799 
1800 	hf.hfinfo.name = wmem_strdup(wmem_epan_scope(), name);
1801 	hf.hfinfo.abbrev = alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, NULL));
1802 	if (vs_ext) {
1803 		hf.hfinfo.strings = vs_ext;
1804 	}
1805 
1806 	wmem_array_append(build_dict.hf,&hf,1);
1807 	g_ptr_array_add(build_dict.ett,ettp);
1808 }
1809 
1810 static diam_avp_t *
build_address_avp(const avp_type_t * type _U_,guint32 code,diam_vnd_t * vendor,const char * name,const value_string * vs _U_,void * data _U_)1811 build_address_avp(const avp_type_t *type _U_, guint32 code,
1812 		  diam_vnd_t *vendor, const char *name,
1813 		  const value_string *vs _U_, void *data _U_)
1814 {
1815 	diam_avp_t *a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1816 	address_avp_t *t = wmem_new(wmem_epan_scope(), address_avp_t);
1817 	gint *ettp = &(t->ett);
1818 
1819 	a->code = code;
1820 	a->vendor = vendor;
1821 /*
1822  * It seems like the radius AVPs 1-255 will use the defs from RADIUS in which case:
1823  * https://tools.ietf.org/html/rfc2685
1824  * Address
1825  *    The Address field is four octets.  The value 0xFFFFFFFF indicates
1826  *    that the NAS Should allow the user to select an address (e.g.
1827  *    Negotiated).  The value 0xFFFFFFFE indicates that the NAS should
1828  *    select an address for the user (e.g. Assigned from a pool of
1829  *    addresses kept by the NAS).  Other valid values indicate that the
1830  *    NAS should use that value as the user's IP address.
1831  *
1832  * Where as in Diameter:
1833  * RFC3588
1834  * Address
1835  *    The Address format is derived from the OctetString AVP Base
1836  *    Format.  It is a discriminated union, representing, for example a
1837  *    32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most
1838  *    significant octet first.  The first two octets of the Address
1839  *    AVP represents the AddressType, which contains an Address Family
1840  *    defined in [IANAADFAM].  The AddressType is used to discriminate
1841  *    the content and format of the remaining octets.
1842  */
1843 	a->dissector_v16 = address_v16_avp;
1844 	if (code<256) {
1845 		a->dissector_rfc = address_v16_avp;
1846 	} else {
1847 		a->dissector_rfc = address_rfc_avp;
1848 	}
1849 	a->ett = -1;
1850 	a->hf_value = -1;
1851 	a->type_data = t;
1852 
1853 	t->ett = -1;
1854 	t->hf_address_type = -1;
1855 	t->hf_ipv4 = -1;
1856 	t->hf_ipv6 = -1;
1857 	t->hf_e164_str = -1;
1858 	t->hf_other = -1;
1859 
1860 	basic_avp_reginfo(a, name, FT_BYTES, BASE_NONE, NULL);
1861 
1862 	reginfo(&(t->hf_address_type), wmem_strconcat(wmem_epan_scope(), name, " Address Family", NULL),
1863 		alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".addr_family", NULL)),
1864 		NULL, FT_UINT16, (field_display_e)(BASE_DEC|BASE_EXT_STRING), &diameter_avp_data_addrfamily_vals_ext, 0);
1865 
1866 	reginfo(&(t->hf_ipv4), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1867 		alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".IPv4", NULL)),
1868 		NULL, FT_IPv4, BASE_NONE, NULL, 0);
1869 
1870 	reginfo(&(t->hf_ipv6), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1871 		alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".IPv6", NULL)),
1872 		NULL, FT_IPv6, BASE_NONE, NULL, 0);
1873 
1874 	reginfo(&(t->hf_e164_str), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1875 		alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".E164", NULL)),
1876 		NULL, FT_STRING, BASE_NONE, NULL, 0);
1877 
1878 	reginfo(&(t->hf_other), wmem_strconcat(wmem_epan_scope(), name, " Address", NULL),
1879 		alnumerize(wmem_strconcat(wmem_epan_scope(), "diameter.", name, ".Bytes", NULL)),
1880 		NULL, FT_BYTES, BASE_NONE, NULL, 0);
1881 
1882 	g_ptr_array_add(build_dict.ett,ettp);
1883 
1884 	return a;
1885 }
1886 
1887 static diam_avp_t *
build_proto_avp(const avp_type_t * type _U_,guint32 code,diam_vnd_t * vendor,const char * name _U_,const value_string * vs _U_,void * data)1888 build_proto_avp(const avp_type_t *type _U_, guint32 code,
1889 		diam_vnd_t *vendor, const char *name _U_,
1890 		const value_string *vs _U_, void *data)
1891 {
1892 	diam_avp_t *a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1893 	proto_avp_t *t = wmem_new0(wmem_epan_scope(), proto_avp_t);
1894 	gint *ettp = &(a->ett);
1895 
1896 	a->code = code;
1897 	a->vendor = vendor;
1898 	a->dissector_v16 = proto_avp;
1899 	a->dissector_rfc = proto_avp;
1900 	a->ett = -1;
1901 	a->hf_value = -2;
1902 	a->type_data = t;
1903 
1904 	t->name = (char *)data;
1905 	t->handle = NULL;
1906 	t->reassemble_mode = REASEMBLE_NEVER;
1907 
1908 	g_ptr_array_add(build_dict.ett,ettp);
1909 
1910 	return a;
1911 }
1912 
1913 static diam_avp_t *
build_simple_avp(const avp_type_t * type,guint32 code,diam_vnd_t * vendor,const char * name,const value_string * vs,void * data _U_)1914 build_simple_avp(const avp_type_t *type, guint32 code, diam_vnd_t *vendor,
1915 		 const char *name, const value_string *vs, void *data _U_)
1916 {
1917 	diam_avp_t *a;
1918 	value_string_ext *vs_ext = NULL;
1919 	field_display_e base;
1920 	guint i = 0;
1921 
1922 	/*
1923 	 * Only 32-bit or shorter integral types can have a list of values.
1924 	 */
1925 	base = (field_display_e)type->base;
1926 	if (vs != NULL) {
1927 		switch (type->ft) {
1928 
1929 		case FT_UINT8:
1930 		case FT_UINT16:
1931 		case FT_UINT32:
1932 		case FT_INT8:
1933 		case FT_INT16:
1934 		case FT_INT32:
1935 			break;
1936 
1937 		default:
1938 			report_failure("Diameter Dictionary: AVP '%s' has a list of values but isn't of a 32-bit or shorter integral type (%s)\n",
1939 				name, ftype_name(type->ft));
1940 			return NULL;
1941 		}
1942 		while (vs[i].strptr) {
1943 		  i++;
1944 		}
1945 		vs_ext = value_string_ext_new(vs, i+1, wmem_strconcat(wmem_epan_scope(), name, "_vals_ext", NULL));
1946 		base = (field_display_e)(base|BASE_EXT_STRING);
1947 	}
1948 
1949 	a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1950 	a->code = code;
1951 	a->vendor = vendor;
1952 	a->dissector_v16 = type->v16;
1953 	a->dissector_rfc = type->rfc;
1954 	a->ett = -1;
1955 	a->hf_value = -1;
1956 
1957 	basic_avp_reginfo(a, name, type->ft, base, vs_ext);
1958 
1959 	return a;
1960 }
1961 
1962 static diam_avp_t *
build_appid_avp(const avp_type_t * type,guint32 code,diam_vnd_t * vendor,const char * name,const value_string * vs,void * data _U_)1963 build_appid_avp(const avp_type_t *type, guint32 code, diam_vnd_t *vendor,
1964 		const char *name, const value_string *vs, void *data _U_)
1965 {
1966 	diam_avp_t *a;
1967 	field_display_e base;
1968 
1969 	a = wmem_new0(wmem_epan_scope(), diam_avp_t);
1970 	a->code = code;
1971 	a->vendor = vendor;
1972 	a->dissector_v16 = type->v16;
1973 	a->dissector_rfc = type->rfc;
1974 	a->ett = -1;
1975 	a->hf_value = -1;
1976 
1977 	if (vs != NULL) {
1978 		report_failure("Diameter Dictionary: AVP '%s' (of type AppId) has a list of values but the list won't be used\n",
1979 				name);
1980 	}
1981 
1982 	base = (field_display_e)(type->base|BASE_EXT_STRING);
1983 
1984 	basic_avp_reginfo(a, name, type->ft, base, dictionary.applications);
1985 	return a;
1986 }
1987 
1988 static const avp_type_t basic_types[] = {
1989 	{"octetstring"			, simple_avp		, simple_avp	, FT_BYTES			, BASE_NONE			, build_simple_avp  },
1990 	{"octetstringorutf8"	, simple_avp		, simple_avp	, FT_BYTES			, BASE_SHOW_ASCII_PRINTABLE	, build_simple_avp  },
1991 	{"utf8string"			, utf8_avp			, utf8_avp		, FT_STRING			, BASE_NONE			, build_simple_avp  },
1992 	{"grouped"				, grouped_avp		, grouped_avp	, FT_BYTES			, BASE_NONE			, build_simple_avp  },
1993 	{"integer32"			, integer32_avp		, integer32_avp	, FT_INT32			, BASE_DEC			, build_simple_avp  },
1994 	{"unsigned32"			, unsigned32_avp	, unsigned32_avp, FT_UINT32			, BASE_DEC			, build_simple_avp  },
1995 	{"integer64"			, integer64_avp		, integer64_avp	, FT_INT64			, BASE_DEC			, build_simple_avp  },
1996 	{"unsigned64"			, unsigned64_avp	, unsigned64_avp, FT_UINT64			, BASE_DEC			, build_simple_avp  },
1997 	{"float32"				, float32_avp		, float32_avp	, FT_FLOAT			, BASE_NONE			, build_simple_avp  },
1998 	{"float64"				, float64_avp		, float64_avp	, FT_DOUBLE			, BASE_NONE			, build_simple_avp  },
1999 	{"ipaddress"			, NULL				, NULL			, FT_NONE			, BASE_NONE			, build_address_avp },
2000 	{"diameteruri"			, utf8_avp			, utf8_avp		, FT_STRING			, BASE_NONE			, build_simple_avp  },
2001 	{"diameteridentity"		, utf8_avp			, utf8_avp		, FT_STRING			, BASE_NONE			, build_simple_avp  },
2002 	{"ipfilterrule"			, utf8_avp			, utf8_avp		, FT_STRING			, BASE_NONE			, build_simple_avp  },
2003 	{"qosfilterrule"		, utf8_avp			, utf8_avp		, FT_STRING			, BASE_NONE			, build_simple_avp  },
2004 	{"time"					, time_avp			, time_avp		, FT_ABSOLUTE_TIME	, ABSOLUTE_TIME_UTC	, build_simple_avp  },
2005 	{"AppId"				, simple_avp		, simple_avp	, FT_UINT32			, BASE_DEC			, build_appid_avp   },
2006 	{NULL, NULL, NULL, FT_NONE, BASE_NONE, NULL }
2007 };
2008 
2009 
2010 
2011 /*
2012  * This is like g_str_hash() (as of GLib 2.4.8), but it maps all
2013  * upper-case ASCII characters to their ASCII lower-case equivalents.
2014  * We can't use g_strdown(), as that doesn't do an ASCII mapping;
2015  * in Turkish locales, for example, there are two lower-case "i"s
2016  * and two upper-case "I"s, with and without dots - the ones with
2017  * dots map between each other, as do the ones without dots, so "I"
2018  * doesn't map to "i".
2019  */
2020 static guint
strcase_hash(gconstpointer key)2021 strcase_hash(gconstpointer key)
2022 {
2023 	const char *p = (const char *)key;
2024 	guint h = *p;
2025 	char c;
2026 
2027 	if (h) {
2028 		if (h >= 'A' && h <= 'Z')
2029 			h = h - 'A' + 'a';
2030 		for (p += 1; *p != '\0'; p++) {
2031 			c = *p;
2032 			if (c >= 'A' && c <= 'Z')
2033 				c = c - 'A' + 'a';
2034 			h = (h << 5) - h + c;
2035 		}
2036 	}
2037 
2038 	return h;
2039 }
2040 
2041 /*
2042  * Again, use g_ascii_strcasecmp(), not strcasecmp(), so that only ASCII
2043  * letters are mapped, and they're mapped to the lower-case ASCII
2044  * equivalents.
2045  */
2046 static gboolean
strcase_equal(gconstpointer ka,gconstpointer kb)2047 strcase_equal(gconstpointer ka, gconstpointer kb)
2048 {
2049 	const char *a = (const char *)ka;
2050 	const char *b = (const char *)kb;
2051 	return g_ascii_strcasecmp(a,b) == 0;
2052 }
2053 
2054 static gboolean
ddict_cleanup_cb(wmem_allocator_t * allocator _U_,wmem_cb_event_t event _U_,void * user_data)2055 ddict_cleanup_cb(wmem_allocator_t* allocator _U_, wmem_cb_event_t event _U_, void *user_data)
2056 {
2057 	ddict_t *d = (ddict_t *)user_data;
2058 	ddict_free(d);
2059 	return FALSE;
2060 }
2061 
2062 
2063 /* Note: Dynamic "value string arrays" (e.g., vs_cmds, vs_avps, ...) are constructed using */
2064 /*       "zero-terminated" GArrays so that they will have the same form as standard        */
2065 /*       value_string arrays created at compile time. Since the last entry in a            */
2066 /*       value_string array must be {0, NULL}, we are assuming that NULL == 0 (hackish).   */
2067 
2068 static int
dictionary_load(void)2069 dictionary_load(void)
2070 {
2071 	ddict_t *d;
2072 	ddict_application_t *p;
2073 	ddict_vendor_t *v;
2074 	ddict_cmd_t *c;
2075 	ddict_typedefn_t *t;
2076 	ddict_avp_t *a;
2077 	gboolean do_debug_parser = getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? TRUE : FALSE;
2078 	gboolean do_dump_dict = getenv("WIRESHARK_DUMP_DIAM_DICT") ? TRUE : FALSE;
2079 	char *dir;
2080 	const avp_type_t *type;
2081 	const avp_type_t *octetstring = &basic_types[0];
2082 	diam_avp_t *avp;
2083 	GHashTable *vendors = g_hash_table_new(strcase_hash,strcase_equal);
2084 	diam_vnd_t *vnd;
2085 	GArray *vnd_shrt_arr = g_array_new(TRUE,TRUE,sizeof(value_string));
2086 
2087 	/* Pre allocate the arrays big enough to hold the hf:s and etts:s*/
2088 	build_dict.hf = wmem_array_sized_new(wmem_epan_scope(), sizeof(hf_register_info), 4096);
2089 	build_dict.ett = g_ptr_array_sized_new(4096);
2090 	build_dict.types = g_hash_table_new(strcase_hash,strcase_equal);
2091 	build_dict.avps = g_hash_table_new(strcase_hash,strcase_equal);
2092 
2093 	dictionary.vnds = wmem_tree_new(wmem_epan_scope());
2094 	dictionary.avps = wmem_tree_new(wmem_epan_scope());
2095 
2096 	unknown_vendor.vs_cmds = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2097 	wmem_array_set_null_terminator(unknown_vendor.vs_cmds);
2098 	wmem_array_bzero(unknown_vendor.vs_cmds);
2099 	unknown_vendor.vs_avps = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2100 	wmem_array_set_null_terminator(unknown_vendor.vs_avps);
2101 	wmem_array_bzero(unknown_vendor.vs_avps);
2102 	no_vnd.vs_cmds = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2103 	wmem_array_set_null_terminator(no_vnd.vs_cmds);
2104 	wmem_array_bzero(no_vnd.vs_cmds);
2105 	no_vnd.vs_avps = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2106 	wmem_array_set_null_terminator(no_vnd.vs_avps);
2107 	wmem_array_bzero(no_vnd.vs_avps);
2108 
2109 	all_cmds = g_array_new(TRUE,TRUE,sizeof(value_string));
2110 
2111 	wmem_tree_insert32(dictionary.vnds,0,&no_vnd);
2112 	g_hash_table_insert(vendors,"None",&no_vnd);
2113 
2114 	/* initialize the types hash with the known basic types */
2115 	for (type = basic_types; type->name; type++) {
2116 		g_hash_table_insert(build_dict.types,(gchar *)type->name,(void *)type);
2117 	}
2118 
2119 	/* load the dictionary */
2120 	dir = wmem_strdup_printf(NULL, "%s" G_DIR_SEPARATOR_S "diameter" G_DIR_SEPARATOR_S, get_datafile_dir());
2121 	d = ddict_scan(dir,"dictionary.xml",do_debug_parser);
2122 	wmem_free(NULL, dir);
2123 	if (d == NULL) {
2124 		g_hash_table_destroy(vendors);
2125 		g_array_free(vnd_shrt_arr, TRUE);
2126 		return 0;
2127 	}
2128 	wmem_register_callback(wmem_epan_scope(), ddict_cleanup_cb, d);
2129 
2130 	if (do_dump_dict) ddict_print(stdout, d);
2131 
2132 	/* populate the types */
2133 	for (t = d->typedefns; t; t = t->next) {
2134 		const avp_type_t *parent = NULL;
2135 		/* try to get the parent type */
2136 
2137 		if (t->name == NULL) {
2138 			report_failure("Diameter Dictionary: Invalid Type (empty name): parent==%s\n",
2139 				t->parent ? t->parent : "(null)");
2140 			continue;
2141 		}
2142 
2143 
2144 		if (g_hash_table_lookup(build_dict.types,t->name))
2145 			continue;
2146 
2147 		if (t->parent) {
2148 			parent = (avp_type_t *)g_hash_table_lookup(build_dict.types,t->parent);
2149 		}
2150 
2151 		if (!parent) parent = octetstring;
2152 
2153 		/* insert the parent type for this type */
2154 		g_hash_table_insert(build_dict.types,t->name,(void *)parent);
2155 	}
2156 
2157 	/* populate the applications */
2158 	if ((p = d->applications)) {
2159 		wmem_array_t *arr = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2160 		value_string term[1];
2161 
2162 		term[0].value =  0;
2163 		term[0].strptr = NULL;
2164 
2165 		for (; p; p = p->next) {
2166 			value_string item[1];
2167 
2168 			item[0].value = p->code;
2169 			item[0].strptr = p->name;
2170 			if (!p->name) {
2171 				report_failure("Diameter Dictionary: Invalid Application (empty name): id=%d\n", p->code);
2172 				continue;
2173 			}
2174 
2175 			wmem_array_append_one(arr,item);
2176 		}
2177 
2178 		wmem_array_sort(arr, compare_avps);
2179 		wmem_array_append_one(arr,term);
2180 
2181 		/* TODO: Remove duplicates */
2182 
2183 		dictionary.applications = value_string_ext_new((value_string *)wmem_array_get_raw(arr),
2184 								wmem_array_get_count(arr),
2185 								wmem_strdup(wmem_epan_scope(), "applications_vals_ext"));
2186 	}
2187 
2188 	if ((v = d->vendors)) {
2189 		for ( ; v; v = v->next) {
2190 			value_string item[1];
2191 
2192 			item[0].value = v->code;
2193 			item[0].strptr = v->name;
2194 
2195 			if (v->name == NULL) {
2196 				report_failure("Diameter Dictionary: Invalid Vendor (empty name): code==%d\n", v->code);
2197 				continue;
2198 			}
2199 
2200 			if (g_hash_table_lookup(vendors,v->name))
2201 				continue;
2202 
2203 			g_array_append_val(vnd_shrt_arr,item);
2204 
2205 			vnd = wmem_new(wmem_epan_scope(), diam_vnd_t);
2206 			vnd->code = v->code;
2207 			vnd->vs_cmds = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2208 			wmem_array_set_null_terminator(vnd->vs_cmds);
2209 			wmem_array_bzero(vnd->vs_cmds);
2210 			vnd->vs_avps = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2211 			wmem_array_set_null_terminator(vnd->vs_avps);
2212 			wmem_array_bzero(vnd->vs_avps);
2213 			vnd->vs_avps_ext = NULL;
2214 			wmem_tree_insert32(dictionary.vnds,vnd->code,vnd);
2215 			g_hash_table_insert(vendors,v->name,vnd);
2216 		}
2217 	}
2218 
2219 	vnd_short_vs = (value_string *)g_array_free(vnd_shrt_arr, FALSE);
2220 
2221 	if ((c = d->cmds)) {
2222 		for (; c; c = c->next) {
2223 			if (c->vendor == NULL) {
2224 				report_failure("Diameter Dictionary: Invalid Vendor (empty name) for command %s\n",
2225 					c->name ? c->name : "(null)");
2226 				continue;
2227 			}
2228 
2229 			if ((vnd = (diam_vnd_t *)g_hash_table_lookup(vendors,c->vendor))) {
2230 				value_string item[1];
2231 
2232 				item[0].value =  c->code;
2233 				item[0].strptr = c->name;
2234 
2235 				wmem_array_append_one(vnd->vs_cmds,item);
2236 				/* Also add to all_cmds as used by RFC version */
2237 				g_array_append_val(all_cmds,item);
2238 			} else {
2239 				report_failure("Diameter Dictionary: No Vendor: %s\n",c->vendor);
2240 			}
2241 		}
2242 	}
2243 
2244 
2245 	for (a = d->avps; a; a = a->next) {
2246 		ddict_enum_t *e;
2247 		value_string *vs = NULL;
2248 		const char *vend = a->vendor ? a->vendor : "None";
2249 		ddict_xmlpi_t *x;
2250 		void *avp_data = NULL;
2251 
2252 		if (a->name == NULL) {
2253 			report_failure("Diameter Dictionary: Invalid AVP (empty name)\n");
2254 			continue;
2255 		}
2256 
2257 		if ((vnd = (diam_vnd_t *)g_hash_table_lookup(vendors,vend))) {
2258 			value_string vndvs[1];
2259 
2260 			vndvs[0].value =  a->code;
2261 			vndvs[0].strptr = a->name;
2262 
2263 
2264 			wmem_array_append_one(vnd->vs_avps,vndvs);
2265 		} else {
2266 			report_failure("Diameter Dictionary: No Vendor: %s\n",vend);
2267 			vnd = &unknown_vendor;
2268 		}
2269 
2270 		if ((e = a->enums)) {
2271 			wmem_array_t *arr = wmem_array_new(wmem_epan_scope(), sizeof(value_string));
2272 			value_string term[1];
2273 
2274 			term[0].value =  0;
2275 			term[0].strptr = NULL;
2276 
2277 			for (; e; e = e->next) {
2278 				value_string item[1];
2279 
2280 				item[0].value =  e->code;
2281 				item[0].strptr = e->name;
2282 				wmem_array_append_one(arr,item);
2283 			}
2284 			wmem_array_sort(arr, compare_avps);
2285 			wmem_array_append_one(arr,term);
2286 			vs = (value_string *)wmem_array_get_raw(arr);
2287 		}
2288 
2289 		type = NULL;
2290 
2291 		for( x = d->xmlpis; x; x = x->next ) {
2292 			if ( (strcase_equal(x->name,"avp-proto") && strcase_equal(x->key,a->name))
2293 				 || (a->type && strcase_equal(x->name,"type-proto") && strcase_equal(x->key,a->type))
2294 				 ) {
2295 				static avp_type_t proto_type = {"proto", proto_avp, proto_avp, FT_UINT32, BASE_HEX, build_proto_avp};
2296 				type =  &proto_type;
2297 
2298 				avp_data = x->value;
2299 				break;
2300 			}
2301 		}
2302 
2303 		if ( (!type) && a->type )
2304 			type = (avp_type_t *)g_hash_table_lookup(build_dict.types,a->type);
2305 
2306 		if (!type) type = octetstring;
2307 
2308 		avp = type->build( type, a->code, vnd, a->name, vs, avp_data);
2309 		if (avp != NULL) {
2310 			g_hash_table_insert(build_dict.avps, a->name, avp);
2311 
2312 			{
2313 				wmem_tree_key_t k[3];
2314 
2315 				k[0].length = 1;
2316 				k[0].key	= &(a->code);
2317 				k[1].length = 1;
2318 				k[1].key	= &(vnd->code);
2319 				k[2].length = 0;
2320 				k[2].key	= NULL;
2321 
2322 				wmem_tree_insert32_array(dictionary.avps,k,avp);
2323 			}
2324 		}
2325 	}
2326 	g_hash_table_destroy(build_dict.types);
2327 	g_hash_table_destroy(build_dict.avps);
2328 	g_hash_table_destroy(vendors);
2329 
2330 	return 1;
2331 }
2332 
2333 /*
2334  * This does most of the registration work; see register_diameter_fields()
2335  * for the reason why we split it off.
2336  */
2337 static void
real_register_diameter_fields(void)2338 real_register_diameter_fields(void)
2339 {
2340 	expert_module_t* expert_diameter;
2341 	guint i, ett_length;
2342 
2343 	hf_register_info hf_base[] = {
2344 	{ &hf_diameter_version,
2345 		  { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
2346 			  NULL, HFILL }},
2347 	{ &hf_diameter_length,
2348 		  { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
2349 			  NULL, HFILL }},
2350 	{ &hf_diameter_flags,
2351 		  { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
2352 			  NULL, HFILL }},
2353 	{ &hf_diameter_flags_request,
2354 		  { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_R,
2355 			  NULL, HFILL }},
2356 	{ &hf_diameter_flags_proxyable,
2357 		  { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_P,
2358 			  NULL, HFILL }},
2359 	{ &hf_diameter_flags_error,
2360 		  { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_E,
2361 			  NULL, HFILL }},
2362 	{ &hf_diameter_flags_T,
2363 		  { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DIAM_FLAGS_T,
2364 			  NULL, HFILL }},
2365 	{ &hf_diameter_flags_reserved4,
2366 		  { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2367 			  DIAM_FLAGS_RESERVED4, NULL, HFILL }},
2368 	{ &hf_diameter_flags_reserved5,
2369 		  { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2370 			  DIAM_FLAGS_RESERVED5, NULL, HFILL }},
2371 	{ &hf_diameter_flags_reserved6,
2372 		  { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2373 			  DIAM_FLAGS_RESERVED6, NULL, HFILL }},
2374 	{ &hf_diameter_flags_reserved7,
2375 		  { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2376 			  DIAM_FLAGS_RESERVED7, NULL, HFILL }},
2377 	{ &hf_diameter_vendor_id,
2378 		  { "VendorId",	"diameter.vendorId", FT_UINT32, BASE_ENTERPRISES, STRINGS_ENTERPRISES,
2379 			  0x0, NULL, HFILL }},
2380 	{ &hf_diameter_application_id,
2381 		  { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC|BASE_EXT_STRING, VALS_EXT_PTR(dictionary.applications),
2382 			  0x0, NULL, HFILL }},
2383 	{ &hf_diameter_hopbyhopid,
2384 		  { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
2385 			  BASE_HEX, NULL, 0x0, NULL, HFILL }},
2386 	{ &hf_diameter_endtoendid,
2387 		  { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
2388 			  BASE_HEX, NULL, 0x0, NULL, HFILL }},
2389 	{ &hf_diameter_avp,
2390 		  { "AVP","diameter.avp", FT_BYTES, BASE_NONE,
2391 			  NULL, 0x0, NULL, HFILL }},
2392 	{ &hf_diameter_avp_len,
2393 		  { "AVP Length","diameter.avp.len", FT_UINT24, BASE_DEC,
2394 			  NULL, 0x0, NULL, HFILL }},
2395 	{ &hf_diameter_avp_code,
2396 		  { "AVP Code", "diameter.avp.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
2397 	{ &hf_diameter_avp_flags,
2398 		  { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
2399 			  NULL, 0x0, NULL, HFILL }},
2400 	{ &hf_diameter_avp_flags_vendor_specific,
2401 		  { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_V,
2402 			  NULL, HFILL }},
2403 	{ &hf_diameter_avp_flags_mandatory,
2404 		  { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_M,
2405 			  NULL, HFILL }},
2406 	{ &hf_diameter_avp_flags_protected,
2407 		  { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&tfs_set_notset), AVP_FLAGS_P,
2408 			  NULL, HFILL }},
2409 	{ &hf_diameter_avp_flags_reserved3,
2410 		  { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2411 			  AVP_FLAGS_RESERVED3,	NULL, HFILL }},
2412 	{ &hf_diameter_avp_flags_reserved4,
2413 		  { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2414 			  AVP_FLAGS_RESERVED4,	NULL, HFILL }},
2415 	{ &hf_diameter_avp_flags_reserved5,
2416 		  { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2417 			  AVP_FLAGS_RESERVED5,	NULL, HFILL }},
2418 	{ &hf_diameter_avp_flags_reserved6,
2419 		  { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2420 			  AVP_FLAGS_RESERVED6,	NULL, HFILL }},
2421 	{ &hf_diameter_avp_flags_reserved7,
2422 		  { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&tfs_set_notset),
2423 			  AVP_FLAGS_RESERVED7,	NULL, HFILL }},
2424 	{ &hf_diameter_avp_vendor_id,
2425 		  { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_ENTERPRISES, STRINGS_ENTERPRISES,
2426 			  0x0, NULL, HFILL }},
2427 	{ &(unknown_avp.hf_value),
2428 		  { "Value","diameter.avp.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2429 	{ &hf_diameter_avp_data_wrong_length,
2430 		  { "Data","diameter.avp.invalid-data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2431 	{ &hf_diameter_avp_pad,
2432 		  { "Padding","diameter.avp.pad", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2433 	{ &hf_diameter_code,
2434 		  { "Command Code", "diameter.cmd.code", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
2435 	{ &hf_diameter_answer_in,
2436 		{ "Answer In", "diameter.answer_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
2437 		"The answer to this diameter request is in this frame", HFILL }},
2438 	{ &hf_diameter_answer_to,
2439 		{ "Request In", "diameter.answer_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
2440 		"This is an answer to the diameter request in this frame", HFILL }},
2441 	{ &hf_diameter_answer_time,
2442 		{ "Response Time", "diameter.resp_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2443 		"The time between the request and the answer", HFILL }},
2444 	{ &hf_framed_ipv6_prefix_reserved,
2445 	    { "Framed IPv6 Prefix Reserved byte", "diameter.framed_ipv6_prefix_reserved",
2446 	    FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
2447 	{ &hf_framed_ipv6_prefix_length,
2448 	    { "Framed IPv6 Prefix length (in bits)", "diameter.framed_ipv6_prefix_length",
2449 	    FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
2450 	{ &hf_framed_ipv6_prefix_bytes,
2451 	    { "Framed IPv6 Prefix as a bytestring", "diameter.framed_ipv6_prefix_bytes",
2452 	    FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
2453 	{ &hf_framed_ipv6_prefix_ipv6,
2454 	    { "Framed IPv6 Prefix as an IPv6 address", "diameter.framed_ipv6_prefix_ipv6",
2455 	    FT_IPv6, BASE_NONE, NULL, 0, "This field is present only if the prefix length is 128", HFILL }},
2456 	{ &hf_diameter_3gpp2_exp_res,
2457 		{ "Experimental-Result-Code", "diameter.3gpp2.exp_res",
2458 		FT_UINT32, BASE_DEC, VALS(diameter_3gpp2_exp_res_vals), 0x0,	NULL, HFILL }},
2459 	{ &hf_diameter_other_vendor_exp_res,
2460 		{ "Experimental-Result-Code", "diameter.other_vendor.Experimental-Result-Code",
2461 		FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2462 	{ &hf_diameter_mip6_feature_vector,
2463 		{ "MIP6-Feature-Vector", "diameter.mip6_feature_vector",
2464 		 FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2465 	{ &hf_diameter_mip6_feature_vector_mip6_integrated,
2466 		{ "MIP6_INTEGRATED", "diameter.mip6_feature_vector.mip6_integrated.mip6_integrated",
2467 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000000000000001, NULL, HFILL }},
2468 	{ &hf_diameter_mip6_feature_vector_local_home_agent_assignment,
2469 		{ "LOCAL_HOME_AGENT_ASSIGNMENT", "diameter.mip6_feature_vector.local_home_agent_assignment",
2470 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000000000000002, NULL, HFILL }},
2471 	{ &hf_diameter_mip6_feature_vector_pmip6_supported,
2472 		{ "PMIP6_SUPPORTED", "diameter.mip6_feature_vector.pmip6_supported",
2473 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000010000000000, NULL, HFILL }},
2474 	{ &hf_diameter_mip6_feature_vector_ip4_hoa_supported,
2475 		{ "IP4_HOA_SUPPORTED", "diameter.mip6_feature_vector.ip4_hoa_supported",
2476 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000020000000000, NULL, HFILL }},
2477 	{ &hf_diameter_mip6_feature_vector_local_mag_routing_supported,
2478 		{ "LOCAL_MAG_ROUTING_SUPPORTED", "diameter.mip6_feature_vector.local_mag_routing_supported",
2479 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000040000000000,NULL, HFILL }},
2480 	{ &hf_diameter_3gpp_mip6_feature_vector,
2481 		{ "MIP6-Feature-Vector [3GPP]", "diameter.3gpp.mip6_feature_vector",
2482 		FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2483 	{ &hf_diameter_3gpp_mip6_feature_vector_assign_local_ip,
2484 		{ "MIP6_INTEGRATED", "diameter.3gpp.mip6_feature_vector.assign_local_ip",
2485 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000080000000000, NULL, HFILL }},
2486 	{ &hf_diameter_3gpp_mip6_feature_vector_mip4_supported,
2487 		{ "PMIP6_SUPPORTED", "diameter.3gpp.mip6_feature_vector.mip4_supported",
2488 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000100000000000, NULL, HFILL }},
2489 	{ &hf_diameter_3gpp_mip6_feature_vector_optimized_idle_mode_mobility,
2490 		{ "OPTIMIZED_IDLE_MODE_MOBILITY", "diameter.3gpp.mip6_feature_vector.optimized_idle_mode_mobility",
2491 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000200000000000, NULL, HFILL }},
2492 	{ &hf_diameter_3gpp_mip6_feature_vector_gtpv2_supported,
2493 		{ "GTPv2_SUPPORTED", "diameter.3gpp.mip6_feature_vector.gtpv2_supported",
2494 		FT_BOOLEAN, 64, TFS(&tfs_set_notset), 0x0000400000000000, NULL, HFILL }},
2495 	{ &hf_diameter_user_equipment_info_imeisv,
2496 		{ "IMEISV","diameter.user_equipment_info.imeisv", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2497 	{ &hf_diameter_user_equipment_info_mac,
2498 		{ "MAC","diameter.user_equipment_info.mac", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2499 	{ &hf_diameter_user_equipment_info_eui64,
2500 		{ "EUI64","diameter.user_equipment_info.eui64", FT_EUI64, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2501 	{ &hf_diameter_user_equipment_info_modified_eui64,
2502 		{ "Modified EUI64","diameter.user_equipment_info.modified_eui64", FT_EUI64, BASE_NONE, NULL, 0x0, NULL, HFILL }}
2503 	};
2504 
2505 	gint *ett_base[] = {
2506 		&ett_diameter,
2507 		&ett_diameter_flags,
2508 		&ett_diameter_avp_flags,
2509 		&ett_diameter_avpinfo,
2510 		&ett_unknown,
2511 		&ett_err,
2512 		&ett_diameter_mip6_feature_vector,
2513 	    &ett_diameter_3gpp_mip6_feature_vector,
2514 		&(unknown_avp.ett)
2515 	};
2516 
2517 	static ei_register_info ei[] = {
2518 		{ &ei_diameter_reserved_bit_set, { "diameter.reserved_bit_set", PI_MALFORMED, PI_WARN, "Reserved bit set", EXPFILL }},
2519 		{ &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 }},
2520 		{ &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 }},
2521 		{ &ei_diameter_avp_no_data, { "diameter.avp.no_data", PI_UNDECODED, PI_WARN, "Data is empty", EXPFILL }},
2522 		{ &ei_diameter_avp_pad, { "diameter.avp.pad.non_zero", PI_MALFORMED, PI_NOTE, "Padding is non-zero", EXPFILL }},
2523 		{ &ei_diameter_avp_pad_missing, { "diameter.avp.pad.missing", PI_MALFORMED, PI_NOTE, "Padding is missing", EXPFILL }},
2524 		{ &ei_diameter_avp_len, { "diameter.avp.invalid-len", PI_MALFORMED, PI_WARN, "Wrong length", EXPFILL }},
2525 		{ &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 }},
2526 		{ &ei_diameter_version, { "diameter.version.unknown", PI_UNDECODED, PI_WARN, "Unknown Diameter Version (decoding as RFC 3588)", EXPFILL }},
2527 		{ &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 }},
2528 		{ &ei_diameter_invalid_ipv6_prefix_len, { "diameter.invalid_ipv6_prefix_len", PI_MALFORMED, PI_ERROR, "Invalid IPv6 Prefix length", EXPFILL }},
2529 		{ &ei_diameter_invalid_avp_len,{ "diameter.invalid_avp_len", PI_MALFORMED, PI_ERROR, "Invalid AVP length", EXPFILL }},
2530 		{ &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 }}
2531 	};
2532 
2533 	wmem_array_append(build_dict.hf, hf_base, array_length(hf_base));
2534 	ett_length = array_length(ett_base);
2535 	for (i = 0; i < ett_length; i++) {
2536 		g_ptr_array_add(build_dict.ett, ett_base[i]);
2537 	}
2538 
2539 	proto_register_field_array(proto_diameter, (hf_register_info *)wmem_array_get_raw(build_dict.hf), wmem_array_get_count(build_dict.hf));
2540 	proto_register_subtree_array((gint **)build_dict.ett->pdata, build_dict.ett->len);
2541 	expert_diameter = expert_register_protocol(proto_diameter);
2542 	expert_register_field_array(expert_diameter, ei, array_length(ei));
2543 
2544 	g_ptr_array_free(build_dict.ett,TRUE);
2545 
2546 }
2547 
2548 static void
register_diameter_fields(const char * unused _U_)2549 register_diameter_fields(const char *unused _U_)
2550 {
2551 	/*
2552 	 * The hf_base[] array for Diameter refers to a variable
2553 	 * that is set by dictionary_load(), so we need to call
2554 	 * dictionary_load() before hf_base[] is initialized.
2555 	 *
2556 	 * To ensure that, we call dictionary_load() and then
2557 	 * call a routine that defines hf_base[] and does all
2558 	 * the registration work.
2559 	 */
2560 	dictionary_load();
2561 	real_register_diameter_fields();
2562 }
2563 
2564 void
proto_register_diameter(void)2565 proto_register_diameter(void)
2566 {
2567 	module_t *diameter_module;
2568 
2569 	proto_diameter = proto_register_protocol ("Diameter Protocol", "Diameter", "diameter");
2570 
2571 	/* Allow dissector to find be found by name. */
2572 	diameter_sctp_handle = register_dissector("diameter", dissect_diameter, proto_diameter);
2573 	/* Diameter AVPs without Diameter header, for EAP-TTLS (RFC 5281, Section 10) */
2574 	register_dissector("diameter_avps", dissect_diameter_avps, proto_diameter);
2575 
2576 	/* Delay registration of Diameter fields */
2577 	proto_register_prefix("diameter", register_diameter_fields);
2578 
2579 	/* Register dissector table(s) to do sub dissection of AVPs (OctetStrings) */
2580 	diameter_dissector_table = register_dissector_table("diameter.base", "Diameter Base AVP", proto_diameter, FT_UINT32, BASE_DEC);
2581 	diameter_3gpp_avp_dissector_table = register_dissector_table("diameter.3gpp", "Diameter 3GPP AVP", proto_diameter, FT_UINT32, BASE_DEC);
2582 	diameter_ericsson_avp_dissector_table = register_dissector_table("diameter.ericsson", "Diameter Ericsson AVP", proto_diameter, FT_UINT32, BASE_DEC);
2583 	diameter_verizon_avp_dissector_table = register_dissector_table("diameter.verizon", "DIAMETER_VERIZON_AVPS", proto_diameter, FT_UINT32, BASE_DEC);
2584 
2585 	diameter_expr_result_vnd_table = register_dissector_table("diameter.vnd_exp_res", "Diameter Experimental-Result-Code", proto_diameter, FT_UINT32, BASE_DEC);
2586 
2587 	/* Set default TCP ports */
2588 	range_convert_str(wmem_epan_scope(), &global_diameter_sctp_port_range, DEFAULT_DIAMETER_PORT_RANGE, MAX_SCTP_PORT);
2589 
2590 	/* Register configuration options for ports */
2591 	diameter_module = prefs_register_protocol(proto_diameter, proto_reg_handoff_diameter);
2592 	/* For reading older preference files with "Diameter." preferences */
2593 	prefs_register_module_alias("Diameter", diameter_module);
2594 
2595 	prefs_register_range_preference(diameter_module, "sctp.ports",
2596 					"Diameter SCTP Ports",
2597 					"SCTP ports to be decoded as Diameter (default: "
2598 					DEFAULT_DIAMETER_PORT_RANGE ")",
2599 					&global_diameter_sctp_port_range, MAX_SCTP_PORT);
2600 
2601 	/* Desegmentation */
2602 	prefs_register_bool_preference(diameter_module, "desegment",
2603 				       "Reassemble Diameter messages spanning multiple TCP segments",
2604 				       "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments."
2605 				       " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2606 				       &gbl_diameter_desegment);
2607 
2608 	/*  Register some preferences we no longer support, so we can report
2609 	 *  them as obsolete rather than just illegal.
2610 	 */
2611 	prefs_register_obsolete_preference(diameter_module, "version");
2612 	prefs_register_obsolete_preference(diameter_module, "sctp.port");
2613 	prefs_register_obsolete_preference(diameter_module, "command_in_header");
2614 	prefs_register_obsolete_preference(diameter_module, "dictionary.name");
2615 	prefs_register_obsolete_preference(diameter_module, "dictionary.use");
2616 	prefs_register_obsolete_preference(diameter_module, "allow_zero_as_app_id");
2617 	prefs_register_obsolete_preference(diameter_module, "suppress_console_output");
2618 
2619 	/* Register tap */
2620 	diameter_tap = register_tap("diameter");
2621 
2622 	register_srt_table(proto_diameter, NULL, 1, diameterstat_packet, diameterstat_init, NULL);
2623 
2624 } /* proto_register_diameter */
2625 
2626 void
proto_reg_handoff_diameter(void)2627 proto_reg_handoff_diameter(void)
2628 {
2629 	static gboolean Initialized=FALSE;
2630 	static range_t *diameter_sctp_port_range;
2631 
2632 	if (!Initialized) {
2633 		diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
2634 							      proto_diameter);
2635 		diameter_udp_handle = create_dissector_handle(dissect_diameter, proto_diameter);
2636 		data_handle = find_dissector("data");
2637 		eap_handle = find_dissector_add_dependency("eap", proto_diameter);
2638 
2639 		dissector_add_uint("sctp.ppi", DIAMETER_PROTOCOL_ID, diameter_sctp_handle);
2640 
2641 		/* Register special decoding for some AVPs */
2642 
2643 		/* AVP Code: 1 User-Name */
2644 		dissector_add_uint("diameter.base", 1, create_dissector_handle(dissect_diameter_user_name, proto_diameter));
2645 
2646 		/* AVP Code: 79 EAP-Message (defined in RFC 2869, but used for EAP-TTLS, RFC 5281) */
2647 		dissector_add_uint("diameter.base", 79, create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
2648 
2649 		/* AVP Code: 97 Framed-IPv6-Address */
2650 		dissector_add_uint("diameter.base", 97, create_dissector_handle(dissect_diameter_base_framed_ipv6_prefix, proto_diameter));
2651 
2652 		/* AVP Code: 124 MIP6-Feature-Vector */
2653 		dissector_add_uint("diameter.base", 124, create_dissector_handle(dissect_diameter_mip6_feature_vector, proto_diameter));
2654 
2655 		/* AVP Code: 265 Supported-Vendor-Id */
2656 		dissector_add_uint("diameter.base", 265, create_dissector_handle(dissect_diameter_vendor_id, proto_diameter));
2657 
2658 		/* AVP Code: 266 Vendor-Id */
2659 		dissector_add_uint("diameter.base", 266, create_dissector_handle(dissect_diameter_vendor_id, proto_diameter));
2660 
2661 		/* AVP Code: 443 Subscription-Id */
2662 		dissector_add_uint("diameter.base", 443, create_dissector_handle(dissect_diameter_subscription_id, proto_diameter));
2663 
2664 		/* AVP Code: 450 Subscription-Id-Type */
2665 		dissector_add_uint("diameter.base", 450, create_dissector_handle(dissect_diameter_subscription_id_type, proto_diameter));
2666 
2667 		/* AVP Code: 444 Subscription-Id-Data */
2668 		dissector_add_uint("diameter.base", 444, create_dissector_handle(dissect_diameter_subscription_id_data, proto_diameter));
2669 
2670 		/* AVP Code: 458 User-Equipment-Info */
2671 		dissector_add_uint("diameter.base", 458, create_dissector_handle(dissect_diameter_user_equipment_info, proto_diameter));
2672 
2673 		/* AVP Code: 459 User-Equipment-Info-Type */
2674 		dissector_add_uint("diameter.base", 459, create_dissector_handle(dissect_diameter_user_equipment_info_type, proto_diameter));
2675 
2676 		/* AVP Code: 460 User-Equipment-Info-Value */
2677 		dissector_add_uint("diameter.base", 460, create_dissector_handle(dissect_diameter_user_equipment_info_value, proto_diameter));
2678 
2679 		/* AVP Code: 462 EAP-Payload */
2680 		dissector_add_uint("diameter.base", 462, create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
2681 		/* AVP Code: 463 EAP-Reissued-Payload */
2682 		dissector_add_uint("diameter.base", 463, create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
2683 
2684 		/* Register dissector for Experimental result code, with 3GPP2's vendor Id */
2685 		dissector_add_uint("diameter.vnd_exp_res", VENDOR_THE3GPP2, create_dissector_handle(dissect_diameter_3gpp2_exp_res, proto_diameter));
2686 
2687 		dissector_add_uint_range_with_preference("tcp.port", DEFAULT_DIAMETER_PORT_RANGE, diameter_tcp_handle);
2688 		dissector_add_uint_range_with_preference("udp.port", "", diameter_udp_handle);
2689 
2690 		Initialized=TRUE;
2691 	} else {
2692 		dissector_delete_uint_range("sctp.port", diameter_sctp_port_range, diameter_sctp_handle);
2693 		wmem_free(wmem_epan_scope(), diameter_sctp_port_range);
2694 	}
2695 
2696 	/* set port for future deletes */
2697 	diameter_sctp_port_range = range_copy(wmem_epan_scope(), global_diameter_sctp_port_range);
2698 	dissector_add_uint_range("sctp.port", diameter_sctp_port_range, diameter_sctp_handle);
2699 
2700 	exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_7);
2701 
2702 }
2703 
2704 
2705 /*
2706  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2707  *
2708  * Local variables:
2709  * c-basic-offset: 8
2710  * tab-width: 8
2711  * indent-tabs-mode: t
2712  * End:
2713  *
2714  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2715  * :indentSize=8:tabSize=8:noTabs=false:
2716  */
2717