/src/wireshark/epan/dissectors/packet-sctp.c
Line | Count | Source |
1 | | /* packet-sctp.c |
2 | | * Routines for Stream Control Transmission Protocol dissection |
3 | | * Copyright 2000-2012 Michael Tuexen <tuexen [AT] fh-muenster.de> |
4 | | * Copyright 2011-2021 Thomas Dreibholz <dreibh [AT] iem.uni-due.de> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | /* |
13 | | * It should be compliant to |
14 | | * - RFC 2960 |
15 | | * - RFC 3309 |
16 | | * - RFC 3758 |
17 | | * - RFC 4460 |
18 | | * - RFC 4895 |
19 | | * - RFC 4960 |
20 | | * - RFC 5061 |
21 | | * - RFC 6525 |
22 | | * - RFC 7053 |
23 | | * - https://tools.ietf.org/html/draft-stewart-sctp-pktdrprep-02 |
24 | | * - https://www.ietf.org/archive/id/draft-ietf-tsvwg-sctp-zero-checksum-01.html |
25 | | * - https://www.ietf.org/archive/id/draft-ietf-tsvwg-sctp-dtls-chunk-03.html |
26 | | * |
27 | | * Still to do (so stay tuned) |
28 | | * - error checking mode |
29 | | * * padding errors |
30 | | * * length errors |
31 | | * * bundling errors |
32 | | * * value errors |
33 | | * |
34 | | * Reassembly added 2006 by Robin Seggelmann |
35 | | * TSN Tracking by Luis E. G. Ontanon (Feb 2007) |
36 | | * Copyright 2009, Varun Notibala <nbvarun [AT] gmail.com> |
37 | | * |
38 | | * PPID types updated by Thomas Dreibholz (Feb 2011) |
39 | | */ |
40 | | |
41 | | #include "config.h" |
42 | 0 | #define WS_LOG_DOMAIN "sctp" |
43 | | |
44 | | #include <wireshark.h> |
45 | | |
46 | | #include <epan/packet.h> |
47 | | #include <epan/capture_dissectors.h> |
48 | | #include <epan/prefs.h> |
49 | | #include <epan/exceptions.h> |
50 | | #include <epan/exported_pdu.h> |
51 | | #include <epan/addr_resolv.h> |
52 | | #include <epan/uat.h> |
53 | | #include <epan/expert.h> |
54 | | #include <epan/conversation_table.h> |
55 | | #include <epan/show_exception.h> |
56 | | #include <epan/decode_as.h> |
57 | | #include <epan/proto_data.h> |
58 | | #include <epan/tfs.h> |
59 | | #include <epan/iana-info.h> |
60 | | #include <wsutil/array.h> |
61 | | |
62 | | #include <wsutil/crc32.h> |
63 | | #include <wsutil/adler32.h> |
64 | | #include <wsutil/utf8_entities.h> |
65 | | #include <wsutil/str_util.h> |
66 | | #include <wsutil/ws_roundup.h> |
67 | | |
68 | | #include "packet-sctp.h" |
69 | | |
70 | | /* |
71 | | * Based on https://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml |
72 | | * as of February 22, 2021 |
73 | | */ |
74 | | static const value_string sctp_payload_proto_id_values[] = { |
75 | | { NOT_SPECIFIED_PROTOCOL_ID, "not specified" }, |
76 | | { IUA_PAYLOAD_PROTOCOL_ID, "IUA" }, |
77 | | { M2UA_PAYLOAD_PROTOCOL_ID, "M2UA" }, |
78 | | { M3UA_PAYLOAD_PROTOCOL_ID, "M3UA" }, |
79 | | { SUA_PAYLOAD_PROTOCOL_ID, "SUA" }, |
80 | | { M2PA_PAYLOAD_PROTOCOL_ID, "M2PA" }, |
81 | | { V5UA_PAYLOAD_PROTOCOL_ID, "V5UA" }, |
82 | | { H248_PAYLOAD_PROTOCOL_ID, "H.248/MEGACO" }, |
83 | | { BICC_PAYLOAD_PROTOCOL_ID, "BICC/Q.2150.3" }, |
84 | | { TALI_PAYLOAD_PROTOCOL_ID, "TALI" }, |
85 | | { DUA_PAYLOAD_PROTOCOL_ID, "DUA" }, |
86 | | { ASAP_PAYLOAD_PROTOCOL_ID, "ASAP" }, |
87 | | { ENRP_PAYLOAD_PROTOCOL_ID, "ENRP" }, |
88 | | { H323_PAYLOAD_PROTOCOL_ID, "H.323" }, |
89 | | { QIPC_PAYLOAD_PROTOCOL_ID, "Q.IPC/Q.2150.3" }, |
90 | | { SIMCO_PAYLOAD_PROTOCOL_ID, "SIMCO" }, |
91 | | { DDP_SEG_CHUNK_PROTOCOL_ID, "DDP Segment Chunk" }, |
92 | | { DDP_STREAM_SES_CTRL_PROTOCOL_ID, "DDP Stream Session Control" }, |
93 | | { S1AP_PAYLOAD_PROTOCOL_ID, "S1 Application Protocol (S1AP)" }, |
94 | | { RUA_PAYLOAD_PROTOCOL_ID, "RUA" }, |
95 | | { HNBAP_PAYLOAD_PROTOCOL_ID, "HNBAP" }, |
96 | | { FORCES_HP_PAYLOAD_PROTOCOL_ID, "ForCES-HP" }, |
97 | | { FORCES_MP_PAYLOAD_PROTOCOL_ID, "ForCES-MP" }, |
98 | | { FORCES_LP_PAYLOAD_PROTOCOL_ID, "ForCES-LP" }, |
99 | | { SBC_AP_PAYLOAD_PROTOCOL_ID, "SBc-AP" }, |
100 | | { NBAP_PAYLOAD_PROTOCOL_ID, "NBAP" }, |
101 | | { 26, "Unassigned" }, /* Unassigned 26 */ |
102 | | { X2AP_PAYLOAD_PROTOCOL_ID, "X2AP" }, |
103 | | { IRCP_PAYLOAD_PROTOCOL_ID, "IRCP" }, |
104 | | { LCS_AP_PAYLOAD_PROTOCOL_ID, "LCS-AP" }, |
105 | | { MPICH2_PAYLOAD_PROTOCOL_ID, "MPICH2" }, |
106 | | { SABP_PAYLOAD_PROTOCOL_ID, "SABP" }, |
107 | | { FGP_PAYLOAD_PROTOCOL_ID, "Fractal Generator Protocol" }, |
108 | | { PPP_PAYLOAD_PROTOCOL_ID, "Ping Pong Protocol" }, |
109 | | { CALCAPP_PAYLOAD_PROTOCOL_ID, "CalcApp Protocol" }, |
110 | | { SSP_PAYLOAD_PROTOCOL_ID, "Scripting Service Protocol" }, |
111 | | { NPMP_CTRL_PAYLOAD_PROTOCOL_ID, "NetPerfMeter Control" }, |
112 | | { NPMP_DATA_PAYLOAD_PROTOCOL_ID, "NetPerfMeter Data" }, |
113 | | { ECHO_PAYLOAD_PROTOCOL_ID, "Echo" }, |
114 | | { DISCARD_PAYLOAD_PROTOCOL_ID, "Discard" }, |
115 | | { DAYTIME_PAYLOAD_PROTOCOL_ID, "Daytime" }, |
116 | | { CHARGEN_PAYLOAD_PROTOCOL_ID, "Character Generator" }, |
117 | | { PROTO_3GPP_RNA_PROTOCOL_ID, "3GPP RNA" }, |
118 | | { PROTO_3GPP_M2AP_PROTOCOL_ID, "3GPP M2AP" }, |
119 | | { PROTO_3GPP_M3AP_PROTOCOL_ID, "3GPP M3AP" }, |
120 | | { SSH_PAYLOAD_PROTOCOL_ID, "SSH" }, |
121 | | { DIAMETER_PROTOCOL_ID, "DIAMETER" }, |
122 | | { DIAMETER_DTLS_PROTOCOL_ID, "DIAMETER over DTLS" }, |
123 | | { R14P_BER_PROTOCOL_ID, "R14P" }, |
124 | | { GDT_PROTOCOL_ID, "Generic Data Transfer Protocol (GDT)" }, |
125 | | { WEBRTC_DCEP_PROTOCOL_ID, "WebRTC Control" }, |
126 | | { WEBRTC_STRING_PAYLOAD_PROTOCOL_ID, "WebRTC String" }, |
127 | | { WEBRTC_BINARY_PARTIAL_PAYLOAD_PROTOCOL_ID, "WebRTC Binary Partial (Deprecated)" }, |
128 | | { WEBRTC_BINARY_PAYLOAD_PROTOCOL_ID, "WebRTC Binary" }, |
129 | | { WEBRTC_STRING_PARTIAL_PAYLOAD_PROTOCOL_ID, "WebRTC String Partial (Deprecated)" }, |
130 | | { PROTO_3GPP_PUA_PAYLOAD_PROTOCOL_ID, "3GPP PUA" }, |
131 | | { WEBRTC_STRING_EMPTY_PAYLOAD_PROTOCOL_ID, "WebRTC String Empty" }, |
132 | | { WEBRTC_BINARY_EMPTY_PAYLOAD_PROTOCOL_ID, "WebRTC Binary Empty" }, |
133 | | { XWAP_PROTOCOL_ID, "XwAP" }, |
134 | | { XW_CONTROL_PLANE_PROTOCOL_ID, "Xw - Control Plane" }, |
135 | | { NGAP_PROTOCOL_ID, "NGAP" }, |
136 | | { XNAP_PROTOCOL_ID, "XnAP" }, |
137 | | { F1AP_PROTOCOL_ID, "F1 AP" }, |
138 | | { ELE2_PROTOCOL_ID, "ELE2 Lawful Interception" }, |
139 | | { NGAP_OVER_DTLS_PROTOCOL_ID, "NGAP over DTLS" }, |
140 | | { XNAP_OVER_DTLS_PROTOCOL_ID, "XnAP over DTLS" }, |
141 | | { F1AP_OVER_DTLS_PROTOCOL_ID, "F1AP over DTLS" }, |
142 | | { E1AP_OVER_DTLS_PROTOCOL_ID, "E1AP over DTLS" }, |
143 | | { E2_CP_PROTOCOL_ID, "E2-CP" }, |
144 | | { E2_UP_PROTOCOL_ID, "E2-UP" }, |
145 | | { E2_DU_PROTOCOL_ID, "E2-DU" }, |
146 | | { W1AP_PROTOCOL_ID, "W1AP" }, |
147 | | { DTLS_CHUNK_KM_MESSAGES_PAYLOAD_PROTOCOL_ID, "DTLS chunk KM" }, |
148 | | |
149 | | { 0, NULL } }; |
150 | | |
151 | | |
152 | | value_string_ext sctpppid_val_ext = VALUE_STRING_EXT_INIT(sctp_payload_proto_id_values); |
153 | | |
154 | | #define LT(x, y) ((int32_t)((x) - (y)) < 0) |
155 | | |
156 | 32 | #define UDP_TUNNELING_PORT 9899 |
157 | | |
158 | 99.1k | #define MAX_NUMBER_OF_PPIDS 2 |
159 | | /** This is a valid PPID, but we use it to mark the end of the list */ |
160 | 39.0k | #define LAST_PPID 0xffffffff |
161 | | |
162 | | void proto_register_sctp(void); |
163 | | void proto_reg_handoff_sctp(void); |
164 | | |
165 | | /* Initialize the protocol and registered fields */ |
166 | | static int proto_sctp; |
167 | | static int hf_port; |
168 | | static int hf_source_port; |
169 | | static int hf_destination_port; |
170 | | static int hf_verification_tag; |
171 | | static int hf_checksum; |
172 | | static int hf_checksum_adler; |
173 | | static int hf_checksum_crc32c; |
174 | | static int hf_checksum_status; |
175 | | |
176 | | static int hf_chunk; |
177 | | static int hf_chunk_type; |
178 | | static int hf_chunk_flags; |
179 | | static int hf_chunk_bit_1; |
180 | | static int hf_chunk_bit_2; |
181 | | static int hf_chunk_length; |
182 | | static int hf_chunk_padding; |
183 | | static int hf_chunk_value; |
184 | | |
185 | | static int hf_initiate_tag; |
186 | | static int hf_init_chunk_initiate_tag; |
187 | | static int hf_init_chunk_adv_rec_window_credit; |
188 | | static int hf_init_chunk_number_of_outbound_streams; |
189 | | static int hf_init_chunk_number_of_inbound_streams; |
190 | | static int hf_init_chunk_initial_tsn; |
191 | | |
192 | | static int hf_initack_chunk_initiate_tag; |
193 | | static int hf_initack_chunk_adv_rec_window_credit; |
194 | | static int hf_initack_chunk_number_of_outbound_streams; |
195 | | static int hf_initack_chunk_number_of_inbound_streams; |
196 | | static int hf_initack_chunk_initial_tsn; |
197 | | |
198 | | static int hf_data_chunk_tsn; |
199 | | static int hf_data_chunk_tsn_raw; |
200 | | static int hf_data_chunk_stream_id; |
201 | | static int hf_data_chunk_stream_seq_number; |
202 | | static int hf_data_chunk_payload_proto_id; |
203 | | static int hf_idata_chunk_reserved; |
204 | | static int hf_idata_chunk_mid; |
205 | | static int hf_idata_chunk_fsn; |
206 | | |
207 | | static int hf_data_chunk_e_bit; |
208 | | static int hf_data_chunk_b_bit; |
209 | | static int hf_data_chunk_u_bit; |
210 | | static int hf_data_chunk_i_bit; |
211 | | |
212 | | static int hf_sack_chunk_ns; |
213 | | static int hf_sack_chunk_cumulative_tsn_ack; |
214 | | static int hf_sack_chunk_cumulative_tsn_ack_raw; |
215 | | static int hf_sack_chunk_adv_rec_window_credit; |
216 | | static int hf_sack_chunk_number_of_gap_blocks; |
217 | | static int hf_sack_chunk_number_of_dup_tsns; |
218 | | static int hf_sack_chunk_gap_block_start; |
219 | | static int hf_sack_chunk_gap_block_end; |
220 | | static int hf_sack_chunk_gap_block_start_tsn; |
221 | | static int hf_sack_chunk_gap_block_end_tsn; |
222 | | static int hf_sack_chunk_number_tsns_gap_acked; |
223 | | static int hf_sack_chunk_duplicate_tsn; |
224 | | |
225 | | static int hf_nr_sack_chunk_ns; |
226 | | static int hf_nr_sack_chunk_cumulative_tsn_ack; |
227 | | static int hf_nr_sack_chunk_adv_rec_window_credit; |
228 | | static int hf_nr_sack_chunk_number_of_gap_blocks; |
229 | | static int hf_nr_sack_chunk_number_of_nr_gap_blocks; |
230 | | static int hf_nr_sack_chunk_number_of_dup_tsns; |
231 | | static int hf_nr_sack_chunk_reserved; |
232 | | static int hf_nr_sack_chunk_gap_block_start; |
233 | | static int hf_nr_sack_chunk_gap_block_end; |
234 | | static int hf_nr_sack_chunk_gap_block_start_tsn; |
235 | | static int hf_nr_sack_chunk_gap_block_end_tsn; |
236 | | static int hf_nr_sack_chunk_number_tsns_gap_acked; |
237 | | static int hf_nr_sack_chunk_nr_gap_block_start; |
238 | | static int hf_nr_sack_chunk_nr_gap_block_end; |
239 | | static int hf_nr_sack_chunk_nr_gap_block_start_tsn; |
240 | | static int hf_nr_sack_chunk_nr_gap_block_end_tsn; |
241 | | static int hf_nr_sack_chunk_number_tsns_nr_gap_acked; |
242 | | static int hf_nr_sack_chunk_duplicate_tsn; |
243 | | |
244 | | static int hf_shutdown_chunk_cumulative_tsn_ack; |
245 | | static int hf_cookie; |
246 | | static int hf_cwr_chunk_lowest_tsn; |
247 | | |
248 | | static int hf_ecne_chunk_lowest_tsn; |
249 | | static int hf_abort_chunk_t_bit; |
250 | | static int hf_shutdown_complete_chunk_t_bit; |
251 | | |
252 | | static int hf_parameter_type; |
253 | | static int hf_parameter_length; |
254 | | static int hf_parameter_value; |
255 | | static int hf_parameter_padding; |
256 | | static int hf_parameter_bit_1; |
257 | | static int hf_parameter_bit_2; |
258 | | static int hf_ipv4_address; |
259 | | static int hf_ipv6_address; |
260 | | static int hf_heartbeat_info; |
261 | | static int hf_state_cookie; |
262 | | static int hf_cookie_preservative_increment; |
263 | | static int hf_hostname; |
264 | | static int hf_supported_address_type; |
265 | | static int hf_stream_reset_req_seq_nr; |
266 | | static int hf_stream_reset_rsp_seq_nr; |
267 | | static int hf_senders_last_assigned_tsn; |
268 | | static int hf_senders_next_tsn; |
269 | | static int hf_receivers_next_tsn; |
270 | | static int hf_stream_reset_rsp_result; |
271 | | static int hf_stream_reset_sid; |
272 | | static int hf_add_outgoing_streams_number_streams; |
273 | | static int hf_add_outgoing_streams_reserved; |
274 | | static int hf_add_incoming_streams_number_streams; |
275 | | static int hf_add_incoming_streams_reserved; |
276 | | |
277 | | static int hf_zero_checksum_edmid; |
278 | | |
279 | | static int hf_random_number; |
280 | | static int hf_chunks_to_auth; |
281 | | static int hf_hmac_id; |
282 | | static int hf_hmac; |
283 | | static int hf_shared_key_id; |
284 | | static int hf_supported_chunk_type; |
285 | | |
286 | | static int hf_dtls_km_tiebreaker; |
287 | | static int hf_dtls_km_flags; |
288 | | static int hf_dtls_km_c_bit; |
289 | | static int hf_dtls_km_s_bit; |
290 | | static int hf_dtls_km_r_bit; |
291 | | static int hf_dtls_km_id; |
292 | | |
293 | | static int hf_cause_code; |
294 | | static int hf_cause_length; |
295 | | static int hf_cause_padding; |
296 | | static int hf_cause_info; |
297 | | |
298 | | static int hf_cause_stream_identifier; |
299 | | static int hf_cause_reserved; |
300 | | |
301 | | static int hf_cause_number_of_missing_parameters; |
302 | | static int hf_cause_missing_parameter_type; |
303 | | |
304 | | static int hf_cause_measure_of_staleness; |
305 | | |
306 | | static int hf_cause_tsn; |
307 | | |
308 | | static int hf_forward_tsn_chunk_tsn; |
309 | | static int hf_forward_tsn_chunk_sid; |
310 | | static int hf_forward_tsn_chunk_ssn; |
311 | | |
312 | | static int hf_i_forward_tsn_chunk_tsn; |
313 | | static int hf_i_forward_tsn_chunk_sid; |
314 | | static int hf_i_forward_tsn_chunk_flags; |
315 | | static int hf_i_forward_tsn_chunk_res; |
316 | | static int hf_i_forward_tsn_chunk_u_bit; |
317 | | static int hf_i_forward_tsn_chunk_mid; |
318 | | |
319 | | static int hf_asconf_ack_seq_nr; |
320 | | static int hf_asconf_seq_nr; |
321 | | static int hf_correlation_id; |
322 | | |
323 | | static int hf_dtls_chunk_r_bit; |
324 | | |
325 | | static int hf_adap_indication; |
326 | | |
327 | | static int hf_pktdrop_chunk_m_bit; |
328 | | static int hf_pktdrop_chunk_b_bit; |
329 | | static int hf_pktdrop_chunk_t_bit; |
330 | | static int hf_pktdrop_chunk_bandwidth; |
331 | | static int hf_pktdrop_chunk_queuesize; |
332 | | static int hf_pktdrop_chunk_truncated_length; |
333 | | static int hf_pktdrop_chunk_reserved; |
334 | | static int hf_pktdrop_chunk_data_field; |
335 | | |
336 | | static int hf_pad_chunk_padding_data; |
337 | | |
338 | | static int hf_sctp_reassembled_in; |
339 | | static int hf_sctp_duplicate; |
340 | | static int hf_sctp_fragments; |
341 | | static int hf_sctp_fragment; |
342 | | |
343 | | static int hf_sctp_retransmission; |
344 | | static int hf_sctp_retransmitted; |
345 | | static int hf_sctp_retransmitted_count; |
346 | | static int hf_sctp_data_rtt; |
347 | | static int hf_sctp_sack_rtt; |
348 | | static int hf_sctp_rto; |
349 | | static int hf_sctp_ack_tsn; |
350 | | static int hf_sctp_ack_frame; |
351 | | static int hf_sctp_acked; |
352 | | static int hf_sctp_retransmitted_after_ack; |
353 | | |
354 | | static int hf_sctp_assoc_index; |
355 | | |
356 | | static dissector_table_t sctp_port_dissector_table; |
357 | | static dissector_table_t sctp_ppi_dissector_table; |
358 | | static heur_dissector_list_t sctp_heur_subdissector_list; |
359 | | static int sctp_tap; |
360 | | static int exported_pdu_tap; |
361 | | |
362 | | /* Initialize the subtree pointers */ |
363 | | static int ett_sctp; |
364 | | static int ett_sctp_chunk; |
365 | | static int ett_sctp_chunk_parameter; |
366 | | static int ett_sctp_chunk_cause; |
367 | | static int ett_sctp_chunk_type; |
368 | | static int ett_sctp_data_chunk_flags; |
369 | | static int ett_sctp_sack_chunk_flags; |
370 | | static int ett_sctp_nr_sack_chunk_flags; |
371 | | static int ett_sctp_abort_chunk_flags; |
372 | | static int ett_sctp_shutdown_complete_chunk_flags; |
373 | | static int ett_sctp_pktdrop_chunk_flags; |
374 | | static int ett_sctp_parameter_type; |
375 | | static int ett_sctp_sack_chunk_gap_block; |
376 | | static int ett_sctp_sack_chunk_gap_block_start; |
377 | | static int ett_sctp_sack_chunk_gap_block_end; |
378 | | static int ett_sctp_nr_sack_chunk_gap_block; |
379 | | static int ett_sctp_nr_sack_chunk_gap_block_start; |
380 | | static int ett_sctp_nr_sack_chunk_gap_block_end; |
381 | | static int ett_sctp_nr_sack_chunk_nr_gap_block; |
382 | | static int ett_sctp_nr_sack_chunk_nr_gap_block_start; |
383 | | static int ett_sctp_nr_sack_chunk_nr_gap_block_end; |
384 | | static int ett_sctp_unrecognized_parameter_parameter; |
385 | | static int ett_sctp_i_forward_tsn_chunk_flags; |
386 | | static int ett_sctp_dtls_chunk_flags; |
387 | | |
388 | | static int ett_sctp_fragments; |
389 | | static int ett_sctp_fragment; |
390 | | |
391 | | static int ett_sctp_tsn; |
392 | | static int ett_sctp_ack; |
393 | | static int ett_sctp_acked; |
394 | | static int ett_sctp_tsn_retransmission; |
395 | | static int ett_sctp_tsn_retransmitted_count; |
396 | | static int ett_sctp_tsn_retransmitted; |
397 | | |
398 | | static int ett_sctp_dtls_km_flags; |
399 | | static expert_field ei_sctp_sack_chunk_adv_rec_window_credit; |
400 | | static expert_field ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100; |
401 | | static expert_field ei_sctp_parameter_length; |
402 | | static expert_field ei_sctp_bad_sctp_checksum; |
403 | | static expert_field ei_sctp_tsn_retransmitted_more_than_twice; |
404 | | static expert_field ei_sctp_parameter_padding; |
405 | | static expert_field ei_sctp_retransmitted_after_ack; |
406 | | static expert_field ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100; |
407 | | static expert_field ei_sctp_sack_chunk_gap_block_out_of_order; |
408 | | static expert_field ei_sctp_chunk_length_bad; |
409 | | static expert_field ei_sctp_tsn_retransmitted; |
410 | | static expert_field ei_sctp_sack_chunk_gap_block_malformed; |
411 | | static expert_field ei_sctp_sack_chunk_number_tsns_gap_acked_100; |
412 | | static expert_field ei_sctp_illegal_parameter_occurrence; |
413 | | static expert_field ei_sctp_dtls_km_illegal_number_of_ids; |
414 | | |
415 | | static const value_string chunk_type_values[] = { |
416 | | { SCTP_DATA_CHUNK_ID, "DATA" }, |
417 | | { SCTP_INIT_CHUNK_ID, "INIT" }, |
418 | | { SCTP_INIT_ACK_CHUNK_ID, "INIT_ACK" }, |
419 | | { SCTP_SACK_CHUNK_ID, "SACK" }, |
420 | | { SCTP_HEARTBEAT_CHUNK_ID, "HEARTBEAT" }, |
421 | | { SCTP_HEARTBEAT_ACK_CHUNK_ID, "HEARTBEAT_ACK" }, |
422 | | { SCTP_ABORT_CHUNK_ID, "ABORT" }, |
423 | | { SCTP_SHUTDOWN_CHUNK_ID, "SHUTDOWN" }, |
424 | | { SCTP_SHUTDOWN_ACK_CHUNK_ID, "SHUTDOWN_ACK" }, |
425 | | { SCTP_ERROR_CHUNK_ID, "ERROR" }, |
426 | | { SCTP_COOKIE_ECHO_CHUNK_ID, "COOKIE_ECHO" }, |
427 | | { SCTP_COOKIE_ACK_CHUNK_ID, "COOKIE_ACK" }, |
428 | | { SCTP_ECNE_CHUNK_ID, "ECNE" }, |
429 | | { SCTP_CWR_CHUNK_ID, "CWR" }, |
430 | | { SCTP_SHUTDOWN_COMPLETE_CHUNK_ID, "SHUTDOWN_COMPLETE" }, |
431 | | { SCTP_AUTH_CHUNK_ID, "AUTH" }, |
432 | | { SCTP_NR_SACK_CHUNK_ID, "NR_SACK" }, |
433 | | { SCTP_I_DATA_CHUNK_ID, "I_DATA" }, |
434 | | { SCTP_DTLS_CHUNK_ID, "DTLS" }, |
435 | | { SCTP_ASCONF_ACK_CHUNK_ID, "ASCONF_ACK" }, |
436 | | { SCTP_PKTDROP_CHUNK_ID, "PKTDROP" }, |
437 | | { SCTP_RE_CONFIG_CHUNK_ID, "RE_CONFIG" }, |
438 | | { SCTP_PAD_CHUNK_ID, "PAD" }, |
439 | | { SCTP_FORWARD_TSN_CHUNK_ID, "FORWARD_TSN" }, |
440 | | { SCTP_ASCONF_CHUNK_ID, "ASCONF" }, |
441 | | { SCTP_I_FORWARD_TSN_CHUNK_ID, "I_FORWARD_TSN" }, |
442 | | { SCTP_IETF_EXT, "IETF_EXTENSION" }, |
443 | | { 0, NULL } }; |
444 | | |
445 | | |
446 | 774k | #define CHUNK_TYPE_LENGTH 1U |
447 | 622k | #define CHUNK_FLAGS_LENGTH 1U |
448 | 445k | #define CHUNK_LENGTH_LENGTH 2U |
449 | 147k | #define CHUNK_HEADER_LENGTH (CHUNK_TYPE_LENGTH + \ |
450 | 147k | CHUNK_FLAGS_LENGTH + \ |
451 | 147k | CHUNK_LENGTH_LENGTH) |
452 | 711k | #define CHUNK_HEADER_OFFSET 0 |
453 | 655k | #define CHUNK_TYPE_OFFSET CHUNK_HEADER_OFFSET |
454 | 509k | #define CHUNK_FLAGS_OFFSET (CHUNK_TYPE_OFFSET + CHUNK_TYPE_LENGTH) |
455 | 371k | #define CHUNK_LENGTH_OFFSET (CHUNK_FLAGS_OFFSET + CHUNK_FLAGS_LENGTH) |
456 | 261k | #define CHUNK_VALUE_OFFSET (CHUNK_LENGTH_OFFSET + CHUNK_LENGTH_LENGTH) |
457 | | |
458 | 2.91k | #define PARAMETER_TYPE_LENGTH 2 |
459 | 1.07k | #define PARAMETER_LENGTH_LENGTH 2 |
460 | 310 | #define PARAMETER_HEADER_LENGTH (PARAMETER_TYPE_LENGTH + PARAMETER_LENGTH_LENGTH) |
461 | | |
462 | 3.50k | #define PARAMETER_HEADER_OFFSET 0 |
463 | 3.09k | #define PARAMETER_TYPE_OFFSET PARAMETER_HEADER_OFFSET |
464 | 1.65k | #define PARAMETER_LENGTH_OFFSET (PARAMETER_TYPE_OFFSET + PARAMETER_TYPE_LENGTH) |
465 | 445 | #define PARAMETER_VALUE_OFFSET (PARAMETER_LENGTH_OFFSET + PARAMETER_LENGTH_LENGTH) |
466 | | |
467 | 432k | #define SOURCE_PORT_LENGTH 2 |
468 | 305k | #define DESTINATION_PORT_LENGTH 2 |
469 | 178k | #define VERIFICATION_TAG_LENGTH 4 |
470 | 71.3k | #define CHECKSUM_LENGTH 4 |
471 | 71.3k | #define COMMON_HEADER_LENGTH (SOURCE_PORT_LENGTH + \ |
472 | 71.3k | DESTINATION_PORT_LENGTH + \ |
473 | 71.3k | VERIFICATION_TAG_LENGTH + \ |
474 | 71.3k | CHECKSUM_LENGTH) |
475 | 416k | #define SOURCE_PORT_OFFSET 0 |
476 | 289k | #define DESTINATION_PORT_OFFSET (SOURCE_PORT_OFFSET + SOURCE_PORT_LENGTH) |
477 | 162k | #define VERIFICATION_TAG_OFFSET (DESTINATION_PORT_OFFSET + DESTINATION_PORT_LENGTH) |
478 | 71.3k | #define CHECKSUM_OFFSET (VERIFICATION_TAG_OFFSET + VERIFICATION_TAG_LENGTH) |
479 | | |
480 | 71.3k | #define SCTP_CHECKSUM_NONE 0 |
481 | 16 | #define SCTP_CHECKSUM_ADLER32 1 |
482 | 16 | #define SCTP_CHECKSUM_CRC32C 2 |
483 | 16 | #define SCTP_CHECKSUM_AUTOMATIC 3 |
484 | | |
485 | | #define FORWARD_STREAM 0 |
486 | | #define BACKWARD_STREAM 1 |
487 | | #define FORWARD_ADD_FORWARD_VTAG 2 |
488 | | #define BACKWARD_ADD_FORWARD_VTAG 3 |
489 | | #define BACKWARD_ADD_BACKWARD_VTAG 4 |
490 | 19.9k | #define ASSOC_NOT_FOUND 5 |
491 | | |
492 | | /* Default values for preferences */ |
493 | | static bool show_port_numbers = true; |
494 | | static int sctp_checksum = SCTP_CHECKSUM_NONE; |
495 | | static bool enable_tsn_analysis = true; |
496 | | static bool enable_association_indexing; |
497 | | static bool enable_ulp_dissection = true; |
498 | | static bool use_reassembly = true; |
499 | | static bool show_always_control_chunks = true; |
500 | | static bool show_relative_tsns = true; |
501 | | |
502 | | /* Data types and functions for generation/handling of chunk types for chunk statistics */ |
503 | | |
504 | | static const value_string chunk_enabled[] = { |
505 | | {0,"Show"}, |
506 | | {1,"Hide"}, |
507 | | {0, NULL} |
508 | | }; |
509 | | typedef struct _type_field_t { |
510 | | unsigned type_id; |
511 | | char* type_name; |
512 | | unsigned type_enable; |
513 | | } type_field_t; |
514 | | |
515 | | static type_field_t* type_fields; |
516 | | static unsigned num_type_fields; |
517 | | |
518 | | typedef struct _assoc_info_t { |
519 | | uint16_t assoc_index; |
520 | | uint16_t direction; |
521 | | address saddr; |
522 | | address daddr; |
523 | | uint16_t sport; |
524 | | uint16_t dport; |
525 | | uint32_t verification_tag1; |
526 | | uint32_t verification_tag2; |
527 | | } assoc_info_t; |
528 | | |
529 | | typedef struct _infodata_t { |
530 | | uint16_t assoc_index; |
531 | | uint16_t direction; |
532 | | } infodata_t; |
533 | | |
534 | | static wmem_map_t *assoc_info_half_map; |
535 | | static wmem_map_t *assoc_info_map; |
536 | | static unsigned num_assocs; |
537 | | |
538 | 0 | UAT_CSTRING_CB_DEF(type_fields, type_name, type_field_t) |
539 | 0 | UAT_VS_DEF(type_fields, type_enable, type_field_t, unsigned, 0, "Show") Unexecuted instantiation: packet-sctp.c:type_fields_type_enable_set_cb Unexecuted instantiation: packet-sctp.c:type_fields_type_enable_tostr_cb |
540 | 0 | UAT_DEC_CB_DEF(type_fields, type_id, type_field_t) Unexecuted instantiation: packet-sctp.c:type_fields_type_id_set_cb Unexecuted instantiation: packet-sctp.c:type_fields_type_id_tostr_cb |
541 | | |
542 | | static void *sctp_chunk_type_copy_cb(void* n, const void* o, size_t siz _U_) |
543 | 0 | { |
544 | 0 | type_field_t* new_rec = (type_field_t*)n; |
545 | 0 | const type_field_t* old_rec = (const type_field_t*)o; |
546 | 0 | new_rec->type_name = g_strdup(old_rec->type_name); |
547 | |
|
548 | 0 | return new_rec; |
549 | 0 | } |
550 | | |
551 | | static void |
552 | | sctp_chunk_type_free_cb(void* r) |
553 | 0 | { |
554 | 0 | type_field_t* rec = (type_field_t*)r; |
555 | 0 | g_free(rec->type_name); |
556 | 0 | } |
557 | | |
558 | | static bool |
559 | | sctp_chunk_type_update_cb(void *r, char **err) |
560 | 0 | { |
561 | 0 | type_field_t *rec = (type_field_t *)r; |
562 | 0 | char c; |
563 | 0 | if (rec->type_name == NULL) { |
564 | 0 | *err = g_strdup("Header name can't be empty"); |
565 | 0 | return false; |
566 | 0 | } |
567 | | |
568 | 0 | g_strstrip(rec->type_name); |
569 | 0 | if (rec->type_name[0] == 0) { |
570 | 0 | *err = g_strdup("Header name can't be empty"); |
571 | 0 | return false; |
572 | 0 | } |
573 | | |
574 | | /* Check for invalid characters (to avoid asserting out when |
575 | | * registering the field). |
576 | | */ |
577 | 0 | c = proto_check_field_name(rec->type_name); |
578 | 0 | if (c) { |
579 | 0 | *err = ws_strdup_printf("Header name can't contain '%c'", c); |
580 | 0 | return false; |
581 | 0 | } |
582 | | |
583 | 0 | *err = NULL; |
584 | 0 | return true; |
585 | 0 | } |
586 | | |
587 | | static dissector_handle_t sctp_handle; |
588 | | |
589 | | static struct _sctp_info sctp_info; |
590 | | |
591 | | static bool |
592 | | sctp_vtag_match(uint32_t vtag1, uint32_t vtag2) |
593 | 0 | { |
594 | | /* If zero (unknown) tags match anything. Nonzero tags must be the same. */ |
595 | 0 | if (vtag1 != 0) { |
596 | 0 | return (vtag1 == vtag2 || vtag2 == 0); |
597 | 0 | } |
598 | 0 | return true; |
599 | 0 | } |
600 | | |
601 | | static assoc_info_t* |
602 | | sctp_assoc_reverse(wmem_allocator_t *scope, const assoc_info_t *assoc) |
603 | 0 | { |
604 | 0 | assoc_info_t *new_assoc; |
605 | |
|
606 | 0 | new_assoc = wmem_new(scope, assoc_info_t); |
607 | 0 | new_assoc->assoc_index = assoc->assoc_index; |
608 | 0 | new_assoc->direction = (assoc->direction == 1) ? 2 : 1; |
609 | 0 | copy_address_shallow(&new_assoc->saddr, &assoc->daddr); |
610 | 0 | copy_address_shallow(&new_assoc->daddr, &assoc->saddr); |
611 | 0 | new_assoc->sport = assoc->dport; |
612 | 0 | new_assoc->dport = assoc->sport; |
613 | 0 | new_assoc->verification_tag1 = assoc->verification_tag2; |
614 | 0 | new_assoc->verification_tag2 = assoc->verification_tag1; |
615 | |
|
616 | 0 | return new_assoc; |
617 | 0 | } |
618 | | |
619 | | static unsigned |
620 | | sctp_assoc_half_hash(const void *key) |
621 | 0 | { |
622 | 0 | const assoc_info_t *k = (const assoc_info_t *)key; |
623 | | |
624 | | /* Add the ports so that the hash is the same regardless of direction */ |
625 | 0 | return g_direct_hash(GUINT_TO_POINTER(k->sport + k->dport)); |
626 | 0 | } |
627 | | |
628 | | static unsigned |
629 | | sctp_assoc_hash(const void *key) |
630 | 0 | { |
631 | 0 | const assoc_info_t *k = (const assoc_info_t *)key; |
632 | | |
633 | | // When inserting in this map, we know we have both vtags. |
634 | | // Hash via the first one (we expect vtag collisions will be low.) |
635 | | // When looking up with a entry from a packet that only has one vtag, |
636 | | // we'll reverse the temporary key as necessary. |
637 | 0 | return g_int_hash(&k->verification_tag1); |
638 | 0 | } |
639 | | |
640 | | /* Association comparison strategy: |
641 | | * 1. Ports MUST match. |
642 | | * 2. Assume vtag collisions are rare compared to multihoming. Thus: |
643 | | * 3. If we have already discovered the vtags on both sides (e.g., with an |
644 | | * INIT ACK, which contains both sides) and the ports match, don't require |
645 | | * address matches. |
646 | | * 4. If we have two keys each with 1 matching vtag in the same direction (and |
647 | | * the other vtag 0), don't require address matches; if there are new addresses |
648 | | * assume it's multihoming. |
649 | | * 5. However, if we have two keys each with 1 vtag (and the other tag 0) |
650 | | * that are different but could be the two vtags of one association |
651 | | * (e.g., two unmatched DATA chunks in the opposite direction, or an INIT |
652 | | * and a DATA in the same direction) require address matching. Otherwise |
653 | | * we'll make likely spurious matches. |
654 | | * 6. Don't worry about odd possibilities like both sides of an association |
655 | | * choosing the same vtag. |
656 | | * 7. We ought to track additional addresses given in INIT, INIT ACK, ASCONF. |
657 | | * If we do, we could have an option of more strict association matching |
658 | | * that uses the addresses in all cases and is more similar to what SCTP |
659 | | * stacks actually do. We'd have to store a list/map/set of known source |
660 | | * and destination addresses instead of just one each. This would fail in |
661 | | * the case of multihoming and where we missed the configuration messages |
662 | | * setting up multihoming. |
663 | | */ |
664 | | |
665 | | static gboolean |
666 | | sctp_assoc_half_equal(const void *key1, const void *key2) |
667 | 0 | { |
668 | 0 | const assoc_info_t *a = (const assoc_info_t *)key1; |
669 | 0 | const assoc_info_t *b = (const assoc_info_t *)key2; |
670 | | |
671 | | /* Matching for associations where for the entries already in the table |
672 | | * only have one vtag, and have zero for the other direction. (For an |
673 | | * new INIT ACK, we know both directions.) |
674 | | */ |
675 | |
|
676 | 0 | if (a->sport == b->sport && a->dport == b->dport) { |
677 | | // Forward match |
678 | 0 | if ((a->verification_tag1 == 0 || b->verification_tag1 == 0) && |
679 | 0 | (a->verification_tag2 == 0 || b->verification_tag2 == 0)) { |
680 | | // Possible INIT and DATA in the same direction, where we didn't get |
681 | | // the INIT ACK. Call it a match if the addresses match. |
682 | 0 | if (addresses_equal(&a->saddr, &b->saddr) && addresses_equal(&a->daddr, &b->daddr)) { |
683 | 0 | return TRUE; |
684 | 0 | } |
685 | 0 | } else if (sctp_vtag_match(a->verification_tag1, b->verification_tag1) && |
686 | 0 | sctp_vtag_match(a->verification_tag2, b->verification_tag2)) { |
687 | 0 | return TRUE; |
688 | 0 | } |
689 | 0 | } |
690 | 0 | if (a->sport == b->dport && a->dport == b->sport) { |
691 | | // Reverse direction (not an else so we can handle identical ports) |
692 | 0 | if ((a->verification_tag1 == 0 || b->verification_tag2 == 0) && |
693 | 0 | (a->verification_tag2 == 0 || b->verification_tag1 == 0)) { |
694 | | // Possible two DATAs chunks in the opposite direction, where we |
695 | | // didn't get the INIT ACK. Call it a match if the addresses match. |
696 | 0 | if (addresses_equal(&a->saddr, &b->daddr) && addresses_equal(&a->daddr, &b->saddr)) { |
697 | 0 | return TRUE; |
698 | 0 | } |
699 | 0 | } else if (sctp_vtag_match(a->verification_tag1, b->verification_tag2) && |
700 | 0 | sctp_vtag_match(a->verification_tag2, b->verification_tag1)) { |
701 | 0 | return TRUE; |
702 | 0 | } |
703 | 0 | } |
704 | | |
705 | 0 | return FALSE; |
706 | 0 | } |
707 | | |
708 | | static gboolean |
709 | | sctp_assoc_equal(const void *key1, const void *key2) |
710 | 0 | { |
711 | 0 | const assoc_info_t *a = (const assoc_info_t *)key1; |
712 | 0 | const assoc_info_t *b = (const assoc_info_t *)key2; |
713 | | |
714 | | /* |
715 | | * Matching for associations where for the entries already in the map |
716 | | * we know the vtags in each direction. |
717 | | * We will not check addresses. |
718 | | */ |
719 | |
|
720 | 0 | if (a->sport == b->sport && a->dport == b->dport) { |
721 | | // Forward match |
722 | | // ASSERTION: at least one of the verification tags must be nonzero. |
723 | 0 | if (sctp_vtag_match(a->verification_tag1, b->verification_tag1) && |
724 | 0 | sctp_vtag_match(a->verification_tag2, b->verification_tag2)) { |
725 | 0 | return TRUE; |
726 | 0 | } |
727 | 0 | } |
728 | 0 | if (a->sport == b->dport && a->dport == b->sport) { |
729 | | // Reverse direction (not an else so we can handle identical ports) |
730 | 0 | if (sctp_vtag_match(a->verification_tag1, b->verification_tag2) && |
731 | 0 | sctp_vtag_match(a->verification_tag2, b->verification_tag1)) { |
732 | 0 | return TRUE; |
733 | 0 | } |
734 | 0 | } |
735 | | |
736 | 0 | return FALSE; |
737 | 0 | } |
738 | | |
739 | | static infodata_t |
740 | | find_assoc_index(assoc_info_t* tmpinfo, packet_info *pinfo) |
741 | 0 | { |
742 | 0 | assoc_info_t *info = NULL; |
743 | 0 | infodata_t inf; |
744 | 0 | inf.assoc_index = -1; |
745 | 0 | inf.direction = 1; |
746 | | |
747 | | /* At least one of tmpinfo's vtag1 must be nonzero (both might be, if |
748 | | * it's an INIT ACK.) Lookup in the proper direction(s). |
749 | | */ |
750 | 0 | if (tmpinfo->verification_tag1 != 0) { |
751 | 0 | info = (assoc_info_t*)wmem_map_lookup(assoc_info_map, tmpinfo); |
752 | 0 | if (info) { |
753 | 0 | inf.assoc_index = info->assoc_index; |
754 | 0 | inf.direction = info->direction; |
755 | 0 | return inf; |
756 | 0 | } |
757 | 0 | } |
758 | | |
759 | 0 | if (tmpinfo->verification_tag2 != 0) { |
760 | 0 | info = sctp_assoc_reverse(pinfo->pool, tmpinfo); |
761 | 0 | info = (assoc_info_t*)wmem_map_lookup(assoc_info_map, info); |
762 | 0 | if (info) { |
763 | 0 | inf.assoc_index = info->assoc_index; |
764 | 0 | inf.direction = info->direction == 1 ? 2 : 1; |
765 | 0 | return inf; |
766 | 0 | } |
767 | 0 | } |
768 | | |
769 | 0 | info = (assoc_info_t*)wmem_map_lookup(assoc_info_half_map, tmpinfo); |
770 | 0 | if (info == NULL) { |
771 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
772 | 0 | info = wmem_new(wmem_file_scope(), assoc_info_t); |
773 | 0 | *info = *tmpinfo; |
774 | 0 | copy_address_wmem(wmem_file_scope(), &info->saddr, &tmpinfo->saddr); |
775 | 0 | copy_address_wmem(wmem_file_scope(), &info->daddr, &tmpinfo->daddr); |
776 | 0 | info->assoc_index = num_assocs++; |
777 | 0 | info->direction = 1; |
778 | 0 | inf.assoc_index = info->assoc_index; |
779 | 0 | if (info->verification_tag1 == 0 || info->verification_tag2 == 0) { |
780 | 0 | wmem_map_insert(assoc_info_half_map, info, info); |
781 | 0 | } else { |
782 | 0 | info->direction = 1; |
783 | 0 | wmem_map_insert(assoc_info_map, info, info); |
784 | 0 | info = sctp_assoc_reverse(wmem_file_scope(), info); |
785 | 0 | wmem_map_insert(assoc_info_map, info, info); |
786 | 0 | } |
787 | 0 | } else { |
788 | 0 | ws_info("association not found on second pass"); |
789 | 0 | } |
790 | 0 | } else { |
791 | 0 | inf.assoc_index = info->assoc_index; |
792 | | /* Now figure out why we matched and fill in new information. */ |
793 | 0 | if (info->sport == tmpinfo->dport && |
794 | 0 | sctp_vtag_match(info->verification_tag1, tmpinfo->verification_tag1) && |
795 | 0 | sctp_vtag_match(info->verification_tag2, tmpinfo->verification_tag2)) { |
796 | | /* We already checked the addresses if needed when looking up in the map. */ |
797 | 0 | if (info->verification_tag1 == 0) { |
798 | 0 | info->verification_tag1 = tmpinfo->verification_tag1; |
799 | 0 | } |
800 | 0 | if (info->verification_tag2 == 0) { |
801 | 0 | info->verification_tag2 = tmpinfo->verification_tag2; |
802 | 0 | } |
803 | 0 | } else if (sctp_vtag_match(info->verification_tag1, tmpinfo->verification_tag2) && |
804 | 0 | sctp_vtag_match(info->verification_tag2, tmpinfo->verification_tag1)) { |
805 | | /* We already checked the addresses if needed when looking up in the map. */ |
806 | 0 | inf.direction = 2; |
807 | 0 | if (info->verification_tag1 == 0) { |
808 | 0 | info->verification_tag1 = tmpinfo->verification_tag2; |
809 | 0 | } |
810 | 0 | if (info->verification_tag2 == 0) { |
811 | 0 | info->verification_tag2 = tmpinfo->verification_tag1; |
812 | 0 | } |
813 | 0 | } |
814 | 0 | if (info->verification_tag1 != 0 && info->verification_tag2 != 0) { |
815 | 0 | DISSECTOR_ASSERT(wmem_map_remove(assoc_info_half_map, info) != NULL); |
816 | 0 | wmem_map_insert(assoc_info_map, info, info); |
817 | 0 | info = sctp_assoc_reverse(wmem_file_scope(), info); |
818 | 0 | wmem_map_insert(assoc_info_map, info, info); |
819 | 0 | } |
820 | 0 | } |
821 | |
|
822 | 0 | return inf; |
823 | 0 | } |
824 | | |
825 | | static void |
826 | | sctp_src_prompt(packet_info *pinfo, char *result) |
827 | 0 | { |
828 | 0 | uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num)); |
829 | |
|
830 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "source (%s%u)", UTF8_RIGHTWARDS_ARROW, port); |
831 | 0 | } |
832 | | |
833 | | static void * |
834 | | sctp_src_value(packet_info *pinfo) |
835 | 0 | { |
836 | 0 | return p_get_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num); |
837 | 0 | } |
838 | | |
839 | | static void |
840 | | sctp_dst_prompt(packet_info *pinfo, char *result) |
841 | 0 | { |
842 | 0 | uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num)); |
843 | |
|
844 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "destination (%s%u)", UTF8_RIGHTWARDS_ARROW, port); |
845 | 0 | } |
846 | | |
847 | | static void * |
848 | | sctp_dst_value(packet_info *pinfo) |
849 | 0 | { |
850 | 0 | return p_get_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num); |
851 | 0 | } |
852 | | |
853 | | static void |
854 | | sctp_both_prompt(packet_info *pinfo, char *result) |
855 | 0 | { |
856 | 0 | uint32_t srcport = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num)), |
857 | 0 | destport = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num)); |
858 | |
|
859 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "both (%u%s%u)", srcport, UTF8_LEFT_RIGHT_ARROW, destport); |
860 | 0 | } |
861 | | |
862 | | static void |
863 | | sctp_ppi_prompt1(packet_info *pinfo _U_, char* result) |
864 | 0 | { |
865 | 0 | uint32_t ppid = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 0)); |
866 | |
|
867 | 0 | if (ppid == LAST_PPID) { |
868 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (none)"); |
869 | 0 | } else { |
870 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (%d)", ppid); |
871 | 0 | } |
872 | 0 | } |
873 | | |
874 | | static void |
875 | | sctp_ppi_prompt2(packet_info *pinfo _U_, char* result) |
876 | 0 | { |
877 | 0 | uint32_t ppid = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 1)); |
878 | |
|
879 | 0 | if (ppid == LAST_PPID) { |
880 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (none)"); |
881 | 0 | } else { |
882 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (%d)", ppid); |
883 | 0 | } |
884 | 0 | } |
885 | | |
886 | | static void * |
887 | | sctp_ppi_value1(packet_info *pinfo) |
888 | 0 | { |
889 | 0 | return p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 0); |
890 | 0 | } |
891 | | |
892 | | static void * |
893 | | sctp_ppi_value2(packet_info *pinfo) |
894 | 0 | { |
895 | 0 | return p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 1); |
896 | 0 | } |
897 | | |
898 | | static const char* sctp_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) |
899 | 0 | { |
900 | 0 | if (filter == CONV_FT_SRC_PORT) |
901 | 0 | return "sctp.srcport"; |
902 | | |
903 | 0 | if (filter == CONV_FT_DST_PORT) |
904 | 0 | return "sctp.dstport"; |
905 | | |
906 | 0 | if (filter == CONV_FT_ANY_PORT) |
907 | 0 | return "sctp.port"; |
908 | | |
909 | 0 | if(!conv) { |
910 | 0 | return CONV_FILTER_INVALID; |
911 | 0 | } |
912 | | |
913 | 0 | if (filter == CONV_FT_SRC_ADDRESS) { |
914 | 0 | if (conv->src_address.type == AT_IPv4) |
915 | 0 | return "ip.src"; |
916 | 0 | if (conv->src_address.type == AT_IPv6) |
917 | 0 | return "ipv6.src"; |
918 | 0 | } |
919 | | |
920 | 0 | if (filter == CONV_FT_DST_ADDRESS) { |
921 | 0 | if (conv->dst_address.type == AT_IPv4) |
922 | 0 | return "ip.dst"; |
923 | 0 | if (conv->dst_address.type == AT_IPv6) |
924 | 0 | return "ipv6.dst"; |
925 | 0 | } |
926 | | |
927 | 0 | if (filter == CONV_FT_ANY_ADDRESS) { |
928 | 0 | if (conv->src_address.type == AT_IPv4) |
929 | 0 | return "ip.addr"; |
930 | 0 | if (conv->src_address.type == AT_IPv6) |
931 | 0 | return "ipv6.addr"; |
932 | 0 | } |
933 | | |
934 | 0 | return CONV_FILTER_INVALID; |
935 | 0 | } |
936 | | |
937 | | static ct_dissector_info_t sctp_ct_dissector_info = {&sctp_conv_get_filter_type}; |
938 | | |
939 | | static tap_packet_status |
940 | | sctp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags) |
941 | 0 | { |
942 | 0 | conv_hash_t *hash = (conv_hash_t*) pct; |
943 | 0 | hash->flags = flags; |
944 | |
|
945 | 0 | const struct _sctp_info *sctphdr=(const struct _sctp_info *)vip; |
946 | |
|
947 | 0 | add_conversation_table_data(hash, &sctphdr->ip_src, &sctphdr->ip_dst, |
948 | 0 | sctphdr->sport, sctphdr->dport, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &sctp_ct_dissector_info, CONVERSATION_SCTP); |
949 | | |
950 | |
|
951 | 0 | return TAP_PACKET_REDRAW; |
952 | 0 | } |
953 | | |
954 | | static const char* sctp_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter) |
955 | 0 | { |
956 | 0 | if (filter == CONV_FT_SRC_PORT) |
957 | 0 | return "sctp.srcport"; |
958 | | |
959 | 0 | if (filter == CONV_FT_DST_PORT) |
960 | 0 | return "sctp.dstport"; |
961 | | |
962 | 0 | if (filter == CONV_FT_ANY_PORT) |
963 | 0 | return "sctp.port"; |
964 | | |
965 | 0 | if(!endpoint) { |
966 | 0 | return CONV_FILTER_INVALID; |
967 | 0 | } |
968 | | |
969 | 0 | if (filter == CONV_FT_SRC_ADDRESS) { |
970 | 0 | if (endpoint->myaddress.type == AT_IPv4) |
971 | 0 | return "ip.src"; |
972 | 0 | if (endpoint->myaddress.type == AT_IPv6) |
973 | 0 | return "ipv6.src"; |
974 | 0 | } |
975 | | |
976 | 0 | if (filter == CONV_FT_DST_ADDRESS) { |
977 | 0 | if (endpoint->myaddress.type == AT_IPv4) |
978 | 0 | return "ip.dst"; |
979 | 0 | if (endpoint->myaddress.type == AT_IPv6) |
980 | 0 | return "ipv6.dst"; |
981 | 0 | } |
982 | | |
983 | 0 | if (filter == CONV_FT_ANY_ADDRESS) { |
984 | 0 | if (endpoint->myaddress.type == AT_IPv4) |
985 | 0 | return "ip.addr"; |
986 | 0 | if (endpoint->myaddress.type == AT_IPv6) |
987 | 0 | return "ipv6.addr"; |
988 | 0 | } |
989 | | |
990 | 0 | return CONV_FILTER_INVALID; |
991 | 0 | } |
992 | | |
993 | | static et_dissector_info_t sctp_endpoint_dissector_info = {&sctp_endpoint_get_filter_type}; |
994 | | |
995 | | static tap_packet_status |
996 | | sctp_endpoint_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags) |
997 | 0 | { |
998 | 0 | conv_hash_t *hash = (conv_hash_t*) pit; |
999 | 0 | hash->flags = flags; |
1000 | |
|
1001 | 0 | const struct _sctp_info *sctphdr=(const struct _sctp_info *)vip; |
1002 | | |
1003 | | /* Take two "add" passes per packet, adding for each direction, ensures that all |
1004 | | packets are counted properly (even if address is sending to itself) |
1005 | | XXX - this could probably be done more efficiently inside endpoint_table */ |
1006 | 0 | add_endpoint_table_data(hash, &sctphdr->ip_src, sctphdr->sport, true, 1, pinfo->fd->pkt_len, &sctp_endpoint_dissector_info, ENDPOINT_SCTP); |
1007 | 0 | add_endpoint_table_data(hash, &sctphdr->ip_dst, sctphdr->dport, false, 1, pinfo->fd->pkt_len, &sctp_endpoint_dissector_info, ENDPOINT_SCTP); |
1008 | |
|
1009 | 0 | return TAP_PACKET_REDRAW; |
1010 | 0 | } |
1011 | | |
1012 | | static unsigned int |
1013 | | sctp_adler32(tvbuff_t *tvb, unsigned int len) |
1014 | 0 | { |
1015 | 0 | const uint8_t *buf = tvb_get_ptr(tvb, 0, len); |
1016 | 0 | uint32_t result = 1; |
1017 | |
|
1018 | 0 | result = update_adler32(result, buf, SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH); |
1019 | | /* handle four 0 bytes as checksum */ |
1020 | 0 | result = update_adler32(result, (const uint8_t*)"\0\0\0\0", 4); |
1021 | 0 | result = update_adler32(result, buf+COMMON_HEADER_LENGTH, len-COMMON_HEADER_LENGTH); |
1022 | |
|
1023 | 0 | return result; |
1024 | 0 | } |
1025 | | |
1026 | | static uint32_t |
1027 | | sctp_crc32c(tvbuff_t *tvb, unsigned int len) |
1028 | 0 | { |
1029 | 0 | const uint8_t *buf = tvb_get_ptr(tvb, 0, len); |
1030 | 0 | uint32_t crc32, |
1031 | 0 | zero = 0; |
1032 | 0 | uint32_t result; |
1033 | | |
1034 | | /* CRC for header */ |
1035 | 0 | crc32 = crc32c_calculate_no_swap(buf, SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH, CRC32C_PRELOAD); |
1036 | | |
1037 | | /* handle four 0 bytes as checksum */ |
1038 | 0 | crc32 = crc32c_calculate_no_swap(&zero, 4, crc32); |
1039 | | |
1040 | | /* CRC for the rest of the packet */ |
1041 | 0 | crc32 = crc32c_calculate_no_swap(&buf[COMMON_HEADER_LENGTH], len-COMMON_HEADER_LENGTH, crc32); |
1042 | |
|
1043 | 0 | result = CRC32C_SWAP(crc32); |
1044 | |
|
1045 | 0 | return ( ~result ); |
1046 | 0 | } |
1047 | | |
1048 | | /* |
1049 | | * Routines for dissecting parameters |
1050 | | */ |
1051 | | |
1052 | | typedef struct _sctp_half_assoc_t sctp_half_assoc_t; |
1053 | | |
1054 | | static void dissect_parameter(tvbuff_t *, packet_info *, proto_tree *, proto_item *, bool, bool, bool); |
1055 | | |
1056 | | static void dissect_parameters(tvbuff_t *, packet_info *, proto_tree *, proto_item *, bool, bool); |
1057 | | |
1058 | | static void dissect_error_cause(tvbuff_t *, packet_info *, proto_tree *); |
1059 | | |
1060 | | static void dissect_error_causes(tvbuff_t *, packet_info *, proto_tree *); |
1061 | | |
1062 | | static bool dissect_data_chunk(tvbuff_t*, uint16_t, packet_info*, proto_tree*, proto_tree*, proto_item*, proto_item*, sctp_half_assoc_t*, bool); |
1063 | | |
1064 | | static void dissect_sctp_packet(tvbuff_t *, packet_info *, proto_tree *, bool); |
1065 | | |
1066 | | |
1067 | | /* TSN ANALYSIS CODE */ |
1068 | | |
1069 | | struct _sctp_half_assoc_t { |
1070 | | uint32_t spt; |
1071 | | uint32_t dpt; |
1072 | | uint32_t vtag; |
1073 | | |
1074 | | bool started; |
1075 | | |
1076 | | uint32_t first_tsn; /* start */ |
1077 | | uint32_t cumm_ack; /* rel */ |
1078 | | wmem_tree_t *tsns; /* sctp_tsn_t* by rel_tsn */ |
1079 | | wmem_tree_t *tsn_acks; /* sctp_tsn_t* by ctsn_frame */ |
1080 | | |
1081 | | struct _sctp_half_assoc_t *peer; |
1082 | | }; |
1083 | | |
1084 | | |
1085 | | typedef struct _retransmit_t { |
1086 | | uint32_t framenum; |
1087 | | nstime_t ts; |
1088 | | struct _retransmit_t *next; |
1089 | | } retransmit_t; |
1090 | | |
1091 | | typedef struct _sctp_tsn_t { |
1092 | | uint32_t tsn; |
1093 | | struct { |
1094 | | uint32_t framenum; |
1095 | | nstime_t ts; |
1096 | | } first_transmit; |
1097 | | struct { |
1098 | | uint32_t framenum; |
1099 | | nstime_t ts; |
1100 | | } ack; |
1101 | | retransmit_t *retransmit; |
1102 | | uint32_t retransmit_count; |
1103 | | struct _sctp_tsn_t *next; |
1104 | | } sctp_tsn_t; |
1105 | | |
1106 | | |
1107 | | static wmem_tree_key_t* |
1108 | | make_address_key(wmem_allocator_t *pool, uint32_t spt, uint32_t dpt, address *addr) |
1109 | 30.2k | { |
1110 | 30.2k | wmem_tree_key_t *k = (wmem_tree_key_t *)wmem_alloc(pool, sizeof(wmem_tree_key_t)*6); |
1111 | | |
1112 | 30.2k | k[0].length = 1; k[0].key = (uint32_t*)wmem_memdup(pool, &spt,sizeof(spt)); |
1113 | 30.2k | k[1].length = 1; k[1].key = (uint32_t*)wmem_memdup(pool, &dpt,sizeof(dpt)); |
1114 | 30.2k | k[2].length = 1; k[2].key = (uint32_t*)(void *)&(addr->type); |
1115 | 30.2k | k[3].length = 1; k[3].key = (uint32_t*)(void *)&(addr->len); |
1116 | | |
1117 | 30.2k | k[4].length = ((addr->len/4)+1); |
1118 | 30.2k | k[4].key = (uint32_t*)wmem_alloc0(pool, ((addr->len/4)+1)*4); |
1119 | 30.2k | if (addr->len) memcpy(k[4].key, addr->data, addr->len); |
1120 | | |
1121 | 30.2k | k[5].length = 0; k[5].key = NULL; |
1122 | | |
1123 | 30.2k | return k; |
1124 | 30.2k | } |
1125 | | |
1126 | | static wmem_tree_key_t * |
1127 | | make_dir_key(wmem_allocator_t *pool, uint32_t spt, uint32_t dpt, uint32_t vtag) |
1128 | 15.5k | { |
1129 | 15.5k | wmem_tree_key_t *k = (wmem_tree_key_t *)wmem_alloc(pool, sizeof(wmem_tree_key_t)*4); |
1130 | | |
1131 | 15.5k | k[0].length = 1; k[0].key = (uint32_t*)wmem_memdup(pool, &spt,sizeof(spt)); |
1132 | 15.5k | k[1].length = 1; k[1].key = (uint32_t*)wmem_memdup(pool, &dpt,sizeof(dpt)); |
1133 | 15.5k | k[2].length = 1; k[2].key = (uint32_t*)wmem_memdup(pool, &vtag,sizeof(vtag)); |
1134 | 15.5k | k[3].length = 0; k[3].key = NULL; |
1135 | | |
1136 | 15.5k | return k; |
1137 | 15.5k | } |
1138 | | |
1139 | | |
1140 | | |
1141 | | static wmem_tree_t *dirs_by_ptvtag; /* sctp_half_assoc_t* */ |
1142 | | static wmem_tree_t *dirs_by_ptaddr; /* sctp_half_assoc_t**, it may contain a null pointer */ |
1143 | | |
1144 | | static sctp_half_assoc_t * |
1145 | | get_half_assoc(packet_info *pinfo, uint32_t spt, uint32_t dpt, uint32_t vtag) |
1146 | 35.6k | { |
1147 | 35.6k | sctp_half_assoc_t *ha; |
1148 | 35.6k | sctp_half_assoc_t **hb; |
1149 | 35.6k | wmem_tree_key_t *k; |
1150 | | |
1151 | 35.6k | if (!enable_tsn_analysis || !vtag || pinfo->flags.in_error_pkt) |
1152 | 20.1k | return NULL; |
1153 | | |
1154 | | /* look for the current half_assoc by spt, dpt and vtag */ |
1155 | | |
1156 | 15.5k | k = make_dir_key(pinfo->pool, spt, dpt, vtag); |
1157 | 15.5k | if (( ha = (sctp_half_assoc_t *)wmem_tree_lookup32_array(dirs_by_ptvtag, k) )) { |
1158 | | /* found, if it has been already matched we're done */ |
1159 | 12.6k | if (ha->peer) return ha; |
1160 | 12.6k | } else { |
1161 | | /* not found, make a new one and add it to the table */ |
1162 | 2.93k | ha = wmem_new0(wmem_file_scope(), sctp_half_assoc_t); |
1163 | 2.93k | ha->spt = spt; |
1164 | 2.93k | ha->dpt = dpt; |
1165 | 2.93k | ha->vtag = vtag; |
1166 | 2.93k | ha->tsns = wmem_tree_new(wmem_file_scope()); |
1167 | 2.93k | ha->tsn_acks = wmem_tree_new(wmem_file_scope()); |
1168 | 2.93k | ha->started = false; |
1169 | 2.93k | ha->first_tsn= 0; |
1170 | 2.93k | ha->cumm_ack= 0; |
1171 | | |
1172 | | /* add this half to the table indexed by ports and vtag */ |
1173 | 2.93k | wmem_tree_insert32_array(dirs_by_ptvtag, k, ha); |
1174 | 2.93k | } |
1175 | | |
1176 | | /* at this point we have an unmatched half, look for its other half using the ports and IP address */ |
1177 | 15.1k | k = make_address_key(pinfo->pool, dpt, spt, &(pinfo->dst)); |
1178 | | |
1179 | 15.1k | if (( hb = (sctp_half_assoc_t **)wmem_tree_lookup32_array(dirs_by_ptaddr, k) )) { |
1180 | | /*the table contains a pointer to a pointer to a half */ |
1181 | 140 | if (! *hb) { |
1182 | | /* if there is no half pointed by this, add the current half to the table */ |
1183 | 62 | *hb = ha; |
1184 | 78 | } else { |
1185 | | /* there's a half pointed by this, assume it's our peer and clear the table's pointer */ |
1186 | 78 | ha->peer = *hb; |
1187 | 78 | (*hb)->peer = ha; |
1188 | 78 | *hb = NULL; |
1189 | 78 | } |
1190 | 15.0k | } else { |
1191 | | /* we found no entry in the table: add one (using reversed ports and src addresses) so that it can be matched later */ |
1192 | 15.0k | *(hb = (sctp_half_assoc_t **)wmem_alloc(wmem_file_scope(), sizeof(void*))) = ha; |
1193 | 15.0k | k = make_address_key(pinfo->pool, spt, dpt, &(pinfo->src)); |
1194 | 15.0k | wmem_tree_insert32_array(dirs_by_ptaddr, k, hb); |
1195 | 15.0k | } |
1196 | | |
1197 | 15.1k | return ha; |
1198 | 15.5k | } |
1199 | | |
1200 | | /* Limit the number of retransmissions we track (to limit memory usage--and |
1201 | | * tree size--in pathological cases, for example zero window probing forever). |
1202 | | */ |
1203 | 1.53k | #define MAX_RETRANS_TRACKED_PER_TSN 100 |
1204 | | |
1205 | | static void |
1206 | | tsn_tree(sctp_tsn_t *t, proto_item *tsn_item, packet_info *pinfo, |
1207 | | tvbuff_t *tvb, uint32_t framenum) |
1208 | 609 | { |
1209 | 609 | proto_item *pi; |
1210 | 609 | proto_tree *pt; |
1211 | 609 | proto_tree *tsn_tree_pt = proto_item_add_subtree(tsn_item, ett_sctp_tsn); |
1212 | | |
1213 | 609 | if (t->first_transmit.framenum != framenum) { |
1214 | 216 | nstime_t rto; |
1215 | | |
1216 | 216 | pi = proto_tree_add_uint(tsn_tree_pt, hf_sctp_retransmission, tvb, 0, 0, t->first_transmit.framenum); |
1217 | 216 | pt = proto_item_add_subtree(pi, ett_sctp_tsn_retransmission); |
1218 | 216 | proto_item_set_generated(pi); |
1219 | 216 | expert_add_info(pinfo, pi, &ei_sctp_tsn_retransmitted); |
1220 | | |
1221 | 216 | nstime_delta( &rto, &pinfo->abs_ts, &(t->first_transmit.ts) ); |
1222 | 216 | pi = proto_tree_add_time(pt, hf_sctp_rto, tvb, 0, 0, &rto); |
1223 | 216 | proto_item_set_generated(pi); |
1224 | | |
1225 | | /* Detect reneged acks */ |
1226 | | /* XXX what if the frames aren't sorted by time? */ |
1227 | 216 | if (t->ack.framenum && t->ack.framenum < framenum) |
1228 | 0 | { |
1229 | 0 | pi = proto_tree_add_uint_format(pt, hf_sctp_retransmitted_after_ack, tvb, 0, 0, t->ack.framenum, |
1230 | 0 | "This TSN was acked (in frame %u) prior to this retransmission (reneged ack?)", |
1231 | 0 | t->ack.framenum); |
1232 | 0 | proto_item_set_generated(pi); |
1233 | 0 | expert_add_info(pinfo, pi, &ei_sctp_retransmitted_after_ack); |
1234 | 0 | } |
1235 | 393 | } else if (t->retransmit) { |
1236 | 0 | retransmit_t **r; |
1237 | 0 | nstime_t rto; |
1238 | 0 | char ds[64]; |
1239 | |
|
1240 | 0 | if (t->retransmit_count > MAX_RETRANS_TRACKED_PER_TSN) |
1241 | 0 | snprintf(ds, sizeof(ds), " (only %d displayed)", MAX_RETRANS_TRACKED_PER_TSN); |
1242 | 0 | else |
1243 | 0 | ds[0] = 0; |
1244 | |
|
1245 | 0 | pi = proto_tree_add_uint_format(tsn_tree_pt, |
1246 | 0 | hf_sctp_retransmitted_count, |
1247 | 0 | tvb, 0, 0, t->retransmit_count, |
1248 | 0 | "This TSN was retransmitted %u time%s%s", |
1249 | 0 | t->retransmit_count, |
1250 | 0 | plurality(t->retransmit_count, "", "s"), |
1251 | 0 | ds); |
1252 | 0 | proto_item_set_generated(pi); |
1253 | |
|
1254 | 0 | if (t->retransmit_count > 2) |
1255 | 0 | expert_add_info(pinfo, pi, &ei_sctp_tsn_retransmitted_more_than_twice); |
1256 | |
|
1257 | 0 | pt = proto_item_add_subtree(pi, ett_sctp_tsn_retransmitted_count); |
1258 | |
|
1259 | 0 | r = &t->retransmit; |
1260 | 0 | while (*r) { |
1261 | 0 | nstime_delta(&rto, &((*r)->ts), &pinfo->abs_ts); |
1262 | 0 | pi = proto_tree_add_uint_format(pt, |
1263 | 0 | hf_sctp_retransmitted, |
1264 | 0 | tvb, 0, 0, |
1265 | 0 | (*r)->framenum, |
1266 | 0 | "This TSN was retransmitted in frame %u (%s seconds after this frame)", |
1267 | 0 | (*r)->framenum, |
1268 | 0 | rel_time_to_secs_str(pinfo->pool, &rto)); |
1269 | 0 | proto_item_set_generated(pi); |
1270 | 0 | r = &(*r)->next; |
1271 | 0 | } |
1272 | 0 | } |
1273 | | |
1274 | 609 | if (t->ack.framenum) { |
1275 | 0 | nstime_t rtt; |
1276 | |
|
1277 | 0 | pi = proto_tree_add_uint(tsn_tree_pt, hf_sctp_acked, tvb, 0 , 0, t->ack.framenum); |
1278 | 0 | proto_item_set_generated(pi); |
1279 | 0 | pt = proto_item_add_subtree(pi, ett_sctp_ack); |
1280 | |
|
1281 | 0 | nstime_delta( &rtt, &(t->ack.ts), &(t->first_transmit.ts) ); |
1282 | 0 | pi = proto_tree_add_time(pt, hf_sctp_data_rtt, tvb, 0, 0, &rtt); |
1283 | 0 | proto_item_set_generated(pi); |
1284 | 0 | } |
1285 | 609 | } |
1286 | | |
1287 | 609 | #define RELTSN(tsn) (((tsn) < h->first_tsn) ? (tsn + (0xffffffff - (h->first_tsn)) + 1) : (tsn - h->first_tsn)) |
1288 | | |
1289 | | /* Returns true if the tsn is a retransmission (we've seen it before), false |
1290 | | * otherwise. |
1291 | | */ |
1292 | | static bool |
1293 | | sctp_tsn(packet_info *pinfo, tvbuff_t *tvb, proto_item *tsn_item, |
1294 | | sctp_half_assoc_t *h, uint32_t tsn) |
1295 | 19.4k | { |
1296 | 19.4k | sctp_tsn_t *t; |
1297 | 19.4k | uint32_t framenum; |
1298 | 19.4k | uint32_t reltsn; |
1299 | 19.4k | bool is_retransmission = false; |
1300 | | |
1301 | | /* no half assoc? nothing to do!*/ |
1302 | 19.4k | if (!h) |
1303 | 18.8k | return is_retransmission; |
1304 | | |
1305 | | |
1306 | 609 | framenum = pinfo->num; |
1307 | | |
1308 | | /* If we're dissecting for a read filter in the GUI [tshark assigns |
1309 | | * frame numbers before running the read filter], don't do the TSN |
1310 | | * analysis. (We can't anyway because we don't have a valid frame |
1311 | | * number...) |
1312 | | * |
1313 | | * Without this check if you load a capture file in the |
1314 | | * GUI while using a read filter, every SCTP TSN is marked as a |
1315 | | * retransmission of that in frame 0. |
1316 | | */ |
1317 | 609 | if (framenum == 0) |
1318 | 0 | return is_retransmission; |
1319 | | |
1320 | | /* we have not seen any tsn yet in this half assoc set the ground */ |
1321 | 609 | if (! h->started) { |
1322 | 0 | h->first_tsn = tsn; |
1323 | 0 | h->started = true; |
1324 | 0 | } |
1325 | | |
1326 | | |
1327 | 609 | reltsn = RELTSN(tsn); |
1328 | | |
1329 | | /* printf("%.3d REL TSN: %p->%p [%u] %u \n",framenum,h,h->peer,tsn,reltsn); */ |
1330 | | |
1331 | | /* look for this tsn in this half's tsn table */ |
1332 | 609 | if (! (t = (sctp_tsn_t *)wmem_tree_lookup32(h->tsns,reltsn) )) { |
1333 | | /* no tsn found, create a new one */ |
1334 | 356 | t = wmem_new0(wmem_file_scope(), sctp_tsn_t); |
1335 | 356 | t->tsn = tsn; |
1336 | | |
1337 | 356 | t->first_transmit.framenum = framenum; |
1338 | 356 | t->first_transmit.ts = pinfo->abs_ts; |
1339 | | |
1340 | 356 | wmem_tree_insert32(h->tsns,reltsn,t); |
1341 | 356 | } |
1342 | | |
1343 | 609 | is_retransmission = (t->first_transmit.framenum != framenum); |
1344 | | |
1345 | 609 | if ( (! pinfo->fd->visited ) && is_retransmission ) { |
1346 | 216 | retransmit_t **r; |
1347 | 216 | int i; |
1348 | | |
1349 | 216 | t->retransmit_count++; |
1350 | 216 | r = &t->retransmit; |
1351 | 216 | i = 0; |
1352 | 1.53k | while (*r && i < MAX_RETRANS_TRACKED_PER_TSN) { |
1353 | 1.32k | r = &(*r)->next; |
1354 | 1.32k | i++; |
1355 | 1.32k | } |
1356 | | |
1357 | 216 | if (i <= MAX_RETRANS_TRACKED_PER_TSN) { |
1358 | 216 | *r = wmem_new0(wmem_file_scope(), retransmit_t); |
1359 | 216 | (*r)->framenum = framenum; |
1360 | 216 | (*r)->ts = pinfo->abs_ts; |
1361 | 216 | } |
1362 | 216 | } |
1363 | | |
1364 | 609 | tsn_tree(t, tsn_item, pinfo, tvb, framenum); |
1365 | | |
1366 | 609 | return is_retransmission; |
1367 | 609 | } |
1368 | | |
1369 | | static void |
1370 | | ack_tree(sctp_tsn_t *t, proto_tree *acks_tree, |
1371 | | tvbuff_t *tvb, packet_info *pinfo) |
1372 | 0 | { |
1373 | 0 | proto_item *pi; |
1374 | 0 | proto_tree *pt; |
1375 | 0 | nstime_t rtt; |
1376 | 0 | unsigned framenum = pinfo->num; |
1377 | |
|
1378 | 0 | if ( t->ack.framenum == framenum ) { |
1379 | 0 | nstime_delta( &rtt, &(t->ack.ts), &(t->first_transmit.ts) ); |
1380 | |
|
1381 | 0 | pi = proto_tree_add_uint(acks_tree, hf_sctp_ack_tsn, tvb, 0 , 0, t->tsn); |
1382 | 0 | proto_item_set_generated(pi); |
1383 | |
|
1384 | 0 | pt = proto_item_add_subtree(pi, ett_sctp_acked); |
1385 | |
|
1386 | 0 | pi = proto_tree_add_uint(pt, hf_sctp_ack_frame, tvb, 0 , 0, t->first_transmit.framenum); |
1387 | 0 | proto_item_set_generated(pi); |
1388 | |
|
1389 | 0 | pi = proto_tree_add_time(pt, hf_sctp_sack_rtt, tvb, 0, 0, &rtt); |
1390 | 0 | proto_item_set_generated(pi); |
1391 | 0 | } |
1392 | 0 | } |
1393 | | |
1394 | | static void |
1395 | | sctp_ack(packet_info *pinfo, tvbuff_t *tvb, proto_tree *acks_tree, |
1396 | | sctp_half_assoc_t *h, uint32_t reltsn) |
1397 | 132k | { |
1398 | 132k | sctp_tsn_t *t; |
1399 | 132k | uint32_t framenum; |
1400 | | |
1401 | | |
1402 | 132k | if (!h || !h->peer) |
1403 | 0 | return; |
1404 | | |
1405 | 132k | framenum = pinfo->num; |
1406 | | |
1407 | | /* printf("%.6d ACK: %p->%p [%u] \n",framenum,h,h->peer,reltsn); */ |
1408 | | |
1409 | 132k | t = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsns,reltsn); |
1410 | | |
1411 | 132k | if (t) { |
1412 | 0 | if (! t->ack.framenum) { |
1413 | 0 | sctp_tsn_t *t2; |
1414 | |
|
1415 | 0 | t->ack.framenum = framenum; |
1416 | 0 | t->ack.ts = pinfo->abs_ts; |
1417 | |
|
1418 | 0 | if (( t2 = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsn_acks, framenum) )) { |
1419 | 0 | for(;t2->next;t2 = t2->next) |
1420 | 0 | ; |
1421 | |
|
1422 | 0 | t2->next = t; |
1423 | 0 | } else { |
1424 | 0 | wmem_tree_insert32(h->peer->tsn_acks, framenum,t); |
1425 | 0 | } |
1426 | 0 | } |
1427 | |
|
1428 | 0 | if ( t->ack.framenum == framenum) |
1429 | 0 | ack_tree(t, acks_tree, tvb, pinfo); |
1430 | |
|
1431 | 0 | } /* else { |
1432 | | proto_tree_add_debug_text(acks_tree, tvb, 0 , 0, "Assoc: %p vs %p ?? %ld",h,h->peer,tsn); |
1433 | | } */ |
1434 | 132k | } |
1435 | | |
1436 | 2.23k | #define RELTSNACK(tsn) (((tsn) < h->peer->first_tsn) ? ((tsn) + (0xffffffff - (h->peer->first_tsn)) + 1) : ((tsn) - h->peer->first_tsn)) |
1437 | | static void |
1438 | | sctp_ack_block(packet_info *pinfo, sctp_half_assoc_t *h, tvbuff_t *tvb, |
1439 | | proto_item *acks_tree, const uint32_t *tsn_start_ptr, |
1440 | | uint32_t tsn_end) |
1441 | 5.52k | { |
1442 | 5.52k | sctp_tsn_t *t; |
1443 | 5.52k | uint32_t framenum; |
1444 | 5.52k | uint32_t rel_start; |
1445 | 5.52k | uint32_t rel_end; |
1446 | | |
1447 | | |
1448 | 5.52k | if ( !h || !h->peer || ! h->peer->started ) |
1449 | 4.40k | return; |
1450 | | |
1451 | 1.12k | framenum = pinfo->num; |
1452 | 1.12k | rel_end = RELTSNACK(tsn_end); |
1453 | | |
1454 | 1.12k | if (tsn_start_ptr) { |
1455 | 1.10k | rel_start = RELTSNACK(*tsn_start_ptr); |
1456 | | /* printf("%.3d BACK: %p->%p [%u-%u]\n",framenum,h,h->peer,rel_start,rel_end); */ |
1457 | 1.10k | } else { |
1458 | 22 | rel_start = h->peer->cumm_ack; |
1459 | | /* printf("%.3d CACK: %p->%p [%u-%u]\n",framenum,h,h->peer,rel_start,rel_end); */ |
1460 | 22 | } |
1461 | | |
1462 | | |
1463 | 1.12k | if ((t = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsn_acks, framenum))) { |
1464 | 0 | for(;t;t = t->next) { |
1465 | 0 | uint32_t tsn = t->tsn; |
1466 | |
|
1467 | 0 | tsn -= h->peer->first_tsn; |
1468 | |
|
1469 | 0 | if (t->ack.framenum == framenum && ( (!tsn_start_ptr) || rel_start <= tsn) && tsn <= rel_end) |
1470 | 0 | ack_tree(t, acks_tree, tvb, pinfo); |
1471 | 0 | } |
1472 | |
|
1473 | 0 | return; |
1474 | 0 | } |
1475 | | |
1476 | 1.12k | if (PINFO_FD_VISITED(pinfo) || rel_end < rel_start || rel_end - rel_start > 0xffff0000 ) return; |
1477 | | |
1478 | 784 | if (! tsn_start_ptr ) |
1479 | 5 | h->peer->cumm_ack = rel_end + 1; |
1480 | | |
1481 | 784 | if (rel_start <= rel_end && rel_end - rel_start < 5000 ) { |
1482 | 541 | uint32_t rel_tsn, i; |
1483 | 132k | for (i=0; i <= rel_end-rel_start; i++) { |
1484 | 132k | rel_tsn = (uint32_t) (i+rel_start); |
1485 | 132k | sctp_ack(pinfo, tvb, acks_tree, h, rel_tsn); |
1486 | 132k | } |
1487 | 541 | } |
1488 | 784 | } |
1489 | | |
1490 | | /* END TSN ANALYSIS CODE */ |
1491 | | |
1492 | | |
1493 | | |
1494 | | |
1495 | 9 | #define HEARTBEAT_INFO_PARAMETER_INFO_OFFSET PARAMETER_VALUE_OFFSET |
1496 | | |
1497 | | static void |
1498 | | dissect_heartbeat_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1499 | 9 | { |
1500 | 9 | uint16_t heartbeat_info_length; |
1501 | | |
1502 | 9 | heartbeat_info_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH; |
1503 | 9 | if (heartbeat_info_length > 0) |
1504 | 9 | proto_tree_add_item(parameter_tree, hf_heartbeat_info, parameter_tvb, HEARTBEAT_INFO_PARAMETER_INFO_OFFSET, heartbeat_info_length, ENC_NA); |
1505 | 9 | proto_item_append_text(parameter_item, " (Information: %u byte%s)", heartbeat_info_length, plurality(heartbeat_info_length, "", "s")); |
1506 | 9 | } |
1507 | | |
1508 | 8 | #define IPV4_ADDRESS_LENGTH 4 |
1509 | 8 | #define IPV4_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET |
1510 | | |
1511 | | static void |
1512 | | dissect_ipv4_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item, bool dissecting_init_init_ack_chunk) |
1513 | 8 | { |
1514 | 8 | if (parameter_tree) { |
1515 | 8 | proto_tree_add_item(parameter_tree, hf_ipv4_address, parameter_tvb, IPV4_ADDRESS_OFFSET, IPV4_ADDRESS_LENGTH, ENC_BIG_ENDIAN); |
1516 | 8 | proto_item_append_text(parameter_item, " (Address: %s)", tvb_ip_to_str(pinfo->pool, parameter_tvb, IPV4_ADDRESS_OFFSET)); |
1517 | 8 | if (additional_item) |
1518 | 0 | proto_item_append_text(additional_item, "%s", tvb_ip_to_str(pinfo->pool, parameter_tvb, IPV4_ADDRESS_OFFSET)); |
1519 | 8 | } |
1520 | 8 | if (dissecting_init_init_ack_chunk) { |
1521 | 4 | if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS) |
1522 | 4 | sctp_info.tvb[sctp_info.number_of_tvbs++] = parameter_tvb; |
1523 | 0 | else |
1524 | 0 | sctp_info.incomplete = true; |
1525 | 4 | } |
1526 | 8 | } |
1527 | | |
1528 | 5 | #define IPV6_ADDRESS_LENGTH 16 |
1529 | 5 | #define IPV6_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET |
1530 | | |
1531 | | static void |
1532 | | dissect_ipv6_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item, bool dissecting_init_init_ack_chunk) |
1533 | 5 | { |
1534 | 5 | if (parameter_tree) { |
1535 | 5 | proto_tree_add_item(parameter_tree, hf_ipv6_address, parameter_tvb, IPV6_ADDRESS_OFFSET, IPV6_ADDRESS_LENGTH, ENC_NA); |
1536 | 5 | proto_item_append_text(parameter_item, " (Address: %s)", tvb_ip6_to_str(pinfo->pool, parameter_tvb, IPV6_ADDRESS_OFFSET)); |
1537 | 5 | if (additional_item) |
1538 | 0 | proto_item_append_text(additional_item, "%s", tvb_ip6_to_str(pinfo->pool, parameter_tvb, IPV6_ADDRESS_OFFSET)); |
1539 | 5 | } |
1540 | 5 | if (dissecting_init_init_ack_chunk) { |
1541 | 2 | if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS) |
1542 | 2 | sctp_info.tvb[sctp_info.number_of_tvbs++] = parameter_tvb; |
1543 | 0 | else |
1544 | 0 | sctp_info.incomplete = true; |
1545 | 2 | } |
1546 | 5 | } |
1547 | | |
1548 | 2 | #define STATE_COOKIE_PARAMETER_COOKIE_OFFSET PARAMETER_VALUE_OFFSET |
1549 | | |
1550 | | static void |
1551 | | dissect_state_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1552 | 3 | { |
1553 | 3 | uint16_t state_cookie_length; |
1554 | | |
1555 | 3 | state_cookie_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH; |
1556 | 3 | if (state_cookie_length > 0) |
1557 | 2 | proto_tree_add_item(parameter_tree, hf_state_cookie, parameter_tvb, STATE_COOKIE_PARAMETER_COOKIE_OFFSET, state_cookie_length, ENC_NA); |
1558 | 3 | proto_item_append_text(parameter_item, " (Cookie length: %u byte%s)", state_cookie_length, plurality(state_cookie_length, "", "s")); |
1559 | 3 | } |
1560 | | |
1561 | | static void |
1562 | | // NOLINTNEXTLINE(misc-no-recursion) |
1563 | | dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree) |
1564 | 3 | { |
1565 | | /* FIXME: Does it contain one or more parameters? */ |
1566 | 3 | dissect_parameter(tvb_new_subset_remaining(parameter_tvb, PARAMETER_VALUE_OFFSET), pinfo, parameter_tree, NULL, false, false, false); |
1567 | 3 | } |
1568 | | |
1569 | 2 | #define COOKIE_PRESERVATIVE_PARAMETER_INCR_LENGTH 4 |
1570 | 4 | #define COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET PARAMETER_VALUE_OFFSET |
1571 | | |
1572 | | static void |
1573 | | dissect_cookie_preservative_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1574 | 2 | { |
1575 | 2 | proto_tree_add_item(parameter_tree, hf_cookie_preservative_increment, parameter_tvb, COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET, COOKIE_PRESERVATIVE_PARAMETER_INCR_LENGTH, ENC_BIG_ENDIAN); |
1576 | 2 | proto_item_append_text(parameter_item, " (Increment :%u msec)", tvb_get_ntohl(parameter_tvb, COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET)); |
1577 | 2 | } |
1578 | | |
1579 | 3 | #define HOSTNAME_OFFSET PARAMETER_VALUE_OFFSET |
1580 | | |
1581 | | static void |
1582 | | dissect_hostname_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item) |
1583 | 3 | { |
1584 | 3 | char *hostname; |
1585 | 3 | uint16_t hostname_length; |
1586 | | |
1587 | 3 | hostname_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH; |
1588 | 3 | proto_tree_add_item_ret_display_string(parameter_tree, hf_hostname, parameter_tvb, HOSTNAME_OFFSET, hostname_length, ENC_ASCII, pinfo->pool, &hostname); |
1589 | 3 | if (hostname_length > 1) { |
1590 | 1 | proto_item_append_text(parameter_item, " (Hostname: %s)", hostname); |
1591 | 1 | if (additional_item != NULL) { |
1592 | 0 | proto_item_append_text(additional_item, " (Hostname: %s)", hostname); |
1593 | 0 | } |
1594 | 1 | } |
1595 | 3 | } |
1596 | | |
1597 | 22 | #define IPv4_ADDRESS_TYPE 5 |
1598 | 33 | #define IPv6_ADDRESS_TYPE 6 |
1599 | 12 | #define HOSTNAME_ADDRESS_TYPE 11 |
1600 | | |
1601 | | static const value_string address_types_values[] = { |
1602 | | { IPv4_ADDRESS_TYPE, "IPv4 address" }, |
1603 | | { IPv6_ADDRESS_TYPE, "IPv6 address" }, |
1604 | | { HOSTNAME_ADDRESS_TYPE, "Hostname address" }, |
1605 | | { 0, NULL } |
1606 | | }; |
1607 | | |
1608 | 9.81k | #define SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH 2 |
1609 | | |
1610 | | static void |
1611 | | dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1612 | 38 | { |
1613 | 38 | uint16_t addr_type, number_of_addr_types, addr_type_number; |
1614 | 38 | unsigned offset; |
1615 | | |
1616 | 38 | number_of_addr_types = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) |
1617 | 38 | / SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH; |
1618 | | |
1619 | 38 | offset = PARAMETER_VALUE_OFFSET; |
1620 | 38 | proto_item_append_text(parameter_item, " (Supported types: "); |
1621 | 4.91k | for(addr_type_number = 0; addr_type_number < number_of_addr_types; addr_type_number++) { |
1622 | 4.90k | proto_tree_add_item(parameter_tree, hf_supported_address_type, parameter_tvb, offset, SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH, ENC_BIG_ENDIAN); |
1623 | 4.90k | addr_type = tvb_get_ntohs(parameter_tvb, offset); |
1624 | 4.90k | switch (addr_type) { |
1625 | 22 | case IPv4_ADDRESS_TYPE: |
1626 | 22 | proto_item_append_text(parameter_item, "IPv4"); |
1627 | 22 | break; |
1628 | 33 | case IPv6_ADDRESS_TYPE: |
1629 | 33 | proto_item_append_text(parameter_item, "IPv6"); |
1630 | 33 | break; |
1631 | 12 | case HOSTNAME_ADDRESS_TYPE: |
1632 | 12 | proto_item_append_text(parameter_item, "hostname"); |
1633 | 12 | break; |
1634 | 4.80k | default: |
1635 | 4.80k | proto_item_append_text(parameter_item, "%u", addr_type); |
1636 | 4.90k | } |
1637 | 4.87k | if (addr_type_number < (number_of_addr_types-1)) |
1638 | 4.86k | proto_item_append_text(parameter_item, ", "); |
1639 | 4.87k | offset += SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH; |
1640 | 4.87k | } |
1641 | 5 | proto_item_append_text(parameter_item, ")"); |
1642 | 5 | } |
1643 | | |
1644 | 266 | #define STREAM_RESET_SEQ_NR_LENGTH 4 |
1645 | 72 | #define SENDERS_LAST_ASSIGNED_TSN_LENGTH 4 |
1646 | 3.15k | #define SID_LENGTH 2 |
1647 | | |
1648 | 42 | #define STREAM_RESET_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET |
1649 | 54 | #define STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET (PARAMETER_VALUE_OFFSET + STREAM_RESET_SEQ_NR_LENGTH) |
1650 | 36 | #define SENDERS_LAST_ASSIGNED_TSN_OFFSET (STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH) |
1651 | | |
1652 | | static void |
1653 | | dissect_outgoing_ssn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_) |
1654 | 18 | { |
1655 | 18 | unsigned length, number_of_sids, sid_number, sid_offset; |
1656 | | |
1657 | 18 | proto_tree_add_item(parameter_tree, hf_stream_reset_req_seq_nr, parameter_tvb, STREAM_RESET_REQ_SEQ_NR_OFFSET, STREAM_RESET_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1658 | 18 | proto_tree_add_item(parameter_tree, hf_stream_reset_rsp_seq_nr, parameter_tvb, STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET, STREAM_RESET_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1659 | 18 | proto_tree_add_item(parameter_tree, hf_senders_last_assigned_tsn, parameter_tvb, SENDERS_LAST_ASSIGNED_TSN_OFFSET, SENDERS_LAST_ASSIGNED_TSN_LENGTH, ENC_BIG_ENDIAN); |
1660 | | |
1661 | 18 | length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); |
1662 | 18 | sid_offset = SENDERS_LAST_ASSIGNED_TSN_OFFSET + SENDERS_LAST_ASSIGNED_TSN_LENGTH; |
1663 | 18 | if (length > PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + SENDERS_LAST_ASSIGNED_TSN_LENGTH) { |
1664 | 18 | number_of_sids = (length - (PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + SENDERS_LAST_ASSIGNED_TSN_LENGTH)) / SID_LENGTH; |
1665 | 1.13k | for(sid_number = 0; sid_number < number_of_sids; sid_number++) { |
1666 | 1.11k | proto_tree_add_item(parameter_tree, hf_stream_reset_sid, parameter_tvb, sid_offset, SID_LENGTH, ENC_BIG_ENDIAN); |
1667 | 1.11k | sid_offset += SID_LENGTH; |
1668 | 1.11k | } |
1669 | 18 | } |
1670 | 18 | } |
1671 | | |
1672 | | static void |
1673 | | dissect_incoming_ssn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_) |
1674 | 12 | { |
1675 | 12 | unsigned length, number_of_sids, sid_number, sid_offset; |
1676 | | |
1677 | 12 | proto_tree_add_item(parameter_tree, hf_stream_reset_req_seq_nr, parameter_tvb, STREAM_RESET_REQ_SEQ_NR_OFFSET, STREAM_RESET_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1678 | | |
1679 | 12 | length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); |
1680 | 12 | sid_offset = STREAM_RESET_REQ_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH; |
1681 | 12 | if (length > PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH) { |
1682 | 11 | number_of_sids = (length - (PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH)) / SID_LENGTH; |
1683 | 458 | for(sid_number = 0; sid_number < number_of_sids; sid_number++) { |
1684 | 447 | proto_tree_add_item(parameter_tree, hf_stream_reset_sid, parameter_tvb, sid_offset, SID_LENGTH, ENC_BIG_ENDIAN); |
1685 | 447 | sid_offset += SID_LENGTH; |
1686 | 447 | } |
1687 | 11 | } |
1688 | 12 | } |
1689 | | |
1690 | 3 | #define STREAM_RESET_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET |
1691 | | |
1692 | | static void |
1693 | | dissect_ssn_tsn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_) |
1694 | 3 | { |
1695 | 3 | proto_tree_add_item(parameter_tree, hf_stream_reset_req_seq_nr, parameter_tvb, STREAM_RESET_REQ_SEQ_NR_OFFSET, STREAM_RESET_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1696 | 3 | } |
1697 | | |
1698 | 15 | #define STREAM_RESET_RSP_RESULT_LENGTH 4 |
1699 | 12 | #define SENDERS_NEXT_TSN_LENGTH 4 |
1700 | 6 | #define RECEIVERS_NEXT_TSN_LENGTH 4 |
1701 | | |
1702 | 12 | #define STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET |
1703 | 9 | #define STREAM_RESET_RSP_RESULT_OFFSET (STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH) |
1704 | 6 | #define SENDERS_NEXT_TSN_OFFSET (STREAM_RESET_RSP_RESULT_OFFSET + STREAM_RESET_RSP_RESULT_LENGTH) |
1705 | 3 | #define RECEIVERS_NEXT_TSN_OFFSET (SENDERS_NEXT_TSN_OFFSET + SENDERS_NEXT_TSN_LENGTH) |
1706 | | |
1707 | | static const value_string stream_reset_result_values[] = { |
1708 | | { 0, "Nothing to do" }, |
1709 | | { 1, "Performed" }, |
1710 | | { 2, "Denied" }, |
1711 | | { 3, "Error - Wrong SSN" }, |
1712 | | { 4, "Error - Request already in progress" }, |
1713 | | { 5, "Error - Bad sequence number" }, |
1714 | | { 6, "In progress" }, |
1715 | | { 0, NULL } |
1716 | | }; |
1717 | | |
1718 | | |
1719 | | static void |
1720 | | dissect_re_configuration_response_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_) |
1721 | 3 | { |
1722 | 3 | unsigned length; |
1723 | | |
1724 | 3 | length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); |
1725 | | |
1726 | 3 | proto_tree_add_item(parameter_tree, hf_stream_reset_rsp_seq_nr, parameter_tvb, STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET, STREAM_RESET_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1727 | 3 | proto_tree_add_item(parameter_tree, hf_stream_reset_rsp_result, parameter_tvb, STREAM_RESET_RSP_RESULT_OFFSET, STREAM_RESET_RSP_RESULT_LENGTH, ENC_BIG_ENDIAN); |
1728 | 3 | if (length >= PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_RSP_RESULT_LENGTH + SENDERS_NEXT_TSN_LENGTH) |
1729 | 3 | proto_tree_add_item(parameter_tree, hf_senders_next_tsn, parameter_tvb, SENDERS_NEXT_TSN_OFFSET, SENDERS_NEXT_TSN_LENGTH, ENC_BIG_ENDIAN); |
1730 | 3 | if (length >= PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_RSP_RESULT_LENGTH + SENDERS_NEXT_TSN_LENGTH + RECEIVERS_NEXT_TSN_LENGTH) |
1731 | 3 | proto_tree_add_item(parameter_tree, hf_receivers_next_tsn, parameter_tvb, RECEIVERS_NEXT_TSN_OFFSET, RECEIVERS_NEXT_TSN_LENGTH, ENC_BIG_ENDIAN); |
1732 | 3 | } |
1733 | | |
1734 | 15 | #define ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH 4 |
1735 | 7 | #define ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH 2 |
1736 | 2 | #define ADD_OUTGOING_STREAM_REQ_RESERVED_LENGTH 2 |
1737 | | |
1738 | 6 | #define ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET |
1739 | 4 | #define ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET (ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET + ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH) |
1740 | 2 | #define ADD_OUTGOING_STREAM_REQ_RESERVED_OFFSET (ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET + ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH) |
1741 | | |
1742 | | static void |
1743 | | dissect_add_outgoing_streams_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_) |
1744 | 2 | { |
1745 | | /* unsigned length; */ |
1746 | | |
1747 | | /* length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); */ |
1748 | | |
1749 | 2 | proto_tree_add_item(parameter_tree, hf_stream_reset_req_seq_nr, parameter_tvb, ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET, ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1750 | 2 | proto_tree_add_item(parameter_tree, hf_add_outgoing_streams_number_streams, parameter_tvb, ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET, ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH, ENC_BIG_ENDIAN); |
1751 | 2 | proto_tree_add_item(parameter_tree, hf_add_outgoing_streams_reserved, parameter_tvb, ADD_OUTGOING_STREAM_REQ_RESERVED_OFFSET, ADD_OUTGOING_STREAM_REQ_RESERVED_LENGTH, ENC_BIG_ENDIAN); |
1752 | 2 | } |
1753 | | |
1754 | | #define ADD_INCOMING_STREAM_REQ_SEQ_NR_LENGTH 4 |
1755 | 3 | #define ADD_INCOMING_STREAM_REQ_NUM_STREAMS_LENGTH 2 |
1756 | 3 | #define ADD_INCOMING_STREAM_REQ_RESERVED_LENGTH 2 |
1757 | | |
1758 | 9 | #define ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET |
1759 | 6 | #define ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET (ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET + ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH) |
1760 | 3 | #define ADD_INCOMING_STREAM_REQ_RESERVED_OFFSET (ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET + ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH) |
1761 | | |
1762 | | static void |
1763 | | dissect_add_incoming_streams_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_) |
1764 | 3 | { |
1765 | | /* unsigned length; */ |
1766 | | |
1767 | | /* length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); */ |
1768 | | |
1769 | 3 | proto_tree_add_item(parameter_tree, hf_stream_reset_req_seq_nr, parameter_tvb, ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET, ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH, ENC_BIG_ENDIAN); |
1770 | 3 | proto_tree_add_item(parameter_tree, hf_add_incoming_streams_number_streams, parameter_tvb, ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET, ADD_INCOMING_STREAM_REQ_NUM_STREAMS_LENGTH, ENC_BIG_ENDIAN); |
1771 | 3 | proto_tree_add_item(parameter_tree, hf_add_incoming_streams_reserved, parameter_tvb, ADD_INCOMING_STREAM_REQ_RESERVED_OFFSET, ADD_INCOMING_STREAM_REQ_RESERVED_LENGTH, ENC_BIG_ENDIAN); |
1772 | 3 | } |
1773 | | |
1774 | | static void |
1775 | | dissect_ecn_parameter(tvbuff_t *parameter_tvb _U_) |
1776 | 2 | { |
1777 | 2 | } |
1778 | | |
1779 | 2 | #define ZERO_CHECKSUM_PARAMETER_EDMID_LENGTH 4 |
1780 | 4 | #define ZERO_CHECKSUM_PARAMETER_EDMID_OFFSET PARAMETER_VALUE_OFFSET |
1781 | | |
1782 | | static const value_string edmid_values[] = { |
1783 | | { 1, "SCTP over DTLS" }, |
1784 | | { 0, NULL } |
1785 | | }; |
1786 | | |
1787 | | static void |
1788 | | dissect_zero_checksum_acceptable_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1789 | 2 | { |
1790 | 2 | proto_tree_add_item(parameter_tree, hf_zero_checksum_edmid, parameter_tvb, ZERO_CHECKSUM_PARAMETER_EDMID_OFFSET, ZERO_CHECKSUM_PARAMETER_EDMID_LENGTH, ENC_BIG_ENDIAN); |
1791 | 2 | proto_item_append_text(parameter_item, " (EDMID: %s)", val_to_str_const(tvb_get_ntohl(parameter_tvb, ZERO_CHECKSUM_PARAMETER_EDMID_OFFSET), edmid_values, "Unknown")); |
1792 | 2 | } |
1793 | | |
1794 | 2 | #define RANDOM_NUMBER_OFFSET PARAMETER_VALUE_OFFSET |
1795 | | |
1796 | | static void |
1797 | | dissect_random_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree) |
1798 | 2 | { |
1799 | 2 | int32_t number_length; |
1800 | | |
1801 | 2 | number_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH; |
1802 | 2 | if (number_length > 0) |
1803 | 2 | proto_tree_add_item(parameter_tree, hf_random_number, parameter_tvb, RANDOM_NUMBER_OFFSET, number_length, ENC_NA); |
1804 | 2 | } |
1805 | | |
1806 | | static void |
1807 | | dissect_chunks_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1808 | 9 | { |
1809 | 9 | uint16_t number_of_chunks; |
1810 | 9 | uint16_t chunk_number, offset; |
1811 | | |
1812 | 9 | proto_item_append_text(parameter_item, " (Chunk types to be authenticated: "); |
1813 | 9 | number_of_chunks = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH; |
1814 | 1.58k | for(chunk_number = 0, offset = PARAMETER_VALUE_OFFSET; chunk_number < number_of_chunks; chunk_number++, offset += CHUNK_TYPE_LENGTH) { |
1815 | 1.57k | proto_tree_add_item(parameter_tree, hf_chunks_to_auth, parameter_tvb, offset, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN); |
1816 | 1.57k | proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_uint8(parameter_tvb, offset), chunk_type_values, "Unknown")); |
1817 | 1.57k | if (chunk_number < (number_of_chunks - 1)) |
1818 | 1.56k | proto_item_append_text(parameter_item, ", "); |
1819 | 1.57k | } |
1820 | 9 | proto_item_append_text(parameter_item, ")"); |
1821 | 9 | } |
1822 | | |
1823 | | static const value_string hmac_id_values[] = { |
1824 | | { 0x0000, "Reserved" }, |
1825 | | { 0x0001, "SHA-1" }, |
1826 | | { 0x0002, "Reserved" }, |
1827 | | { 0x0003, "SHA-256" }, |
1828 | | { 0, NULL } }; |
1829 | | |
1830 | 820 | #define HMAC_ID_LENGTH 2 |
1831 | | |
1832 | | static void |
1833 | | dissect_hmac_algo_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1834 | 9 | { |
1835 | 9 | uint16_t number_of_ids; |
1836 | 9 | uint16_t id_number, offset; |
1837 | | |
1838 | 9 | proto_item_append_text(parameter_item, " (Supported HMACs: "); |
1839 | 9 | number_of_ids = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) / HMAC_ID_LENGTH; |
1840 | 410 | for(id_number = 0, offset = PARAMETER_VALUE_OFFSET; id_number < number_of_ids; id_number++, offset += HMAC_ID_LENGTH) { |
1841 | 401 | proto_tree_add_item(parameter_tree, hf_hmac_id, parameter_tvb, offset, HMAC_ID_LENGTH, ENC_BIG_ENDIAN); |
1842 | 401 | proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_ntohs(parameter_tvb, offset), hmac_id_values, "Unknown")); |
1843 | 401 | if (id_number < (number_of_ids - 1)) |
1844 | 392 | proto_item_append_text(parameter_item, ", "); |
1845 | 401 | } |
1846 | 9 | proto_item_append_text(parameter_item, ")"); |
1847 | 9 | } |
1848 | | |
1849 | | static const value_string dtls_km_id_values[] = { |
1850 | | { 0x00, "Reserved" }, |
1851 | | { 0x01, "Single DTLS connection" }, |
1852 | | { 0xC0, "Single TLS connection" }, |
1853 | | { 0, NULL } }; |
1854 | | |
1855 | 42 | #define DTLS_KM_PARAMETER_TIE_BREAKER_LENGTH 4 |
1856 | 28 | #define DTLS_KM_PARAMETER_FLAGS_LENGTH 1 |
1857 | 6.66k | #define DTLS_KM_PARAMETER_KMID_LENGTH 1 |
1858 | | |
1859 | 42 | #define DTLS_KM_PARAMETER_TIE_BREAKER_OFFSET PARAMETER_VALUE_OFFSET |
1860 | 35 | #define DTLS_KM_PARAMETER_FLAGS_OFFSET (DTLS_KM_PARAMETER_TIE_BREAKER_OFFSET + DTLS_KM_PARAMETER_TIE_BREAKER_LENGTH) |
1861 | 14 | #define DTLS_KM_PARAMETER_KMID_OFFSET (DTLS_KM_PARAMETER_FLAGS_OFFSET + DTLS_KM_PARAMETER_FLAGS_LENGTH) |
1862 | | |
1863 | 23 | #define DTLS_KM_PARAMETER_C_BIT 0x01 |
1864 | 23 | #define DTLS_KM_PARAMETER_S_BIT 0x02 |
1865 | 23 | #define DTLS_KM_PARAMETER_R_BIT 0x04 |
1866 | | |
1867 | | static const true_false_string sctp_dtls_km_parameter_c_bit_value = { |
1868 | | "Client role supported", |
1869 | | "Client role not supported" |
1870 | | }; |
1871 | | |
1872 | | static const true_false_string sctp_dtls_km_parameter_s_bit_value = { |
1873 | | "Server role supported", |
1874 | | "Server role not supported" |
1875 | | }; |
1876 | | |
1877 | | static const true_false_string sctp_dtls_km_parameter_r_bit_value = { |
1878 | | "Restart supported", |
1879 | | "Restart not supported" |
1880 | | }; |
1881 | | |
1882 | | static void |
1883 | | dissect_dtls_key_management_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item, bool dissecting_init_chunk, bool dissecting_init_ack_chunk) |
1884 | 7 | { |
1885 | 7 | proto_item *flags_item; |
1886 | 7 | proto_tree *flags_tree; |
1887 | 7 | uint16_t number_of_ids; |
1888 | 7 | uint16_t id_number, offset; |
1889 | 7 | uint8_t flags, c_bit, s_bit, r_bit; |
1890 | 7 | static int* const flag_list[] = { |
1891 | 7 | &hf_dtls_km_c_bit, |
1892 | 7 | &hf_dtls_km_s_bit, |
1893 | 7 | &hf_dtls_km_r_bit, |
1894 | 7 | NULL |
1895 | 7 | }; |
1896 | | |
1897 | 7 | if (!dissecting_init_chunk && !dissecting_init_ack_chunk) |
1898 | 2 | expert_add_info(pinfo, parameter_item, &ei_sctp_illegal_parameter_occurrence); |
1899 | | |
1900 | 7 | proto_tree_add_item(parameter_tree, hf_dtls_km_tiebreaker, parameter_tvb, DTLS_KM_PARAMETER_TIE_BREAKER_OFFSET, DTLS_KM_PARAMETER_TIE_BREAKER_LENGTH, ENC_BIG_ENDIAN); |
1901 | 7 | flags = tvb_get_uint8(parameter_tvb, DTLS_KM_PARAMETER_FLAGS_OFFSET); |
1902 | 7 | c_bit = flags & DTLS_KM_PARAMETER_C_BIT; |
1903 | 7 | s_bit = flags & DTLS_KM_PARAMETER_S_BIT; |
1904 | 7 | r_bit = flags & DTLS_KM_PARAMETER_R_BIT; |
1905 | 7 | proto_item_append_text(parameter_item, " ("); |
1906 | 7 | if (c_bit) |
1907 | 2 | proto_item_append_text(parameter_item, "client%s", s_bit ? " and " : " "); |
1908 | 7 | if (s_bit) |
1909 | 5 | proto_item_append_text(parameter_item, "server"); |
1910 | 7 | if (c_bit || s_bit) |
1911 | 5 | proto_item_append_text(parameter_item, " role, "); |
1912 | 7 | proto_item_append_text(parameter_item, "restart%ssupported, ", r_bit ? " " : " not "); |
1913 | 7 | flags_item = proto_tree_add_item(parameter_tree, hf_dtls_km_flags, parameter_tvb, DTLS_KM_PARAMETER_FLAGS_OFFSET, DTLS_KM_PARAMETER_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
1914 | 7 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_dtls_km_flags); |
1915 | 7 | proto_tree_add_bitmask_list(flags_tree, parameter_tvb, DTLS_KM_PARAMETER_FLAGS_OFFSET, DTLS_KM_PARAMETER_FLAGS_LENGTH, flag_list, ENC_NA); |
1916 | 7 | proto_item_append_text(parameter_item, "ids: "); |
1917 | 7 | number_of_ids = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - DTLS_KM_PARAMETER_KMID_OFFSET) / DTLS_KM_PARAMETER_KMID_LENGTH; |
1918 | 3.33k | for(id_number = 0, offset = DTLS_KM_PARAMETER_KMID_OFFSET; id_number < number_of_ids; id_number++, offset += DTLS_KM_PARAMETER_KMID_LENGTH) { |
1919 | 3.33k | proto_tree_add_item(parameter_tree, hf_dtls_km_id, parameter_tvb, offset, DTLS_KM_PARAMETER_KMID_LENGTH, ENC_BIG_ENDIAN); |
1920 | 3.33k | proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_uint8(parameter_tvb, offset), dtls_km_id_values, "Unknown")); |
1921 | 3.33k | if (id_number < (number_of_ids - 1)) |
1922 | 3.32k | proto_item_append_text(parameter_item, ", "); |
1923 | 3.33k | } |
1924 | 7 | proto_item_append_text(parameter_item, ")"); |
1925 | 7 | if (number_of_ids == 0) |
1926 | 0 | expert_add_info_format(pinfo, parameter_item, &ei_sctp_dtls_km_illegal_number_of_ids, "At least one identifier required."); |
1927 | 7 | } |
1928 | | |
1929 | | static void |
1930 | | dissect_supported_extensions_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
1931 | 12 | { |
1932 | 12 | uint16_t number_of_types; |
1933 | 12 | uint16_t type_number, offset; |
1934 | | |
1935 | 12 | proto_item_append_text(parameter_item, " (Supported types: "); |
1936 | 12 | number_of_types = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) / CHUNK_TYPE_LENGTH; |
1937 | 2.23k | for(type_number = 0, offset = PARAMETER_VALUE_OFFSET; type_number < number_of_types; type_number++, offset += CHUNK_TYPE_LENGTH) { |
1938 | 2.22k | proto_tree_add_item(parameter_tree, hf_supported_chunk_type, parameter_tvb, offset, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN); |
1939 | 2.22k | proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_uint8(parameter_tvb, offset), chunk_type_values, "Unknown")); |
1940 | 2.22k | if (type_number < (number_of_types - 1)) |
1941 | 2.21k | proto_item_append_text(parameter_item, ", "); |
1942 | 2.22k | } |
1943 | 12 | proto_item_append_text(parameter_item, ")"); |
1944 | 12 | } |
1945 | | |
1946 | | static void |
1947 | | dissect_forward_tsn_supported_parameter(tvbuff_t *parameter_tvb _U_) |
1948 | 2 | { |
1949 | 2 | } |
1950 | | |
1951 | 9 | #define CORRELATION_ID_LENGTH 4 |
1952 | 9 | #define CORRELATION_ID_OFFSET PARAMETER_VALUE_OFFSET |
1953 | 3 | #define ADDRESS_PARAMETER_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH) |
1954 | | |
1955 | | static void |
1956 | | // NOLINTNEXTLINE(misc-no-recursion) |
1957 | | dissect_add_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item) |
1958 | 1 | { |
1959 | 1 | uint16_t address_length; |
1960 | 1 | tvbuff_t *address_tvb; |
1961 | | |
1962 | 1 | address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH; |
1963 | | |
1964 | 1 | proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN); |
1965 | 1 | address_tvb = tvb_new_subset_length(parameter_tvb, ADDRESS_PARAMETER_OFFSET, |
1966 | 1 | MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET))); |
1967 | 1 | proto_item_append_text(parameter_item, " (Address: "); |
1968 | 1 | dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, false, false, false); |
1969 | 1 | proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET)); |
1970 | 1 | } |
1971 | | |
1972 | | static void |
1973 | | // NOLINTNEXTLINE(misc-no-recursion) |
1974 | | dissect_del_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item) |
1975 | 2 | { |
1976 | 2 | uint16_t address_length; |
1977 | 2 | tvbuff_t *address_tvb; |
1978 | | |
1979 | 2 | address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH; |
1980 | | |
1981 | 2 | proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN); |
1982 | 2 | address_tvb = tvb_new_subset_length(parameter_tvb, ADDRESS_PARAMETER_OFFSET, |
1983 | 2 | MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET))); |
1984 | 2 | proto_item_append_text(parameter_item, " (Address: "); |
1985 | 2 | dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, false, false, false); |
1986 | 2 | proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET)); |
1987 | 2 | } |
1988 | | |
1989 | 0 | #define ERROR_CAUSE_IND_CASUES_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH) |
1990 | | |
1991 | | static void |
1992 | | // NOLINTNEXTLINE(misc-no-recursion) |
1993 | | dissect_error_cause_indication_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree) |
1994 | 0 | { |
1995 | 0 | uint16_t causes_length; |
1996 | 0 | tvbuff_t *causes_tvb; |
1997 | |
|
1998 | 0 | proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN); |
1999 | 0 | causes_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH; |
2000 | 0 | causes_tvb = tvb_new_subset_length(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET, |
2001 | 0 | MIN(causes_length, tvb_reported_length_remaining(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET))); |
2002 | 0 | dissect_error_causes(causes_tvb, pinfo, parameter_tree); |
2003 | 0 | } |
2004 | | |
2005 | | static void |
2006 | | // NOLINTNEXTLINE(misc-no-recursion) |
2007 | | dissect_set_primary_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item) |
2008 | 0 | { |
2009 | 0 | uint16_t address_length; |
2010 | 0 | tvbuff_t *address_tvb; |
2011 | |
|
2012 | 0 | address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH; |
2013 | |
|
2014 | 0 | proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN); |
2015 | 0 | address_tvb = tvb_new_subset_length(parameter_tvb, ADDRESS_PARAMETER_OFFSET, |
2016 | 0 | MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET))); |
2017 | 0 | proto_item_append_text(parameter_item, " (Address: "); |
2018 | 0 | dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, false, false, false); |
2019 | 0 | proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET)); |
2020 | 0 | } |
2021 | | |
2022 | | static void |
2023 | | dissect_success_report_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
2024 | 0 | { |
2025 | 0 | proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN); |
2026 | 0 | proto_item_append_text(parameter_item, " (Correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET)); |
2027 | 0 | } |
2028 | | |
2029 | 0 | #define ADAP_INDICATION_LENGTH 4 |
2030 | 0 | #define ADAP_INDICATION_OFFSET PARAMETER_VALUE_OFFSET |
2031 | | |
2032 | | static void |
2033 | | dissect_adap_indication_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
2034 | 0 | { |
2035 | 0 | proto_tree_add_item(parameter_tree, hf_adap_indication, parameter_tvb, ADAP_INDICATION_OFFSET, ADAP_INDICATION_LENGTH, ENC_BIG_ENDIAN); |
2036 | 0 | proto_item_append_text(parameter_item, " (Indication: %u)", tvb_get_ntohl(parameter_tvb, ADAP_INDICATION_OFFSET)); |
2037 | 0 | } |
2038 | | |
2039 | | static void |
2040 | | dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item) |
2041 | 157 | { |
2042 | 157 | uint16_t type, parameter_value_length; |
2043 | | |
2044 | 157 | type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET); |
2045 | 157 | parameter_value_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH; |
2046 | | |
2047 | 157 | if (parameter_value_length > 0) |
2048 | 151 | proto_tree_add_item(parameter_tree, hf_parameter_value, parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length, ENC_NA); |
2049 | | |
2050 | 157 | proto_item_append_text(parameter_item, " (Type %u, value length: %u byte%s)", type, parameter_value_length, plurality(parameter_value_length, "", "s")); |
2051 | 157 | } |
2052 | | |
2053 | 9 | #define HEARTBEAT_INFO_PARAMETER_ID 0x0001 |
2054 | 8 | #define IPV4ADDRESS_PARAMETER_ID 0x0005 |
2055 | 5 | #define IPV6ADDRESS_PARAMETER_ID 0x0006 |
2056 | 3 | #define STATE_COOKIE_PARAMETER_ID 0x0007 |
2057 | 3 | #define UNREC_PARA_PARAMETER_ID 0x0008 |
2058 | 2 | #define COOKIE_PRESERVATIVE_PARAMETER_ID 0x0009 |
2059 | 3 | #define HOSTNAME_ADDRESS_PARAMETER_ID 0x000b |
2060 | 38 | #define SUPPORTED_ADDRESS_TYPES_PARAMETER_ID 0x000c |
2061 | 18 | #define OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID 0x000d |
2062 | 12 | #define INCOMING_SSN_RESET_REQUEST_PARAMETER_ID 0x000e |
2063 | 3 | #define SSN_TSN_RESET_REQUEST_PARAMETER_ID 0x000f |
2064 | 3 | #define RE_CONFIGURATION_RESPONSE_PARAMETER_ID 0x0010 |
2065 | 2 | #define ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID 0x0011 |
2066 | 3 | #define ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID 0x0012 |
2067 | 2 | #define ECN_PARAMETER_ID 0x8000 |
2068 | 2 | #define ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_ID 0x8001 |
2069 | 2 | #define RANDOM_PARAMETER_ID 0x8002 |
2070 | 9 | #define CHUNKS_PARAMETER_ID 0x8003 |
2071 | 9 | #define HMAC_ALGO_PARAMETER_ID 0x8004 |
2072 | 7 | #define DTLS_KEY_MANAGEMENT_PARAMETER_ID 0x8006 |
2073 | 12 | #define SUPPORTED_EXTENSIONS_PARAMETER_ID 0x8008 |
2074 | 2 | #define FORWARD_TSN_SUPPORTED_PARAMETER_ID 0xC000 |
2075 | 1 | #define ADD_IP_ADDRESS_PARAMETER_ID 0xC001 |
2076 | 2 | #define DEL_IP_ADDRESS_PARAMETER_ID 0xC002 |
2077 | 0 | #define ERROR_CAUSE_INDICATION_PARAMETER_ID 0xC003 |
2078 | 0 | #define SET_PRIMARY_ADDRESS_PARAMETER_ID 0xC004 |
2079 | 0 | #define SUCCESS_REPORT_PARAMETER_ID 0xC005 |
2080 | 0 | #define ADAP_LAYER_INDICATION_PARAMETER_ID 0xC006 |
2081 | | |
2082 | | static const value_string parameter_identifier_values[] = { |
2083 | | { HEARTBEAT_INFO_PARAMETER_ID, "Heartbeat info" }, |
2084 | | { IPV4ADDRESS_PARAMETER_ID, "IPv4 address" }, |
2085 | | { IPV6ADDRESS_PARAMETER_ID, "IPv6 address" }, |
2086 | | { STATE_COOKIE_PARAMETER_ID, "State cookie" }, |
2087 | | { UNREC_PARA_PARAMETER_ID, "Unrecognized parameter" }, |
2088 | | { COOKIE_PRESERVATIVE_PARAMETER_ID, "Cookie preservative" }, |
2089 | | { HOSTNAME_ADDRESS_PARAMETER_ID, "Hostname address" }, |
2090 | | { OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID, "Outgoing SSN reset request" }, |
2091 | | { INCOMING_SSN_RESET_REQUEST_PARAMETER_ID, "Incoming SSN reset request" }, |
2092 | | { SSN_TSN_RESET_REQUEST_PARAMETER_ID, "SSN/TSN reset request" }, |
2093 | | { RE_CONFIGURATION_RESPONSE_PARAMETER_ID, "Re-configuration response" }, |
2094 | | { ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID, "Add outgoing streams request" }, |
2095 | | { ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID, "Add incoming streams request" }, |
2096 | | { SUPPORTED_ADDRESS_TYPES_PARAMETER_ID, "Supported address types" }, |
2097 | | { ECN_PARAMETER_ID, "ECN" }, |
2098 | | { ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_ID, "Zero checksum acceptable" }, |
2099 | | { RANDOM_PARAMETER_ID, "Random" }, |
2100 | | { CHUNKS_PARAMETER_ID, "Authenticated Chunk list" }, |
2101 | | { HMAC_ALGO_PARAMETER_ID, "Requested HMAC Algorithm" }, |
2102 | | { DTLS_KEY_MANAGEMENT_PARAMETER_ID, "DTLS key management" }, |
2103 | | { SUPPORTED_EXTENSIONS_PARAMETER_ID, "Supported Extensions" }, |
2104 | | { FORWARD_TSN_SUPPORTED_PARAMETER_ID, "Forward TSN supported" }, |
2105 | | { ADD_IP_ADDRESS_PARAMETER_ID, "Add IP address" }, |
2106 | | { DEL_IP_ADDRESS_PARAMETER_ID, "Delete IP address" }, |
2107 | | { ERROR_CAUSE_INDICATION_PARAMETER_ID, "Error cause indication" }, |
2108 | | { SET_PRIMARY_ADDRESS_PARAMETER_ID, "Set primary address" }, |
2109 | | { SUCCESS_REPORT_PARAMETER_ID, "Success report" }, |
2110 | | { ADAP_LAYER_INDICATION_PARAMETER_ID, "Adaptation Layer Indication" }, |
2111 | | { 0, NULL } }; |
2112 | | |
2113 | 16 | #define SCTP_PARAMETER_BIT_1 0x8000 |
2114 | 16 | #define SCTP_PARAMETER_BIT_2 0x4000 |
2115 | | |
2116 | | static const true_false_string sctp_parameter_bit_1_value = { |
2117 | | "Skip parameter and continue processing of the chunk", |
2118 | | "Stop processing of chunk" |
2119 | | }; |
2120 | | |
2121 | | static const true_false_string sctp_parameter_bit_2_value = { |
2122 | | "Do report", |
2123 | | "Do not report" |
2124 | | }; |
2125 | | |
2126 | | static void |
2127 | | // NOLINTNEXTLINE(misc-no-recursion) |
2128 | | dissect_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, |
2129 | | proto_tree *chunk_tree, proto_item *additional_item, |
2130 | | bool dissecting_init_chunk, |
2131 | | bool dissecting_init_ack_chunk, |
2132 | | bool final_parameter) |
2133 | 331 | { |
2134 | 331 | uint16_t type, length, padding_length, reported_length; |
2135 | 331 | proto_item *parameter_item, *type_item; |
2136 | 331 | proto_tree *parameter_tree, *type_tree; |
2137 | 331 | bool dissecting_init_init_ack_chunk; |
2138 | | |
2139 | 331 | dissecting_init_init_ack_chunk = dissecting_init_chunk || dissecting_init_ack_chunk; |
2140 | | |
2141 | 331 | type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET); |
2142 | 331 | length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); |
2143 | 331 | reported_length = tvb_reported_length(parameter_tvb); |
2144 | 331 | padding_length = reported_length - length; |
2145 | | |
2146 | 331 | parameter_tree = proto_tree_add_subtree_format(chunk_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, -1, |
2147 | 331 | ett_sctp_chunk_parameter, ¶meter_item, "%s parameter", |
2148 | 331 | val_to_str_const(type, parameter_identifier_values, "Unknown")); |
2149 | 331 | if (final_parameter) { |
2150 | 219 | if (padding_length > 0) { |
2151 | 216 | expert_add_info(pinfo, parameter_item, &ei_sctp_parameter_padding); |
2152 | 216 | } |
2153 | 219 | } else { |
2154 | 112 | if (reported_length % 4) { |
2155 | 5 | expert_add_info_format(pinfo, parameter_item, &ei_sctp_parameter_length, "Parameter length is not padded to a multiple of 4 bytes (length=%d)", reported_length); |
2156 | 5 | } |
2157 | 112 | } |
2158 | | |
2159 | 331 | if (!(chunk_tree || (dissecting_init_init_ack_chunk && (type == IPV4ADDRESS_PARAMETER_ID || type == IPV6ADDRESS_PARAMETER_ID || type == DTLS_KEY_MANAGEMENT_PARAMETER_ID)))) |
2160 | 0 | return; |
2161 | | |
2162 | 331 | if (chunk_tree) { |
2163 | 317 | type_item = proto_tree_add_item(parameter_tree, hf_parameter_type, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN); |
2164 | 317 | type_tree = proto_item_add_subtree(type_item, ett_sctp_parameter_type); |
2165 | 317 | proto_tree_add_item(type_tree, hf_parameter_bit_1, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN); |
2166 | 317 | proto_tree_add_item(type_tree, hf_parameter_bit_2, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN); |
2167 | 317 | proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, ENC_BIG_ENDIAN); |
2168 | | /* XXX - add expert info if length is bogus? */ |
2169 | 317 | } else { |
2170 | 14 | parameter_item = NULL; |
2171 | 14 | parameter_tree = NULL; |
2172 | 14 | } |
2173 | | |
2174 | 331 | increment_dissection_depth(pinfo); |
2175 | 331 | switch(type) { |
2176 | 9 | case HEARTBEAT_INFO_PARAMETER_ID: |
2177 | 9 | dissect_heartbeat_info_parameter(parameter_tvb, parameter_tree, parameter_item); |
2178 | 9 | break; |
2179 | 8 | case IPV4ADDRESS_PARAMETER_ID: |
2180 | 8 | dissect_ipv4_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item, additional_item, dissecting_init_init_ack_chunk); |
2181 | 8 | break; |
2182 | 5 | case IPV6ADDRESS_PARAMETER_ID: |
2183 | 5 | dissect_ipv6_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item, additional_item, dissecting_init_init_ack_chunk); |
2184 | 5 | break; |
2185 | 3 | case STATE_COOKIE_PARAMETER_ID: |
2186 | 3 | dissect_state_cookie_parameter(parameter_tvb, parameter_tree, parameter_item); |
2187 | 3 | break; |
2188 | 3 | case UNREC_PARA_PARAMETER_ID: |
2189 | 3 | dissect_unrecognized_parameters_parameter(parameter_tvb, pinfo, parameter_tree); |
2190 | 3 | break; |
2191 | 2 | case COOKIE_PRESERVATIVE_PARAMETER_ID: |
2192 | 2 | dissect_cookie_preservative_parameter(parameter_tvb, parameter_tree, parameter_item); |
2193 | 2 | break; |
2194 | 3 | case HOSTNAME_ADDRESS_PARAMETER_ID: |
2195 | 3 | dissect_hostname_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item, additional_item); |
2196 | 3 | break; |
2197 | 38 | case SUPPORTED_ADDRESS_TYPES_PARAMETER_ID: |
2198 | 38 | dissect_supported_address_types_parameter(parameter_tvb, parameter_tree, parameter_item); |
2199 | 38 | break; |
2200 | 18 | case OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID: |
2201 | 18 | dissect_outgoing_ssn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item); |
2202 | 18 | break; |
2203 | 12 | case INCOMING_SSN_RESET_REQUEST_PARAMETER_ID: |
2204 | 12 | dissect_incoming_ssn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item); |
2205 | 12 | break; |
2206 | 3 | case SSN_TSN_RESET_REQUEST_PARAMETER_ID: |
2207 | 3 | dissect_ssn_tsn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item); |
2208 | 3 | break; |
2209 | 3 | case RE_CONFIGURATION_RESPONSE_PARAMETER_ID: |
2210 | 3 | dissect_re_configuration_response_parameter(parameter_tvb, parameter_tree, parameter_item); |
2211 | 3 | break; |
2212 | 2 | case ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID: |
2213 | 2 | dissect_add_outgoing_streams_parameter(parameter_tvb, parameter_tree, parameter_item); |
2214 | 2 | break; |
2215 | 3 | case ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID: |
2216 | 3 | dissect_add_incoming_streams_parameter(parameter_tvb, parameter_tree, parameter_item); |
2217 | 3 | break; |
2218 | 2 | case ECN_PARAMETER_ID: |
2219 | 2 | dissect_ecn_parameter(parameter_tvb); |
2220 | 2 | break; |
2221 | 2 | case ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_ID: |
2222 | 2 | dissect_zero_checksum_acceptable_parameter(parameter_tvb, parameter_tree, parameter_item); |
2223 | 2 | break; |
2224 | 2 | case RANDOM_PARAMETER_ID: |
2225 | 2 | dissect_random_parameter(parameter_tvb, parameter_tree); |
2226 | 2 | break; |
2227 | 9 | case CHUNKS_PARAMETER_ID: |
2228 | 9 | dissect_chunks_parameter(parameter_tvb, parameter_tree, parameter_item); |
2229 | 9 | break; |
2230 | 9 | case HMAC_ALGO_PARAMETER_ID: |
2231 | 9 | dissect_hmac_algo_parameter(parameter_tvb, parameter_tree, parameter_item); |
2232 | 9 | break; |
2233 | 7 | case DTLS_KEY_MANAGEMENT_PARAMETER_ID: |
2234 | 7 | dissect_dtls_key_management_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item, dissecting_init_chunk, dissecting_init_ack_chunk); |
2235 | 7 | break; |
2236 | 12 | case SUPPORTED_EXTENSIONS_PARAMETER_ID: |
2237 | 12 | dissect_supported_extensions_parameter(parameter_tvb, parameter_tree, parameter_item); |
2238 | 12 | break; |
2239 | 2 | case FORWARD_TSN_SUPPORTED_PARAMETER_ID: |
2240 | 2 | dissect_forward_tsn_supported_parameter(parameter_tvb); |
2241 | 2 | break; |
2242 | 1 | case ADD_IP_ADDRESS_PARAMETER_ID: |
2243 | 1 | dissect_add_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item); |
2244 | 1 | break; |
2245 | 2 | case DEL_IP_ADDRESS_PARAMETER_ID: |
2246 | 2 | dissect_del_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item); |
2247 | 2 | break; |
2248 | 0 | case ERROR_CAUSE_INDICATION_PARAMETER_ID: |
2249 | 0 | dissect_error_cause_indication_parameter(parameter_tvb, pinfo, parameter_tree); |
2250 | 0 | break; |
2251 | 0 | case SET_PRIMARY_ADDRESS_PARAMETER_ID: |
2252 | 0 | dissect_set_primary_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item); |
2253 | 0 | break; |
2254 | 0 | case SUCCESS_REPORT_PARAMETER_ID: |
2255 | 0 | dissect_success_report_parameter(parameter_tvb, parameter_tree, parameter_item); |
2256 | 0 | break; |
2257 | 0 | case ADAP_LAYER_INDICATION_PARAMETER_ID: |
2258 | 0 | dissect_adap_indication_parameter(parameter_tvb, parameter_tree, parameter_item); |
2259 | 0 | break; |
2260 | 157 | default: |
2261 | 157 | dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item); |
2262 | 157 | break; |
2263 | 331 | } |
2264 | 118 | decrement_dissection_depth(pinfo); |
2265 | | |
2266 | 118 | if (padding_length > 0) { |
2267 | 81 | proto_tree_add_item(parameter_tree, hf_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, ENC_NA); |
2268 | 81 | } |
2269 | 118 | } |
2270 | | |
2271 | | static void |
2272 | | // NOLINTNEXTLINE(misc-no-recursion) |
2273 | | dissect_parameters(tvbuff_t *parameters_tvb, packet_info *pinfo, proto_tree *tree, proto_item *additional_item, bool dissecting_init_chunk, bool dissecting_init_ack_chunk) |
2274 | 199 | { |
2275 | 199 | int offset, length, total_length, remaining_length; |
2276 | 199 | tvbuff_t *parameter_tvb; |
2277 | 199 | bool final_parameter; |
2278 | | |
2279 | 199 | offset = 0; |
2280 | 199 | remaining_length = tvb_reported_length_remaining(parameters_tvb, offset); |
2281 | 476 | while (remaining_length > 0) { |
2282 | 277 | if ((offset > 0) && additional_item) |
2283 | 1 | proto_item_append_text(additional_item, " "); |
2284 | | |
2285 | 277 | length = tvb_get_ntohs(parameters_tvb, offset + PARAMETER_LENGTH_OFFSET); |
2286 | 277 | total_length = WS_ROUNDUP_4(length); |
2287 | | |
2288 | | /* If we have less bytes than we need, throw an exception while dissecting |
2289 | | * the parameter--not when generating the parameter_tvb below. |
2290 | | */ |
2291 | 277 | total_length = MIN(total_length, remaining_length); |
2292 | | |
2293 | | /* create a tvb for the parameter including the padding bytes */ |
2294 | 277 | parameter_tvb = tvb_new_subset_length(parameters_tvb, offset, total_length); |
2295 | | /* get rid of the handled parameter */ |
2296 | 277 | offset += total_length; |
2297 | 277 | remaining_length = tvb_reported_length_remaining(parameters_tvb, offset); |
2298 | 277 | if (remaining_length > 0) { |
2299 | 100 | final_parameter = false; |
2300 | 177 | } else { |
2301 | 177 | final_parameter = true; |
2302 | 177 | } |
2303 | 277 | dissect_parameter(parameter_tvb, pinfo, tree, additional_item, dissecting_init_chunk, dissecting_init_ack_chunk, final_parameter); |
2304 | 277 | } |
2305 | 199 | } |
2306 | | |
2307 | | |
2308 | | /* |
2309 | | * Code to handle error causes for ABORT and ERROR chunks |
2310 | | */ |
2311 | | |
2312 | | |
2313 | 1.02k | #define CAUSE_CODE_LENGTH 2 |
2314 | 432 | #define CAUSE_LENGTH_LENGTH 2 |
2315 | 112 | #define CAUSE_HEADER_LENGTH (CAUSE_CODE_LENGTH + CAUSE_LENGTH_LENGTH) |
2316 | | |
2317 | 1.38k | #define CAUSE_HEADER_OFFSET 0 |
2318 | 1.16k | #define CAUSE_CODE_OFFSET CAUSE_HEADER_OFFSET |
2319 | 754 | #define CAUSE_LENGTH_OFFSET (CAUSE_CODE_OFFSET + CAUSE_CODE_LENGTH) |
2320 | 161 | #define CAUSE_INFO_OFFSET (CAUSE_LENGTH_OFFSET + CAUSE_LENGTH_LENGTH) |
2321 | | |
2322 | | |
2323 | 10 | #define CAUSE_STREAM_IDENTIFIER_LENGTH 2 |
2324 | 5 | #define CAUSE_RESERVED_LENGTH 2 |
2325 | 15 | #define CAUSE_STREAM_IDENTIFIER_OFFSET CAUSE_INFO_OFFSET |
2326 | 5 | #define CAUSE_RESERVED_OFFSET (CAUSE_STREAM_IDENTIFIER_OFFSET + CAUSE_STREAM_IDENTIFIER_LENGTH) |
2327 | | |
2328 | | static void |
2329 | | dissect_invalid_stream_identifier_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item) |
2330 | 5 | { |
2331 | 5 | proto_tree_add_item(cause_tree, hf_cause_stream_identifier, cause_tvb, CAUSE_STREAM_IDENTIFIER_OFFSET, CAUSE_STREAM_IDENTIFIER_LENGTH, ENC_BIG_ENDIAN); |
2332 | 5 | proto_tree_add_item(cause_tree, hf_cause_reserved, cause_tvb, CAUSE_RESERVED_OFFSET, CAUSE_RESERVED_LENGTH, ENC_BIG_ENDIAN); |
2333 | 5 | proto_item_append_text(cause_item, " (SID: %u)", tvb_get_ntohs(cause_tvb, CAUSE_STREAM_IDENTIFIER_OFFSET)); |
2334 | 5 | } |
2335 | | |
2336 | 30 | #define CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH 4 |
2337 | 3.51k | #define CAUSE_MISSING_PARAMETER_TYPE_LENGTH 2 |
2338 | | |
2339 | 30 | #define CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET CAUSE_INFO_OFFSET |
2340 | 15 | #define CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET (CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET + \ |
2341 | 15 | CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH ) |
2342 | | |
2343 | | static void |
2344 | | dissect_missing_mandatory_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree) |
2345 | 15 | { |
2346 | 15 | uint32_t number_of_missing_parameters, missing_parameter_number; |
2347 | 15 | unsigned offset; |
2348 | | |
2349 | 15 | proto_tree_add_item_ret_uint(cause_tree, hf_cause_number_of_missing_parameters, cause_tvb, CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET, |
2350 | 15 | CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH, ENC_BIG_ENDIAN, &number_of_missing_parameters); |
2351 | 15 | offset = CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET; |
2352 | 1.77k | for(missing_parameter_number = 0; missing_parameter_number < number_of_missing_parameters; missing_parameter_number++) { |
2353 | 1.75k | proto_tree_add_item(cause_tree, hf_cause_missing_parameter_type, cause_tvb, offset, CAUSE_MISSING_PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN); |
2354 | 1.75k | offset += CAUSE_MISSING_PARAMETER_TYPE_LENGTH; |
2355 | 1.75k | } |
2356 | 15 | } |
2357 | | |
2358 | 2 | #define CAUSE_MEASURE_OF_STALENESS_LENGTH 4 |
2359 | 4 | #define CAUSE_MEASURE_OF_STALENESS_OFFSET CAUSE_INFO_OFFSET |
2360 | | |
2361 | | static void |
2362 | | dissect_stale_cookie_error_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item) |
2363 | 2 | { |
2364 | 2 | proto_tree_add_item(cause_tree, hf_cause_measure_of_staleness, cause_tvb, CAUSE_MEASURE_OF_STALENESS_OFFSET, CAUSE_MEASURE_OF_STALENESS_LENGTH, ENC_BIG_ENDIAN); |
2365 | 2 | proto_item_append_text(cause_item, " (Measure: %u usec)", tvb_get_ntohl(cause_tvb, CAUSE_MEASURE_OF_STALENESS_OFFSET)); |
2366 | 2 | } |
2367 | | |
2368 | | static void |
2369 | | dissect_out_of_resource_cause(tvbuff_t *cause_tvb _U_) |
2370 | 2 | { |
2371 | 2 | } |
2372 | | |
2373 | | static void |
2374 | | // NOLINTNEXTLINE(misc-no-recursion) |
2375 | | dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item) |
2376 | 4 | { |
2377 | 4 | uint16_t parameter_length; |
2378 | 4 | tvbuff_t *parameter_tvb; |
2379 | | |
2380 | 4 | parameter_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2381 | 4 | parameter_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2382 | 4 | MIN(parameter_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2383 | 4 | dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, false, false, true); |
2384 | 4 | } |
2385 | | |
2386 | | static bool |
2387 | | dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, proto_tree *sctp_tree, sctp_half_assoc_t *assoc, bool useinfo); |
2388 | | |
2389 | | static void |
2390 | | // NOLINTNEXTLINE(misc-no-recursion) |
2391 | | dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item) |
2392 | 5 | { |
2393 | 5 | uint16_t chunk_length; |
2394 | 5 | uint8_t unrecognized_type; |
2395 | 5 | tvbuff_t *unrecognized_chunk_tvb; |
2396 | | |
2397 | 5 | chunk_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2398 | 5 | unrecognized_chunk_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2399 | 5 | MIN(chunk_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2400 | 5 | dissect_sctp_chunk(unrecognized_chunk_tvb, pinfo, cause_tree,cause_tree, NULL, false); |
2401 | 5 | unrecognized_type = tvb_get_uint8(unrecognized_chunk_tvb, CHUNK_TYPE_OFFSET); |
2402 | 5 | proto_item_append_text(cause_item, " (Type: %u (%s))", unrecognized_type, val_to_str_const(unrecognized_type, chunk_type_values, "unknown")); |
2403 | 5 | } |
2404 | | |
2405 | | static void |
2406 | | dissect_invalid_mandatory_parameter_cause(tvbuff_t *cause_tvb _U_) |
2407 | 2 | { |
2408 | 2 | } |
2409 | | |
2410 | | static void |
2411 | | // NOLINTNEXTLINE(misc-no-recursion) |
2412 | | dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree) |
2413 | 2 | { |
2414 | 2 | uint16_t cause_info_length; |
2415 | 2 | tvbuff_t *unrecognized_parameters_tvb; |
2416 | | |
2417 | 2 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2418 | | |
2419 | 2 | unrecognized_parameters_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2420 | 2 | MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2421 | 2 | dissect_parameters(unrecognized_parameters_tvb, pinfo, cause_tree, NULL, false, false); |
2422 | 2 | } |
2423 | | |
2424 | 3 | #define CAUSE_TSN_LENGTH 4 |
2425 | 6 | #define CAUSE_TSN_OFFSET CAUSE_INFO_OFFSET |
2426 | | |
2427 | | static void |
2428 | | dissect_no_user_data_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item) |
2429 | 3 | { |
2430 | 3 | proto_tree_add_item(cause_tree, hf_cause_tsn, cause_tvb, CAUSE_TSN_OFFSET, CAUSE_TSN_LENGTH, ENC_BIG_ENDIAN); |
2431 | 3 | proto_item_append_text(cause_item, " (TSN: %u)", tvb_get_ntohl(cause_tvb, CAUSE_TSN_OFFSET)); |
2432 | 3 | } |
2433 | | |
2434 | | static void |
2435 | | dissect_cookie_received_while_shutting_down_cause(tvbuff_t *cause_tvb _U_) |
2436 | 3 | { |
2437 | 3 | } |
2438 | | |
2439 | | static void |
2440 | | // NOLINTNEXTLINE(misc-no-recursion) |
2441 | | dissect_restart_with_new_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item) |
2442 | 2 | { |
2443 | 2 | uint16_t cause_info_length; |
2444 | 2 | tvbuff_t *parameter_tvb; |
2445 | | |
2446 | 2 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2447 | 2 | parameter_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2448 | 2 | MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2449 | 2 | proto_item_append_text(cause_item, " (New addresses: "); |
2450 | 2 | dissect_parameters(parameter_tvb, pinfo, cause_tree, cause_item, false, false); |
2451 | 2 | proto_item_append_text(cause_item, ")"); |
2452 | 2 | } |
2453 | | |
2454 | | static void |
2455 | | dissect_user_initiated_abort_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree) |
2456 | 1 | { |
2457 | 1 | uint16_t cause_info_length; |
2458 | | |
2459 | 1 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2460 | 1 | if (cause_info_length > 0) |
2461 | 1 | proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA); |
2462 | 1 | } |
2463 | | |
2464 | | static void |
2465 | | dissect_protocol_violation_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree) |
2466 | 2 | { |
2467 | 2 | uint16_t cause_info_length; |
2468 | | |
2469 | 2 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2470 | 2 | if (cause_info_length > 0) |
2471 | 2 | proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA); |
2472 | 2 | } |
2473 | | |
2474 | | static void |
2475 | | dissect_missing_dtls_chunk_support_cause(tvbuff_t *cause_tvb _U_, proto_tree *cause_tree _U_) |
2476 | 2 | { |
2477 | 2 | } |
2478 | | |
2479 | | static void |
2480 | | dissect_no_common_dtls_key_management_method_cause(tvbuff_t *cause_tvb _U_, proto_tree *cause_tree _U_) |
2481 | 0 | { |
2482 | 0 | } |
2483 | | |
2484 | | static void |
2485 | | dissect_dtls_key_management_tie_breaker_collision_cause(tvbuff_t *cause_tvb _U_, proto_tree *cause_tree _U_) |
2486 | 0 | { |
2487 | 0 | } |
2488 | | |
2489 | | static void |
2490 | | dissect_incompatible_dtls_key_management_roles_cause(tvbuff_t *cause_tvb _U_, proto_tree *cause_tree _U_) |
2491 | 0 | { |
2492 | 0 | } |
2493 | | |
2494 | | static void |
2495 | | // NOLINTNEXTLINE(misc-no-recursion) |
2496 | | dissect_delete_last_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item) |
2497 | 1 | { |
2498 | 1 | uint16_t cause_info_length; |
2499 | 1 | tvbuff_t *parameter_tvb; |
2500 | | |
2501 | 1 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2502 | 1 | parameter_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2503 | 1 | MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2504 | 1 | proto_item_append_text(cause_item, " (Last address: "); |
2505 | 1 | dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, false, false, false); |
2506 | 1 | proto_item_append_text(cause_item, ")"); |
2507 | 1 | } |
2508 | | |
2509 | | static void |
2510 | | // NOLINTNEXTLINE(misc-no-recursion) |
2511 | | dissect_resource_outage_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree) |
2512 | 1 | { |
2513 | 1 | uint16_t cause_info_length; |
2514 | 1 | tvbuff_t *parameter_tvb; |
2515 | | |
2516 | 1 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2517 | 1 | parameter_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2518 | 1 | MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2519 | 1 | dissect_parameter(parameter_tvb, pinfo, cause_tree, NULL, false, false, false); |
2520 | 1 | } |
2521 | | |
2522 | | static void |
2523 | | // NOLINTNEXTLINE(misc-no-recursion) |
2524 | | dissect_delete_source_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item) |
2525 | 0 | { |
2526 | 0 | uint16_t cause_info_length; |
2527 | 0 | tvbuff_t *parameter_tvb; |
2528 | |
|
2529 | 0 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2530 | 0 | parameter_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2531 | 0 | MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2532 | 0 | proto_item_append_text(cause_item, " (Deleted address: "); |
2533 | 0 | dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, false, false, false); |
2534 | 0 | proto_item_append_text(cause_item, ")"); |
2535 | 0 | } |
2536 | | |
2537 | | static void |
2538 | | // NOLINTNEXTLINE(misc-no-recursion) |
2539 | | dissect_request_refused_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree) |
2540 | 1 | { |
2541 | 1 | uint16_t cause_info_length; |
2542 | 1 | tvbuff_t *parameter_tvb; |
2543 | | |
2544 | 1 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2545 | 1 | parameter_tvb = tvb_new_subset_length(cause_tvb, CAUSE_INFO_OFFSET, |
2546 | 1 | MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET))); |
2547 | 1 | dissect_parameter(parameter_tvb, pinfo, cause_tree, NULL, false, false, false); |
2548 | 1 | } |
2549 | | |
2550 | | static void |
2551 | | dissect_unsupported_hmac_id_cause(tvbuff_t *cause_tvb, packet_info *pinfo _U_, proto_tree *cause_tree) |
2552 | 0 | { |
2553 | 0 | proto_tree_add_item(cause_tree, hf_hmac_id, cause_tvb, CAUSE_INFO_OFFSET, HMAC_ID_LENGTH, ENC_BIG_ENDIAN); |
2554 | 0 | } |
2555 | | |
2556 | | static void |
2557 | | dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item) |
2558 | 93 | { |
2559 | 93 | uint16_t cause_info_length; |
2560 | | |
2561 | 93 | cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH; |
2562 | 93 | if (cause_info_length > 0) |
2563 | 87 | proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA); |
2564 | 93 | proto_item_append_text(cause_item, " (Code: %u, information length: %u byte%s)", tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET), cause_info_length, plurality(cause_info_length, "", "s")); |
2565 | 93 | } |
2566 | | |
2567 | 5 | #define INVALID_STREAM_IDENTIFIER 0x0001 |
2568 | 15 | #define MISSING_MANDATORY_PARAMETERS 0x0002 |
2569 | 2 | #define STALE_COOKIE_ERROR 0x0003 |
2570 | 2 | #define OUT_OF_RESOURCE 0x0004 |
2571 | 4 | #define UNRESOLVABLE_ADDRESS 0x0005 |
2572 | 5 | #define UNRECOGNIZED_CHUNK_TYPE 0x0006 |
2573 | 2 | #define INVALID_MANDATORY_PARAMETER 0x0007 |
2574 | 2 | #define UNRECOGNIZED_PARAMETERS 0x0008 |
2575 | 3 | #define NO_USER_DATA 0x0009 |
2576 | 3 | #define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN 0x000a |
2577 | 2 | #define RESTART_WITH_NEW_ADDRESSES 0x000b |
2578 | 1 | #define USER_INITIATED_ABORT 0x000c |
2579 | 2 | #define PROTOCOL_VIOLATION 0x000d |
2580 | 2 | #define MISSING_DTLS_CHUNK_SUPPORT 0x0064 |
2581 | 0 | #define NO_COMMON_DTLS_KEY_MANAGEMENT_METHOD 0x0065 |
2582 | 0 | #define DTLS_KEY_MANAGEMENT_TIE_BREAKER_COLLISION 0x0066 |
2583 | 0 | #define INCOMPATIBLE_DTLS_KEY_MANAGEMENT_ROLES 0x0067 |
2584 | 1 | #define REQUEST_TO_DELETE_LAST_ADDRESS 0x00a0 |
2585 | 1 | #define OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE 0x00a1 |
2586 | 0 | #define REQUEST_TO_DELETE_SOURCE_ADDRESS 0x00a2 |
2587 | | #define ABORT_DUE_TO_ILLEGAL_ASCONF 0x00a3 |
2588 | 1 | #define REQUEST_REFUSED 0x00a4 |
2589 | 0 | #define UNSUPPORTED_HMAC_ID 0x0105 |
2590 | | |
2591 | | static const value_string cause_code_values[] = { |
2592 | | { INVALID_STREAM_IDENTIFIER, "Invalid stream identifier" }, |
2593 | | { MISSING_MANDATORY_PARAMETERS, "Missing mandatory parameter" }, |
2594 | | { STALE_COOKIE_ERROR, "Stale cookie error" }, |
2595 | | { OUT_OF_RESOURCE, "Out of resource" }, |
2596 | | { UNRESOLVABLE_ADDRESS, "Unresolvable address" }, |
2597 | | { UNRECOGNIZED_CHUNK_TYPE, "Unrecognized chunk type" }, |
2598 | | { INVALID_MANDATORY_PARAMETER, "Invalid mandatory parameter" }, |
2599 | | { UNRECOGNIZED_PARAMETERS, "Unrecognized parameters" }, |
2600 | | { NO_USER_DATA, "No user data" }, |
2601 | | { COOKIE_RECEIVED_WHILE_SHUTTING_DOWN, "Cookie received while shutting down" }, |
2602 | | { RESTART_WITH_NEW_ADDRESSES, "Restart of an association with new addresses" }, |
2603 | | { USER_INITIATED_ABORT, "User initiated ABORT" }, |
2604 | | { PROTOCOL_VIOLATION, "Protocol violation" }, |
2605 | | { MISSING_DTLS_CHUNK_SUPPORT, "Missing DTLS chunk support" }, |
2606 | | { NO_COMMON_DTLS_KEY_MANAGEMENT_METHOD, "No common DTLS key management method" }, |
2607 | | { DTLS_KEY_MANAGEMENT_TIE_BREAKER_COLLISION, "DTLS key management tie breaker collision" }, |
2608 | | { INCOMPATIBLE_DTLS_KEY_MANAGEMENT_ROLES, "Incompatible DTLS key management roles" }, |
2609 | | { REQUEST_TO_DELETE_LAST_ADDRESS, "Request to delete last address" }, |
2610 | | { OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE, "Operation refused due to resource shortage" }, |
2611 | | { REQUEST_TO_DELETE_SOURCE_ADDRESS, "Request to delete source address" }, |
2612 | | { ABORT_DUE_TO_ILLEGAL_ASCONF, "Association Aborted due to illegal ASCONF-ACK" }, |
2613 | | { REQUEST_REFUSED, "Request refused - no authorization" }, |
2614 | | { UNSUPPORTED_HMAC_ID, "Unsupported HMAC identifier" }, |
2615 | | { 0, NULL } }; |
2616 | | |
2617 | | |
2618 | | static void |
2619 | | // NOLINTNEXTLINE(misc-no-recursion) |
2620 | | dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_tree) |
2621 | 159 | { |
2622 | 159 | uint16_t code, length, padding_length; |
2623 | 159 | proto_item *cause_item; |
2624 | 159 | proto_tree *cause_tree; |
2625 | | |
2626 | 159 | code = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET); |
2627 | 159 | length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET); |
2628 | 159 | padding_length = tvb_reported_length(cause_tvb) - length; |
2629 | | |
2630 | 159 | cause_tree = proto_tree_add_subtree_format(chunk_tree, cause_tvb, CAUSE_HEADER_OFFSET, -1, |
2631 | 159 | ett_sctp_chunk_cause, &cause_item, "%s cause", val_to_str_const(code, cause_code_values, "Unknown")); |
2632 | | |
2633 | 159 | proto_tree_add_item(cause_tree, hf_cause_code, cause_tvb, CAUSE_CODE_OFFSET, CAUSE_CODE_LENGTH, ENC_BIG_ENDIAN); |
2634 | 159 | proto_tree_add_item(cause_tree, hf_cause_length, cause_tvb, CAUSE_LENGTH_OFFSET, CAUSE_LENGTH_LENGTH, ENC_BIG_ENDIAN); |
2635 | | /* XXX - add expert info if length is bogus? */ |
2636 | | |
2637 | 159 | increment_dissection_depth(pinfo); |
2638 | 159 | switch(code) { |
2639 | 5 | case INVALID_STREAM_IDENTIFIER: |
2640 | 5 | dissect_invalid_stream_identifier_cause(cause_tvb, cause_tree, cause_item); |
2641 | 5 | break; |
2642 | 15 | case MISSING_MANDATORY_PARAMETERS: |
2643 | 15 | dissect_missing_mandatory_parameters_cause(cause_tvb, cause_tree); |
2644 | 15 | break; |
2645 | 2 | case STALE_COOKIE_ERROR: |
2646 | 2 | dissect_stale_cookie_error_cause(cause_tvb, cause_tree, cause_item); |
2647 | 2 | break; |
2648 | 2 | case OUT_OF_RESOURCE: |
2649 | 2 | dissect_out_of_resource_cause(cause_tvb); |
2650 | 2 | break; |
2651 | 4 | case UNRESOLVABLE_ADDRESS: |
2652 | 4 | dissect_unresolvable_address_cause(cause_tvb, pinfo, cause_tree, cause_item); |
2653 | 4 | break; |
2654 | 5 | case UNRECOGNIZED_CHUNK_TYPE: |
2655 | 5 | dissect_unrecognized_chunk_type_cause(cause_tvb, pinfo, cause_tree, cause_item); |
2656 | 5 | break; |
2657 | 2 | case INVALID_MANDATORY_PARAMETER: |
2658 | 2 | dissect_invalid_mandatory_parameter_cause(cause_tvb); |
2659 | 2 | break; |
2660 | 2 | case UNRECOGNIZED_PARAMETERS: |
2661 | 2 | dissect_unrecognized_parameters_cause(cause_tvb, pinfo, cause_tree); |
2662 | 2 | break; |
2663 | 3 | case NO_USER_DATA: |
2664 | 3 | dissect_no_user_data_cause(cause_tvb, cause_tree, cause_item); |
2665 | 3 | break; |
2666 | 3 | case COOKIE_RECEIVED_WHILE_SHUTTING_DOWN: |
2667 | 3 | dissect_cookie_received_while_shutting_down_cause(cause_tvb); |
2668 | 3 | break; |
2669 | 2 | case RESTART_WITH_NEW_ADDRESSES: |
2670 | 2 | dissect_restart_with_new_address_cause(cause_tvb, pinfo, cause_tree, cause_item); |
2671 | 2 | break; |
2672 | 1 | case USER_INITIATED_ABORT: |
2673 | 1 | dissect_user_initiated_abort_cause(cause_tvb, cause_tree); |
2674 | 1 | break; |
2675 | 2 | case PROTOCOL_VIOLATION: |
2676 | 2 | dissect_protocol_violation_cause(cause_tvb, cause_tree); |
2677 | 2 | break; |
2678 | 2 | case MISSING_DTLS_CHUNK_SUPPORT: |
2679 | 2 | dissect_missing_dtls_chunk_support_cause(cause_tvb, cause_tree); |
2680 | 2 | break; |
2681 | 0 | case NO_COMMON_DTLS_KEY_MANAGEMENT_METHOD: |
2682 | 0 | dissect_no_common_dtls_key_management_method_cause(cause_tvb, cause_tree); |
2683 | 0 | break; |
2684 | 0 | case DTLS_KEY_MANAGEMENT_TIE_BREAKER_COLLISION: |
2685 | 0 | dissect_dtls_key_management_tie_breaker_collision_cause(cause_tvb, cause_tree); |
2686 | 0 | break; |
2687 | 0 | case INCOMPATIBLE_DTLS_KEY_MANAGEMENT_ROLES: |
2688 | 0 | dissect_incompatible_dtls_key_management_roles_cause(cause_tvb, cause_tree); |
2689 | 0 | break; |
2690 | 1 | case REQUEST_TO_DELETE_LAST_ADDRESS: |
2691 | 1 | dissect_delete_last_address_cause(cause_tvb, pinfo, cause_tree, cause_item); |
2692 | 1 | break; |
2693 | 1 | case OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE: |
2694 | 1 | dissect_resource_outage_cause(cause_tvb, pinfo, cause_tree); |
2695 | 1 | break; |
2696 | 0 | case REQUEST_TO_DELETE_SOURCE_ADDRESS: |
2697 | 0 | dissect_delete_source_address_cause(cause_tvb, pinfo, cause_tree, cause_item); |
2698 | 0 | break; |
2699 | 1 | case REQUEST_REFUSED: |
2700 | 1 | dissect_request_refused_cause(cause_tvb, pinfo, cause_tree); |
2701 | 1 | break; |
2702 | 0 | case UNSUPPORTED_HMAC_ID: |
2703 | 0 | dissect_unsupported_hmac_id_cause(cause_tvb, pinfo, cause_tree); |
2704 | 0 | break; |
2705 | 93 | default: |
2706 | 93 | dissect_unknown_cause(cause_tvb, cause_tree, cause_item); |
2707 | 93 | break; |
2708 | 159 | } |
2709 | 91 | decrement_dissection_depth(pinfo); |
2710 | | |
2711 | 91 | if (padding_length > 0) |
2712 | 61 | proto_tree_add_item(cause_tree, hf_cause_padding, cause_tvb, CAUSE_HEADER_OFFSET + length, padding_length, ENC_NA); |
2713 | 91 | } |
2714 | | |
2715 | | static void |
2716 | | // NOLINTNEXTLINE(misc-no-recursion) |
2717 | | dissect_error_causes(tvbuff_t *causes_tvb, packet_info *pinfo, proto_tree *tree) |
2718 | 98 | { |
2719 | 98 | int offset, length, total_length, remaining_length; |
2720 | 98 | tvbuff_t *cause_tvb; |
2721 | | |
2722 | 98 | offset = 0; |
2723 | 261 | while((remaining_length = tvb_reported_length_remaining(causes_tvb, offset))) { |
2724 | 163 | length = tvb_get_ntohs(causes_tvb, offset + CAUSE_LENGTH_OFFSET); |
2725 | 163 | total_length = WS_ROUNDUP_4(length); |
2726 | | |
2727 | | /* If we have less bytes than we need, throw an exception while dissecting |
2728 | | * the cause--not when generating the causes_tvb below. |
2729 | | */ |
2730 | 163 | total_length = MIN(total_length, remaining_length); |
2731 | | |
2732 | | /* create a tvb for the parameter including the padding bytes */ |
2733 | 163 | cause_tvb = tvb_new_subset_length(causes_tvb, offset, total_length); |
2734 | | |
2735 | 163 | dissect_error_cause(cause_tvb, pinfo, tree); |
2736 | | |
2737 | | /* get rid of the handled cause */ |
2738 | 163 | offset += total_length; |
2739 | 163 | } |
2740 | 98 | } |
2741 | | |
2742 | | |
2743 | | /* |
2744 | | * Code to actually dissect the packets |
2745 | | */ |
2746 | | |
2747 | | static bool try_heuristic_first; |
2748 | | |
2749 | | static bool |
2750 | | dissect_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree, uint32_t ppi) |
2751 | 18.8k | { |
2752 | 18.8k | uint32_t low_port, high_port; |
2753 | 18.8k | bool try_ppi, try_low_port, try_high_port; |
2754 | 18.8k | heur_dtbl_entry_t *hdtbl_entry; |
2755 | | |
2756 | 18.8k | if (enable_ulp_dissection) { |
2757 | | |
2758 | | /* XXX - we ignore port numbers of 0, as some dissectors use a port |
2759 | | number of 0 to disable the port. */ |
2760 | 18.8k | if (pinfo->srcport > pinfo->destport) { |
2761 | 8.91k | low_port = pinfo->destport; |
2762 | 8.91k | high_port = pinfo->srcport; |
2763 | 9.97k | } else { |
2764 | 9.97k | low_port = pinfo->srcport; |
2765 | 9.97k | high_port = pinfo->destport; |
2766 | 9.97k | } |
2767 | | |
2768 | 18.8k | try_ppi = false; |
2769 | 18.8k | if (dissector_is_uint_changed(sctp_ppi_dissector_table, ppi)) { |
2770 | 0 | if (dissector_try_uint_with_data(sctp_ppi_dissector_table, ppi, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) { |
2771 | 0 | return true; |
2772 | 0 | } |
2773 | 18.8k | } else { |
2774 | | /* The default; try it later */ |
2775 | 18.8k | try_ppi = true; |
2776 | 18.8k | } |
2777 | | |
2778 | 18.8k | try_low_port = false; |
2779 | 18.8k | if (low_port != 0) { |
2780 | 15.4k | if (dissector_is_uint_changed(sctp_port_dissector_table, low_port)) { |
2781 | 0 | if (dissector_try_uint_with_data(sctp_port_dissector_table, low_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) { |
2782 | 0 | return true; |
2783 | 0 | } |
2784 | 15.4k | } else { |
2785 | | /* The default; try it later */ |
2786 | 15.4k | try_low_port = true; |
2787 | 15.4k | } |
2788 | 15.4k | } |
2789 | | |
2790 | 18.8k | try_high_port = false; |
2791 | 18.8k | if (high_port != 0) { |
2792 | 18.0k | if (dissector_is_uint_changed(sctp_port_dissector_table, high_port)) { |
2793 | 0 | if (dissector_try_uint_with_data(sctp_port_dissector_table, high_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) { |
2794 | 0 | return true; |
2795 | 0 | } |
2796 | 18.0k | } else { |
2797 | | /* The default; try it later */ |
2798 | 18.0k | try_high_port = true; |
2799 | 18.0k | } |
2800 | 18.0k | } |
2801 | | |
2802 | 18.8k | if (try_heuristic_first) { |
2803 | | /* do lookup with the heuristic subdissector table */ |
2804 | 0 | if (dissector_try_heuristic(sctp_heur_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, GUINT_TO_POINTER(ppi))) |
2805 | 0 | return true; |
2806 | 0 | } |
2807 | | |
2808 | | /* Do lookups with the subdissector table. |
2809 | | First try the PPI. |
2810 | | |
2811 | | When trying port numbers, we try the port number with the lower value |
2812 | | first, followed by the port number with the higher value. This means |
2813 | | that, for packets where a dissector is registered for *both* port |
2814 | | numbers, and where there's no match on the PPI: |
2815 | | |
2816 | | 1) we pick the same dissector for traffic going in both directions; |
2817 | | |
2818 | | 2) we prefer the port number that's more likely to be the right |
2819 | | one (as that prefers well-known ports to reserved ports); |
2820 | | |
2821 | | although there is, of course, no guarantee that any such strategy |
2822 | | will always pick the right port number. */ |
2823 | 18.8k | if (try_ppi && |
2824 | 18.8k | dissector_try_uint_with_data(sctp_ppi_dissector_table, ppi, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) |
2825 | 15.7k | return true; |
2826 | | |
2827 | 3.12k | if (try_low_port && |
2828 | 187 | dissector_try_uint_with_data(sctp_port_dissector_table, low_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) |
2829 | 5 | return true; |
2830 | 3.11k | if (try_high_port && |
2831 | 141 | dissector_try_uint_with_data(sctp_port_dissector_table, high_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) |
2832 | 10 | return true; |
2833 | | |
2834 | 3.10k | if (!try_heuristic_first) { |
2835 | | /* do lookup with the heuristic subdissector table */ |
2836 | 86 | if (dissector_try_heuristic(sctp_heur_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, GUINT_TO_POINTER(ppi))) |
2837 | 5 | return true; |
2838 | 86 | } |
2839 | 3.10k | } |
2840 | | /* Oh, well, we don't know this; dissect it as data. */ |
2841 | 3.10k | call_data_dissector(payload_tvb, pinfo, tree); |
2842 | 3.10k | return true; |
2843 | 18.8k | } |
2844 | | |
2845 | 235k | #define DATA_CHUNK_TSN_LENGTH 4 |
2846 | 195k | #define DATA_CHUNK_STREAM_ID_LENGTH 2 |
2847 | 155k | #define DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH 2 |
2848 | 116k | #define DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH 4 |
2849 | 550 | #define I_DATA_CHUNK_RESERVED_LENGTH 2 |
2850 | 432 | #define I_DATA_CHUNK_MID_LENGTH 4 |
2851 | 272 | #define I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH 4 |
2852 | 23 | #define I_DATA_CHUNK_FSN_LENGTH 4 |
2853 | | |
2854 | 176k | #define DATA_CHUNK_TSN_OFFSET (CHUNK_VALUE_OFFSET + 0) |
2855 | 136k | #define DATA_CHUNK_STREAM_ID_OFFSET (DATA_CHUNK_TSN_OFFSET + DATA_CHUNK_TSN_LENGTH) |
2856 | 97.3k | #define DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET (DATA_CHUNK_STREAM_ID_OFFSET + \ |
2857 | 97.3k | DATA_CHUNK_STREAM_ID_LENGTH) |
2858 | 58.2k | #define DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET (DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET + \ |
2859 | 58.2k | DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH) |
2860 | 19.4k | #define DATA_CHUNK_PAYLOAD_OFFSET (DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET + \ |
2861 | 19.4k | DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH) |
2862 | 351 | #define I_DATA_CHUNK_RESERVED_OFFSET (DATA_CHUNK_STREAM_ID_OFFSET + \ |
2863 | 351 | DATA_CHUNK_STREAM_ID_LENGTH) |
2864 | 303 | #define I_DATA_CHUNK_MID_OFFSET (I_DATA_CHUNK_RESERVED_OFFSET + \ |
2865 | 303 | I_DATA_CHUNK_RESERVED_LENGTH) |
2866 | 124 | #define I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET (I_DATA_CHUNK_MID_OFFSET + \ |
2867 | 124 | I_DATA_CHUNK_MID_LENGTH) |
2868 | 61 | #define I_DATA_CHUNK_FSN_OFFSET (I_DATA_CHUNK_MID_OFFSET + \ |
2869 | 61 | I_DATA_CHUNK_MID_LENGTH) |
2870 | 48 | #define I_DATA_CHUNK_PAYLOAD_OFFSET (I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET + \ |
2871 | 48 | I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH) |
2872 | | |
2873 | 78.1k | #define DATA_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \ |
2874 | 78.1k | DATA_CHUNK_TSN_LENGTH + \ |
2875 | 78.1k | DATA_CHUNK_STREAM_ID_LENGTH + \ |
2876 | 78.1k | DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH + \ |
2877 | 78.1k | DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH) |
2878 | 199 | #define I_DATA_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \ |
2879 | 199 | DATA_CHUNK_TSN_LENGTH + \ |
2880 | 199 | DATA_CHUNK_STREAM_ID_LENGTH + \ |
2881 | 199 | I_DATA_CHUNK_RESERVED_LENGTH + \ |
2882 | 199 | I_DATA_CHUNK_MID_LENGTH +\ |
2883 | 199 | I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH) |
2884 | | |
2885 | 19.4k | #define SCTP_DATA_CHUNK_E_BIT 0x01 |
2886 | 19.4k | #define SCTP_DATA_CHUNK_B_BIT 0x02 |
2887 | 19.4k | #define SCTP_DATA_CHUNK_U_BIT 0x04 |
2888 | 16 | #define SCTP_DATA_CHUNK_I_BIT 0x08 |
2889 | | |
2890 | | /* table to hold fragmented SCTP messages */ |
2891 | | static GHashTable *frag_table; |
2892 | | |
2893 | | |
2894 | | typedef struct _frag_key { |
2895 | | uint16_t sport; |
2896 | | uint16_t dport; |
2897 | | uint32_t verification_tag; |
2898 | | uint16_t stream_id; |
2899 | | uint32_t stream_seq_num; |
2900 | | uint8_t u_bit; |
2901 | | } frag_key; |
2902 | | |
2903 | | |
2904 | | static int |
2905 | | frag_equal(const void *k1, const void *k2) |
2906 | 926 | { |
2907 | 926 | const frag_key *key1 = (const frag_key *) k1; |
2908 | 926 | const frag_key *key2 = (const frag_key *) k2; |
2909 | | |
2910 | 926 | return ( (key1->sport == key2->sport) && |
2911 | 858 | (key1->dport == key2->dport) && |
2912 | 781 | (key1->verification_tag == key2->verification_tag) && |
2913 | 781 | (key1->stream_id == key2->stream_id) && |
2914 | 688 | (key1->stream_seq_num == key2->stream_seq_num) && |
2915 | 684 | (key1->u_bit == key2->u_bit) |
2916 | 926 | ? true : false); |
2917 | 926 | } |
2918 | | |
2919 | | |
2920 | | static unsigned |
2921 | | frag_hash(const void *k) |
2922 | 1.15k | { |
2923 | 1.15k | const frag_key *key = (const frag_key *) k; |
2924 | | |
2925 | 1.15k | return key->sport ^ key->dport ^ key->verification_tag ^ |
2926 | 1.15k | key->stream_id ^ key->stream_seq_num ^ key->u_bit; |
2927 | 1.15k | } |
2928 | | |
2929 | | |
2930 | | static void |
2931 | | frag_free_msgs(sctp_frag_msg *msg) |
2932 | 0 | { |
2933 | 0 | sctp_frag_be *beginend; |
2934 | 0 | sctp_fragment *fragment; |
2935 | | |
2936 | | /* free all begins */ |
2937 | 0 | while (msg->begins) { |
2938 | 0 | beginend = msg->begins; |
2939 | 0 | msg->begins = msg->begins->next; |
2940 | 0 | g_free(beginend); |
2941 | 0 | } |
2942 | | |
2943 | | /* free all ends */ |
2944 | 0 | while (msg->ends) { |
2945 | 0 | beginend = msg->ends; |
2946 | 0 | msg->ends = msg->ends->next; |
2947 | 0 | g_free(beginend); |
2948 | 0 | } |
2949 | | |
2950 | | /* free all fragments */ |
2951 | 0 | while (msg->fragments) { |
2952 | 0 | fragment = msg->fragments; |
2953 | 0 | msg->fragments = msg->fragments->next; |
2954 | 0 | g_free(fragment->data); |
2955 | 0 | g_free(fragment); |
2956 | 0 | } |
2957 | | |
2958 | | /* msg->messages is wmem_ allocated, no need to free it */ |
2959 | |
|
2960 | 0 | g_free(msg); |
2961 | 0 | } |
2962 | | |
2963 | | static void |
2964 | | sctp_init(void) |
2965 | 16 | { |
2966 | 16 | frag_table = g_hash_table_new_full(frag_hash, frag_equal, |
2967 | 16 | (GDestroyNotify)g_free, (GDestroyNotify)frag_free_msgs); |
2968 | 16 | num_assocs = 0; |
2969 | 16 | } |
2970 | | |
2971 | | static void |
2972 | | sctp_cleanup(void) |
2973 | 0 | { |
2974 | 0 | g_hash_table_destroy(frag_table); |
2975 | 0 | } |
2976 | | |
2977 | | |
2978 | | static sctp_frag_msg* |
2979 | | find_message(uint16_t stream_id, uint32_t stream_seq_num, uint8_t u_bit) |
2980 | 918 | { |
2981 | 918 | frag_key key; |
2982 | | |
2983 | 918 | key.sport = sctp_info.sport; |
2984 | 918 | key.dport = sctp_info.dport; |
2985 | 918 | key.verification_tag = sctp_info.verification_tag; |
2986 | 918 | key.stream_id = stream_id; |
2987 | 918 | key.stream_seq_num = stream_seq_num; |
2988 | 918 | key.u_bit = u_bit; |
2989 | | |
2990 | 918 | return (sctp_frag_msg *)g_hash_table_lookup(frag_table, &key); |
2991 | 918 | } |
2992 | | |
2993 | | |
2994 | | static sctp_fragment* |
2995 | | find_fragment(uint32_t tsn, uint16_t stream_id, uint32_t stream_seq_num, uint8_t u_bit) |
2996 | 317 | { |
2997 | 317 | sctp_frag_msg *msg; |
2998 | 317 | sctp_fragment *next_fragment; |
2999 | | |
3000 | 317 | msg = find_message(stream_id, stream_seq_num, u_bit); |
3001 | | |
3002 | 317 | if (msg) { |
3003 | 317 | next_fragment = msg->fragments; |
3004 | 398 | while (next_fragment) { |
3005 | 116 | if (next_fragment->tsn == tsn) |
3006 | 35 | return next_fragment; |
3007 | 81 | next_fragment = next_fragment->next; |
3008 | 81 | } |
3009 | 317 | } |
3010 | | |
3011 | 282 | return NULL; |
3012 | 317 | } |
3013 | | |
3014 | | |
3015 | | static sctp_fragment * |
3016 | | add_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t tsn, |
3017 | | uint16_t stream_id, uint32_t stream_seq_num, uint8_t b_bit, uint8_t e_bit, |
3018 | | uint8_t u_bit, uint32_t ppi, bool is_idata) |
3019 | 352 | { |
3020 | 352 | sctp_frag_msg *msg; |
3021 | 352 | sctp_fragment *fragment, *last_fragment; |
3022 | 352 | sctp_frag_be *beginend, *last_beginend; |
3023 | 352 | frag_key *key; |
3024 | | |
3025 | | /* Don't try to do reassembly on error packets */ |
3026 | 352 | if (pinfo->flags.in_error_pkt) |
3027 | 35 | return NULL; |
3028 | | |
3029 | | /* lookup message. if not found, create it */ |
3030 | 317 | msg = find_message(stream_id, stream_seq_num, u_bit); |
3031 | | |
3032 | 317 | if (!msg) { |
3033 | 234 | msg = g_new(sctp_frag_msg, 1); |
3034 | 234 | msg->begins = NULL; |
3035 | 234 | msg->ends = NULL; |
3036 | 234 | msg->fragments = NULL; |
3037 | 234 | msg->messages = NULL; |
3038 | 234 | msg->next = NULL; |
3039 | 234 | if (is_idata) |
3040 | 17 | if (b_bit) |
3041 | 4 | msg->ppi = ppi; |
3042 | 13 | else |
3043 | 13 | msg->ppi = 0; |
3044 | 217 | else |
3045 | 217 | msg->ppi = ppi; |
3046 | | |
3047 | 234 | key = g_new(frag_key, 1); |
3048 | 234 | key->sport = sctp_info.sport; |
3049 | 234 | key->dport = sctp_info.dport; |
3050 | 234 | key->verification_tag = sctp_info.verification_tag; |
3051 | 234 | key->stream_id = stream_id; |
3052 | 234 | key->stream_seq_num = stream_seq_num; |
3053 | 234 | key->u_bit = u_bit; |
3054 | | |
3055 | 234 | g_hash_table_insert(frag_table, key, msg); |
3056 | 234 | } else { |
3057 | 83 | if (b_bit) |
3058 | 10 | msg->ppi = ppi; |
3059 | 83 | } |
3060 | | |
3061 | | /* lookup segment. if not found, create it */ |
3062 | 317 | fragment = find_fragment(tsn, stream_id, stream_seq_num, u_bit); |
3063 | | |
3064 | 317 | if (fragment) { |
3065 | | /* this fragment is already known. |
3066 | | * compare frame number to check if it's a duplicate |
3067 | | */ |
3068 | 35 | if (fragment->frame_num == pinfo->num) { |
3069 | 28 | return fragment; |
3070 | 28 | } else { |
3071 | | /* There already is a fragment having the same ports, v_tag, |
3072 | | * stream id, stream_seq_num and tsn but it appeared in a different |
3073 | | * frame, so it must be a duplicate fragment. Maybe a retransmission? |
3074 | | * Mark it as duplicate and return NULL. |
3075 | | * |
3076 | | * Note: This won't happen if TSN analysis is on: the caller will have |
3077 | | * detected the retransmission and not pass it to the reassembly code. |
3078 | | */ |
3079 | 7 | col_append_str(pinfo->cinfo, COL_INFO, "(Duplicate Message Fragment) "); |
3080 | | |
3081 | 7 | proto_tree_add_uint(tree, hf_sctp_duplicate, tvb, 0, 0, fragment->frame_num); |
3082 | 7 | return NULL; |
3083 | 7 | } |
3084 | 35 | } |
3085 | | |
3086 | | /* There is no point in storing a fragment with no data in it */ |
3087 | 282 | if (tvb_captured_length(tvb) == 0) |
3088 | 26 | return NULL; |
3089 | | |
3090 | | /* create new fragment */ |
3091 | 256 | fragment = g_new(sctp_fragment, 1); |
3092 | 256 | fragment->frame_num = pinfo->num; |
3093 | 256 | fragment->tsn = tsn; |
3094 | 256 | fragment->len = tvb_captured_length(tvb); |
3095 | 256 | fragment->ppi = msg->ppi; |
3096 | 256 | fragment->next = NULL; |
3097 | 256 | fragment->data = (unsigned char *)g_malloc (fragment->len); |
3098 | 256 | tvb_memcpy(tvb, fragment->data, 0, fragment->len); |
3099 | | |
3100 | | /* add new fragment to linked list. sort ascending by tsn */ |
3101 | 256 | if (!msg->fragments) |
3102 | 211 | msg->fragments = fragment; |
3103 | 45 | else { |
3104 | 45 | if (msg->fragments->tsn > fragment->tsn) { |
3105 | 7 | fragment->next = msg->fragments; |
3106 | 7 | msg->fragments = fragment; |
3107 | 38 | } else { |
3108 | 38 | last_fragment = msg->fragments; |
3109 | 60 | while (last_fragment->next && |
3110 | 31 | last_fragment->next->tsn < fragment->tsn) |
3111 | 22 | last_fragment = last_fragment->next; |
3112 | | |
3113 | 38 | fragment->next = last_fragment->next; |
3114 | 38 | last_fragment->next = fragment; |
3115 | 38 | } |
3116 | 45 | } |
3117 | | |
3118 | | |
3119 | | /* save begin or end if necessary */ |
3120 | 256 | if (b_bit && !e_bit) { |
3121 | 31 | beginend = g_new(sctp_frag_be, 1); |
3122 | 31 | beginend->fragment = fragment; |
3123 | 31 | beginend->next = NULL; |
3124 | | |
3125 | | /* add begin to linked list. sort descending by tsn */ |
3126 | 31 | if (!msg->begins) |
3127 | 24 | msg->begins = beginend; |
3128 | 7 | else { |
3129 | 7 | if (msg->begins->fragment->tsn < beginend->fragment->tsn) { |
3130 | 4 | beginend->next = msg->begins; |
3131 | 4 | msg->begins = beginend; |
3132 | 4 | } else { |
3133 | 3 | last_beginend = msg->begins; |
3134 | 3 | while (last_beginend->next && |
3135 | 2 | last_beginend->next->fragment->tsn > beginend->fragment->tsn) |
3136 | 0 | last_beginend = last_beginend->next; |
3137 | | |
3138 | 3 | beginend->next = last_beginend->next; |
3139 | 3 | last_beginend->next = beginend; |
3140 | 3 | } |
3141 | 7 | } |
3142 | | |
3143 | 31 | } |
3144 | | |
3145 | 256 | if (!b_bit && e_bit) { |
3146 | 57 | beginend = g_new(sctp_frag_be, 1); |
3147 | 57 | beginend->fragment = fragment; |
3148 | 57 | beginend->next = NULL; |
3149 | | |
3150 | | /* add end to linked list. sort ascending by tsn */ |
3151 | 57 | if (!msg->ends) |
3152 | 51 | msg->ends = beginend; |
3153 | 6 | else { |
3154 | 6 | if (msg->ends->fragment->tsn > beginend->fragment->tsn) { |
3155 | 1 | beginend->next = msg->ends; |
3156 | 1 | msg->ends = beginend; |
3157 | 5 | } else { |
3158 | 5 | last_beginend = msg->ends; |
3159 | 7 | while (last_beginend->next && |
3160 | 3 | last_beginend->next->fragment->tsn < beginend->fragment->tsn) |
3161 | 2 | last_beginend = last_beginend->next; |
3162 | | |
3163 | 5 | beginend->next = last_beginend->next; |
3164 | 5 | last_beginend->next = beginend; |
3165 | 5 | } |
3166 | 6 | } |
3167 | | |
3168 | 57 | } |
3169 | | |
3170 | 256 | return fragment; |
3171 | 282 | } |
3172 | | |
3173 | | static tvbuff_t* |
3174 | | fragment_reassembly(tvbuff_t *tvb, sctp_fragment *fragment, |
3175 | | packet_info *pinfo, proto_tree *tree, uint16_t stream_id, |
3176 | | uint32_t stream_seq_num, uint8_t u_bit) |
3177 | 284 | { |
3178 | 284 | sctp_frag_msg *msg; |
3179 | 284 | sctp_complete_msg *message, *last_message; |
3180 | 284 | sctp_fragment *frag_i, *last_frag, *first_frag; |
3181 | 284 | sctp_frag_be *begin, *end, *beginend; |
3182 | 284 | uint32_t len, offset = 0; |
3183 | 284 | tvbuff_t *new_tvb = NULL; |
3184 | 284 | proto_item *item; |
3185 | 284 | proto_tree *ptree; |
3186 | | |
3187 | 284 | msg = find_message(stream_id, stream_seq_num, u_bit); |
3188 | | |
3189 | 284 | if (!msg) { |
3190 | | /* no message, we can't do anything */ |
3191 | 0 | return NULL; |
3192 | 0 | } |
3193 | | |
3194 | | /* check if fragment is part of an already reassembled message */ |
3195 | 284 | for (message = msg->messages; |
3196 | 284 | message && |
3197 | 0 | !(message->begin <= fragment->tsn && message->end >= fragment->tsn) && |
3198 | 0 | !(message->begin > message->end && |
3199 | 0 | (message->begin <= fragment->tsn || message->end >= fragment->tsn)); |
3200 | 284 | message = message->next); |
3201 | | |
3202 | 284 | if (message) { |
3203 | | /* we found the reassembled message this fragment belongs to */ |
3204 | 0 | if (fragment == message->reassembled_in) { |
3205 | | |
3206 | | /* this is the last fragment, create data source */ |
3207 | 0 | new_tvb = tvb_new_child_real_data(tvb, message->data, message->len, message->len); |
3208 | 0 | add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message"); |
3209 | | |
3210 | | /* display reassembly info */ |
3211 | 0 | item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, ENC_NA); |
3212 | 0 | ptree = proto_item_add_subtree(item, ett_sctp_fragments); |
3213 | 0 | proto_item_append_text(item, " (%u bytes, %u fragments): ", |
3214 | 0 | message->len, message->end - message->begin + 1); |
3215 | |
|
3216 | 0 | if (message->begin > message->end) { |
3217 | 0 | for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit); |
3218 | 0 | frag_i; |
3219 | 0 | frag_i = frag_i->next) { |
3220 | |
|
3221 | 0 | proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len, |
3222 | 0 | frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)", |
3223 | 0 | frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len); |
3224 | 0 | offset += frag_i->len; |
3225 | |
|
3226 | 0 | mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num); |
3227 | 0 | } |
3228 | |
|
3229 | 0 | for (frag_i = msg->fragments; |
3230 | 0 | frag_i && frag_i->tsn <= message->end; |
3231 | 0 | frag_i = frag_i->next) { |
3232 | |
|
3233 | 0 | proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len, |
3234 | 0 | frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)", |
3235 | 0 | frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len); |
3236 | 0 | offset += frag_i->len; |
3237 | |
|
3238 | 0 | mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num); |
3239 | 0 | } |
3240 | 0 | } else { |
3241 | 0 | for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit); |
3242 | 0 | frag_i && frag_i->tsn <= message->end; |
3243 | 0 | frag_i = frag_i->next) { |
3244 | |
|
3245 | 0 | proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len, |
3246 | 0 | frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)", |
3247 | 0 | frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len); |
3248 | 0 | offset += frag_i->len; |
3249 | |
|
3250 | 0 | mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num); |
3251 | 0 | } |
3252 | 0 | } |
3253 | |
|
3254 | 0 | return new_tvb; |
3255 | 0 | } |
3256 | | |
3257 | | /* this is not the last fragment, |
3258 | | * so let the user know the frame where the reassembly is |
3259 | | */ |
3260 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) "); |
3261 | |
|
3262 | 0 | proto_tree_add_uint(tree, hf_sctp_reassembled_in, tvb, 0, 0, message->reassembled_in->frame_num); |
3263 | 0 | return NULL; |
3264 | 0 | } |
3265 | | |
3266 | | /* this fragment has not been reassembled, yet |
3267 | | * check now if we can reassemble it |
3268 | | * at first look for the first and last tsn of the msg |
3269 | | */ |
3270 | 284 | for (begin = msg->begins; |
3271 | 288 | begin && begin->fragment->tsn > fragment->tsn; |
3272 | 284 | begin = begin->next); |
3273 | | |
3274 | | /* in case begin still is null, set it to first (highest) begin |
3275 | | * maybe the message tsn restart at 0 in between |
3276 | | */ |
3277 | 284 | if (!begin) |
3278 | 252 | begin = msg->begins; |
3279 | | |
3280 | 284 | for (end = msg->ends; |
3281 | 292 | end && end->fragment->tsn < fragment->tsn; |
3282 | 284 | end = end->next); |
3283 | | |
3284 | | /* in case end still is null, set it to first (lowest) end |
3285 | | * maybe the message tsn restart at 0 in between |
3286 | | */ |
3287 | 284 | if (!end) |
3288 | 219 | end = msg->ends; |
3289 | | |
3290 | 284 | if (!begin || !end || !msg->fragments || |
3291 | 283 | (begin->fragment->tsn > end->fragment->tsn && msg->fragments->tsn)) { |
3292 | | /* begin and end have not been collected, yet |
3293 | | * or there might be a tsn restart but the first fragment hasn't a tsn of 0 |
3294 | | * just mark as fragment |
3295 | | */ |
3296 | | |
3297 | 283 | col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) "); |
3298 | | |
3299 | 283 | return NULL; |
3300 | 283 | } |
3301 | | |
3302 | | /* we found possible begin and end |
3303 | | * look for the first fragment and then try to get to the end |
3304 | | */ |
3305 | 1 | first_frag = begin->fragment; |
3306 | | |
3307 | | /* while looking if all fragments are there |
3308 | | * we can calculate the overall length that |
3309 | | * we need in case of success |
3310 | | */ |
3311 | 1 | len = first_frag->len; |
3312 | | |
3313 | | /* check if begin is past end |
3314 | | * this can happen if there has been a tsn restart |
3315 | | * or we just got the wrong begin and end |
3316 | | * so give it a try |
3317 | | */ |
3318 | 1 | if (begin->fragment->tsn > end->fragment->tsn) { |
3319 | 1 | for (last_frag = first_frag, frag_i = first_frag->next; |
3320 | 1 | frag_i && frag_i->tsn == (last_frag->tsn + 1); |
3321 | 1 | last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len; |
3322 | | |
3323 | | /* check if we reached the last possible tsn |
3324 | | * if yes, restart and continue |
3325 | | */ |
3326 | 1 | if ((last_frag->tsn + 1)) { |
3327 | | /* there are just fragments missing */ |
3328 | 1 | col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) "); |
3329 | | |
3330 | 1 | return NULL; |
3331 | 1 | } |
3332 | | |
3333 | | /* we got all fragments until the last possible tsn |
3334 | | * and the first is 0 if we got here |
3335 | | */ |
3336 | | |
3337 | 0 | len += msg->fragments->len; |
3338 | 0 | for (last_frag = msg->fragments, frag_i = last_frag->next; |
3339 | 0 | frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1); |
3340 | 0 | last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len; |
3341 | |
|
3342 | 0 | } else { |
3343 | 0 | for (last_frag = first_frag, frag_i = first_frag->next; |
3344 | 0 | frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1); |
3345 | 0 | last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len; |
3346 | 0 | } |
3347 | | |
3348 | 0 | if (!frag_i || frag_i != end->fragment || frag_i->tsn != (last_frag->tsn + 1)) { |
3349 | | /* we need more fragments. just mark as fragment */ |
3350 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) "); |
3351 | |
|
3352 | 0 | return NULL; |
3353 | 0 | } |
3354 | | |
3355 | | /* ok, this message is complete, we can reassemble it |
3356 | | * but at first don't forget to add the length of the last fragment |
3357 | | */ |
3358 | 0 | len += frag_i->len; |
3359 | |
|
3360 | 0 | message = wmem_new(wmem_file_scope(), sctp_complete_msg); |
3361 | 0 | message->begin = begin->fragment->tsn; |
3362 | 0 | message->end = end->fragment->tsn; |
3363 | 0 | message->reassembled_in = fragment; |
3364 | 0 | message->len = len; |
3365 | 0 | message->data = (unsigned char *)wmem_alloc(wmem_file_scope(), len); |
3366 | 0 | message->next = NULL; |
3367 | | |
3368 | | /* now copy all fragments */ |
3369 | 0 | if (begin->fragment->tsn > end->fragment->tsn) { |
3370 | | /* a tsn restart has occurred */ |
3371 | 0 | for (frag_i = first_frag; |
3372 | 0 | frag_i; |
3373 | 0 | frag_i = frag_i->next) { |
3374 | |
|
3375 | 0 | if (frag_i->len && frag_i->data) |
3376 | 0 | memcpy(message->data + offset, frag_i->data, frag_i->len); |
3377 | 0 | offset += frag_i->len; |
3378 | | |
3379 | | /* release fragment data */ |
3380 | 0 | g_free(frag_i->data); |
3381 | 0 | frag_i->data = NULL; |
3382 | 0 | } |
3383 | |
|
3384 | 0 | for (frag_i = msg->fragments; |
3385 | 0 | frag_i && frag_i->tsn <= end->fragment->tsn; |
3386 | 0 | frag_i = frag_i->next) { |
3387 | |
|
3388 | 0 | if (frag_i->len && frag_i->data) |
3389 | 0 | memcpy(message->data + offset, frag_i->data, frag_i->len); |
3390 | 0 | offset += frag_i->len; |
3391 | | |
3392 | | /* release fragment data */ |
3393 | 0 | g_free(frag_i->data); |
3394 | 0 | frag_i->data = NULL; |
3395 | 0 | } |
3396 | |
|
3397 | 0 | } else { |
3398 | 0 | for (frag_i = first_frag; |
3399 | 0 | frag_i && frag_i->tsn <= end->fragment->tsn; |
3400 | 0 | frag_i = frag_i->next) { |
3401 | |
|
3402 | 0 | if (frag_i->len && frag_i->data) |
3403 | 0 | memcpy(message->data + offset, frag_i->data, frag_i->len); |
3404 | 0 | offset += frag_i->len; |
3405 | | |
3406 | | /* release fragment data */ |
3407 | 0 | g_free(frag_i->data); |
3408 | 0 | frag_i->data = NULL; |
3409 | 0 | } |
3410 | 0 | } |
3411 | | |
3412 | | /* save message */ |
3413 | 0 | if (!msg->messages) { |
3414 | 0 | msg->messages = message; |
3415 | 0 | } else { |
3416 | 0 | for (last_message = msg->messages; |
3417 | 0 | last_message->next; |
3418 | 0 | last_message = last_message->next); |
3419 | 0 | last_message->next = message; |
3420 | 0 | } |
3421 | | |
3422 | | /* remove begin and end from list */ |
3423 | 0 | if (msg->begins == begin) { |
3424 | 0 | msg->begins = begin->next; |
3425 | 0 | } else { |
3426 | 0 | for (beginend = msg->begins; |
3427 | 0 | beginend && beginend->next != begin; |
3428 | 0 | beginend = beginend->next); |
3429 | 0 | if (beginend && beginend->next == begin) |
3430 | 0 | beginend->next = begin->next; |
3431 | 0 | } |
3432 | 0 | g_free(begin); |
3433 | |
|
3434 | 0 | if (msg->ends == end) { |
3435 | 0 | msg->ends = end->next; |
3436 | 0 | } else { |
3437 | 0 | for (beginend = msg->ends; |
3438 | 0 | beginend && beginend->next != end; |
3439 | 0 | beginend = beginend->next); |
3440 | 0 | if (beginend && beginend->next == end) |
3441 | 0 | beginend->next = end->next; |
3442 | 0 | } |
3443 | 0 | g_free(end); |
3444 | | |
3445 | | /* create data source */ |
3446 | 0 | new_tvb = tvb_new_child_real_data(tvb, message->data, len, len); |
3447 | 0 | add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message"); |
3448 | | |
3449 | | /* display reassembly info */ |
3450 | 0 | item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, ENC_NA); |
3451 | 0 | ptree = proto_item_add_subtree(item, ett_sctp_fragments); |
3452 | 0 | proto_item_append_text(item, " (%u bytes, %u fragments): ", |
3453 | 0 | message->len, message->end - message->begin + 1); |
3454 | |
|
3455 | 0 | if (message->begin > message->end) { |
3456 | 0 | for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit); |
3457 | 0 | frag_i; |
3458 | 0 | frag_i = frag_i->next) { |
3459 | |
|
3460 | 0 | proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len, |
3461 | 0 | frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)", |
3462 | 0 | frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len); |
3463 | 0 | offset += frag_i->len; |
3464 | |
|
3465 | 0 | mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num); |
3466 | 0 | } |
3467 | |
|
3468 | 0 | for (frag_i = msg->fragments; |
3469 | 0 | frag_i && frag_i->tsn <= message->end; |
3470 | 0 | frag_i = frag_i->next) { |
3471 | |
|
3472 | 0 | proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len, |
3473 | 0 | frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)", |
3474 | 0 | frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len); |
3475 | 0 | offset += frag_i->len; |
3476 | |
|
3477 | 0 | mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num); |
3478 | 0 | } |
3479 | 0 | } else { |
3480 | 0 | for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit); |
3481 | 0 | frag_i && frag_i->tsn <= message->end; |
3482 | 0 | frag_i = frag_i->next) { |
3483 | |
|
3484 | 0 | proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len, |
3485 | 0 | frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)", |
3486 | 0 | frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len); |
3487 | 0 | offset += frag_i->len; |
3488 | |
|
3489 | 0 | mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num); |
3490 | 0 | } |
3491 | 0 | } |
3492 | | |
3493 | | /* it's not fragmented anymore */ |
3494 | 0 | pinfo->fragmented = false; |
3495 | |
|
3496 | 0 | return new_tvb; |
3497 | 0 | } |
3498 | | |
3499 | | static exp_pdu_data_t* |
3500 | | create_exp_pdu_table(packet_info *pinfo, tvbuff_t *tvb, const char *table_name, uint32_t table_value) |
3501 | 0 | { |
3502 | 0 | exp_pdu_data_item_t exp_pdu_data_table_value = { |
3503 | 0 | exp_pdu_data_dissector_table_num_value_size, |
3504 | 0 | exp_pdu_data_dissector_table_num_value_populate_data, |
3505 | 0 | GUINT_TO_POINTER(table_value) |
3506 | 0 | }; |
3507 | |
|
3508 | 0 | const exp_pdu_data_item_t *sctp_exp_pdu_items[] = { |
3509 | 0 | &exp_pdu_data_src_ip, |
3510 | 0 | &exp_pdu_data_dst_ip, |
3511 | 0 | &exp_pdu_data_port_type, |
3512 | 0 | &exp_pdu_data_src_port, |
3513 | 0 | &exp_pdu_data_dst_port, |
3514 | 0 | &exp_pdu_data_orig_frame_num, |
3515 | 0 | &exp_pdu_data_table_value, |
3516 | 0 | NULL |
3517 | 0 | }; |
3518 | |
|
3519 | 0 | exp_pdu_data_t *exp_pdu_data = export_pdu_create_tags(pinfo, table_name, EXP_PDU_TAG_DISSECTOR_TABLE_NAME, sctp_exp_pdu_items); |
3520 | |
|
3521 | 0 | exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb); |
3522 | 0 | exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb); |
3523 | 0 | exp_pdu_data->pdu_tvb = tvb; |
3524 | |
|
3525 | 0 | return exp_pdu_data; |
3526 | 0 | } |
3527 | | |
3528 | | static exp_pdu_data_t* |
3529 | | create_exp_pdu_proto_name(packet_info *pinfo, tvbuff_t *tvb, const char *proto_name) |
3530 | 0 | { |
3531 | 0 | exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, proto_name, EXP_PDU_TAG_DISSECTOR_NAME); |
3532 | |
|
3533 | 0 | exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb); |
3534 | 0 | exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb); |
3535 | 0 | exp_pdu_data->pdu_tvb = tvb; |
3536 | |
|
3537 | 0 | return exp_pdu_data; |
3538 | 0 | } |
3539 | | |
3540 | | static void |
3541 | | export_sctp_data_chunk(packet_info *pinfo, tvbuff_t *tvb, uint32_t payload_proto_id, |
3542 | | const wmem_list_frame_t *frame) |
3543 | 18.8k | { |
3544 | 18.8k | const char *proto_name = NULL; |
3545 | 18.8k | exp_pdu_data_t *exp_pdu_data = NULL; |
3546 | | |
3547 | 18.8k | if (!have_tap_listener(exported_pdu_tap)) { |
3548 | | /* Do nothing when there is no export pdu tap listener */ |
3549 | 18.8k | return; |
3550 | 18.8k | } |
3551 | | |
3552 | 0 | if (enable_ulp_dissection && frame) { |
3553 | | /* get the proto_name of the next frame */ |
3554 | 0 | proto_name = proto_get_protocol_filter_name(GPOINTER_TO_UINT(wmem_list_frame_data(frame))); |
3555 | 0 | } |
3556 | |
|
3557 | 0 | if (proto_name && (strcmp(proto_name, "data") != 0)) { |
3558 | | /* when we have proto_name and it is not "data" export using the proto_name */ |
3559 | 0 | exp_pdu_data = create_exp_pdu_proto_name(pinfo, tvb, proto_name); |
3560 | 0 | } else if (payload_proto_id != 0) { |
3561 | 0 | exp_pdu_data = create_exp_pdu_table(pinfo, tvb, "sctp.ppi", payload_proto_id); |
3562 | 0 | } else if (pinfo->destport != 0) { |
3563 | 0 | exp_pdu_data = create_exp_pdu_table(pinfo, tvb, "sctp.port", pinfo->destport); |
3564 | 0 | } else if (pinfo->srcport != 0) { |
3565 | 0 | exp_pdu_data = create_exp_pdu_table(pinfo, tvb, "sctp.port", pinfo->srcport); |
3566 | 0 | } else { |
3567 | | /* do not export anything when none of the above fields are available */ |
3568 | 0 | return; |
3569 | 0 | } |
3570 | | |
3571 | 0 | tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data); |
3572 | 0 | } |
3573 | | |
3574 | | static bool |
3575 | | dissect_fragmented_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree, |
3576 | | proto_tree *chunk_tree, uint32_t tsn, uint32_t ppi, uint16_t stream_id, |
3577 | | uint32_t stream_seq_num, uint8_t b_bit, uint8_t e_bit, uint8_t u_bit, bool is_idata) |
3578 | 352 | { |
3579 | 352 | sctp_fragment *fragment; |
3580 | 352 | tvbuff_t *new_tvb = NULL; |
3581 | | |
3582 | | /* |
3583 | | * If this is a short frame, then we can't, and don't, do |
3584 | | * reassembly on it. We just give up. |
3585 | | */ |
3586 | 352 | if (tvb_reported_length(payload_tvb) > tvb_captured_length(payload_tvb)) |
3587 | 0 | return true; |
3588 | | |
3589 | | /* add fragment to list of known fragments. returns NULL if segment is a duplicate */ |
3590 | 352 | fragment = add_fragment(payload_tvb, pinfo, chunk_tree, tsn, stream_id, stream_seq_num, b_bit, e_bit, u_bit, ppi, is_idata); |
3591 | | |
3592 | 352 | if (fragment) |
3593 | 284 | new_tvb = fragment_reassembly(payload_tvb, fragment, pinfo, chunk_tree, stream_id, stream_seq_num, u_bit); |
3594 | | |
3595 | | /* pass reassembled data to next dissector, if possible */ |
3596 | 352 | if (new_tvb){ |
3597 | 0 | bool retval; |
3598 | 0 | wmem_list_frame_t *cur = wmem_list_tail(pinfo->layers); |
3599 | |
|
3600 | 0 | retval = dissect_payload(new_tvb, pinfo, tree, ppi); |
3601 | 0 | export_sctp_data_chunk(pinfo, new_tvb, ppi, wmem_list_frame_next(cur)); |
3602 | 0 | return retval; |
3603 | 0 | } |
3604 | | |
3605 | | /* no reassembly done, do nothing */ |
3606 | 352 | return true; |
3607 | 352 | } |
3608 | | |
3609 | | static const true_false_string sctp_data_chunk_e_bit_value = { |
3610 | | "Last segment", |
3611 | | "Not the last segment" |
3612 | | }; |
3613 | | |
3614 | | static const true_false_string sctp_data_chunk_b_bit_value = { |
3615 | | "First segment", |
3616 | | "Subsequent segment" |
3617 | | }; |
3618 | | |
3619 | | static const true_false_string sctp_data_chunk_u_bit_value = { |
3620 | | "Unordered delivery", |
3621 | | "Ordered delivery" |
3622 | | }; |
3623 | | |
3624 | | static const true_false_string sctp_data_chunk_i_bit_value = { |
3625 | | "Send SACK immediately", |
3626 | | "Possibly delay SACK" |
3627 | | }; |
3628 | | |
3629 | | static bool |
3630 | | dissect_data_chunk(tvbuff_t *chunk_tvb, |
3631 | | uint16_t chunk_length, |
3632 | | packet_info *pinfo, |
3633 | | proto_tree *tree, |
3634 | | proto_tree *chunk_tree, |
3635 | | proto_item *chunk_item, |
3636 | | proto_item *flags_item, |
3637 | | sctp_half_assoc_t *ha, |
3638 | | bool is_idata) |
3639 | 19.5k | { |
3640 | 19.5k | unsigned number_of_ppid; |
3641 | 19.5k | volatile uint32_t payload_proto_id; |
3642 | 19.5k | tvbuff_t *payload_tvb; |
3643 | 19.5k | proto_tree *flags_tree; |
3644 | 19.5k | uint8_t oct, e_bit, b_bit, u_bit; |
3645 | 19.5k | uint16_t stream_id; |
3646 | 19.5k | uint32_t tsn, rawtsn, ppid, stream_seq_num = 0; |
3647 | 19.5k | proto_item *tsn_item = NULL; |
3648 | 19.5k | bool call_subdissector = false; |
3649 | 19.5k | bool is_retransmission; |
3650 | 19.5k | uint32_t header_length; |
3651 | 19.5k | uint32_t payload_offset; |
3652 | | |
3653 | 19.5k | static int* const chunk_flags[] = { |
3654 | 19.5k | &hf_data_chunk_i_bit, |
3655 | 19.5k | &hf_data_chunk_u_bit, |
3656 | 19.5k | &hf_data_chunk_b_bit, |
3657 | 19.5k | &hf_data_chunk_e_bit, |
3658 | 19.5k | NULL |
3659 | 19.5k | }; |
3660 | | |
3661 | 19.5k | if (is_idata) { |
3662 | 53 | if (chunk_length < I_DATA_CHUNK_HEADER_LENGTH) { |
3663 | 2 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, I_DATA_CHUNK_HEADER_LENGTH); |
3664 | 2 | return true; |
3665 | 2 | } |
3666 | 51 | payload_proto_id = tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET); |
3667 | 19.4k | } else { |
3668 | 19.4k | if (chunk_length < DATA_CHUNK_HEADER_LENGTH) { |
3669 | 43 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, DATA_CHUNK_HEADER_LENGTH); |
3670 | 43 | return true; |
3671 | 43 | } |
3672 | 19.4k | payload_proto_id = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET); |
3673 | 19.4k | } |
3674 | | |
3675 | | /* insert the PPID in the pinfo structure if it is not already there and there is still room */ |
3676 | 19.8k | for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) { |
3677 | 19.7k | void *tmp = p_get_proto_data(pinfo->pool, pinfo, proto_sctp, number_of_ppid); |
3678 | 19.7k | ppid = GPOINTER_TO_UINT(tmp); |
3679 | 19.7k | if ((ppid == LAST_PPID) || (ppid == payload_proto_id)) |
3680 | 19.3k | break; |
3681 | 19.7k | } |
3682 | 19.4k | if ((number_of_ppid < MAX_NUMBER_OF_PPIDS) && (ppid == LAST_PPID)) |
3683 | 19.2k | p_add_proto_data(pinfo->pool, pinfo, proto_sctp, number_of_ppid, GUINT_TO_POINTER(payload_proto_id)); |
3684 | | |
3685 | 19.4k | oct = tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET); |
3686 | 19.4k | e_bit = oct & SCTP_DATA_CHUNK_E_BIT; |
3687 | 19.4k | b_bit = oct & SCTP_DATA_CHUNK_B_BIT; |
3688 | 19.4k | u_bit = oct & SCTP_DATA_CHUNK_U_BIT; |
3689 | | |
3690 | 19.4k | tsn = rawtsn = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET); |
3691 | 19.4k | if ((show_relative_tsns) && (ha)) { |
3692 | 609 | if (!ha->started) { |
3693 | 204 | ha->first_tsn = tsn; |
3694 | 204 | ha->started = true; |
3695 | 204 | } |
3696 | 609 | tsn -= ha->first_tsn; |
3697 | 609 | } |
3698 | | |
3699 | 19.4k | col_append_fstr(pinfo->cinfo, COL_INFO, "(TSN=%" PRIu32 ") ", tsn); |
3700 | | |
3701 | 19.4k | if (chunk_tree) { |
3702 | 19.4k | if (is_idata) |
3703 | 48 | proto_item_set_len(chunk_item, I_DATA_CHUNK_HEADER_LENGTH); |
3704 | 19.4k | else |
3705 | 19.4k | proto_item_set_len(chunk_item, DATA_CHUNK_HEADER_LENGTH); |
3706 | | |
3707 | 19.4k | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags); |
3708 | 19.4k | proto_tree_add_bitmask_list(flags_tree, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, chunk_flags, ENC_NA); |
3709 | 19.4k | if((show_relative_tsns) && (ha)) { |
3710 | 609 | tsn_item = proto_tree_add_uint(chunk_tree, hf_data_chunk_tsn, chunk_tvb, DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH, tsn); |
3711 | 609 | proto_tree_add_item(chunk_tree, hf_data_chunk_tsn_raw, chunk_tvb, DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH, ENC_BIG_ENDIAN); |
3712 | 609 | } |
3713 | 18.8k | else { |
3714 | 18.8k | tsn_item = proto_tree_add_item(chunk_tree, hf_data_chunk_tsn_raw, chunk_tvb, DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH, ENC_BIG_ENDIAN); |
3715 | 18.8k | } |
3716 | 19.4k | proto_tree_add_item(chunk_tree, hf_data_chunk_stream_id, chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET, DATA_CHUNK_STREAM_ID_LENGTH, ENC_BIG_ENDIAN); |
3717 | 19.4k | if (is_idata) { |
3718 | 48 | proto_tree_add_item(chunk_tree, hf_idata_chunk_reserved, chunk_tvb, I_DATA_CHUNK_RESERVED_OFFSET, I_DATA_CHUNK_RESERVED_LENGTH, ENC_BIG_ENDIAN); |
3719 | 48 | proto_tree_add_item(chunk_tree, hf_idata_chunk_mid, chunk_tvb, I_DATA_CHUNK_MID_OFFSET, I_DATA_CHUNK_MID_LENGTH, ENC_BIG_ENDIAN); |
3720 | 48 | if (b_bit) |
3721 | 25 | proto_tree_add_item(chunk_tree, hf_data_chunk_payload_proto_id, chunk_tvb, I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET, I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH, ENC_BIG_ENDIAN); |
3722 | 23 | else |
3723 | 23 | proto_tree_add_item(chunk_tree, hf_idata_chunk_fsn, chunk_tvb, I_DATA_CHUNK_FSN_OFFSET, I_DATA_CHUNK_FSN_LENGTH, ENC_BIG_ENDIAN); |
3724 | 19.4k | } else { |
3725 | 19.4k | proto_tree_add_item(chunk_tree, hf_data_chunk_stream_seq_number, chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET, DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH, ENC_BIG_ENDIAN); |
3726 | 19.4k | proto_tree_add_item(chunk_tree, hf_data_chunk_payload_proto_id, chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH, ENC_BIG_ENDIAN); |
3727 | 19.4k | } |
3728 | 19.4k | proto_item_append_text(chunk_item, " (%s, ", (u_bit) ? "unordered" : "ordered"); |
3729 | 19.4k | if (b_bit) { |
3730 | 18.9k | if (e_bit) |
3731 | 18.9k | proto_item_append_text(chunk_item, "complete"); |
3732 | 58 | else |
3733 | 58 | proto_item_append_text(chunk_item, "first"); |
3734 | 18.9k | } else { |
3735 | 491 | if (e_bit) |
3736 | 128 | proto_item_append_text(chunk_item, "last"); |
3737 | 363 | else |
3738 | 363 | proto_item_append_text(chunk_item, "middle"); |
3739 | 491 | } |
3740 | | |
3741 | 19.4k | if (is_idata) { |
3742 | 48 | if (b_bit) |
3743 | 25 | proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, MID: %u, payload length: %u byte%s)", |
3744 | 25 | tsn, |
3745 | 25 | tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET), |
3746 | 25 | tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_MID_OFFSET), |
3747 | 25 | chunk_length - I_DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - I_DATA_CHUNK_HEADER_LENGTH, "", "s")); |
3748 | 23 | else |
3749 | 23 | proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, MID: %u, FSN: %u, payload length: %u byte%s)", |
3750 | 23 | tsn, |
3751 | 23 | tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET), |
3752 | 23 | tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_MID_OFFSET), |
3753 | 23 | tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_FSN_OFFSET), |
3754 | 23 | chunk_length - I_DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - I_DATA_CHUNK_HEADER_LENGTH, "", "s")); |
3755 | 48 | } else |
3756 | 19.4k | proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, SSN: %u, PPID: %u, payload length: %u byte%s)", |
3757 | 19.4k | tsn, |
3758 | 19.4k | tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET), |
3759 | 19.4k | tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET), |
3760 | 19.4k | payload_proto_id, |
3761 | 19.4k | chunk_length - DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - DATA_CHUNK_HEADER_LENGTH, "", "s")); |
3762 | 19.4k | } |
3763 | | |
3764 | 19.4k | is_retransmission = sctp_tsn(pinfo, chunk_tvb, tsn_item, ha, rawtsn); |
3765 | | |
3766 | 19.4k | if (is_idata) { |
3767 | 48 | header_length = I_DATA_CHUNK_HEADER_LENGTH; |
3768 | 48 | payload_offset = I_DATA_CHUNK_PAYLOAD_OFFSET; |
3769 | 19.4k | } else { |
3770 | 19.4k | header_length = DATA_CHUNK_HEADER_LENGTH; |
3771 | 19.4k | payload_offset = DATA_CHUNK_PAYLOAD_OFFSET; |
3772 | 19.4k | } |
3773 | 19.4k | payload_tvb = tvb_new_subset_length(chunk_tvb, payload_offset, |
3774 | 19.4k | MIN(chunk_length - header_length, tvb_reported_length_remaining(chunk_tvb, payload_offset))); |
3775 | | |
3776 | | /* Is this a fragment? */ |
3777 | 19.4k | if (b_bit && e_bit) { |
3778 | | /* No - just call the subdissector. */ |
3779 | 18.9k | if (!is_retransmission) |
3780 | 18.8k | call_subdissector = true; |
3781 | 18.9k | } else { |
3782 | | /* Yes. */ |
3783 | 563 | pinfo->fragmented = true; |
3784 | | |
3785 | | /* if reassembly is off just mark as fragment for next dissector and proceed */ |
3786 | 563 | if (!use_reassembly) |
3787 | 0 | { |
3788 | | /* Don't pass on non-first fragments since the next dissector will |
3789 | | * almost certainly not understand the data. |
3790 | | */ |
3791 | 0 | if (b_bit) { |
3792 | 0 | if (!is_retransmission) |
3793 | 0 | call_subdissector = true; |
3794 | 0 | } else |
3795 | 0 | return false; |
3796 | 0 | } |
3797 | | |
3798 | 563 | } |
3799 | | |
3800 | 19.4k | if (call_subdissector) { |
3801 | | /* This isn't a fragment or reassembly is off and it's the first fragment */ |
3802 | | |
3803 | 18.8k | volatile bool retval = false; |
3804 | 18.8k | wmem_list_frame_t *cur = wmem_list_tail(pinfo->layers); |
3805 | | |
3806 | 18.8k | TRY { |
3807 | 18.8k | retval = dissect_payload(payload_tvb, pinfo, tree, payload_proto_id); |
3808 | 18.8k | } |
3809 | 18.8k | CATCH_NONFATAL_ERRORS { |
3810 | | /* |
3811 | | * Somebody threw an exception that means that there was a problem |
3812 | | * dissecting the payload; that means that a dissector was found, |
3813 | | * so we don't need to dissect the payload as data or update the |
3814 | | * protocol or info columns. |
3815 | | * |
3816 | | * Just show the exception and then continue dissecting chunks. |
3817 | | */ |
3818 | 2.98k | show_exception(payload_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
3819 | 2.98k | } |
3820 | 18.8k | ENDTRY; |
3821 | | |
3822 | 18.8k | export_sctp_data_chunk(pinfo, payload_tvb, payload_proto_id, wmem_list_frame_next(cur)); |
3823 | 18.8k | return retval; |
3824 | | |
3825 | 18.8k | } else if (is_retransmission) { |
3826 | 216 | col_append_str(pinfo->cinfo, COL_INFO, "(retransmission) "); |
3827 | 216 | return false; |
3828 | 366 | } else { |
3829 | | |
3830 | | /* The logic above should ensure this... */ |
3831 | 366 | DISSECTOR_ASSERT(use_reassembly); |
3832 | | |
3833 | 366 | stream_id = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET); |
3834 | 366 | if (is_idata) { |
3835 | | /* The stream_seq_num variable is used to hold the MID, the tsn variable holds the FSN*/ |
3836 | 22 | stream_seq_num = tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_MID_OFFSET); |
3837 | 22 | if (b_bit) { |
3838 | 7 | tsn = 0; |
3839 | 15 | } else { |
3840 | 15 | tsn = tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_FSN_OFFSET); |
3841 | 15 | payload_proto_id = 0; |
3842 | 15 | } |
3843 | 344 | } else { |
3844 | | /* if unordered set stream_seq_num to 0 for easier handling */ |
3845 | 344 | if (u_bit) |
3846 | 47 | stream_seq_num = 0; |
3847 | 297 | else |
3848 | 297 | stream_seq_num = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET); |
3849 | 344 | } |
3850 | | /* start reassembly */ |
3851 | 366 | return dissect_fragmented_payload(payload_tvb, pinfo, tree, chunk_tree, tsn, payload_proto_id, stream_id, stream_seq_num, b_bit, e_bit, u_bit, is_idata); |
3852 | 366 | } |
3853 | | |
3854 | 19.4k | } |
3855 | | |
3856 | 1.83k | #define INIT_CHUNK_INITIATE_TAG_LENGTH 4 |
3857 | 1.50k | #define INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4 |
3858 | 1.17k | #define INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH 2 |
3859 | 846 | #define INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH 2 |
3860 | 682 | #define INIT_CHUNK_INITIAL_TSN_LENGTH 4 |
3861 | 354 | #define INIT_CHUNK_FIXED_PARAMTERS_LENGTH (CHUNK_HEADER_LENGTH + \ |
3862 | 354 | INIT_CHUNK_INITIATE_TAG_LENGTH + \ |
3863 | 354 | INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH + \ |
3864 | 354 | INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH + \ |
3865 | 354 | INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH + \ |
3866 | 354 | INIT_CHUNK_INITIAL_TSN_LENGTH) |
3867 | | |
3868 | 1.47k | #define INIT_CHUNK_INITIATE_TAG_OFFSET CHUNK_VALUE_OFFSET |
3869 | 1.14k | #define INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (INIT_CHUNK_INITIATE_TAG_OFFSET + \ |
3870 | 1.14k | INIT_CHUNK_INITIATE_TAG_LENGTH ) |
3871 | 984 | #define INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET (INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \ |
3872 | 984 | INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH ) |
3873 | 656 | #define INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET (INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET + \ |
3874 | 656 | INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH ) |
3875 | 328 | #define INIT_CHUNK_INITIAL_TSN_OFFSET (INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET + \ |
3876 | 328 | INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH ) |
3877 | 164 | #define INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET (INIT_CHUNK_INITIAL_TSN_OFFSET + \ |
3878 | 164 | INIT_CHUNK_INITIAL_TSN_LENGTH ) |
3879 | | |
3880 | | static void |
3881 | | // NOLINTNEXTLINE(misc-no-recursion) |
3882 | | dissect_init_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item) |
3883 | 120 | { |
3884 | 120 | tvbuff_t *parameters_tvb; |
3885 | 120 | proto_item *hidden_item; |
3886 | | |
3887 | 120 | if (chunk_length < INIT_CHUNK_FIXED_PARAMTERS_LENGTH) { |
3888 | 10 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, INIT_CHUNK_FIXED_PARAMTERS_LENGTH); |
3889 | 10 | return; |
3890 | 10 | } |
3891 | | |
3892 | 110 | if (chunk_tree) { |
3893 | | /* handle fixed parameters */ |
3894 | 110 | proto_tree_add_item(chunk_tree, hf_init_chunk_initiate_tag, chunk_tvb, INIT_CHUNK_INITIATE_TAG_OFFSET, INIT_CHUNK_INITIATE_TAG_LENGTH, ENC_BIG_ENDIAN); |
3895 | 110 | hidden_item = proto_tree_add_item(chunk_tree, hf_initiate_tag, chunk_tvb, INIT_CHUNK_INITIATE_TAG_OFFSET, INIT_CHUNK_INITIATE_TAG_LENGTH, ENC_BIG_ENDIAN); |
3896 | 110 | proto_item_set_hidden(hidden_item); |
3897 | 110 | proto_tree_add_item(chunk_tree, hf_init_chunk_adv_rec_window_credit, chunk_tvb, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH, ENC_BIG_ENDIAN); |
3898 | 110 | proto_tree_add_item(chunk_tree, hf_init_chunk_number_of_outbound_streams, chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH, ENC_BIG_ENDIAN); |
3899 | 110 | proto_tree_add_item(chunk_tree, hf_init_chunk_number_of_inbound_streams, chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH, ENC_BIG_ENDIAN); |
3900 | 110 | proto_tree_add_item(chunk_tree, hf_init_chunk_initial_tsn, chunk_tvb, INIT_CHUNK_INITIAL_TSN_OFFSET, INIT_CHUNK_INITIAL_TSN_LENGTH, ENC_BIG_ENDIAN); |
3901 | | |
3902 | 110 | proto_item_append_text(chunk_item, " (Outbound streams: %u, inbound streams: %u)", |
3903 | 110 | tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET), |
3904 | 110 | tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET)); |
3905 | 110 | } |
3906 | | |
3907 | | /* handle variable parameters */ |
3908 | 110 | chunk_length -= INIT_CHUNK_FIXED_PARAMTERS_LENGTH; |
3909 | 110 | parameters_tvb = tvb_new_subset_length(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET, |
3910 | 110 | MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET))); |
3911 | 110 | dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, true, false); |
3912 | 110 | } |
3913 | | |
3914 | | static void |
3915 | | // NOLINTNEXTLINE(misc-no-recursion) |
3916 | | dissect_init_ack_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item) |
3917 | 57 | { |
3918 | 57 | tvbuff_t *parameters_tvb; |
3919 | 57 | proto_item *hidden_item; |
3920 | | |
3921 | 57 | if (chunk_length < INIT_CHUNK_FIXED_PARAMTERS_LENGTH) { |
3922 | 3 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", |
3923 | 3 | chunk_length, |
3924 | 3 | INIT_CHUNK_FIXED_PARAMTERS_LENGTH); |
3925 | 3 | return; |
3926 | 3 | } |
3927 | 54 | if (chunk_tree) { |
3928 | | /* handle fixed parameters */ |
3929 | 54 | proto_tree_add_item(chunk_tree, hf_initack_chunk_initiate_tag, chunk_tvb, INIT_CHUNK_INITIATE_TAG_OFFSET, INIT_CHUNK_INITIATE_TAG_LENGTH, ENC_BIG_ENDIAN); |
3930 | 54 | hidden_item = proto_tree_add_item(chunk_tree, hf_initiate_tag, chunk_tvb, INIT_CHUNK_INITIATE_TAG_OFFSET, INIT_CHUNK_INITIATE_TAG_LENGTH, ENC_BIG_ENDIAN); |
3931 | 54 | proto_item_set_hidden(hidden_item); |
3932 | 54 | proto_tree_add_item(chunk_tree, hf_initack_chunk_adv_rec_window_credit, chunk_tvb, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH, ENC_BIG_ENDIAN); |
3933 | 54 | proto_tree_add_item(chunk_tree, hf_initack_chunk_number_of_outbound_streams, chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH, ENC_BIG_ENDIAN); |
3934 | 54 | proto_tree_add_item(chunk_tree, hf_initack_chunk_number_of_inbound_streams, chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH, ENC_BIG_ENDIAN); |
3935 | 54 | proto_tree_add_item(chunk_tree, hf_initack_chunk_initial_tsn, chunk_tvb, INIT_CHUNK_INITIAL_TSN_OFFSET, INIT_CHUNK_INITIAL_TSN_LENGTH, ENC_BIG_ENDIAN); |
3936 | | |
3937 | 54 | proto_item_append_text(chunk_item, " (Outbound streams: %u, inbound streams: %u)", |
3938 | 54 | tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET), |
3939 | 54 | tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET)); |
3940 | 54 | } |
3941 | | /* handle variable parameters */ |
3942 | 54 | chunk_length -= INIT_CHUNK_FIXED_PARAMTERS_LENGTH; |
3943 | 54 | parameters_tvb = tvb_new_subset_length(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET, |
3944 | 54 | MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET))); |
3945 | 54 | dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false, true); |
3946 | 54 | } |
3947 | | |
3948 | 16 | #define SCTP_SACK_CHUNK_NS_BIT 0x01 |
3949 | 1.32k | #define SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4 |
3950 | 1.00k | #define SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4 |
3951 | 720 | #define SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH 2 |
3952 | 432 | #define SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH 2 |
3953 | 6.61k | #define SACK_CHUNK_GAP_BLOCK_LENGTH 4 |
3954 | 16.1k | #define SACK_CHUNK_GAP_BLOCK_START_LENGTH 2 |
3955 | 6.47k | #define SACK_CHUNK_GAP_BLOCK_END_LENGTH 2 |
3956 | 1.03k | #define SACK_CHUNK_DUP_TSN_LENGTH 4 |
3957 | | |
3958 | 1.61k | #define SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET (CHUNK_VALUE_OFFSET + 0) |
3959 | 1.15k | #define SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET + \ |
3960 | 1.15k | SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH) |
3961 | 864 | #define SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET (SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \ |
3962 | 864 | SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH) |
3963 | 576 | #define SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET (SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET + \ |
3964 | 576 | SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH) |
3965 | 288 | #define SACK_CHUNK_GAP_BLOCK_OFFSET (SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET + \ |
3966 | 288 | SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH) |
3967 | | |
3968 | | |
3969 | | static void |
3970 | | dissect_sack_chunk(packet_info *pinfo, tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item, sctp_half_assoc_t *ha) |
3971 | 144 | { |
3972 | 144 | uint16_t number_of_gap_blocks, number_of_dup_tsns; |
3973 | 144 | uint16_t gap_block_number, dup_tsn_number, start, end; |
3974 | 144 | int gap_block_offset, dup_tsn_offset; |
3975 | 144 | uint32_t cum_tsn_ack; |
3976 | 144 | proto_tree *block_tree; |
3977 | 144 | proto_tree *flags_tree; |
3978 | 144 | proto_item *ctsa_item; |
3979 | 144 | proto_item *a_rwnd_item; |
3980 | 144 | proto_tree *acks_tree; |
3981 | 144 | uint32_t tsns_gap_acked = 0; |
3982 | 144 | uint32_t a_rwnd; |
3983 | 144 | uint16_t last_end; |
3984 | | |
3985 | 144 | cum_tsn_ack = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET); |
3986 | 144 | if((show_relative_tsns) && (ha) && (ha->peer)) { |
3987 | 32 | cum_tsn_ack -= ha->peer->first_tsn; |
3988 | 32 | } |
3989 | | |
3990 | 144 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_sack_chunk_flags); |
3991 | 144 | proto_tree_add_item(flags_tree, hf_sack_chunk_ns, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
3992 | 144 | if((show_relative_tsns) && (ha) && (ha->peer)) { |
3993 | 32 | ctsa_item = proto_tree_add_uint(chunk_tree, hf_sack_chunk_cumulative_tsn_ack, chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH, cum_tsn_ack); |
3994 | 32 | proto_tree_add_item(chunk_tree, hf_sack_chunk_cumulative_tsn_ack_raw, chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH, ENC_BIG_ENDIAN); |
3995 | 32 | } |
3996 | 112 | else { |
3997 | 112 | ctsa_item = proto_tree_add_item(chunk_tree, hf_sack_chunk_cumulative_tsn_ack_raw, chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH, ENC_BIG_ENDIAN); |
3998 | 112 | } |
3999 | 144 | a_rwnd_item = proto_tree_add_item(chunk_tree, hf_sack_chunk_adv_rec_window_credit, chunk_tvb, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH, ENC_BIG_ENDIAN); |
4000 | 144 | proto_tree_add_item(chunk_tree, hf_sack_chunk_number_of_gap_blocks, chunk_tvb, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH, ENC_BIG_ENDIAN); |
4001 | 144 | proto_tree_add_item(chunk_tree, hf_sack_chunk_number_of_dup_tsns, chunk_tvb, SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET, SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH, ENC_BIG_ENDIAN); |
4002 | | |
4003 | 144 | a_rwnd = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET); |
4004 | 144 | if (a_rwnd == 0) |
4005 | 11 | expert_add_info(pinfo, a_rwnd_item, &ei_sctp_sack_chunk_adv_rec_window_credit); |
4006 | | |
4007 | | |
4008 | | /* handle the gap acknowledgement blocks */ |
4009 | 144 | number_of_gap_blocks = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET); |
4010 | 144 | gap_block_offset = SACK_CHUNK_GAP_BLOCK_OFFSET; |
4011 | | |
4012 | 144 | acks_tree = proto_item_add_subtree(ctsa_item,ett_sctp_ack); |
4013 | 144 | sctp_ack_block(pinfo, ha, chunk_tvb, acks_tree, NULL, cum_tsn_ack); |
4014 | | |
4015 | 144 | last_end = 0; |
4016 | 3.37k | for(gap_block_number = 0; gap_block_number < number_of_gap_blocks; gap_block_number++) { |
4017 | 3.23k | proto_item *pi; |
4018 | 3.23k | proto_tree *pt; |
4019 | 3.23k | uint32_t tsn_start; |
4020 | | |
4021 | 3.23k | start = tvb_get_ntohs(chunk_tvb, gap_block_offset); |
4022 | 3.23k | end = tvb_get_ntohs(chunk_tvb, gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH); |
4023 | 3.23k | tsn_start = cum_tsn_ack + start; |
4024 | | |
4025 | 3.23k | block_tree = proto_tree_add_subtree_format(chunk_tree, chunk_tvb, gap_block_offset, SACK_CHUNK_GAP_BLOCK_LENGTH, |
4026 | 3.23k | ett_sctp_sack_chunk_gap_block, NULL, "Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end); |
4027 | | |
4028 | 3.23k | pi = proto_tree_add_item(block_tree, hf_sack_chunk_gap_block_start, chunk_tvb, gap_block_offset, SACK_CHUNK_GAP_BLOCK_START_LENGTH, ENC_BIG_ENDIAN); |
4029 | 3.23k | pt = proto_item_add_subtree(pi, ett_sctp_sack_chunk_gap_block_start); |
4030 | 3.23k | pi = proto_tree_add_uint(pt, hf_sack_chunk_gap_block_start_tsn, |
4031 | 3.23k | chunk_tvb, gap_block_offset,SACK_CHUNK_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start); |
4032 | 3.23k | proto_item_set_generated(pi); |
4033 | | |
4034 | 3.23k | pi = proto_tree_add_item(block_tree, hf_sack_chunk_gap_block_end, chunk_tvb, gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH, SACK_CHUNK_GAP_BLOCK_END_LENGTH, ENC_BIG_ENDIAN); |
4035 | 3.23k | pt = proto_item_add_subtree(pi, ett_sctp_sack_chunk_gap_block_end); |
4036 | 3.23k | pi = proto_tree_add_uint(pt, hf_sack_chunk_gap_block_end_tsn, chunk_tvb, |
4037 | 3.23k | gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH, SACK_CHUNK_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end); |
4038 | 3.23k | proto_item_set_generated(pi); |
4039 | | |
4040 | 3.23k | sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end); |
4041 | 3.23k | gap_block_offset += SACK_CHUNK_GAP_BLOCK_LENGTH; |
4042 | | |
4043 | 3.23k | tsns_gap_acked += (end+1 - start); |
4044 | | |
4045 | | /* Check validity */ |
4046 | 3.23k | if (start > end) { |
4047 | 897 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed); |
4048 | 897 | } |
4049 | 3.23k | if (last_end > start) { |
4050 | 884 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order); |
4051 | 884 | } |
4052 | 3.23k | last_end = end; |
4053 | 3.23k | } |
4054 | | |
4055 | 144 | if(last_end == 0) { |
4056 | | /* No GapAck -> only show CumAck */ |
4057 | 29 | col_append_fstr(pinfo->cinfo, COL_INFO, |
4058 | 29 | "(Ack=%" PRIu32 ", Arwnd=%" PRIu32 ") ", |
4059 | 29 | cum_tsn_ack, a_rwnd); |
4060 | 29 | } |
4061 | 115 | else { |
4062 | | /* Show CumAck + highest GapAck */ |
4063 | 115 | col_append_fstr(pinfo->cinfo, COL_INFO, |
4064 | 115 | "(Ack=%" PRIu32 "+%" PRIu32 ", Arwnd=%" PRIu32 ") ", |
4065 | 115 | cum_tsn_ack, last_end, a_rwnd); |
4066 | 115 | } |
4067 | | |
4068 | 144 | if (tsns_gap_acked) { |
4069 | 10 | proto_item *pi; |
4070 | | |
4071 | 10 | pi = proto_tree_add_uint(chunk_tree, hf_sack_chunk_number_tsns_gap_acked, chunk_tvb, 0, 0, tsns_gap_acked); |
4072 | 10 | proto_item_set_generated(pi); |
4073 | | |
4074 | | /* If there are a huge number of GAP ACKs, warn the user. 100 is a random |
4075 | | * number: it could be tuned. |
4076 | | */ |
4077 | 10 | if (tsns_gap_acked > 100) |
4078 | 8 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_number_tsns_gap_acked_100); |
4079 | | |
4080 | 10 | } |
4081 | | |
4082 | | |
4083 | | /* handle the duplicate TSNs */ |
4084 | 144 | number_of_dup_tsns = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET); |
4085 | 144 | dup_tsn_offset = SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * SACK_CHUNK_GAP_BLOCK_LENGTH; |
4086 | 660 | for(dup_tsn_number = 0; dup_tsn_number < number_of_dup_tsns; dup_tsn_number++) { |
4087 | 516 | proto_tree_add_item(chunk_tree, hf_sack_chunk_duplicate_tsn, chunk_tvb, dup_tsn_offset, SACK_CHUNK_DUP_TSN_LENGTH, ENC_BIG_ENDIAN); |
4088 | 516 | dup_tsn_offset += SACK_CHUNK_DUP_TSN_LENGTH; |
4089 | 516 | } |
4090 | | |
4091 | 144 | proto_item_append_text(chunk_item, " (Cumulative TSN: %u, a_rwnd: %u, gaps: %u, duplicate TSNs: %u)", |
4092 | 144 | tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET), |
4093 | 144 | a_rwnd, |
4094 | 144 | number_of_gap_blocks, number_of_dup_tsns); |
4095 | 144 | } |
4096 | | |
4097 | | /* NE: Dissect nr-sack chunk */ |
4098 | 16 | #define SCTP_NR_SACK_CHUNK_NS_BIT 0x01 |
4099 | 2.04k | #define NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4 |
4100 | 1.70k | #define NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4 |
4101 | 1.36k | #define NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH 2 |
4102 | 1.02k | #define NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH 2 |
4103 | 680 | #define NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH 2 |
4104 | 510 | #define NR_SACK_CHUNK_RESERVED_LENGTH 2 |
4105 | 4.47k | #define NR_SACK_CHUNK_GAP_BLOCK_LENGTH 4 |
4106 | 10.7k | #define NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH 2 |
4107 | 4.30k | #define NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH 2 |
4108 | 4.38k | #define NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH 4 |
4109 | 10.5k | #define NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH 2 |
4110 | 4.21k | #define NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH 2 |
4111 | 1.12k | #define NR_SACK_CHUNK_DUP_TSN_LENGTH 4 |
4112 | | |
4113 | 2.38k | #define NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET (CHUNK_VALUE_OFFSET + 0) |
4114 | 1.87k | #define NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET + \ |
4115 | 1.87k | NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH) |
4116 | 1.53k | #define NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET (NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \ |
4117 | 1.53k | NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH) |
4118 | 1.19k | #define NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET (NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET + \ |
4119 | 1.19k | NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH) |
4120 | 850 | #define NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET (NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET + \ |
4121 | 850 | NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH) |
4122 | 510 | #define NR_SACK_CHUNK_RESERVED_OFFSET (NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET + \ |
4123 | 510 | NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH) |
4124 | 340 | #define NR_SACK_CHUNK_GAP_BLOCK_OFFSET (NR_SACK_CHUNK_RESERVED_OFFSET + \ |
4125 | 340 | NR_SACK_CHUNK_RESERVED_LENGTH) |
4126 | | |
4127 | | static void |
4128 | | dissect_nr_sack_chunk(packet_info *pinfo, tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item, sctp_half_assoc_t *ha) |
4129 | 170 | { |
4130 | 170 | uint16_t number_of_gap_blocks, number_of_dup_tsns; |
4131 | 170 | uint16_t number_of_nr_gap_blocks; |
4132 | 170 | uint16_t gap_block_number, nr_gap_block_number, dup_tsn_number, start, end; |
4133 | 170 | int gap_block_offset, nr_gap_block_offset, dup_tsn_offset; |
4134 | 170 | uint32_t cum_tsn_ack; |
4135 | 170 | proto_tree *block_tree; |
4136 | 170 | proto_tree *flags_tree; |
4137 | 170 | proto_item *ctsa_item; |
4138 | 170 | proto_tree *acks_tree; |
4139 | 170 | uint32_t tsns_gap_acked = 0; |
4140 | 170 | uint32_t tsns_nr_gap_acked = 0; |
4141 | 170 | uint16_t last_end; |
4142 | | |
4143 | 170 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_nr_sack_chunk_flags); |
4144 | 170 | proto_tree_add_item(flags_tree, hf_nr_sack_chunk_ns, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4145 | | |
4146 | 170 | ctsa_item = proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_cumulative_tsn_ack, chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH, ENC_BIG_ENDIAN); |
4147 | 170 | proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_adv_rec_window_credit, chunk_tvb, NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET, NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH, ENC_BIG_ENDIAN); |
4148 | | |
4149 | 170 | proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_number_of_gap_blocks, chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET, NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH, ENC_BIG_ENDIAN); |
4150 | | |
4151 | 170 | proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_number_of_nr_gap_blocks, chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET, NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH, ENC_BIG_ENDIAN); |
4152 | 170 | proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_number_of_dup_tsns, chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET, NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH, ENC_BIG_ENDIAN); |
4153 | 170 | proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_reserved, chunk_tvb, NR_SACK_CHUNK_RESERVED_OFFSET, NR_SACK_CHUNK_RESERVED_LENGTH, ENC_BIG_ENDIAN); |
4154 | | |
4155 | | |
4156 | 170 | number_of_gap_blocks = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET); |
4157 | 170 | gap_block_offset = NR_SACK_CHUNK_GAP_BLOCK_OFFSET; |
4158 | 170 | cum_tsn_ack = tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET); |
4159 | | |
4160 | 170 | acks_tree = proto_item_add_subtree(ctsa_item,ett_sctp_ack); |
4161 | 170 | sctp_ack_block(pinfo, ha, chunk_tvb, acks_tree, NULL, cum_tsn_ack); |
4162 | | |
4163 | 170 | last_end = 0; |
4164 | 2.32k | for(gap_block_number = 0; gap_block_number < number_of_gap_blocks; gap_block_number++) { |
4165 | 2.15k | proto_item *pi; |
4166 | 2.15k | proto_tree *pt; |
4167 | 2.15k | uint32_t tsn_start; |
4168 | | |
4169 | 2.15k | start = tvb_get_ntohs(chunk_tvb, gap_block_offset); |
4170 | 2.15k | end = tvb_get_ntohs(chunk_tvb, gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH); |
4171 | 2.15k | tsn_start = cum_tsn_ack + start; |
4172 | | |
4173 | 2.15k | block_tree = proto_tree_add_subtree_format(chunk_tree, chunk_tvb, gap_block_offset, NR_SACK_CHUNK_GAP_BLOCK_LENGTH, |
4174 | 2.15k | ett_sctp_nr_sack_chunk_gap_block, NULL, "Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end); |
4175 | | |
4176 | 2.15k | pi = proto_tree_add_item(block_tree, hf_nr_sack_chunk_gap_block_start, chunk_tvb, gap_block_offset, NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, ENC_BIG_ENDIAN); |
4177 | 2.15k | pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_gap_block_start); |
4178 | 2.15k | pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_gap_block_start_tsn, |
4179 | 2.15k | chunk_tvb, gap_block_offset,NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start); |
4180 | 2.15k | proto_item_set_generated(pi); |
4181 | | |
4182 | 2.15k | pi = proto_tree_add_item(block_tree, hf_nr_sack_chunk_gap_block_end, chunk_tvb, gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH, ENC_BIG_ENDIAN); |
4183 | 2.15k | pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_gap_block_end); |
4184 | 2.15k | pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_gap_block_end_tsn, chunk_tvb, |
4185 | 2.15k | gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end); |
4186 | 2.15k | proto_item_set_generated(pi); |
4187 | | |
4188 | 2.15k | sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end); |
4189 | 2.15k | gap_block_offset += NR_SACK_CHUNK_GAP_BLOCK_LENGTH; |
4190 | 2.15k | tsns_gap_acked += (end - start) + 1; |
4191 | | |
4192 | | /* Check validity */ |
4193 | 2.15k | if (start > end) { |
4194 | 608 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed); |
4195 | 608 | } |
4196 | 2.15k | if (last_end > start) { |
4197 | 581 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order); |
4198 | 581 | } |
4199 | 2.15k | last_end = end; |
4200 | 2.15k | } |
4201 | | |
4202 | 170 | if (tsns_gap_acked) { |
4203 | 18 | proto_item *pi; |
4204 | | |
4205 | 18 | pi = proto_tree_add_uint(chunk_tree, hf_nr_sack_chunk_number_tsns_gap_acked, chunk_tvb, 0, 0, tsns_gap_acked); |
4206 | 18 | proto_item_set_generated(pi); |
4207 | | |
4208 | | /* If there are a huge number of GAP ACKs, warn the user. 100 is a random |
4209 | | * number: it could be tuned. |
4210 | | */ |
4211 | 18 | if (tsns_gap_acked > 100) |
4212 | 13 | expert_add_info(pinfo, pi, &ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100); |
4213 | | |
4214 | 18 | } |
4215 | | |
4216 | | /* NE: handle the nr-sack chunk's nr-gap blocks */ |
4217 | 170 | number_of_nr_gap_blocks = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET); |
4218 | 170 | nr_gap_block_offset = gap_block_offset; |
4219 | | |
4220 | 170 | last_end = 0; |
4221 | 2.27k | for(nr_gap_block_number = 0; nr_gap_block_number < number_of_nr_gap_blocks; nr_gap_block_number++) { |
4222 | 2.10k | proto_item *pi; |
4223 | 2.10k | proto_tree *pt; |
4224 | | /*uint32_t tsn_start;*/ |
4225 | | |
4226 | 2.10k | start = tvb_get_ntohs(chunk_tvb, nr_gap_block_offset); |
4227 | 2.10k | end = tvb_get_ntohs(chunk_tvb, nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH); |
4228 | | /*tsn_start = cum_tsn_ack + start;*/ |
4229 | | |
4230 | 2.10k | block_tree = proto_tree_add_subtree_format(chunk_tree, chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH, |
4231 | 2.10k | ett_sctp_nr_sack_chunk_nr_gap_block, NULL, "NR-Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end); |
4232 | | |
4233 | 2.10k | pi = proto_tree_add_item(block_tree, hf_nr_sack_chunk_nr_gap_block_start, chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, ENC_BIG_ENDIAN); |
4234 | 2.10k | pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_nr_gap_block_start); |
4235 | 2.10k | pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_nr_gap_block_start_tsn, |
4236 | 2.10k | chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start); |
4237 | 2.10k | proto_item_set_generated(pi); |
4238 | | |
4239 | 2.10k | pi = proto_tree_add_item(block_tree, hf_nr_sack_chunk_nr_gap_block_end, chunk_tvb, nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH, ENC_BIG_ENDIAN); |
4240 | 2.10k | pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_nr_gap_block_end); |
4241 | 2.10k | pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_nr_gap_block_end_tsn, chunk_tvb, |
4242 | 2.10k | nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end); |
4243 | 2.10k | proto_item_set_generated(pi); |
4244 | | |
4245 | | /* sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end); */ |
4246 | 2.10k | nr_gap_block_offset += NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH; |
4247 | 2.10k | tsns_nr_gap_acked += (end - start) + 1; |
4248 | | |
4249 | | /* Check validity */ |
4250 | 2.10k | if (start > end) { |
4251 | 618 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed); |
4252 | 618 | } |
4253 | 2.10k | if (last_end > start) { |
4254 | 599 | expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order); |
4255 | 599 | } |
4256 | 2.10k | last_end = end; |
4257 | 2.10k | } |
4258 | | |
4259 | 170 | if (tsns_nr_gap_acked) { |
4260 | 10 | proto_item *pi; |
4261 | | |
4262 | 10 | pi = proto_tree_add_uint(chunk_tree, hf_nr_sack_chunk_number_tsns_nr_gap_acked, chunk_tvb, 0, 0, tsns_nr_gap_acked); |
4263 | 10 | proto_item_set_generated(pi); |
4264 | | |
4265 | | /* If there are a huge number of GAP ACKs, warn the user. 100 is a random |
4266 | | * number: it could be tuned. |
4267 | | */ |
4268 | 10 | if (tsns_nr_gap_acked > 100) |
4269 | 7 | expert_add_info(pinfo, pi, &ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100); |
4270 | 10 | } |
4271 | | |
4272 | | /* handle the duplicate TSNs */ |
4273 | 170 | number_of_dup_tsns = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET); |
4274 | 170 | dup_tsn_offset = NR_SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * NR_SACK_CHUNK_GAP_BLOCK_LENGTH |
4275 | 170 | + number_of_nr_gap_blocks * NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH; |
4276 | | |
4277 | | |
4278 | 730 | for(dup_tsn_number = 0; dup_tsn_number < number_of_dup_tsns; dup_tsn_number++) { |
4279 | 560 | proto_tree_add_item(chunk_tree, hf_nr_sack_chunk_duplicate_tsn, chunk_tvb, dup_tsn_offset, NR_SACK_CHUNK_DUP_TSN_LENGTH, ENC_BIG_ENDIAN); |
4280 | 560 | dup_tsn_offset += NR_SACK_CHUNK_DUP_TSN_LENGTH; |
4281 | 560 | } |
4282 | | |
4283 | 170 | proto_item_append_text(chunk_item, " (Cumulative TSN: %u, a_rwnd: %u, gaps: %u, nr-gaps: %u, duplicate TSNs: %u)", |
4284 | 170 | tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET), |
4285 | 170 | tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET), |
4286 | 170 | number_of_gap_blocks, number_of_nr_gap_blocks, number_of_dup_tsns); |
4287 | 170 | } |
4288 | | |
4289 | 29 | #define HEARTBEAT_CHUNK_INFO_OFFSET CHUNK_VALUE_OFFSET |
4290 | | |
4291 | | static void |
4292 | | // NOLINTNEXTLINE(misc-no-recursion) |
4293 | | dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item) |
4294 | 29 | { |
4295 | 29 | tvbuff_t *parameter_tvb; |
4296 | | |
4297 | 29 | if (chunk_tree) { |
4298 | 29 | proto_item_append_text(chunk_item, " (Information: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s")); |
4299 | 29 | parameter_tvb = tvb_new_subset_length(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET, |
4300 | 29 | MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET))); |
4301 | | /* FIXME: Parameters or parameter? */ |
4302 | 29 | dissect_parameter(parameter_tvb, pinfo, chunk_tree, NULL, false, false, true); |
4303 | 29 | } |
4304 | 29 | } |
4305 | | |
4306 | 16 | #define HEARTBEAT_ACK_CHUNK_INFO_OFFSET CHUNK_VALUE_OFFSET |
4307 | | |
4308 | | static void |
4309 | | // NOLINTNEXTLINE(misc-no-recursion) |
4310 | | dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item) |
4311 | 16 | { |
4312 | 16 | tvbuff_t *parameter_tvb; |
4313 | | |
4314 | 16 | if (chunk_tree) { |
4315 | 16 | proto_item_append_text(chunk_item, " (Information: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s")); |
4316 | 16 | parameter_tvb = tvb_new_subset_length(chunk_tvb, HEARTBEAT_ACK_CHUNK_INFO_OFFSET, |
4317 | 16 | MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, HEARTBEAT_ACK_CHUNK_INFO_OFFSET))); |
4318 | | /* FIXME: Parameters or parameter? */ |
4319 | 16 | dissect_parameter(parameter_tvb, pinfo, chunk_tree, NULL, false, false, true); |
4320 | 16 | } |
4321 | 16 | } |
4322 | | |
4323 | | #define ABORT_CHUNK_FIRST_ERROR_CAUSE_OFFSET 4 |
4324 | 72 | #define SCTP_ABORT_CHUNK_T_BIT 0x01 |
4325 | | |
4326 | | static void |
4327 | | // NOLINTNEXTLINE(misc-no-recursion) |
4328 | | dissect_abort_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *flags_item) |
4329 | 56 | { |
4330 | 56 | tvbuff_t *causes_tvb; |
4331 | 56 | proto_tree *flags_tree; |
4332 | | |
4333 | 56 | sctp_info.vtag_reflected = |
4334 | 56 | (tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_ABORT_CHUNK_T_BIT) != 0; |
4335 | | |
4336 | 56 | if (chunk_tree) { |
4337 | 56 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_abort_chunk_flags); |
4338 | 56 | proto_tree_add_item(flags_tree, hf_abort_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4339 | 56 | causes_tvb = tvb_new_subset_length(chunk_tvb, CHUNK_VALUE_OFFSET, |
4340 | 56 | MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, CHUNK_VALUE_OFFSET))); |
4341 | 56 | dissect_error_causes(causes_tvb, pinfo, chunk_tree); |
4342 | 56 | } |
4343 | 56 | } |
4344 | | |
4345 | 12 | #define SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET CHUNK_VALUE_OFFSET |
4346 | 6 | #define SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4 |
4347 | | |
4348 | | static void |
4349 | | dissect_shutdown_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item) |
4350 | 6 | { |
4351 | 6 | if (chunk_tree) { |
4352 | 6 | proto_tree_add_item(chunk_tree, hf_shutdown_chunk_cumulative_tsn_ack, chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_LENGTH, ENC_BIG_ENDIAN); |
4353 | 6 | proto_item_append_text(chunk_item, " (Cumulative TSN ack: %u)", tvb_get_ntohl(chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET)); |
4354 | 6 | } |
4355 | 6 | } |
4356 | | |
4357 | | static void |
4358 | | dissect_shutdown_ack_chunk(tvbuff_t *chunk_tvb _U_) |
4359 | 13 | { |
4360 | 13 | } |
4361 | | |
4362 | 42 | #define ERROR_CAUSE_IND_CAUSES_OFFSET CHUNK_VALUE_OFFSET |
4363 | | |
4364 | | static void |
4365 | | // NOLINTNEXTLINE(misc-no-recursion) |
4366 | | dissect_error_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree) |
4367 | 42 | { |
4368 | 42 | tvbuff_t *causes_tvb; |
4369 | | |
4370 | 42 | if (chunk_tree) { |
4371 | 42 | causes_tvb = tvb_new_subset_length(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET, |
4372 | 42 | MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET))); |
4373 | 42 | dissect_error_causes(causes_tvb, pinfo, chunk_tree); |
4374 | 42 | } |
4375 | 42 | } |
4376 | | |
4377 | 7 | #define COOKIE_OFFSET CHUNK_VALUE_OFFSET |
4378 | | |
4379 | | static void |
4380 | | dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item) |
4381 | 7 | { |
4382 | 7 | if (chunk_tree) { |
4383 | 7 | proto_tree_add_item(chunk_tree, hf_cookie, chunk_tvb, COOKIE_OFFSET, chunk_length - CHUNK_HEADER_LENGTH, ENC_NA); |
4384 | 7 | proto_item_append_text(chunk_item, " (Cookie length: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s")); |
4385 | 7 | } |
4386 | 7 | } |
4387 | | |
4388 | | static void |
4389 | | dissect_cookie_ack_chunk(tvbuff_t *chunk_tvb _U_) |
4390 | 8 | { |
4391 | 8 | } |
4392 | | |
4393 | 14 | #define ECNE_CHUNK_LOWEST_TSN_OFFSET CHUNK_VALUE_OFFSET |
4394 | 7 | #define ECNE_CHUNK_LOWEST_TSN_LENGTH 4 |
4395 | | |
4396 | | static void |
4397 | | dissect_ecne_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item) |
4398 | 7 | { |
4399 | 7 | proto_tree_add_item(chunk_tree, hf_ecne_chunk_lowest_tsn, chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET, ECNE_CHUNK_LOWEST_TSN_LENGTH, ENC_BIG_ENDIAN); |
4400 | 7 | proto_item_append_text(chunk_item, " (Lowest TSN: %u)", tvb_get_ntohl(chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET)); |
4401 | 7 | } |
4402 | | |
4403 | 16 | #define CWR_CHUNK_LOWEST_TSN_OFFSET CHUNK_VALUE_OFFSET |
4404 | 8 | #define CWR_CHUNK_LOWEST_TSN_LENGTH 4 |
4405 | | |
4406 | | static void |
4407 | | dissect_cwr_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item) |
4408 | 8 | { |
4409 | 8 | proto_tree_add_item(chunk_tree, hf_cwr_chunk_lowest_tsn, chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET, CWR_CHUNK_LOWEST_TSN_LENGTH, ENC_BIG_ENDIAN); |
4410 | 8 | proto_item_append_text(chunk_item, " (Lowest TSN: %u)", tvb_get_ntohl(chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET)); |
4411 | 8 | } |
4412 | | |
4413 | 18 | #define SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT 0x01 |
4414 | | |
4415 | | |
4416 | | static const true_false_string sctp_shutdown_complete_chunk_t_bit_value = { |
4417 | | "Tag reflected", |
4418 | | "Tag not reflected" |
4419 | | }; |
4420 | | |
4421 | | |
4422 | | static void |
4423 | | dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *flags_item) |
4424 | 2 | { |
4425 | 2 | proto_tree *flags_tree; |
4426 | | |
4427 | 2 | sctp_info.vtag_reflected = |
4428 | 2 | (tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) != 0; |
4429 | | |
4430 | 2 | if (chunk_tree) { |
4431 | 2 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_shutdown_complete_chunk_flags); |
4432 | 2 | proto_tree_add_item(flags_tree, hf_shutdown_complete_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4433 | 2 | } |
4434 | 2 | } |
4435 | | |
4436 | 108 | #define FORWARD_TSN_CHUNK_TSN_LENGTH 4 |
4437 | 1.71k | #define FORWARD_TSN_CHUNK_SID_LENGTH 2 |
4438 | 1.15k | #define FORWARD_TSN_CHUNK_SSN_LENGTH 2 |
4439 | 54 | #define FORWARD_TSN_CHUNK_TSN_OFFSET CHUNK_VALUE_OFFSET |
4440 | 1.12k | #define FORWARD_TSN_CHUNK_SID_OFFSET 0 |
4441 | 562 | #define FORWARD_TSN_CHUNK_SSN_OFFSET (FORWARD_TSN_CHUNK_SID_OFFSET + FORWARD_TSN_CHUNK_SID_LENGTH) |
4442 | | |
4443 | | static void |
4444 | | dissect_forward_tsn_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item) |
4445 | 27 | { |
4446 | 27 | unsigned offset; |
4447 | 27 | uint16_t number_of_affected_streams, affected_stream; |
4448 | | |
4449 | | /* FIXME */ |
4450 | 27 | if (chunk_length < CHUNK_HEADER_LENGTH + FORWARD_TSN_CHUNK_TSN_LENGTH) { |
4451 | 0 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", |
4452 | 0 | chunk_length, |
4453 | 0 | CHUNK_HEADER_LENGTH + FORWARD_TSN_CHUNK_TSN_LENGTH); |
4454 | 0 | return; |
4455 | 0 | } |
4456 | 27 | if (chunk_tree) { |
4457 | 27 | proto_tree_add_item(chunk_tree, hf_forward_tsn_chunk_tsn, chunk_tvb, FORWARD_TSN_CHUNK_TSN_OFFSET, FORWARD_TSN_CHUNK_TSN_LENGTH, ENC_BIG_ENDIAN); |
4458 | 27 | number_of_affected_streams = (chunk_length - CHUNK_HEADER_LENGTH - FORWARD_TSN_CHUNK_TSN_LENGTH) / |
4459 | 27 | (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH); |
4460 | 27 | offset = CHUNK_VALUE_OFFSET + FORWARD_TSN_CHUNK_TSN_LENGTH; |
4461 | | |
4462 | 589 | for(affected_stream = 0; affected_stream < number_of_affected_streams; affected_stream++) { |
4463 | 562 | proto_tree_add_item(chunk_tree, hf_forward_tsn_chunk_sid, chunk_tvb, offset + FORWARD_TSN_CHUNK_SID_OFFSET, FORWARD_TSN_CHUNK_SID_LENGTH, ENC_BIG_ENDIAN); |
4464 | 562 | proto_tree_add_item(chunk_tree, hf_forward_tsn_chunk_ssn, chunk_tvb, offset + FORWARD_TSN_CHUNK_SSN_OFFSET, FORWARD_TSN_CHUNK_SSN_LENGTH, ENC_BIG_ENDIAN); |
4465 | 562 | offset = offset + (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH); |
4466 | 562 | } |
4467 | 27 | proto_item_append_text(chunk_item, "(Cumulative TSN: %u)", tvb_get_ntohl(chunk_tvb, FORWARD_TSN_CHUNK_TSN_OFFSET)); |
4468 | 27 | } |
4469 | 27 | } |
4470 | | |
4471 | 114 | #define I_FORWARD_TSN_CHUNK_TSN_LENGTH 4 |
4472 | 1.64k | #define I_FORWARD_TSN_CHUNK_SID_LENGTH 2 |
4473 | 1.37k | #define I_FORWARD_TSN_CHUNK_FLAGS_LENGTH 2 |
4474 | 568 | #define I_FORWARD_TSN_CHUNK_MID_LENGTH 4 |
4475 | 56 | #define I_FORWARD_TSN_CHUNK_TSN_OFFSET CHUNK_VALUE_OFFSET |
4476 | 1.35k | #define I_FORWARD_TSN_CHUNK_SID_OFFSET 0 |
4477 | 1.08k | #define I_FORWARD_TSN_CHUNK_FLAGS_OFFSET (I_FORWARD_TSN_CHUNK_SID_OFFSET + I_FORWARD_TSN_CHUNK_SID_LENGTH) |
4478 | 270 | #define I_FORWARD_TSN_CHUNK_MID_OFFSET (I_FORWARD_TSN_CHUNK_FLAGS_OFFSET + I_FORWARD_TSN_CHUNK_FLAGS_LENGTH) |
4479 | | |
4480 | 16 | #define SCTP_I_FORWARD_TSN_CHUNK_U_BIT 0x0001 |
4481 | 16 | #define SCTP_I_FORWARD_TSN_CHUNK_RES_MASK 0xfffe |
4482 | | |
4483 | | static const true_false_string sctp_i_forward_tsn_chunk_u_bit_value = { |
4484 | | "Unordered messages", |
4485 | | "Ordered messages" |
4486 | | }; |
4487 | | |
4488 | | static void |
4489 | | dissect_i_forward_tsn_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item) |
4490 | 29 | { |
4491 | 29 | unsigned offset; |
4492 | 29 | uint16_t number_of_affected_streams, affected_stream; |
4493 | 29 | proto_tree *flags_tree; |
4494 | 29 | proto_item *flags_item = NULL; |
4495 | | |
4496 | | /* FIXME */ |
4497 | 29 | if (chunk_length < CHUNK_HEADER_LENGTH + I_FORWARD_TSN_CHUNK_TSN_LENGTH) { |
4498 | 1 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", |
4499 | 1 | chunk_length, |
4500 | 1 | CHUNK_HEADER_LENGTH + I_FORWARD_TSN_CHUNK_TSN_LENGTH); |
4501 | 1 | return; |
4502 | 1 | } |
4503 | 28 | if (chunk_tree) { |
4504 | 28 | proto_tree_add_item(chunk_tree, hf_i_forward_tsn_chunk_tsn, chunk_tvb, I_FORWARD_TSN_CHUNK_TSN_OFFSET, I_FORWARD_TSN_CHUNK_TSN_LENGTH, ENC_BIG_ENDIAN); |
4505 | 28 | number_of_affected_streams = (chunk_length - CHUNK_HEADER_LENGTH - I_FORWARD_TSN_CHUNK_TSN_LENGTH) / |
4506 | 28 | (I_FORWARD_TSN_CHUNK_SID_LENGTH + I_FORWARD_TSN_CHUNK_FLAGS_LENGTH + I_FORWARD_TSN_CHUNK_MID_LENGTH); |
4507 | 28 | offset = CHUNK_VALUE_OFFSET + I_FORWARD_TSN_CHUNK_TSN_LENGTH; |
4508 | | |
4509 | 298 | for(affected_stream = 0; affected_stream < number_of_affected_streams; affected_stream++) { |
4510 | 270 | proto_tree_add_item(chunk_tree, hf_i_forward_tsn_chunk_sid, chunk_tvb, offset + I_FORWARD_TSN_CHUNK_SID_OFFSET, I_FORWARD_TSN_CHUNK_SID_LENGTH, ENC_BIG_ENDIAN); |
4511 | 270 | flags_item = proto_tree_add_item(chunk_tree, hf_i_forward_tsn_chunk_flags, chunk_tvb, offset + I_FORWARD_TSN_CHUNK_FLAGS_OFFSET, I_FORWARD_TSN_CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4512 | 270 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_i_forward_tsn_chunk_flags); |
4513 | 270 | proto_tree_add_item(flags_tree, hf_i_forward_tsn_chunk_res, chunk_tvb, offset + I_FORWARD_TSN_CHUNK_FLAGS_OFFSET, I_FORWARD_TSN_CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4514 | 270 | proto_tree_add_item(flags_tree, hf_i_forward_tsn_chunk_u_bit, chunk_tvb, offset + I_FORWARD_TSN_CHUNK_FLAGS_OFFSET, I_FORWARD_TSN_CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4515 | 270 | proto_tree_add_item(chunk_tree, hf_i_forward_tsn_chunk_mid, chunk_tvb, offset + I_FORWARD_TSN_CHUNK_MID_OFFSET, I_FORWARD_TSN_CHUNK_MID_LENGTH, ENC_BIG_ENDIAN); |
4516 | 270 | offset += (I_FORWARD_TSN_CHUNK_SID_LENGTH + I_FORWARD_TSN_CHUNK_FLAGS_LENGTH + I_FORWARD_TSN_CHUNK_MID_LENGTH); |
4517 | 270 | } |
4518 | 28 | proto_item_append_text(chunk_item, "(Cumulative TSN: %u)", tvb_get_ntohl(chunk_tvb, I_FORWARD_TSN_CHUNK_TSN_OFFSET)); |
4519 | 28 | } |
4520 | 28 | } |
4521 | | |
4522 | 13 | #define RE_CONFIG_PARAMETERS_OFFSET CHUNK_HEADER_LENGTH |
4523 | | |
4524 | | static void |
4525 | | // NOLINTNEXTLINE(misc-no-recursion) |
4526 | | dissect_re_config_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item _U_) |
4527 | 13 | { |
4528 | 13 | tvbuff_t *parameters_tvb; |
4529 | | |
4530 | 13 | parameters_tvb = tvb_new_subset_length(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET, |
4531 | 13 | MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET))); |
4532 | 13 | dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false, false); |
4533 | 13 | } |
4534 | | |
4535 | 12 | #define SHARED_KEY_ID_LENGTH 2 |
4536 | | |
4537 | 9 | #define SHARED_KEY_ID_OFFSET PARAMETER_VALUE_OFFSET |
4538 | 6 | #define HMAC_ID_OFFSET (SHARED_KEY_ID_OFFSET + SHARED_KEY_ID_LENGTH) |
4539 | 3 | #define HMAC_OFFSET (HMAC_ID_OFFSET + HMAC_ID_LENGTH) |
4540 | | |
4541 | | static void |
4542 | | dissect_auth_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item _U_) |
4543 | 3 | { |
4544 | 3 | unsigned hmac_length; |
4545 | | |
4546 | 3 | hmac_length = chunk_length - CHUNK_HEADER_LENGTH - HMAC_ID_LENGTH - SHARED_KEY_ID_LENGTH; |
4547 | 3 | proto_tree_add_item(chunk_tree, hf_shared_key_id, chunk_tvb, SHARED_KEY_ID_OFFSET, SHARED_KEY_ID_LENGTH, ENC_BIG_ENDIAN); |
4548 | 3 | proto_tree_add_item(chunk_tree, hf_hmac_id, chunk_tvb, HMAC_ID_OFFSET, HMAC_ID_LENGTH, ENC_BIG_ENDIAN); |
4549 | 3 | if (hmac_length > 0) |
4550 | 3 | proto_tree_add_item(chunk_tree, hf_hmac, chunk_tvb, HMAC_OFFSET, hmac_length, ENC_NA); |
4551 | 3 | } |
4552 | | |
4553 | 16 | #define SCTP_DTLS_CHUNK_R_BIT 0x01 |
4554 | | |
4555 | | static const true_false_string sctp_dtls_chunk_r_bit_value = { |
4556 | | "Restart DTLS key context", |
4557 | | "Primary DTLS key context" |
4558 | | }; |
4559 | | |
4560 | | static void |
4561 | | dissect_dtls_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length _U_, proto_tree *chunk_tree, proto_item *flags_item) |
4562 | 8 | { |
4563 | 8 | proto_tree *flags_tree; |
4564 | | |
4565 | 8 | if (chunk_tree) { |
4566 | 8 | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_dtls_chunk_flags); |
4567 | 8 | proto_tree_add_item(flags_tree, hf_dtls_chunk_r_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4568 | 8 | } |
4569 | 8 | } |
4570 | | |
4571 | | |
4572 | 120 | #define SCTP_SEQUENCE_NUMBER_LENGTH 4 |
4573 | 56 | #define SEQUENCE_NUMBER_OFFSET CHUNK_VALUE_OFFSET |
4574 | 7 | #define ASCONF_CHUNK_PARAMETERS_OFFSET (SEQUENCE_NUMBER_OFFSET + SCTP_SEQUENCE_NUMBER_LENGTH) |
4575 | | |
4576 | | static void |
4577 | | // NOLINTNEXTLINE(misc-no-recursion) |
4578 | | dissect_asconf_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item) |
4579 | 8 | { |
4580 | 8 | tvbuff_t *parameters_tvb; |
4581 | | |
4582 | 8 | if (chunk_length < CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH) { |
4583 | 1 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", |
4584 | 1 | chunk_length, |
4585 | 1 | CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH); |
4586 | 1 | return; |
4587 | 1 | } |
4588 | 7 | if (chunk_tree) { |
4589 | 7 | proto_tree_add_item(chunk_tree, hf_asconf_seq_nr, chunk_tvb, SEQUENCE_NUMBER_OFFSET, SCTP_SEQUENCE_NUMBER_LENGTH, ENC_BIG_ENDIAN); |
4590 | 7 | } |
4591 | 7 | chunk_length -= CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH; |
4592 | 7 | parameters_tvb = tvb_new_subset_length(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET, |
4593 | 7 | MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET))); |
4594 | 7 | dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false, false); |
4595 | 7 | } |
4596 | | |
4597 | 21 | #define ASCONF_ACK_CHUNK_PARAMETERS_OFFSET (SEQUENCE_NUMBER_OFFSET + SCTP_SEQUENCE_NUMBER_LENGTH) |
4598 | | |
4599 | | static void |
4600 | | // NOLINTNEXTLINE(misc-no-recursion) |
4601 | | dissect_asconf_ack_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item) |
4602 | 24 | { |
4603 | 24 | tvbuff_t *parameters_tvb; |
4604 | | |
4605 | 24 | if (chunk_length < CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH) { |
4606 | 3 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", |
4607 | 3 | chunk_length + CHUNK_HEADER_LENGTH, |
4608 | 3 | CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH); |
4609 | 3 | return; |
4610 | 3 | } |
4611 | 21 | if (chunk_tree) { |
4612 | 21 | proto_tree_add_item(chunk_tree, hf_asconf_ack_seq_nr, chunk_tvb, SEQUENCE_NUMBER_OFFSET, SCTP_SEQUENCE_NUMBER_LENGTH, ENC_BIG_ENDIAN); |
4613 | 21 | } |
4614 | 21 | chunk_length -= CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH; |
4615 | 21 | parameters_tvb = tvb_new_subset_length(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET, |
4616 | 21 | MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET))); |
4617 | 21 | dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false, false); |
4618 | 21 | } |
4619 | | |
4620 | 110k | #define PKTDROP_CHUNK_BANDWIDTH_LENGTH 4 |
4621 | 94.7k | #define PKTDROP_CHUNK_QUEUESIZE_LENGTH 4 |
4622 | 78.9k | #define PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH 2 |
4623 | 63.1k | #define PKTDROP_CHUNK_RESERVED_SIZE_LENGTH 2 |
4624 | | |
4625 | 31.5k | #define PKTDROP_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \ |
4626 | 31.5k | PKTDROP_CHUNK_BANDWIDTH_LENGTH + \ |
4627 | 31.5k | PKTDROP_CHUNK_QUEUESIZE_LENGTH + \ |
4628 | 31.5k | PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH + \ |
4629 | 31.5k | PKTDROP_CHUNK_RESERVED_SIZE_LENGTH) |
4630 | | |
4631 | 78.9k | #define PKTDROP_CHUNK_BANDWIDTH_OFFSET CHUNK_VALUE_OFFSET |
4632 | 63.1k | #define PKTDROP_CHUNK_QUEUESIZE_OFFSET (PKTDROP_CHUNK_BANDWIDTH_OFFSET + PKTDROP_CHUNK_BANDWIDTH_LENGTH) |
4633 | 47.3k | #define PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET (PKTDROP_CHUNK_QUEUESIZE_OFFSET + PKTDROP_CHUNK_QUEUESIZE_LENGTH) |
4634 | 31.5k | #define PKTDROP_CHUNK_RESERVED_SIZE_OFFSET (PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET + PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH) |
4635 | 15.7k | #define PKTDROP_CHUNK_DATA_FIELD_OFFSET (PKTDROP_CHUNK_RESERVED_SIZE_OFFSET + PKTDROP_CHUNK_RESERVED_SIZE_LENGTH) |
4636 | | |
4637 | 16 | #define SCTP_PKTDROP_CHUNK_M_BIT 0x01 |
4638 | 16 | #define SCTP_PKTDROP_CHUNK_B_BIT 0x02 |
4639 | 15.7k | #define SCTP_PKTDROP_CHUNK_T_BIT 0x04 |
4640 | | |
4641 | | static const true_false_string sctp_pktdropk_m_bit_value = { |
4642 | | "Source is a middlebox", |
4643 | | "Source is an endhost" |
4644 | | }; |
4645 | | |
4646 | | static const true_false_string sctp_pktdropk_b_bit_value = { |
4647 | | "SCTP checksum was incorrect", |
4648 | | "SCTP checksum was correct" |
4649 | | }; |
4650 | | |
4651 | | static const true_false_string sctp_pktdropk_t_bit_value = { |
4652 | | "Packet is truncated", |
4653 | | "Packet is not truncated" |
4654 | | }; |
4655 | | |
4656 | | static void |
4657 | | // NOLINTNEXTLINE(misc-no-recursion) |
4658 | | dissect_pktdrop_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item) |
4659 | 15.7k | { |
4660 | 15.7k | tvbuff_t *data_field_tvb; |
4661 | 15.7k | proto_tree *flags_tree; |
4662 | | |
4663 | 15.7k | if (chunk_length < PKTDROP_CHUNK_HEADER_LENGTH) { |
4664 | 2 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", |
4665 | 2 | chunk_length, |
4666 | 2 | PKTDROP_CHUNK_HEADER_LENGTH); |
4667 | 2 | return; |
4668 | 2 | } |
4669 | 15.7k | chunk_length -= PKTDROP_CHUNK_HEADER_LENGTH; |
4670 | 15.7k | data_field_tvb = tvb_new_subset_length(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET, |
4671 | 15.7k | MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET))); |
4672 | | |
4673 | 15.7k | if (chunk_tree) { |
4674 | 15.7k | flags_tree = proto_item_add_subtree(flags_item, ett_sctp_pktdrop_chunk_flags); |
4675 | | |
4676 | 15.7k | proto_tree_add_item(flags_tree, hf_pktdrop_chunk_m_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4677 | 15.7k | proto_tree_add_item(flags_tree, hf_pktdrop_chunk_b_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4678 | 15.7k | proto_tree_add_item(flags_tree, hf_pktdrop_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4679 | 15.7k | proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_bandwidth, chunk_tvb, PKTDROP_CHUNK_BANDWIDTH_OFFSET, PKTDROP_CHUNK_BANDWIDTH_LENGTH, ENC_BIG_ENDIAN); |
4680 | 15.7k | proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_queuesize, chunk_tvb, PKTDROP_CHUNK_QUEUESIZE_OFFSET, PKTDROP_CHUNK_QUEUESIZE_LENGTH, ENC_BIG_ENDIAN); |
4681 | 15.7k | proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_truncated_length, chunk_tvb, PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET, PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH, ENC_BIG_ENDIAN); |
4682 | 15.7k | proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_reserved, chunk_tvb, PKTDROP_CHUNK_RESERVED_SIZE_OFFSET, PKTDROP_CHUNK_RESERVED_SIZE_LENGTH, ENC_BIG_ENDIAN); |
4683 | | |
4684 | 15.7k | if (chunk_length > 0) { |
4685 | | /* XXX - We should dissect what we can and catch the BoundsError when we run out of bytes */ |
4686 | 15.7k | if (tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_PKTDROP_CHUNK_T_BIT) |
4687 | 4 | proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_data_field, chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET, chunk_length, ENC_NA); |
4688 | 15.7k | else { |
4689 | 15.7k | bool save_in_error_pkt = pinfo->flags.in_error_pkt; |
4690 | 15.7k | pinfo->flags.in_error_pkt = true; |
4691 | | |
4692 | 15.7k | dissect_sctp_packet(data_field_tvb, pinfo, chunk_tree, true); |
4693 | | |
4694 | 15.7k | pinfo->flags.in_error_pkt = save_in_error_pkt; |
4695 | 15.7k | } |
4696 | 15.7k | } |
4697 | 15.7k | } |
4698 | 15.7k | } |
4699 | | |
4700 | | static void |
4701 | | dissect_pad_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item) |
4702 | 3 | { |
4703 | 3 | uint16_t value_length; |
4704 | | |
4705 | 3 | if (chunk_tree) { |
4706 | 3 | value_length = chunk_length - CHUNK_HEADER_LENGTH; |
4707 | 3 | proto_tree_add_item(chunk_tree, hf_pad_chunk_padding_data, chunk_tvb, CHUNK_VALUE_OFFSET, value_length, ENC_NA); |
4708 | 3 | proto_item_append_text(chunk_item, " (Padding data length: %u byte%s)", value_length, plurality(value_length, "", "s")); |
4709 | 3 | } |
4710 | 3 | } |
4711 | | |
4712 | | static void |
4713 | | dissect_unknown_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, uint8_t chunk_type, proto_tree *chunk_tree, proto_item *chunk_item) |
4714 | 194 | { |
4715 | 194 | uint16_t value_length; |
4716 | | |
4717 | 194 | if (chunk_tree) { |
4718 | 194 | value_length = chunk_length - CHUNK_HEADER_LENGTH; |
4719 | 194 | if (value_length > 0) |
4720 | 189 | proto_tree_add_item(chunk_tree, hf_chunk_value, chunk_tvb, CHUNK_VALUE_OFFSET, value_length, ENC_NA); |
4721 | 194 | proto_item_append_text(chunk_item, " (Type: %u, value length: %u byte%s)", chunk_type, value_length, plurality(value_length, "", "s")); |
4722 | 194 | } |
4723 | 194 | } |
4724 | | |
4725 | 16 | #define SCTP_CHUNK_BIT_1 0x80 |
4726 | 16 | #define SCTP_CHUNK_BIT_2 0x40 |
4727 | | |
4728 | | static const true_false_string sctp_chunk_bit_1_value = { |
4729 | | "Skip chunk and continue processing of the packet", |
4730 | | "Stop processing of the packet" |
4731 | | }; |
4732 | | |
4733 | | static const true_false_string sctp_chunk_bit_2_value = { |
4734 | | "Do report", |
4735 | | "Do not report" |
4736 | | }; |
4737 | | |
4738 | | |
4739 | | static bool |
4740 | | // NOLINTNEXTLINE(misc-no-recursion) |
4741 | | dissect_sctp_chunk(tvbuff_t *chunk_tvb, |
4742 | | packet_info *pinfo, |
4743 | | proto_tree *tree, |
4744 | | proto_tree *sctp_tree, |
4745 | | sctp_half_assoc_t *ha, |
4746 | | bool useinfo) |
4747 | 36.4k | { |
4748 | 36.4k | uint8_t type; |
4749 | 36.4k | uint16_t length, padding_length, reported_length; |
4750 | 36.4k | bool result; |
4751 | 36.4k | proto_item *flags_item, *chunk_item, *type_item, *length_item; |
4752 | 36.4k | proto_tree *chunk_tree, *type_tree; |
4753 | | |
4754 | 36.4k | result = false; |
4755 | | |
4756 | | /* first extract the chunk header */ |
4757 | 36.4k | type = tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET); |
4758 | 36.4k | length = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET); |
4759 | 36.4k | reported_length = tvb_reported_length(chunk_tvb); |
4760 | 36.4k | padding_length = reported_length - length; |
4761 | | |
4762 | 36.4k | if (useinfo) |
4763 | 20.5k | col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(type, chunk_type_values, "RESERVED")); |
4764 | | |
4765 | | /* create proto_tree stuff */ |
4766 | 36.4k | chunk_item = proto_tree_add_none_format(sctp_tree, hf_chunk, chunk_tvb, CHUNK_HEADER_OFFSET, reported_length, |
4767 | 36.4k | "%s chunk", val_to_str_const(type, chunk_type_values, "RESERVED")); |
4768 | 36.4k | chunk_tree = proto_item_add_subtree(chunk_item, ett_sctp_chunk); |
4769 | | |
4770 | 36.4k | if (tree) { |
4771 | | /* then insert the chunk header components into the protocol tree */ |
4772 | 36.4k | type_item = proto_tree_add_item(chunk_tree, hf_chunk_type, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN); |
4773 | 36.4k | type_tree = proto_item_add_subtree(type_item, ett_sctp_chunk_type); |
4774 | 36.4k | proto_tree_add_item(type_tree, hf_chunk_bit_1, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN); |
4775 | 36.4k | proto_tree_add_item(type_tree, hf_chunk_bit_2, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN); |
4776 | 36.4k | flags_item = proto_tree_add_item(chunk_tree, hf_chunk_flags, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN); |
4777 | 36.4k | } else { |
4778 | 61 | chunk_tree = NULL; |
4779 | 61 | chunk_item = NULL; |
4780 | 61 | flags_item = NULL; |
4781 | 61 | } |
4782 | | |
4783 | 36.4k | if (length < CHUNK_HEADER_LENGTH) { |
4784 | 123 | if (tree) { |
4785 | 123 | proto_tree_add_uint_format_value(chunk_tree, hf_chunk_length, chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH, length, |
4786 | 123 | "%u (invalid, should be >= %u)", length, CHUNK_HEADER_LENGTH); |
4787 | 123 | proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", length, CHUNK_HEADER_LENGTH); |
4788 | 123 | } |
4789 | | |
4790 | 123 | if (type == SCTP_DATA_CHUNK_ID) |
4791 | 76 | result = true; |
4792 | 123 | return result; |
4793 | 123 | } |
4794 | | |
4795 | 36.3k | length_item = proto_tree_add_uint(chunk_tree, hf_chunk_length, chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH, length); |
4796 | 36.3k | if (length > reported_length && !pinfo->flags.in_error_pkt) { |
4797 | 19.7k | expert_add_info_format(pinfo, length_item, &ei_sctp_chunk_length_bad, "Chunk length (%d) is longer than remaining data (%d) in the packet.", length, reported_length); |
4798 | | /* We'll almost certainly throw an exception shortly... */ |
4799 | 19.7k | } |
4800 | | |
4801 | | /* |
4802 | | length -= CHUNK_HEADER_LENGTH; |
4803 | | */ |
4804 | | |
4805 | | /* now dissect the chunk value */ |
4806 | 36.3k | increment_dissection_depth(pinfo); |
4807 | 36.3k | switch(type) { |
4808 | 19.4k | case SCTP_DATA_CHUNK_ID: |
4809 | 19.4k | result = dissect_data_chunk(chunk_tvb, length, pinfo, tree, chunk_tree, chunk_item, flags_item, ha, false); |
4810 | 19.4k | break; |
4811 | 53 | case SCTP_I_DATA_CHUNK_ID: |
4812 | 53 | result = dissect_data_chunk(chunk_tvb, length, pinfo, tree, chunk_tree, chunk_item, flags_item, ha, true); |
4813 | 53 | break; |
4814 | 120 | case SCTP_INIT_CHUNK_ID: |
4815 | 120 | dissect_init_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4816 | 120 | break; |
4817 | 57 | case SCTP_INIT_ACK_CHUNK_ID: |
4818 | 57 | dissect_init_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4819 | 57 | break; |
4820 | 144 | case SCTP_SACK_CHUNK_ID: |
4821 | 144 | dissect_sack_chunk(pinfo, chunk_tvb, chunk_tree, chunk_item, flags_item, ha); |
4822 | 144 | break; |
4823 | 29 | case SCTP_HEARTBEAT_CHUNK_ID: |
4824 | 29 | dissect_heartbeat_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4825 | 29 | break; |
4826 | 16 | case SCTP_HEARTBEAT_ACK_CHUNK_ID: |
4827 | 16 | dissect_heartbeat_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4828 | 16 | break; |
4829 | 56 | case SCTP_ABORT_CHUNK_ID: |
4830 | 56 | dissect_abort_chunk(chunk_tvb, length, pinfo, chunk_tree, flags_item); |
4831 | 56 | break; |
4832 | 6 | case SCTP_SHUTDOWN_CHUNK_ID: |
4833 | 6 | dissect_shutdown_chunk(chunk_tvb, chunk_tree, chunk_item); |
4834 | 6 | break; |
4835 | 13 | case SCTP_SHUTDOWN_ACK_CHUNK_ID: |
4836 | 13 | dissect_shutdown_ack_chunk(chunk_tvb); |
4837 | 13 | break; |
4838 | 42 | case SCTP_ERROR_CHUNK_ID: |
4839 | 42 | dissect_error_chunk(chunk_tvb, length, pinfo, chunk_tree); |
4840 | 42 | break; |
4841 | 7 | case SCTP_COOKIE_ECHO_CHUNK_ID: |
4842 | 7 | dissect_cookie_echo_chunk(chunk_tvb, length, chunk_tree, chunk_item); |
4843 | 7 | break; |
4844 | 8 | case SCTP_COOKIE_ACK_CHUNK_ID: |
4845 | 8 | dissect_cookie_ack_chunk(chunk_tvb); |
4846 | 8 | break; |
4847 | 7 | case SCTP_ECNE_CHUNK_ID: |
4848 | 7 | dissect_ecne_chunk(chunk_tvb, chunk_tree, chunk_item); |
4849 | 7 | break; |
4850 | 8 | case SCTP_CWR_CHUNK_ID: |
4851 | 8 | dissect_cwr_chunk(chunk_tvb, chunk_tree, chunk_item); |
4852 | 8 | break; |
4853 | 2 | case SCTP_SHUTDOWN_COMPLETE_CHUNK_ID: |
4854 | 2 | dissect_shutdown_complete_chunk(chunk_tvb, chunk_tree, flags_item); |
4855 | 2 | break; |
4856 | 27 | case SCTP_FORWARD_TSN_CHUNK_ID: |
4857 | 27 | dissect_forward_tsn_chunk(chunk_tvb, length, chunk_tree, chunk_item); |
4858 | 27 | break; |
4859 | 13 | case SCTP_RE_CONFIG_CHUNK_ID: |
4860 | 13 | dissect_re_config_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4861 | 13 | break; |
4862 | 3 | case SCTP_AUTH_CHUNK_ID: |
4863 | 3 | dissect_auth_chunk(chunk_tvb, length, chunk_tree, chunk_item); |
4864 | 3 | break; |
4865 | 170 | case SCTP_NR_SACK_CHUNK_ID: |
4866 | 170 | dissect_nr_sack_chunk(pinfo, chunk_tvb, chunk_tree, chunk_item, flags_item, ha); |
4867 | 170 | break; |
4868 | 8 | case SCTP_DTLS_CHUNK_ID: |
4869 | 8 | dissect_dtls_chunk(chunk_tvb, length, chunk_tree, flags_item); |
4870 | 8 | break; |
4871 | 24 | case SCTP_ASCONF_ACK_CHUNK_ID: |
4872 | 24 | dissect_asconf_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4873 | 24 | break; |
4874 | 8 | case SCTP_ASCONF_CHUNK_ID: |
4875 | 8 | dissect_asconf_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item); |
4876 | 8 | break; |
4877 | 29 | case SCTP_I_FORWARD_TSN_CHUNK_ID: |
4878 | 29 | dissect_i_forward_tsn_chunk(chunk_tvb, length, chunk_tree, chunk_item); |
4879 | 29 | break; |
4880 | 15.7k | case SCTP_PKTDROP_CHUNK_ID: |
4881 | 15.7k | col_set_writable(pinfo->cinfo, -1, false); |
4882 | 15.7k | dissect_pktdrop_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item, flags_item); |
4883 | 15.7k | col_set_writable(pinfo->cinfo, -1, true); |
4884 | 15.7k | break; |
4885 | 3 | case SCTP_PAD_CHUNK_ID: |
4886 | 3 | dissect_pad_chunk(chunk_tvb, length, chunk_tree, chunk_item); |
4887 | 3 | break; |
4888 | 194 | default: |
4889 | 194 | dissect_unknown_chunk(chunk_tvb, length, type, chunk_tree, chunk_item); |
4890 | 194 | break; |
4891 | 36.3k | } |
4892 | 19.6k | decrement_dissection_depth(pinfo); |
4893 | | |
4894 | 19.6k | if (padding_length > 0) |
4895 | 19.3k | proto_tree_add_item(chunk_tree, hf_chunk_padding, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length, ENC_NA); |
4896 | | |
4897 | 19.6k | if (useinfo && ((type == SCTP_DATA_CHUNK_ID) || show_always_control_chunks)) |
4898 | 698 | col_set_fence(pinfo->cinfo, COL_INFO); |
4899 | | |
4900 | 19.6k | return result; |
4901 | 36.3k | } |
4902 | | |
4903 | | static void |
4904 | | // NOLINTNEXTLINE(misc-no-recursion) |
4905 | | dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *sctp_item, proto_tree *sctp_tree, sctp_half_assoc_t *ha, bool encapsulated, proto_item *vt) |
4906 | 35.6k | { |
4907 | 35.6k | proto_item *pi; |
4908 | 35.6k | tvbuff_t *chunk_tvb; |
4909 | 35.6k | uint16_t length, total_length, remaining_length; |
4910 | 35.6k | int last_offset, offset; |
4911 | 35.6k | bool sctp_item_length_set; |
4912 | 35.6k | assoc_info_t tmpinfo; |
4913 | 35.6k | infodata_t id_dir; |
4914 | 35.6k | bool first_chunk = true; |
4915 | | |
4916 | | /* the common header of the datagram is already handled */ |
4917 | 35.6k | last_offset = 0; |
4918 | 35.6k | offset = COMMON_HEADER_LENGTH; |
4919 | 35.6k | sctp_item_length_set = false; |
4920 | | |
4921 | 72.2k | while((remaining_length = tvb_reported_length_remaining(tvb, offset))) { |
4922 | | /* extract the chunk length and compute number of padding bytes */ |
4923 | 36.5k | length = tvb_get_ntohs(tvb, offset + CHUNK_LENGTH_OFFSET); |
4924 | 36.5k | total_length = WS_ROUNDUP_4(length); |
4925 | | |
4926 | | /* If we have less bytes than we need, throw an exception while dissecting |
4927 | | * the chunk--not when generating the chunk_tvb below. |
4928 | | */ |
4929 | 36.5k | total_length = MIN(total_length, remaining_length); |
4930 | | |
4931 | | /* create a tvb for the chunk including the padding bytes */ |
4932 | 36.5k | chunk_tvb = tvb_new_subset_length(tvb, offset, total_length); |
4933 | | |
4934 | | /* save it in the sctp_info structure */ |
4935 | 36.5k | if (!encapsulated) { |
4936 | 20.6k | if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS) |
4937 | 20.6k | sctp_info.tvb[sctp_info.number_of_tvbs++] = chunk_tvb; |
4938 | 0 | else |
4939 | 0 | sctp_info.incomplete = true; |
4940 | 20.6k | } |
4941 | 36.5k | if (first_chunk) { |
4942 | 35.6k | first_chunk = false; |
4943 | 35.6k | if (enable_association_indexing) { |
4944 | 0 | tmpinfo.assoc_index = -1; |
4945 | 0 | tmpinfo.direction = 1; |
4946 | 0 | copy_address_shallow(&tmpinfo.saddr, &pinfo->src); |
4947 | 0 | copy_address_shallow(&tmpinfo.daddr, &pinfo->dst); |
4948 | 0 | tmpinfo.sport = sctp_info.sport; |
4949 | 0 | tmpinfo.dport = sctp_info.dport; |
4950 | 0 | bool vtag_reflected = false; |
4951 | | /* Certain chunk types have exceptional Verification Tag handling |
4952 | | * ( see https://datatracker.ietf.org/doc/html/rfc9260#section-8.5.1 ) |
4953 | | * XXX: Those chunk types shouldn't be bundled with other chunk types |
4954 | | * (ABORT can be bundled after other control types, but ABORT with the |
4955 | | * T bit set should not be) and there should be an expert info if so. |
4956 | | * Should we use the association from the first chunk or the last |
4957 | | * chunk in such a case? |
4958 | | */ |
4959 | 0 | if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_ABORT_CHUNK_ID) { |
4960 | 0 | if ((tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_ABORT_CHUNK_T_BIT) != 0) { |
4961 | 0 | vtag_reflected = true; |
4962 | 0 | } |
4963 | 0 | } |
4964 | 0 | if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_SHUTDOWN_COMPLETE_CHUNK_ID) { |
4965 | 0 | if ((tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) != 0) { |
4966 | 0 | vtag_reflected = true; |
4967 | 0 | } |
4968 | 0 | } |
4969 | 0 | if (vtag_reflected) { |
4970 | 0 | tmpinfo.verification_tag1 = 0; |
4971 | 0 | tmpinfo.verification_tag2 = sctp_info.verification_tag; |
4972 | 0 | } |
4973 | 0 | else { |
4974 | 0 | tmpinfo.verification_tag1 = sctp_info.verification_tag; |
4975 | 0 | tmpinfo.verification_tag2 = 0; |
4976 | 0 | } |
4977 | 0 | if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_INIT_CHUNK_ID) { |
4978 | 0 | tmpinfo.verification_tag1 = 0; |
4979 | 0 | tmpinfo.verification_tag2 = tvb_get_ntohl(sctp_info.tvb[0], 4); |
4980 | 0 | } |
4981 | 0 | if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_INIT_ACK_CHUNK_ID) { |
4982 | 0 | tmpinfo.verification_tag2 = tvb_get_ntohl(sctp_info.tvb[0], 4); |
4983 | 0 | } |
4984 | |
|
4985 | 0 | id_dir = find_assoc_index(&tmpinfo, pinfo); |
4986 | 0 | pi = proto_tree_add_uint(sctp_tree, hf_sctp_assoc_index, tvb, 0 , 0, id_dir.assoc_index); |
4987 | | /* XXX: Should we set these if encapsulated is true or not? */ |
4988 | 0 | sctp_info.assoc_index = id_dir.assoc_index; |
4989 | 0 | sctp_info.direction = id_dir.direction; |
4990 | |
|
4991 | 35.6k | } else { |
4992 | 35.6k | pi = proto_tree_add_uint_format_value(sctp_tree, hf_sctp_assoc_index, tvb, 0 , 0, sctp_info.assoc_index, "disabled (enable in preferences)"); |
4993 | 35.6k | } |
4994 | | |
4995 | 35.6k | proto_item_set_generated(pi); |
4996 | 35.6k | proto_tree_move_item(sctp_tree, vt, pi); |
4997 | 35.6k | } |
4998 | | |
4999 | | /* call dissect_sctp_chunk for the actual work */ |
5000 | 36.5k | if (dissect_sctp_chunk(chunk_tvb, pinfo, tree, sctp_tree, ha, !encapsulated) && (tree)) { |
5001 | 410 | proto_item_set_len(sctp_item, offset - last_offset + DATA_CHUNK_HEADER_LENGTH); |
5002 | 410 | sctp_item_length_set = true; |
5003 | 410 | offset += total_length; |
5004 | 410 | last_offset = offset; |
5005 | 410 | if (tvb_reported_length_remaining(tvb, offset) > 0) { |
5006 | 404 | sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, offset, -1, ENC_NA); |
5007 | 404 | sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp); |
5008 | 404 | sctp_item_length_set = false; |
5009 | 404 | } |
5010 | 36.1k | } else { |
5011 | | /* get rid of the dissected chunk */ |
5012 | 36.1k | offset += total_length; |
5013 | 36.1k | } |
5014 | 36.5k | } |
5015 | 35.6k | if (!sctp_item_length_set && (tree)) { |
5016 | 54 | proto_item_set_len(sctp_item, offset - last_offset); |
5017 | 54 | } |
5018 | 35.6k | } |
5019 | | |
5020 | | static void |
5021 | | // NOLINTNEXTLINE(misc-no-recursion) |
5022 | | dissect_sctp_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool encapsulated) |
5023 | 35.6k | { |
5024 | 35.6k | uint32_t checksum = 0, calculated_crc32c = 0, calculated_adler32 = 0; |
5025 | 35.6k | uint16_t source_port, destination_port; |
5026 | 35.6k | unsigned captured_length, reported_length; |
5027 | 35.6k | bool crc32c_correct = false, adler32_correct = false; |
5028 | 35.6k | proto_item *sctp_item, *hidden_item; |
5029 | 35.6k | proto_tree *sctp_tree; |
5030 | 35.6k | uint32_t vtag; |
5031 | 35.6k | sctp_half_assoc_t *ha = NULL; |
5032 | 35.6k | proto_item *vt = NULL; |
5033 | | |
5034 | 35.6k | captured_length = tvb_captured_length(tvb); |
5035 | 35.6k | reported_length = tvb_reported_length(tvb); |
5036 | 35.6k | checksum = tvb_get_ntohl(tvb, CHECKSUM_OFFSET); |
5037 | 35.6k | sctp_info.checksum_zero = (checksum == 0); |
5038 | | |
5039 | | /* Only try to checksum the packet if we have all of it */ |
5040 | 35.6k | if ((captured_length == reported_length) && |
5041 | 35.6k | (captured_length >= COMMON_HEADER_LENGTH)) { |
5042 | | |
5043 | 35.6k | switch(sctp_checksum) { |
5044 | 35.6k | case SCTP_CHECKSUM_NONE: |
5045 | 35.6k | break; |
5046 | 0 | case SCTP_CHECKSUM_ADLER32: |
5047 | 0 | calculated_adler32 = sctp_adler32(tvb, captured_length); |
5048 | 0 | adler32_correct = (checksum == calculated_adler32); |
5049 | 0 | sctp_info.adler32_calculated = true; |
5050 | 0 | sctp_info.adler32_correct = adler32_correct; |
5051 | 0 | break; |
5052 | 0 | case SCTP_CHECKSUM_CRC32C: |
5053 | 0 | calculated_crc32c = sctp_crc32c(tvb, captured_length); |
5054 | 0 | crc32c_correct = (checksum == calculated_crc32c); |
5055 | 0 | sctp_info.crc32c_calculated = true; |
5056 | 0 | sctp_info.crc32c_correct = crc32c_correct; |
5057 | 0 | break; |
5058 | 0 | case SCTP_CHECKSUM_AUTOMATIC: |
5059 | 0 | calculated_adler32 = sctp_adler32(tvb, captured_length); |
5060 | 0 | adler32_correct = (checksum == calculated_adler32); |
5061 | 0 | calculated_crc32c = sctp_crc32c(tvb, captured_length); |
5062 | 0 | crc32c_correct = (checksum == calculated_crc32c); |
5063 | 0 | sctp_info.adler32_calculated = true; |
5064 | 0 | sctp_info.adler32_correct = adler32_correct; |
5065 | 0 | sctp_info.crc32c_calculated = true; |
5066 | 0 | sctp_info.crc32c_correct = crc32c_correct; |
5067 | 0 | break; |
5068 | 35.6k | } |
5069 | 35.6k | } |
5070 | | |
5071 | 35.6k | source_port = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET); |
5072 | 35.6k | destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET); |
5073 | 35.6k | vtag = tvb_get_ntohl(tvb,VERIFICATION_TAG_OFFSET); |
5074 | | |
5075 | 35.6k | ha = get_half_assoc(pinfo, source_port, destination_port, vtag); |
5076 | | |
5077 | | /* In the interest of speed, if "tree" is NULL, don't do any work not |
5078 | | necessary to generate protocol tree items. */ |
5079 | 35.6k | if (tree) { |
5080 | | |
5081 | | /* create the sctp protocol tree */ |
5082 | 35.6k | if (show_port_numbers) |
5083 | 35.6k | sctp_item = proto_tree_add_protocol_format(tree, proto_sctp, tvb, 0, -1, |
5084 | 35.6k | "Stream Control Transmission Protocol, Src Port: %s (%u), Dst Port: %s (%u)", |
5085 | 35.6k | sctp_port_to_display(pinfo->pool, source_port), source_port, |
5086 | 35.6k | sctp_port_to_display(pinfo->pool, destination_port), destination_port); |
5087 | 0 | else |
5088 | 0 | sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, 0, -1, ENC_NA); |
5089 | | |
5090 | 35.6k | sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp); |
5091 | | |
5092 | | /* add the components of the common header to the protocol tree */ |
5093 | 35.6k | proto_tree_add_item(sctp_tree, hf_source_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, ENC_BIG_ENDIAN); |
5094 | 35.6k | proto_tree_add_item(sctp_tree, hf_destination_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, ENC_BIG_ENDIAN); |
5095 | 35.6k | vt = proto_tree_add_item(sctp_tree, hf_verification_tag, tvb, VERIFICATION_TAG_OFFSET, VERIFICATION_TAG_LENGTH, ENC_BIG_ENDIAN); |
5096 | 35.6k | hidden_item = proto_tree_add_item(sctp_tree, hf_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, ENC_BIG_ENDIAN); |
5097 | 35.6k | proto_item_set_hidden(hidden_item); |
5098 | 35.6k | hidden_item = proto_tree_add_item(sctp_tree, hf_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, ENC_BIG_ENDIAN); |
5099 | 35.6k | proto_item_set_hidden(hidden_item); |
5100 | 35.6k | } else { |
5101 | 12 | sctp_tree = NULL; |
5102 | 12 | sctp_item = NULL; |
5103 | 12 | } |
5104 | | |
5105 | 35.6k | if (captured_length == reported_length) { |
5106 | | /* We have the whole packet */ |
5107 | | |
5108 | 35.6k | switch(sctp_checksum) { |
5109 | 35.6k | case SCTP_CHECKSUM_NONE: |
5110 | 35.6k | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, 0, |
5111 | 35.6k | ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
5112 | 35.6k | break; |
5113 | 0 | case SCTP_CHECKSUM_ADLER32: |
5114 | 0 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_adler, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_adler32, |
5115 | 0 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
5116 | 0 | break; |
5117 | 0 | case SCTP_CHECKSUM_CRC32C: |
5118 | 0 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_crc32c, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_crc32c, |
5119 | 0 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
5120 | 0 | break; |
5121 | 0 | case SCTP_CHECKSUM_AUTOMATIC: |
5122 | 0 | if ((adler32_correct) && !(crc32c_correct)) |
5123 | 0 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_adler, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_adler32, |
5124 | 0 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
5125 | 0 | else if ((!adler32_correct) && (crc32c_correct)) |
5126 | 0 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_crc32c, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_crc32c, |
5127 | 0 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
5128 | 0 | else { |
5129 | 0 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_adler, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_adler32, |
5130 | 0 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
5131 | 0 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_crc32c, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_crc32c, |
5132 | 0 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
5133 | 0 | } |
5134 | 0 | break; |
5135 | 35.6k | } |
5136 | 35.6k | } else { |
5137 | | /* We don't have the whole packet so we can't verify the checksum */ |
5138 | 14 | proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, 0, |
5139 | 14 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
5140 | 14 | } |
5141 | | |
5142 | | /* add all chunks of the sctp datagram to the protocol tree */ |
5143 | 35.6k | dissect_sctp_chunks(tvb, pinfo, tree, sctp_item, sctp_tree, ha, encapsulated, vt); |
5144 | | |
5145 | 35.6k | } |
5146 | | |
5147 | | static bool |
5148 | | capture_sctp(const unsigned char *pd _U_, int offset _U_, int len _U_, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_) |
5149 | 0 | { |
5150 | 0 | capture_dissector_increment_count(cpinfo, proto_sctp); |
5151 | 0 | return true; |
5152 | 0 | } |
5153 | | |
5154 | | static int |
5155 | | dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
5156 | 19.9k | { |
5157 | 19.9k | uint16_t source_port, destination_port; |
5158 | 19.9k | unsigned number_of_ppid; |
5159 | | |
5160 | | /* Extract the common header */ |
5161 | 19.9k | source_port = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET); |
5162 | 19.9k | destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET); |
5163 | | |
5164 | | /* update pi structure */ |
5165 | 19.9k | pinfo->ptype = PT_SCTP; |
5166 | 19.9k | pinfo->srcport = source_port; |
5167 | 19.9k | pinfo->destport = destination_port; |
5168 | | |
5169 | | /* make entry in the Protocol column on summary display */ |
5170 | 19.9k | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCTP"); |
5171 | | |
5172 | | /* Clear entries in Info column on summary display */ |
5173 | 19.9k | col_clear(pinfo->cinfo, COL_INFO); |
5174 | | |
5175 | | |
5176 | 59.7k | for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) { |
5177 | 39.8k | p_add_proto_data(pinfo->pool, pinfo, proto_sctp, number_of_ppid, GUINT_TO_POINTER(LAST_PPID)); |
5178 | 39.8k | } |
5179 | | |
5180 | | /* The tvb array in struct _sctp_info is huge: currently 2k pointers. |
5181 | | * We know (by the value of 'number_of_tvbs') which of these entries have |
5182 | | * been used, so don't memset() the array. This saves us from zeroing out |
5183 | | * 8k (4-byte pointers) or 16k (8-byte pointers) of memory every time we |
5184 | | * dissect a packet (saving quite a bit of time!). |
5185 | | */ |
5186 | 19.9k | sctp_info.incomplete = 0; |
5187 | 19.9k | sctp_info.adler32_calculated = 0; |
5188 | 19.9k | sctp_info.adler32_correct = 0; |
5189 | 19.9k | sctp_info.crc32c_calculated = 0; |
5190 | 19.9k | sctp_info.crc32c_correct = 0; |
5191 | 19.9k | sctp_info.vtag_reflected = 0; |
5192 | 19.9k | sctp_info.number_of_tvbs = 0; |
5193 | 19.9k | sctp_info.verification_tag = tvb_get_ntohl(tvb, VERIFICATION_TAG_OFFSET); |
5194 | | /* Initialize these to unknown */ |
5195 | 19.9k | sctp_info.assoc_index = -1; |
5196 | 19.9k | sctp_info.direction = ASSOC_NOT_FOUND; |
5197 | | |
5198 | 19.9k | sctp_info.sport = pinfo->srcport; |
5199 | 19.9k | sctp_info.dport = pinfo->destport; |
5200 | 19.9k | set_address(&sctp_info.ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data); |
5201 | 19.9k | set_address(&sctp_info.ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data); |
5202 | | |
5203 | 19.9k | p_add_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num, GUINT_TO_POINTER(pinfo->srcport)); |
5204 | 19.9k | p_add_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num, GUINT_TO_POINTER(pinfo->destport)); |
5205 | | |
5206 | 19.9k | TRY { |
5207 | 19.9k | dissect_sctp_packet(tvb, pinfo, tree, false); |
5208 | 19.9k | } |
5209 | | |
5210 | 19.9k | FINALLY { |
5211 | 19.9k | if (!pinfo->flags.in_error_pkt && sctp_info.number_of_tvbs > 0) |
5212 | | /* XXX: If a (only present in an expired Internet-Draft) |
5213 | | * PKTDROP chunk is present, that shouldn't stop us from |
5214 | | * tapping the information from the outer encapsulation, |
5215 | | * but we'd have to be careful about not updating sctp_info |
5216 | | * with information from the encapsulated packet. |
5217 | | */ |
5218 | 4.44k | tap_queue_packet(sctp_tap, pinfo, &sctp_info); |
5219 | 19.9k | } |
5220 | | |
5221 | 19.9k | ENDTRY; |
5222 | | |
5223 | 19.9k | return tvb_captured_length(tvb); |
5224 | 19.9k | } |
5225 | | |
5226 | | /* Register the protocol with Wireshark */ |
5227 | | void |
5228 | | proto_register_sctp(void) |
5229 | 16 | { |
5230 | | |
5231 | | /* Setup list of header fields */ |
5232 | 16 | static hf_register_info hf[] = { |
5233 | 16 | { &hf_source_port, { "Source port", "sctp.srcport", FT_UINT16, BASE_PT_SCTP, NULL, 0x0, NULL, HFILL } }, |
5234 | 16 | { &hf_destination_port, { "Destination port", "sctp.dstport", FT_UINT16, BASE_PT_SCTP, NULL, 0x0, NULL, HFILL } }, |
5235 | 16 | { &hf_port, { "Port", "sctp.port", FT_UINT16, BASE_PT_SCTP, NULL, 0x0, NULL, HFILL } }, |
5236 | 16 | { &hf_verification_tag, { "Verification tag", "sctp.verification_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5237 | 16 | { &hf_checksum, { "Checksum", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5238 | 16 | { &hf_checksum_adler, { "Checksum (Adler)", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5239 | 16 | { &hf_checksum_crc32c, { "Checksum (CRC32C)", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5240 | 16 | { &hf_checksum_status, { "Checksum Status", "sctp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL } }, |
5241 | 16 | { &hf_chunk, { "Chunk", "sctp.chunk", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5242 | 16 | { &hf_chunk_type, { "Chunk type", "sctp.chunk_type", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } }, |
5243 | 16 | { &hf_chunk_flags, { "Chunk flags", "sctp.chunk_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5244 | 16 | { &hf_chunk_bit_1, { "Bit", "sctp.chunk_bit_1", FT_BOOLEAN, 8, TFS(&sctp_chunk_bit_1_value), SCTP_CHUNK_BIT_1, NULL, HFILL } }, |
5245 | 16 | { &hf_chunk_bit_2, { "Bit", "sctp.chunk_bit_2", FT_BOOLEAN, 8, TFS(&sctp_chunk_bit_2_value), SCTP_CHUNK_BIT_2, NULL, HFILL } }, |
5246 | 16 | { &hf_chunk_length, { "Chunk length", "sctp.chunk_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5247 | 16 | { &hf_chunk_padding, { "Chunk padding", "sctp.chunk_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5248 | 16 | { &hf_chunk_value, { "Chunk value", "sctp.chunk_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5249 | 16 | { &hf_cookie, { "Cookie", "sctp.cookie", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5250 | 16 | { &hf_initiate_tag, { "Initiate tag", "sctp.initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5251 | 16 | { &hf_init_chunk_initiate_tag, { "Initiate tag", "sctp.init_initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5252 | 16 | { &hf_init_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.init_credit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5253 | 16 | { &hf_init_chunk_number_of_outbound_streams, { "Number of outbound streams", "sctp.init_nr_out_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5254 | 16 | { &hf_init_chunk_number_of_inbound_streams, { "Number of inbound streams", "sctp.init_nr_in_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5255 | 16 | { &hf_init_chunk_initial_tsn, { "Initial TSN", "sctp.init_initial_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5256 | 16 | { &hf_initack_chunk_initiate_tag, { "Initiate tag", "sctp.initack_initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5257 | 16 | { &hf_initack_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.initack_credit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5258 | 16 | { &hf_initack_chunk_number_of_outbound_streams, { "Number of outbound streams", "sctp.initack_nr_out_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5259 | 16 | { &hf_initack_chunk_number_of_inbound_streams, { "Number of inbound streams", "sctp.initack_nr_in_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5260 | 16 | { &hf_initack_chunk_initial_tsn, { "Initial TSN", "sctp.initack_initial_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5261 | 16 | { &hf_data_chunk_tsn, { "Transmission sequence number (relative)", "sctp.data_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5262 | 16 | { &hf_data_chunk_tsn_raw, { "Transmission sequence number (absolute)", "sctp.data_tsn_raw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5263 | 16 | { &hf_data_chunk_stream_id, { "Stream identifier", "sctp.data_sid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5264 | 16 | { &hf_data_chunk_stream_seq_number, { "Stream sequence number", "sctp.data_ssn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5265 | 16 | { &hf_data_chunk_payload_proto_id, { "Payload protocol identifier", "sctp.data_payload_proto_id", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &sctpppid_val_ext, 0x0, NULL, HFILL } }, |
5266 | 16 | { &hf_idata_chunk_reserved, { "Reserved", "sctp.data_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5267 | 16 | { &hf_idata_chunk_mid, { "Message identifier", "sctp.data_mid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5268 | 16 | { &hf_idata_chunk_fsn, { "Fragment sequence number", "sctp.data_fsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5269 | 16 | { &hf_data_chunk_e_bit, { "E-Bit", "sctp.data_e_bit", FT_BOOLEAN, 8, TFS(&sctp_data_chunk_e_bit_value), SCTP_DATA_CHUNK_E_BIT, NULL, HFILL } }, |
5270 | 16 | { &hf_data_chunk_b_bit, { "B-Bit", "sctp.data_b_bit", FT_BOOLEAN, 8, TFS(&sctp_data_chunk_b_bit_value), SCTP_DATA_CHUNK_B_BIT, NULL, HFILL } }, |
5271 | 16 | { &hf_data_chunk_u_bit, { "U-Bit", "sctp.data_u_bit", FT_BOOLEAN, 8, TFS(&sctp_data_chunk_u_bit_value), SCTP_DATA_CHUNK_U_BIT, NULL, HFILL } }, |
5272 | 16 | { &hf_data_chunk_i_bit, { "I-Bit", "sctp.data_i_bit", FT_BOOLEAN, 8, TFS(&sctp_data_chunk_i_bit_value), SCTP_DATA_CHUNK_I_BIT, NULL, HFILL } }, |
5273 | 16 | { &hf_sack_chunk_ns, { "Nonce sum", "sctp.sack_nonce_sum", FT_UINT8, BASE_DEC, NULL, SCTP_SACK_CHUNK_NS_BIT, NULL, HFILL } }, |
5274 | 16 | { &hf_sack_chunk_cumulative_tsn_ack, { "Cumulative TSN ACK (relative)", "sctp.sack_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5275 | 16 | { &hf_sack_chunk_cumulative_tsn_ack_raw, { "Cumulative TSN ACK (absolute)", "sctp.sack_cumulative_tsn_ack_raw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5276 | 16 | { &hf_sack_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.sack_a_rwnd", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5277 | 16 | { &hf_sack_chunk_number_of_gap_blocks, { "Number of gap acknowledgement blocks", "sctp.sack_number_of_gap_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5278 | 16 | { &hf_sack_chunk_number_of_dup_tsns, { "Number of duplicated TSNs", "sctp.sack_number_of_duplicated_tsns", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5279 | 16 | { &hf_sack_chunk_gap_block_start, { "Start", "sctp.sack_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5280 | 16 | { &hf_sack_chunk_gap_block_start_tsn, { "Start TSN", "sctp.sack_gap_block_start_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5281 | 16 | { &hf_sack_chunk_gap_block_end, { "End", "sctp.sack_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5282 | 16 | { &hf_sack_chunk_gap_block_end_tsn, { "End TSN", "sctp.sack_gap_block_end_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5283 | 16 | { &hf_sack_chunk_number_tsns_gap_acked, { "Number of TSNs in gap acknowledgement blocks", "sctp.sack_number_of_tsns_gap_acked", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5284 | 16 | { &hf_sack_chunk_duplicate_tsn, { "Duplicate TSN", "sctp.sack_duplicate_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5285 | 16 | { &hf_nr_sack_chunk_ns, { "Nonce sum", "sctp.nr_sack_nonce_sum", FT_UINT8, BASE_DEC, NULL, SCTP_NR_SACK_CHUNK_NS_BIT, NULL, HFILL } }, |
5286 | 16 | { &hf_nr_sack_chunk_cumulative_tsn_ack, { "Cumulative TSN ACK", "sctp.nr_sack_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5287 | 16 | { &hf_nr_sack_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.nr_sack_a_rwnd", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5288 | 16 | { &hf_nr_sack_chunk_number_of_gap_blocks, { "Number of gap acknowledgement blocks", "sctp.nr_sack_number_of_gap_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5289 | 16 | { &hf_nr_sack_chunk_number_of_nr_gap_blocks, { "Number of nr-gap acknowledgement blocks", "sctp.nr_sack_number_of_nr_gap_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5290 | 16 | { &hf_nr_sack_chunk_number_of_dup_tsns, { "Number of duplicated TSNs", "sctp.nr_sack_number_of_duplicated_tsns", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5291 | 16 | { &hf_nr_sack_chunk_reserved, { "Reserved", "sctp.nr_sack_reserved", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5292 | 16 | { &hf_nr_sack_chunk_gap_block_start, { "Start", "sctp.nr_sack_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5293 | 16 | { &hf_nr_sack_chunk_gap_block_start_tsn, { "Start TSN", "sctp.nr_sack_gap_block_start_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5294 | 16 | { &hf_nr_sack_chunk_gap_block_end, { "End", "sctp.nr_sack_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5295 | 16 | { &hf_nr_sack_chunk_gap_block_end_tsn, { "End TSN", "sctp.nr_sack_gap_block_end_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5296 | 16 | { &hf_nr_sack_chunk_number_tsns_gap_acked, { "Number of TSNs in gap acknowledgement blocks", "sctp.nr_sack_number_of_tsns_gap_acked", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5297 | 16 | { &hf_nr_sack_chunk_nr_gap_block_start, { "Start", "sctp.nr_sack_nr_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5298 | 16 | { &hf_nr_sack_chunk_nr_gap_block_start_tsn, { "Start TSN", "sctp.nr_sack_nr_gap_block_start_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5299 | 16 | { &hf_nr_sack_chunk_nr_gap_block_end, { "End", "sctp.nr_sack_nr_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5300 | 16 | { &hf_nr_sack_chunk_nr_gap_block_end_tsn, { "End TSN", "sctp.nr_sack_nr_gap_block_end_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5301 | 16 | { &hf_nr_sack_chunk_number_tsns_nr_gap_acked, { "Number of TSNs in nr-gap acknowledgement blocks","sctp.nr_sack_number_of_tsns_nr_gap_acked", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5302 | 16 | { &hf_nr_sack_chunk_duplicate_tsn, { "Duplicate TSN", "sctp.nr_sack_duplicate_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5303 | 16 | { &hf_shutdown_chunk_cumulative_tsn_ack, { "Cumulative TSN Ack", "sctp.shutdown_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5304 | 16 | { &hf_ecne_chunk_lowest_tsn, { "Lowest TSN", "sctp.ecne_lowest_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5305 | 16 | { &hf_cwr_chunk_lowest_tsn, { "Lowest TSN", "sctp.cwr_lowest_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5306 | 16 | { &hf_shutdown_complete_chunk_t_bit, { "T-Bit", "sctp.shutdown_complete_t_bit", FT_BOOLEAN, 8, TFS(&sctp_shutdown_complete_chunk_t_bit_value), SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT, NULL, HFILL } }, |
5307 | 16 | { &hf_abort_chunk_t_bit, { "T-Bit", "sctp.abort_t_bit", FT_BOOLEAN, 8, TFS(&sctp_shutdown_complete_chunk_t_bit_value), SCTP_ABORT_CHUNK_T_BIT, NULL, HFILL } }, |
5308 | 16 | { &hf_forward_tsn_chunk_tsn, { "New cumulative TSN", "sctp.forward_tsn_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5309 | 16 | { &hf_forward_tsn_chunk_sid, { "Stream identifier", "sctp.forward_tsn_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5310 | 16 | { &hf_forward_tsn_chunk_ssn, { "Stream sequence number", "sctp.forward_tsn_ssn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5311 | 16 | { &hf_i_forward_tsn_chunk_tsn, { "New cumulative TSN", "sctp.i_forward_tsn_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5312 | 16 | { &hf_i_forward_tsn_chunk_sid, { "Stream identifier", "sctp.i_forward_tsn_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5313 | 16 | { &hf_i_forward_tsn_chunk_flags, { "Flags", "sctp.i_forward_tsn_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5314 | 16 | { &hf_i_forward_tsn_chunk_res, { "Reserved", "sctp.i_forward_tsn_res", FT_UINT16, BASE_DEC, NULL, SCTP_I_FORWARD_TSN_CHUNK_RES_MASK, NULL, HFILL } }, |
5315 | 16 | { &hf_i_forward_tsn_chunk_u_bit, { "U-Bit", "sctp.i_forward_tsn_u_bit", FT_BOOLEAN, 16, TFS(&sctp_i_forward_tsn_chunk_u_bit_value), SCTP_I_FORWARD_TSN_CHUNK_U_BIT, NULL, HFILL } }, |
5316 | 16 | { &hf_i_forward_tsn_chunk_mid, { "Message identifier", "sctp.forward_tsn_mid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5317 | 16 | { &hf_parameter_type, { "Parameter type", "sctp.parameter_type", FT_UINT16, BASE_HEX, VALS(parameter_identifier_values), 0x0, NULL, HFILL } }, |
5318 | 16 | { &hf_parameter_length, { "Parameter length", "sctp.parameter_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5319 | 16 | { &hf_parameter_value, { "Parameter value", "sctp.parameter_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5320 | 16 | { &hf_parameter_padding, { "Parameter padding", "sctp.parameter_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5321 | 16 | { &hf_parameter_bit_1, { "Bit", "sctp.parameter_bit_1", FT_BOOLEAN, 16, TFS(&sctp_parameter_bit_1_value), SCTP_PARAMETER_BIT_1, NULL, HFILL } }, |
5322 | 16 | { &hf_parameter_bit_2, { "Bit", "sctp.parameter_bit_2", FT_BOOLEAN, 16, TFS(&sctp_parameter_bit_2_value), SCTP_PARAMETER_BIT_2, NULL, HFILL } }, |
5323 | 16 | { &hf_ipv4_address, { "IP Version 4 address", "sctp.parameter_ipv4_address", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5324 | 16 | { &hf_ipv6_address, { "IP Version 6 address", "sctp.parameter_ipv6_address", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5325 | 16 | { &hf_heartbeat_info, { "Heartbeat information", "sctp.parameter_heartbeat_information", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5326 | 16 | { &hf_state_cookie, { "State cookie", "sctp.parameter_state_cookie", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5327 | 16 | { &hf_cookie_preservative_increment, { "Suggested Cookie life-span increment (msec)", "sctp.parameter_cookie_preservative_incr", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5328 | 16 | { &hf_hostname, { "Hostname", "sctp.parameter_hostname", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5329 | 16 | { &hf_supported_address_type, { "Supported address type", "sctp.parameter_supported_address_type", FT_UINT16, BASE_DEC, VALS(address_types_values), 0x0, NULL, HFILL } }, |
5330 | 16 | { &hf_stream_reset_req_seq_nr, { "Re-configuration request sequence number", "sctp.parameter_reconfig_request_sequence_number", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5331 | 16 | { &hf_stream_reset_rsp_seq_nr, { "Re-configuration response sequence number", "sctp.parameter_reconfig_response_sequence_number", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5332 | 16 | { &hf_senders_last_assigned_tsn, { "Senders last assigned TSN", "sctp.parameter_senders_last_assigned_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5333 | 16 | { &hf_senders_next_tsn, { "Senders next TSN", "sctp.parameter_senders_next_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5334 | 16 | { &hf_receivers_next_tsn, { "Receivers next TSN", "sctp.parameter_receivers_next_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5335 | 16 | { &hf_stream_reset_rsp_result, { "Result", "sctp.parameter_reconfig_response_result", FT_UINT32, BASE_DEC, VALS(stream_reset_result_values), 0x0, NULL, HFILL } }, |
5336 | 16 | { &hf_stream_reset_sid, { "Stream Identifier", "sctp.parameter_reconfig_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5337 | 16 | { &hf_add_outgoing_streams_number_streams, { "Number of streams", "sctp.parameter_add_outgoing_streams_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5338 | 16 | { &hf_add_outgoing_streams_reserved, { "Reserved", "sctp.parameter_add_outgoing_streams_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5339 | 16 | { &hf_add_incoming_streams_number_streams, { "Number of streams", "sctp.parameter_add_incoming_streams_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5340 | 16 | { &hf_add_incoming_streams_reserved, { "Reserved", "sctp.parameter_add_incoming_streams_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5341 | 16 | { &hf_asconf_seq_nr, { "Sequence number", "sctp.asconf_seq_nr_number", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5342 | 16 | { &hf_asconf_ack_seq_nr, { "Sequence number", "sctp.asconf_ack_seq_nr_number", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5343 | 16 | { &hf_correlation_id, { "Correlation_id", "sctp.correlation_id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5344 | 16 | { &hf_adap_indication, { "Indication", "sctp.adaptation_layer_indication", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5345 | 16 | { &hf_zero_checksum_edmid, { "Error Detection Method Identifier", "sctp.edmid", FT_UINT32, BASE_DEC, VALS(edmid_values), 0x0, NULL, HFILL } }, |
5346 | 16 | { &hf_random_number, { "Random number", "sctp.random_number", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5347 | 16 | { &hf_chunks_to_auth, { "Chunk type", "sctp.chunk_type_to_auth", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } }, |
5348 | 16 | { &hf_hmac_id, { "HMAC identifier", "sctp.hmac_id", FT_UINT16, BASE_DEC, VALS(hmac_id_values), 0x0, NULL, HFILL } }, |
5349 | 16 | { &hf_hmac, { "HMAC", "sctp.hmac", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5350 | 16 | { &hf_dtls_km_tiebreaker, { "DTLS KM tiebreaker identifier", "sctp.dtls_km_tiebreaker", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5351 | 16 | { &hf_dtls_km_flags, { "DTLS KM flags", "sctp.dtls_km_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, |
5352 | 16 | { &hf_dtls_km_c_bit, { "C-Bit", "sctp.dtls_km_c_bit", FT_BOOLEAN, 8, TFS(&sctp_dtls_km_parameter_c_bit_value), DTLS_KM_PARAMETER_C_BIT, NULL, HFILL } }, |
5353 | 16 | { &hf_dtls_km_s_bit, { "S-Bit", "sctp.dtls_km_s_bit", FT_BOOLEAN, 8, TFS(&sctp_dtls_km_parameter_s_bit_value), DTLS_KM_PARAMETER_S_BIT, NULL, HFILL } }, |
5354 | 16 | { &hf_dtls_km_r_bit, { "R-Bit", "sctp.dtls_km_r_bit", FT_BOOLEAN, 8, TFS(&sctp_dtls_km_parameter_r_bit_value), DTLS_KM_PARAMETER_R_BIT, NULL, HFILL } }, |
5355 | 16 | { &hf_dtls_km_id, { "DTLS KM identifier", "sctp.dtls_km_id", FT_UINT8, BASE_DEC, VALS(dtls_km_id_values), 0x0, NULL, HFILL } }, |
5356 | 16 | { &hf_dtls_chunk_r_bit, { "R-Bit", "sctp.dtls_r_bit", FT_BOOLEAN, 8, TFS(&sctp_dtls_chunk_r_bit_value), SCTP_DTLS_CHUNK_R_BIT, NULL, HFILL } }, |
5357 | 16 | { &hf_shared_key_id, { "Shared key identifier", "sctp.shared_key_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5358 | 16 | { &hf_supported_chunk_type, { "Supported chunk type", "sctp.supported_chunk_type", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } }, |
5359 | 16 | { &hf_cause_code, { "Cause code", "sctp.cause_code", FT_UINT16, BASE_HEX, VALS(cause_code_values), 0x0, NULL, HFILL } }, |
5360 | 16 | { &hf_cause_length, { "Cause length", "sctp.cause_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5361 | 16 | { &hf_cause_info, { "Cause information", "sctp.cause_information", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5362 | 16 | { &hf_cause_padding, { "Cause padding", "sctp.cause_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5363 | 16 | { &hf_cause_stream_identifier, { "Stream identifier", "sctp.cause_stream_identifier", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5364 | 16 | { &hf_cause_reserved, { "Reserved", "sctp.cause_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5365 | 16 | { &hf_cause_number_of_missing_parameters, { "Number of missing parameters", "sctp.cause_nr_of_missing_parameters", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5366 | 16 | { &hf_cause_missing_parameter_type, { "Missing parameter type", "sctp.cause_missing_parameter_type", FT_UINT16, BASE_HEX, VALS(parameter_identifier_values), 0x0, NULL, HFILL } }, |
5367 | 16 | { &hf_cause_measure_of_staleness, { "Measure of staleness in usec", "sctp.cause_measure_of_staleness", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5368 | 16 | { &hf_cause_tsn, { "TSN", "sctp.cause_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5369 | 16 | { &hf_pktdrop_chunk_m_bit, { "M-Bit", "sctp.pckdrop_m_bit", FT_BOOLEAN, 8, TFS(&sctp_pktdropk_m_bit_value), SCTP_PKTDROP_CHUNK_M_BIT, NULL, HFILL } }, |
5370 | 16 | { &hf_pktdrop_chunk_b_bit, { "B-Bit", "sctp.pckdrop_b_bit", FT_BOOLEAN, 8, TFS(&sctp_pktdropk_b_bit_value), SCTP_PKTDROP_CHUNK_B_BIT, NULL, HFILL } }, |
5371 | 16 | { &hf_pktdrop_chunk_t_bit, { "T-Bit", "sctp.pckdrop_t_bit", FT_BOOLEAN, 8, TFS(&sctp_pktdropk_t_bit_value), SCTP_PKTDROP_CHUNK_T_BIT, NULL, HFILL } }, |
5372 | 16 | { &hf_pktdrop_chunk_bandwidth, { "Bandwidth", "sctp.pktdrop_bandwidth", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5373 | 16 | { &hf_pktdrop_chunk_queuesize, { "Queuesize", "sctp.pktdrop_queuesize", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5374 | 16 | { &hf_pktdrop_chunk_truncated_length, { "Truncated length", "sctp.pktdrop_truncated_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5375 | 16 | { &hf_pktdrop_chunk_reserved, { "Reserved", "sctp.pktdrop_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5376 | 16 | { &hf_pktdrop_chunk_data_field, { "Data field", "sctp.pktdrop_datafield", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5377 | 16 | { &hf_pad_chunk_padding_data, { "Padding data", "sctp.padding_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5378 | | |
5379 | 16 | { &hf_sctp_fragment, { "SCTP Fragment", "sctp.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5380 | 16 | { &hf_sctp_fragments, { "Reassembled SCTP Fragments", "sctp.fragments", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5381 | 16 | { &hf_sctp_reassembled_in, { "Reassembled Message in frame", "sctp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5382 | 16 | { &hf_sctp_duplicate, { "Fragment already seen in frame", "sctp.duplicate", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5383 | | |
5384 | 16 | { &hf_sctp_data_rtt, { "The RTT to SACK was", "sctp.data_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5385 | 16 | { &hf_sctp_sack_rtt, { "The RTT since DATA was", "sctp.sack_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5386 | 16 | { &hf_sctp_rto, { "Retransmitted after", "sctp.retransmission_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5387 | 16 | { &hf_sctp_retransmission, { "This TSN is a retransmission of one in frame", "sctp.retransmission", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5388 | 16 | { &hf_sctp_retransmitted, { "This TSN is retransmitted in frame", "sctp.retransmitted", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5389 | 16 | { &hf_sctp_retransmitted_count, { "TSN was retransmitted this many times", "sctp.retransmitted_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5390 | 16 | { &hf_sctp_acked, { "This chunk is acked in frame", "sctp.acked", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5391 | 16 | { &hf_sctp_ack_tsn, { "Acknowledges TSN", "sctp.ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, |
5392 | 16 | { &hf_sctp_ack_frame, { "Acknowledges TSN in frame", "sctp.ack_frame", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL } }, |
5393 | 16 | { &hf_sctp_retransmitted_after_ack, { "Chunk was acked prior to retransmission", "sctp.retransmitted_after_ack", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, |
5394 | 16 | { &hf_sctp_assoc_index, { "Association index", "sctp.assoc_index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } } |
5395 | | |
5396 | 16 | }; |
5397 | | |
5398 | | /* Setup protocol subtree array */ |
5399 | 16 | static int *ett[] = { |
5400 | 16 | &ett_sctp, |
5401 | 16 | &ett_sctp_chunk, |
5402 | 16 | &ett_sctp_chunk_parameter, |
5403 | 16 | &ett_sctp_chunk_cause, |
5404 | 16 | &ett_sctp_chunk_type, |
5405 | 16 | &ett_sctp_data_chunk_flags, |
5406 | 16 | &ett_sctp_sack_chunk_flags, |
5407 | 16 | &ett_sctp_nr_sack_chunk_flags, |
5408 | 16 | &ett_sctp_abort_chunk_flags, |
5409 | 16 | &ett_sctp_shutdown_complete_chunk_flags, |
5410 | 16 | &ett_sctp_pktdrop_chunk_flags, |
5411 | 16 | &ett_sctp_parameter_type, |
5412 | 16 | &ett_sctp_sack_chunk_gap_block, |
5413 | 16 | &ett_sctp_sack_chunk_gap_block_start, |
5414 | 16 | &ett_sctp_sack_chunk_gap_block_end, |
5415 | 16 | &ett_sctp_nr_sack_chunk_gap_block, |
5416 | 16 | &ett_sctp_nr_sack_chunk_gap_block_start, |
5417 | 16 | &ett_sctp_nr_sack_chunk_gap_block_end, |
5418 | 16 | &ett_sctp_nr_sack_chunk_nr_gap_block, |
5419 | 16 | &ett_sctp_nr_sack_chunk_nr_gap_block_start, |
5420 | 16 | &ett_sctp_nr_sack_chunk_nr_gap_block_end, |
5421 | 16 | &ett_sctp_unrecognized_parameter_parameter, |
5422 | 16 | &ett_sctp_i_forward_tsn_chunk_flags, |
5423 | 16 | &ett_sctp_dtls_chunk_flags, |
5424 | 16 | &ett_sctp_fragments, |
5425 | 16 | &ett_sctp_fragment, |
5426 | 16 | &ett_sctp_ack, |
5427 | 16 | &ett_sctp_acked, |
5428 | 16 | &ett_sctp_tsn, |
5429 | 16 | &ett_sctp_tsn_retransmission, |
5430 | 16 | &ett_sctp_tsn_retransmitted_count, |
5431 | 16 | &ett_sctp_tsn_retransmitted, |
5432 | 16 | &ett_sctp_dtls_km_flags |
5433 | 16 | }; |
5434 | | |
5435 | 16 | static ei_register_info ei[] = { |
5436 | 16 | { &ei_sctp_tsn_retransmitted, { "sctp.retransmission.expert", PI_SEQUENCE, PI_NOTE, "Retransmitted TSN", EXPFILL }}, |
5437 | 16 | { &ei_sctp_retransmitted_after_ack, { "sctp.retransmitted_after_ack.expert", PI_SEQUENCE, PI_WARN, "This TSN was acked prior to this retransmission (reneged ack?).", EXPFILL }}, |
5438 | 16 | { &ei_sctp_tsn_retransmitted_more_than_twice, { "sctp.retransmission.more_than_twice", PI_SEQUENCE, PI_WARN, "This TSN was retransmitted more than 2 times.", EXPFILL }}, |
5439 | 16 | { &ei_sctp_parameter_padding, { "sctp.parameter_padding.expert", PI_MALFORMED, PI_NOTE, "The padding of this final parameter should be the padding of the chunk.", EXPFILL }}, |
5440 | 16 | { &ei_sctp_parameter_length, { "sctp.parameter_length.bad", PI_MALFORMED, PI_ERROR, "Parameter length bad", EXPFILL }}, |
5441 | 16 | { &ei_sctp_sack_chunk_adv_rec_window_credit, { "sctp.sack_a_rwnd.expert", PI_SEQUENCE, PI_NOTE, "Zero Advertised Receiver Window Credit", EXPFILL }}, |
5442 | 16 | { &ei_sctp_sack_chunk_gap_block_malformed, { "sctp.sack_gap_block_malformed", PI_PROTOCOL, PI_ERROR, "Malformed gap block.", EXPFILL }}, |
5443 | 16 | { &ei_sctp_sack_chunk_gap_block_out_of_order, { "sctp.sack_gap_block_out_of_order", PI_PROTOCOL, PI_WARN, "Gap blocks not in strict order.", EXPFILL }}, |
5444 | 16 | { &ei_sctp_sack_chunk_number_tsns_gap_acked_100, { "sctp.sack_number_of_tsns_gap_acked.100", PI_SEQUENCE, PI_WARN, "More than 100 TSNs were gap-acknowledged in this SACK.", EXPFILL }}, |
5445 | 16 | { &ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100, { "sctp.nr_sack_number_of_tsns_gap_acked.100", PI_SEQUENCE, PI_WARN, "More than 100 TSNs were gap-acknowledged in this NR-SACK.", EXPFILL }}, |
5446 | 16 | { &ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100, { "sctp.nr_sack_number_of_tsns_nr_gap_acked.100", PI_SEQUENCE, PI_WARN, "More than 100 TSNs were nr-gap-acknowledged in this NR-SACK.", EXPFILL }}, |
5447 | 16 | { &ei_sctp_chunk_length_bad, { "sctp.chunk_length.bad", PI_MALFORMED, PI_ERROR, "Chunk length bad", EXPFILL }}, |
5448 | 16 | { &ei_sctp_bad_sctp_checksum, { "sctp.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad SCTP checksum.", EXPFILL }}, |
5449 | 16 | { &ei_sctp_illegal_parameter_occurrence, { "sctp.illegal_parameter_occurrence.expert", PI_PROTOCOL, PI_ERROR, "Illegal parameter occurrence.", EXPFILL }}, |
5450 | 16 | { &ei_sctp_dtls_km_illegal_number_of_ids, { "sctp.dtls_km_illegal_number_of_ids.expert", PI_PROTOCOL, PI_ERROR, "Illegal number of IDs.", EXPFILL }}, |
5451 | 16 | }; |
5452 | | |
5453 | 16 | static const enum_val_t sctp_checksum_options[] = { |
5454 | 16 | { "none", "None", SCTP_CHECKSUM_NONE }, |
5455 | 16 | { "adler-32", "Adler 32", SCTP_CHECKSUM_ADLER32 }, |
5456 | 16 | { "crc-32c", "CRC 32c", SCTP_CHECKSUM_CRC32C }, |
5457 | 16 | { "automatic", "Automatic", SCTP_CHECKSUM_AUTOMATIC}, |
5458 | 16 | { NULL, NULL, 0 } |
5459 | 16 | }; |
5460 | | |
5461 | | /* Decode As handling */ |
5462 | 16 | static build_valid_func sctp_da_src_values[1] = {sctp_src_value}; |
5463 | 16 | static build_valid_func sctp_da_dst_values[1] = {sctp_dst_value}; |
5464 | 16 | static build_valid_func sctp_da_both_values[2] = {sctp_src_value, sctp_dst_value}; |
5465 | 16 | static decode_as_value_t sctp_da_port_values[3] = {{sctp_src_prompt, 1, sctp_da_src_values}, {sctp_dst_prompt, 1, sctp_da_dst_values}, {sctp_both_prompt, 2, sctp_da_both_values}}; |
5466 | 16 | static decode_as_t sctp_da_port = {"sctp", "sctp.port", 3, 2, sctp_da_port_values, "SCTP", "port(s) as", |
5467 | 16 | decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL, NULL, NULL }; |
5468 | | |
5469 | 16 | static build_valid_func sctp_da_ppi_build_value1[1] = {sctp_ppi_value1}; |
5470 | 16 | static build_valid_func sctp_da_ppi_build_value2[1] = {sctp_ppi_value2}; |
5471 | 16 | static decode_as_value_t sctp_da_ppi_values[2] = {{sctp_ppi_prompt1, 1, sctp_da_ppi_build_value1}, {sctp_ppi_prompt2, 1, sctp_da_ppi_build_value2}}; |
5472 | 16 | static decode_as_t sctp_da_ppi = {"sctp", "sctp.ppi", 2, 0, sctp_da_ppi_values, "SCTP", NULL, |
5473 | 16 | decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL, NULL, NULL }; |
5474 | | |
5475 | | /* UAT for header fields */ |
5476 | 16 | static uat_field_t custom_types_uat_fields[] = { |
5477 | 16 | UAT_FLD_NONE(type_fields, type_id, "Chunk ID", "IANA chunk type ID"), |
5478 | 16 | UAT_FLD_CSTRING(type_fields, type_name, "Type name", "Chunk Type name"), |
5479 | 16 | UAT_FLD_VS(type_fields, type_enable, "Visibility", chunk_enabled, "Hide or show the type in the chunk statistics"), |
5480 | 16 | UAT_END_FIELDS |
5481 | 16 | }; |
5482 | | |
5483 | 16 | module_t *sctp_module; |
5484 | 16 | expert_module_t* expert_sctp; |
5485 | 16 | uat_t* chunk_types_uat; |
5486 | | |
5487 | 16 | chunk_types_uat = uat_new("Chunk types for the statistics dialog", |
5488 | 16 | sizeof(type_field_t), |
5489 | 16 | "statistics_chunk_types", |
5490 | 16 | true, |
5491 | 16 | &type_fields, |
5492 | 16 | &num_type_fields, |
5493 | 16 | 0, |
5494 | 16 | NULL, |
5495 | 16 | sctp_chunk_type_copy_cb, |
5496 | 16 | sctp_chunk_type_update_cb, |
5497 | 16 | sctp_chunk_type_free_cb, |
5498 | 16 | NULL, |
5499 | 16 | NULL, |
5500 | 16 | custom_types_uat_fields |
5501 | 16 | ); |
5502 | | |
5503 | | /* Register the protocol name and description */ |
5504 | 16 | proto_sctp = proto_register_protocol("Stream Control Transmission Protocol", "SCTP", "sctp"); |
5505 | 16 | sctp_module = prefs_register_protocol(proto_sctp, NULL); |
5506 | 16 | prefs_register_bool_preference(sctp_module, "show_port_numbers_in_tree", |
5507 | 16 | "Show port numbers in the protocol tree", |
5508 | 16 | "Show source and destination port numbers in the protocol tree", |
5509 | 16 | &show_port_numbers); |
5510 | 16 | prefs_register_bool_preference(sctp_module, "relative_tsns", "Relative TSNs", |
5511 | 16 | "Use relative TSNs instead of absolute ones", |
5512 | 16 | &show_relative_tsns); |
5513 | 16 | prefs_register_enum_preference(sctp_module, "checksum", "Checksum type", |
5514 | 16 | "The type of checksum used in SCTP packets", |
5515 | 16 | &sctp_checksum, sctp_checksum_options, false); |
5516 | 16 | prefs_register_bool_preference(sctp_module, "show_always_control_chunks", |
5517 | 16 | "Show always control chunks", |
5518 | 16 | "Show always SCTP control chunks in the Info column", |
5519 | 16 | &show_always_control_chunks); |
5520 | 16 | prefs_register_bool_preference(sctp_module, "try_heuristic_first", |
5521 | 16 | "Try heuristic sub-dissectors first", |
5522 | 16 | "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port or PPI", |
5523 | 16 | &try_heuristic_first); |
5524 | 16 | prefs_register_bool_preference(sctp_module, "reassembly", |
5525 | 16 | "Reassemble fragmented SCTP user messages", |
5526 | 16 | "Whether fragmented SCTP user messages should be reassembled", |
5527 | 16 | &use_reassembly); |
5528 | 16 | prefs_register_bool_preference(sctp_module, "tsn_analysis", |
5529 | 16 | "Enable TSN analysis", |
5530 | 16 | "Match TSNs and their SACKs", |
5531 | 16 | &enable_tsn_analysis); |
5532 | 16 | prefs_register_bool_preference(sctp_module, "association_index", |
5533 | 16 | "Enable Association indexing (Can be CPU intense)", |
5534 | 16 | "Match verification tags (CPU intense)", |
5535 | 16 | &enable_association_indexing); |
5536 | 16 | prefs_register_bool_preference(sctp_module, "ulp_dissection", |
5537 | 16 | "Dissect upper layer protocols", |
5538 | 16 | "Dissect upper layer protocols", |
5539 | 16 | &enable_ulp_dissection); |
5540 | 16 | prefs_register_uat_preference(sctp_module, "statistics_chunk_types", |
5541 | 16 | "Select the chunk types for the statistics dialog", |
5542 | 16 | "Select the chunk types for the statistics dialog", |
5543 | 16 | chunk_types_uat); |
5544 | | |
5545 | | /* Required function calls to register the header fields and subtrees used */ |
5546 | 16 | proto_register_field_array(proto_sctp, hf, array_length(hf)); |
5547 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
5548 | 16 | expert_sctp = expert_register_protocol(proto_sctp); |
5549 | 16 | expert_register_field_array(expert_sctp, ei, array_length(ei)); |
5550 | | |
5551 | 16 | sctp_tap = register_tap("sctp"); |
5552 | 16 | exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_3); |
5553 | | /* subdissector code */ |
5554 | 16 | sctp_port_dissector_table = register_dissector_table("sctp.port", "SCTP port", proto_sctp, FT_UINT16, BASE_DEC); |
5555 | 16 | sctp_ppi_dissector_table = register_dissector_table("sctp.ppi", "SCTP payload protocol identifier", proto_sctp, FT_UINT32, BASE_HEX); |
5556 | | |
5557 | 16 | sctp_handle = register_dissector("sctp", dissect_sctp, proto_sctp); |
5558 | 16 | sctp_heur_subdissector_list = register_heur_dissector_list_with_description("sctp", "SCTP payload", proto_sctp); |
5559 | | |
5560 | 16 | register_init_routine(sctp_init); |
5561 | 16 | register_cleanup_routine(sctp_cleanup); |
5562 | | |
5563 | 16 | dirs_by_ptvtag = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); |
5564 | 16 | dirs_by_ptaddr = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); |
5565 | | |
5566 | 16 | register_decode_as(&sctp_da_port); |
5567 | 16 | register_decode_as(&sctp_da_ppi); |
5568 | | |
5569 | 16 | register_conversation_table(proto_sctp, false, sctp_conversation_packet, sctp_endpoint_packet); |
5570 | | |
5571 | 16 | assoc_info_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), |
5572 | 16 | sctp_assoc_hash, sctp_assoc_equal); |
5573 | 16 | assoc_info_half_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), |
5574 | 16 | sctp_assoc_half_hash, sctp_assoc_half_equal); |
5575 | | |
5576 | 16 | register_external_value_string("chunk_type_values", chunk_type_values); |
5577 | 16 | } |
5578 | | |
5579 | | void |
5580 | | proto_reg_handoff_sctp(void) |
5581 | 16 | { |
5582 | 16 | capture_dissector_handle_t sctp_cap_handle; |
5583 | | |
5584 | 16 | dissector_add_uint("wtap_encap", WTAP_ENCAP_SCTP, sctp_handle); |
5585 | 16 | dissector_add_uint("ip.proto", IP_PROTO_SCTP, sctp_handle); |
5586 | 16 | dissector_add_uint_with_preference("udp.port", UDP_TUNNELING_PORT, sctp_handle); |
5587 | 16 | dissector_add_uint_with_preference("dtls.port", UDP_TUNNELING_PORT, sctp_handle); |
5588 | 16 | sctp_cap_handle = create_capture_dissector_handle(capture_sctp, proto_sctp); |
5589 | 16 | capture_dissector_add_uint("ip.proto", IP_PROTO_SCTP, sctp_cap_handle); |
5590 | 16 | } |
5591 | | |
5592 | | /* |
5593 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
5594 | | * |
5595 | | * Local variables: |
5596 | | * c-basic-offset: 2 |
5597 | | * tab-width: 8 |
5598 | | * indent-tabs-mode: nil |
5599 | | * End: |
5600 | | * |
5601 | | * vi: set shiftwidth=2 tabstop=8 expandtab: |
5602 | | * :indentSize=2:tabSize=8:noTabs=true: |
5603 | | */ |