Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-sctp.c
blobdbcb1579c4bdd31b8bf0ba8a0fb3272b3f1eb0f9
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>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 * It should be compliant to
14 * - RFC 2960
15 * - RFC 3309
16 * - RFC 3758
17 * - RFC 4460
18 * - RFC 4895
19 * - RFC 4960
20 * - RFC 5061
21 * - RFC 6525
22 * - RFC 7053
23 * - https://tools.ietf.org/html/draft-stewart-sctp-pktdrprep-02
24 * - https://www.ietf.org/archive/id/draft-ietf-tsvwg-sctp-zero-checksum-01.html
26 * Still to do (so stay tuned)
27 * - error checking mode
28 * * padding errors
29 * * length errors
30 * * bundling errors
31 * * value errors
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>
37 * PPID types updated by Thomas Dreibholz (Feb 2011)
40 #include "config.h"
42 #define WS_LOG_DOMAIN "sctp"
44 #include "ws_symbol_export.h"
46 #include <epan/packet.h>
47 #include <epan/capture_dissectors.h>
48 #include <epan/prefs.h>
49 #include <epan/exceptions.h>
50 #include <epan/exported_pdu.h>
51 #include <epan/ipproto.h>
52 #include <epan/addr_resolv.h>
53 #include <epan/sctpppids.h>
54 #include <epan/uat.h>
55 #include <epan/expert.h>
56 #include <epan/conversation_table.h>
57 #include <epan/show_exception.h>
58 #include <epan/decode_as.h>
59 #include <epan/proto_data.h>
60 #include <epan/tfs.h>
61 #include <wsutil/array.h>
63 #include <wsutil/crc32.h>
64 #include <wsutil/adler32.h>
65 #include <wsutil/utf8_entities.h>
66 #include <wsutil/str_util.h>
67 #include <wsutil/ws_roundup.h>
69 #include "packet-sctp.h"
71 #define LT(x, y) ((int32_t)((x) - (y)) < 0)
73 #define UDP_TUNNELING_PORT 9899
75 #define MAX_NUMBER_OF_PPIDS 2
76 /** This is a valid PPID, but we use it to mark the end of the list */
77 #define LAST_PPID 0xffffffff
79 void proto_register_sctp(void);
80 void proto_reg_handoff_sctp(void);
82 /* Initialize the protocol and registered fields */
83 static int proto_sctp;
84 static int hf_port;
85 static int hf_source_port;
86 static int hf_destination_port;
87 static int hf_verification_tag;
88 static int hf_checksum;
89 static int hf_checksum_adler;
90 static int hf_checksum_crc32c;
91 static int hf_checksum_status;
93 static int hf_chunk;
94 static int hf_chunk_type;
95 static int hf_chunk_flags;
96 static int hf_chunk_bit_1;
97 static int hf_chunk_bit_2;
98 static int hf_chunk_length;
99 static int hf_chunk_padding;
100 static int hf_chunk_value;
102 static int hf_initiate_tag;
103 static int hf_init_chunk_initiate_tag;
104 static int hf_init_chunk_adv_rec_window_credit;
105 static int hf_init_chunk_number_of_outbound_streams;
106 static int hf_init_chunk_number_of_inbound_streams;
107 static int hf_init_chunk_initial_tsn;
109 static int hf_initack_chunk_initiate_tag;
110 static int hf_initack_chunk_adv_rec_window_credit;
111 static int hf_initack_chunk_number_of_outbound_streams;
112 static int hf_initack_chunk_number_of_inbound_streams;
113 static int hf_initack_chunk_initial_tsn;
115 static int hf_data_chunk_tsn;
116 static int hf_data_chunk_tsn_raw;
117 static int hf_data_chunk_stream_id;
118 static int hf_data_chunk_stream_seq_number;
119 static int hf_data_chunk_payload_proto_id;
120 static int hf_idata_chunk_reserved;
121 static int hf_idata_chunk_mid;
122 static int hf_idata_chunk_fsn;
124 static int hf_data_chunk_e_bit;
125 static int hf_data_chunk_b_bit;
126 static int hf_data_chunk_u_bit;
127 static int hf_data_chunk_i_bit;
129 static int hf_sack_chunk_ns;
130 static int hf_sack_chunk_cumulative_tsn_ack;
131 static int hf_sack_chunk_cumulative_tsn_ack_raw;
132 static int hf_sack_chunk_adv_rec_window_credit;
133 static int hf_sack_chunk_number_of_gap_blocks;
134 static int hf_sack_chunk_number_of_dup_tsns;
135 static int hf_sack_chunk_gap_block_start;
136 static int hf_sack_chunk_gap_block_end;
137 static int hf_sack_chunk_gap_block_start_tsn;
138 static int hf_sack_chunk_gap_block_end_tsn;
139 static int hf_sack_chunk_number_tsns_gap_acked;
140 static int hf_sack_chunk_duplicate_tsn;
142 static int hf_nr_sack_chunk_ns;
143 static int hf_nr_sack_chunk_cumulative_tsn_ack;
144 static int hf_nr_sack_chunk_adv_rec_window_credit;
145 static int hf_nr_sack_chunk_number_of_gap_blocks;
146 static int hf_nr_sack_chunk_number_of_nr_gap_blocks;
147 static int hf_nr_sack_chunk_number_of_dup_tsns;
148 static int hf_nr_sack_chunk_reserved;
149 static int hf_nr_sack_chunk_gap_block_start;
150 static int hf_nr_sack_chunk_gap_block_end;
151 static int hf_nr_sack_chunk_gap_block_start_tsn;
152 static int hf_nr_sack_chunk_gap_block_end_tsn;
153 static int hf_nr_sack_chunk_number_tsns_gap_acked;
154 static int hf_nr_sack_chunk_nr_gap_block_start;
155 static int hf_nr_sack_chunk_nr_gap_block_end;
156 static int hf_nr_sack_chunk_nr_gap_block_start_tsn;
157 static int hf_nr_sack_chunk_nr_gap_block_end_tsn;
158 static int hf_nr_sack_chunk_number_tsns_nr_gap_acked;
159 static int hf_nr_sack_chunk_duplicate_tsn;
161 static int hf_shutdown_chunk_cumulative_tsn_ack;
162 static int hf_cookie;
163 static int hf_cwr_chunk_lowest_tsn;
165 static int hf_ecne_chunk_lowest_tsn;
166 static int hf_abort_chunk_t_bit;
167 static int hf_shutdown_complete_chunk_t_bit;
169 static int hf_parameter_type;
170 static int hf_parameter_length;
171 static int hf_parameter_value;
172 static int hf_parameter_padding;
173 static int hf_parameter_bit_1;
174 static int hf_parameter_bit_2;
175 static int hf_ipv4_address;
176 static int hf_ipv6_address;
177 static int hf_heartbeat_info;
178 static int hf_state_cookie;
179 static int hf_cookie_preservative_increment;
180 static int hf_hostname;
181 static int hf_supported_address_type;
182 static int hf_stream_reset_req_seq_nr;
183 static int hf_stream_reset_rsp_seq_nr;
184 static int hf_senders_last_assigned_tsn;
185 static int hf_senders_next_tsn;
186 static int hf_receivers_next_tsn;
187 static int hf_stream_reset_rsp_result;
188 static int hf_stream_reset_sid;
189 static int hf_add_outgoing_streams_number_streams;
190 static int hf_add_outgoing_streams_reserved;
191 static int hf_add_incoming_streams_number_streams;
192 static int hf_add_incoming_streams_reserved;
194 static int hf_zero_checksum_edmid;
196 static int hf_random_number;
197 static int hf_chunks_to_auth;
198 static int hf_hmac_id;
199 static int hf_hmac;
200 static int hf_shared_key_id;
201 static int hf_supported_chunk_type;
203 static int hf_cause_code;
204 static int hf_cause_length;
205 static int hf_cause_padding;
206 static int hf_cause_info;
208 static int hf_cause_stream_identifier;
209 static int hf_cause_reserved;
211 static int hf_cause_number_of_missing_parameters;
212 static int hf_cause_missing_parameter_type;
214 static int hf_cause_measure_of_staleness;
216 static int hf_cause_tsn;
218 static int hf_forward_tsn_chunk_tsn;
219 static int hf_forward_tsn_chunk_sid;
220 static int hf_forward_tsn_chunk_ssn;
222 static int hf_i_forward_tsn_chunk_tsn;
223 static int hf_i_forward_tsn_chunk_sid;
224 static int hf_i_forward_tsn_chunk_flags;
225 static int hf_i_forward_tsn_chunk_res;
226 static int hf_i_forward_tsn_chunk_u_bit;
227 static int hf_i_forward_tsn_chunk_mid;
229 static int hf_asconf_ack_seq_nr;
230 static int hf_asconf_seq_nr;
231 static int hf_correlation_id;
233 static int hf_adap_indication;
235 static int hf_pktdrop_chunk_m_bit;
236 static int hf_pktdrop_chunk_b_bit;
237 static int hf_pktdrop_chunk_t_bit;
238 static int hf_pktdrop_chunk_bandwidth;
239 static int hf_pktdrop_chunk_queuesize;
240 static int hf_pktdrop_chunk_truncated_length;
241 static int hf_pktdrop_chunk_reserved;
242 static int hf_pktdrop_chunk_data_field;
244 static int hf_pad_chunk_padding_data;
246 static int hf_sctp_reassembled_in;
247 static int hf_sctp_duplicate;
248 static int hf_sctp_fragments;
249 static int hf_sctp_fragment;
251 static int hf_sctp_retransmission;
252 static int hf_sctp_retransmitted;
253 static int hf_sctp_retransmitted_count;
254 static int hf_sctp_data_rtt;
255 static int hf_sctp_sack_rtt;
256 static int hf_sctp_rto;
257 static int hf_sctp_ack_tsn;
258 static int hf_sctp_ack_frame;
259 static int hf_sctp_acked;
260 static int hf_sctp_retransmitted_after_ack;
262 static int hf_sctp_assoc_index;
264 static dissector_table_t sctp_port_dissector_table;
265 static dissector_table_t sctp_ppi_dissector_table;
266 static heur_dissector_list_t sctp_heur_subdissector_list;
267 static int sctp_tap;
268 static int exported_pdu_tap;
270 /* Initialize the subtree pointers */
271 static int ett_sctp;
272 static int ett_sctp_chunk;
273 static int ett_sctp_chunk_parameter;
274 static int ett_sctp_chunk_cause;
275 static int ett_sctp_chunk_type;
276 static int ett_sctp_data_chunk_flags;
277 static int ett_sctp_sack_chunk_flags;
278 static int ett_sctp_nr_sack_chunk_flags;
279 static int ett_sctp_abort_chunk_flags;
280 static int ett_sctp_shutdown_complete_chunk_flags;
281 static int ett_sctp_pktdrop_chunk_flags;
282 static int ett_sctp_parameter_type;
283 static int ett_sctp_sack_chunk_gap_block;
284 static int ett_sctp_sack_chunk_gap_block_start;
285 static int ett_sctp_sack_chunk_gap_block_end;
286 static int ett_sctp_nr_sack_chunk_gap_block;
287 static int ett_sctp_nr_sack_chunk_gap_block_start;
288 static int ett_sctp_nr_sack_chunk_gap_block_end;
289 static int ett_sctp_nr_sack_chunk_nr_gap_block;
290 static int ett_sctp_nr_sack_chunk_nr_gap_block_start;
291 static int ett_sctp_nr_sack_chunk_nr_gap_block_end;
292 static int ett_sctp_unrecognized_parameter_parameter;
293 static int ett_sctp_i_forward_tsn_chunk_flags;
295 static int ett_sctp_fragments;
296 static int ett_sctp_fragment;
298 static int ett_sctp_tsn;
299 static int ett_sctp_ack;
300 static int ett_sctp_acked;
301 static int ett_sctp_tsn_retransmission;
302 static int ett_sctp_tsn_retransmitted_count;
303 static int ett_sctp_tsn_retransmitted;
305 static expert_field ei_sctp_sack_chunk_adv_rec_window_credit;
306 static expert_field ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100;
307 static expert_field ei_sctp_parameter_length;
308 static expert_field ei_sctp_bad_sctp_checksum;
309 static expert_field ei_sctp_tsn_retransmitted_more_than_twice;
310 static expert_field ei_sctp_parameter_padding;
311 static expert_field ei_sctp_retransmitted_after_ack;
312 static expert_field ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100;
313 static expert_field ei_sctp_sack_chunk_gap_block_out_of_order;
314 static expert_field ei_sctp_chunk_length_bad;
315 static expert_field ei_sctp_tsn_retransmitted;
316 static expert_field ei_sctp_sack_chunk_gap_block_malformed;
317 static expert_field ei_sctp_sack_chunk_number_tsns_gap_acked_100;
319 WS_DLL_PUBLIC_DEF const value_string chunk_type_values[] = {
320 { SCTP_DATA_CHUNK_ID, "DATA" },
321 { SCTP_INIT_CHUNK_ID, "INIT" },
322 { SCTP_INIT_ACK_CHUNK_ID, "INIT_ACK" },
323 { SCTP_SACK_CHUNK_ID, "SACK" },
324 { SCTP_HEARTBEAT_CHUNK_ID, "HEARTBEAT" },
325 { SCTP_HEARTBEAT_ACK_CHUNK_ID, "HEARTBEAT_ACK" },
326 { SCTP_ABORT_CHUNK_ID, "ABORT" },
327 { SCTP_SHUTDOWN_CHUNK_ID, "SHUTDOWN" },
328 { SCTP_SHUTDOWN_ACK_CHUNK_ID, "SHUTDOWN_ACK" },
329 { SCTP_ERROR_CHUNK_ID, "ERROR" },
330 { SCTP_COOKIE_ECHO_CHUNK_ID, "COOKIE_ECHO" },
331 { SCTP_COOKIE_ACK_CHUNK_ID, "COOKIE_ACK" },
332 { SCTP_ECNE_CHUNK_ID, "ECNE" },
333 { SCTP_CWR_CHUNK_ID, "CWR" },
334 { SCTP_SHUTDOWN_COMPLETE_CHUNK_ID, "SHUTDOWN_COMPLETE" },
335 { SCTP_AUTH_CHUNK_ID, "AUTH" },
336 { SCTP_NR_SACK_CHUNK_ID, "NR_SACK" },
337 { SCTP_I_DATA_CHUNK_ID, "I_DATA" },
338 { SCTP_ASCONF_ACK_CHUNK_ID, "ASCONF_ACK" },
339 { SCTP_PKTDROP_CHUNK_ID, "PKTDROP" },
340 { SCTP_RE_CONFIG_CHUNK_ID, "RE_CONFIG" },
341 { SCTP_PAD_CHUNK_ID, "PAD" },
342 { SCTP_FORWARD_TSN_CHUNK_ID, "FORWARD_TSN" },
343 { SCTP_ASCONF_CHUNK_ID, "ASCONF" },
344 { SCTP_I_FORWARD_TSN_CHUNK_ID, "I_FORWARD_TSN" },
345 { SCTP_IETF_EXT, "IETF_EXTENSION" },
346 { 0, NULL } };
349 #define CHUNK_TYPE_LENGTH 1
350 #define CHUNK_FLAGS_LENGTH 1
351 #define CHUNK_LENGTH_LENGTH 2
352 #define CHUNK_HEADER_LENGTH (CHUNK_TYPE_LENGTH + \
353 CHUNK_FLAGS_LENGTH + \
354 CHUNK_LENGTH_LENGTH)
355 #define CHUNK_HEADER_OFFSET 0
356 #define CHUNK_TYPE_OFFSET CHUNK_HEADER_OFFSET
357 #define CHUNK_FLAGS_OFFSET (CHUNK_TYPE_OFFSET + CHUNK_TYPE_LENGTH)
358 #define CHUNK_LENGTH_OFFSET (CHUNK_FLAGS_OFFSET + CHUNK_FLAGS_LENGTH)
359 #define CHUNK_VALUE_OFFSET (CHUNK_LENGTH_OFFSET + CHUNK_LENGTH_LENGTH)
361 #define PARAMETER_TYPE_LENGTH 2
362 #define PARAMETER_LENGTH_LENGTH 2
363 #define PARAMETER_HEADER_LENGTH (PARAMETER_TYPE_LENGTH + PARAMETER_LENGTH_LENGTH)
365 #define PARAMETER_HEADER_OFFSET 0
366 #define PARAMETER_TYPE_OFFSET PARAMETER_HEADER_OFFSET
367 #define PARAMETER_LENGTH_OFFSET (PARAMETER_TYPE_OFFSET + PARAMETER_TYPE_LENGTH)
368 #define PARAMETER_VALUE_OFFSET (PARAMETER_LENGTH_OFFSET + PARAMETER_LENGTH_LENGTH)
370 #define SOURCE_PORT_LENGTH 2
371 #define DESTINATION_PORT_LENGTH 2
372 #define VERIFICATION_TAG_LENGTH 4
373 #define CHECKSUM_LENGTH 4
374 #define COMMON_HEADER_LENGTH (SOURCE_PORT_LENGTH + \
375 DESTINATION_PORT_LENGTH + \
376 VERIFICATION_TAG_LENGTH + \
377 CHECKSUM_LENGTH)
378 #define SOURCE_PORT_OFFSET 0
379 #define DESTINATION_PORT_OFFSET (SOURCE_PORT_OFFSET + SOURCE_PORT_LENGTH)
380 #define VERIFICATION_TAG_OFFSET (DESTINATION_PORT_OFFSET + DESTINATION_PORT_LENGTH)
381 #define CHECKSUM_OFFSET (VERIFICATION_TAG_OFFSET + VERIFICATION_TAG_LENGTH)
383 #define SCTP_CHECKSUM_NONE 0
384 #define SCTP_CHECKSUM_ADLER32 1
385 #define SCTP_CHECKSUM_CRC32C 2
386 #define SCTP_CHECKSUM_AUTOMATIC 3
388 #define FORWARD_STREAM 0
389 #define BACKWARD_STREAM 1
390 #define FORWARD_ADD_FORWARD_VTAG 2
391 #define BACKWARD_ADD_FORWARD_VTAG 3
392 #define BACKWARD_ADD_BACKWARD_VTAG 4
393 #define ASSOC_NOT_FOUND 5
395 /* Default values for preferences */
396 static bool show_port_numbers = true;
397 static int sctp_checksum = SCTP_CHECKSUM_NONE;
398 static bool enable_tsn_analysis = true;
399 static bool enable_association_indexing;
400 static bool enable_ulp_dissection = true;
401 static bool use_reassembly = true;
402 static bool show_always_control_chunks = true;
403 static bool show_relative_tsns = true;
405 /* Data types and functions for generation/handling of chunk types for chunk statistics */
407 static const value_string chunk_enabled[] = {
408 {0,"Show"},
409 {1,"Hide"},
410 {0, NULL}
412 typedef struct _type_field_t {
413 unsigned type_id;
414 char* type_name;
415 unsigned type_enable;
416 } type_field_t;
418 static type_field_t* type_fields;
419 static unsigned num_type_fields;
421 typedef struct _assoc_info_t {
422 uint16_t assoc_index;
423 uint16_t direction;
424 address saddr;
425 address daddr;
426 uint16_t sport;
427 uint16_t dport;
428 uint32_t verification_tag1;
429 uint32_t verification_tag2;
430 } assoc_info_t;
432 typedef struct _infodata_t {
433 uint16_t assoc_index;
434 uint16_t direction;
435 } infodata_t;
437 static wmem_map_t *assoc_info_half_map;
438 static wmem_map_t *assoc_info_map;
439 static unsigned num_assocs;
441 UAT_CSTRING_CB_DEF(type_fields, type_name, type_field_t)
442 UAT_VS_DEF(type_fields, type_enable, type_field_t, unsigned, 0, "Show")
443 UAT_DEC_CB_DEF(type_fields, type_id, type_field_t)
445 static void *sctp_chunk_type_copy_cb(void* n, const void* o, size_t siz _U_)
447 type_field_t* new_rec = (type_field_t*)n;
448 const type_field_t* old_rec = (const type_field_t*)o;
449 new_rec->type_name = g_strdup(old_rec->type_name);
451 return new_rec;
454 static void
455 sctp_chunk_type_free_cb(void* r)
457 type_field_t* rec = (type_field_t*)r;
458 g_free(rec->type_name);
461 static bool
462 sctp_chunk_type_update_cb(void *r, char **err)
464 type_field_t *rec = (type_field_t *)r;
465 char c;
466 if (rec->type_name == NULL) {
467 *err = g_strdup("Header name can't be empty");
468 return false;
471 g_strstrip(rec->type_name);
472 if (rec->type_name[0] == 0) {
473 *err = g_strdup("Header name can't be empty");
474 return false;
477 /* Check for invalid characters (to avoid asserting out when
478 * registering the field).
480 c = proto_check_field_name(rec->type_name);
481 if (c) {
482 *err = ws_strdup_printf("Header name can't contain '%c'", c);
483 return false;
486 *err = NULL;
487 return true;
490 static dissector_handle_t sctp_handle;
492 static struct _sctp_info sctp_info;
494 static bool
495 sctp_vtag_match(uint32_t vtag1, uint32_t vtag2)
497 /* If zero (unknown) tags match anything. Nonzero tags must be the same. */
498 if (vtag1 != 0) {
499 return (vtag1 == vtag2 || vtag2 == 0);
501 return true;
504 static assoc_info_t*
505 sctp_assoc_reverse(wmem_allocator_t *scope, const assoc_info_t *assoc)
507 assoc_info_t *new_assoc;
509 new_assoc = wmem_new(scope, assoc_info_t);
510 new_assoc->assoc_index = assoc->assoc_index;
511 new_assoc->direction = (assoc->direction == 1) ? 2 : 1;
512 copy_address_shallow(&new_assoc->saddr, &assoc->daddr);
513 copy_address_shallow(&new_assoc->daddr, &assoc->saddr);
514 new_assoc->sport = assoc->dport;
515 new_assoc->dport = assoc->sport;
516 new_assoc->verification_tag1 = assoc->verification_tag2;
517 new_assoc->verification_tag2 = assoc->verification_tag1;
519 return new_assoc;
522 static unsigned
523 sctp_assoc_half_hash(const void *key)
525 const assoc_info_t *k = (const assoc_info_t *)key;
527 /* Add the ports so that the hash is the same regardless of direction */
528 return g_direct_hash(GUINT_TO_POINTER(k->sport + k->dport));
531 static unsigned
532 sctp_assoc_hash(const void *key)
534 const assoc_info_t *k = (const assoc_info_t *)key;
536 // When inserting in this map, we know we have both vtags.
537 // Hash via the first one (we expect vtag collisions will be low.)
538 // When looking up with a entry from a packet that only has one vtag,
539 // we'll reverse the temporary key as necessary.
540 return g_int_hash(&k->verification_tag1);
543 /* Association comparison strategy:
544 * 1. Ports MUST match.
545 * 2. Assume vtag collisions are rare compared to multihoming. Thus:
546 * 3. If we have already discovered the vtags on both sides (e.g., with an
547 * INIT ACK, which contains both sides) and the ports match, don't require
548 * address matches.
549 * 4. If we have two keys each with 1 matching vtag in the same direction (and
550 * the other vtag 0), don't require address matches; if there are new addresses
551 * assume it's multihoming.
552 * 5. However, if we have two keys each with 1 vtag (and the other tag 0)
553 * that are different but could be the two vtags of one association
554 * (e.g., two unmatched DATA chunks in the opposite direction, or an INIT
555 * and a DATA in the same direction) require address matching. Otherwise
556 * we'll make likely spurious matches.
557 * 6. Don't worry about odd possibilities like both sides of an association
558 * chosing the same vtag.
559 * 7. We ought to track additional addresses given in INIT, INIT ACK, ASCONF.
560 * If we do, we could have an option of more strict association matching
561 * that uses the addresses in all cases and is more similar to what SCTP
562 * stacks actually do. We'd have to store a list/map/set of known source
563 * and destinatiion addresses instead of just one each. This would fail in
564 * the case of multihoming and where we missed the configuration messages
565 * setting up multihoming.
568 static gboolean
569 sctp_assoc_half_equal(const void *key1, const void *key2)
571 const assoc_info_t *a = (const assoc_info_t *)key1;
572 const assoc_info_t *b = (const assoc_info_t *)key2;
574 /* Matching for associations where for the entries already in the table
575 * only have one vtag, and have zero for the other direction. (For an
576 * new INIT ACK, we know both directions.)
579 if (a->sport == b->sport && a->dport == b->dport) {
580 // Forward match
581 if ((a->verification_tag1 == 0 || b->verification_tag1 == 0) &&
582 (a->verification_tag2 == 0 || b->verification_tag2 == 0)) {
583 // Possible INIT and DATA in the same direction, where we didn't get
584 // the INIT ACK. Call it a match if the addresses match.
585 if (addresses_equal(&a->saddr, &b->saddr) && addresses_equal(&a->daddr, &b->daddr)) {
586 return TRUE;
588 } else if (sctp_vtag_match(a->verification_tag1, b->verification_tag1) &&
589 sctp_vtag_match(a->verification_tag2, b->verification_tag2)) {
590 return TRUE;
593 if (a->sport == b->dport && a->dport == b->sport) {
594 // Reverse direction (not an else so we can handle identical ports)
595 if ((a->verification_tag1 == 0 || b->verification_tag2 == 0) &&
596 (a->verification_tag2 == 0 || b->verification_tag1 == 0)) {
597 // Possible two DATAs chunks in the opposite direction, where we
598 // didn't get the INIT ACK. Call it a match if the addresses match.
599 if (addresses_equal(&a->saddr, &b->daddr) && addresses_equal(&a->daddr, &b->saddr)) {
600 return TRUE;
602 } else if (sctp_vtag_match(a->verification_tag1, b->verification_tag2) &&
603 sctp_vtag_match(a->verification_tag2, b->verification_tag1)) {
604 return TRUE;
608 return FALSE;
611 static gboolean
612 sctp_assoc_equal(const void *key1, const void *key2)
614 const assoc_info_t *a = (const assoc_info_t *)key1;
615 const assoc_info_t *b = (const assoc_info_t *)key2;
618 * Matching for associations where for the entries already in the map
619 * we know the vtags in each direction.
620 * We will not check addresses.
623 if (a->sport == b->sport && a->dport == b->dport) {
624 // Forward match
625 // ASSERTION: at least one of the verification tags must be nonzero.
626 if (sctp_vtag_match(a->verification_tag1, b->verification_tag1) &&
627 sctp_vtag_match(a->verification_tag2, b->verification_tag2)) {
628 return TRUE;
631 if (a->sport == b->dport && a->dport == b->sport) {
632 // Reverse direction (not an else so we can handle identical ports)
633 if (sctp_vtag_match(a->verification_tag1, b->verification_tag2) &&
634 sctp_vtag_match(a->verification_tag2, b->verification_tag1)) {
635 return TRUE;
639 return FALSE;
642 static infodata_t
643 find_assoc_index(assoc_info_t* tmpinfo, packet_info *pinfo)
645 assoc_info_t *info = NULL;
646 infodata_t inf;
647 inf.assoc_index = -1;
648 inf.direction = 1;
650 /* At least one of tmpinfo's vtag1 must be nonzero (both might be, if
651 * it's an INIT ACK.) Lookup in the proper direction(s).
653 if (tmpinfo->verification_tag1 != 0) {
654 info = (assoc_info_t*)wmem_map_lookup(assoc_info_map, tmpinfo);
655 if (info) {
656 inf.assoc_index = info->assoc_index;
657 inf.direction = info->direction;
658 return inf;
662 if (tmpinfo->verification_tag2 != 0) {
663 info = sctp_assoc_reverse(pinfo->pool, tmpinfo);
664 info = (assoc_info_t*)wmem_map_lookup(assoc_info_map, info);
665 if (info) {
666 inf.assoc_index = info->assoc_index;
667 inf.direction = info->direction == 1 ? 2 : 1;
668 return inf;
672 info = (assoc_info_t*)wmem_map_lookup(assoc_info_half_map, tmpinfo);
673 if (info == NULL) {
674 if (!PINFO_FD_VISITED(pinfo)) {
675 info = wmem_new(wmem_file_scope(), assoc_info_t);
676 *info = *tmpinfo;
677 copy_address_wmem(wmem_file_scope(), &info->saddr, &tmpinfo->saddr);
678 copy_address_wmem(wmem_file_scope(), &info->daddr, &tmpinfo->daddr);
679 info->assoc_index = num_assocs++;
680 info->direction = 1;
681 inf.assoc_index = info->assoc_index;
682 if (info->verification_tag1 == 0 || info->verification_tag2 == 0) {
683 wmem_map_insert(assoc_info_half_map, info, info);
684 } else {
685 info->direction = 1;
686 wmem_map_insert(assoc_info_map, info, info);
687 info = sctp_assoc_reverse(wmem_file_scope(), info);
688 wmem_map_insert(assoc_info_map, info, info);
690 } else {
691 ws_info("association not found on second pass");
693 } else {
694 inf.assoc_index = info->assoc_index;
695 /* Now figure out why we matched and fill in new information. */
696 if (info->sport == tmpinfo->dport &&
697 sctp_vtag_match(info->verification_tag1, tmpinfo->verification_tag1) &&
698 sctp_vtag_match(info->verification_tag2, tmpinfo->verification_tag2)) {
699 /* We already checked the addresses if needed when looking up in the map. */
700 if (info->verification_tag1 == 0) {
701 info->verification_tag1 = tmpinfo->verification_tag1;
703 if (info->verification_tag2 == 0) {
704 info->verification_tag2 = tmpinfo->verification_tag2;
706 } else if (sctp_vtag_match(info->verification_tag1, tmpinfo->verification_tag2) &&
707 sctp_vtag_match(info->verification_tag2, tmpinfo->verification_tag1)) {
708 /* We already checked the addresses if needed when looking up in the map. */
709 inf.direction = 2;
710 if (info->verification_tag1 == 0) {
711 info->verification_tag1 = tmpinfo->verification_tag2;
713 if (info->verification_tag2 == 0) {
714 info->verification_tag2 = tmpinfo->verification_tag1;
717 if (info->verification_tag1 != 0 && info->verification_tag2 != 0) {
718 DISSECTOR_ASSERT(wmem_map_remove(assoc_info_half_map, info) != NULL);
719 wmem_map_insert(assoc_info_map, info, info);
720 info = sctp_assoc_reverse(wmem_file_scope(), info);
721 wmem_map_insert(assoc_info_map, info, info);
725 return inf;
728 static void
729 sctp_src_prompt(packet_info *pinfo, char *result)
731 uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num));
733 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "source (%s%u)", UTF8_RIGHTWARDS_ARROW, port);
736 static void *
737 sctp_src_value(packet_info *pinfo)
739 return p_get_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num);
742 static void
743 sctp_dst_prompt(packet_info *pinfo, char *result)
745 uint32_t port = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num));
747 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "destination (%s%u)", UTF8_RIGHTWARDS_ARROW, port);
750 static void *
751 sctp_dst_value(packet_info *pinfo)
753 return p_get_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num);
756 static void
757 sctp_both_prompt(packet_info *pinfo, char *result)
759 uint32_t srcport = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num)),
760 destport = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num));
762 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "both (%u%s%u)", srcport, UTF8_LEFT_RIGHT_ARROW, destport);
765 static void
766 sctp_ppi_prompt1(packet_info *pinfo _U_, char* result)
768 uint32_t ppid = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 0));
770 if (ppid == LAST_PPID) {
771 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (none)");
772 } else {
773 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (%d)", ppid);
777 static void
778 sctp_ppi_prompt2(packet_info *pinfo _U_, char* result)
780 uint32_t ppid = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 1));
782 if (ppid == LAST_PPID) {
783 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (none)");
784 } else {
785 snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "PPID (%d)", ppid);
789 static void *
790 sctp_ppi_value1(packet_info *pinfo)
792 return p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 0);
795 static void *
796 sctp_ppi_value2(packet_info *pinfo)
798 return p_get_proto_data(pinfo->pool, pinfo, proto_sctp, 1);
801 static const char* sctp_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
803 if (filter == CONV_FT_SRC_PORT)
804 return "sctp.srcport";
806 if (filter == CONV_FT_DST_PORT)
807 return "sctp.dstport";
809 if (filter == CONV_FT_ANY_PORT)
810 return "sctp.port";
812 if(!conv) {
813 return CONV_FILTER_INVALID;
816 if (filter == CONV_FT_SRC_ADDRESS) {
817 if (conv->src_address.type == AT_IPv4)
818 return "ip.src";
819 if (conv->src_address.type == AT_IPv6)
820 return "ipv6.src";
823 if (filter == CONV_FT_DST_ADDRESS) {
824 if (conv->dst_address.type == AT_IPv4)
825 return "ip.dst";
826 if (conv->dst_address.type == AT_IPv6)
827 return "ipv6.dst";
830 if (filter == CONV_FT_ANY_ADDRESS) {
831 if (conv->src_address.type == AT_IPv4)
832 return "ip.addr";
833 if (conv->src_address.type == AT_IPv6)
834 return "ipv6.addr";
837 return CONV_FILTER_INVALID;
840 static ct_dissector_info_t sctp_ct_dissector_info = {&sctp_conv_get_filter_type};
842 static tap_packet_status
843 sctp_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags)
845 conv_hash_t *hash = (conv_hash_t*) pct;
846 hash->flags = flags;
848 const struct _sctp_info *sctphdr=(const struct _sctp_info *)vip;
850 add_conversation_table_data(hash, &sctphdr->ip_src, &sctphdr->ip_dst,
851 sctphdr->sport, sctphdr->dport, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &sctp_ct_dissector_info, CONVERSATION_SCTP);
854 return TAP_PACKET_REDRAW;
857 static const char* sctp_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter)
859 if (filter == CONV_FT_SRC_PORT)
860 return "sctp.srcport";
862 if (filter == CONV_FT_DST_PORT)
863 return "sctp.dstport";
865 if (filter == CONV_FT_ANY_PORT)
866 return "sctp.port";
868 if(!endpoint) {
869 return CONV_FILTER_INVALID;
872 if (filter == CONV_FT_SRC_ADDRESS) {
873 if (endpoint->myaddress.type == AT_IPv4)
874 return "ip.src";
875 if (endpoint->myaddress.type == AT_IPv6)
876 return "ipv6.src";
879 if (filter == CONV_FT_DST_ADDRESS) {
880 if (endpoint->myaddress.type == AT_IPv4)
881 return "ip.dst";
882 if (endpoint->myaddress.type == AT_IPv6)
883 return "ipv6.dst";
886 if (filter == CONV_FT_ANY_ADDRESS) {
887 if (endpoint->myaddress.type == AT_IPv4)
888 return "ip.addr";
889 if (endpoint->myaddress.type == AT_IPv6)
890 return "ipv6.addr";
893 return CONV_FILTER_INVALID;
896 static et_dissector_info_t sctp_endpoint_dissector_info = {&sctp_endpoint_get_filter_type};
898 static tap_packet_status
899 sctp_endpoint_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags)
901 conv_hash_t *hash = (conv_hash_t*) pit;
902 hash->flags = flags;
904 const struct _sctp_info *sctphdr=(const struct _sctp_info *)vip;
906 /* Take two "add" passes per packet, adding for each direction, ensures that all
907 packets are counted properly (even if address is sending to itself)
908 XXX - this could probably be done more efficiently inside endpoint_table */
909 add_endpoint_table_data(hash, &sctphdr->ip_src, sctphdr->sport, true, 1, pinfo->fd->pkt_len, &sctp_endpoint_dissector_info, ENDPOINT_SCTP);
910 add_endpoint_table_data(hash, &sctphdr->ip_dst, sctphdr->dport, false, 1, pinfo->fd->pkt_len, &sctp_endpoint_dissector_info, ENDPOINT_SCTP);
912 return TAP_PACKET_REDRAW;
915 static unsigned int
916 sctp_adler32(tvbuff_t *tvb, unsigned int len)
918 const uint8_t *buf = tvb_get_ptr(tvb, 0, len);
919 uint32_t result = 1;
921 result = update_adler32(result, buf, SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH);
922 /* handle four 0 bytes as checksum */
923 result = update_adler32(result, "\0\0\0\0", 4);
924 result = update_adler32(result, buf+COMMON_HEADER_LENGTH, len-COMMON_HEADER_LENGTH);
926 return result;
929 static uint32_t
930 sctp_crc32c(tvbuff_t *tvb, unsigned int len)
932 const uint8_t *buf = tvb_get_ptr(tvb, 0, len);
933 uint32_t crc32,
934 zero = 0;
935 uint32_t result;
937 /* CRC for header */
938 crc32 = crc32c_calculate_no_swap(buf, SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH, CRC32C_PRELOAD);
940 /* handle four 0 bytes as checksum */
941 crc32 = crc32c_calculate_no_swap(&zero, 4, crc32);
943 /* CRC for the rest of the packet */
944 crc32 = crc32c_calculate_no_swap(&buf[COMMON_HEADER_LENGTH], len-COMMON_HEADER_LENGTH, crc32);
946 result = CRC32C_SWAP(crc32);
948 return ( ~result );
952 * Routines for dissecting parameters
955 typedef struct _sctp_half_assoc_t sctp_half_assoc_t;
957 static void dissect_parameter(tvbuff_t *, packet_info *, proto_tree *, proto_item *, bool, bool);
959 static void dissect_parameters(tvbuff_t *, packet_info *, proto_tree *, proto_item *, bool);
961 static void dissect_error_cause(tvbuff_t *, packet_info *, proto_tree *);
963 static void dissect_error_causes(tvbuff_t *, packet_info *, proto_tree *);
965 static bool dissect_data_chunk(tvbuff_t*, uint16_t, packet_info*, proto_tree*, proto_tree*, proto_item*, proto_item*, sctp_half_assoc_t*, bool);
967 static void dissect_sctp_packet(tvbuff_t *, packet_info *, proto_tree *, bool);
970 /* TSN ANALYSIS CODE */
972 struct _sctp_half_assoc_t {
973 uint32_t spt;
974 uint32_t dpt;
975 uint32_t vtag;
977 bool started;
979 uint32_t first_tsn; /* start */
980 uint32_t cumm_ack; /* rel */
981 wmem_tree_t *tsns; /* sctp_tsn_t* by rel_tsn */
982 wmem_tree_t *tsn_acks; /* sctp_tsn_t* by ctsn_frame */
984 struct _sctp_half_assoc_t *peer;
988 typedef struct _retransmit_t {
989 uint32_t framenum;
990 nstime_t ts;
991 struct _retransmit_t *next;
992 } retransmit_t;
994 typedef struct _sctp_tsn_t {
995 uint32_t tsn;
996 struct {
997 uint32_t framenum;
998 nstime_t ts;
999 } first_transmit;
1000 struct {
1001 uint32_t framenum;
1002 nstime_t ts;
1003 } ack;
1004 retransmit_t *retransmit;
1005 uint32_t retransmit_count;
1006 struct _sctp_tsn_t *next;
1007 } sctp_tsn_t;
1010 static wmem_tree_key_t*
1011 make_address_key(wmem_allocator_t *pool, uint32_t spt, uint32_t dpt, address *addr)
1013 wmem_tree_key_t *k = (wmem_tree_key_t *)wmem_alloc(pool, sizeof(wmem_tree_key_t)*6);
1015 k[0].length = 1; k[0].key = (uint32_t*)wmem_memdup(pool, &spt,sizeof(spt));
1016 k[1].length = 1; k[1].key = (uint32_t*)wmem_memdup(pool, &dpt,sizeof(dpt));
1017 k[2].length = 1; k[2].key = (uint32_t*)(void *)&(addr->type);
1018 k[3].length = 1; k[3].key = (uint32_t*)(void *)&(addr->len);
1020 k[4].length = ((addr->len/4)+1);
1021 k[4].key = (uint32_t*)wmem_alloc0(pool, ((addr->len/4)+1)*4);
1022 if (addr->len) memcpy(k[4].key, addr->data, addr->len);
1024 k[5].length = 0; k[5].key = NULL;
1026 return k;
1029 static wmem_tree_key_t *
1030 make_dir_key(wmem_allocator_t *pool, uint32_t spt, uint32_t dpt, uint32_t vtag)
1032 wmem_tree_key_t *k = (wmem_tree_key_t *)wmem_alloc(pool, sizeof(wmem_tree_key_t)*4);
1034 k[0].length = 1; k[0].key = (uint32_t*)wmem_memdup(pool, &spt,sizeof(spt));
1035 k[1].length = 1; k[1].key = (uint32_t*)wmem_memdup(pool, &dpt,sizeof(dpt));
1036 k[2].length = 1; k[2].key = (uint32_t*)wmem_memdup(pool, &vtag,sizeof(vtag));
1037 k[3].length = 0; k[3].key = NULL;
1039 return k;
1044 static wmem_tree_t *dirs_by_ptvtag; /* sctp_half_assoc_t* */
1045 static wmem_tree_t *dirs_by_ptaddr; /* sctp_half_assoc_t**, it may contain a null pointer */
1047 static sctp_half_assoc_t *
1048 get_half_assoc(packet_info *pinfo, uint32_t spt, uint32_t dpt, uint32_t vtag)
1050 sctp_half_assoc_t *ha;
1051 sctp_half_assoc_t **hb;
1052 wmem_tree_key_t *k;
1054 if (!enable_tsn_analysis || !vtag || pinfo->flags.in_error_pkt)
1055 return NULL;
1057 /* look for the current half_assoc by spt, dpt and vtag */
1059 k = make_dir_key(pinfo->pool, spt, dpt, vtag);
1060 if (( ha = (sctp_half_assoc_t *)wmem_tree_lookup32_array(dirs_by_ptvtag, k) )) {
1061 /* found, if it has been already matched we're done */
1062 if (ha->peer) return ha;
1063 } else {
1064 /* not found, make a new one and add it to the table */
1065 ha = wmem_new0(wmem_file_scope(), sctp_half_assoc_t);
1066 ha->spt = spt;
1067 ha->dpt = dpt;
1068 ha->vtag = vtag;
1069 ha->tsns = wmem_tree_new(wmem_file_scope());
1070 ha->tsn_acks = wmem_tree_new(wmem_file_scope());
1071 ha->started = false;
1072 ha->first_tsn= 0;
1073 ha->cumm_ack= 0;
1075 /* add this half to the table indexed by ports and vtag */
1076 wmem_tree_insert32_array(dirs_by_ptvtag, k, ha);
1079 /* at this point we have an unmatched half, look for its other half using the ports and IP address */
1080 k = make_address_key(pinfo->pool, dpt, spt, &(pinfo->dst));
1082 if (( hb = (sctp_half_assoc_t **)wmem_tree_lookup32_array(dirs_by_ptaddr, k) )) {
1083 /*the table contains a pointer to a pointer to a half */
1084 if (! *hb) {
1085 /* if there is no half pointed by this, add the current half to the table */
1086 *hb = ha;
1087 } else {
1088 /* there's a half pointed by this, assume it's our peer and clear the table's pointer */
1089 ha->peer = *hb;
1090 (*hb)->peer = ha;
1091 *hb = NULL;
1093 } else {
1094 /* we found no entry in the table: add one (using reversed ports and src addresses) so that it can be matched later */
1095 *(hb = (sctp_half_assoc_t **)wmem_alloc(wmem_file_scope(), sizeof(void*))) = ha;
1096 k = make_address_key(pinfo->pool, spt, dpt, &(pinfo->src));
1097 wmem_tree_insert32_array(dirs_by_ptaddr, k, hb);
1100 return ha;
1103 /* Limit the number of retransmissions we track (to limit memory usage--and
1104 * tree size--in pathological cases, for example zero window probing forever).
1106 #define MAX_RETRANS_TRACKED_PER_TSN 100
1108 static void
1109 tsn_tree(sctp_tsn_t *t, proto_item *tsn_item, packet_info *pinfo,
1110 tvbuff_t *tvb, uint32_t framenum)
1112 proto_item *pi;
1113 proto_tree *pt;
1114 proto_tree *tsn_tree_pt = proto_item_add_subtree(tsn_item, ett_sctp_tsn);
1116 if (t->first_transmit.framenum != framenum) {
1117 nstime_t rto;
1119 pi = proto_tree_add_uint(tsn_tree_pt, hf_sctp_retransmission, tvb, 0, 0, t->first_transmit.framenum);
1120 pt = proto_item_add_subtree(pi, ett_sctp_tsn_retransmission);
1121 proto_item_set_generated(pi);
1122 expert_add_info(pinfo, pi, &ei_sctp_tsn_retransmitted);
1124 nstime_delta( &rto, &pinfo->abs_ts, &(t->first_transmit.ts) );
1125 pi = proto_tree_add_time(pt, hf_sctp_rto, tvb, 0, 0, &rto);
1126 proto_item_set_generated(pi);
1128 /* Detect reneged acks */
1129 /* XXX what if the frames aren't sorted by time? */
1130 if (t->ack.framenum && t->ack.framenum < framenum)
1132 pi = proto_tree_add_uint_format(pt, hf_sctp_retransmitted_after_ack, tvb, 0, 0, t->ack.framenum,
1133 "This TSN was acked (in frame %u) prior to this retransmission (reneged ack?)",
1134 t->ack.framenum);
1135 proto_item_set_generated(pi);
1136 expert_add_info(pinfo, pi, &ei_sctp_retransmitted_after_ack);
1138 } else if (t->retransmit) {
1139 retransmit_t **r;
1140 nstime_t rto;
1141 char ds[64];
1143 if (t->retransmit_count > MAX_RETRANS_TRACKED_PER_TSN)
1144 snprintf(ds, sizeof(ds), " (only %d displayed)", MAX_RETRANS_TRACKED_PER_TSN);
1145 else
1146 ds[0] = 0;
1148 pi = proto_tree_add_uint_format(tsn_tree_pt,
1149 hf_sctp_retransmitted_count,
1150 tvb, 0, 0, t->retransmit_count,
1151 "This TSN was retransmitted %u time%s%s",
1152 t->retransmit_count,
1153 plurality(t->retransmit_count, "", "s"),
1154 ds);
1155 proto_item_set_generated(pi);
1157 if (t->retransmit_count > 2)
1158 expert_add_info(pinfo, pi, &ei_sctp_tsn_retransmitted_more_than_twice);
1160 pt = proto_item_add_subtree(pi, ett_sctp_tsn_retransmitted_count);
1162 r = &t->retransmit;
1163 while (*r) {
1164 nstime_delta(&rto, &((*r)->ts), &pinfo->abs_ts);
1165 pi = proto_tree_add_uint_format(pt,
1166 hf_sctp_retransmitted,
1167 tvb, 0, 0,
1168 (*r)->framenum,
1169 "This TSN was retransmitted in frame %u (%s seconds after this frame)",
1170 (*r)->framenum,
1171 rel_time_to_secs_str(pinfo->pool, &rto));
1172 proto_item_set_generated(pi);
1173 r = &(*r)->next;
1177 if (t->ack.framenum) {
1178 nstime_t rtt;
1180 pi = proto_tree_add_uint(tsn_tree_pt, hf_sctp_acked, tvb, 0 , 0, t->ack.framenum);
1181 proto_item_set_generated(pi);
1182 pt = proto_item_add_subtree(pi, ett_sctp_ack);
1184 nstime_delta( &rtt, &(t->ack.ts), &(t->first_transmit.ts) );
1185 pi = proto_tree_add_time(pt, hf_sctp_data_rtt, tvb, 0, 0, &rtt);
1186 proto_item_set_generated(pi);
1190 #define RELTSN(tsn) (((tsn) < h->first_tsn) ? (tsn + (0xffffffff - (h->first_tsn)) + 1) : (tsn - h->first_tsn))
1192 /* Returns true if the tsn is a retransmission (we've seen it before), false
1193 * otherwise.
1195 static bool
1196 sctp_tsn(packet_info *pinfo, tvbuff_t *tvb, proto_item *tsn_item,
1197 sctp_half_assoc_t *h, uint32_t tsn)
1199 sctp_tsn_t *t;
1200 uint32_t framenum;
1201 uint32_t reltsn;
1202 bool is_retransmission = false;
1204 /* no half assoc? nothing to do!*/
1205 if (!h)
1206 return is_retransmission;
1209 framenum = pinfo->num;
1211 /* If we're dissecting for a read filter in the GUI [tshark assigns
1212 * frame numbers before running the read filter], don't do the TSN
1213 * analysis. (We can't anyway because we don't have a valid frame
1214 * number...)
1216 * Without this check if you load a capture file in the
1217 * GUI while using a read filter, every SCTP TSN is marked as a
1218 * retransmission of that in frame 0.
1220 if (framenum == 0)
1221 return is_retransmission;
1223 /* we have not seen any tsn yet in this half assoc set the ground */
1224 if (! h->started) {
1225 h->first_tsn = tsn;
1226 h->started = true;
1230 reltsn = RELTSN(tsn);
1232 /* printf("%.3d REL TSN: %p->%p [%u] %u \n",framenum,h,h->peer,tsn,reltsn); */
1234 /* look for this tsn in this half's tsn table */
1235 if (! (t = (sctp_tsn_t *)wmem_tree_lookup32(h->tsns,reltsn) )) {
1236 /* no tsn found, create a new one */
1237 t = wmem_new0(wmem_file_scope(), sctp_tsn_t);
1238 t->tsn = tsn;
1240 t->first_transmit.framenum = framenum;
1241 t->first_transmit.ts = pinfo->abs_ts;
1243 wmem_tree_insert32(h->tsns,reltsn,t);
1246 is_retransmission = (t->first_transmit.framenum != framenum);
1248 if ( (! pinfo->fd->visited ) && is_retransmission ) {
1249 retransmit_t **r;
1250 int i;
1252 t->retransmit_count++;
1253 r = &t->retransmit;
1254 i = 0;
1255 while (*r && i < MAX_RETRANS_TRACKED_PER_TSN) {
1256 r = &(*r)->next;
1257 i++;
1260 if (i <= MAX_RETRANS_TRACKED_PER_TSN) {
1261 *r = wmem_new0(wmem_file_scope(), retransmit_t);
1262 (*r)->framenum = framenum;
1263 (*r)->ts = pinfo->abs_ts;
1267 tsn_tree(t, tsn_item, pinfo, tvb, framenum);
1269 return is_retransmission;
1272 static void
1273 ack_tree(sctp_tsn_t *t, proto_tree *acks_tree,
1274 tvbuff_t *tvb, packet_info *pinfo)
1276 proto_item *pi;
1277 proto_tree *pt;
1278 nstime_t rtt;
1279 unsigned framenum = pinfo->num;
1281 if ( t->ack.framenum == framenum ) {
1282 nstime_delta( &rtt, &(t->ack.ts), &(t->first_transmit.ts) );
1284 pi = proto_tree_add_uint(acks_tree, hf_sctp_ack_tsn, tvb, 0 , 0, t->tsn);
1285 proto_item_set_generated(pi);
1287 pt = proto_item_add_subtree(pi, ett_sctp_acked);
1289 pi = proto_tree_add_uint(pt, hf_sctp_ack_frame, tvb, 0 , 0, t->first_transmit.framenum);
1290 proto_item_set_generated(pi);
1292 pi = proto_tree_add_time(pt, hf_sctp_sack_rtt, tvb, 0, 0, &rtt);
1293 proto_item_set_generated(pi);
1297 static void
1298 sctp_ack(packet_info *pinfo, tvbuff_t *tvb, proto_tree *acks_tree,
1299 sctp_half_assoc_t *h, uint32_t reltsn)
1301 sctp_tsn_t *t;
1302 uint32_t framenum;
1305 if (!h || !h->peer)
1306 return;
1308 framenum = pinfo->num;
1310 /* printf("%.6d ACK: %p->%p [%u] \n",framenum,h,h->peer,reltsn); */
1312 t = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsns,reltsn);
1314 if (t) {
1315 if (! t->ack.framenum) {
1316 sctp_tsn_t *t2;
1318 t->ack.framenum = framenum;
1319 t->ack.ts = pinfo->abs_ts;
1321 if (( t2 = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsn_acks, framenum) )) {
1322 for(;t2->next;t2 = t2->next)
1325 t2->next = t;
1326 } else {
1327 wmem_tree_insert32(h->peer->tsn_acks, framenum,t);
1331 if ( t->ack.framenum == framenum)
1332 ack_tree(t, acks_tree, tvb, pinfo);
1334 } /* else {
1335 proto_tree_add_debug_text(acks_tree, tvb, 0 , 0, "Assoc: %p vs %p ?? %ld",h,h->peer,tsn);
1336 } */
1339 #define RELTSNACK(tsn) (((tsn) < h->peer->first_tsn) ? ((tsn) + (0xffffffff - (h->peer->first_tsn)) + 1) : ((tsn) - h->peer->first_tsn))
1340 static void
1341 sctp_ack_block(packet_info *pinfo, sctp_half_assoc_t *h, tvbuff_t *tvb,
1342 proto_item *acks_tree, const uint32_t *tsn_start_ptr,
1343 uint32_t tsn_end)
1345 sctp_tsn_t *t;
1346 uint32_t framenum;
1347 uint32_t rel_start;
1348 uint32_t rel_end;
1351 if ( !h || !h->peer || ! h->peer->started )
1352 return;
1354 framenum = pinfo->num;
1355 rel_end = RELTSNACK(tsn_end);
1357 if (tsn_start_ptr) {
1358 rel_start = RELTSNACK(*tsn_start_ptr);
1359 /* printf("%.3d BACK: %p->%p [%u-%u]\n",framenum,h,h->peer,rel_start,rel_end); */
1360 } else {
1361 rel_start = h->peer->cumm_ack;
1362 /* printf("%.3d CACK: %p->%p [%u-%u]\n",framenum,h,h->peer,rel_start,rel_end); */
1366 if ((t = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsn_acks, framenum))) {
1367 for(;t;t = t->next) {
1368 uint32_t tsn = t->tsn;
1370 tsn -= h->peer->first_tsn;
1372 if (t->ack.framenum == framenum && ( (!tsn_start_ptr) || rel_start <= tsn) && tsn <= rel_end)
1373 ack_tree(t, acks_tree, tvb, pinfo);
1376 return;
1379 if (PINFO_FD_VISITED(pinfo) || rel_end < rel_start || rel_end - rel_start > 0xffff0000 ) return;
1381 if (! tsn_start_ptr )
1382 h->peer->cumm_ack = rel_end + 1;
1384 if (rel_start <= rel_end && rel_end - rel_start < 5000 ) {
1385 uint32_t rel_tsn, i;
1386 for (i=0; i <= rel_end-rel_start; i++) {
1387 rel_tsn = (uint32_t) (i+rel_start);
1388 sctp_ack(pinfo, tvb, acks_tree, h, rel_tsn);
1393 /* END TSN ANALYSIS CODE */
1398 #define HEARTBEAT_INFO_PARAMETER_INFO_OFFSET PARAMETER_VALUE_OFFSET
1400 static void
1401 dissect_heartbeat_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1403 uint16_t heartbeat_info_length;
1405 heartbeat_info_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1406 if (heartbeat_info_length > 0)
1407 proto_tree_add_item(parameter_tree, hf_heartbeat_info, parameter_tvb, HEARTBEAT_INFO_PARAMETER_INFO_OFFSET, heartbeat_info_length, ENC_NA);
1408 proto_item_append_text(parameter_item, " (Information: %u byte%s)", heartbeat_info_length, plurality(heartbeat_info_length, "", "s"));
1411 #define IPV4_ADDRESS_LENGTH 4
1412 #define IPV4_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET
1414 static void
1415 dissect_ipv4_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item, bool dissecting_init_init_ack_chunk)
1417 if (parameter_tree) {
1418 proto_tree_add_item(parameter_tree, hf_ipv4_address, parameter_tvb, IPV4_ADDRESS_OFFSET, IPV4_ADDRESS_LENGTH, ENC_BIG_ENDIAN);
1419 proto_item_append_text(parameter_item, " (Address: %s)", tvb_ip_to_str(wmem_packet_scope(), parameter_tvb, IPV4_ADDRESS_OFFSET));
1420 if (additional_item)
1421 proto_item_append_text(additional_item, "%s", tvb_ip_to_str(wmem_packet_scope(), parameter_tvb, IPV4_ADDRESS_OFFSET));
1423 if (dissecting_init_init_ack_chunk) {
1424 if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS)
1425 sctp_info.tvb[sctp_info.number_of_tvbs++] = parameter_tvb;
1426 else
1427 sctp_info.incomplete = true;
1431 #define IPV6_ADDRESS_LENGTH 16
1432 #define IPV6_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET
1434 static void
1435 dissect_ipv6_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item, bool dissecting_init_init_ack_chunk)
1437 if (parameter_tree) {
1438 proto_tree_add_item(parameter_tree, hf_ipv6_address, parameter_tvb, IPV6_ADDRESS_OFFSET, IPV6_ADDRESS_LENGTH, ENC_NA);
1439 proto_item_append_text(parameter_item, " (Address: %s)", tvb_ip6_to_str(wmem_packet_scope(), parameter_tvb, IPV6_ADDRESS_OFFSET));
1440 if (additional_item)
1441 proto_item_append_text(additional_item, "%s", tvb_ip6_to_str(wmem_packet_scope(), parameter_tvb, IPV6_ADDRESS_OFFSET));
1443 if (dissecting_init_init_ack_chunk) {
1444 if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS)
1445 sctp_info.tvb[sctp_info.number_of_tvbs++] = parameter_tvb;
1446 else
1447 sctp_info.incomplete = true;
1451 #define STATE_COOKIE_PARAMETER_COOKIE_OFFSET PARAMETER_VALUE_OFFSET
1453 static void
1454 dissect_state_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1456 uint16_t state_cookie_length;
1458 state_cookie_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1459 if (state_cookie_length > 0)
1460 proto_tree_add_item(parameter_tree, hf_state_cookie, parameter_tvb, STATE_COOKIE_PARAMETER_COOKIE_OFFSET, state_cookie_length, ENC_NA);
1461 proto_item_append_text(parameter_item, " (Cookie length: %u byte%s)", state_cookie_length, plurality(state_cookie_length, "", "s"));
1464 static void
1465 // NOLINTNEXTLINE(misc-no-recursion)
1466 dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree)
1468 /* FIXME: Does it contain one or more parameters? */
1469 dissect_parameter(tvb_new_subset_remaining(parameter_tvb, PARAMETER_VALUE_OFFSET), pinfo, parameter_tree, NULL, false, false);
1472 #define COOKIE_PRESERVATIVE_PARAMETER_INCR_LENGTH 4
1473 #define COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET PARAMETER_VALUE_OFFSET
1475 static void
1476 dissect_cookie_preservative_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1478 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);
1479 proto_item_append_text(parameter_item, " (Increment :%u msec)", tvb_get_ntohl(parameter_tvb, COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET));
1482 #define HOSTNAME_OFFSET PARAMETER_VALUE_OFFSET
1484 static void
1485 dissect_hostname_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item)
1487 char *hostname;
1488 uint16_t hostname_length;
1490 hostname_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1491 proto_tree_add_item_ret_display_string(parameter_tree, hf_hostname, parameter_tvb, HOSTNAME_OFFSET, hostname_length, ENC_ASCII, wmem_packet_scope(), &hostname);
1492 if (hostname_length > 1) {
1493 proto_item_append_text(parameter_item, " (Hostname: %s)", hostname);
1494 if (additional_item != NULL) {
1495 proto_item_append_text(additional_item, " (Hostname: %s)", hostname);
1500 #define IPv4_ADDRESS_TYPE 5
1501 #define IPv6_ADDRESS_TYPE 6
1502 #define HOSTNAME_ADDRESS_TYPE 11
1504 static const value_string address_types_values[] = {
1505 { IPv4_ADDRESS_TYPE, "IPv4 address" },
1506 { IPv6_ADDRESS_TYPE, "IPv6 address" },
1507 { HOSTNAME_ADDRESS_TYPE, "Hostname address" },
1508 { 0, NULL }
1511 #define SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH 2
1513 static void
1514 dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1516 uint16_t addr_type, number_of_addr_types, addr_type_number;
1517 unsigned offset;
1519 number_of_addr_types = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH)
1520 / SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH;
1522 offset = PARAMETER_VALUE_OFFSET;
1523 proto_item_append_text(parameter_item, " (Supported types: ");
1524 for(addr_type_number = 0; addr_type_number < number_of_addr_types; addr_type_number++) {
1525 proto_tree_add_item(parameter_tree, hf_supported_address_type, parameter_tvb, offset, SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH, ENC_BIG_ENDIAN);
1526 addr_type = tvb_get_ntohs(parameter_tvb, offset);
1527 switch (addr_type) {
1528 case IPv4_ADDRESS_TYPE:
1529 proto_item_append_text(parameter_item, "IPv4");
1530 break;
1531 case IPv6_ADDRESS_TYPE:
1532 proto_item_append_text(parameter_item, "IPv6");
1533 break;
1534 case HOSTNAME_ADDRESS_TYPE:
1535 proto_item_append_text(parameter_item, "hostname");
1536 break;
1537 default:
1538 proto_item_append_text(parameter_item, "%u", addr_type);
1540 if (addr_type_number < (number_of_addr_types-1))
1541 proto_item_append_text(parameter_item, ", ");
1542 offset += SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH;
1544 proto_item_append_text(parameter_item, ")");
1547 #define STREAM_RESET_SEQ_NR_LENGTH 4
1548 #define SENDERS_LAST_ASSIGNED_TSN_LENGTH 4
1549 #define SID_LENGTH 2
1551 #define STREAM_RESET_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1552 #define STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET (PARAMETER_VALUE_OFFSET + STREAM_RESET_SEQ_NR_LENGTH)
1553 #define SENDERS_LAST_ASSIGNED_TSN_OFFSET (STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH)
1555 static void
1556 dissect_outgoing_ssn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1558 unsigned length, number_of_sids, sid_number, sid_offset;
1560 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);
1561 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);
1562 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);
1564 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1565 sid_offset = SENDERS_LAST_ASSIGNED_TSN_OFFSET + SENDERS_LAST_ASSIGNED_TSN_LENGTH;
1566 if (length > PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + SENDERS_LAST_ASSIGNED_TSN_LENGTH) {
1567 number_of_sids = (length - (PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + SENDERS_LAST_ASSIGNED_TSN_LENGTH)) / SID_LENGTH;
1568 for(sid_number = 0; sid_number < number_of_sids; sid_number++) {
1569 proto_tree_add_item(parameter_tree, hf_stream_reset_sid, parameter_tvb, sid_offset, SID_LENGTH, ENC_BIG_ENDIAN);
1570 sid_offset += SID_LENGTH;
1575 static void
1576 dissect_incoming_ssn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1578 unsigned length, number_of_sids, sid_number, sid_offset;
1580 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);
1582 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1583 sid_offset = STREAM_RESET_REQ_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH;
1584 if (length > PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH) {
1585 number_of_sids = (length - (PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH)) / SID_LENGTH;
1586 for(sid_number = 0; sid_number < number_of_sids; sid_number++) {
1587 proto_tree_add_item(parameter_tree, hf_stream_reset_sid, parameter_tvb, sid_offset, SID_LENGTH, ENC_BIG_ENDIAN);
1588 sid_offset += SID_LENGTH;
1593 #define STREAM_RESET_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1595 static void
1596 dissect_ssn_tsn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1598 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);
1601 #define STREAM_RESET_RSP_RESULT_LENGTH 4
1602 #define SENDERS_NEXT_TSN_LENGTH 4
1603 #define RECEIVERS_NEXT_TSN_LENGTH 4
1605 #define STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1606 #define STREAM_RESET_RSP_RESULT_OFFSET (STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH)
1607 #define SENDERS_NEXT_TSN_OFFSET (STREAM_RESET_RSP_RESULT_OFFSET + STREAM_RESET_RSP_RESULT_LENGTH)
1608 #define RECEIVERS_NEXT_TSN_OFFSET (SENDERS_NEXT_TSN_OFFSET + SENDERS_NEXT_TSN_LENGTH)
1610 static const value_string stream_reset_result_values[] = {
1611 { 0, "Nothing to do" },
1612 { 1, "Performed" },
1613 { 2, "Denied" },
1614 { 3, "Error - Wrong SSN" },
1615 { 4, "Error - Request already in progress" },
1616 { 5, "Error - Bad sequence number" },
1617 { 6, "In progress" },
1618 { 0, NULL }
1622 static void
1623 dissect_re_configuration_response_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1625 unsigned length;
1627 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1629 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);
1630 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);
1631 if (length >= PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_RSP_RESULT_LENGTH + SENDERS_NEXT_TSN_LENGTH)
1632 proto_tree_add_item(parameter_tree, hf_senders_next_tsn, parameter_tvb, SENDERS_NEXT_TSN_OFFSET, SENDERS_NEXT_TSN_LENGTH, ENC_BIG_ENDIAN);
1633 if (length >= PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_RSP_RESULT_LENGTH + SENDERS_NEXT_TSN_LENGTH + RECEIVERS_NEXT_TSN_LENGTH)
1634 proto_tree_add_item(parameter_tree, hf_receivers_next_tsn, parameter_tvb, RECEIVERS_NEXT_TSN_OFFSET, RECEIVERS_NEXT_TSN_LENGTH, ENC_BIG_ENDIAN);
1637 #define ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH 4
1638 #define ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH 2
1639 #define ADD_OUTGOING_STREAM_REQ_RESERVED_LENGTH 2
1641 #define ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1642 #define ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET (ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET + ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH)
1643 #define ADD_OUTGOING_STREAM_REQ_RESERVED_OFFSET (ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET + ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH)
1645 static void
1646 dissect_add_outgoing_streams_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1648 /* unsigned length; */
1650 /* length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); */
1652 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);
1653 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);
1654 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);
1657 #define ADD_INCOMING_STREAM_REQ_SEQ_NR_LENGTH 4
1658 #define ADD_INCOMING_STREAM_REQ_NUM_STREAMS_LENGTH 2
1659 #define ADD_INCOMING_STREAM_REQ_RESERVED_LENGTH 2
1661 #define ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1662 #define ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET (ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET + ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH)
1663 #define ADD_INCOMING_STREAM_REQ_RESERVED_OFFSET (ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET + ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH)
1665 static void
1666 dissect_add_incoming_streams_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1668 /* unsigned length; */
1670 /* length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); */
1672 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);
1673 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);
1674 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);
1677 static void
1678 dissect_ecn_parameter(tvbuff_t *parameter_tvb _U_)
1682 #define ZERO_CHECKSUM_PARAMETER_EDMID_LENGTH 4
1683 #define ZERO_CHECKSUM_PARAMETER_EDMID_OFFSET PARAMETER_VALUE_OFFSET
1685 static const value_string edmid_values[] = {
1686 { 1, "SCTP over DTLS" },
1687 { 0, NULL }
1690 static void
1691 dissect_zero_checksum_acceptable_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1693 proto_tree_add_item(parameter_tree, hf_zero_checksum_edmid, parameter_tvb, ZERO_CHECKSUM_PARAMETER_EDMID_OFFSET, ZERO_CHECKSUM_PARAMETER_EDMID_LENGTH, ENC_BIG_ENDIAN);
1694 proto_item_append_text(parameter_item, " (EDMID: %s)", val_to_str_const(tvb_get_ntohl(parameter_tvb, ZERO_CHECKSUM_PARAMETER_EDMID_OFFSET), edmid_values, "Unknown"));
1697 #define RANDOM_NUMBER_OFFSET PARAMETER_VALUE_OFFSET
1699 static void
1700 dissect_random_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
1702 int32_t number_length;
1704 number_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1705 if (number_length > 0)
1706 proto_tree_add_item(parameter_tree, hf_random_number, parameter_tvb, RANDOM_NUMBER_OFFSET, number_length, ENC_NA);
1709 static void
1710 dissect_chunks_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1712 uint16_t number_of_chunks;
1713 uint16_t chunk_number, offset;
1715 proto_item_append_text(parameter_item, " (Chunk types to be authenticated: ");
1716 number_of_chunks = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1717 for(chunk_number = 0, offset = PARAMETER_VALUE_OFFSET; chunk_number < number_of_chunks; chunk_number++, offset += CHUNK_TYPE_LENGTH) {
1718 proto_tree_add_item(parameter_tree, hf_chunks_to_auth, parameter_tvb, offset, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
1719 proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_uint8(parameter_tvb, offset), chunk_type_values, "Unknown"));
1720 if (chunk_number < (number_of_chunks - 1))
1721 proto_item_append_text(parameter_item, ", ");
1723 proto_item_append_text(parameter_item, ")");
1726 static const value_string hmac_id_values[] = {
1727 { 0x0000, "Reserved" },
1728 { 0x0001, "SHA-1" },
1729 { 0x0002, "Reserved" },
1730 { 0x0003, "SHA-256" },
1731 { 0, NULL } };
1733 #define HMAC_ID_LENGTH 2
1735 static void
1736 dissect_hmac_algo_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1738 uint16_t number_of_ids;
1739 uint16_t id_number, offset;
1741 proto_item_append_text(parameter_item, " (Supported HMACs: ");
1742 number_of_ids = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) / HMAC_ID_LENGTH;
1743 for(id_number = 0, offset = PARAMETER_VALUE_OFFSET; id_number < number_of_ids; id_number++, offset += HMAC_ID_LENGTH) {
1744 proto_tree_add_item(parameter_tree, hf_hmac_id, parameter_tvb, offset, HMAC_ID_LENGTH, ENC_BIG_ENDIAN);
1745 proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_ntohs(parameter_tvb, offset), hmac_id_values, "Unknown"));
1746 if (id_number < (number_of_ids - 1))
1747 proto_item_append_text(parameter_item, ", ");
1749 proto_item_append_text(parameter_item, ")");
1752 static void
1753 dissect_supported_extensions_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1755 uint16_t number_of_types;
1756 uint16_t type_number, offset;
1758 proto_item_append_text(parameter_item, " (Supported types: ");
1759 number_of_types = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) / CHUNK_TYPE_LENGTH;
1760 for(type_number = 0, offset = PARAMETER_VALUE_OFFSET; type_number < number_of_types; type_number++, offset += CHUNK_TYPE_LENGTH) {
1761 proto_tree_add_item(parameter_tree, hf_supported_chunk_type, parameter_tvb, offset, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
1762 proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_uint8(parameter_tvb, offset), chunk_type_values, "Unknown"));
1763 if (type_number < (number_of_types - 1))
1764 proto_item_append_text(parameter_item, ", ");
1766 proto_item_append_text(parameter_item, ")");
1769 static void
1770 dissect_forward_tsn_supported_parameter(tvbuff_t *parameter_tvb _U_)
1774 #define CORRELATION_ID_LENGTH 4
1775 #define CORRELATION_ID_OFFSET PARAMETER_VALUE_OFFSET
1776 #define ADDRESS_PARAMETER_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH)
1778 static void
1779 // NOLINTNEXTLINE(misc-no-recursion)
1780 dissect_add_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
1782 uint16_t address_length;
1783 tvbuff_t *address_tvb;
1785 address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1787 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1788 address_tvb = tvb_new_subset_length_caplen(parameter_tvb, ADDRESS_PARAMETER_OFFSET,
1789 MIN(address_length, tvb_captured_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)),
1790 MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)));
1791 proto_item_append_text(parameter_item, " (Address: ");
1792 dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, false, false);
1793 proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1796 static void
1797 // NOLINTNEXTLINE(misc-no-recursion)
1798 dissect_del_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
1800 uint16_t address_length;
1801 tvbuff_t *address_tvb;
1803 address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1805 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1806 address_tvb = tvb_new_subset_length_caplen(parameter_tvb, ADDRESS_PARAMETER_OFFSET,
1807 MIN(address_length, tvb_captured_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)),
1808 MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)));
1809 proto_item_append_text(parameter_item, " (Address: ");
1810 dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, false, false);
1811 proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1814 #define ERROR_CAUSE_IND_CASUES_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH)
1816 static void
1817 // NOLINTNEXTLINE(misc-no-recursion)
1818 dissect_error_cause_indication_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree)
1820 uint16_t causes_length;
1821 tvbuff_t *causes_tvb;
1823 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1824 causes_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1825 causes_tvb = tvb_new_subset_length_caplen(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET,
1826 MIN(causes_length, tvb_captured_length_remaining(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET)),
1827 MIN(causes_length, tvb_reported_length_remaining(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET)));
1828 dissect_error_causes(causes_tvb, pinfo, parameter_tree);
1831 static void
1832 // NOLINTNEXTLINE(misc-no-recursion)
1833 dissect_set_primary_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
1835 uint16_t address_length;
1836 tvbuff_t *address_tvb;
1838 address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1840 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1841 address_tvb = tvb_new_subset_length_caplen(parameter_tvb, ADDRESS_PARAMETER_OFFSET,
1842 MIN(address_length, tvb_captured_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)),
1843 MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)));
1844 proto_item_append_text(parameter_item, " (Address: ");
1845 dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, false, false);
1846 proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1849 static void
1850 dissect_success_report_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1852 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1853 proto_item_append_text(parameter_item, " (Correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1856 #define ADAP_INDICATION_LENGTH 4
1857 #define ADAP_INDICATION_OFFSET PARAMETER_VALUE_OFFSET
1859 static void
1860 dissect_adap_indication_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1862 proto_tree_add_item(parameter_tree, hf_adap_indication, parameter_tvb, ADAP_INDICATION_OFFSET, ADAP_INDICATION_LENGTH, ENC_BIG_ENDIAN);
1863 proto_item_append_text(parameter_item, " (Indication: %u)", tvb_get_ntohl(parameter_tvb, ADAP_INDICATION_OFFSET));
1866 static void
1867 dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1869 uint16_t type, parameter_value_length;
1871 type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
1872 parameter_value_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1874 if (parameter_value_length > 0)
1875 proto_tree_add_item(parameter_tree, hf_parameter_value, parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length, ENC_NA);
1877 proto_item_append_text(parameter_item, " (Type %u, value length: %u byte%s)", type, parameter_value_length, plurality(parameter_value_length, "", "s"));
1880 #define HEARTBEAT_INFO_PARAMETER_ID 0x0001
1881 #define IPV4ADDRESS_PARAMETER_ID 0x0005
1882 #define IPV6ADDRESS_PARAMETER_ID 0x0006
1883 #define STATE_COOKIE_PARAMETER_ID 0x0007
1884 #define UNREC_PARA_PARAMETER_ID 0x0008
1885 #define COOKIE_PRESERVATIVE_PARAMETER_ID 0x0009
1886 #define HOSTNAME_ADDRESS_PARAMETER_ID 0x000b
1887 #define SUPPORTED_ADDRESS_TYPES_PARAMETER_ID 0x000c
1888 #define OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID 0x000d
1889 #define INCOMING_SSN_RESET_REQUEST_PARAMETER_ID 0x000e
1890 #define SSN_TSN_RESET_REQUEST_PARAMETER_ID 0x000f
1891 #define RE_CONFIGURATION_RESPONSE_PARAMETER_ID 0x0010
1892 #define ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID 0x0011
1893 #define ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID 0x0012
1894 #define ECN_PARAMETER_ID 0x8000
1895 #define ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_ID 0x8001
1896 #define RANDOM_PARAMETER_ID 0x8002
1897 #define CHUNKS_PARAMETER_ID 0x8003
1898 #define HMAC_ALGO_PARAMETER_ID 0x8004
1899 #define SUPPORTED_EXTENSIONS_PARAMETER_ID 0x8008
1900 #define FORWARD_TSN_SUPPORTED_PARAMETER_ID 0xC000
1901 #define ADD_IP_ADDRESS_PARAMETER_ID 0xC001
1902 #define DEL_IP_ADDRESS_PARAMETER_ID 0xC002
1903 #define ERROR_CAUSE_INDICATION_PARAMETER_ID 0xC003
1904 #define SET_PRIMARY_ADDRESS_PARAMETER_ID 0xC004
1905 #define SUCCESS_REPORT_PARAMETER_ID 0xC005
1906 #define ADAP_LAYER_INDICATION_PARAMETER_ID 0xC006
1908 static const value_string parameter_identifier_values[] = {
1909 { HEARTBEAT_INFO_PARAMETER_ID, "Heartbeat info" },
1910 { IPV4ADDRESS_PARAMETER_ID, "IPv4 address" },
1911 { IPV6ADDRESS_PARAMETER_ID, "IPv6 address" },
1912 { STATE_COOKIE_PARAMETER_ID, "State cookie" },
1913 { UNREC_PARA_PARAMETER_ID, "Unrecognized parameter" },
1914 { COOKIE_PRESERVATIVE_PARAMETER_ID, "Cookie preservative" },
1915 { HOSTNAME_ADDRESS_PARAMETER_ID, "Hostname address" },
1916 { OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID, "Outgoing SSN reset request" },
1917 { INCOMING_SSN_RESET_REQUEST_PARAMETER_ID, "Incoming SSN reset request" },
1918 { SSN_TSN_RESET_REQUEST_PARAMETER_ID, "SSN/TSN reset request" },
1919 { RE_CONFIGURATION_RESPONSE_PARAMETER_ID, "Re-configuration response" },
1920 { ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID, "Add outgoing streams request" },
1921 { ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID, "Add incoming streams request" },
1922 { SUPPORTED_ADDRESS_TYPES_PARAMETER_ID, "Supported address types" },
1923 { ECN_PARAMETER_ID, "ECN" },
1924 { ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_ID, "Zero checksum acceptable" },
1925 { RANDOM_PARAMETER_ID, "Random" },
1926 { CHUNKS_PARAMETER_ID, "Authenticated Chunk list" },
1927 { HMAC_ALGO_PARAMETER_ID, "Requested HMAC Algorithm" },
1928 { SUPPORTED_EXTENSIONS_PARAMETER_ID, "Supported Extensions" },
1929 { FORWARD_TSN_SUPPORTED_PARAMETER_ID, "Forward TSN supported" },
1930 { ADD_IP_ADDRESS_PARAMETER_ID, "Add IP address" },
1931 { DEL_IP_ADDRESS_PARAMETER_ID, "Delete IP address" },
1932 { ERROR_CAUSE_INDICATION_PARAMETER_ID, "Error cause indication" },
1933 { SET_PRIMARY_ADDRESS_PARAMETER_ID, "Set primary address" },
1934 { SUCCESS_REPORT_PARAMETER_ID, "Success report" },
1935 { ADAP_LAYER_INDICATION_PARAMETER_ID, "Adaptation Layer Indication" },
1936 { 0, NULL } };
1938 #define SCTP_PARAMETER_BIT_1 0x8000
1939 #define SCTP_PARAMETER_BIT_2 0x4000
1941 static const true_false_string sctp_parameter_bit_1_value = {
1942 "Skip parameter and continue processing of the chunk",
1943 "Stop processing of chunk"
1946 static const true_false_string sctp_parameter_bit_2_value = {
1947 "Do report",
1948 "Do not report"
1951 static void
1952 // NOLINTNEXTLINE(misc-no-recursion)
1953 dissect_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo,
1954 proto_tree *chunk_tree, proto_item *additional_item,
1955 bool dissecting_init_init_ack_chunk,
1956 bool final_parameter)
1958 uint16_t type, length, padding_length, reported_length;
1959 proto_item *parameter_item, *type_item;
1960 proto_tree *parameter_tree, *type_tree;
1962 type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
1963 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1964 reported_length = tvb_reported_length(parameter_tvb);
1965 padding_length = reported_length - length;
1967 parameter_tree = proto_tree_add_subtree_format(chunk_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, -1,
1968 ett_sctp_chunk_parameter, &parameter_item, "%s parameter",
1969 val_to_str_const(type, parameter_identifier_values, "Unknown"));
1970 if (final_parameter) {
1971 if (padding_length > 0) {
1972 expert_add_info(pinfo, parameter_item, &ei_sctp_parameter_padding);
1974 } else {
1975 if (reported_length % 4) {
1976 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);
1980 if (!(chunk_tree || (dissecting_init_init_ack_chunk && (type == IPV4ADDRESS_PARAMETER_ID || type == IPV6ADDRESS_PARAMETER_ID))))
1981 return;
1983 if (chunk_tree) {
1984 type_item = proto_tree_add_item(parameter_tree, hf_parameter_type, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1985 type_tree = proto_item_add_subtree(type_item, ett_sctp_parameter_type);
1986 proto_tree_add_item(type_tree, hf_parameter_bit_1, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1987 proto_tree_add_item(type_tree, hf_parameter_bit_2, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1988 proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, ENC_BIG_ENDIAN);
1989 /* XXX - add expert info if length is bogus? */
1990 } else {
1991 parameter_item = NULL;
1992 parameter_tree = NULL;
1995 increment_dissection_depth(pinfo);
1996 switch(type) {
1997 case HEARTBEAT_INFO_PARAMETER_ID:
1998 dissect_heartbeat_info_parameter(parameter_tvb, parameter_tree, parameter_item);
1999 break;
2000 case IPV4ADDRESS_PARAMETER_ID:
2001 dissect_ipv4_parameter(parameter_tvb, parameter_tree, parameter_item, additional_item, dissecting_init_init_ack_chunk);
2002 break;
2003 case IPV6ADDRESS_PARAMETER_ID:
2004 dissect_ipv6_parameter(parameter_tvb, parameter_tree, parameter_item, additional_item, dissecting_init_init_ack_chunk);
2005 break;
2006 case STATE_COOKIE_PARAMETER_ID:
2007 dissect_state_cookie_parameter(parameter_tvb, parameter_tree, parameter_item);
2008 break;
2009 case UNREC_PARA_PARAMETER_ID:
2010 dissect_unrecognized_parameters_parameter(parameter_tvb, pinfo, parameter_tree);
2011 break;
2012 case COOKIE_PRESERVATIVE_PARAMETER_ID:
2013 dissect_cookie_preservative_parameter(parameter_tvb, parameter_tree, parameter_item);
2014 break;
2015 case HOSTNAME_ADDRESS_PARAMETER_ID:
2016 dissect_hostname_parameter(parameter_tvb, parameter_tree, parameter_item, additional_item);
2017 break;
2018 case SUPPORTED_ADDRESS_TYPES_PARAMETER_ID:
2019 dissect_supported_address_types_parameter(parameter_tvb, parameter_tree, parameter_item);
2020 break;
2021 case OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID:
2022 dissect_outgoing_ssn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item);
2023 break;
2024 case INCOMING_SSN_RESET_REQUEST_PARAMETER_ID:
2025 dissect_incoming_ssn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item);
2026 break;
2027 case SSN_TSN_RESET_REQUEST_PARAMETER_ID:
2028 dissect_ssn_tsn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item);
2029 break;
2030 case RE_CONFIGURATION_RESPONSE_PARAMETER_ID:
2031 dissect_re_configuration_response_parameter(parameter_tvb, parameter_tree, parameter_item);
2032 break;
2033 case ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID:
2034 dissect_add_outgoing_streams_parameter(parameter_tvb, parameter_tree, parameter_item);
2035 break;
2036 case ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID:
2037 dissect_add_incoming_streams_parameter(parameter_tvb, parameter_tree, parameter_item);
2038 break;
2039 case ECN_PARAMETER_ID:
2040 dissect_ecn_parameter(parameter_tvb);
2041 break;
2042 case ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_ID:
2043 dissect_zero_checksum_acceptable_parameter(parameter_tvb, parameter_tree, parameter_item);
2044 break;
2045 case RANDOM_PARAMETER_ID:
2046 dissect_random_parameter(parameter_tvb, parameter_tree);
2047 break;
2048 case CHUNKS_PARAMETER_ID:
2049 dissect_chunks_parameter(parameter_tvb, parameter_tree, parameter_item);
2050 break;
2051 case HMAC_ALGO_PARAMETER_ID:
2052 dissect_hmac_algo_parameter(parameter_tvb, parameter_tree, parameter_item);
2053 break;
2054 case SUPPORTED_EXTENSIONS_PARAMETER_ID:
2055 dissect_supported_extensions_parameter(parameter_tvb, parameter_tree, parameter_item);
2056 break;
2057 case FORWARD_TSN_SUPPORTED_PARAMETER_ID:
2058 dissect_forward_tsn_supported_parameter(parameter_tvb);
2059 break;
2060 case ADD_IP_ADDRESS_PARAMETER_ID:
2061 dissect_add_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
2062 break;
2063 case DEL_IP_ADDRESS_PARAMETER_ID:
2064 dissect_del_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
2065 break;
2066 case ERROR_CAUSE_INDICATION_PARAMETER_ID:
2067 dissect_error_cause_indication_parameter(parameter_tvb, pinfo, parameter_tree);
2068 break;
2069 case SET_PRIMARY_ADDRESS_PARAMETER_ID:
2070 dissect_set_primary_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
2071 break;
2072 case SUCCESS_REPORT_PARAMETER_ID:
2073 dissect_success_report_parameter(parameter_tvb, parameter_tree, parameter_item);
2074 break;
2075 case ADAP_LAYER_INDICATION_PARAMETER_ID:
2076 dissect_adap_indication_parameter(parameter_tvb, parameter_tree, parameter_item);
2077 break;
2078 default:
2079 dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
2080 break;
2082 decrement_dissection_depth(pinfo);
2084 if (padding_length > 0) {
2085 proto_tree_add_item(parameter_tree, hf_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, ENC_NA);
2089 static void
2090 // NOLINTNEXTLINE(misc-no-recursion)
2091 dissect_parameters(tvbuff_t *parameters_tvb, packet_info *pinfo, proto_tree *tree, proto_item *additional_item, bool dissecting_init_init_ack_chunk)
2093 int offset, length, total_length, remaining_length;
2094 tvbuff_t *parameter_tvb;
2095 bool final_parameter;
2097 offset = 0;
2098 remaining_length = tvb_reported_length_remaining(parameters_tvb, offset);
2099 while (remaining_length > 0) {
2100 if ((offset > 0) && additional_item)
2101 proto_item_append_text(additional_item, " ");
2103 length = tvb_get_ntohs(parameters_tvb, offset + PARAMETER_LENGTH_OFFSET);
2104 total_length = WS_ROUNDUP_4(length);
2106 /* If we have less bytes than we need, throw an exception while dissecting
2107 * the parameter--not when generating the parameter_tvb below.
2109 total_length = MIN(total_length, remaining_length);
2111 /* create a tvb for the parameter including the padding bytes */
2112 parameter_tvb = tvb_new_subset_length_caplen(parameters_tvb, offset, MIN(total_length, tvb_captured_length_remaining(parameters_tvb, offset)), total_length);
2113 /* get rid of the handled parameter */
2114 offset += total_length;
2115 remaining_length = tvb_reported_length_remaining(parameters_tvb, offset);
2116 if (remaining_length > 0) {
2117 final_parameter = false;
2118 } else {
2119 final_parameter = true;
2121 dissect_parameter(parameter_tvb, pinfo, tree, additional_item, dissecting_init_init_ack_chunk, final_parameter);
2127 * Code to handle error causes for ABORT and ERROR chunks
2131 #define CAUSE_CODE_LENGTH 2
2132 #define CAUSE_LENGTH_LENGTH 2
2133 #define CAUSE_HEADER_LENGTH (CAUSE_CODE_LENGTH + CAUSE_LENGTH_LENGTH)
2135 #define CAUSE_HEADER_OFFSET 0
2136 #define CAUSE_CODE_OFFSET CAUSE_HEADER_OFFSET
2137 #define CAUSE_LENGTH_OFFSET (CAUSE_CODE_OFFSET + CAUSE_CODE_LENGTH)
2138 #define CAUSE_INFO_OFFSET (CAUSE_LENGTH_OFFSET + CAUSE_LENGTH_LENGTH)
2141 #define CAUSE_STREAM_IDENTIFIER_LENGTH 2
2142 #define CAUSE_RESERVED_LENGTH 2
2143 #define CAUSE_STREAM_IDENTIFIER_OFFSET CAUSE_INFO_OFFSET
2144 #define CAUSE_RESERVED_OFFSET (CAUSE_STREAM_IDENTIFIER_OFFSET + CAUSE_STREAM_IDENTIFIER_LENGTH)
2146 static void
2147 dissect_invalid_stream_identifier_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
2149 proto_tree_add_item(cause_tree, hf_cause_stream_identifier, cause_tvb, CAUSE_STREAM_IDENTIFIER_OFFSET, CAUSE_STREAM_IDENTIFIER_LENGTH, ENC_BIG_ENDIAN);
2150 proto_tree_add_item(cause_tree, hf_cause_reserved, cause_tvb, CAUSE_RESERVED_OFFSET, CAUSE_RESERVED_LENGTH, ENC_BIG_ENDIAN);
2151 proto_item_append_text(cause_item, " (SID: %u)", tvb_get_ntohs(cause_tvb, CAUSE_STREAM_IDENTIFIER_OFFSET));
2154 #define CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH 4
2155 #define CAUSE_MISSING_PARAMETER_TYPE_LENGTH 2
2157 #define CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET CAUSE_INFO_OFFSET
2158 #define CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET (CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET + \
2159 CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH )
2161 static void
2162 dissect_missing_mandatory_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree)
2164 uint32_t number_of_missing_parameters, missing_parameter_number;
2165 unsigned offset;
2167 number_of_missing_parameters = tvb_get_ntohl(cause_tvb, CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET);
2168 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);
2169 offset = CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET;
2170 for(missing_parameter_number = 0; missing_parameter_number < number_of_missing_parameters; missing_parameter_number++) {
2171 proto_tree_add_item(cause_tree, hf_cause_missing_parameter_type, cause_tvb, offset, CAUSE_MISSING_PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
2172 offset += CAUSE_MISSING_PARAMETER_TYPE_LENGTH;
2176 #define CAUSE_MEASURE_OF_STALENESS_LENGTH 4
2177 #define CAUSE_MEASURE_OF_STALENESS_OFFSET CAUSE_INFO_OFFSET
2179 static void
2180 dissect_stale_cookie_error_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
2182 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);
2183 proto_item_append_text(cause_item, " (Measure: %u usec)", tvb_get_ntohl(cause_tvb, CAUSE_MEASURE_OF_STALENESS_OFFSET));
2186 static void
2187 dissect_out_of_resource_cause(tvbuff_t *cause_tvb _U_)
2191 static void
2192 // NOLINTNEXTLINE(misc-no-recursion)
2193 dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
2195 uint16_t parameter_length;
2196 tvbuff_t *parameter_tvb;
2198 parameter_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2199 parameter_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2200 MIN(parameter_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2201 MIN(parameter_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2202 dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, false, true);
2205 static bool
2206 dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, proto_tree *sctp_tree, sctp_half_assoc_t *assoc, bool useinfo);
2208 static void
2209 // NOLINTNEXTLINE(misc-no-recursion)
2210 dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
2212 uint16_t chunk_length;
2213 uint8_t unrecognized_type;
2214 tvbuff_t *unrecognized_chunk_tvb;
2216 chunk_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2217 unrecognized_chunk_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2218 MIN(chunk_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2219 MIN(chunk_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2220 dissect_sctp_chunk(unrecognized_chunk_tvb, pinfo, cause_tree,cause_tree, NULL, false);
2221 unrecognized_type = tvb_get_uint8(unrecognized_chunk_tvb, CHUNK_TYPE_OFFSET);
2222 proto_item_append_text(cause_item, " (Type: %u (%s))", unrecognized_type, val_to_str_const(unrecognized_type, chunk_type_values, "unknown"));
2225 static void
2226 dissect_invalid_mandatory_parameter_cause(tvbuff_t *cause_tvb _U_)
2230 static void
2231 // NOLINTNEXTLINE(misc-no-recursion)
2232 dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree)
2234 uint16_t cause_info_length;
2235 tvbuff_t *unrecognized_parameters_tvb;
2237 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2239 unrecognized_parameters_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2240 MIN(cause_info_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2241 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2242 dissect_parameters(unrecognized_parameters_tvb, pinfo, cause_tree, NULL, false);
2245 #define CAUSE_TSN_LENGTH 4
2246 #define CAUSE_TSN_OFFSET CAUSE_INFO_OFFSET
2248 static void
2249 dissect_no_user_data_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
2251 proto_tree_add_item(cause_tree, hf_cause_tsn, cause_tvb, CAUSE_TSN_OFFSET, CAUSE_TSN_LENGTH, ENC_BIG_ENDIAN);
2252 proto_item_append_text(cause_item, " (TSN: %u)", tvb_get_ntohl(cause_tvb, CAUSE_TSN_OFFSET));
2255 static void
2256 dissect_cookie_received_while_shutting_down_cause(tvbuff_t *cause_tvb _U_)
2260 static void
2261 // NOLINTNEXTLINE(misc-no-recursion)
2262 dissect_restart_with_new_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
2264 uint16_t cause_info_length;
2265 tvbuff_t *parameter_tvb;
2267 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2268 parameter_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2269 MIN(cause_info_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2270 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2271 proto_item_append_text(cause_item, " (New addresses: ");
2272 dissect_parameters(parameter_tvb, pinfo, cause_tree, cause_item, false);
2273 proto_item_append_text(cause_item, ")");
2276 static void
2277 dissect_user_initiated_abort_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree)
2279 uint16_t cause_info_length;
2281 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2282 if (cause_info_length > 0)
2283 proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
2286 static void
2287 dissect_protocol_violation_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree)
2289 uint16_t cause_info_length;
2291 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2292 if (cause_info_length > 0)
2293 proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
2296 static void
2297 // NOLINTNEXTLINE(misc-no-recursion)
2298 dissect_delete_last_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
2300 uint16_t cause_info_length;
2301 tvbuff_t *parameter_tvb;
2303 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2304 parameter_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2305 MIN(cause_info_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2306 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2307 proto_item_append_text(cause_item, " (Last address: ");
2308 dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, false, false);
2309 proto_item_append_text(cause_item, ")");
2312 static void
2313 // NOLINTNEXTLINE(misc-no-recursion)
2314 dissect_resource_outage_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree)
2316 uint16_t cause_info_length;
2317 tvbuff_t *parameter_tvb;
2319 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2320 parameter_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2321 MIN(cause_info_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2322 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2323 dissect_parameter(parameter_tvb, pinfo, cause_tree, NULL, false, false);
2326 static void
2327 // NOLINTNEXTLINE(misc-no-recursion)
2328 dissect_delete_source_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
2330 uint16_t cause_info_length;
2331 tvbuff_t *parameter_tvb;
2333 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2334 parameter_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2335 MIN(cause_info_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2336 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2337 proto_item_append_text(cause_item, " (Deleted address: ");
2338 dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, false, false);
2339 proto_item_append_text(cause_item, ")");
2342 static void
2343 // NOLINTNEXTLINE(misc-no-recursion)
2344 dissect_request_refused_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree)
2346 uint16_t cause_info_length;
2347 tvbuff_t *parameter_tvb;
2349 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2350 parameter_tvb = tvb_new_subset_length_caplen(cause_tvb, CAUSE_INFO_OFFSET,
2351 MIN(cause_info_length, tvb_captured_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
2352 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
2353 dissect_parameter(parameter_tvb, pinfo, cause_tree, NULL, false, false);
2356 static void
2357 dissect_unsupported_hmac_id_cause(tvbuff_t *cause_tvb, packet_info *pinfo _U_, proto_tree *cause_tree)
2359 proto_tree_add_item(cause_tree, hf_hmac_id, cause_tvb, CAUSE_INFO_OFFSET, HMAC_ID_LENGTH, ENC_BIG_ENDIAN);
2362 static void
2363 dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
2365 uint16_t cause_info_length;
2367 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
2368 if (cause_info_length > 0)
2369 proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
2370 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"));
2373 #define INVALID_STREAM_IDENTIFIER 0x01
2374 #define MISSING_MANDATORY_PARAMETERS 0x02
2375 #define STALE_COOKIE_ERROR 0x03
2376 #define OUT_OF_RESOURCE 0x04
2377 #define UNRESOLVABLE_ADDRESS 0x05
2378 #define UNRECOGNIZED_CHUNK_TYPE 0x06
2379 #define INVALID_MANDATORY_PARAMETER 0x07
2380 #define UNRECOGNIZED_PARAMETERS 0x08
2381 #define NO_USER_DATA 0x09
2382 #define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN 0x0a
2383 #define RESTART_WITH_NEW_ADDRESSES 0x0b
2384 #define USER_INITIATED_ABORT 0x0c
2385 #define PROTOCOL_VIOLATION 0x0d
2386 #define REQUEST_TO_DELETE_LAST_ADDRESS 0x00a0
2387 #define OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE 0x00a1
2388 #define REQUEST_TO_DELETE_SOURCE_ADDRESS 0x00a2
2389 #define ABORT_DUE_TO_ILLEGAL_ASCONF 0x00a3
2390 #define REQUEST_REFUSED 0x00a4
2391 #define UNSUPPORTED_HMAC_ID 0x0105
2393 static const value_string cause_code_values[] = {
2394 { INVALID_STREAM_IDENTIFIER, "Invalid stream identifier" },
2395 { MISSING_MANDATORY_PARAMETERS, "Missing mandatory parameter" },
2396 { STALE_COOKIE_ERROR, "Stale cookie error" },
2397 { OUT_OF_RESOURCE, "Out of resource" },
2398 { UNRESOLVABLE_ADDRESS, "Unresolvable address" },
2399 { UNRECOGNIZED_CHUNK_TYPE, "Unrecognized chunk type" },
2400 { INVALID_MANDATORY_PARAMETER, "Invalid mandatory parameter" },
2401 { UNRECOGNIZED_PARAMETERS, "Unrecognized parameters" },
2402 { NO_USER_DATA, "No user data" },
2403 { COOKIE_RECEIVED_WHILE_SHUTTING_DOWN, "Cookie received while shutting down" },
2404 { RESTART_WITH_NEW_ADDRESSES, "Restart of an association with new addresses" },
2405 { USER_INITIATED_ABORT, "User initiated ABORT" },
2406 { PROTOCOL_VIOLATION, "Protocol violation" },
2407 { REQUEST_TO_DELETE_LAST_ADDRESS, "Request to delete last address" },
2408 { OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE, "Operation refused due to resource shortage" },
2409 { REQUEST_TO_DELETE_SOURCE_ADDRESS, "Request to delete source address" },
2410 { ABORT_DUE_TO_ILLEGAL_ASCONF, "Association Aborted due to illegal ASCONF-ACK" },
2411 { REQUEST_REFUSED, "Request refused - no authorization" },
2412 { UNSUPPORTED_HMAC_ID, "Unsupported HMAC identifier" },
2413 { 0, NULL } };
2416 static void
2417 // NOLINTNEXTLINE(misc-no-recursion)
2418 dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_tree)
2420 uint16_t code, length, padding_length;
2421 proto_item *cause_item;
2422 proto_tree *cause_tree;
2424 code = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET);
2425 length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
2426 padding_length = tvb_reported_length(cause_tvb) - length;
2428 cause_tree = proto_tree_add_subtree_format(chunk_tree, cause_tvb, CAUSE_HEADER_OFFSET, -1,
2429 ett_sctp_chunk_cause, &cause_item, "%s cause", val_to_str_const(code, cause_code_values, "Unknown"));
2431 proto_tree_add_item(cause_tree, hf_cause_code, cause_tvb, CAUSE_CODE_OFFSET, CAUSE_CODE_LENGTH, ENC_BIG_ENDIAN);
2432 proto_tree_add_item(cause_tree, hf_cause_length, cause_tvb, CAUSE_LENGTH_OFFSET, CAUSE_LENGTH_LENGTH, ENC_BIG_ENDIAN);
2433 /* XXX - add expert info if length is bogus? */
2435 increment_dissection_depth(pinfo);
2436 switch(code) {
2437 case INVALID_STREAM_IDENTIFIER:
2438 dissect_invalid_stream_identifier_cause(cause_tvb, cause_tree, cause_item);
2439 break;
2440 case MISSING_MANDATORY_PARAMETERS:
2441 dissect_missing_mandatory_parameters_cause(cause_tvb, cause_tree);
2442 break;
2443 case STALE_COOKIE_ERROR:
2444 dissect_stale_cookie_error_cause(cause_tvb, cause_tree, cause_item);
2445 break;
2446 case OUT_OF_RESOURCE:
2447 dissect_out_of_resource_cause(cause_tvb);
2448 break;
2449 case UNRESOLVABLE_ADDRESS:
2450 dissect_unresolvable_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
2451 break;
2452 case UNRECOGNIZED_CHUNK_TYPE:
2453 dissect_unrecognized_chunk_type_cause(cause_tvb, pinfo, cause_tree, cause_item);
2454 break;
2455 case INVALID_MANDATORY_PARAMETER:
2456 dissect_invalid_mandatory_parameter_cause(cause_tvb);
2457 break;
2458 case UNRECOGNIZED_PARAMETERS:
2459 dissect_unrecognized_parameters_cause(cause_tvb, pinfo, cause_tree);
2460 break;
2461 case NO_USER_DATA:
2462 dissect_no_user_data_cause(cause_tvb, cause_tree, cause_item);
2463 break;
2464 case COOKIE_RECEIVED_WHILE_SHUTTING_DOWN:
2465 dissect_cookie_received_while_shutting_down_cause(cause_tvb);
2466 break;
2467 case RESTART_WITH_NEW_ADDRESSES:
2468 dissect_restart_with_new_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
2469 break;
2470 case USER_INITIATED_ABORT:
2471 dissect_user_initiated_abort_cause(cause_tvb, cause_tree);
2472 break;
2473 case PROTOCOL_VIOLATION:
2474 dissect_protocol_violation_cause(cause_tvb, cause_tree);
2475 break;
2476 case REQUEST_TO_DELETE_LAST_ADDRESS:
2477 dissect_delete_last_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
2478 break;
2479 case OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE:
2480 dissect_resource_outage_cause(cause_tvb, pinfo, cause_tree);
2481 break;
2482 case REQUEST_TO_DELETE_SOURCE_ADDRESS:
2483 dissect_delete_source_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
2484 break;
2485 case REQUEST_REFUSED:
2486 dissect_request_refused_cause(cause_tvb, pinfo, cause_tree);
2487 break;
2488 case UNSUPPORTED_HMAC_ID:
2489 dissect_unsupported_hmac_id_cause(cause_tvb, pinfo, cause_tree);
2490 break;
2491 default:
2492 dissect_unknown_cause(cause_tvb, cause_tree, cause_item);
2493 break;
2495 decrement_dissection_depth(pinfo);
2497 if (padding_length > 0)
2498 proto_tree_add_item(cause_tree, hf_cause_padding, cause_tvb, CAUSE_HEADER_OFFSET + length, padding_length, ENC_NA);
2501 static void
2502 // NOLINTNEXTLINE(misc-no-recursion)
2503 dissect_error_causes(tvbuff_t *causes_tvb, packet_info *pinfo, proto_tree *tree)
2505 int offset, length, total_length, remaining_length;
2506 tvbuff_t *cause_tvb;
2508 offset = 0;
2509 while((remaining_length = tvb_reported_length_remaining(causes_tvb, offset))) {
2510 length = tvb_get_ntohs(causes_tvb, offset + CAUSE_LENGTH_OFFSET);
2511 total_length = WS_ROUNDUP_4(length);
2513 /* If we have less bytes than we need, throw an exception while dissecting
2514 * the cause--not when generating the causes_tvb below.
2516 total_length = MIN(total_length, remaining_length);
2518 /* create a tvb for the parameter including the padding bytes */
2519 cause_tvb = tvb_new_subset_length_caplen(causes_tvb, offset, MIN(total_length, tvb_captured_length_remaining(causes_tvb, offset)), total_length);
2521 dissect_error_cause(cause_tvb, pinfo, tree);
2523 /* get rid of the handled cause */
2524 offset += total_length;
2530 * Code to actually dissect the packets
2533 static bool try_heuristic_first;
2535 static bool
2536 dissect_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree, uint32_t ppi)
2538 uint32_t low_port, high_port;
2539 bool try_ppi, try_low_port, try_high_port;
2540 heur_dtbl_entry_t *hdtbl_entry;
2542 if (enable_ulp_dissection) {
2544 /* XXX - we ignore port numbers of 0, as some dissectors use a port
2545 number of 0 to disable the port. */
2546 if (pinfo->srcport > pinfo->destport) {
2547 low_port = pinfo->destport;
2548 high_port = pinfo->srcport;
2549 } else {
2550 low_port = pinfo->srcport;
2551 high_port = pinfo->destport;
2554 try_ppi = false;
2555 if (dissector_is_uint_changed(sctp_ppi_dissector_table, ppi)) {
2556 if (dissector_try_uint_with_data(sctp_ppi_dissector_table, ppi, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) {
2557 return true;
2559 } else {
2560 /* The default; try it later */
2561 try_ppi = true;
2564 try_low_port = false;
2565 if (low_port != 0) {
2566 if (dissector_is_uint_changed(sctp_port_dissector_table, low_port)) {
2567 if (dissector_try_uint_with_data(sctp_port_dissector_table, low_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) {
2568 return true;
2570 } else {
2571 /* The default; try it later */
2572 try_low_port = true;
2576 try_high_port = false;
2577 if (high_port != 0) {
2578 if (dissector_is_uint_changed(sctp_port_dissector_table, high_port)) {
2579 if (dissector_try_uint_with_data(sctp_port_dissector_table, high_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi))) {
2580 return true;
2582 } else {
2583 /* The default; try it later */
2584 try_high_port = true;
2588 if (try_heuristic_first) {
2589 /* do lookup with the heuristic subdissector table */
2590 if (dissector_try_heuristic(sctp_heur_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, GUINT_TO_POINTER(ppi)))
2591 return true;
2594 /* Do lookups with the subdissector table.
2595 First try the PPI.
2597 When trying port numbers, we try the port number with the lower value
2598 first, followed by the port number with the higher value. This means
2599 that, for packets where a dissector is registered for *both* port
2600 numbers, and where there's no match on the PPI:
2602 1) we pick the same dissector for traffic going in both directions;
2604 2) we prefer the port number that's more likely to be the right
2605 one (as that prefers well-known ports to reserved ports);
2607 although there is, of course, no guarantee that any such strategy
2608 will always pick the right port number. */
2609 if (try_ppi &&
2610 dissector_try_uint_with_data(sctp_ppi_dissector_table, ppi, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi)))
2611 return true;
2613 if (try_low_port &&
2614 dissector_try_uint_with_data(sctp_port_dissector_table, low_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi)))
2615 return true;
2616 if (try_high_port &&
2617 dissector_try_uint_with_data(sctp_port_dissector_table, high_port, payload_tvb, pinfo, tree, true, GUINT_TO_POINTER(ppi)))
2618 return true;
2620 if (!try_heuristic_first) {
2621 /* do lookup with the heuristic subdissector table */
2622 if (dissector_try_heuristic(sctp_heur_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, GUINT_TO_POINTER(ppi)))
2623 return true;
2626 /* Oh, well, we don't know this; dissect it as data. */
2627 call_data_dissector(payload_tvb, pinfo, tree);
2628 return true;
2631 #define DATA_CHUNK_TSN_LENGTH 4
2632 #define DATA_CHUNK_STREAM_ID_LENGTH 2
2633 #define DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH 2
2634 #define DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH 4
2635 #define I_DATA_CHUNK_RESERVED_LENGTH 2
2636 #define I_DATA_CHUNK_MID_LENGTH 4
2637 #define I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH 4
2638 #define I_DATA_CHUNK_FSN_LENGTH 4
2640 #define DATA_CHUNK_TSN_OFFSET (CHUNK_VALUE_OFFSET + 0)
2641 #define DATA_CHUNK_STREAM_ID_OFFSET (DATA_CHUNK_TSN_OFFSET + DATA_CHUNK_TSN_LENGTH)
2642 #define DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET (DATA_CHUNK_STREAM_ID_OFFSET + \
2643 DATA_CHUNK_STREAM_ID_LENGTH)
2644 #define DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET (DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET + \
2645 DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH)
2646 #define DATA_CHUNK_PAYLOAD_OFFSET (DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET + \
2647 DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH)
2648 #define I_DATA_CHUNK_RESERVED_OFFSET (DATA_CHUNK_STREAM_ID_OFFSET + \
2649 DATA_CHUNK_STREAM_ID_LENGTH)
2650 #define I_DATA_CHUNK_MID_OFFSET (I_DATA_CHUNK_RESERVED_OFFSET + \
2651 I_DATA_CHUNK_RESERVED_LENGTH)
2652 #define I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET (I_DATA_CHUNK_MID_OFFSET + \
2653 I_DATA_CHUNK_MID_LENGTH)
2654 #define I_DATA_CHUNK_FSN_OFFSET (I_DATA_CHUNK_MID_OFFSET + \
2655 I_DATA_CHUNK_MID_LENGTH)
2656 #define I_DATA_CHUNK_PAYLOAD_OFFSET (I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET + \
2657 I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH)
2659 #define DATA_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \
2660 DATA_CHUNK_TSN_LENGTH + \
2661 DATA_CHUNK_STREAM_ID_LENGTH + \
2662 DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH + \
2663 DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH)
2664 #define I_DATA_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \
2665 DATA_CHUNK_TSN_LENGTH + \
2666 DATA_CHUNK_STREAM_ID_LENGTH + \
2667 I_DATA_CHUNK_RESERVED_LENGTH + \
2668 I_DATA_CHUNK_MID_LENGTH +\
2669 I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH)
2671 #define SCTP_DATA_CHUNK_E_BIT 0x01
2672 #define SCTP_DATA_CHUNK_B_BIT 0x02
2673 #define SCTP_DATA_CHUNK_U_BIT 0x04
2674 #define SCTP_DATA_CHUNK_I_BIT 0x08
2676 /* table to hold fragmented SCTP messages */
2677 static GHashTable *frag_table;
2680 typedef struct _frag_key {
2681 uint16_t sport;
2682 uint16_t dport;
2683 uint32_t verification_tag;
2684 uint16_t stream_id;
2685 uint32_t stream_seq_num;
2686 uint8_t u_bit;
2687 } frag_key;
2690 static int
2691 frag_equal(const void *k1, const void *k2)
2693 const frag_key *key1 = (const frag_key *) k1;
2694 const frag_key *key2 = (const frag_key *) k2;
2696 return ( (key1->sport == key2->sport) &&
2697 (key1->dport == key2->dport) &&
2698 (key1->verification_tag == key2->verification_tag) &&
2699 (key1->stream_id == key2->stream_id) &&
2700 (key1->stream_seq_num == key2->stream_seq_num) &&
2701 (key1->u_bit == key2->u_bit)
2702 ? true : false);
2706 static unsigned
2707 frag_hash(const void *k)
2709 const frag_key *key = (const frag_key *) k;
2711 return key->sport ^ key->dport ^ key->verification_tag ^
2712 key->stream_id ^ key->stream_seq_num ^ key->u_bit;
2716 static void
2717 frag_free_msgs(sctp_frag_msg *msg)
2719 sctp_frag_be *beginend;
2720 sctp_fragment *fragment;
2722 /* free all begins */
2723 while (msg->begins) {
2724 beginend = msg->begins;
2725 msg->begins = msg->begins->next;
2726 g_free(beginend);
2729 /* free all ends */
2730 while (msg->ends) {
2731 beginend = msg->ends;
2732 msg->ends = msg->ends->next;
2733 g_free(beginend);
2736 /* free all fragments */
2737 while (msg->fragments) {
2738 fragment = msg->fragments;
2739 msg->fragments = msg->fragments->next;
2740 g_free(fragment->data);
2741 g_free(fragment);
2744 /* msg->messages is wmem_ allocated, no need to free it */
2746 g_free(msg);
2749 static void
2750 sctp_init(void)
2752 frag_table = g_hash_table_new_full(frag_hash, frag_equal,
2753 (GDestroyNotify)g_free, (GDestroyNotify)frag_free_msgs);
2754 num_assocs = 0;
2757 static void
2758 sctp_cleanup(void)
2760 g_hash_table_destroy(frag_table);
2764 static sctp_frag_msg*
2765 find_message(uint16_t stream_id, uint32_t stream_seq_num, uint8_t u_bit)
2767 frag_key key;
2769 key.sport = sctp_info.sport;
2770 key.dport = sctp_info.dport;
2771 key.verification_tag = sctp_info.verification_tag;
2772 key.stream_id = stream_id;
2773 key.stream_seq_num = stream_seq_num;
2774 key.u_bit = u_bit;
2776 return (sctp_frag_msg *)g_hash_table_lookup(frag_table, &key);
2780 static sctp_fragment*
2781 find_fragment(uint32_t tsn, uint16_t stream_id, uint32_t stream_seq_num, uint8_t u_bit)
2783 sctp_frag_msg *msg;
2784 sctp_fragment *next_fragment;
2786 msg = find_message(stream_id, stream_seq_num, u_bit);
2788 if (msg) {
2789 next_fragment = msg->fragments;
2790 while (next_fragment) {
2791 if (next_fragment->tsn == tsn)
2792 return next_fragment;
2793 next_fragment = next_fragment->next;
2797 return NULL;
2801 static sctp_fragment *
2802 add_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t tsn,
2803 uint16_t stream_id, uint32_t stream_seq_num, uint8_t b_bit, uint8_t e_bit,
2804 uint8_t u_bit, uint32_t ppi, bool is_idata)
2806 sctp_frag_msg *msg;
2807 sctp_fragment *fragment, *last_fragment;
2808 sctp_frag_be *beginend, *last_beginend;
2809 frag_key *key;
2811 /* Don't try to do reassembly on error packets */
2812 if (pinfo->flags.in_error_pkt)
2813 return NULL;
2815 /* lookup message. if not found, create it */
2816 msg = find_message(stream_id, stream_seq_num, u_bit);
2818 if (!msg) {
2819 msg = g_new(sctp_frag_msg, 1);
2820 msg->begins = NULL;
2821 msg->ends = NULL;
2822 msg->fragments = NULL;
2823 msg->messages = NULL;
2824 msg->next = NULL;
2825 if (is_idata)
2826 if (b_bit)
2827 msg->ppi = ppi;
2828 else
2829 msg->ppi = 0;
2830 else
2831 msg->ppi = ppi;
2833 key = g_new(frag_key, 1);
2834 key->sport = sctp_info.sport;
2835 key->dport = sctp_info.dport;
2836 key->verification_tag = sctp_info.verification_tag;
2837 key->stream_id = stream_id;
2838 key->stream_seq_num = stream_seq_num;
2839 key->u_bit = u_bit;
2841 g_hash_table_insert(frag_table, key, msg);
2842 } else {
2843 if (b_bit)
2844 msg->ppi = ppi;
2847 /* lookup segment. if not found, create it */
2848 fragment = find_fragment(tsn, stream_id, stream_seq_num, u_bit);
2850 if (fragment) {
2851 /* this fragment is already known.
2852 * compare frame number to check if it's a duplicate
2854 if (fragment->frame_num == pinfo->num) {
2855 return fragment;
2856 } else {
2857 /* There already is a fragment having the same ports, v_tag,
2858 * stream id, stream_seq_num and tsn but it appeared in a different
2859 * frame, so it must be a duplicate fragment. Maybe a retransmission?
2860 * Mark it as duplicate and return NULL.
2862 * Note: This won't happen if TSN analysis is on: the caller will have
2863 * detected the retransmission and not pass it to the reassembly code.
2865 col_append_str(pinfo->cinfo, COL_INFO, "(Duplicate Message Fragment) ");
2867 proto_tree_add_uint(tree, hf_sctp_duplicate, tvb, 0, 0, fragment->frame_num);
2868 return NULL;
2872 /* There is no point in storing a fragment with no data in it */
2873 if (tvb_captured_length(tvb) == 0)
2874 return NULL;
2876 /* create new fragment */
2877 fragment = g_new(sctp_fragment, 1);
2878 fragment->frame_num = pinfo->num;
2879 fragment->tsn = tsn;
2880 fragment->len = tvb_captured_length(tvb);
2881 fragment->ppi = msg->ppi;
2882 fragment->next = NULL;
2883 fragment->data = (unsigned char *)g_malloc (fragment->len);
2884 tvb_memcpy(tvb, fragment->data, 0, fragment->len);
2886 /* add new fragment to linked list. sort ascending by tsn */
2887 if (!msg->fragments)
2888 msg->fragments = fragment;
2889 else {
2890 if (msg->fragments->tsn > fragment->tsn) {
2891 fragment->next = msg->fragments;
2892 msg->fragments = fragment;
2893 } else {
2894 last_fragment = msg->fragments;
2895 while (last_fragment->next &&
2896 last_fragment->next->tsn < fragment->tsn)
2897 last_fragment = last_fragment->next;
2899 fragment->next = last_fragment->next;
2900 last_fragment->next = fragment;
2905 /* save begin or end if necessary */
2906 if (b_bit && !e_bit) {
2907 beginend = g_new(sctp_frag_be, 1);
2908 beginend->fragment = fragment;
2909 beginend->next = NULL;
2911 /* add begin to linked list. sort descending by tsn */
2912 if (!msg->begins)
2913 msg->begins = beginend;
2914 else {
2915 if (msg->begins->fragment->tsn < beginend->fragment->tsn) {
2916 beginend->next = msg->begins;
2917 msg->begins = beginend;
2918 } else {
2919 last_beginend = msg->begins;
2920 while (last_beginend->next &&
2921 last_beginend->next->fragment->tsn > beginend->fragment->tsn)
2922 last_beginend = last_beginend->next;
2924 beginend->next = last_beginend->next;
2925 last_beginend->next = beginend;
2931 if (!b_bit && e_bit) {
2932 beginend = g_new(sctp_frag_be, 1);
2933 beginend->fragment = fragment;
2934 beginend->next = NULL;
2936 /* add end to linked list. sort ascending by tsn */
2937 if (!msg->ends)
2938 msg->ends = beginend;
2939 else {
2940 if (msg->ends->fragment->tsn > beginend->fragment->tsn) {
2941 beginend->next = msg->ends;
2942 msg->ends = beginend;
2943 } else {
2944 last_beginend = msg->ends;
2945 while (last_beginend->next &&
2946 last_beginend->next->fragment->tsn < beginend->fragment->tsn)
2947 last_beginend = last_beginend->next;
2949 beginend->next = last_beginend->next;
2950 last_beginend->next = beginend;
2956 return fragment;
2959 static tvbuff_t*
2960 fragment_reassembly(tvbuff_t *tvb, sctp_fragment *fragment,
2961 packet_info *pinfo, proto_tree *tree, uint16_t stream_id,
2962 uint32_t stream_seq_num, uint8_t u_bit)
2964 sctp_frag_msg *msg;
2965 sctp_complete_msg *message, *last_message;
2966 sctp_fragment *frag_i, *last_frag, *first_frag;
2967 sctp_frag_be *begin, *end, *beginend;
2968 uint32_t len, offset = 0;
2969 tvbuff_t *new_tvb = NULL;
2970 proto_item *item;
2971 proto_tree *ptree;
2973 msg = find_message(stream_id, stream_seq_num, u_bit);
2975 if (!msg) {
2976 /* no message, we can't do anything */
2977 return NULL;
2980 /* check if fragment is part of an already reassembled message */
2981 for (message = msg->messages;
2982 message &&
2983 !(message->begin <= fragment->tsn && message->end >= fragment->tsn) &&
2984 !(message->begin > message->end &&
2985 (message->begin <= fragment->tsn || message->end >= fragment->tsn));
2986 message = message->next);
2988 if (message) {
2989 /* we found the reassembled message this fragment belongs to */
2990 if (fragment == message->reassembled_in) {
2992 /* this is the last fragment, create data source */
2993 new_tvb = tvb_new_child_real_data(tvb, message->data, message->len, message->len);
2994 add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message");
2996 /* display reassembly info */
2997 item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, ENC_NA);
2998 ptree = proto_item_add_subtree(item, ett_sctp_fragments);
2999 proto_item_append_text(item, " (%u bytes, %u fragments): ",
3000 message->len, message->end - message->begin + 1);
3002 if (message->begin > message->end) {
3003 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit);
3004 frag_i;
3005 frag_i = frag_i->next) {
3007 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
3008 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
3009 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
3010 offset += frag_i->len;
3012 mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num);
3015 for (frag_i = msg->fragments;
3016 frag_i && frag_i->tsn <= message->end;
3017 frag_i = frag_i->next) {
3019 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
3020 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
3021 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
3022 offset += frag_i->len;
3024 mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num);
3026 } else {
3027 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit);
3028 frag_i && frag_i->tsn <= message->end;
3029 frag_i = frag_i->next) {
3031 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
3032 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
3033 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
3034 offset += frag_i->len;
3036 mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num);
3040 return new_tvb;
3043 /* this is not the last fragment,
3044 * so let the user know the frame where the reassembly is
3046 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
3048 proto_tree_add_uint(tree, hf_sctp_reassembled_in, tvb, 0, 0, message->reassembled_in->frame_num);
3049 return NULL;
3052 /* this fragment has not been reassembled, yet
3053 * check now if we can reassemble it
3054 * at first look for the first and last tsn of the msg
3056 for (begin = msg->begins;
3057 begin && begin->fragment->tsn > fragment->tsn;
3058 begin = begin->next);
3060 /* in case begin still is null, set it to first (highest) begin
3061 * maybe the message tsn restart at 0 in between
3063 if (!begin)
3064 begin = msg->begins;
3066 for (end = msg->ends;
3067 end && end->fragment->tsn < fragment->tsn;
3068 end = end->next);
3070 /* in case end still is null, set it to first (lowest) end
3071 * maybe the message tsn restart at 0 in between
3073 if (!end)
3074 end = msg->ends;
3076 if (!begin || !end || !msg->fragments ||
3077 (begin->fragment->tsn > end->fragment->tsn && msg->fragments->tsn)) {
3078 /* begin and end have not been collected, yet
3079 * or there might be a tsn restart but the first fragment hasn't a tsn of 0
3080 * just mark as fragment
3083 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
3085 return NULL;
3088 /* we found possible begin and end
3089 * look for the first fragment and then try to get to the end
3091 first_frag = begin->fragment;
3093 /* while looking if all fragments are there
3094 * we can calculate the overall length that
3095 * we need in case of success
3097 len = first_frag->len;
3099 /* check if begin is past end
3100 * this can happen if there has been a tsn restart
3101 * or we just got the wrong begin and end
3102 * so give it a try
3104 if (begin->fragment->tsn > end->fragment->tsn) {
3105 for (last_frag = first_frag, frag_i = first_frag->next;
3106 frag_i && frag_i->tsn == (last_frag->tsn + 1);
3107 last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
3109 /* check if we reached the last possible tsn
3110 * if yes, restart and continue
3112 if ((last_frag->tsn + 1)) {
3113 /* there are just fragments missing */
3114 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
3116 return NULL;
3119 /* we got all fragments until the last possible tsn
3120 * and the first is 0 if we got here
3123 len += msg->fragments->len;
3124 for (last_frag = msg->fragments, frag_i = last_frag->next;
3125 frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1);
3126 last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
3128 } else {
3129 for (last_frag = first_frag, frag_i = first_frag->next;
3130 frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1);
3131 last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
3134 if (!frag_i || frag_i != end->fragment || frag_i->tsn != (last_frag->tsn + 1)) {
3135 /* we need more fragments. just mark as fragment */
3136 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
3138 return NULL;
3141 /* ok, this message is complete, we can reassemble it
3142 * but at first don't forget to add the length of the last fragment
3144 len += frag_i->len;
3146 message = wmem_new(wmem_file_scope(), sctp_complete_msg);
3147 message->begin = begin->fragment->tsn;
3148 message->end = end->fragment->tsn;
3149 message->reassembled_in = fragment;
3150 message->len = len;
3151 message->data = (unsigned char *)wmem_alloc(wmem_file_scope(), len);
3152 message->next = NULL;
3154 /* now copy all fragments */
3155 if (begin->fragment->tsn > end->fragment->tsn) {
3156 /* a tsn restart has occurred */
3157 for (frag_i = first_frag;
3158 frag_i;
3159 frag_i = frag_i->next) {
3161 if (frag_i->len && frag_i->data)
3162 memcpy(message->data + offset, frag_i->data, frag_i->len);
3163 offset += frag_i->len;
3165 /* release fragment data */
3166 g_free(frag_i->data);
3167 frag_i->data = NULL;
3170 for (frag_i = msg->fragments;
3171 frag_i && frag_i->tsn <= end->fragment->tsn;
3172 frag_i = frag_i->next) {
3174 if (frag_i->len && frag_i->data)
3175 memcpy(message->data + offset, frag_i->data, frag_i->len);
3176 offset += frag_i->len;
3178 /* release fragment data */
3179 g_free(frag_i->data);
3180 frag_i->data = NULL;
3183 } else {
3184 for (frag_i = first_frag;
3185 frag_i && frag_i->tsn <= end->fragment->tsn;
3186 frag_i = frag_i->next) {
3188 if (frag_i->len && frag_i->data)
3189 memcpy(message->data + offset, frag_i->data, frag_i->len);
3190 offset += frag_i->len;
3192 /* release fragment data */
3193 g_free(frag_i->data);
3194 frag_i->data = NULL;
3198 /* save message */
3199 if (!msg->messages) {
3200 msg->messages = message;
3201 } else {
3202 for (last_message = msg->messages;
3203 last_message->next;
3204 last_message = last_message->next);
3205 last_message->next = message;
3208 /* remove begin and end from list */
3209 if (msg->begins == begin) {
3210 msg->begins = begin->next;
3211 } else {
3212 for (beginend = msg->begins;
3213 beginend && beginend->next != begin;
3214 beginend = beginend->next);
3215 if (beginend && beginend->next == begin)
3216 beginend->next = begin->next;
3218 g_free(begin);
3220 if (msg->ends == end) {
3221 msg->ends = end->next;
3222 } else {
3223 for (beginend = msg->ends;
3224 beginend && beginend->next != end;
3225 beginend = beginend->next);
3226 if (beginend && beginend->next == end)
3227 beginend->next = end->next;
3229 g_free(end);
3231 /* create data source */
3232 new_tvb = tvb_new_child_real_data(tvb, message->data, len, len);
3233 add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message");
3235 /* display reassembly info */
3236 item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, ENC_NA);
3237 ptree = proto_item_add_subtree(item, ett_sctp_fragments);
3238 proto_item_append_text(item, " (%u bytes, %u fragments): ",
3239 message->len, message->end - message->begin + 1);
3241 if (message->begin > message->end) {
3242 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit);
3243 frag_i;
3244 frag_i = frag_i->next) {
3246 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
3247 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
3248 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
3249 offset += frag_i->len;
3251 mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num);
3254 for (frag_i = msg->fragments;
3255 frag_i && frag_i->tsn <= message->end;
3256 frag_i = frag_i->next) {
3258 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
3259 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
3260 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
3261 offset += frag_i->len;
3263 mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num);
3265 } else {
3266 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num, u_bit);
3267 frag_i && frag_i->tsn <= message->end;
3268 frag_i = frag_i->next) {
3270 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
3271 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
3272 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
3273 offset += frag_i->len;
3275 mark_frame_as_depended_upon(pinfo->fd, frag_i->frame_num);
3279 /* it's not fragmented anymore */
3280 pinfo->fragmented = false;
3282 return new_tvb;
3285 static exp_pdu_data_t*
3286 create_exp_pdu_table(packet_info *pinfo, tvbuff_t *tvb, const char *table_name, uint32_t table_value)
3288 exp_pdu_data_item_t exp_pdu_data_table_value = {
3289 exp_pdu_data_dissector_table_num_value_size,
3290 exp_pdu_data_dissector_table_num_value_populate_data,
3291 GUINT_TO_POINTER(table_value)
3294 const exp_pdu_data_item_t *sctp_exp_pdu_items[] = {
3295 &exp_pdu_data_src_ip,
3296 &exp_pdu_data_dst_ip,
3297 &exp_pdu_data_port_type,
3298 &exp_pdu_data_src_port,
3299 &exp_pdu_data_dst_port,
3300 &exp_pdu_data_orig_frame_num,
3301 &exp_pdu_data_table_value,
3302 NULL
3305 exp_pdu_data_t *exp_pdu_data = export_pdu_create_tags(pinfo, table_name, EXP_PDU_TAG_DISSECTOR_TABLE_NAME, sctp_exp_pdu_items);
3307 exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
3308 exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
3309 exp_pdu_data->pdu_tvb = tvb;
3311 return exp_pdu_data;
3314 static exp_pdu_data_t*
3315 create_exp_pdu_proto_name(packet_info *pinfo, tvbuff_t *tvb, const char *proto_name)
3317 exp_pdu_data_t *exp_pdu_data = export_pdu_create_common_tags(pinfo, proto_name, EXP_PDU_TAG_DISSECTOR_NAME);
3319 exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
3320 exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
3321 exp_pdu_data->pdu_tvb = tvb;
3323 return exp_pdu_data;
3326 static void
3327 export_sctp_data_chunk(packet_info *pinfo, tvbuff_t *tvb, uint32_t payload_proto_id,
3328 const wmem_list_frame_t *frame)
3330 const char *proto_name = NULL;
3331 exp_pdu_data_t *exp_pdu_data = NULL;
3333 if (!have_tap_listener(exported_pdu_tap)) {
3334 /* Do nothing when there is no export pdu tap listener */
3335 return;
3338 if (enable_ulp_dissection && frame) {
3339 /* get the proto_name of the next frame */
3340 proto_name = proto_get_protocol_filter_name(GPOINTER_TO_UINT(wmem_list_frame_data(frame)));
3343 if (proto_name && (strcmp(proto_name, "data") != 0)) {
3344 /* when we have proto_name and it is not "data" export using the proto_name */
3345 exp_pdu_data = create_exp_pdu_proto_name(pinfo, tvb, proto_name);
3346 } else if (payload_proto_id != 0) {
3347 exp_pdu_data = create_exp_pdu_table(pinfo, tvb, "sctp.ppi", payload_proto_id);
3348 } else if (pinfo->destport != 0) {
3349 exp_pdu_data = create_exp_pdu_table(pinfo, tvb, "sctp.port", pinfo->destport);
3350 } else if (pinfo->srcport != 0) {
3351 exp_pdu_data = create_exp_pdu_table(pinfo, tvb, "sctp.port", pinfo->srcport);
3352 } else {
3353 /* do not export anything when none of the above fileds are available */
3354 return;
3357 tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
3360 static bool
3361 dissect_fragmented_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree,
3362 proto_tree *chunk_tree, uint32_t tsn, uint32_t ppi, uint16_t stream_id,
3363 uint32_t stream_seq_num, uint8_t b_bit, uint8_t e_bit, uint8_t u_bit, bool is_idata)
3365 sctp_fragment *fragment;
3366 tvbuff_t *new_tvb = NULL;
3369 * If this is a short frame, then we can't, and don't, do
3370 * reassembly on it. We just give up.
3372 if (tvb_reported_length(payload_tvb) > tvb_captured_length(payload_tvb))
3373 return true;
3375 /* add fragment to list of known fragments. returns NULL if segment is a duplicate */
3376 fragment = add_fragment(payload_tvb, pinfo, chunk_tree, tsn, stream_id, stream_seq_num, b_bit, e_bit, u_bit, ppi, is_idata);
3378 if (fragment)
3379 new_tvb = fragment_reassembly(payload_tvb, fragment, pinfo, chunk_tree, stream_id, stream_seq_num, u_bit);
3381 /* pass reassembled data to next dissector, if possible */
3382 if (new_tvb){
3383 bool retval;
3384 wmem_list_frame_t *cur = wmem_list_tail(pinfo->layers);
3386 retval = dissect_payload(new_tvb, pinfo, tree, ppi);
3387 export_sctp_data_chunk(pinfo, new_tvb, ppi, wmem_list_frame_next(cur));
3388 return retval;
3391 /* no reassembly done, do nothing */
3392 return true;
3395 static const true_false_string sctp_data_chunk_e_bit_value = {
3396 "Last segment",
3397 "Not the last segment"
3400 static const true_false_string sctp_data_chunk_b_bit_value = {
3401 "First segment",
3402 "Subsequent segment"
3405 static const true_false_string sctp_data_chunk_u_bit_value = {
3406 "Unordered delivery",
3407 "Ordered delivery"
3410 static const true_false_string sctp_data_chunk_i_bit_value = {
3411 "Send SACK immediately",
3412 "Possibly delay SACK"
3415 static bool
3416 dissect_data_chunk(tvbuff_t *chunk_tvb,
3417 uint16_t chunk_length,
3418 packet_info *pinfo,
3419 proto_tree *tree,
3420 proto_tree *chunk_tree,
3421 proto_item *chunk_item,
3422 proto_item *flags_item,
3423 sctp_half_assoc_t *ha,
3424 bool is_idata)
3426 unsigned number_of_ppid;
3427 volatile uint32_t payload_proto_id;
3428 tvbuff_t *payload_tvb;
3429 proto_tree *flags_tree;
3430 uint8_t oct, e_bit, b_bit, u_bit;
3431 uint16_t stream_id;
3432 uint32_t tsn, rawtsn, ppid, stream_seq_num = 0;
3433 proto_item *tsn_item = NULL;
3434 bool call_subdissector = false;
3435 bool is_retransmission;
3436 uint16_t header_length;
3437 uint16_t payload_offset;
3439 static int* const chunk_flags[] = {
3440 &hf_data_chunk_i_bit,
3441 &hf_data_chunk_u_bit,
3442 &hf_data_chunk_b_bit,
3443 &hf_data_chunk_e_bit,
3444 NULL
3447 if (is_idata) {
3448 if (chunk_length < I_DATA_CHUNK_HEADER_LENGTH) {
3449 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, I_DATA_CHUNK_HEADER_LENGTH);
3450 return true;
3452 payload_proto_id = tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET);
3453 } else {
3454 if (chunk_length < DATA_CHUNK_HEADER_LENGTH) {
3455 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, DATA_CHUNK_HEADER_LENGTH);
3456 return true;
3458 payload_proto_id = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET);
3461 /* insert the PPID in the pinfo structure if it is not already there and there is still room */
3462 for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) {
3463 void *tmp = p_get_proto_data(pinfo->pool, pinfo, proto_sctp, number_of_ppid);
3464 ppid = GPOINTER_TO_UINT(tmp);
3465 if ((ppid == LAST_PPID) || (ppid == payload_proto_id))
3466 break;
3468 if ((number_of_ppid < MAX_NUMBER_OF_PPIDS) && (ppid == LAST_PPID))
3469 p_add_proto_data(pinfo->pool, pinfo, proto_sctp, number_of_ppid, GUINT_TO_POINTER(payload_proto_id));
3471 oct = tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET);
3472 e_bit = oct & SCTP_DATA_CHUNK_E_BIT;
3473 b_bit = oct & SCTP_DATA_CHUNK_B_BIT;
3474 u_bit = oct & SCTP_DATA_CHUNK_U_BIT;
3476 tsn = rawtsn = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
3477 if ((show_relative_tsns) && (ha)) {
3478 if (!ha->started) {
3479 ha->first_tsn = tsn;
3480 ha->started = true;
3482 tsn -= ha->first_tsn;
3485 col_append_fstr(pinfo->cinfo, COL_INFO, "(TSN=%" PRIu32 ") ", tsn);
3487 if (chunk_tree) {
3488 if (is_idata)
3489 proto_item_set_len(chunk_item, I_DATA_CHUNK_HEADER_LENGTH);
3490 else
3491 proto_item_set_len(chunk_item, DATA_CHUNK_HEADER_LENGTH);
3493 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
3494 proto_tree_add_bitmask_list(flags_tree, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, chunk_flags, ENC_NA);
3495 if((show_relative_tsns) && (ha)) {
3496 tsn_item = proto_tree_add_uint(chunk_tree, hf_data_chunk_tsn, chunk_tvb, DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH, tsn);
3497 proto_tree_add_item(chunk_tree, hf_data_chunk_tsn_raw, chunk_tvb, DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH, ENC_BIG_ENDIAN);
3499 else {
3500 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);
3502 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);
3503 if (is_idata) {
3504 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);
3505 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);
3506 if (b_bit)
3507 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);
3508 else
3509 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);
3510 } else {
3511 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);
3512 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);
3514 proto_item_append_text(chunk_item, " (%s, ", (u_bit) ? "unordered" : "ordered");
3515 if (b_bit) {
3516 if (e_bit)
3517 proto_item_append_text(chunk_item, "complete");
3518 else
3519 proto_item_append_text(chunk_item, "first");
3520 } else {
3521 if (e_bit)
3522 proto_item_append_text(chunk_item, "last");
3523 else
3524 proto_item_append_text(chunk_item, "middle");
3527 if (is_idata) {
3528 if (b_bit)
3529 proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, MID: %u, payload length: %u byte%s)",
3530 tsn,
3531 tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET),
3532 tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_MID_OFFSET),
3533 chunk_length - I_DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - I_DATA_CHUNK_HEADER_LENGTH, "", "s"));
3534 else
3535 proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, MID: %u, FSN: %u, payload length: %u byte%s)",
3536 tsn,
3537 tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET),
3538 tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_MID_OFFSET),
3539 tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_FSN_OFFSET),
3540 chunk_length - I_DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - I_DATA_CHUNK_HEADER_LENGTH, "", "s"));
3541 } else
3542 proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, SSN: %u, PPID: %u, payload length: %u byte%s)",
3543 tsn,
3544 tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET),
3545 tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET),
3546 payload_proto_id,
3547 chunk_length - DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - DATA_CHUNK_HEADER_LENGTH, "", "s"));
3550 is_retransmission = sctp_tsn(pinfo, chunk_tvb, tsn_item, ha, rawtsn);
3552 if (is_idata) {
3553 header_length = I_DATA_CHUNK_HEADER_LENGTH;
3554 payload_offset = I_DATA_CHUNK_PAYLOAD_OFFSET;
3555 } else {
3556 header_length = DATA_CHUNK_HEADER_LENGTH;
3557 payload_offset = DATA_CHUNK_PAYLOAD_OFFSET;
3559 payload_tvb = tvb_new_subset_length_caplen(chunk_tvb, payload_offset,
3560 MIN(chunk_length - header_length, tvb_captured_length_remaining(chunk_tvb, payload_offset)),
3561 MIN(chunk_length - header_length, tvb_reported_length_remaining(chunk_tvb, payload_offset)));
3563 /* Is this a fragment? */
3564 if (b_bit && e_bit) {
3565 /* No - just call the subdissector. */
3566 if (!is_retransmission)
3567 call_subdissector = true;
3568 } else {
3569 /* Yes. */
3570 pinfo->fragmented = true;
3572 /* if reassembly is off just mark as fragment for next dissector and proceed */
3573 if (!use_reassembly)
3575 /* Don't pass on non-first fragments since the next dissector will
3576 * almost certainly not understand the data.
3578 if (b_bit) {
3579 if (!is_retransmission)
3580 call_subdissector = true;
3581 } else
3582 return false;
3587 if (call_subdissector) {
3588 /* This isn't a fragment or reassembly is off and it's the first fragment */
3590 volatile bool retval = false;
3591 wmem_list_frame_t *cur = wmem_list_tail(pinfo->layers);
3593 TRY {
3594 retval = dissect_payload(payload_tvb, pinfo, tree, payload_proto_id);
3596 CATCH_NONFATAL_ERRORS {
3598 * Somebody threw an exception that means that there was a problem
3599 * dissecting the payload; that means that a dissector was found,
3600 * so we don't need to dissect the payload as data or update the
3601 * protocol or info columns.
3603 * Just show the exception and then continue dissecting chunks.
3605 show_exception(payload_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
3607 ENDTRY;
3609 export_sctp_data_chunk(pinfo, payload_tvb, payload_proto_id, wmem_list_frame_next(cur));
3610 return retval;
3612 } else if (is_retransmission) {
3613 col_append_str(pinfo->cinfo, COL_INFO, "(retransmission) ");
3614 return false;
3615 } else {
3617 /* The logic above should ensure this... */
3618 DISSECTOR_ASSERT(use_reassembly);
3620 stream_id = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
3621 if (is_idata) {
3622 /* The stream_seq_num variable is used to hold the MID, the tsn variable holds the FSN*/
3623 stream_seq_num = tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_MID_OFFSET);
3624 if (b_bit) {
3625 tsn = 0;
3626 } else {
3627 tsn = tvb_get_ntohl(chunk_tvb, I_DATA_CHUNK_FSN_OFFSET);
3628 payload_proto_id = 0;
3630 } else {
3631 /* if unordered set stream_seq_num to 0 for easier handling */
3632 if (u_bit)
3633 stream_seq_num = 0;
3634 else
3635 stream_seq_num = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
3637 /* start reassembly */
3638 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);
3643 #define INIT_CHUNK_INITIATE_TAG_LENGTH 4
3644 #define INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4
3645 #define INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH 2
3646 #define INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH 2
3647 #define INIT_CHUNK_INITIAL_TSN_LENGTH 4
3648 #define INIT_CHUNK_FIXED_PARAMTERS_LENGTH (CHUNK_HEADER_LENGTH + \
3649 INIT_CHUNK_INITIATE_TAG_LENGTH + \
3650 INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH + \
3651 INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH + \
3652 INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH + \
3653 INIT_CHUNK_INITIAL_TSN_LENGTH)
3655 #define INIT_CHUNK_INITIATE_TAG_OFFSET CHUNK_VALUE_OFFSET
3656 #define INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (INIT_CHUNK_INITIATE_TAG_OFFSET + \
3657 INIT_CHUNK_INITIATE_TAG_LENGTH )
3658 #define INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET (INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \
3659 INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH )
3660 #define INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET (INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET + \
3661 INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH )
3662 #define INIT_CHUNK_INITIAL_TSN_OFFSET (INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET + \
3663 INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH )
3664 #define INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET (INIT_CHUNK_INITIAL_TSN_OFFSET + \
3665 INIT_CHUNK_INITIAL_TSN_LENGTH )
3667 static void
3668 // NOLINTNEXTLINE(misc-no-recursion)
3669 dissect_init_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
3671 tvbuff_t *parameters_tvb;
3672 proto_item *hidden_item;
3674 if (chunk_length < INIT_CHUNK_FIXED_PARAMTERS_LENGTH) {
3675 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, INIT_CHUNK_FIXED_PARAMTERS_LENGTH);
3676 return;
3679 if (chunk_tree) {
3680 /* handle fixed parameters */
3681 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);
3682 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);
3683 proto_item_set_hidden(hidden_item);
3684 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);
3685 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);
3686 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);
3687 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);
3689 proto_item_append_text(chunk_item, " (Outbound streams: %u, inbound streams: %u)",
3690 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET),
3691 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET));
3694 /* handle variable parameters */
3695 chunk_length -= INIT_CHUNK_FIXED_PARAMTERS_LENGTH;
3696 parameters_tvb = tvb_new_subset_length_caplen(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET,
3697 MIN(chunk_length, tvb_captured_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)),
3698 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)));
3699 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, true);
3702 static void
3703 // NOLINTNEXTLINE(misc-no-recursion)
3704 dissect_init_ack_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
3706 tvbuff_t *parameters_tvb;
3707 proto_item *hidden_item;
3709 if (chunk_length < INIT_CHUNK_FIXED_PARAMTERS_LENGTH) {
3710 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
3711 chunk_length,
3712 INIT_CHUNK_FIXED_PARAMTERS_LENGTH);
3713 return;
3715 if (chunk_tree) {
3716 /* handle fixed parameters */
3717 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);
3718 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);
3719 proto_item_set_hidden(hidden_item);
3720 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);
3721 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);
3722 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);
3723 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);
3725 proto_item_append_text(chunk_item, " (Outbound streams: %u, inbound streams: %u)",
3726 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET),
3727 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET));
3729 /* handle variable parameters */
3730 chunk_length -= INIT_CHUNK_FIXED_PARAMTERS_LENGTH;
3731 parameters_tvb = tvb_new_subset_length_caplen(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET,
3732 MIN(chunk_length, tvb_captured_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)),
3733 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)));
3734 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, true);
3737 #define SCTP_SACK_CHUNK_NS_BIT 0x01
3738 #define SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4
3739 #define SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4
3740 #define SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH 2
3741 #define SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH 2
3742 #define SACK_CHUNK_GAP_BLOCK_LENGTH 4
3743 #define SACK_CHUNK_GAP_BLOCK_START_LENGTH 2
3744 #define SACK_CHUNK_GAP_BLOCK_END_LENGTH 2
3745 #define SACK_CHUNK_DUP_TSN_LENGTH 4
3747 #define SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET (CHUNK_VALUE_OFFSET + 0)
3748 #define SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET + \
3749 SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH)
3750 #define SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET (SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \
3751 SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH)
3752 #define SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET (SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET + \
3753 SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH)
3754 #define SACK_CHUNK_GAP_BLOCK_OFFSET (SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET + \
3755 SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH)
3758 static void
3759 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)
3761 uint16_t number_of_gap_blocks, number_of_dup_tsns;
3762 uint16_t gap_block_number, dup_tsn_number, start, end;
3763 int gap_block_offset, dup_tsn_offset;
3764 uint32_t cum_tsn_ack;
3765 proto_tree *block_tree;
3766 proto_tree *flags_tree;
3767 proto_item *ctsa_item;
3768 proto_item *a_rwnd_item;
3769 proto_tree *acks_tree;
3770 uint32_t tsns_gap_acked = 0;
3771 uint32_t a_rwnd;
3772 uint16_t last_end;
3774 cum_tsn_ack = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
3775 if((show_relative_tsns) && (ha) && (ha->peer)) {
3776 cum_tsn_ack -= ha->peer->first_tsn;
3779 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_sack_chunk_flags);
3780 proto_tree_add_item(flags_tree, hf_sack_chunk_ns, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3781 if((show_relative_tsns) && (ha) && (ha->peer)) {
3782 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);
3783 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);
3785 else {
3786 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);
3788 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);
3789 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);
3790 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);
3792 a_rwnd = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET);
3793 if (a_rwnd == 0)
3794 expert_add_info(pinfo, a_rwnd_item, &ei_sctp_sack_chunk_adv_rec_window_credit);
3797 /* handle the gap acknowledgement blocks */
3798 number_of_gap_blocks = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET);
3799 gap_block_offset = SACK_CHUNK_GAP_BLOCK_OFFSET;
3801 acks_tree = proto_item_add_subtree(ctsa_item,ett_sctp_ack);
3802 sctp_ack_block(pinfo, ha, chunk_tvb, acks_tree, NULL, cum_tsn_ack);
3804 last_end = 0;
3805 for(gap_block_number = 0; gap_block_number < number_of_gap_blocks; gap_block_number++) {
3806 proto_item *pi;
3807 proto_tree *pt;
3808 uint32_t tsn_start;
3810 start = tvb_get_ntohs(chunk_tvb, gap_block_offset);
3811 end = tvb_get_ntohs(chunk_tvb, gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH);
3812 tsn_start = cum_tsn_ack + start;
3814 block_tree = proto_tree_add_subtree_format(chunk_tree, chunk_tvb, gap_block_offset, SACK_CHUNK_GAP_BLOCK_LENGTH,
3815 ett_sctp_sack_chunk_gap_block, NULL, "Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end);
3817 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);
3818 pt = proto_item_add_subtree(pi, ett_sctp_sack_chunk_gap_block_start);
3819 pi = proto_tree_add_uint(pt, hf_sack_chunk_gap_block_start_tsn,
3820 chunk_tvb, gap_block_offset,SACK_CHUNK_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start);
3821 proto_item_set_generated(pi);
3823 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);
3824 pt = proto_item_add_subtree(pi, ett_sctp_sack_chunk_gap_block_end);
3825 pi = proto_tree_add_uint(pt, hf_sack_chunk_gap_block_end_tsn, chunk_tvb,
3826 gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH, SACK_CHUNK_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end);
3827 proto_item_set_generated(pi);
3829 sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end);
3830 gap_block_offset += SACK_CHUNK_GAP_BLOCK_LENGTH;
3832 tsns_gap_acked += (end+1 - start);
3834 /* Check validity */
3835 if (start > end) {
3836 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed);
3838 if (last_end > start) {
3839 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order);
3841 last_end = end;
3844 if(last_end == 0) {
3845 /* No GapAck -> only show CumAck */
3846 col_append_fstr(pinfo->cinfo, COL_INFO,
3847 "(Ack=%" PRIu32 ", Arwnd=%" PRIu32 ") ",
3848 cum_tsn_ack, a_rwnd);
3850 else {
3851 /* Show CumAck + highest GapAck */
3852 col_append_fstr(pinfo->cinfo, COL_INFO,
3853 "(Ack=%" PRIu32 "+%" PRIu32 ", Arwnd=%" PRIu32 ") ",
3854 cum_tsn_ack, last_end, a_rwnd);
3857 if (tsns_gap_acked) {
3858 proto_item *pi;
3860 pi = proto_tree_add_uint(chunk_tree, hf_sack_chunk_number_tsns_gap_acked, chunk_tvb, 0, 0, tsns_gap_acked);
3861 proto_item_set_generated(pi);
3863 /* If there are a huge number of GAP ACKs, warn the user. 100 is a random
3864 * number: it could be tuned.
3866 if (tsns_gap_acked > 100)
3867 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_number_tsns_gap_acked_100);
3872 /* handle the duplicate TSNs */
3873 number_of_dup_tsns = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET);
3874 dup_tsn_offset = SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * SACK_CHUNK_GAP_BLOCK_LENGTH;
3875 for(dup_tsn_number = 0; dup_tsn_number < number_of_dup_tsns; dup_tsn_number++) {
3876 proto_tree_add_item(chunk_tree, hf_sack_chunk_duplicate_tsn, chunk_tvb, dup_tsn_offset, SACK_CHUNK_DUP_TSN_LENGTH, ENC_BIG_ENDIAN);
3877 dup_tsn_offset += SACK_CHUNK_DUP_TSN_LENGTH;
3880 proto_item_append_text(chunk_item, " (Cumulative TSN: %u, a_rwnd: %u, gaps: %u, duplicate TSNs: %u)",
3881 tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET),
3882 a_rwnd,
3883 number_of_gap_blocks, number_of_dup_tsns);
3886 /* NE: Dissect nr-sack chunk */
3887 #define SCTP_NR_SACK_CHUNK_NS_BIT 0x01
3888 #define NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4
3889 #define NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4
3890 #define NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH 2
3891 #define NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH 2
3892 #define NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH 2
3893 #define NR_SACK_CHUNK_RESERVED_LENGTH 2
3894 #define NR_SACK_CHUNK_GAP_BLOCK_LENGTH 4
3895 #define NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH 2
3896 #define NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH 2
3897 #define NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH 4
3898 #define NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH 2
3899 #define NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH 2
3900 #define NR_SACK_CHUNK_DUP_TSN_LENGTH 4
3902 #define NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET (CHUNK_VALUE_OFFSET + 0)
3903 #define NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET + \
3904 NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH)
3905 #define NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET (NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \
3906 NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH)
3907 #define NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET (NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET + \
3908 NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH)
3909 #define NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET (NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET + \
3910 NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH)
3911 #define NR_SACK_CHUNK_RESERVED_OFFSET (NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET + \
3912 NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH)
3913 #define NR_SACK_CHUNK_GAP_BLOCK_OFFSET (NR_SACK_CHUNK_RESERVED_OFFSET + \
3914 NR_SACK_CHUNK_RESERVED_LENGTH)
3916 static void
3917 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)
3919 uint16_t number_of_gap_blocks, number_of_dup_tsns;
3920 uint16_t number_of_nr_gap_blocks;
3921 uint16_t gap_block_number, nr_gap_block_number, dup_tsn_number, start, end;
3922 int gap_block_offset, nr_gap_block_offset, dup_tsn_offset;
3923 uint32_t cum_tsn_ack;
3924 proto_tree *block_tree;
3925 proto_tree *flags_tree;
3926 proto_item *ctsa_item;
3927 proto_tree *acks_tree;
3928 uint32_t tsns_gap_acked = 0;
3929 uint32_t tsns_nr_gap_acked = 0;
3930 uint16_t last_end;
3932 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_nr_sack_chunk_flags);
3933 proto_tree_add_item(flags_tree, hf_nr_sack_chunk_ns, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3935 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);
3936 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);
3938 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);
3940 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);
3941 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);
3942 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);
3945 number_of_gap_blocks = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET);
3946 gap_block_offset = NR_SACK_CHUNK_GAP_BLOCK_OFFSET;
3947 cum_tsn_ack = tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
3949 acks_tree = proto_item_add_subtree(ctsa_item,ett_sctp_ack);
3950 sctp_ack_block(pinfo, ha, chunk_tvb, acks_tree, NULL, cum_tsn_ack);
3952 last_end = 0;
3953 for(gap_block_number = 0; gap_block_number < number_of_gap_blocks; gap_block_number++) {
3954 proto_item *pi;
3955 proto_tree *pt;
3956 uint32_t tsn_start;
3958 start = tvb_get_ntohs(chunk_tvb, gap_block_offset);
3959 end = tvb_get_ntohs(chunk_tvb, gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH);
3960 tsn_start = cum_tsn_ack + start;
3962 block_tree = proto_tree_add_subtree_format(chunk_tree, chunk_tvb, gap_block_offset, NR_SACK_CHUNK_GAP_BLOCK_LENGTH,
3963 ett_sctp_nr_sack_chunk_gap_block, NULL, "Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end);
3965 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);
3966 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_gap_block_start);
3967 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_gap_block_start_tsn,
3968 chunk_tvb, gap_block_offset,NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start);
3969 proto_item_set_generated(pi);
3971 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);
3972 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_gap_block_end);
3973 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_gap_block_end_tsn, chunk_tvb,
3974 gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end);
3975 proto_item_set_generated(pi);
3977 sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end);
3978 gap_block_offset += NR_SACK_CHUNK_GAP_BLOCK_LENGTH;
3979 tsns_gap_acked += (end - start) + 1;
3981 /* Check validity */
3982 if (start > end) {
3983 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed);
3985 if (last_end > start) {
3986 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order);
3988 last_end = end;
3991 if (tsns_gap_acked) {
3992 proto_item *pi;
3994 pi = proto_tree_add_uint(chunk_tree, hf_nr_sack_chunk_number_tsns_gap_acked, chunk_tvb, 0, 0, tsns_gap_acked);
3995 proto_item_set_generated(pi);
3997 /* If there are a huge number of GAP ACKs, warn the user. 100 is a random
3998 * number: it could be tuned.
4000 if (tsns_gap_acked > 100)
4001 expert_add_info(pinfo, pi, &ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100);
4005 /* NE: handle the nr-sack chunk's nr-gap blocks */
4006 number_of_nr_gap_blocks = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET);
4007 nr_gap_block_offset = gap_block_offset;
4009 last_end = 0;
4010 for(nr_gap_block_number = 0; nr_gap_block_number < number_of_nr_gap_blocks; nr_gap_block_number++) {
4011 proto_item *pi;
4012 proto_tree *pt;
4013 /*uint32_t tsn_start;*/
4015 start = tvb_get_ntohs(chunk_tvb, nr_gap_block_offset);
4016 end = tvb_get_ntohs(chunk_tvb, nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH);
4017 /*tsn_start = cum_tsn_ack + start;*/
4019 block_tree = proto_tree_add_subtree_format(chunk_tree, chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH,
4020 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);
4022 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);
4023 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_nr_gap_block_start);
4024 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_nr_gap_block_start_tsn,
4025 chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start);
4026 proto_item_set_generated(pi);
4028 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);
4029 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_nr_gap_block_end);
4030 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_nr_gap_block_end_tsn, chunk_tvb,
4031 nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end);
4032 proto_item_set_generated(pi);
4034 /* sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end); */
4035 nr_gap_block_offset += NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH;
4036 tsns_nr_gap_acked += (end - start) + 1;
4038 /* Check validity */
4039 if (start > end) {
4040 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed);
4042 if (last_end > start) {
4043 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order);
4045 last_end = end;
4048 if (tsns_nr_gap_acked) {
4049 proto_item *pi;
4051 pi = proto_tree_add_uint(chunk_tree, hf_nr_sack_chunk_number_tsns_nr_gap_acked, chunk_tvb, 0, 0, tsns_nr_gap_acked);
4052 proto_item_set_generated(pi);
4054 /* If there are a huge number of GAP ACKs, warn the user. 100 is a random
4055 * number: it could be tuned.
4057 if (tsns_nr_gap_acked > 100)
4058 expert_add_info(pinfo, pi, &ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100);
4061 /* handle the duplicate TSNs */
4062 number_of_dup_tsns = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET);
4063 dup_tsn_offset = NR_SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * NR_SACK_CHUNK_GAP_BLOCK_LENGTH
4064 + number_of_nr_gap_blocks * NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH;
4067 for(dup_tsn_number = 0; dup_tsn_number < number_of_dup_tsns; dup_tsn_number++) {
4068 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);
4069 dup_tsn_offset += NR_SACK_CHUNK_DUP_TSN_LENGTH;
4072 proto_item_append_text(chunk_item, " (Cumulative TSN: %u, a_rwnd: %u, gaps: %u, nr-gaps: %u, duplicate TSNs: %u)",
4073 tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET),
4074 tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET),
4075 number_of_gap_blocks, number_of_nr_gap_blocks, number_of_dup_tsns);
4078 #define HEARTBEAT_CHUNK_INFO_OFFSET CHUNK_VALUE_OFFSET
4080 static void
4081 // NOLINTNEXTLINE(misc-no-recursion)
4082 dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
4084 tvbuff_t *parameter_tvb;
4086 if (chunk_tree) {
4087 proto_item_append_text(chunk_item, " (Information: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
4088 parameter_tvb = tvb_new_subset_length_caplen(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET,
4089 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_captured_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET)),
4090 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET)));
4091 /* FIXME: Parameters or parameter? */
4092 dissect_parameter(parameter_tvb, pinfo, chunk_tree, NULL, false, true);
4096 #define HEARTBEAT_ACK_CHUNK_INFO_OFFSET CHUNK_VALUE_OFFSET
4098 static void
4099 // NOLINTNEXTLINE(misc-no-recursion)
4100 dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
4102 tvbuff_t *parameter_tvb;
4104 if (chunk_tree) {
4105 proto_item_append_text(chunk_item, " (Information: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
4106 parameter_tvb = tvb_new_subset_length_caplen(chunk_tvb, HEARTBEAT_ACK_CHUNK_INFO_OFFSET,
4107 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_captured_length_remaining(chunk_tvb, HEARTBEAT_ACK_CHUNK_INFO_OFFSET)),
4108 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, HEARTBEAT_ACK_CHUNK_INFO_OFFSET)));
4109 /* FIXME: Parameters or parameter? */
4110 dissect_parameter(parameter_tvb, pinfo, chunk_tree, NULL, false, true);
4114 #define ABORT_CHUNK_FIRST_ERROR_CAUSE_OFFSET 4
4115 #define SCTP_ABORT_CHUNK_T_BIT 0x01
4117 static void
4118 // NOLINTNEXTLINE(misc-no-recursion)
4119 dissect_abort_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *flags_item)
4121 tvbuff_t *causes_tvb;
4122 proto_tree *flags_tree;
4124 sctp_info.vtag_reflected =
4125 (tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_ABORT_CHUNK_T_BIT) != 0;
4127 if (chunk_tree) {
4128 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_abort_chunk_flags);
4129 proto_tree_add_item(flags_tree, hf_abort_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
4130 causes_tvb = tvb_new_subset_length_caplen(chunk_tvb, CHUNK_VALUE_OFFSET,
4131 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_captured_length_remaining(chunk_tvb, CHUNK_VALUE_OFFSET)),
4132 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, CHUNK_VALUE_OFFSET)));
4133 dissect_error_causes(causes_tvb, pinfo, chunk_tree);
4137 #define SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET CHUNK_VALUE_OFFSET
4138 #define SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4
4140 static void
4141 dissect_shutdown_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item)
4143 if (chunk_tree) {
4144 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);
4145 proto_item_append_text(chunk_item, " (Cumulative TSN ack: %u)", tvb_get_ntohl(chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET));
4149 static void
4150 dissect_shutdown_ack_chunk(tvbuff_t *chunk_tvb _U_)
4154 #define ERROR_CAUSE_IND_CAUSES_OFFSET CHUNK_VALUE_OFFSET
4156 static void
4157 // NOLINTNEXTLINE(misc-no-recursion)
4158 dissect_error_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree)
4160 tvbuff_t *causes_tvb;
4162 if (chunk_tree) {
4163 causes_tvb = tvb_new_subset_length_caplen(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET,
4164 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_captured_length_remaining(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET)),
4165 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET)));
4166 dissect_error_causes(causes_tvb, pinfo, chunk_tree);
4170 #define COOKIE_OFFSET CHUNK_VALUE_OFFSET
4172 static void
4173 dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item)
4175 if (chunk_tree) {
4176 proto_tree_add_item(chunk_tree, hf_cookie, chunk_tvb, COOKIE_OFFSET, chunk_length - CHUNK_HEADER_LENGTH, ENC_NA);
4177 proto_item_append_text(chunk_item, " (Cookie length: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
4181 static void
4182 dissect_cookie_ack_chunk(tvbuff_t *chunk_tvb _U_)
4186 #define ECNE_CHUNK_LOWEST_TSN_OFFSET CHUNK_VALUE_OFFSET
4187 #define ECNE_CHUNK_LOWEST_TSN_LENGTH 4
4189 static void
4190 dissect_ecne_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item)
4192 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);
4193 proto_item_append_text(chunk_item, " (Lowest TSN: %u)", tvb_get_ntohl(chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET));
4196 #define CWR_CHUNK_LOWEST_TSN_OFFSET CHUNK_VALUE_OFFSET
4197 #define CWR_CHUNK_LOWEST_TSN_LENGTH 4
4199 static void
4200 dissect_cwr_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item)
4202 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);
4203 proto_item_append_text(chunk_item, " (Lowest TSN: %u)", tvb_get_ntohl(chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET));
4206 #define SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT 0x01
4209 static const true_false_string sctp_shutdown_complete_chunk_t_bit_value = {
4210 "Tag reflected",
4211 "Tag not reflected"
4215 static void
4216 dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *flags_item)
4218 proto_tree *flags_tree;
4220 sctp_info.vtag_reflected =
4221 (tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) != 0;
4223 if (chunk_tree) {
4224 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_shutdown_complete_chunk_flags);
4225 proto_tree_add_item(flags_tree, hf_shutdown_complete_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
4229 #define FORWARD_TSN_CHUNK_TSN_LENGTH 4
4230 #define FORWARD_TSN_CHUNK_SID_LENGTH 2
4231 #define FORWARD_TSN_CHUNK_SSN_LENGTH 2
4232 #define FORWARD_TSN_CHUNK_TSN_OFFSET CHUNK_VALUE_OFFSET
4233 #define FORWARD_TSN_CHUNK_SID_OFFSET 0
4234 #define FORWARD_TSN_CHUNK_SSN_OFFSET (FORWARD_TSN_CHUNK_SID_OFFSET + FORWARD_TSN_CHUNK_SID_LENGTH)
4236 static void
4237 dissect_forward_tsn_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item)
4239 unsigned offset;
4240 uint16_t number_of_affected_streams, affected_stream;
4242 /* FIXME */
4243 if (chunk_length < CHUNK_HEADER_LENGTH + FORWARD_TSN_CHUNK_TSN_LENGTH) {
4244 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
4245 chunk_length,
4246 CHUNK_HEADER_LENGTH + FORWARD_TSN_CHUNK_TSN_LENGTH);
4247 return;
4249 if (chunk_tree) {
4250 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);
4251 number_of_affected_streams = (chunk_length - CHUNK_HEADER_LENGTH - FORWARD_TSN_CHUNK_TSN_LENGTH) /
4252 (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH);
4253 offset = CHUNK_VALUE_OFFSET + FORWARD_TSN_CHUNK_TSN_LENGTH;
4255 for(affected_stream = 0; affected_stream < number_of_affected_streams; affected_stream++) {
4256 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);
4257 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);
4258 offset = offset + (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH);
4260 proto_item_append_text(chunk_item, "(Cumulative TSN: %u)", tvb_get_ntohl(chunk_tvb, FORWARD_TSN_CHUNK_TSN_OFFSET));
4264 #define I_FORWARD_TSN_CHUNK_TSN_LENGTH 4
4265 #define I_FORWARD_TSN_CHUNK_SID_LENGTH 2
4266 #define I_FORWARD_TSN_CHUNK_FLAGS_LENGTH 2
4267 #define I_FORWARD_TSN_CHUNK_MID_LENGTH 4
4268 #define I_FORWARD_TSN_CHUNK_TSN_OFFSET CHUNK_VALUE_OFFSET
4269 #define I_FORWARD_TSN_CHUNK_SID_OFFSET 0
4270 #define I_FORWARD_TSN_CHUNK_FLAGS_OFFSET (I_FORWARD_TSN_CHUNK_SID_OFFSET + I_FORWARD_TSN_CHUNK_SID_LENGTH)
4271 #define I_FORWARD_TSN_CHUNK_MID_OFFSET (I_FORWARD_TSN_CHUNK_FLAGS_OFFSET + I_FORWARD_TSN_CHUNK_FLAGS_LENGTH)
4273 #define SCTP_I_FORWARD_TSN_CHUNK_U_BIT 0x0001
4274 #define SCTP_I_FORWARD_TSN_CHUNK_RES_MASK 0xfffe
4276 static const true_false_string sctp_i_forward_tsn_chunk_u_bit_value = {
4277 "Unordered messages",
4278 "Ordered messages"
4281 static void
4282 dissect_i_forward_tsn_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item)
4284 unsigned offset;
4285 uint16_t number_of_affected_streams, affected_stream;
4286 proto_tree *flags_tree;
4287 proto_item *flags_item = NULL;
4289 /* FIXME */
4290 if (chunk_length < CHUNK_HEADER_LENGTH + I_FORWARD_TSN_CHUNK_TSN_LENGTH) {
4291 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
4292 chunk_length,
4293 CHUNK_HEADER_LENGTH + I_FORWARD_TSN_CHUNK_TSN_LENGTH);
4294 return;
4296 if (chunk_tree) {
4297 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);
4298 number_of_affected_streams = (chunk_length - CHUNK_HEADER_LENGTH - I_FORWARD_TSN_CHUNK_TSN_LENGTH) /
4299 (I_FORWARD_TSN_CHUNK_SID_LENGTH + I_FORWARD_TSN_CHUNK_FLAGS_LENGTH + I_FORWARD_TSN_CHUNK_MID_LENGTH);
4300 offset = CHUNK_VALUE_OFFSET + I_FORWARD_TSN_CHUNK_TSN_LENGTH;
4302 for(affected_stream = 0; affected_stream < number_of_affected_streams; affected_stream++) {
4303 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);
4304 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);
4305 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_i_forward_tsn_chunk_flags);
4306 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);
4307 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);
4308 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);
4309 offset += (I_FORWARD_TSN_CHUNK_SID_LENGTH + I_FORWARD_TSN_CHUNK_FLAGS_LENGTH + I_FORWARD_TSN_CHUNK_MID_LENGTH);
4311 proto_item_append_text(chunk_item, "(Cumulative TSN: %u)", tvb_get_ntohl(chunk_tvb, I_FORWARD_TSN_CHUNK_TSN_OFFSET));
4315 #define RE_CONFIG_PARAMETERS_OFFSET CHUNK_HEADER_LENGTH
4317 static void
4318 // NOLINTNEXTLINE(misc-no-recursion)
4319 dissect_re_config_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item _U_)
4321 tvbuff_t *parameters_tvb;
4323 parameters_tvb = tvb_new_subset_length_caplen(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET,
4324 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_captured_length_remaining(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET)),
4325 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET)));
4326 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false);
4329 #define SHARED_KEY_ID_LENGTH 2
4331 #define SHARED_KEY_ID_OFFSET PARAMETER_VALUE_OFFSET
4332 #define HMAC_ID_OFFSET (SHARED_KEY_ID_OFFSET + SHARED_KEY_ID_LENGTH)
4333 #define HMAC_OFFSET (HMAC_ID_OFFSET + HMAC_ID_LENGTH)
4335 static void
4336 dissect_auth_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item _U_)
4338 unsigned hmac_length;
4340 hmac_length = chunk_length - CHUNK_HEADER_LENGTH - HMAC_ID_LENGTH - SHARED_KEY_ID_LENGTH;
4341 proto_tree_add_item(chunk_tree, hf_shared_key_id, chunk_tvb, SHARED_KEY_ID_OFFSET, SHARED_KEY_ID_LENGTH, ENC_BIG_ENDIAN);
4342 proto_tree_add_item(chunk_tree, hf_hmac_id, chunk_tvb, HMAC_ID_OFFSET, HMAC_ID_LENGTH, ENC_BIG_ENDIAN);
4343 if (hmac_length > 0)
4344 proto_tree_add_item(chunk_tree, hf_hmac, chunk_tvb, HMAC_OFFSET, hmac_length, ENC_NA);
4347 #define SCTP_SEQUENCE_NUMBER_LENGTH 4
4348 #define SEQUENCE_NUMBER_OFFSET CHUNK_VALUE_OFFSET
4349 #define ASCONF_CHUNK_PARAMETERS_OFFSET (SEQUENCE_NUMBER_OFFSET + SCTP_SEQUENCE_NUMBER_LENGTH)
4351 static void
4352 // NOLINTNEXTLINE(misc-no-recursion)
4353 dissect_asconf_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
4355 tvbuff_t *parameters_tvb;
4357 if (chunk_length < CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH) {
4358 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
4359 chunk_length,
4360 CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH);
4361 return;
4363 if (chunk_tree) {
4364 proto_tree_add_item(chunk_tree, hf_asconf_seq_nr, chunk_tvb, SEQUENCE_NUMBER_OFFSET, SCTP_SEQUENCE_NUMBER_LENGTH, ENC_BIG_ENDIAN);
4366 chunk_length -= CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH;
4367 parameters_tvb = tvb_new_subset_length_caplen(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET,
4368 MIN(chunk_length, tvb_captured_length_remaining(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET)),
4369 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET)));
4370 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false);
4373 #define ASCONF_ACK_CHUNK_PARAMETERS_OFFSET (SEQUENCE_NUMBER_OFFSET + SCTP_SEQUENCE_NUMBER_LENGTH)
4375 static void
4376 // NOLINTNEXTLINE(misc-no-recursion)
4377 dissect_asconf_ack_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
4379 tvbuff_t *parameters_tvb;
4381 if (chunk_length < CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH) {
4382 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
4383 chunk_length + CHUNK_HEADER_LENGTH,
4384 CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH);
4385 return;
4387 if (chunk_tree) {
4388 proto_tree_add_item(chunk_tree, hf_asconf_ack_seq_nr, chunk_tvb, SEQUENCE_NUMBER_OFFSET, SCTP_SEQUENCE_NUMBER_LENGTH, ENC_BIG_ENDIAN);
4390 chunk_length -= CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH;
4391 parameters_tvb = tvb_new_subset_length_caplen(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET,
4392 MIN(chunk_length, tvb_captured_length_remaining(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET)),
4393 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET)));
4394 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, false);
4397 #define PKTDROP_CHUNK_BANDWIDTH_LENGTH 4
4398 #define PKTDROP_CHUNK_QUEUESIZE_LENGTH 4
4399 #define PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH 2
4400 #define PKTDROP_CHUNK_RESERVED_SIZE_LENGTH 2
4402 #define PKTDROP_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \
4403 PKTDROP_CHUNK_BANDWIDTH_LENGTH + \
4404 PKTDROP_CHUNK_QUEUESIZE_LENGTH + \
4405 PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH + \
4406 PKTDROP_CHUNK_RESERVED_SIZE_LENGTH)
4408 #define PKTDROP_CHUNK_BANDWIDTH_OFFSET CHUNK_VALUE_OFFSET
4409 #define PKTDROP_CHUNK_QUEUESIZE_OFFSET (PKTDROP_CHUNK_BANDWIDTH_OFFSET + PKTDROP_CHUNK_BANDWIDTH_LENGTH)
4410 #define PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET (PKTDROP_CHUNK_QUEUESIZE_OFFSET + PKTDROP_CHUNK_QUEUESIZE_LENGTH)
4411 #define PKTDROP_CHUNK_RESERVED_SIZE_OFFSET (PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET + PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH)
4412 #define PKTDROP_CHUNK_DATA_FIELD_OFFSET (PKTDROP_CHUNK_RESERVED_SIZE_OFFSET + PKTDROP_CHUNK_RESERVED_SIZE_LENGTH)
4414 #define SCTP_PKTDROP_CHUNK_M_BIT 0x01
4415 #define SCTP_PKTDROP_CHUNK_B_BIT 0x02
4416 #define SCTP_PKTDROP_CHUNK_T_BIT 0x04
4418 static const true_false_string sctp_pktdropk_m_bit_value = {
4419 "Source is a middlebox",
4420 "Source is an endhost"
4423 static const true_false_string sctp_pktdropk_b_bit_value = {
4424 "SCTP checksum was incorrect",
4425 "SCTP checksum was correct"
4428 static const true_false_string sctp_pktdropk_t_bit_value = {
4429 "Packet is truncated",
4430 "Packet is not truncated"
4433 static void
4434 // NOLINTNEXTLINE(misc-no-recursion)
4435 dissect_pktdrop_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
4437 tvbuff_t *data_field_tvb;
4438 proto_tree *flags_tree;
4440 if (chunk_length < PKTDROP_CHUNK_HEADER_LENGTH) {
4441 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
4442 chunk_length,
4443 PKTDROP_CHUNK_HEADER_LENGTH);
4444 return;
4446 chunk_length -= PKTDROP_CHUNK_HEADER_LENGTH;
4447 data_field_tvb = tvb_new_subset_length_caplen(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET,
4448 MIN(chunk_length, tvb_captured_length_remaining(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET)),
4449 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET)));
4451 if (chunk_tree) {
4452 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_pktdrop_chunk_flags);
4454 proto_tree_add_item(flags_tree, hf_pktdrop_chunk_m_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
4455 proto_tree_add_item(flags_tree, hf_pktdrop_chunk_b_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
4456 proto_tree_add_item(flags_tree, hf_pktdrop_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
4457 proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_bandwidth, chunk_tvb, PKTDROP_CHUNK_BANDWIDTH_OFFSET, PKTDROP_CHUNK_BANDWIDTH_LENGTH, ENC_BIG_ENDIAN);
4458 proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_queuesize, chunk_tvb, PKTDROP_CHUNK_QUEUESIZE_OFFSET, PKTDROP_CHUNK_QUEUESIZE_LENGTH, ENC_BIG_ENDIAN);
4459 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);
4460 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);
4462 if (chunk_length > 0) {
4463 /* XXX - We should dissect what we can and catch the BoundsError when we run out of bytes */
4464 if (tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_PKTDROP_CHUNK_T_BIT)
4465 proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_data_field, chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET, chunk_length, ENC_NA);
4466 else {
4467 bool save_in_error_pkt = pinfo->flags.in_error_pkt;
4468 pinfo->flags.in_error_pkt = true;
4470 dissect_sctp_packet(data_field_tvb, pinfo, chunk_tree, true);
4472 pinfo->flags.in_error_pkt = save_in_error_pkt;
4478 static void
4479 dissect_pad_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, proto_tree *chunk_tree, proto_item *chunk_item)
4481 uint16_t value_length;
4483 if (chunk_tree) {
4484 value_length = chunk_length - CHUNK_HEADER_LENGTH;
4485 proto_tree_add_item(chunk_tree, hf_pad_chunk_padding_data, chunk_tvb, CHUNK_VALUE_OFFSET, value_length, ENC_NA);
4486 proto_item_append_text(chunk_item, " (Padding data length: %u byte%s)", value_length, plurality(value_length, "", "s"));
4490 static void
4491 dissect_unknown_chunk(tvbuff_t *chunk_tvb, uint16_t chunk_length, uint8_t chunk_type, proto_tree *chunk_tree, proto_item *chunk_item)
4493 uint16_t value_length;
4495 if (chunk_tree) {
4496 value_length = chunk_length - CHUNK_HEADER_LENGTH;
4497 if (value_length > 0)
4498 proto_tree_add_item(chunk_tree, hf_chunk_value, chunk_tvb, CHUNK_VALUE_OFFSET, value_length, ENC_NA);
4499 proto_item_append_text(chunk_item, " (Type: %u, value length: %u byte%s)", chunk_type, value_length, plurality(value_length, "", "s"));
4503 #define SCTP_CHUNK_BIT_1 0x80
4504 #define SCTP_CHUNK_BIT_2 0x40
4506 static const true_false_string sctp_chunk_bit_1_value = {
4507 "Skip chunk and continue processing of the packet",
4508 "Stop processing of the packet"
4511 static const true_false_string sctp_chunk_bit_2_value = {
4512 "Do report",
4513 "Do not report"
4517 static bool
4518 // NOLINTNEXTLINE(misc-no-recursion)
4519 dissect_sctp_chunk(tvbuff_t *chunk_tvb,
4520 packet_info *pinfo,
4521 proto_tree *tree,
4522 proto_tree *sctp_tree,
4523 sctp_half_assoc_t *ha,
4524 bool useinfo)
4526 uint8_t type;
4527 uint16_t length, padding_length, reported_length;
4528 bool result;
4529 proto_item *flags_item, *chunk_item, *type_item, *length_item;
4530 proto_tree *chunk_tree, *type_tree;
4532 result = false;
4534 /* first extract the chunk header */
4535 type = tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET);
4536 length = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
4537 reported_length = tvb_reported_length(chunk_tvb);
4538 padding_length = reported_length - length;
4540 if (useinfo)
4541 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(type, chunk_type_values, "RESERVED"));
4543 /* create proto_tree stuff */
4544 chunk_item = proto_tree_add_none_format(sctp_tree, hf_chunk, chunk_tvb, CHUNK_HEADER_OFFSET, reported_length,
4545 "%s chunk", val_to_str_const(type, chunk_type_values, "RESERVED"));
4546 chunk_tree = proto_item_add_subtree(chunk_item, ett_sctp_chunk);
4548 if (tree) {
4549 /* then insert the chunk header components into the protocol tree */
4550 type_item = proto_tree_add_item(chunk_tree, hf_chunk_type, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
4551 type_tree = proto_item_add_subtree(type_item, ett_sctp_chunk_type);
4552 proto_tree_add_item(type_tree, hf_chunk_bit_1, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
4553 proto_tree_add_item(type_tree, hf_chunk_bit_2, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
4554 flags_item = proto_tree_add_item(chunk_tree, hf_chunk_flags, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
4555 } else {
4556 chunk_tree = NULL;
4557 chunk_item = NULL;
4558 flags_item = NULL;
4561 if (length < CHUNK_HEADER_LENGTH) {
4562 if (tree) {
4563 proto_tree_add_uint_format_value(chunk_tree, hf_chunk_length, chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH, length,
4564 "%u (invalid, should be >= %u)", length, CHUNK_HEADER_LENGTH);
4565 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", length, CHUNK_HEADER_LENGTH);
4568 if (type == SCTP_DATA_CHUNK_ID)
4569 result = true;
4570 return result;
4573 length_item = proto_tree_add_uint(chunk_tree, hf_chunk_length, chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH, length);
4574 if (length > reported_length && !pinfo->flags.in_error_pkt) {
4575 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);
4576 /* We'll almost certainly throw an exception shortly... */
4580 length -= CHUNK_HEADER_LENGTH;
4583 /* now dissect the chunk value */
4584 increment_dissection_depth(pinfo);
4585 switch(type) {
4586 case SCTP_DATA_CHUNK_ID:
4587 result = dissect_data_chunk(chunk_tvb, length, pinfo, tree, chunk_tree, chunk_item, flags_item, ha, false);
4588 break;
4589 case SCTP_I_DATA_CHUNK_ID:
4590 result = dissect_data_chunk(chunk_tvb, length, pinfo, tree, chunk_tree, chunk_item, flags_item, ha, true);
4591 break;
4592 case SCTP_INIT_CHUNK_ID:
4593 dissect_init_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4594 break;
4595 case SCTP_INIT_ACK_CHUNK_ID:
4596 dissect_init_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4597 break;
4598 case SCTP_SACK_CHUNK_ID:
4599 dissect_sack_chunk(pinfo, chunk_tvb, chunk_tree, chunk_item, flags_item, ha);
4600 break;
4601 case SCTP_HEARTBEAT_CHUNK_ID:
4602 dissect_heartbeat_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4603 break;
4604 case SCTP_HEARTBEAT_ACK_CHUNK_ID:
4605 dissect_heartbeat_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4606 break;
4607 case SCTP_ABORT_CHUNK_ID:
4608 dissect_abort_chunk(chunk_tvb, length, pinfo, chunk_tree, flags_item);
4609 break;
4610 case SCTP_SHUTDOWN_CHUNK_ID:
4611 dissect_shutdown_chunk(chunk_tvb, chunk_tree, chunk_item);
4612 break;
4613 case SCTP_SHUTDOWN_ACK_CHUNK_ID:
4614 dissect_shutdown_ack_chunk(chunk_tvb);
4615 break;
4616 case SCTP_ERROR_CHUNK_ID:
4617 dissect_error_chunk(chunk_tvb, length, pinfo, chunk_tree);
4618 break;
4619 case SCTP_COOKIE_ECHO_CHUNK_ID:
4620 dissect_cookie_echo_chunk(chunk_tvb, length, chunk_tree, chunk_item);
4621 break;
4622 case SCTP_COOKIE_ACK_CHUNK_ID:
4623 dissect_cookie_ack_chunk(chunk_tvb);
4624 break;
4625 case SCTP_ECNE_CHUNK_ID:
4626 dissect_ecne_chunk(chunk_tvb, chunk_tree, chunk_item);
4627 break;
4628 case SCTP_CWR_CHUNK_ID:
4629 dissect_cwr_chunk(chunk_tvb, chunk_tree, chunk_item);
4630 break;
4631 case SCTP_SHUTDOWN_COMPLETE_CHUNK_ID:
4632 dissect_shutdown_complete_chunk(chunk_tvb, chunk_tree, flags_item);
4633 break;
4634 case SCTP_FORWARD_TSN_CHUNK_ID:
4635 dissect_forward_tsn_chunk(chunk_tvb, length, chunk_tree, chunk_item);
4636 break;
4637 case SCTP_RE_CONFIG_CHUNK_ID:
4638 dissect_re_config_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4639 break;
4640 case SCTP_AUTH_CHUNK_ID:
4641 dissect_auth_chunk(chunk_tvb, length, chunk_tree, chunk_item);
4642 break;
4643 case SCTP_NR_SACK_CHUNK_ID:
4644 dissect_nr_sack_chunk(pinfo, chunk_tvb, chunk_tree, chunk_item, flags_item, ha);
4645 break;
4646 case SCTP_ASCONF_ACK_CHUNK_ID:
4647 dissect_asconf_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4648 break;
4649 case SCTP_ASCONF_CHUNK_ID:
4650 dissect_asconf_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
4651 break;
4652 case SCTP_I_FORWARD_TSN_CHUNK_ID:
4653 dissect_i_forward_tsn_chunk(chunk_tvb, length, chunk_tree, chunk_item);
4654 break;
4655 case SCTP_PKTDROP_CHUNK_ID:
4656 col_set_writable(pinfo->cinfo, -1, false);
4657 dissect_pktdrop_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item, flags_item);
4658 col_set_writable(pinfo->cinfo, -1, true);
4659 break;
4660 case SCTP_PAD_CHUNK_ID:
4661 dissect_pad_chunk(chunk_tvb, length, chunk_tree, chunk_item);
4662 break;
4663 default:
4664 dissect_unknown_chunk(chunk_tvb, length, type, chunk_tree, chunk_item);
4665 break;
4667 decrement_dissection_depth(pinfo);
4669 if (padding_length > 0)
4670 proto_tree_add_item(chunk_tree, hf_chunk_padding, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length, ENC_NA);
4672 if (useinfo && ((type == SCTP_DATA_CHUNK_ID) || show_always_control_chunks))
4673 col_set_fence(pinfo->cinfo, COL_INFO);
4675 return result;
4678 static void
4679 // NOLINTNEXTLINE(misc-no-recursion)
4680 dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *sctp_item, proto_tree *sctp_tree, sctp_half_assoc_t *ha, bool encapsulated, proto_item *vt)
4682 proto_item *pi;
4683 tvbuff_t *chunk_tvb;
4684 uint16_t length, total_length, remaining_length;
4685 int last_offset, offset;
4686 bool sctp_item_length_set;
4687 assoc_info_t tmpinfo;
4688 infodata_t id_dir;
4689 bool first_chunk = true;
4691 /* the common header of the datagram is already handled */
4692 last_offset = 0;
4693 offset = COMMON_HEADER_LENGTH;
4694 sctp_item_length_set = false;
4696 while((remaining_length = tvb_reported_length_remaining(tvb, offset))) {
4697 /* extract the chunk length and compute number of padding bytes */
4698 length = tvb_get_ntohs(tvb, offset + CHUNK_LENGTH_OFFSET);
4699 total_length = WS_ROUNDUP_4(length);
4701 /* If we have less bytes than we need, throw an exception while dissecting
4702 * the chunk--not when generating the chunk_tvb below.
4704 total_length = MIN(total_length, remaining_length);
4706 /* create a tvb for the chunk including the padding bytes */
4707 chunk_tvb = tvb_new_subset_length_caplen(tvb, offset, MIN(total_length, tvb_captured_length_remaining(tvb, offset)), total_length);
4709 /* save it in the sctp_info structure */
4710 if (!encapsulated) {
4711 if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS)
4712 sctp_info.tvb[sctp_info.number_of_tvbs++] = chunk_tvb;
4713 else
4714 sctp_info.incomplete = true;
4716 if (first_chunk) {
4717 first_chunk = false;
4718 if (enable_association_indexing) {
4719 tmpinfo.assoc_index = -1;
4720 tmpinfo.direction = 1;
4721 copy_address_shallow(&tmpinfo.saddr, &pinfo->src);
4722 copy_address_shallow(&tmpinfo.daddr, &pinfo->dst);
4723 tmpinfo.sport = sctp_info.sport;
4724 tmpinfo.dport = sctp_info.dport;
4725 bool vtag_reflected = false;
4726 /* Certain chunk types have exceptional Verification Tag handling
4727 * ( see https://datatracker.ietf.org/doc/html/rfc9260#section-8.5.1 )
4728 * XXX: Those chunk types shouldn't be bundled with other chunk types
4729 * (ABORT can be bundled after other control types, but ABORT with the
4730 * T bit set should not be) and there should be an expert info if so.
4731 * Should we use the association from the first chunk or the last
4732 * chunk in such a case?
4734 if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_ABORT_CHUNK_ID) {
4735 if ((tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_ABORT_CHUNK_T_BIT) != 0) {
4736 vtag_reflected = true;
4739 if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_SHUTDOWN_COMPLETE_CHUNK_ID) {
4740 if ((tvb_get_uint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) != 0) {
4741 vtag_reflected = true;
4744 if (vtag_reflected) {
4745 tmpinfo.verification_tag1 = 0;
4746 tmpinfo.verification_tag2 = sctp_info.verification_tag;
4748 else {
4749 tmpinfo.verification_tag1 = sctp_info.verification_tag;
4750 tmpinfo.verification_tag2 = 0;
4752 if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_INIT_CHUNK_ID) {
4753 tmpinfo.verification_tag1 = 0;
4754 tmpinfo.verification_tag2 = tvb_get_ntohl(sctp_info.tvb[0], 4);
4756 if (tvb_get_uint8(chunk_tvb, CHUNK_TYPE_OFFSET) == SCTP_INIT_ACK_CHUNK_ID) {
4757 tmpinfo.verification_tag2 = tvb_get_ntohl(sctp_info.tvb[0], 4);
4760 id_dir = find_assoc_index(&tmpinfo, pinfo);
4761 pi = proto_tree_add_uint(sctp_tree, hf_sctp_assoc_index, tvb, 0 , 0, id_dir.assoc_index);
4762 /* XXX: Should we set these if encapsulated is true or not? */
4763 sctp_info.assoc_index = id_dir.assoc_index;
4764 sctp_info.direction = id_dir.direction;
4766 } else {
4767 pi = proto_tree_add_uint_format_value(sctp_tree, hf_sctp_assoc_index, tvb, 0 , 0, sctp_info.assoc_index, "disabled (enable in preferences)");
4770 proto_item_set_generated(pi);
4771 proto_tree_move_item(sctp_tree, vt, pi);
4774 /* call dissect_sctp_chunk for the actual work */
4775 if (dissect_sctp_chunk(chunk_tvb, pinfo, tree, sctp_tree, ha, !encapsulated) && (tree)) {
4776 proto_item_set_len(sctp_item, offset - last_offset + DATA_CHUNK_HEADER_LENGTH);
4777 sctp_item_length_set = true;
4778 offset += total_length;
4779 last_offset = offset;
4780 if (tvb_reported_length_remaining(tvb, offset) > 0) {
4781 sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, offset, -1, ENC_NA);
4782 sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
4783 sctp_item_length_set = false;
4785 } else {
4786 /* get rid of the dissected chunk */
4787 offset += total_length;
4790 if (!sctp_item_length_set && (tree)) {
4791 proto_item_set_len(sctp_item, offset - last_offset);
4795 static void
4796 // NOLINTNEXTLINE(misc-no-recursion)
4797 dissect_sctp_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bool encapsulated)
4799 uint32_t checksum = 0, calculated_crc32c = 0, calculated_adler32 = 0;
4800 uint16_t source_port, destination_port;
4801 unsigned captured_length, reported_length;
4802 bool crc32c_correct = false, adler32_correct = false;
4803 proto_item *sctp_item, *hidden_item;
4804 proto_tree *sctp_tree;
4805 uint32_t vtag;
4806 sctp_half_assoc_t *ha = NULL;
4807 proto_item *vt = NULL;
4809 captured_length = tvb_captured_length(tvb);
4810 reported_length = tvb_reported_length(tvb);
4811 checksum = tvb_get_ntohl(tvb, CHECKSUM_OFFSET);
4812 sctp_info.checksum_zero = (checksum == 0);
4814 /* Only try to checksum the packet if we have all of it */
4815 if ((captured_length == reported_length) &&
4816 (captured_length >= COMMON_HEADER_LENGTH)) {
4818 switch(sctp_checksum) {
4819 case SCTP_CHECKSUM_NONE:
4820 break;
4821 case SCTP_CHECKSUM_ADLER32:
4822 calculated_adler32 = sctp_adler32(tvb, captured_length);
4823 adler32_correct = (checksum == calculated_adler32);
4824 sctp_info.adler32_calculated = true;
4825 sctp_info.adler32_correct = adler32_correct;
4826 break;
4827 case SCTP_CHECKSUM_CRC32C:
4828 calculated_crc32c = sctp_crc32c(tvb, captured_length);
4829 crc32c_correct = (checksum == calculated_crc32c);
4830 sctp_info.crc32c_calculated = true;
4831 sctp_info.crc32c_correct = crc32c_correct;
4832 break;
4833 case SCTP_CHECKSUM_AUTOMATIC:
4834 calculated_adler32 = sctp_adler32(tvb, captured_length);
4835 adler32_correct = (checksum == calculated_adler32);
4836 calculated_crc32c = sctp_crc32c(tvb, captured_length);
4837 crc32c_correct = (checksum == calculated_crc32c);
4838 sctp_info.adler32_calculated = true;
4839 sctp_info.adler32_correct = adler32_correct;
4840 sctp_info.crc32c_calculated = true;
4841 sctp_info.crc32c_correct = crc32c_correct;
4842 break;
4846 source_port = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET);
4847 destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET);
4848 vtag = tvb_get_ntohl(tvb,VERIFICATION_TAG_OFFSET);
4850 ha = get_half_assoc(pinfo, source_port, destination_port, vtag);
4852 /* In the interest of speed, if "tree" is NULL, don't do any work not
4853 necessary to generate protocol tree items. */
4854 if (tree) {
4856 /* create the sctp protocol tree */
4857 if (show_port_numbers)
4858 sctp_item = proto_tree_add_protocol_format(tree, proto_sctp, tvb, 0, -1,
4859 "Stream Control Transmission Protocol, Src Port: %s (%u), Dst Port: %s (%u)",
4860 sctp_port_to_display(pinfo->pool, source_port), source_port,
4861 sctp_port_to_display(pinfo->pool, destination_port), destination_port);
4862 else
4863 sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, 0, -1, ENC_NA);
4865 sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
4867 /* add the components of the common header to the protocol tree */
4868 proto_tree_add_item(sctp_tree, hf_source_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, ENC_BIG_ENDIAN);
4869 proto_tree_add_item(sctp_tree, hf_destination_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, ENC_BIG_ENDIAN);
4870 vt = proto_tree_add_item(sctp_tree, hf_verification_tag, tvb, VERIFICATION_TAG_OFFSET, VERIFICATION_TAG_LENGTH, ENC_BIG_ENDIAN);
4871 hidden_item = proto_tree_add_item(sctp_tree, hf_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, ENC_BIG_ENDIAN);
4872 proto_item_set_hidden(hidden_item);
4873 hidden_item = proto_tree_add_item(sctp_tree, hf_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, ENC_BIG_ENDIAN);
4874 proto_item_set_hidden(hidden_item);
4875 } else {
4876 sctp_tree = NULL;
4877 sctp_item = NULL;
4880 if (captured_length == reported_length) {
4881 /* We have the whole packet */
4883 switch(sctp_checksum) {
4884 case SCTP_CHECKSUM_NONE:
4885 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, 0,
4886 ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
4887 break;
4888 case SCTP_CHECKSUM_ADLER32:
4889 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_adler, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_adler32,
4890 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
4891 break;
4892 case SCTP_CHECKSUM_CRC32C:
4893 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_crc32c, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_crc32c,
4894 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
4895 break;
4896 case SCTP_CHECKSUM_AUTOMATIC:
4897 if ((adler32_correct) && !(crc32c_correct))
4898 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_adler, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_adler32,
4899 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
4900 else if ((!adler32_correct) && (crc32c_correct))
4901 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_crc32c, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_crc32c,
4902 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
4903 else {
4904 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_adler, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_adler32,
4905 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
4906 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum_crc32c, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, calculated_crc32c,
4907 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
4909 break;
4911 } else {
4912 /* We don't have the whole packet so we can't verify the checksum */
4913 proto_tree_add_checksum(sctp_tree, tvb, CHECKSUM_OFFSET, hf_checksum, hf_checksum_status, &ei_sctp_bad_sctp_checksum, pinfo, 0,
4914 ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
4917 /* add all chunks of the sctp datagram to the protocol tree */
4918 dissect_sctp_chunks(tvb, pinfo, tree, sctp_item, sctp_tree, ha, encapsulated, vt);
4922 static bool
4923 capture_sctp(const unsigned char *pd _U_, int offset _U_, int len _U_, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_)
4925 capture_dissector_increment_count(cpinfo, proto_sctp);
4926 return true;
4929 static int
4930 dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
4932 uint16_t source_port, destination_port;
4933 unsigned number_of_ppid;
4935 /* Extract the common header */
4936 source_port = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET);
4937 destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET);
4939 /* update pi structure */
4940 pinfo->ptype = PT_SCTP;
4941 pinfo->srcport = source_port;
4942 pinfo->destport = destination_port;
4944 /* make entry in the Protocol column on summary display */
4945 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCTP");
4947 /* Clear entries in Info column on summary display */
4948 col_clear(pinfo->cinfo, COL_INFO);
4951 for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) {
4952 p_add_proto_data(pinfo->pool, pinfo, proto_sctp, number_of_ppid, GUINT_TO_POINTER(LAST_PPID));
4955 /* The tvb array in struct _sctp_info is huge: currently 2k pointers.
4956 * We know (by the value of 'number_of_tvbs') which of these entries have
4957 * been used, so don't memset() the array. This saves us from zeroing out
4958 * 8k (4-byte pointers) or 16k (8-byte pointers) of memory every time we
4959 * dissect a packet (saving quite a bit of time!).
4961 sctp_info.incomplete = 0;
4962 sctp_info.adler32_calculated = 0;
4963 sctp_info.adler32_correct = 0;
4964 sctp_info.crc32c_calculated = 0;
4965 sctp_info.crc32c_correct = 0;
4966 sctp_info.vtag_reflected = 0;
4967 sctp_info.number_of_tvbs = 0;
4968 sctp_info.verification_tag = tvb_get_ntohl(tvb, VERIFICATION_TAG_OFFSET);
4969 /* Initialize these to unknown */
4970 sctp_info.assoc_index = -1;
4971 sctp_info.direction = ASSOC_NOT_FOUND;
4973 sctp_info.sport = pinfo->srcport;
4974 sctp_info.dport = pinfo->destport;
4975 set_address(&sctp_info.ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
4976 set_address(&sctp_info.ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
4978 p_add_proto_data(pinfo->pool, pinfo, hf_source_port, pinfo->curr_layer_num, GUINT_TO_POINTER(pinfo->srcport));
4979 p_add_proto_data(pinfo->pool, pinfo, hf_destination_port, pinfo->curr_layer_num, GUINT_TO_POINTER(pinfo->destport));
4981 TRY {
4982 dissect_sctp_packet(tvb, pinfo, tree, false);
4985 FINALLY {
4986 if (!pinfo->flags.in_error_pkt && sctp_info.number_of_tvbs > 0)
4987 /* XXX: If a (only present in an expired Internet-Draft)
4988 * PKTDROP chunk is present, that shouldn't stop us from
4989 * tapping the information from the outer encapsulation,
4990 * but we'd have to be careful about not updating sctp_info
4991 * with information from the encapsulated packet.
4993 tap_queue_packet(sctp_tap, pinfo, &sctp_info);
4996 ENDTRY;
4998 return tvb_captured_length(tvb);
5001 /* Register the protocol with Wireshark */
5002 void
5003 proto_register_sctp(void)
5006 /* Setup list of header fields */
5007 static hf_register_info hf[] = {
5008 { &hf_source_port, { "Source port", "sctp.srcport", FT_UINT16, BASE_PT_SCTP, NULL, 0x0, NULL, HFILL } },
5009 { &hf_destination_port, { "Destination port", "sctp.dstport", FT_UINT16, BASE_PT_SCTP, NULL, 0x0, NULL, HFILL } },
5010 { &hf_port, { "Port", "sctp.port", FT_UINT16, BASE_PT_SCTP, NULL, 0x0, NULL, HFILL } },
5011 { &hf_verification_tag, { "Verification tag", "sctp.verification_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5012 { &hf_checksum, { "Checksum", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5013 { &hf_checksum_adler, { "Checksum (Adler)", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5014 { &hf_checksum_crc32c, { "Checksum (CRC32C)", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5015 { &hf_checksum_status, { "Checksum Status", "sctp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL } },
5016 { &hf_chunk, { "Chunk", "sctp.chunk", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5017 { &hf_chunk_type, { "Chunk type", "sctp.chunk_type", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } },
5018 { &hf_chunk_flags, { "Chunk flags", "sctp.chunk_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5019 { &hf_chunk_bit_1, { "Bit", "sctp.chunk_bit_1", FT_BOOLEAN, 8, TFS(&sctp_chunk_bit_1_value), SCTP_CHUNK_BIT_1, NULL, HFILL } },
5020 { &hf_chunk_bit_2, { "Bit", "sctp.chunk_bit_2", FT_BOOLEAN, 8, TFS(&sctp_chunk_bit_2_value), SCTP_CHUNK_BIT_2, NULL, HFILL } },
5021 { &hf_chunk_length, { "Chunk length", "sctp.chunk_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5022 { &hf_chunk_padding, { "Chunk padding", "sctp.chunk_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5023 { &hf_chunk_value, { "Chunk value", "sctp.chunk_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5024 { &hf_cookie, { "Cookie", "sctp.cookie", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5025 { &hf_initiate_tag, { "Initiate tag", "sctp.initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5026 { &hf_init_chunk_initiate_tag, { "Initiate tag", "sctp.init_initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5027 { &hf_init_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.init_credit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5028 { &hf_init_chunk_number_of_outbound_streams, { "Number of outbound streams", "sctp.init_nr_out_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5029 { &hf_init_chunk_number_of_inbound_streams, { "Number of inbound streams", "sctp.init_nr_in_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5030 { &hf_init_chunk_initial_tsn, { "Initial TSN", "sctp.init_initial_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5031 { &hf_initack_chunk_initiate_tag, { "Initiate tag", "sctp.initack_initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5032 { &hf_initack_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.initack_credit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5033 { &hf_initack_chunk_number_of_outbound_streams, { "Number of outbound streams", "sctp.initack_nr_out_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5034 { &hf_initack_chunk_number_of_inbound_streams, { "Number of inbound streams", "sctp.initack_nr_in_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5035 { &hf_initack_chunk_initial_tsn, { "Initial TSN", "sctp.initack_initial_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5036 { &hf_data_chunk_tsn, { "Transmission sequence number (relative)", "sctp.data_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5037 { &hf_data_chunk_tsn_raw, { "Transmission sequence number (absolute)", "sctp.data_tsn_raw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5038 { &hf_data_chunk_stream_id, { "Stream identifier", "sctp.data_sid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5039 { &hf_data_chunk_stream_seq_number, { "Stream sequence number", "sctp.data_ssn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5040 { &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 } },
5041 { &hf_idata_chunk_reserved, { "Reserved", "sctp.data_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5042 { &hf_idata_chunk_mid, { "Message identifier", "sctp.data_mid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5043 { &hf_idata_chunk_fsn, { "Fragment sequence number", "sctp.data_fsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5044 { &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 } },
5045 { &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 } },
5046 { &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 } },
5047 { &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 } },
5048 { &hf_sack_chunk_ns, { "Nonce sum", "sctp.sack_nonce_sum", FT_UINT8, BASE_DEC, NULL, SCTP_SACK_CHUNK_NS_BIT, NULL, HFILL } },
5049 { &hf_sack_chunk_cumulative_tsn_ack, { "Cumulative TSN ACK (relative)", "sctp.sack_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5050 { &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 } },
5051 { &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 } },
5052 { &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 } },
5053 { &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 } },
5054 { &hf_sack_chunk_gap_block_start, { "Start", "sctp.sack_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5055 { &hf_sack_chunk_gap_block_start_tsn, { "Start TSN", "sctp.sack_gap_block_start_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5056 { &hf_sack_chunk_gap_block_end, { "End", "sctp.sack_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5057 { &hf_sack_chunk_gap_block_end_tsn, { "End TSN", "sctp.sack_gap_block_end_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5058 { &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 } },
5059 { &hf_sack_chunk_duplicate_tsn, { "Duplicate TSN", "sctp.sack_duplicate_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5060 { &hf_nr_sack_chunk_ns, { "Nonce sum", "sctp.nr_sack_nonce_sum", FT_UINT8, BASE_DEC, NULL, SCTP_NR_SACK_CHUNK_NS_BIT, NULL, HFILL } },
5061 { &hf_nr_sack_chunk_cumulative_tsn_ack, { "Cumulative TSN ACK", "sctp.nr_sack_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5062 { &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 } },
5063 { &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 } },
5064 { &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 } },
5065 { &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 } },
5066 { &hf_nr_sack_chunk_reserved, { "Reserved", "sctp.nr_sack_reserved", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5067 { &hf_nr_sack_chunk_gap_block_start, { "Start", "sctp.nr_sack_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5068 { &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 } },
5069 { &hf_nr_sack_chunk_gap_block_end, { "End", "sctp.nr_sack_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5070 { &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 } },
5071 { &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 } },
5072 { &hf_nr_sack_chunk_nr_gap_block_start, { "Start", "sctp.nr_sack_nr_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5073 { &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 } },
5074 { &hf_nr_sack_chunk_nr_gap_block_end, { "End", "sctp.nr_sack_nr_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5075 { &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 } },
5076 { &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 } },
5077 { &hf_nr_sack_chunk_duplicate_tsn, { "Duplicate TSN", "sctp.nr_sack_duplicate_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5078 { &hf_shutdown_chunk_cumulative_tsn_ack, { "Cumulative TSN Ack", "sctp.shutdown_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5079 { &hf_ecne_chunk_lowest_tsn, { "Lowest TSN", "sctp.ecne_lowest_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5080 { &hf_cwr_chunk_lowest_tsn, { "Lowest TSN", "sctp.cwr_lowest_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5081 { &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 } },
5082 { &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 } },
5083 { &hf_forward_tsn_chunk_tsn, { "New cumulative TSN", "sctp.forward_tsn_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5084 { &hf_forward_tsn_chunk_sid, { "Stream identifier", "sctp.forward_tsn_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5085 { &hf_forward_tsn_chunk_ssn, { "Stream sequence number", "sctp.forward_tsn_ssn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5086 { &hf_i_forward_tsn_chunk_tsn, { "New cumulative TSN", "sctp.i_forward_tsn_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5087 { &hf_i_forward_tsn_chunk_sid, { "Stream identifier", "sctp.i_forward_tsn_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5088 { &hf_i_forward_tsn_chunk_flags, { "Flags", "sctp.i_forward_tsn_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5089 { &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 } },
5090 { &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 } },
5091 { &hf_i_forward_tsn_chunk_mid, { "Message identifier", "sctp.forward_tsn_mid", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5092 { &hf_parameter_type, { "Parameter type", "sctp.parameter_type", FT_UINT16, BASE_HEX, VALS(parameter_identifier_values), 0x0, NULL, HFILL } },
5093 { &hf_parameter_length, { "Parameter length", "sctp.parameter_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5094 { &hf_parameter_value, { "Parameter value", "sctp.parameter_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5095 { &hf_parameter_padding, { "Parameter padding", "sctp.parameter_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5096 { &hf_parameter_bit_1, { "Bit", "sctp.parameter_bit_1", FT_BOOLEAN, 16, TFS(&sctp_parameter_bit_1_value), SCTP_PARAMETER_BIT_1, NULL, HFILL } },
5097 { &hf_parameter_bit_2, { "Bit", "sctp.parameter_bit_2", FT_BOOLEAN, 16, TFS(&sctp_parameter_bit_2_value), SCTP_PARAMETER_BIT_2, NULL, HFILL } },
5098 { &hf_ipv4_address, { "IP Version 4 address", "sctp.parameter_ipv4_address", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5099 { &hf_ipv6_address, { "IP Version 6 address", "sctp.parameter_ipv6_address", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5100 { &hf_heartbeat_info, { "Heartbeat information", "sctp.parameter_heartbeat_information", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5101 { &hf_state_cookie, { "State cookie", "sctp.parameter_state_cookie", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5102 { &hf_cookie_preservative_increment, { "Suggested Cookie life-span increment (msec)", "sctp.parameter_cookie_preservative_incr", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5103 { &hf_hostname, { "Hostname", "sctp.parameter_hostname", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5104 { &hf_supported_address_type, { "Supported address type", "sctp.parameter_supported_address_type", FT_UINT16, BASE_DEC, VALS(address_types_values), 0x0, NULL, HFILL } },
5105 { &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 } },
5106 { &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 } },
5107 { &hf_senders_last_assigned_tsn, { "Senders last assigned TSN", "sctp.parameter_senders_last_assigned_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5108 { &hf_senders_next_tsn, { "Senders next TSN", "sctp.parameter_senders_next_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5109 { &hf_receivers_next_tsn, { "Receivers next TSN", "sctp.parameter_receivers_next_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5110 { &hf_stream_reset_rsp_result, { "Result", "sctp.parameter_reconfig_response_result", FT_UINT32, BASE_DEC, VALS(stream_reset_result_values), 0x0, NULL, HFILL } },
5111 { &hf_stream_reset_sid, { "Stream Identifier", "sctp.parameter_reconfig_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5112 { &hf_add_outgoing_streams_number_streams, { "Number of streams", "sctp.parameter_add_outgoing_streams_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5113 { &hf_add_outgoing_streams_reserved, { "Reserved", "sctp.parameter_add_outgoing_streams_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5114 { &hf_add_incoming_streams_number_streams, { "Number of streams", "sctp.parameter_add_incoming_streams_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5115 { &hf_add_incoming_streams_reserved, { "Reserved", "sctp.parameter_add_incoming_streams_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5116 { &hf_asconf_seq_nr, { "Sequence number", "sctp.asconf_seq_nr_number", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5117 { &hf_asconf_ack_seq_nr, { "Sequence number", "sctp.asconf_ack_seq_nr_number", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5118 { &hf_correlation_id, { "Correlation_id", "sctp.correlation_id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5119 { &hf_adap_indication, { "Indication", "sctp.adaptation_layer_indication", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
5120 { &hf_zero_checksum_edmid, { "Error Detection Method Identifier", "sctp.edmid", FT_UINT32, BASE_DEC, VALS(edmid_values), 0x0, NULL, HFILL } },
5121 { &hf_random_number, { "Random number", "sctp.random_number", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5122 { &hf_chunks_to_auth, { "Chunk type", "sctp.chunk_type_to_auth", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } },
5123 { &hf_hmac_id, { "HMAC identifier", "sctp.hmac_id", FT_UINT16, BASE_DEC, VALS(hmac_id_values), 0x0, NULL, HFILL } },
5124 { &hf_hmac, { "HMAC", "sctp.hmac", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5125 { &hf_shared_key_id, { "Shared key identifier", "sctp.shared_key_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5126 { &hf_supported_chunk_type, { "Supported chunk type", "sctp.supported_chunk_type", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } },
5127 { &hf_cause_code, { "Cause code", "sctp.cause_code", FT_UINT16, BASE_HEX, VALS(cause_code_values), 0x0, NULL, HFILL } },
5128 { &hf_cause_length, { "Cause length", "sctp.cause_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5129 { &hf_cause_info, { "Cause information", "sctp.cause_information", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5130 { &hf_cause_padding, { "Cause padding", "sctp.cause_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5131 { &hf_cause_stream_identifier, { "Stream identifier", "sctp.cause_stream_identifier", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5132 { &hf_cause_reserved, { "Reserved", "sctp.cause_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5133 { &hf_cause_number_of_missing_parameters, { "Number of missing parameters", "sctp.cause_nr_of_missing_parameters", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5134 { &hf_cause_missing_parameter_type, { "Missing parameter type", "sctp.cause_missing_parameter_type", FT_UINT16, BASE_HEX, VALS(parameter_identifier_values), 0x0, NULL, HFILL } },
5135 { &hf_cause_measure_of_staleness, { "Measure of staleness in usec", "sctp.cause_measure_of_staleness", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5136 { &hf_cause_tsn, { "TSN", "sctp.cause_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5137 { &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 } },
5138 { &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 } },
5139 { &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 } },
5140 { &hf_pktdrop_chunk_bandwidth, { "Bandwidth", "sctp.pktdrop_bandwidth", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5141 { &hf_pktdrop_chunk_queuesize, { "Queuesize", "sctp.pktdrop_queuesize", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5142 { &hf_pktdrop_chunk_truncated_length, { "Truncated length", "sctp.pktdrop_truncated_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5143 { &hf_pktdrop_chunk_reserved, { "Reserved", "sctp.pktdrop_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5144 { &hf_pktdrop_chunk_data_field, { "Data field", "sctp.pktdrop_datafield", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5145 { &hf_pad_chunk_padding_data, { "Padding data", "sctp.padding_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5147 { &hf_sctp_fragment, { "SCTP Fragment", "sctp.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5148 { &hf_sctp_fragments, { "Reassembled SCTP Fragments", "sctp.fragments", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5149 { &hf_sctp_reassembled_in, { "Reassembled Message in frame", "sctp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5150 { &hf_sctp_duplicate, { "Fragment already seen in frame", "sctp.duplicate", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5152 { &hf_sctp_data_rtt, { "The RTT to SACK was", "sctp.data_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5153 { &hf_sctp_sack_rtt, { "The RTT since DATA was", "sctp.sack_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5154 { &hf_sctp_rto, { "Retransmitted after", "sctp.retransmission_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5155 { &hf_sctp_retransmission, { "This TSN is a retransmission of one in frame", "sctp.retransmission", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5156 { &hf_sctp_retransmitted, { "This TSN is retransmitted in frame", "sctp.retransmitted", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5157 { &hf_sctp_retransmitted_count, { "TSN was retransmitted this many times", "sctp.retransmitted_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5158 { &hf_sctp_acked, { "This chunk is acked in frame", "sctp.acked", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5159 { &hf_sctp_ack_tsn, { "Acknowledges TSN", "sctp.ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
5160 { &hf_sctp_ack_frame, { "Acknowledges TSN in frame", "sctp.ack_frame", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL } },
5161 { &hf_sctp_retransmitted_after_ack, { "Chunk was acked prior to retransmission", "sctp.retransmitted_after_ack", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
5162 { &hf_sctp_assoc_index, { "Association index", "sctp.assoc_index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }
5166 /* Setup protocol subtree array */
5167 static int *ett[] = {
5168 &ett_sctp,
5169 &ett_sctp_chunk,
5170 &ett_sctp_chunk_parameter,
5171 &ett_sctp_chunk_cause,
5172 &ett_sctp_chunk_type,
5173 &ett_sctp_data_chunk_flags,
5174 &ett_sctp_sack_chunk_flags,
5175 &ett_sctp_nr_sack_chunk_flags,
5176 &ett_sctp_abort_chunk_flags,
5177 &ett_sctp_shutdown_complete_chunk_flags,
5178 &ett_sctp_pktdrop_chunk_flags,
5179 &ett_sctp_parameter_type,
5180 &ett_sctp_sack_chunk_gap_block,
5181 &ett_sctp_sack_chunk_gap_block_start,
5182 &ett_sctp_sack_chunk_gap_block_end,
5183 &ett_sctp_nr_sack_chunk_gap_block,
5184 &ett_sctp_nr_sack_chunk_gap_block_start,
5185 &ett_sctp_nr_sack_chunk_gap_block_end,
5186 &ett_sctp_nr_sack_chunk_nr_gap_block,
5187 &ett_sctp_nr_sack_chunk_nr_gap_block_start,
5188 &ett_sctp_nr_sack_chunk_nr_gap_block_end,
5189 &ett_sctp_unrecognized_parameter_parameter,
5190 &ett_sctp_i_forward_tsn_chunk_flags,
5191 &ett_sctp_fragments,
5192 &ett_sctp_fragment,
5193 &ett_sctp_ack,
5194 &ett_sctp_acked,
5195 &ett_sctp_tsn,
5196 &ett_sctp_tsn_retransmission,
5197 &ett_sctp_tsn_retransmitted_count,
5198 &ett_sctp_tsn_retransmitted
5201 static ei_register_info ei[] = {
5202 { &ei_sctp_tsn_retransmitted, { "sctp.retransmission.expert", PI_SEQUENCE, PI_NOTE, "Retransmitted TSN", EXPFILL }},
5203 { &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 }},
5204 { &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 }},
5205 { &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 }},
5206 { &ei_sctp_parameter_length, { "sctp.parameter_length.bad", PI_MALFORMED, PI_ERROR, "Parameter length bad", EXPFILL }},
5207 { &ei_sctp_sack_chunk_adv_rec_window_credit, { "sctp.sack_a_rwnd.expert", PI_SEQUENCE, PI_NOTE, "Zero Advertised Receiver Window Credit", EXPFILL }},
5208 { &ei_sctp_sack_chunk_gap_block_malformed, { "sctp.sack_gap_block_malformed", PI_PROTOCOL, PI_ERROR, "Malformed gap block.", EXPFILL }},
5209 { &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 }},
5210 { &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 }},
5211 { &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 }},
5212 { &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 }},
5213 { &ei_sctp_chunk_length_bad, { "sctp.chunk_length.bad", PI_MALFORMED, PI_ERROR, "Chunk length bad", EXPFILL }},
5214 { &ei_sctp_bad_sctp_checksum, { "sctp.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad SCTP checksum.", EXPFILL }},
5217 static const enum_val_t sctp_checksum_options[] = {
5218 { "none", "None", SCTP_CHECKSUM_NONE },
5219 { "adler-32", "Adler 32", SCTP_CHECKSUM_ADLER32 },
5220 { "crc-32c", "CRC 32c", SCTP_CHECKSUM_CRC32C },
5221 { "automatic", "Automatic", SCTP_CHECKSUM_AUTOMATIC},
5222 { NULL, NULL, 0 }
5225 /* Decode As handling */
5226 static build_valid_func sctp_da_src_values[1] = {sctp_src_value};
5227 static build_valid_func sctp_da_dst_values[1] = {sctp_dst_value};
5228 static build_valid_func sctp_da_both_values[2] = {sctp_src_value, sctp_dst_value};
5229 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}};
5230 static decode_as_t sctp_da_port = {"sctp", "sctp.port", 3, 2, sctp_da_port_values, "SCTP", "port(s) as",
5231 decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
5233 static build_valid_func sctp_da_ppi_build_value1[1] = {sctp_ppi_value1};
5234 static build_valid_func sctp_da_ppi_build_value2[1] = {sctp_ppi_value2};
5235 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}};
5236 static decode_as_t sctp_da_ppi = {"sctp", "sctp.ppi", 2, 0, sctp_da_ppi_values, "SCTP", NULL,
5237 decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
5239 /* UAT for header fields */
5240 static uat_field_t custom_types_uat_fields[] = {
5241 UAT_FLD_NONE(type_fields, type_id, "Chunk ID", "IANA chunk type ID"),
5242 UAT_FLD_CSTRING(type_fields, type_name, "Type name", "Chunk Type name"),
5243 UAT_FLD_VS(type_fields, type_enable, "Visibility", chunk_enabled, "Hide or show the type in the chunk statistics"),
5244 UAT_END_FIELDS
5247 module_t *sctp_module;
5248 expert_module_t* expert_sctp;
5249 uat_t* chunk_types_uat;
5251 chunk_types_uat = uat_new("Chunk types for the statistics dialog",
5252 sizeof(type_field_t),
5253 "statistics_chunk_types",
5254 true,
5255 &type_fields,
5256 &num_type_fields,
5258 NULL,
5259 sctp_chunk_type_copy_cb,
5260 sctp_chunk_type_update_cb,
5261 sctp_chunk_type_free_cb,
5262 NULL,
5263 NULL,
5264 custom_types_uat_fields
5267 /* Register the protocol name and description */
5268 proto_sctp = proto_register_protocol("Stream Control Transmission Protocol", "SCTP", "sctp");
5269 sctp_module = prefs_register_protocol(proto_sctp, NULL);
5270 prefs_register_bool_preference(sctp_module, "show_port_numbers_in_tree",
5271 "Show port numbers in the protocol tree",
5272 "Show source and destination port numbers in the protocol tree",
5273 &show_port_numbers);
5274 prefs_register_bool_preference(sctp_module, "relative_tsns", "Relative TSNs",
5275 "Use relative TSNs instead of absolute ones",
5276 &show_relative_tsns);
5277 prefs_register_enum_preference(sctp_module, "checksum", "Checksum type",
5278 "The type of checksum used in SCTP packets",
5279 &sctp_checksum, sctp_checksum_options, false);
5280 prefs_register_bool_preference(sctp_module, "show_always_control_chunks",
5281 "Show always control chunks",
5282 "Show always SCTP control chunks in the Info column",
5283 &show_always_control_chunks);
5284 prefs_register_bool_preference(sctp_module, "try_heuristic_first",
5285 "Try heuristic sub-dissectors first",
5286 "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port or PPI",
5287 &try_heuristic_first);
5288 prefs_register_bool_preference(sctp_module, "reassembly",
5289 "Reassemble fragmented SCTP user messages",
5290 "Whether fragmented SCTP user messages should be reassembled",
5291 &use_reassembly);
5292 prefs_register_bool_preference(sctp_module, "tsn_analysis",
5293 "Enable TSN analysis",
5294 "Match TSNs and their SACKs",
5295 &enable_tsn_analysis);
5296 prefs_register_bool_preference(sctp_module, "association_index",
5297 "Enable Association indexing (Can be CPU intense)",
5298 "Match verification tags (CPU intense)",
5299 &enable_association_indexing);
5300 prefs_register_bool_preference(sctp_module, "ulp_dissection",
5301 "Dissect upper layer protocols",
5302 "Dissect upper layer protocols",
5303 &enable_ulp_dissection);
5304 prefs_register_uat_preference_qt(sctp_module, "statistics_chunk_types",
5305 "Select the chunk types for the statistics dialog",
5306 "Select the chunk types for the statistics dialog",
5307 chunk_types_uat);
5309 /* Required function calls to register the header fields and subtrees used */
5310 proto_register_field_array(proto_sctp, hf, array_length(hf));
5311 proto_register_subtree_array(ett, array_length(ett));
5312 expert_sctp = expert_register_protocol(proto_sctp);
5313 expert_register_field_array(expert_sctp, ei, array_length(ei));
5315 sctp_tap = register_tap("sctp");
5316 exported_pdu_tap = find_tap_id(EXPORT_PDU_TAP_NAME_LAYER_3);
5317 /* subdissector code */
5318 sctp_port_dissector_table = register_dissector_table("sctp.port", "SCTP port", proto_sctp, FT_UINT16, BASE_DEC);
5319 sctp_ppi_dissector_table = register_dissector_table("sctp.ppi", "SCTP payload protocol identifier", proto_sctp, FT_UINT32, BASE_HEX);
5321 sctp_handle = register_dissector("sctp", dissect_sctp, proto_sctp);
5322 sctp_heur_subdissector_list = register_heur_dissector_list_with_description("sctp", "SCTP payload", proto_sctp);
5324 register_init_routine(sctp_init);
5325 register_cleanup_routine(sctp_cleanup);
5327 dirs_by_ptvtag = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
5328 dirs_by_ptaddr = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
5330 register_decode_as(&sctp_da_port);
5331 register_decode_as(&sctp_da_ppi);
5333 register_conversation_table(proto_sctp, false, sctp_conversation_packet, sctp_endpoint_packet);
5335 assoc_info_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
5336 sctp_assoc_hash, sctp_assoc_equal);
5337 assoc_info_half_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
5338 sctp_assoc_half_hash, sctp_assoc_half_equal);
5341 void
5342 proto_reg_handoff_sctp(void)
5344 capture_dissector_handle_t sctp_cap_handle;
5346 dissector_add_uint("wtap_encap", WTAP_ENCAP_SCTP, sctp_handle);
5347 dissector_add_uint("ip.proto", IP_PROTO_SCTP, sctp_handle);
5348 dissector_add_uint_with_preference("udp.port", UDP_TUNNELING_PORT, sctp_handle);
5349 dissector_add_uint_with_preference("dtls.port", UDP_TUNNELING_PORT, sctp_handle);
5350 sctp_cap_handle = create_capture_dissector_handle(capture_sctp, proto_sctp);
5351 capture_dissector_add_uint("ip.proto", IP_PROTO_SCTP, sctp_cap_handle);
5355 * Editor modelines - https://www.wireshark.org/tools/modelines.html
5357 * Local variables:
5358 * c-basic-offset: 2
5359 * tab-width: 8
5360 * indent-tabs-mode: nil
5361 * End:
5363 * vi: set shiftwidth=2 tabstop=8 expandtab:
5364 * :indentSize=2:tabSize=8:noTabs=true: