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