HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-sctp.c
blob0a998425fa05f7da213669575367f03f63698af2
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 Thomas Dreibholz <dreibh [AT] iem.uni-due.de>
6 * $Id$
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * It should be compliant to
28 * - RFC 2960
29 * - RFC 3309
30 * - RFC 3758
31 * - RFC 4460
32 * - RFC 4895
33 * - RFC 4960
34 * - RFC 5061
35 * - RFC 6525
36 * - http://tools.ietf.org/html/draft-stewart-sctp-pktdrprep-02
37 * - http://tools.ietf.org/html/draft-ladha-sctp-nonce-02
38 * - http://tools.ietf.org/html/draft-tuexen-tsvwg-sctp-sack-immediately-00
40 * Still to do (so stay tuned)
41 * - error checking mode
42 * * padding errors
43 * * length errors
44 * * bundling errors
45 * * value errors
47 * Reassembly added 2006 by Robin Seggelmann
48 * TSN Tracking by Luis E. G. Ontanon (Feb 2007)
49 * Copyright 2009, Varun Notibala <nbvarun [AT] gmail.com>
51 * PPID types updated by Thomas Dreibholz (Feb 2011)
54 #include "config.h"
56 #include <string.h>
58 #include <epan/prefs.h>
59 #include <epan/packet.h>
60 #include <epan/exceptions.h>
61 #include <epan/tap.h>
62 #include <epan/ipproto.h>
63 #include <epan/addr_resolv.h>
64 #include <epan/sctpppids.h>
65 #include <epan/wmem/wmem.h>
66 #include <epan/expert.h>
67 #include <epan/show_exception.h>
68 #include <wsutil/crc32.h>
69 #include <wsutil/adler32.h>
71 #include "packet-sctp.h"
73 #define LT(x, y) ((gint32)((x) - (y)) < 0)
75 #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
76 #define UDP_TUNNELING_PORT 9899
78 /* Initialize the protocol and registered fields */
79 static int proto_sctp = -1;
80 static int hf_port = -1;
81 static int hf_source_port = -1;
82 static int hf_destination_port = -1;
83 static int hf_verification_tag = -1;
84 static int hf_checksum = -1;
85 static int hf_checksum_bad = -1;
87 static int hf_chunk_type = -1;
88 static int hf_chunk_flags = -1;
89 static int hf_chunk_bit_1 = -1;
90 static int hf_chunk_bit_2 = -1;
91 static int hf_chunk_length = -1;
92 static int hf_chunk_padding = -1;
93 static int hf_chunk_value = -1;
95 static int hf_initiate_tag = -1;
96 static int hf_init_chunk_initiate_tag = -1;
97 static int hf_init_chunk_adv_rec_window_credit = -1;
98 static int hf_init_chunk_number_of_outbound_streams = -1;
99 static int hf_init_chunk_number_of_inbound_streams = -1;
100 static int hf_init_chunk_initial_tsn = -1;
102 static int hf_initack_chunk_initiate_tag = -1;
103 static int hf_initack_chunk_adv_rec_window_credit = -1;
104 static int hf_initack_chunk_number_of_outbound_streams = -1;
105 static int hf_initack_chunk_number_of_inbound_streams = -1;
106 static int hf_initack_chunk_initial_tsn = -1;
108 /* static int hf_cumulative_tsn_ack = -1; */
110 static int hf_data_chunk_tsn = -1;
111 static int hf_data_chunk_stream_id = -1;
112 static int hf_data_chunk_stream_seq_number = -1;
113 static int hf_data_chunk_payload_proto_id = -1;
115 static int hf_data_chunk_e_bit = -1;
116 static int hf_data_chunk_b_bit = -1;
117 static int hf_data_chunk_u_bit = -1;
118 static int hf_data_chunk_i_bit = -1;
120 static int hf_sack_chunk_ns = -1;
121 static int hf_sack_chunk_cumulative_tsn_ack = -1;
122 static int hf_sack_chunk_adv_rec_window_credit = -1;
123 static int hf_sack_chunk_number_of_gap_blocks = -1;
124 static int hf_sack_chunk_number_of_dup_tsns = -1;
125 static int hf_sack_chunk_gap_block_start = -1;
126 static int hf_sack_chunk_gap_block_end = -1;
127 static int hf_sack_chunk_gap_block_start_tsn = -1;
128 static int hf_sack_chunk_gap_block_end_tsn = -1;
129 static int hf_sack_chunk_number_tsns_gap_acked = -1;
130 static int hf_sack_chunk_duplicate_tsn = -1;
132 static int hf_nr_sack_chunk_ns = -1;
133 static int hf_nr_sack_chunk_cumulative_tsn_ack = -1;
134 static int hf_nr_sack_chunk_adv_rec_window_credit = -1;
135 static int hf_nr_sack_chunk_number_of_gap_blocks = -1;
136 static int hf_nr_sack_chunk_number_of_nr_gap_blocks = -1;
137 static int hf_nr_sack_chunk_number_of_dup_tsns = -1;
138 static int hf_nr_sack_chunk_reserved = -1;
139 static int hf_nr_sack_chunk_gap_block_start = -1;
140 static int hf_nr_sack_chunk_gap_block_end = -1;
141 static int hf_nr_sack_chunk_gap_block_start_tsn = -1;
142 static int hf_nr_sack_chunk_gap_block_end_tsn = -1;
143 static int hf_nr_sack_chunk_number_tsns_gap_acked = -1;
144 static int hf_nr_sack_chunk_nr_gap_block_start = -1;
145 static int hf_nr_sack_chunk_nr_gap_block_end = -1;
146 static int hf_nr_sack_chunk_nr_gap_block_start_tsn = -1;
147 static int hf_nr_sack_chunk_nr_gap_block_end_tsn = -1;
148 static int hf_nr_sack_chunk_number_tsns_nr_gap_acked = -1;
149 /* static int hf_nr_sack_chunk_duplicate_tsn = -1; */
151 static int hf_shutdown_chunk_cumulative_tsn_ack = -1;
152 static int hf_cookie = -1;
153 static int hf_cwr_chunk_lowest_tsn = -1;
155 static int hf_ecne_chunk_lowest_tsn = -1;
156 static int hf_abort_chunk_t_bit = -1;
157 static int hf_shutdown_complete_chunk_t_bit = -1;
159 static int hf_parameter_type = -1;
160 static int hf_parameter_length = -1;
161 static int hf_parameter_value = -1;
162 static int hf_parameter_padding = -1;
163 static int hf_parameter_bit_1 = -1;
164 static int hf_parameter_bit_2 = -1;
165 static int hf_ipv4_address = -1;
166 static int hf_ipv6_address = -1;
167 static int hf_heartbeat_info = -1;
168 static int hf_state_cookie = -1;
169 static int hf_cookie_preservative_increment = -1;
170 static int hf_hostname = -1;
171 static int hf_supported_address_type = -1;
172 static int hf_stream_reset_req_seq_nr = -1;
173 static int hf_stream_reset_rsp_seq_nr = -1;
174 static int hf_senders_last_assigned_tsn = -1;
175 static int hf_senders_next_tsn = -1;
176 static int hf_receivers_next_tsn = -1;
177 static int hf_stream_reset_rsp_result = -1;
178 static int hf_stream_reset_sid = -1;
179 static int hf_add_outgoing_streams_number_streams = -1;
180 static int hf_add_outgoing_streams_reserved = -1;
181 static int hf_add_incoming_streams_number_streams = -1;
182 static int hf_add_incoming_streams_reserved = -1;
184 static int hf_random_number = -1;
185 static int hf_chunks_to_auth = -1;
186 static int hf_hmac_id = -1;
187 static int hf_hmac = -1;
188 static int hf_shared_key_id = -1;
189 static int hf_supported_chunk_type = -1;
191 static int hf_cause_code = -1;
192 static int hf_cause_length = -1;
193 static int hf_cause_padding = -1;
194 static int hf_cause_info = -1;
196 static int hf_cause_stream_identifier = -1;
197 static int hf_cause_reserved = -1;
199 static int hf_cause_number_of_missing_parameters = -1;
200 static int hf_cause_missing_parameter_type = -1;
202 static int hf_cause_measure_of_staleness = -1;
204 static int hf_cause_tsn = -1;
206 static int hf_forward_tsn_chunk_tsn = -1;
207 static int hf_forward_tsn_chunk_sid = -1;
208 static int hf_forward_tsn_chunk_ssn = -1;
210 static int hf_asconf_ack_seq_nr = -1;
211 static int hf_asconf_seq_nr = -1;
212 static int hf_correlation_id = -1;
214 static int hf_adap_indication = -1;
216 static int hf_pktdrop_chunk_m_bit = -1;
217 static int hf_pktdrop_chunk_b_bit = -1;
218 static int hf_pktdrop_chunk_t_bit = -1;
219 static int hf_pktdrop_chunk_bandwidth = -1;
220 static int hf_pktdrop_chunk_queuesize = -1;
221 static int hf_pktdrop_chunk_truncated_length = -1;
222 static int hf_pktdrop_chunk_reserved = -1;
223 static int hf_pktdrop_chunk_data_field = -1;
225 static int hf_sctp_reassembled_in = -1;
226 static int hf_sctp_duplicate = -1;
227 static int hf_sctp_fragments = -1;
228 static int hf_sctp_fragment = -1;
230 static int hf_sctp_retransmission = -1;
231 static int hf_sctp_retransmitted = -1;
232 static int hf_sctp_retransmitted_count = -1;
233 static int hf_sctp_data_rtt = -1;
234 static int hf_sctp_sack_rtt = -1;
235 static int hf_sctp_rto = -1;
236 static int hf_sctp_ack_tsn = -1;
237 static int hf_sctp_ack_frame = -1;
238 static int hf_sctp_acked = -1;
239 static int hf_sctp_retransmitted_after_ack = -1;
241 static dissector_table_t sctp_port_dissector_table;
242 static dissector_table_t sctp_ppi_dissector_table;
243 static heur_dissector_list_t sctp_heur_subdissector_list;
244 static int sctp_tap = -1;
246 /* Initialize the subtree pointers */
247 static gint ett_sctp = -1;
248 static gint ett_sctp_chunk = -1;
249 static gint ett_sctp_chunk_parameter = -1;
250 static gint ett_sctp_chunk_cause = -1;
251 static gint ett_sctp_chunk_type = -1;
252 static gint ett_sctp_data_chunk_flags = -1;
253 static gint ett_sctp_sack_chunk_flags = -1;
254 static gint ett_sctp_nr_sack_chunk_flags = -1;
255 static gint ett_sctp_abort_chunk_flags = -1;
256 static gint ett_sctp_shutdown_complete_chunk_flags = -1;
257 static gint ett_sctp_pktdrop_chunk_flags = -1;
258 static gint ett_sctp_parameter_type= -1;
259 static gint ett_sctp_sack_chunk_gap_block = -1;
260 static gint ett_sctp_sack_chunk_gap_block_start = -1;
261 static gint ett_sctp_sack_chunk_gap_block_end = -1;
262 static gint ett_sctp_nr_sack_chunk_gap_block = -1;
263 static gint ett_sctp_nr_sack_chunk_gap_block_start = -1;
264 static gint ett_sctp_nr_sack_chunk_gap_block_end = -1;
265 static gint ett_sctp_nr_sack_chunk_nr_gap_block = -1;
266 static gint ett_sctp_nr_sack_chunk_nr_gap_block_start = -1;
267 static gint ett_sctp_nr_sack_chunk_nr_gap_block_end = -1;
268 static gint ett_sctp_unrecognized_parameter_parameter = -1;
270 static gint ett_sctp_fragments = -1;
271 static gint ett_sctp_fragment = -1;
273 static gint ett_sctp_tsn = -1;
274 static gint ett_sctp_ack = -1;
275 static gint ett_sctp_acked = -1;
276 static gint ett_sctp_tsn_retransmission = -1;
277 static gint ett_sctp_tsn_retransmitted_count = -1;
278 static gint ett_sctp_tsn_retransmitted = -1;
280 static expert_field ei_sctp_sack_chunk_adv_rec_window_credit = EI_INIT;
281 static expert_field ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100 = EI_INIT;
282 static expert_field ei_sctp_parameter_length = EI_INIT;
283 static expert_field ei_sctp_bad_sctp_checksum = EI_INIT;
284 static expert_field ei_sctp_tsn_retransmitted_more_than_twice = EI_INIT;
285 static expert_field ei_sctp_parameter_padding = EI_INIT;
286 static expert_field ei_sctp_retransmitted_after_ack = EI_INIT;
287 static expert_field ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100 = EI_INIT;
288 static expert_field ei_sctp_sack_chunk_gap_block_out_of_order = EI_INIT;
289 static expert_field ei_sctp_chunk_length_bad = EI_INIT;
290 static expert_field ei_sctp_tsn_retransmitted = EI_INIT;
291 static expert_field ei_sctp_sack_chunk_gap_block_malformed = EI_INIT;
292 static expert_field ei_sctp_sack_chunk_number_tsns_gap_acked_100 = EI_INIT;
294 static dissector_handle_t data_handle;
296 #define SCTP_DATA_CHUNK_ID 0
297 #define SCTP_INIT_CHUNK_ID 1
298 #define SCTP_INIT_ACK_CHUNK_ID 2
299 #define SCTP_SACK_CHUNK_ID 3
300 #define SCTP_HEARTBEAT_CHUNK_ID 4
301 #define SCTP_HEARTBEAT_ACK_CHUNK_ID 5
302 #define SCTP_ABORT_CHUNK_ID 6
303 #define SCTP_SHUTDOWN_CHUNK_ID 7
304 #define SCTP_SHUTDOWN_ACK_CHUNK_ID 8
305 #define SCTP_ERROR_CHUNK_ID 9
306 #define SCTP_COOKIE_ECHO_CHUNK_ID 10
307 #define SCTP_COOKIE_ACK_CHUNK_ID 11
308 #define SCTP_ECNE_CHUNK_ID 12
309 #define SCTP_CWR_CHUNK_ID 13
310 #define SCTP_SHUTDOWN_COMPLETE_CHUNK_ID 14
311 #define SCTP_AUTH_CHUNK_ID 15
312 #define SCTP_NR_SACK_CHUNK_ID 16
313 #define SCTP_ASCONF_ACK_CHUNK_ID 0x80
314 #define SCTP_PKTDROP_CHUNK_ID 0x81
315 #define SCTP_RE_CONFIG_CHUNK_ID 0x82
316 #define SCTP_PAD_CHUNK_ID 0x84
317 #define SCTP_FORWARD_TSN_CHUNK_ID 0xC0
318 #define SCTP_ASCONF_CHUNK_ID 0xC1
319 #define SCTP_IETF_EXT 0xFF
321 static const value_string chunk_type_values[] = {
322 { SCTP_DATA_CHUNK_ID, "DATA" },
323 { SCTP_INIT_CHUNK_ID, "INIT" },
324 { SCTP_INIT_ACK_CHUNK_ID, "INIT_ACK" },
325 { SCTP_SACK_CHUNK_ID, "SACK" },
326 { SCTP_HEARTBEAT_CHUNK_ID, "HEARTBEAT" },
327 { SCTP_HEARTBEAT_ACK_CHUNK_ID, "HEARTBEAT_ACK" },
328 { SCTP_ABORT_CHUNK_ID, "ABORT" },
329 { SCTP_SHUTDOWN_CHUNK_ID, "SHUTDOWN" },
330 { SCTP_SHUTDOWN_ACK_CHUNK_ID, "SHUTDOWN_ACK" },
331 { SCTP_ERROR_CHUNK_ID, "ERROR" },
332 { SCTP_COOKIE_ECHO_CHUNK_ID, "COOKIE_ECHO" },
333 { SCTP_COOKIE_ACK_CHUNK_ID, "COOKIE_ACK" },
334 { SCTP_ECNE_CHUNK_ID, "ECNE" },
335 { SCTP_CWR_CHUNK_ID, "CWR" },
336 { SCTP_SHUTDOWN_COMPLETE_CHUNK_ID, "SHUTDOWN_COMPLETE" },
337 { SCTP_AUTH_CHUNK_ID, "AUTH" },
338 { SCTP_NR_SACK_CHUNK_ID, "NR-SACK" },
339 { SCTP_ASCONF_ACK_CHUNK_ID, "ASCONF_ACK" },
340 { SCTP_PKTDROP_CHUNK_ID, "PKTDROP" },
341 { SCTP_RE_CONFIG_CHUNK_ID, "RE_CONFIG" },
342 { SCTP_PAD_CHUNK_ID, "PAD" },
343 { SCTP_FORWARD_TSN_CHUNK_ID, "FORWARD_TSN" },
344 { SCTP_ASCONF_CHUNK_ID, "ASCONF" },
345 { SCTP_IETF_EXT, "IETF_EXTENSION" },
346 { 0, NULL } };
349 * Based on http://www.iana.org/assignments/sctp-parameters
350 * as of March 15th, 2012
352 static const value_string sctp_payload_proto_id_values[] = {
353 { NOT_SPECIFIED_PROTOCOL_ID, "not specified" },
354 { IUA_PAYLOAD_PROTOCOL_ID, "IUA" },
355 { M2UA_PAYLOAD_PROTOCOL_ID, "M2UA" },
356 { M3UA_PAYLOAD_PROTOCOL_ID, "M3UA" },
357 { SUA_PAYLOAD_PROTOCOL_ID, "SUA" },
358 { M2PA_PAYLOAD_PROTOCOL_ID, "M2PA" },
359 { V5UA_PAYLOAD_PROTOCOL_ID, "V5UA" },
360 { H248_PAYLOAD_PROTOCOL_ID, "H.248/MEGACO" },
361 { BICC_PAYLOAD_PROTOCOL_ID, "BICC/Q.2150.3" },
362 { TALI_PAYLOAD_PROTOCOL_ID, "TALI" },
363 { DUA_PAYLOAD_PROTOCOL_ID, "DUA" },
364 { ASAP_PAYLOAD_PROTOCOL_ID, "ASAP" },
365 { ENRP_PAYLOAD_PROTOCOL_ID, "ENRP" },
366 { H323_PAYLOAD_PROTOCOL_ID, "H.323" },
367 { QIPC_PAYLOAD_PROTOCOL_ID, "Q.IPC/Q.2150.3" },
368 { SIMCO_PAYLOAD_PROTOCOL_ID, "SIMCO" },
369 { DDP_SEG_CHUNK_PROTOCOL_ID, "DDP Segment Chunk" },
370 { DDP_STREAM_SES_CTRL_PROTOCOL_ID, "DDP Stream Session Control" },
371 { S1AP_PAYLOAD_PROTOCOL_ID, "S1 Application Protocol (S1AP)" },
372 { RUA_PAYLOAD_PROTOCOL_ID, "RUA" },
373 { HNBAP_PAYLOAD_PROTOCOL_ID, "HNBAP" },
374 { FORCES_HP_PAYLOAD_PROTOCOL_ID, "ForCES-HP" },
375 { FORCES_MP_PAYLOAD_PROTOCOL_ID, "ForCES-MP" },
376 { FORCES_LP_PAYLOAD_PROTOCOL_ID, "ForCES-LP" },
377 { SBC_AP_PAYLOAD_PROTOCOL_ID, "SBc-AP" },
378 { NBAP_PAYLOAD_PROTOCOL_ID, "NBAP" },
379 /* Unassigned 26 */
380 { X2AP_PAYLOAD_PROTOCOL_ID, "X2AP" },
381 { IRCP_PAYLOAD_PROTOCOL_ID, "IRCP" },
382 { LCS_AP_PAYLOAD_PROTOCOL_ID, "LCS-AP" },
383 { MPICH2_PAYLOAD_PROTOCOL_ID, "MPICH2" },
384 { SABP_PAYLOAD_PROTOCOL_ID, "SABP" },
385 { FGP_PAYLOAD_PROTOCOL_ID, "Fractal Generator Protocol" },
386 { PPP_PAYLOAD_PROTOCOL_ID, "Ping Pong Protocol" },
387 { CALCAPP_PAYLOAD_PROTOCOL_ID, "CalcApp Protocol" },
388 { SSP_PAYLOAD_PROTOCOL_ID, "Scripting Service Protocol" },
389 { NPMP_CTRL_PAYLOAD_PROTOCOL_ID, "NetPerfMeter Control" },
390 { NPMP_DATA_PAYLOAD_PROTOCOL_ID, "NetPerfMeter Data" },
391 { ECHO_PAYLOAD_PROTOCOL_ID, "Echo" },
392 { DISCARD_PAYLOAD_PROTOCOL_ID, "Discard" },
393 { DAYTIME_PAYLOAD_PROTOCOL_ID, "Daytime" },
394 { CHARGEN_PAYLOAD_PROTOCOL_ID, "Character Generator" },
395 { PROTO_3GPP_RNA_PROTOCOL_ID, "3GPP RNA" },
396 { PROTO_3GPP_M2AP_PROTOCOL_ID, "3GPP M2AP" },
397 { PROTO_3GPP_M3AP_PROTOCOL_ID, "3GPP M3AP" },
398 { SSH_PAYLOAD_PROTOCOL_ID, "SSH" },
399 { DIAMETER_PROTOCOL_ID, "DIAMETER" },
400 { DIAMETER_DTLS_PROTOCOL_ID, "DIAMETER OVER DTLS" },
401 { R14P_BER_PROTOCOL_ID, "R14P" },
402 { WEBRTC_CONTROL_PAYLOAD_PROTOCOL_ID, "WebRTC Control" },
403 { WEBRTC_DOMSTRING_LAST_PAYLOAD_PROTOCOL_ID, "WebRTC DOMString Last" },
404 { WEBRTC_BINARY_DATA_PARTIAL_PAYLOAD_PROTOCOL_ID, "WebRTC Binary Data Partial" },
405 { WEBRTC_BINARY_DATA_LAST_PAYLOAD_PROTOCOL_ID, "WebRTC Binary Data Last" },
406 { WEBRTC_DOMSTRING_PARTIAL_PAYLOAD_PROTOCOL_ID, "WebRTC DOMString Partial" },
407 { 0, NULL } };
410 #define CHUNK_TYPE_LENGTH 1
411 #define CHUNK_FLAGS_LENGTH 1
412 #define CHUNK_LENGTH_LENGTH 2
413 #define CHUNK_HEADER_LENGTH (CHUNK_TYPE_LENGTH + \
414 CHUNK_FLAGS_LENGTH + \
415 CHUNK_LENGTH_LENGTH)
416 #define CHUNK_HEADER_OFFSET 0
417 #define CHUNK_TYPE_OFFSET CHUNK_HEADER_OFFSET
418 #define CHUNK_FLAGS_OFFSET (CHUNK_TYPE_OFFSET + CHUNK_TYPE_LENGTH)
419 #define CHUNK_LENGTH_OFFSET (CHUNK_FLAGS_OFFSET + CHUNK_FLAGS_LENGTH)
420 #define CHUNK_VALUE_OFFSET (CHUNK_LENGTH_OFFSET + CHUNK_LENGTH_LENGTH)
422 #define PARAMETER_TYPE_LENGTH 2
423 #define PARAMETER_LENGTH_LENGTH 2
424 #define PARAMETER_HEADER_LENGTH (PARAMETER_TYPE_LENGTH + PARAMETER_LENGTH_LENGTH)
426 #define PARAMETER_HEADER_OFFSET 0
427 #define PARAMETER_TYPE_OFFSET PARAMETER_HEADER_OFFSET
428 #define PARAMETER_LENGTH_OFFSET (PARAMETER_TYPE_OFFSET + PARAMETER_TYPE_LENGTH)
429 #define PARAMETER_VALUE_OFFSET (PARAMETER_LENGTH_OFFSET + PARAMETER_LENGTH_LENGTH)
431 #define SOURCE_PORT_LENGTH 2
432 #define DESTINATION_PORT_LENGTH 2
433 #define VERIFICATION_TAG_LENGTH 4
434 #define CHECKSUM_LENGTH 4
435 #define COMMON_HEADER_LENGTH (SOURCE_PORT_LENGTH + \
436 DESTINATION_PORT_LENGTH + \
437 VERIFICATION_TAG_LENGTH + \
438 CHECKSUM_LENGTH)
439 #define SOURCE_PORT_OFFSET 0
440 #define DESTINATION_PORT_OFFSET (SOURCE_PORT_OFFSET + SOURCE_PORT_LENGTH)
441 #define VERIFICATION_TAG_OFFSET (DESTINATION_PORT_OFFSET + DESTINATION_PORT_LENGTH)
442 #define CHECKSUM_OFFSET (VERIFICATION_TAG_OFFSET + VERIFICATION_TAG_LENGTH)
444 #define SCTP_CHECKSUM_NONE 0
445 #define SCTP_CHECKSUM_ADLER32 1
446 #define SCTP_CHECKSUM_CRC32C 2
447 #define SCTP_CHECKSUM_AUTOMATIC 3
449 /* Default values for preferences */
450 static gboolean show_port_numbers = TRUE;
451 static gint sctp_checksum = SCTP_CHECKSUM_NONE;
452 static gboolean enable_tsn_analysis = TRUE;
453 static gboolean enable_ulp_dissection = TRUE;
454 static gboolean use_reassembly = FALSE;
455 /* FIXME
456 static gboolean show_chunk_types = TRUE;
458 static gboolean show_always_control_chunks = TRUE;
460 static struct _sctp_info sctp_info;
462 static unsigned int
463 sctp_adler32(const unsigned char *buf, unsigned int len)
465 guint32 result = 1L;
467 result = update_adler32(result, buf, SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH);
468 /* handle four 0 bytes as checksum */
469 result = update_adler32(result, "\0\0\0\0", 4);
470 result = update_adler32(result, buf+COMMON_HEADER_LENGTH, len-COMMON_HEADER_LENGTH);
472 return result;
475 static guint32
476 sctp_crc32c(const unsigned char *buf, unsigned int len)
478 guint32 crc32,
479 zero = 0;
480 guint32 result;
482 /* CRC for header */
483 crc32 = crc32c_calculate_no_swap(buf, SOURCE_PORT_LENGTH + DESTINATION_PORT_LENGTH + VERIFICATION_TAG_LENGTH, CRC32C_PRELOAD);
485 /* handle four 0 bytes as checksum */
486 crc32 = crc32c_calculate_no_swap(&zero, 4, crc32);
488 /* CRC for the rest of the packet */
489 crc32 = crc32c_calculate_no_swap(&buf[COMMON_HEADER_LENGTH], len-COMMON_HEADER_LENGTH, crc32);
491 result = CRC32C_SWAP(crc32);
493 return ( ~result );
497 * Routines for dissecting parameters
500 typedef struct _sctp_half_assoc_t sctp_half_assoc_t;
502 static void dissect_parameter(tvbuff_t *, packet_info *, proto_tree *, proto_item *, gboolean, gboolean);
504 static void dissect_parameters(tvbuff_t *, packet_info *, proto_tree *, proto_item *, gboolean);
506 static void dissect_error_cause(tvbuff_t *, packet_info *, proto_tree *);
508 static void dissect_error_causes(tvbuff_t *, packet_info *, proto_tree *);
510 static gboolean dissect_data_chunk(tvbuff_t*, guint16, packet_info*, proto_tree*, proto_tree*, proto_item*, proto_item*, sctp_half_assoc_t*);
512 static void dissect_sctp_packet(tvbuff_t *, packet_info *, proto_tree *, gboolean);
515 /* TSN ANALYSIS CODE */
517 struct _sctp_half_assoc_t {
518 guint32 spt;
519 guint32 dpt;
520 guint32 vtag;
522 gboolean started;
524 guint32 first_tsn; /* start */
525 guint32 cumm_ack; /* rel */
526 wmem_tree_t *tsns; /* sctp_tsn_t* by rel_tsn */
527 wmem_tree_t *tsn_acks; /* sctp_tsn_t* by ctsn_frame */
529 struct _sctp_half_assoc_t *peer;
533 typedef struct _retransmit_t {
534 guint32 framenum;
535 nstime_t ts;
536 struct _retransmit_t *next;
537 } retransmit_t;
539 typedef struct _sctp_tsn_t {
540 guint32 tsn;
541 struct {
542 guint32 framenum;
543 nstime_t ts;
544 } first_transmit;
545 struct {
546 guint32 framenum;
547 nstime_t ts;
548 } ack;
549 retransmit_t *retransmit;
550 guint32 retransmit_count;
551 struct _sctp_tsn_t *next;
552 } sctp_tsn_t;
555 static wmem_tree_key_t*
556 make_address_key(guint32 spt, guint32 dpt, address *addr)
558 wmem_tree_key_t *k = (wmem_tree_key_t *)wmem_alloc(wmem_packet_scope(), sizeof(wmem_tree_key_t)*6);
560 k[0].length = 1; k[0].key = (guint32*)wmem_memdup(wmem_packet_scope(), &spt,sizeof(spt));
561 k[1].length = 1; k[1].key = (guint32*)wmem_memdup(wmem_packet_scope(), &dpt,sizeof(dpt));
562 k[2].length = 1; k[2].key = (guint32*)(void *)&(addr->type);
563 k[3].length = 1; k[3].key = (guint32*)(void *)&(addr->len);
565 k[4].length = ((addr->len/4)+1);
566 k[4].key = (guint32*)wmem_alloc0(wmem_packet_scope(), ((addr->len/4)+1)*4);
567 if (addr->len) memcpy(k[4].key, addr->data, addr->len);
569 k[5].length = 0; k[5].key = NULL;
571 return k;
574 static wmem_tree_key_t *
575 make_dir_key(guint32 spt, guint32 dpt, guint32 vtag)
577 wmem_tree_key_t *k = (wmem_tree_key_t *)wmem_alloc(wmem_packet_scope(), sizeof(wmem_tree_key_t)*4);
579 k[0].length = 1; k[0].key = (guint32*)wmem_memdup(wmem_packet_scope(), &spt,sizeof(spt));
580 k[1].length = 1; k[1].key = (guint32*)wmem_memdup(wmem_packet_scope(), &dpt,sizeof(dpt));
581 k[2].length = 1; k[2].key = (guint32*)wmem_memdup(wmem_packet_scope(), &vtag,sizeof(vtag));
582 k[3].length = 0; k[3].key = NULL;
584 return k;
589 static wmem_tree_t *dirs_by_ptvtag; /* sctp_half_assoc_t* */
590 static wmem_tree_t *dirs_by_ptaddr; /* sctp_half_assoc_t**, it may contain a null pointer */
592 static sctp_half_assoc_t *
593 get_half_assoc(packet_info *pinfo, guint32 spt, guint32 dpt, guint32 vtag)
595 sctp_half_assoc_t *ha;
596 sctp_half_assoc_t **hb;
597 wmem_tree_key_t *k;
599 if (!enable_tsn_analysis || !vtag) return NULL;
601 /* look for the current half_assoc by spt, dpt and vtag */
603 k = make_dir_key(spt, dpt, vtag);
604 if (( ha = (sctp_half_assoc_t *)wmem_tree_lookup32_array(dirs_by_ptvtag, k) )) {
605 /* found, if it has been already matched we're done */
606 if (ha->peer) return ha;
607 } else {
608 /* not found, make a new one and add it to the table */
609 ha = wmem_new0(wmem_file_scope(), sctp_half_assoc_t);
610 ha->spt = spt;
611 ha->dpt = dpt;
612 ha->vtag = vtag;
613 ha->tsns = wmem_tree_new(wmem_file_scope());
614 ha->tsn_acks = wmem_tree_new(wmem_file_scope());
615 ha->started = FALSE;
616 ha->first_tsn= 0;
617 ha->cumm_ack= 0;
619 /* add this half to the table indexed by ports and vtag */
620 wmem_tree_insert32_array(dirs_by_ptvtag, k, ha);
623 /* at this point we have an unmatched half, look for its other half using the ports and IP address */
624 k = make_address_key(dpt, spt, &(pinfo->dst));
626 if (( hb = (sctp_half_assoc_t **)wmem_tree_lookup32_array(dirs_by_ptaddr, k) )) {
627 /*the table contains a pointer to a pointer to a half */
628 if (! *hb) {
629 /* if there is no half pointed by this, add the current half to the table */
630 *hb = ha;
631 } else {
632 /* there's a half pointed by this, assume it's our peer and clear the table's pointer */
633 ha->peer = *hb;
634 (*hb)->peer = ha;
635 *hb = NULL;
637 } else {
638 /* we found no entry in the table: add one (using reversed ports and src addresss) so that it can be matched later */
639 *(hb = (sctp_half_assoc_t **)wmem_alloc(wmem_file_scope(), sizeof(void*))) = ha;
640 k = make_address_key(spt, dpt, &(pinfo->src));
641 wmem_tree_insert32_array(dirs_by_ptaddr, k, hb);
644 return ha;
647 /* Limit the number of retransmissions we track (to limit memory usage--and
648 * tree size--in pathological cases, for example zero window probing forever).
650 #define MAX_RETRANS_TRACKED_PER_TSN 100
652 static void
653 tsn_tree(sctp_tsn_t *t, proto_item *tsn_item, packet_info *pinfo,
654 tvbuff_t *tvb, guint32 framenum)
656 proto_item *pi;
657 proto_tree *pt;
658 proto_tree *tsn_tree_pt = proto_item_add_subtree(tsn_item, ett_sctp_tsn);
660 if (t->first_transmit.framenum != framenum) {
661 nstime_t rto;
663 pi = proto_tree_add_uint(tsn_tree_pt, hf_sctp_retransmission, tvb, 0, 0, t->first_transmit.framenum);
664 pt = proto_item_add_subtree(pi, ett_sctp_tsn_retransmission);
665 PROTO_ITEM_SET_GENERATED(pi);
666 expert_add_info(pinfo, pi, &ei_sctp_tsn_retransmitted);
668 nstime_delta( &rto, &pinfo->fd->abs_ts, &(t->first_transmit.ts) );
669 pi = proto_tree_add_time(pt, hf_sctp_rto, tvb, 0, 0, &rto);
670 PROTO_ITEM_SET_GENERATED(pi);
672 /* Detect reneged acks */
673 /* XXX what if the frames aren't sorted by time? */
674 if (t->ack.framenum && t->ack.framenum < framenum)
676 pi = proto_tree_add_uint_format(pt, hf_sctp_retransmitted_after_ack, tvb, 0, 0, t->ack.framenum,
677 "This TSN was acked (in frame %u) prior to this retransmission (reneged ack?)",
678 t->ack.framenum);
679 PROTO_ITEM_SET_GENERATED(pi);
680 expert_add_info(pinfo, pi, &ei_sctp_retransmitted_after_ack);
682 } else if (t->retransmit) {
683 retransmit_t **r;
684 nstime_t rto;
685 char ds[64];
687 if (t->retransmit_count > MAX_RETRANS_TRACKED_PER_TSN)
688 g_snprintf(ds, sizeof(ds), " (only %d displayed)", MAX_RETRANS_TRACKED_PER_TSN);
689 else
690 ds[0] = 0;
692 pi = proto_tree_add_uint_format(tsn_tree_pt,
693 hf_sctp_retransmitted_count,
694 tvb, 0, 0, t->retransmit_count,
695 "This TSN was retransmitted %u time%s%s",
696 t->retransmit_count,
697 plurality(t->retransmit_count, "", "s"),
698 ds);
699 PROTO_ITEM_SET_GENERATED(pi);
701 if (t->retransmit_count > 2)
702 expert_add_info(pinfo, pi, &ei_sctp_tsn_retransmitted_more_than_twice);
704 pt = proto_item_add_subtree(pi, ett_sctp_tsn_retransmitted_count);
706 r = &t->retransmit;
707 while (*r) {
708 nstime_delta(&rto, &((*r)->ts), &pinfo->fd->abs_ts);
709 pi = proto_tree_add_uint_format(pt,
710 hf_sctp_retransmitted,
711 tvb, 0, 0,
712 (*r)->framenum,
713 "This TSN was retransmitted in frame %u (%s seconds after this frame)",
714 (*r)->framenum,
715 rel_time_to_secs_str(&rto));
716 PROTO_ITEM_SET_GENERATED(pi);
717 r = &(*r)->next;
721 if (t->ack.framenum) {
722 nstime_t rtt;
724 pi = proto_tree_add_uint(tsn_tree_pt, hf_sctp_acked, tvb, 0 , 0, t->ack.framenum);
725 PROTO_ITEM_SET_GENERATED(pi);
726 pt = proto_item_add_subtree(pi, ett_sctp_ack);
728 nstime_delta( &rtt, &(t->ack.ts), &(t->first_transmit.ts) );
729 pi = proto_tree_add_time(pt, hf_sctp_data_rtt, tvb, 0, 0, &rtt);
730 PROTO_ITEM_SET_GENERATED(pi);
734 #define RELTSN(tsn) (((tsn) < h->first_tsn) ? (tsn + (0xffffffff - (h->first_tsn)) + 1) : (tsn - h->first_tsn))
736 /* Returns TRUE if the tsn is a retransmission (we've seen it before), FALSE
737 * otherwise.
739 static gboolean
740 sctp_tsn(packet_info *pinfo, tvbuff_t *tvb, proto_item *tsn_item,
741 sctp_half_assoc_t *h, guint32 tsn)
743 sctp_tsn_t *t;
744 guint32 framenum;
745 guint32 reltsn;
746 gboolean is_retransmission = FALSE;
748 /* no half assoc? nothing to do!*/
749 if (!h)
750 return(is_retransmission);
753 framenum = PINFO_FD_NUM(pinfo);
755 /* If we're dissecting for a read filter in the GUI [tshark assigns
756 * frame numbers before running the read filter], don't do the TSN
757 * analysis. (We can't anyway because we don't have a valid frame
758 * number...)
760 * Without this check if you load a capture file in the
761 * GUI while using a read filter, every SCTP TSN is marked as a
762 * retransmission of that in frame 0.
764 if (framenum == 0)
765 return(is_retransmission);
767 /* we have not seen any tsn yet in this half assoc set the ground */
768 if (! h->started) {
769 h->first_tsn = tsn;
770 h->started = TRUE;
774 reltsn = RELTSN(tsn);
776 /* printf("%.3d REL TSN: %p->%p [%u] %u \n",framenum,h,h->peer,tsn,reltsn); */
778 /* look for this tsn in this half's tsn table */
779 if (! (t = (sctp_tsn_t *)wmem_tree_lookup32(h->tsns,reltsn) )) {
780 /* no tsn found, create a new one */
781 t = wmem_new0(wmem_file_scope(), sctp_tsn_t);
782 t->tsn = tsn;
784 t->first_transmit.framenum = framenum;
785 t->first_transmit.ts = pinfo->fd->abs_ts;
787 wmem_tree_insert32(h->tsns,reltsn,t);
790 is_retransmission = (t->first_transmit.framenum != framenum);
792 if ( (! pinfo->fd->flags.visited ) && is_retransmission ) {
793 retransmit_t **r;
794 int i;
796 t->retransmit_count++;
797 r = &t->retransmit;
798 i = 0;
799 while (*r && i < MAX_RETRANS_TRACKED_PER_TSN) {
800 r = &(*r)->next;
801 i++;
804 if (i <= MAX_RETRANS_TRACKED_PER_TSN) {
805 *r = wmem_new0(wmem_file_scope(), retransmit_t);
806 (*r)->framenum = framenum;
807 (*r)->ts = pinfo->fd->abs_ts;
811 tsn_tree(t, tsn_item, pinfo, tvb, framenum);
813 return(is_retransmission);
816 static void
817 ack_tree(sctp_tsn_t *t, proto_tree *acks_tree,
818 tvbuff_t *tvb, packet_info *pinfo)
820 proto_item *pi;
821 proto_tree *pt;
822 nstime_t rtt;
823 guint framenum = pinfo->fd->num;
825 if ( t->ack.framenum == framenum ) {
826 nstime_delta( &rtt, &(t->ack.ts), &(t->first_transmit.ts) );
828 pi = proto_tree_add_uint(acks_tree, hf_sctp_ack_tsn, tvb, 0 , 0, t->tsn);
829 PROTO_ITEM_SET_GENERATED(pi);
831 pt = proto_item_add_subtree(pi, ett_sctp_acked);
833 pi = proto_tree_add_uint(pt, hf_sctp_ack_frame, tvb, 0 , 0, t->first_transmit.framenum);
834 PROTO_ITEM_SET_GENERATED(pi);
836 pi = proto_tree_add_time(pt, hf_sctp_sack_rtt, tvb, 0, 0, &rtt);
837 PROTO_ITEM_SET_GENERATED(pi);
841 static void
842 sctp_ack(packet_info *pinfo, tvbuff_t *tvb, proto_tree *acks_tree,
843 sctp_half_assoc_t *h, guint32 reltsn)
845 sctp_tsn_t *t;
846 guint32 framenum;
849 if (!h || !h->peer)
850 return;
852 framenum = PINFO_FD_NUM(pinfo);
854 /* printf("%.6d ACK: %p->%p [%u] \n",framenum,h,h->peer,reltsn); */
856 t = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsns,reltsn);
858 if (t) {
859 if (! t->ack.framenum) {
860 sctp_tsn_t *t2;
862 t->ack.framenum = framenum;
863 t->ack.ts = pinfo->fd->abs_ts;
865 if (( t2 = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsn_acks, framenum) )) {
866 for(;t2->next;t2 = t2->next)
869 t2->next = t;
870 } else {
871 wmem_tree_insert32(h->peer->tsn_acks, framenum,t);
875 if ( t->ack.framenum == framenum)
876 ack_tree(t, acks_tree, tvb, pinfo);
878 } /* else {
879 proto_tree_add_text(acks_tree, tvb, 0 , 0, "Assoc: %p vs %p ?? %ld",h,h->peer,tsn);
880 } */
883 #define RELTSNACK(tsn) (((tsn) < h->peer->first_tsn) ? ((tsn) + (0xffffffff - (h->peer->first_tsn)) + 1) : ((tsn) - h->peer->first_tsn))
884 static void
885 sctp_ack_block(packet_info *pinfo, sctp_half_assoc_t *h, tvbuff_t *tvb,
886 proto_item *acks_tree, const guint32 *tsn_start_ptr,
887 guint32 tsn_end)
889 sctp_tsn_t *t;
890 guint32 framenum;
891 guint32 rel_start;
892 guint32 rel_end;
895 if ( !h || !h->peer || ! h->peer->started )
896 return;
898 framenum = PINFO_FD_NUM(pinfo);
899 rel_end = RELTSNACK(tsn_end);
901 if (tsn_start_ptr) {
902 rel_start = RELTSNACK(*tsn_start_ptr);
903 /* printf("%.3d BACK: %p->%p [%u-%u]\n",framenum,h,h->peer,rel_start,rel_end); */
904 } else {
905 rel_start = h->peer->cumm_ack;
906 /* printf("%.3d CACK: %p->%p [%u-%u]\n",framenum,h,h->peer,rel_start,rel_end); */
910 if ((t = (sctp_tsn_t *)wmem_tree_lookup32(h->peer->tsn_acks, framenum))) {
911 for(;t;t = t->next) {
912 guint32 tsn = t->tsn;
914 if ( tsn < h->peer->first_tsn ) {
915 tsn += (0xffffffff - (h->peer->first_tsn)) + 1;
916 } else {
917 tsn -= h->peer->first_tsn;
920 if (t->ack.framenum == framenum && ( (!tsn_start_ptr) || rel_start <= tsn) && tsn <= rel_end)
921 ack_tree(t, acks_tree, tvb, pinfo);
924 return;
927 if (PINFO_FD_VISITED(pinfo) || rel_end < rel_start || rel_end - rel_start > 0xffff0000 ) return;
929 if (! tsn_start_ptr )
930 h->peer->cumm_ack = rel_end + 1;
932 if (rel_start <= rel_end && rel_end - rel_start < 5000 ) {
933 guint32 rel_tsn, i;
934 for (i=0; i <= rel_end-rel_start; i++) {
935 rel_tsn = (guint32) (i+rel_start);
936 sctp_ack(pinfo, tvb, acks_tree, h, rel_tsn);
941 /* END TSN ANALYSIS CODE */
946 #define HEARTBEAT_INFO_PARAMETER_INFO_OFFSET PARAMETER_VALUE_OFFSET
948 static void
949 dissect_heartbeat_info_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
951 guint16 heartbeat_info_length;
953 heartbeat_info_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
954 if (heartbeat_info_length > 0)
955 proto_tree_add_item(parameter_tree, hf_heartbeat_info, parameter_tvb, HEARTBEAT_INFO_PARAMETER_INFO_OFFSET, heartbeat_info_length, ENC_NA);
956 proto_item_append_text(parameter_item, " (Information: %u byte%s)", heartbeat_info_length, plurality(heartbeat_info_length, "", "s"));
959 #define IPV4_ADDRESS_LENGTH 4
960 #define IPV4_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET
962 static void
963 dissect_ipv4_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item, gboolean dissecting_init_init_ack_chunk)
965 if (parameter_tree) {
966 proto_tree_add_item(parameter_tree, hf_ipv4_address, parameter_tvb, IPV4_ADDRESS_OFFSET, IPV4_ADDRESS_LENGTH, ENC_BIG_ENDIAN);
967 proto_item_append_text(parameter_item, " (Address: %s)", tvb_ip_to_str(parameter_tvb, IPV4_ADDRESS_OFFSET));
968 if (additional_item)
969 proto_item_append_text(additional_item, "%s", tvb_ip_to_str(parameter_tvb, IPV4_ADDRESS_OFFSET));
971 if (dissecting_init_init_ack_chunk) {
972 if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS)
973 sctp_info.tvb[sctp_info.number_of_tvbs++] = parameter_tvb;
974 else
975 sctp_info.incomplete = TRUE;
979 #define IPV6_ADDRESS_LENGTH 16
980 #define IPV6_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET
982 static void
983 dissect_ipv6_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item, proto_item *additional_item, gboolean dissecting_init_init_ack_chunk)
985 if (parameter_tree) {
986 proto_tree_add_item(parameter_tree, hf_ipv6_address, parameter_tvb, IPV6_ADDRESS_OFFSET, IPV6_ADDRESS_LENGTH, ENC_NA);
987 proto_item_append_text(parameter_item, " (Address: %s)", tvb_ip6_to_str(parameter_tvb, IPV6_ADDRESS_OFFSET));
988 if (additional_item)
989 proto_item_append_text(additional_item, "%s", tvb_ip6_to_str(parameter_tvb, IPV6_ADDRESS_OFFSET));
991 if (dissecting_init_init_ack_chunk) {
992 if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS)
993 sctp_info.tvb[sctp_info.number_of_tvbs++] = parameter_tvb;
994 else
995 sctp_info.incomplete = TRUE;
999 #define STATE_COOKIE_PARAMETER_COOKIE_OFFSET PARAMETER_VALUE_OFFSET
1001 static void
1002 dissect_state_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1004 guint16 state_cookie_length;
1006 state_cookie_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1007 if (state_cookie_length > 0)
1008 proto_tree_add_item(parameter_tree, hf_state_cookie, parameter_tvb, STATE_COOKIE_PARAMETER_COOKIE_OFFSET, state_cookie_length, ENC_NA);
1009 proto_item_append_text(parameter_item, " (Cookie length: %u byte%s)", state_cookie_length, plurality(state_cookie_length, "", "s"));
1012 static void
1013 dissect_unrecognized_parameters_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree)
1015 /* FIXME: Does it contain one or more parameters? */
1016 dissect_parameter(tvb_new_subset_remaining(parameter_tvb, PARAMETER_VALUE_OFFSET), pinfo, parameter_tree, NULL, FALSE, FALSE);
1019 #define COOKIE_PRESERVATIVE_PARAMETER_INCR_LENGTH 4
1020 #define COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET PARAMETER_VALUE_OFFSET
1022 static void
1023 dissect_cookie_preservative_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1025 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);
1026 proto_item_append_text(parameter_item, " (Increment :%u msec)", tvb_get_ntohl(parameter_tvb, COOKIE_PRESERVATIVE_PARAMETER_INCR_OFFSET));
1029 #define HOSTNAME_OFFSET PARAMETER_VALUE_OFFSET
1031 static void
1032 dissect_hostname_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1034 guint16 hostname_length;
1036 hostname_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1037 proto_tree_add_item(parameter_tree, hf_hostname, parameter_tvb, HOSTNAME_OFFSET, hostname_length, ENC_ASCII|ENC_NA);
1038 proto_item_append_text(parameter_item, " (Hostname: %.*s)", hostname_length, tvb_get_string(wmem_packet_scope(), parameter_tvb, HOSTNAME_OFFSET, hostname_length));
1042 #define IPv4_ADDRESS_TYPE 5
1043 #define IPv6_ADDRESS_TYPE 6
1044 #define HOSTNAME_ADDRESS_TYPE 11
1046 static const value_string address_types_values[] = {
1047 { IPv4_ADDRESS_TYPE, "IPv4 address" },
1048 { IPv6_ADDRESS_TYPE, "IPv6 address" },
1049 { HOSTNAME_ADDRESS_TYPE, "Hostname address" },
1050 { 0, NULL }
1053 #define SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH 2
1055 static void
1056 dissect_supported_address_types_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1058 guint16 addr_type, number_of_addr_types, addr_type_number;
1059 guint offset;
1061 number_of_addr_types = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH)
1062 / SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH;
1064 offset = PARAMETER_VALUE_OFFSET;
1065 proto_item_append_text(parameter_item, " (Supported types: ");
1066 for(addr_type_number = 0; addr_type_number < number_of_addr_types; addr_type_number++) {
1067 proto_tree_add_item(parameter_tree, hf_supported_address_type, parameter_tvb, offset, SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH, ENC_BIG_ENDIAN);
1068 addr_type = tvb_get_ntohs(parameter_tvb, offset);
1069 switch (addr_type) {
1070 case IPv4_ADDRESS_TYPE:
1071 proto_item_append_text(parameter_item, "IPv4");
1072 break;
1073 case IPv6_ADDRESS_TYPE:
1074 proto_item_append_text(parameter_item, "IPv6");
1075 break;
1076 case HOSTNAME_ADDRESS_TYPE:
1077 proto_item_append_text(parameter_item, "hostname");
1078 break;
1079 default:
1080 proto_item_append_text(parameter_item, "%u", addr_type);
1082 if (addr_type_number < (number_of_addr_types-1))
1083 proto_item_append_text(parameter_item, ", ");
1084 offset += SUPPORTED_ADDRESS_TYPE_PARAMETER_ADDRESS_TYPE_LENGTH;
1086 proto_item_append_text(parameter_item, ")");
1089 #define STREAM_RESET_SEQ_NR_LENGTH 4
1090 #define SENDERS_LAST_ASSIGNED_TSN_LENGTH 4
1091 #define SID_LENGTH 2
1093 #define STREAM_RESET_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1094 #define STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET (PARAMETER_VALUE_OFFSET + STREAM_RESET_SEQ_NR_LENGTH)
1095 #define SENDERS_LAST_ASSIGNED_TSN_OFFSET (STREAM_RESET_REQ_RSP_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH)
1097 static void
1098 dissect_outgoing_ssn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1100 guint length, number_of_sids, sid_number, sid_offset;
1102 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);
1103 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);
1104 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);
1106 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1107 sid_offset = SENDERS_LAST_ASSIGNED_TSN_OFFSET + SENDERS_LAST_ASSIGNED_TSN_LENGTH;
1108 if (length > PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + SENDERS_LAST_ASSIGNED_TSN_LENGTH) {
1109 number_of_sids = (length - (PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + SENDERS_LAST_ASSIGNED_TSN_LENGTH)) / SID_LENGTH;
1110 for(sid_number = 0; sid_number < number_of_sids; sid_number++) {
1111 proto_tree_add_item(parameter_tree, hf_stream_reset_sid, parameter_tvb, sid_offset, SID_LENGTH, ENC_BIG_ENDIAN);
1112 sid_offset += SID_LENGTH;
1117 static void
1118 dissect_incoming_ssn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1120 guint length, number_of_sids, sid_number, sid_offset;
1122 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);
1124 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1125 sid_offset = STREAM_RESET_REQ_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH;
1126 if (length > PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH) {
1127 number_of_sids = (length - (PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH)) / SID_LENGTH;
1128 for(sid_number = 0; sid_number < number_of_sids; sid_number++) {
1129 proto_tree_add_item(parameter_tree, hf_stream_reset_sid, parameter_tvb, sid_offset, SID_LENGTH, ENC_BIG_ENDIAN);
1130 sid_offset += SID_LENGTH;
1135 #define STREAM_RESET_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1137 static void
1138 dissect_ssn_tsn_reset_request_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1140 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);
1143 #define STREAM_RESET_RSP_RESULT_LENGTH 4
1144 #define SENDERS_NEXT_TSN_LENGTH 4
1145 #define RECEIVERS_NEXT_TSN_LENGTH 4
1147 #define STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1148 #define STREAM_RESET_RSP_RESULT_OFFSET (STREAM_RESET_RSP_RSP_SEQ_NR_OFFSET + STREAM_RESET_SEQ_NR_LENGTH)
1149 #define SENDERS_NEXT_TSN_OFFSET (STREAM_RESET_RSP_RESULT_OFFSET + STREAM_RESET_RSP_RESULT_LENGTH)
1150 #define RECEIVERS_NEXT_TSN_OFFSET (SENDERS_NEXT_TSN_OFFSET + SENDERS_NEXT_TSN_LENGTH)
1152 static const value_string stream_reset_result_values[] = {
1153 { 0, "Nothing to do" },
1154 { 1, "Performed" },
1155 { 2, "Denied" },
1156 { 3, "Error - Wrong SSN" },
1157 { 4, "Error - Request already in progress" },
1158 { 5, "Error - Bad sequence number" },
1159 { 0, NULL }
1163 static void
1164 dissect_re_configuration_response_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1166 guint length;
1168 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1170 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);
1171 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);
1172 if (length >= PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_RSP_RESULT_LENGTH + SENDERS_NEXT_TSN_LENGTH)
1173 proto_tree_add_item(parameter_tree, hf_senders_next_tsn, parameter_tvb, SENDERS_NEXT_TSN_OFFSET, SENDERS_NEXT_TSN_LENGTH, ENC_BIG_ENDIAN);
1174 if (length >= PARAMETER_HEADER_LENGTH + STREAM_RESET_SEQ_NR_LENGTH + STREAM_RESET_RSP_RESULT_LENGTH + SENDERS_NEXT_TSN_LENGTH + RECEIVERS_NEXT_TSN_LENGTH)
1175 proto_tree_add_item(parameter_tree, hf_receivers_next_tsn, parameter_tvb, RECEIVERS_NEXT_TSN_OFFSET, RECEIVERS_NEXT_TSN_LENGTH, ENC_BIG_ENDIAN);
1178 #define ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH 4
1179 #define ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH 2
1180 #define ADD_OUTGOING_STREAM_REQ_RESERVED_LENGTH 2
1182 #define ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1183 #define ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET (ADD_OUTGOING_STREAM_REQ_SEQ_NR_OFFSET + ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH)
1184 #define ADD_OUTGOING_STREAM_REQ_RESERVED_OFFSET (ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_OFFSET + ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH)
1186 static void
1187 dissect_add_outgoing_streams_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1189 /* guint length; */
1191 /* length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); */
1193 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);
1194 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);
1195 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);
1198 #define ADD_INCOMING_STREAM_REQ_SEQ_NR_LENGTH 4
1199 #define ADD_INCOMING_STREAM_REQ_NUM_STREAMS_LENGTH 2
1200 #define ADD_INCOMING_STREAM_REQ_RESERVED_LENGTH 2
1202 #define ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET PARAMETER_VALUE_OFFSET
1203 #define ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET (ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET + ADD_OUTGOING_STREAM_REQ_SEQ_NR_LENGTH)
1204 #define ADD_INCOMING_STREAM_REQ_RESERVED_OFFSET (ADD_INCOMING_STREAM_REQ_NUM_STREAMS_OFFSET + ADD_OUTGOING_STREAM_REQ_NUM_STREAMS_LENGTH)
1206 static void
1207 dissect_add_incoming_streams_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item _U_)
1209 /* guint length; */
1211 /* length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET); */
1213 proto_tree_add_item(parameter_tree, hf_stream_reset_req_seq_nr, parameter_tvb, ADD_INCOMING_STREAM_REQ_SEQ_NR_OFFSET, ADD_INCOMING_STREAM_REQ_RESERVED_LENGTH, ENC_BIG_ENDIAN);
1214 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);
1215 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);
1218 static void
1219 dissect_ecn_parameter(tvbuff_t *parameter_tvb _U_)
1223 static void
1224 dissect_nonce_supported_parameter(tvbuff_t *parameter_tvb _U_)
1228 #define RANDOM_NUMBER_OFFSET PARAMETER_VALUE_OFFSET
1230 static void
1231 dissect_random_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
1233 gint32 number_length;
1235 number_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1236 if (number_length > 0)
1237 proto_tree_add_item(parameter_tree, hf_random_number, parameter_tvb, RANDOM_NUMBER_OFFSET, number_length, ENC_NA);
1240 static void
1241 dissect_chunks_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1243 guint16 number_of_chunks;
1244 guint16 chunk_number, offset;
1246 proto_item_append_text(parameter_item, " (Chunk types to be authenticated: ");
1247 number_of_chunks = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1248 for(chunk_number = 0, offset = PARAMETER_VALUE_OFFSET; chunk_number < number_of_chunks; chunk_number++, offset += CHUNK_TYPE_LENGTH) {
1249 proto_tree_add_item(parameter_tree, hf_chunks_to_auth, parameter_tvb, offset, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
1250 proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_guint8(parameter_tvb, offset), chunk_type_values, "Unknown"));
1251 if (chunk_number < (number_of_chunks - 1))
1252 proto_item_append_text(parameter_item, ", ");
1254 proto_item_append_text(parameter_item, ")");
1257 static const value_string hmac_id_values[] = {
1258 { 0x0000, "Reserved" },
1259 { 0x0001, "SHA-1" },
1260 { 0x0002, "Reserved" },
1261 { 0x0003, "SHA-256" },
1262 { 0, NULL } };
1264 #define HMAC_ID_LENGTH 2
1266 static void
1267 dissect_hmac_algo_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1269 guint16 number_of_ids;
1270 guint16 id_number, offset;
1272 proto_item_append_text(parameter_item, " (Supported HMACs: ");
1273 number_of_ids = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) / HMAC_ID_LENGTH;
1274 for(id_number = 0, offset = PARAMETER_VALUE_OFFSET; id_number < number_of_ids; id_number++, offset += HMAC_ID_LENGTH) {
1275 proto_tree_add_item(parameter_tree, hf_hmac_id, parameter_tvb, offset, HMAC_ID_LENGTH, ENC_BIG_ENDIAN);
1276 proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_ntohs(parameter_tvb, offset), hmac_id_values, "Unknown"));
1277 if (id_number < (number_of_ids - 1))
1278 proto_item_append_text(parameter_item, ", ");
1280 proto_item_append_text(parameter_item, ")");
1283 static void
1284 dissect_supported_extensions_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1286 guint16 number_of_types;
1287 guint16 type_number, offset;
1289 proto_item_append_text(parameter_item, " (Supported types: ");
1290 number_of_types = (tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH) / CHUNK_TYPE_LENGTH;
1291 for(type_number = 0, offset = PARAMETER_VALUE_OFFSET; type_number < number_of_types; type_number++, offset += CHUNK_TYPE_LENGTH) {
1292 proto_tree_add_item(parameter_tree, hf_supported_chunk_type, parameter_tvb, offset, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
1293 proto_item_append_text(parameter_item, "%s", val_to_str_const(tvb_get_guint8(parameter_tvb, offset), chunk_type_values, "Unknown"));
1294 if (type_number < (number_of_types - 1))
1295 proto_item_append_text(parameter_item, ", ");
1297 proto_item_append_text(parameter_item, ")");
1300 static void
1301 dissect_forward_tsn_supported_parameter(tvbuff_t *parameter_tvb _U_)
1305 #define CORRELATION_ID_LENGTH 4
1306 #define CORRELATION_ID_OFFSET PARAMETER_VALUE_OFFSET
1307 #define ADDRESS_PARAMETER_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH)
1309 static void
1310 dissect_add_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
1312 guint16 address_length;
1313 tvbuff_t *address_tvb;
1315 address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1317 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1318 address_tvb = tvb_new_subset(parameter_tvb, ADDRESS_PARAMETER_OFFSET,
1319 MIN(address_length, tvb_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)),
1320 MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)));
1321 proto_item_append_text(parameter_item, " (Address: ");
1322 dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, FALSE, FALSE);
1323 proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1326 static void
1327 dissect_del_ip_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
1329 guint16 address_length;
1330 tvbuff_t *address_tvb;
1332 address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1334 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1335 address_tvb = tvb_new_subset(parameter_tvb, ADDRESS_PARAMETER_OFFSET,
1336 MIN(address_length, tvb_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)),
1337 MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)));
1338 proto_item_append_text(parameter_item, " (Address: ");
1339 dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, FALSE, FALSE);
1340 proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1343 #define ERROR_CAUSE_IND_CASUES_OFFSET (CORRELATION_ID_OFFSET + CORRELATION_ID_LENGTH)
1345 static void
1346 dissect_error_cause_indication_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree)
1348 guint16 causes_length;
1349 tvbuff_t *causes_tvb;
1351 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1352 causes_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1353 causes_tvb = tvb_new_subset(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET,
1354 MIN(causes_length, tvb_length_remaining(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET)),
1355 MIN(causes_length, tvb_reported_length_remaining(parameter_tvb, ERROR_CAUSE_IND_CASUES_OFFSET)));
1356 dissect_error_causes(causes_tvb, pinfo, parameter_tree);
1359 static void
1360 dissect_set_primary_address_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo, proto_tree *parameter_tree, proto_item *parameter_item)
1362 guint16 address_length;
1363 tvbuff_t *address_tvb;
1365 address_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH - CORRELATION_ID_LENGTH;
1367 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1368 address_tvb = tvb_new_subset(parameter_tvb, ADDRESS_PARAMETER_OFFSET,
1369 MIN(address_length, tvb_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)),
1370 MIN(address_length, tvb_reported_length_remaining(parameter_tvb, ADDRESS_PARAMETER_OFFSET)));
1371 proto_item_append_text(parameter_item, " (Address: ");
1372 dissect_parameter(address_tvb, pinfo, parameter_tree, parameter_item, FALSE, FALSE);
1373 proto_item_append_text(parameter_item, ", correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1376 static void
1377 dissect_success_report_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1379 proto_tree_add_item(parameter_tree, hf_correlation_id, parameter_tvb, CORRELATION_ID_OFFSET, CORRELATION_ID_LENGTH, ENC_BIG_ENDIAN);
1380 proto_item_append_text(parameter_item, " (Correlation ID: %u)", tvb_get_ntohl(parameter_tvb, CORRELATION_ID_OFFSET));
1383 #define ADAP_INDICATION_LENGTH 4
1384 #define ADAP_INDICATION_OFFSET PARAMETER_VALUE_OFFSET
1386 static void
1387 dissect_adap_indication_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1389 proto_tree_add_item(parameter_tree, hf_adap_indication, parameter_tvb, ADAP_INDICATION_OFFSET, ADAP_INDICATION_LENGTH, ENC_BIG_ENDIAN);
1390 proto_item_append_text(parameter_item, " (Indication: %u)", tvb_get_ntohl(parameter_tvb, ADAP_INDICATION_OFFSET));
1393 static void
1394 dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
1396 guint16 type, parameter_value_length;
1398 type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
1399 parameter_value_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
1401 if (parameter_value_length > 0)
1402 proto_tree_add_item(parameter_tree, hf_parameter_value, parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length, ENC_NA);
1404 proto_item_append_text(parameter_item, " (Type %u, value length: %u byte%s)", type, parameter_value_length, plurality(parameter_value_length, "", "s"));
1407 #define HEARTBEAT_INFO_PARAMETER_ID 0x0001
1408 #define IPV4ADDRESS_PARAMETER_ID 0x0005
1409 #define IPV6ADDRESS_PARAMETER_ID 0x0006
1410 #define STATE_COOKIE_PARAMETER_ID 0x0007
1411 #define UNREC_PARA_PARAMETER_ID 0x0008
1412 #define COOKIE_PRESERVATIVE_PARAMETER_ID 0x0009
1413 #define HOSTNAME_ADDRESS_PARAMETER_ID 0x000b
1414 #define SUPPORTED_ADDRESS_TYPES_PARAMETER_ID 0x000c
1415 #define OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID 0x000d
1416 #define INCOMING_SSN_RESET_REQUEST_PARAMETER_ID 0x000e
1417 #define SSN_TSN_RESET_REQUEST_PARAMETER_ID 0x000f
1418 #define RE_CONFIGURATION_RESPONSE_PARAMETER_ID 0x0010
1419 #define ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID 0x0011
1420 #define ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID 0x0012
1421 #define ECN_PARAMETER_ID 0x8000
1422 #define NONCE_SUPPORTED_PARAMETER_ID 0x8001
1423 #define RANDOM_PARAMETER_ID 0x8002
1424 #define CHUNKS_PARAMETER_ID 0x8003
1425 #define HMAC_ALGO_PARAMETER_ID 0x8004
1426 #define SUPPORTED_EXTENSIONS_PARAMETER_ID 0x8008
1427 #define FORWARD_TSN_SUPPORTED_PARAMETER_ID 0xC000
1428 #define ADD_IP_ADDRESS_PARAMETER_ID 0xC001
1429 #define DEL_IP_ADDRESS_PARAMETER_ID 0xC002
1430 #define ERROR_CAUSE_INDICATION_PARAMETER_ID 0xC003
1431 #define SET_PRIMARY_ADDRESS_PARAMETER_ID 0xC004
1432 #define SUCCESS_REPORT_PARAMETER_ID 0xC005
1433 #define ADAP_LAYER_INDICATION_PARAMETER_ID 0xC006
1435 static const value_string parameter_identifier_values[] = {
1436 { HEARTBEAT_INFO_PARAMETER_ID, "Heartbeat info" },
1437 { IPV4ADDRESS_PARAMETER_ID, "IPv4 address" },
1438 { IPV6ADDRESS_PARAMETER_ID, "IPv6 address" },
1439 { STATE_COOKIE_PARAMETER_ID, "State cookie" },
1440 { UNREC_PARA_PARAMETER_ID, "Unrecognized parameter" },
1441 { COOKIE_PRESERVATIVE_PARAMETER_ID, "Cookie preservative" },
1442 { HOSTNAME_ADDRESS_PARAMETER_ID, "Hostname address" },
1443 { OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID, "Outgoing SSN reset request" },
1444 { INCOMING_SSN_RESET_REQUEST_PARAMETER_ID, "Incoming SSN reset request" },
1445 { SSN_TSN_RESET_REQUEST_PARAMETER_ID, "SSN/TSN reset request" },
1446 { RE_CONFIGURATION_RESPONSE_PARAMETER_ID, "Re-configuration response" },
1447 { ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID, "Add outgoing streams request" },
1448 { ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID, "Add incoming streams request" },
1449 { SUPPORTED_ADDRESS_TYPES_PARAMETER_ID, "Supported address types" },
1450 { ECN_PARAMETER_ID, "ECN" },
1451 { NONCE_SUPPORTED_PARAMETER_ID, "Nonce supported" },
1452 { RANDOM_PARAMETER_ID, "Random" },
1453 { CHUNKS_PARAMETER_ID, "Authenticated Chunk list" },
1454 { HMAC_ALGO_PARAMETER_ID, "Requested HMAC Algorithm" },
1455 { SUPPORTED_EXTENSIONS_PARAMETER_ID, "Supported Extensions" },
1456 { FORWARD_TSN_SUPPORTED_PARAMETER_ID, "Forward TSN supported" },
1457 { ADD_IP_ADDRESS_PARAMETER_ID, "Add IP address" },
1458 { DEL_IP_ADDRESS_PARAMETER_ID, "Delete IP address" },
1459 { ERROR_CAUSE_INDICATION_PARAMETER_ID, "Error cause indication" },
1460 { SET_PRIMARY_ADDRESS_PARAMETER_ID, "Set primary address" },
1461 { SUCCESS_REPORT_PARAMETER_ID, "Success report" },
1462 { ADAP_LAYER_INDICATION_PARAMETER_ID, "Adaptation Layer Indication" },
1463 { 0, NULL } };
1465 #define SCTP_PARAMETER_BIT_1 0x8000
1466 #define SCTP_PARAMETER_BIT_2 0x4000
1468 static const true_false_string sctp_parameter_bit_1_value = {
1469 "Skip parameter and continue processing of the chunk",
1470 "Stop processing of chunk"
1473 static const true_false_string sctp_parameter_bit_2_value = {
1474 "Do report",
1475 "Do not report"
1478 static void
1479 dissect_parameter(tvbuff_t *parameter_tvb, packet_info *pinfo,
1480 proto_tree *chunk_tree, proto_item *additional_item,
1481 gboolean dissecting_init_init_ack_chunk,
1482 gboolean final_parameter)
1484 guint16 type, length, padding_length, reported_length;
1485 proto_item *parameter_item, *type_item;
1486 proto_tree *parameter_tree, *type_tree;
1488 type = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
1489 length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
1490 reported_length = tvb_reported_length(parameter_tvb);
1491 padding_length = reported_length - length;
1493 parameter_item = proto_tree_add_text(chunk_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, tvb_reported_length(parameter_tvb), "%s parameter", val_to_str_const(type, parameter_identifier_values, "Unknown"));
1494 parameter_tree = proto_item_add_subtree(parameter_item, ett_sctp_chunk_parameter);
1495 if (final_parameter) {
1496 if (padding_length > 0) {
1497 expert_add_info(pinfo, parameter_item, &ei_sctp_parameter_padding);
1499 } else {
1500 if (reported_length % 4) {
1501 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);
1505 if (!(chunk_tree || (dissecting_init_init_ack_chunk && (type == IPV4ADDRESS_PARAMETER_ID || type == IPV6ADDRESS_PARAMETER_ID))))
1506 return;
1508 if (chunk_tree) {
1509 type_item = proto_tree_add_item(parameter_tree, hf_parameter_type, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1510 type_tree = proto_item_add_subtree(type_item, ett_sctp_parameter_type);
1511 proto_tree_add_item(type_tree, hf_parameter_bit_1, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1512 proto_tree_add_item(type_tree, hf_parameter_bit_2, parameter_tvb, PARAMETER_TYPE_OFFSET, PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1513 proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, ENC_BIG_ENDIAN);
1514 /* XXX - add expert info if length is bogus? */
1515 } else {
1516 parameter_item = NULL;
1517 parameter_tree = NULL;
1520 switch(type) {
1521 case HEARTBEAT_INFO_PARAMETER_ID:
1522 dissect_heartbeat_info_parameter(parameter_tvb, parameter_tree, parameter_item);
1523 break;
1524 case IPV4ADDRESS_PARAMETER_ID:
1525 dissect_ipv4_parameter(parameter_tvb, parameter_tree, parameter_item, additional_item, dissecting_init_init_ack_chunk);
1526 break;
1527 case IPV6ADDRESS_PARAMETER_ID:
1528 dissect_ipv6_parameter(parameter_tvb, parameter_tree, parameter_item, additional_item, dissecting_init_init_ack_chunk);
1529 break;
1530 case STATE_COOKIE_PARAMETER_ID:
1531 dissect_state_cookie_parameter(parameter_tvb, parameter_tree, parameter_item);
1532 break;
1533 case UNREC_PARA_PARAMETER_ID:
1534 dissect_unrecognized_parameters_parameter(parameter_tvb, pinfo, parameter_tree);
1535 break;
1536 case COOKIE_PRESERVATIVE_PARAMETER_ID:
1537 dissect_cookie_preservative_parameter(parameter_tvb, parameter_tree, parameter_item);
1538 break;
1539 case HOSTNAME_ADDRESS_PARAMETER_ID:
1540 dissect_hostname_parameter(parameter_tvb, parameter_tree, parameter_item);
1541 break;
1542 case SUPPORTED_ADDRESS_TYPES_PARAMETER_ID:
1543 dissect_supported_address_types_parameter(parameter_tvb, parameter_tree, parameter_item);
1544 break;
1545 case OUTGOING_SSN_RESET_REQUEST_PARAMETER_ID:
1546 dissect_outgoing_ssn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item);
1547 break;
1548 case INCOMING_SSN_RESET_REQUEST_PARAMETER_ID:
1549 dissect_incoming_ssn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item);
1550 break;
1551 case SSN_TSN_RESET_REQUEST_PARAMETER_ID:
1552 dissect_ssn_tsn_reset_request_parameter(parameter_tvb, parameter_tree, parameter_item);
1553 break;
1554 case RE_CONFIGURATION_RESPONSE_PARAMETER_ID:
1555 dissect_re_configuration_response_parameter(parameter_tvb, parameter_tree, parameter_item);
1556 break;
1557 case ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_ID:
1558 dissect_add_outgoing_streams_parameter(parameter_tvb, parameter_tree, parameter_item);
1559 break;
1560 case ADD_INCOMING_STREAMS_REQUEST_PARAMETER_ID:
1561 dissect_add_incoming_streams_parameter(parameter_tvb, parameter_tree, parameter_item);
1562 break;
1563 case ECN_PARAMETER_ID:
1564 dissect_ecn_parameter(parameter_tvb);
1565 break;
1566 case NONCE_SUPPORTED_PARAMETER_ID:
1567 dissect_nonce_supported_parameter(parameter_tvb);
1568 break;
1569 case RANDOM_PARAMETER_ID:
1570 dissect_random_parameter(parameter_tvb, parameter_tree);
1571 break;
1572 case CHUNKS_PARAMETER_ID:
1573 dissect_chunks_parameter(parameter_tvb, parameter_tree, parameter_item);
1574 break;
1575 case HMAC_ALGO_PARAMETER_ID:
1576 dissect_hmac_algo_parameter(parameter_tvb, parameter_tree, parameter_item);
1577 break;
1578 case SUPPORTED_EXTENSIONS_PARAMETER_ID:
1579 dissect_supported_extensions_parameter(parameter_tvb, parameter_tree, parameter_item);
1580 break;
1581 case FORWARD_TSN_SUPPORTED_PARAMETER_ID:
1582 dissect_forward_tsn_supported_parameter(parameter_tvb);
1583 break;
1584 case ADD_IP_ADDRESS_PARAMETER_ID:
1585 dissect_add_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
1586 break;
1587 case DEL_IP_ADDRESS_PARAMETER_ID:
1588 dissect_del_ip_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
1589 break;
1590 case ERROR_CAUSE_INDICATION_PARAMETER_ID:
1591 dissect_error_cause_indication_parameter(parameter_tvb, pinfo, parameter_tree);
1592 break;
1593 case SET_PRIMARY_ADDRESS_PARAMETER_ID:
1594 dissect_set_primary_address_parameter(parameter_tvb, pinfo, parameter_tree, parameter_item);
1595 break;
1596 case SUCCESS_REPORT_PARAMETER_ID:
1597 dissect_success_report_parameter(parameter_tvb, parameter_tree, parameter_item);
1598 break;
1599 case ADAP_LAYER_INDICATION_PARAMETER_ID:
1600 dissect_adap_indication_parameter(parameter_tvb, parameter_tree, parameter_item);
1601 break;
1602 default:
1603 dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
1604 break;
1607 if (padding_length > 0) {
1608 proto_tree_add_item(parameter_tree, hf_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, ENC_NA);
1612 static void
1613 dissect_parameters(tvbuff_t *parameters_tvb, packet_info *pinfo, proto_tree *tree, proto_item *additional_item, gboolean dissecting_init_init_ack_chunk)
1615 gint offset, length, total_length, remaining_length;
1616 tvbuff_t *parameter_tvb;
1617 gboolean final_parameter;
1619 offset = 0;
1620 remaining_length = tvb_reported_length_remaining(parameters_tvb, offset);
1621 while (remaining_length > 0) {
1622 if ((offset > 0) && additional_item)
1623 proto_item_append_text(additional_item, " ");
1625 length = tvb_get_ntohs(parameters_tvb, offset + PARAMETER_LENGTH_OFFSET);
1626 total_length = ADD_PADDING(length);
1628 /* If we have less bytes than we need, throw an exception while dissecting
1629 * the parameter--not when generating the parameter_tvb below.
1631 total_length = MIN(total_length, remaining_length);
1633 /* create a tvb for the parameter including the padding bytes */
1634 parameter_tvb = tvb_new_subset(parameters_tvb, offset, MIN(total_length, tvb_length_remaining(parameters_tvb, offset)), total_length);
1635 /* get rid of the handled parameter */
1636 offset += total_length;
1637 remaining_length = tvb_reported_length_remaining(parameters_tvb, offset);
1638 if (remaining_length > 0) {
1639 final_parameter = FALSE;
1640 } else {
1641 final_parameter = TRUE;
1643 dissect_parameter(parameter_tvb, pinfo, tree, additional_item, dissecting_init_init_ack_chunk, final_parameter);
1649 * Code to handle error causes for ABORT and ERROR chunks
1653 #define CAUSE_CODE_LENGTH 2
1654 #define CAUSE_LENGTH_LENGTH 2
1655 #define CAUSE_HEADER_LENGTH (CAUSE_CODE_LENGTH + CAUSE_LENGTH_LENGTH)
1657 #define CAUSE_HEADER_OFFSET 0
1658 #define CAUSE_CODE_OFFSET CAUSE_HEADER_OFFSET
1659 #define CAUSE_LENGTH_OFFSET (CAUSE_CODE_OFFSET + CAUSE_CODE_LENGTH)
1660 #define CAUSE_INFO_OFFSET (CAUSE_LENGTH_OFFSET + CAUSE_LENGTH_LENGTH)
1663 #define CAUSE_STREAM_IDENTIFIER_LENGTH 2
1664 #define CAUSE_RESERVED_LENGTH 2
1665 #define CAUSE_STREAM_IDENTIFIER_OFFSET CAUSE_INFO_OFFSET
1666 #define CAUSE_RESERVED_OFFSET (CAUSE_STREAM_IDENTIFIER_OFFSET + CAUSE_STREAM_IDENTIFIER_LENGTH)
1668 static void
1669 dissect_invalid_stream_identifier_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
1671 proto_tree_add_item(cause_tree, hf_cause_stream_identifier, cause_tvb, CAUSE_STREAM_IDENTIFIER_OFFSET, CAUSE_STREAM_IDENTIFIER_LENGTH, ENC_BIG_ENDIAN);
1672 proto_tree_add_item(cause_tree, hf_cause_reserved, cause_tvb, CAUSE_RESERVED_OFFSET, CAUSE_RESERVED_LENGTH, ENC_BIG_ENDIAN);
1673 proto_item_append_text(cause_item, " (SID: %u)", tvb_get_ntohs(cause_tvb, CAUSE_STREAM_IDENTIFIER_OFFSET));
1676 #define CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH 4
1677 #define CAUSE_MISSING_PARAMETER_TYPE_LENGTH 2
1679 #define CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET CAUSE_INFO_OFFSET
1680 #define CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET (CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET + \
1681 CAUSE_NUMBER_OF_MISSING_PARAMETERS_LENGTH )
1683 static void
1684 dissect_missing_mandatory_parameters_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree)
1686 guint32 number_of_missing_parameters, missing_parameter_number;
1687 guint offset;
1689 number_of_missing_parameters = tvb_get_ntohl(cause_tvb, CAUSE_NUMBER_OF_MISSING_PARAMETERS_OFFSET);
1690 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);
1691 offset = CAUSE_FIRST_MISSING_PARAMETER_TYPE_OFFSET;
1692 for(missing_parameter_number = 0; missing_parameter_number < number_of_missing_parameters; missing_parameter_number++) {
1693 proto_tree_add_item(cause_tree, hf_cause_missing_parameter_type, cause_tvb, offset, CAUSE_MISSING_PARAMETER_TYPE_LENGTH, ENC_BIG_ENDIAN);
1694 offset += CAUSE_MISSING_PARAMETER_TYPE_LENGTH;
1698 #define CAUSE_MEASURE_OF_STALENESS_LENGTH 4
1699 #define CAUSE_MEASURE_OF_STALENESS_OFFSET CAUSE_INFO_OFFSET
1701 static void
1702 dissect_stale_cookie_error_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
1704 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);
1705 proto_item_append_text(cause_item, " (Measure: %u usec)", tvb_get_ntohl(cause_tvb, CAUSE_MEASURE_OF_STALENESS_OFFSET));
1708 static void
1709 dissect_out_of_resource_cause(tvbuff_t *cause_tvb _U_)
1713 static void
1714 dissect_unresolvable_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
1716 guint16 parameter_length;
1717 tvbuff_t *parameter_tvb;
1719 parameter_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1720 parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1721 MIN(parameter_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1722 MIN(parameter_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1723 proto_item_append_text(cause_item, " (Address: ");
1724 dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, FALSE, FALSE);
1725 proto_item_append_text(cause_item, ")");
1728 static gboolean
1729 dissect_sctp_chunk(tvbuff_t *chunk_tvb, packet_info *pinfo, proto_tree *tree, proto_tree *sctp_tree, sctp_half_assoc_t *assoc, gboolean useinfo);
1731 static void
1732 dissect_unrecognized_chunk_type_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
1734 guint16 chunk_length;
1735 guint8 unrecognized_type;
1736 tvbuff_t *unrecognized_chunk_tvb;
1738 chunk_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1739 unrecognized_chunk_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1740 MIN(chunk_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1741 MIN(chunk_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1742 dissect_sctp_chunk(unrecognized_chunk_tvb, pinfo, cause_tree,cause_tree, NULL, FALSE);
1743 unrecognized_type = tvb_get_guint8(unrecognized_chunk_tvb, CHUNK_TYPE_OFFSET);
1744 proto_item_append_text(cause_item, " (Type: %u (%s))", unrecognized_type, val_to_str_const(unrecognized_type, chunk_type_values, "unknown"));
1747 static void
1748 dissect_invalid_mandatory_parameter_cause(tvbuff_t *cause_tvb _U_)
1752 static void
1753 dissect_unrecognized_parameters_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree)
1755 guint16 cause_info_length;
1756 tvbuff_t *unrecognized_parameters_tvb;
1758 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1760 unrecognized_parameters_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1761 MIN(cause_info_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1762 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1763 dissect_parameters(unrecognized_parameters_tvb, pinfo, cause_tree, NULL, FALSE);
1766 #define CAUSE_TSN_LENGTH 4
1767 #define CAUSE_TSN_OFFSET CAUSE_INFO_OFFSET
1769 static void
1770 dissect_no_user_data_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
1772 proto_tree_add_item(cause_tree, hf_cause_tsn, cause_tvb, CAUSE_TSN_OFFSET, CAUSE_TSN_LENGTH, ENC_BIG_ENDIAN);
1773 proto_item_append_text(cause_item, " (TSN: %u)", tvb_get_ntohl(cause_tvb, CAUSE_TSN_OFFSET));
1776 static void
1777 dissect_cookie_received_while_shutting_down_cause(tvbuff_t *cause_tvb _U_)
1781 static void
1782 dissect_restart_with_new_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
1784 guint16 cause_info_length;
1785 tvbuff_t *parameter_tvb;
1787 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1788 parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1789 MIN(cause_info_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1790 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1791 proto_item_append_text(cause_item, " (New addresses: ");
1792 dissect_parameters(parameter_tvb, pinfo, cause_tree, cause_item, FALSE);
1793 proto_item_append_text(cause_item, ")");
1796 static void
1797 dissect_user_initiated_abort_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree)
1799 guint16 cause_info_length;
1801 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1802 if (cause_info_length > 0)
1803 proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
1806 static void
1807 dissect_protocol_violation_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree)
1809 guint16 cause_info_length;
1811 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1812 if (cause_info_length > 0)
1813 proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
1816 static void
1817 dissect_delete_last_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
1819 guint16 cause_info_length;
1820 tvbuff_t *parameter_tvb;
1822 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1823 parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1824 MIN(cause_info_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1825 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1826 proto_item_append_text(cause_item, " (Last address: ");
1827 dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, FALSE, FALSE);
1828 proto_item_append_text(cause_item, ")");
1831 static void
1832 dissect_resource_outage_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree)
1834 guint16 cause_info_length;
1835 tvbuff_t *parameter_tvb;
1837 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1838 parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1839 MIN(cause_info_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1840 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1841 dissect_parameter(parameter_tvb, pinfo, cause_tree, NULL, FALSE, FALSE);
1844 static void
1845 dissect_delete_source_address_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree, proto_item *cause_item)
1847 guint16 cause_info_length;
1848 tvbuff_t *parameter_tvb;
1850 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1851 parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1852 MIN(cause_info_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1853 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1854 proto_item_append_text(cause_item, " (Deleted address: ");
1855 dissect_parameter(parameter_tvb, pinfo, cause_tree, cause_item, FALSE, FALSE);
1856 proto_item_append_text(cause_item, ")");
1859 static void
1860 dissect_request_refused_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *cause_tree)
1862 guint16 cause_info_length;
1863 tvbuff_t *parameter_tvb;
1865 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1866 parameter_tvb = tvb_new_subset(cause_tvb, CAUSE_INFO_OFFSET,
1867 MIN(cause_info_length, tvb_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)),
1868 MIN(cause_info_length, tvb_reported_length_remaining(cause_tvb, CAUSE_INFO_OFFSET)));
1869 dissect_parameter(parameter_tvb, pinfo, cause_tree, NULL, FALSE, FALSE);
1872 static void
1873 dissect_unsupported_hmac_id_cause(tvbuff_t *cause_tvb, packet_info *pinfo _U_, proto_tree *cause_tree)
1875 proto_tree_add_item(cause_tree, hf_hmac_id, cause_tvb, CAUSE_INFO_OFFSET, HMAC_ID_LENGTH, ENC_BIG_ENDIAN);
1878 static void
1879 dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
1881 guint16 cause_info_length;
1883 cause_info_length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET) - CAUSE_HEADER_LENGTH;
1884 if (cause_info_length > 0)
1885 proto_tree_add_item(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length, ENC_NA);
1886 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"));
1889 #define INVALID_STREAM_IDENTIFIER 0x01
1890 #define MISSING_MANDATORY_PARAMETERS 0x02
1891 #define STALE_COOKIE_ERROR 0x03
1892 #define OUT_OF_RESOURCE 0x04
1893 #define UNRESOLVABLE_ADDRESS 0x05
1894 #define UNRECOGNIZED_CHUNK_TYPE 0x06
1895 #define INVALID_MANDATORY_PARAMETER 0x07
1896 #define UNRECOGNIZED_PARAMETERS 0x08
1897 #define NO_USER_DATA 0x09
1898 #define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN 0x0a
1899 #define RESTART_WITH_NEW_ADDRESSES 0x0b
1900 #define USER_INITIATED_ABORT 0x0c
1901 #define PROTOCOL_VIOLATION 0x0d
1902 #define REQUEST_TO_DELETE_LAST_ADDRESS 0x00a0
1903 #define OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE 0x00a1
1904 #define REQUEST_TO_DELETE_SOURCE_ADDRESS 0x00a2
1905 #define ABORT_DUE_TO_ILLEGAL_ASCONF 0x00a3
1906 #define REQUEST_REFUSED 0x00a4
1907 #define UNSUPPORTED_HMAC_ID 0x0105
1909 static const value_string cause_code_values[] = {
1910 { INVALID_STREAM_IDENTIFIER, "Invalid stream identifier" },
1911 { MISSING_MANDATORY_PARAMETERS, "Missing mandatory parameter" },
1912 { STALE_COOKIE_ERROR, "Stale cookie error" },
1913 { OUT_OF_RESOURCE, "Out of resource" },
1914 { UNRESOLVABLE_ADDRESS, "Unresolvable address" },
1915 { UNRECOGNIZED_CHUNK_TYPE, "Unrecognized chunk type" },
1916 { INVALID_MANDATORY_PARAMETER, "Invalid mandatory parameter" },
1917 { UNRECOGNIZED_PARAMETERS, "Unrecognized parameters" },
1918 { NO_USER_DATA, "No user data" },
1919 { COOKIE_RECEIVED_WHILE_SHUTTING_DOWN, "Cookie received while shutting down" },
1920 { RESTART_WITH_NEW_ADDRESSES, "Restart of an association with new addresses" },
1921 { USER_INITIATED_ABORT, "User initiated ABORT" },
1922 { PROTOCOL_VIOLATION, "Protocol violation" },
1923 { REQUEST_TO_DELETE_LAST_ADDRESS, "Request to delete last address" },
1924 { OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE, "Operation refused due to resource shortage" },
1925 { REQUEST_TO_DELETE_SOURCE_ADDRESS, "Request to delete source address" },
1926 { ABORT_DUE_TO_ILLEGAL_ASCONF, "Association Aborted due to illegal ASCONF-ACK" },
1927 { REQUEST_REFUSED, "Request refused - no authorization" },
1928 { UNSUPPORTED_HMAC_ID, "Unsupported HMAC identifier" },
1929 { 0, NULL } };
1932 static void
1933 dissect_error_cause(tvbuff_t *cause_tvb, packet_info *pinfo, proto_tree *chunk_tree)
1935 guint16 code, length, padding_length;
1936 proto_item *cause_item;
1937 proto_tree *cause_tree;
1939 code = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET);
1940 length = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
1941 padding_length = tvb_reported_length(cause_tvb) - length;
1943 cause_item = proto_tree_add_text(chunk_tree, cause_tvb, CAUSE_HEADER_OFFSET, tvb_reported_length(cause_tvb), "%s cause", val_to_str_const(code, cause_code_values, "Unknown"));
1944 cause_tree = proto_item_add_subtree(cause_item, ett_sctp_chunk_cause);
1946 proto_tree_add_item(cause_tree, hf_cause_code, cause_tvb, CAUSE_CODE_OFFSET, CAUSE_CODE_LENGTH, ENC_BIG_ENDIAN);
1947 proto_tree_add_item(cause_tree, hf_cause_length, cause_tvb, CAUSE_LENGTH_OFFSET, CAUSE_LENGTH_LENGTH, ENC_BIG_ENDIAN);
1948 /* XXX - add expert info if length is bogus? */
1950 switch(code) {
1951 case INVALID_STREAM_IDENTIFIER:
1952 dissect_invalid_stream_identifier_cause(cause_tvb, cause_tree, cause_item);
1953 break;
1954 case MISSING_MANDATORY_PARAMETERS:
1955 dissect_missing_mandatory_parameters_cause(cause_tvb, cause_tree);
1956 break;
1957 case STALE_COOKIE_ERROR:
1958 dissect_stale_cookie_error_cause(cause_tvb, cause_tree, cause_item);
1959 break;
1960 case OUT_OF_RESOURCE:
1961 dissect_out_of_resource_cause(cause_tvb);
1962 break;
1963 case UNRESOLVABLE_ADDRESS:
1964 dissect_unresolvable_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
1965 break;
1966 case UNRECOGNIZED_CHUNK_TYPE:
1967 dissect_unrecognized_chunk_type_cause(cause_tvb, pinfo, cause_tree, cause_item);
1968 break;
1969 case INVALID_MANDATORY_PARAMETER:
1970 dissect_invalid_mandatory_parameter_cause(cause_tvb);
1971 break;
1972 case UNRECOGNIZED_PARAMETERS:
1973 dissect_unrecognized_parameters_cause(cause_tvb, pinfo, cause_tree);
1974 break;
1975 case NO_USER_DATA:
1976 dissect_no_user_data_cause(cause_tvb, cause_tree, cause_item);
1977 break;
1978 case COOKIE_RECEIVED_WHILE_SHUTTING_DOWN:
1979 dissect_cookie_received_while_shutting_down_cause(cause_tvb);
1980 break;
1981 case RESTART_WITH_NEW_ADDRESSES:
1982 dissect_restart_with_new_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
1983 break;
1984 case USER_INITIATED_ABORT:
1985 dissect_user_initiated_abort_cause(cause_tvb, cause_tree);
1986 break;
1987 case PROTOCOL_VIOLATION:
1988 dissect_protocol_violation_cause(cause_tvb, cause_tree);
1989 break;
1990 case REQUEST_TO_DELETE_LAST_ADDRESS:
1991 dissect_delete_last_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
1992 break;
1993 case OPERATION_REFUSED_DUE_TO_RESOURCE_SHORTAGE:
1994 dissect_resource_outage_cause(cause_tvb, pinfo, cause_tree);
1995 break;
1996 case REQUEST_TO_DELETE_SOURCE_ADDRESS:
1997 dissect_delete_source_address_cause(cause_tvb, pinfo, cause_tree, cause_item);
1998 break;
1999 case REQUEST_REFUSED:
2000 dissect_request_refused_cause(cause_tvb, pinfo, cause_tree);
2001 break;
2002 case UNSUPPORTED_HMAC_ID:
2003 dissect_unsupported_hmac_id_cause(cause_tvb, pinfo, cause_tree);
2004 break;
2005 default:
2006 dissect_unknown_cause(cause_tvb, cause_tree, cause_item);
2007 break;
2010 if (padding_length > 0)
2011 proto_tree_add_item(cause_tree, hf_cause_padding, cause_tvb, CAUSE_HEADER_OFFSET + length, padding_length, ENC_NA);
2014 static void
2015 dissect_error_causes(tvbuff_t *causes_tvb, packet_info *pinfo, proto_tree *tree)
2017 gint offset, length, total_length, remaining_length;
2018 tvbuff_t *cause_tvb;
2020 offset = 0;
2021 while((remaining_length = tvb_reported_length_remaining(causes_tvb, offset))) {
2022 length = tvb_get_ntohs(causes_tvb, offset + CAUSE_LENGTH_OFFSET);
2023 total_length = ADD_PADDING(length);
2025 /* If we have less bytes than we need, throw an exception while dissecting
2026 * the cause--not when generating the causes_tvb below.
2028 total_length = MIN(total_length, remaining_length);
2030 /* create a tvb for the parameter including the padding bytes */
2031 cause_tvb = tvb_new_subset(causes_tvb, offset, MIN(total_length, tvb_length_remaining(causes_tvb, offset)), total_length);
2033 dissect_error_cause(cause_tvb, pinfo, tree);
2035 /* get rid of the handled cause */
2036 offset += total_length;
2042 * Code to actually dissect the packets
2045 static gboolean try_heuristic_first = FALSE;
2047 static gboolean
2048 dissect_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree, guint32 ppi)
2050 guint32 low_port, high_port;
2052 pinfo->ppid = ppi;
2054 if (enable_ulp_dissection) {
2055 if (try_heuristic_first) {
2056 /* do lookup with the heuristic subdissector table */
2057 if (dissector_try_heuristic(sctp_heur_subdissector_list, payload_tvb, pinfo, tree, NULL))
2058 return TRUE;
2061 /* Do lookups with the subdissector table.
2063 When trying port numbers, we try the port number with the lower value
2064 first, followed by the port number with the higher value. This means
2065 that, for packets where a dissector is registered for *both* port
2066 numbers, and where there's no match on the PPI:
2068 1) we pick the same dissector for traffic going in both directions;
2070 2) we prefer the port number that's more likely to be the right
2071 one (as that prefers well-known ports to reserved ports);
2073 although there is, of course, no guarantee that any such strategy
2074 will always pick the right port number.
2076 XXX - we ignore port numbers of 0, as some dissectors use a port
2077 number of 0 to disable the port. */
2078 if (dissector_try_uint(sctp_ppi_dissector_table, ppi, payload_tvb, pinfo, tree))
2079 return TRUE;
2080 if (pinfo->srcport > pinfo->destport) {
2081 low_port = pinfo->destport;
2082 high_port = pinfo->srcport;
2083 } else {
2084 low_port = pinfo->srcport;
2085 high_port = pinfo->destport;
2087 if (low_port != 0 &&
2088 dissector_try_uint(sctp_port_dissector_table, low_port, payload_tvb, pinfo, tree))
2089 return TRUE;
2090 if (high_port != 0 &&
2091 dissector_try_uint(sctp_port_dissector_table, high_port, payload_tvb, pinfo, tree))
2092 return TRUE;
2094 if (!try_heuristic_first) {
2095 /* do lookup with the heuristic subdissector table */
2096 if (dissector_try_heuristic(sctp_heur_subdissector_list, payload_tvb, pinfo, tree, NULL))
2097 return TRUE;
2100 /* Oh, well, we don't know this; dissect it as data. */
2101 call_dissector(data_handle, payload_tvb, pinfo, tree);
2102 return TRUE;
2105 #define DATA_CHUNK_TSN_LENGTH 4
2106 #define DATA_CHUNK_STREAM_ID_LENGTH 2
2107 #define DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH 2
2108 #define DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH 4
2110 #define DATA_CHUNK_TSN_OFFSET (CHUNK_VALUE_OFFSET + 0)
2111 #define DATA_CHUNK_STREAM_ID_OFFSET (DATA_CHUNK_TSN_OFFSET + DATA_CHUNK_TSN_LENGTH)
2112 #define DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET (DATA_CHUNK_STREAM_ID_OFFSET + \
2113 DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH)
2114 #define DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET (DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET + \
2115 DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH)
2116 #define DATA_CHUNK_PAYLOAD_OFFSET (DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET + \
2117 DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH)
2119 #define DATA_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \
2120 DATA_CHUNK_TSN_LENGTH + \
2121 DATA_CHUNK_STREAM_ID_LENGTH + \
2122 DATA_CHUNK_STREAM_SEQ_NUMBER_LENGTH + \
2123 DATA_CHUNK_PAYLOAD_PROTOCOL_ID_LENGTH)
2125 #define SCTP_DATA_CHUNK_E_BIT 0x01
2126 #define SCTP_DATA_CHUNK_B_BIT 0x02
2127 #define SCTP_DATA_CHUNK_U_BIT 0x04
2128 #define SCTP_DATA_CHUNK_I_BIT 0x08
2130 /* table to hold fragmented SCTP messages */
2131 static GHashTable *frag_table = NULL;
2134 typedef struct _frag_key {
2135 guint16 sport;
2136 guint16 dport;
2137 guint32 verification_tag;
2138 guint16 stream_id;
2139 guint16 stream_seq_num;
2140 } frag_key;
2143 static gint
2144 frag_equal(gconstpointer k1, gconstpointer k2)
2146 const frag_key *key1 = (const frag_key *) k1;
2147 const frag_key *key2 = (const frag_key *) k2;
2149 return ( (key1->sport == key2->sport) &&
2150 (key1->dport == key2->dport) &&
2151 (key1->verification_tag == key2->verification_tag) &&
2152 (key1->stream_id == key2->stream_id) &&
2153 (key1->stream_seq_num == key2->stream_seq_num)
2154 ? TRUE : FALSE);
2158 static guint
2159 frag_hash(gconstpointer k)
2161 const frag_key *key = (const frag_key *) k;
2163 return key->sport ^ key->dport ^ key->verification_tag ^
2164 key->stream_id ^ key->stream_seq_num;
2169 static void
2170 frag_free_msgs(sctp_frag_msg *msg)
2172 sctp_frag_be *beginend;
2173 sctp_fragment *fragment;
2175 /* free all begins */
2176 while (msg->begins) {
2177 beginend = msg->begins;
2178 msg->begins = msg->begins->next;
2179 g_free(beginend);
2182 /* free all ends */
2183 while (msg->ends) {
2184 beginend = msg->ends;
2185 msg->ends = msg->ends->next;
2186 g_free(beginend);
2189 /* free all fragments */
2190 while (msg->fragments) {
2191 fragment = msg->fragments;
2192 msg->fragments = msg->fragments->next;
2193 g_free(fragment->data);
2194 g_free(fragment);
2197 /* msg->messages is wmem_ allocated, no need to free it */
2199 g_free(msg);
2202 static gboolean
2203 free_table_entry(gpointer key, gpointer value, gpointer user_data _U_)
2205 sctp_frag_msg *msg = (sctp_frag_msg *)value;
2206 frag_key *fkey = (frag_key *)key;
2208 frag_free_msgs(msg);
2209 g_free(fkey);
2210 return TRUE;
2213 static void
2214 frag_table_init(void)
2216 /* destroy an existing hash table and create a new one */
2217 if (frag_table) {
2218 g_hash_table_foreach_remove(frag_table, free_table_entry, NULL);
2219 g_hash_table_destroy(frag_table);
2220 frag_table=NULL;
2223 frag_table = g_hash_table_new(frag_hash, frag_equal);
2227 static sctp_frag_msg*
2228 find_message(guint16 stream_id, guint16 stream_seq_num)
2230 frag_key key;
2232 key.sport = sctp_info.sport;
2233 key.dport = sctp_info.dport;
2234 key.verification_tag = sctp_info.verification_tag;
2235 key.stream_id = stream_id;
2236 key.stream_seq_num = stream_seq_num;
2238 return (sctp_frag_msg *)g_hash_table_lookup(frag_table, &key);
2242 static sctp_fragment*
2243 find_fragment(guint32 tsn, guint16 stream_id, guint16 stream_seq_num)
2245 sctp_frag_msg *msg;
2246 sctp_fragment *next_fragment;
2248 msg = find_message(stream_id, stream_seq_num);
2250 if (msg) {
2251 next_fragment = msg->fragments;
2252 while (next_fragment) {
2253 if (next_fragment->tsn == tsn)
2254 return next_fragment;
2255 next_fragment = next_fragment->next;
2259 return NULL;
2263 static sctp_fragment*
2264 add_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 tsn,
2265 guint16 stream_id, guint16 stream_seq_num, guint8 b_bit, guint8 e_bit)
2267 sctp_frag_msg *msg;
2268 sctp_fragment *fragment, *last_fragment;
2269 sctp_frag_be *beginend, *last_beginend;
2270 frag_key *key;
2272 /* lookup message. if not found, create it */
2273 msg = find_message(stream_id, stream_seq_num);
2275 if (!msg) {
2276 msg = (sctp_frag_msg *)g_malloc (sizeof (sctp_frag_msg));
2277 msg->begins = NULL;
2278 msg->ends = NULL;
2279 msg->fragments = NULL;
2280 msg->messages = NULL;
2281 msg->next = NULL;
2283 key = (frag_key *)g_malloc(sizeof (frag_key));
2284 key->sport = sctp_info.sport;
2285 key->dport = sctp_info.dport;
2286 key->verification_tag = sctp_info.verification_tag;
2287 key->stream_id = stream_id;
2288 key->stream_seq_num = stream_seq_num;
2290 g_hash_table_insert(frag_table, key, msg);
2293 /* lookup segment. if not found, create it */
2294 fragment = find_fragment(tsn, stream_id, stream_seq_num);
2296 if (fragment) {
2297 /* this fragment is already known.
2298 * compare frame number to check if it's a duplicate
2300 if (fragment->frame_num == pinfo->fd->num) {
2301 return fragment;
2302 } else {
2303 /* There already is a fragment having the same ports, v_tag,
2304 * stream id, stream_seq_num and tsn but it appeared in a different
2305 * frame, so it must be a duplicate fragment. Maybe a retransmission?
2306 * Mark it as duplicate and return NULL.
2308 * Note: This won't happen if TSN analysis is on: the caller will have
2309 * detected the retransmission and not pass it to the reassembly code.
2311 col_append_str(pinfo->cinfo, COL_INFO, "(Duplicate Message Fragment) ");
2313 proto_tree_add_uint(tree, hf_sctp_duplicate, tvb, 0, 0, fragment->frame_num);
2314 return NULL;
2318 /* There is no point in storing a fragment with no data in it */
2319 if (tvb_length(tvb) == 0)
2320 return NULL;
2322 /* create new fragment */
2323 fragment = (sctp_fragment *)g_malloc (sizeof (sctp_fragment));
2324 fragment->frame_num = pinfo->fd->num;
2325 fragment->tsn = tsn;
2326 fragment->len = tvb_length(tvb);
2327 fragment->next = NULL;
2328 fragment->data = (unsigned char *)g_malloc (fragment->len);
2329 tvb_memcpy(tvb, fragment->data, 0, fragment->len);
2331 /* add new fragment to linked list. sort ascending by tsn */
2332 if (!msg->fragments)
2333 msg->fragments = fragment;
2334 else {
2335 if (msg->fragments->tsn > fragment->tsn) {
2336 fragment->next = msg->fragments;
2337 msg->fragments = fragment;
2338 } else {
2339 last_fragment = msg->fragments;
2340 while (last_fragment->next &&
2341 last_fragment->next->tsn < fragment->tsn)
2342 last_fragment = last_fragment->next;
2344 fragment->next = last_fragment->next;
2345 last_fragment->next = fragment;
2350 /* save begin or end if necessary */
2351 if (b_bit && !e_bit) {
2352 beginend = (sctp_frag_be *)g_malloc (sizeof (sctp_frag_be));
2353 beginend->fragment = fragment;
2354 beginend->next = NULL;
2356 /* add begin to linked list. sort descending by tsn */
2357 if (!msg->begins)
2358 msg->begins = beginend;
2359 else {
2360 if (msg->begins->fragment->tsn < beginend->fragment->tsn) {
2361 beginend->next = msg->begins;
2362 msg->begins = beginend;
2363 } else {
2364 last_beginend = msg->begins;
2365 while (last_beginend->next &&
2366 last_beginend->next->fragment->tsn > beginend->fragment->tsn)
2367 last_beginend = last_beginend->next;
2369 beginend->next = last_beginend->next;
2370 last_beginend->next = beginend;
2376 if (!b_bit && e_bit) {
2377 beginend = (sctp_frag_be *)g_malloc (sizeof (sctp_frag_be));
2378 beginend->fragment = fragment;
2379 beginend->next = NULL;
2381 /* add end to linked list. sort ascending by tsn */
2382 if (!msg->ends)
2383 msg->ends = beginend;
2384 else {
2385 if (msg->ends->fragment->tsn > beginend->fragment->tsn) {
2386 beginend->next = msg->ends;
2387 msg->ends = beginend;
2388 } else {
2389 last_beginend = msg->ends;
2390 while (last_beginend->next &&
2391 last_beginend->next->fragment->tsn < beginend->fragment->tsn)
2392 last_beginend = last_beginend->next;
2394 beginend->next = last_beginend->next;
2395 last_beginend->next = beginend;
2401 return fragment;
2404 static tvbuff_t*
2405 fragment_reassembly(tvbuff_t *tvb, sctp_fragment *fragment,
2406 packet_info *pinfo, proto_tree *tree, guint16 stream_id,
2407 guint16 stream_seq_num)
2409 sctp_frag_msg *msg;
2410 sctp_complete_msg *message, *last_message;
2411 sctp_fragment *frag_i, *last_frag, *first_frag;
2412 sctp_frag_be *begin, *end, *beginend;
2413 guint32 len, offset = 0;
2414 tvbuff_t *new_tvb = NULL;
2415 proto_item *item;
2416 proto_tree *ptree;
2418 msg = find_message(stream_id, stream_seq_num);
2420 if (!msg) {
2421 /* no message, we can't do anything */
2422 return NULL;
2425 /* check if fragment is part of an already reassembled message */
2426 for (message = msg->messages;
2427 message &&
2428 !(message->begin <= fragment->tsn && message->end >= fragment->tsn) &&
2429 !(message->begin > message->end &&
2430 (message->begin <= fragment->tsn || message->end >= fragment->tsn));
2431 message = message->next);
2433 if (message) {
2434 /* we found the reassembled message this fragment belongs to */
2435 if (fragment == message->reassembled_in) {
2437 /* this is the last fragment, create data source */
2438 new_tvb = tvb_new_child_real_data(tvb, message->data, message->len, message->len);
2439 add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message");
2441 /* display reassembly info */
2442 item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, ENC_NA);
2443 ptree = proto_item_add_subtree(item, ett_sctp_fragments);
2444 proto_item_append_text(item, " (%u bytes, %u fragments): ",
2445 message->len, message->end - message->begin + 1);
2447 if (message->begin > message->end) {
2448 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
2449 frag_i;
2450 frag_i = frag_i->next) {
2452 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
2453 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
2454 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
2455 offset += frag_i->len;
2457 mark_frame_as_depended_upon(pinfo, frag_i->frame_num);
2460 for (frag_i = msg->fragments;
2461 frag_i && frag_i->tsn <= message->end;
2462 frag_i = frag_i->next) {
2464 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
2465 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
2466 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
2467 offset += frag_i->len;
2469 mark_frame_as_depended_upon(pinfo, frag_i->frame_num);
2471 } else {
2472 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
2473 frag_i && frag_i->tsn <= message->end;
2474 frag_i = frag_i->next) {
2476 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
2477 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
2478 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
2479 offset += frag_i->len;
2481 mark_frame_as_depended_upon(pinfo, frag_i->frame_num);
2485 return new_tvb;
2488 /* this is not the last fragment,
2489 * so let the user know the frame where the reassembly is
2491 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
2493 proto_tree_add_uint(tree, hf_sctp_reassembled_in, tvb, 0, 0, message->reassembled_in->frame_num);
2494 return NULL;
2497 /* this fragment has not been reassembled, yet
2498 * check now if we can reassemble it
2499 * at first look for the first and last tsn of the msg
2501 for (begin = msg->begins;
2502 begin && begin->fragment->tsn > fragment->tsn;
2503 begin = begin->next);
2505 /* in case begin still is null, set it to first (highest) begin
2506 * maybe the message tsn restart at 0 in between
2508 if (!begin)
2509 begin = msg->begins;
2511 for (end = msg->ends;
2512 end && end->fragment->tsn < fragment->tsn;
2513 end = end->next);
2515 /* in case end still is null, set it to first (lowest) end
2516 * maybe the message tsn restart at 0 in between
2518 if (!end)
2519 end = msg->ends;
2521 if (!begin || !end || !msg->fragments ||
2522 (begin->fragment->tsn > end->fragment->tsn && msg->fragments->tsn)) {
2523 /* begin and end have not been collected, yet
2524 * or there might be a tsn restart but the first fragment hasn't a tsn of 0
2525 * just mark as fragment
2528 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
2530 return NULL;
2533 /* we found possible begin and end
2534 * look for the first fragment and then try to get to the end
2536 first_frag = begin->fragment;
2538 /* while looking if all fragments are there
2539 * we can calculate the overall length that
2540 * we need in case of success
2542 len = first_frag->len;
2544 /* check if begin is past end
2545 * this can happen if there has been a tsn restart
2546 * or we just got the wrong begin and end
2547 * so give it a try
2549 if (begin->fragment->tsn > end->fragment->tsn) {
2550 for (last_frag = first_frag, frag_i = first_frag->next;
2551 frag_i && frag_i->tsn == (last_frag->tsn + 1);
2552 last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
2554 /* check if we reached the last possible tsn
2555 * if yes, restart and continue
2557 if ((last_frag->tsn + 1)) {
2558 /* there are just fragments missing */
2559 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
2561 return NULL;
2564 /* we got all fragments until the last possible tsn
2565 * and the first is 0 if we got here
2568 len += msg->fragments->len;
2569 for (last_frag = msg->fragments, frag_i = last_frag->next;
2570 frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1);
2571 last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
2573 } else {
2574 for (last_frag = first_frag, frag_i = first_frag->next;
2575 frag_i && frag_i->tsn < end->fragment->tsn && frag_i->tsn == (last_frag->tsn + 1);
2576 last_frag = frag_i, frag_i = frag_i->next) len += frag_i->len;
2579 if (!frag_i || frag_i != end->fragment || frag_i->tsn != (last_frag->tsn + 1)) {
2580 /* we need more fragments. just mark as fragment */
2581 col_append_str(pinfo->cinfo, COL_INFO, "(Message Fragment) ");
2583 return NULL;
2586 /* ok, this message is complete, we can reassemble it
2587 * but at first don't forget to add the length of the last fragment
2589 len += frag_i->len;
2591 message = wmem_new(wmem_file_scope(), sctp_complete_msg);
2592 message->begin = begin->fragment->tsn;
2593 message->end = end->fragment->tsn;
2594 message->reassembled_in = fragment;
2595 message->len = len;
2596 message->data = (unsigned char *)wmem_alloc(wmem_file_scope(), len);
2597 message->next = NULL;
2599 /* now copy all fragments */
2600 if (begin->fragment->tsn > end->fragment->tsn) {
2601 /* a tsn restart has occurred */
2602 for (frag_i = first_frag;
2603 frag_i;
2604 frag_i = frag_i->next) {
2606 if (frag_i->len && frag_i->data)
2607 memcpy(message->data + offset, frag_i->data, frag_i->len);
2608 offset += frag_i->len;
2610 /* release fragment data */
2611 g_free(frag_i->data);
2612 frag_i->data = NULL;
2615 for (frag_i = msg->fragments;
2616 frag_i && frag_i->tsn <= end->fragment->tsn;
2617 frag_i = frag_i->next) {
2619 if (frag_i->len && frag_i->data)
2620 memcpy(message->data + offset, frag_i->data, frag_i->len);
2621 offset += frag_i->len;
2623 /* release fragment data */
2624 g_free(frag_i->data);
2625 frag_i->data = NULL;
2628 } else {
2629 for (frag_i = first_frag;
2630 frag_i && frag_i->tsn <= end->fragment->tsn;
2631 frag_i = frag_i->next) {
2633 if (frag_i->len && frag_i->data)
2634 memcpy(message->data + offset, frag_i->data, frag_i->len);
2635 offset += frag_i->len;
2637 /* release fragment data */
2638 g_free(frag_i->data);
2639 frag_i->data = NULL;
2643 /* save message */
2644 if (!msg->messages) {
2645 msg->messages = message;
2646 } else {
2647 for (last_message = msg->messages;
2648 last_message->next;
2649 last_message = last_message->next);
2650 last_message->next = message;
2653 /* remove begin and end from list */
2654 if (msg->begins == begin) {
2655 msg->begins = begin->next;
2656 } else {
2657 for (beginend = msg->begins;
2658 beginend && beginend->next != begin;
2659 beginend = beginend->next);
2660 if (beginend && beginend->next == begin)
2661 beginend->next = begin->next;
2663 g_free(begin);
2665 if (msg->ends == end) {
2666 msg->ends = end->next;
2667 } else {
2668 for (beginend = msg->ends;
2669 beginend && beginend->next != end;
2670 beginend = beginend->next);
2671 if (beginend && beginend->next == end)
2672 beginend->next = end->next;
2674 g_free(end);
2676 /* create data source */
2677 new_tvb = tvb_new_child_real_data(tvb, message->data, len, len);
2678 add_new_data_source(pinfo, new_tvb, "Reassembled SCTP Message");
2680 /* display reassembly info */
2681 item = proto_tree_add_item(tree, hf_sctp_fragments, tvb, 0, -1, ENC_NA);
2682 ptree = proto_item_add_subtree(item, ett_sctp_fragments);
2683 proto_item_append_text(item, " (%u bytes, %u fragments): ",
2684 message->len, message->end - message->begin + 1);
2686 if (message->begin > message->end) {
2687 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
2688 frag_i;
2689 frag_i = frag_i->next) {
2691 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
2692 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
2693 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
2694 offset += frag_i->len;
2697 for (frag_i = msg->fragments;
2698 frag_i && frag_i->tsn <= message->end;
2699 frag_i = frag_i->next) {
2701 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
2702 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
2703 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
2704 offset += frag_i->len;
2706 } else {
2707 for (frag_i = find_fragment(message->begin, stream_id, stream_seq_num);
2708 frag_i && frag_i->tsn <= message->end;
2709 frag_i = frag_i->next) {
2711 proto_tree_add_uint_format(ptree, hf_sctp_fragment, new_tvb, offset, frag_i->len,
2712 frag_i->frame_num, "Frame: %u, payload: %u-%u (%u bytes)",
2713 frag_i->frame_num, offset, offset + frag_i->len - 1, frag_i->len);
2714 offset += frag_i->len;
2718 /* it's not fragmented anymore */
2719 pinfo->fragmented = FALSE;
2721 return new_tvb;
2725 static gboolean
2726 dissect_fragmented_payload(tvbuff_t *payload_tvb, packet_info *pinfo, proto_tree *tree,
2727 proto_tree *chunk_tree, guint32 tsn, guint32 ppi, guint16 stream_id,
2728 guint16 stream_seq_num, guint8 b_bit, guint8 e_bit)
2730 sctp_fragment *fragment;
2731 tvbuff_t *new_tvb = NULL;
2734 * If this is a short frame, then we can't, and don't, do
2735 * reassembly on it. We just give up.
2737 if (tvb_reported_length(payload_tvb) > tvb_length(payload_tvb))
2738 return TRUE;
2740 /* add fragement to list of known fragments. returns NULL if segment is a duplicate */
2741 fragment = add_fragment(payload_tvb, pinfo, chunk_tree, tsn, stream_id, stream_seq_num, b_bit, e_bit);
2743 if (fragment)
2744 new_tvb = fragment_reassembly(payload_tvb, fragment, pinfo, chunk_tree, stream_id, stream_seq_num);
2746 /* pass reassembled data to next dissector, if possible */
2747 if (new_tvb)
2748 return dissect_payload(new_tvb, pinfo, tree, ppi);
2750 /* no reassembly done, do nothing */
2751 return TRUE;
2754 static const true_false_string sctp_data_chunk_e_bit_value = {
2755 "Last segment",
2756 "Not the last segment"
2759 static const true_false_string sctp_data_chunk_b_bit_value = {
2760 "First segment",
2761 "Subsequent segment"
2764 static const true_false_string sctp_data_chunk_u_bit_value = {
2765 "Unordered delivery",
2766 "Ordered delivery"
2769 static const true_false_string sctp_data_chunk_i_bit_value = {
2770 "Send SACK immediately",
2771 "Possibly delay SACK"
2774 static gboolean
2775 dissect_data_chunk(tvbuff_t *chunk_tvb,
2776 guint16 chunk_length,
2777 packet_info *pinfo,
2778 proto_tree *tree,
2779 proto_tree *chunk_tree,
2780 proto_item *chunk_item,
2781 proto_item *flags_item,
2782 sctp_half_assoc_t *ha)
2784 guint number_of_ppid;
2785 guint32 payload_proto_id;
2786 tvbuff_t *payload_tvb;
2787 proto_tree *flags_tree;
2788 guint8 e_bit, b_bit, u_bit;
2789 guint16 stream_id, stream_seq_num = 0;
2790 guint32 tsn;
2791 proto_item *tsn_item = NULL;
2792 gboolean call_subdissector = FALSE;
2793 gboolean is_retransmission;
2795 if (chunk_length <= DATA_CHUNK_HEADER_LENGTH) {
2796 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, DATA_CHUNK_HEADER_LENGTH);
2797 return TRUE;
2800 payload_proto_id = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_PAYLOAD_PROTOCOL_ID_OFFSET);
2802 /* insert the PPID in the pinfo structure if it is not already there and there is still room */
2803 for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++)
2804 if ((pinfo->ppids[number_of_ppid] == LAST_PPID) || (pinfo->ppids[number_of_ppid] == payload_proto_id))
2805 break;
2806 if ((number_of_ppid < MAX_NUMBER_OF_PPIDS) && (pinfo->ppids[number_of_ppid] == LAST_PPID))
2807 pinfo->ppids[number_of_ppid] = payload_proto_id;
2809 e_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_E_BIT;
2810 b_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_B_BIT;
2811 u_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_U_BIT;
2812 stream_id = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
2813 stream_seq_num = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
2814 tsn = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
2816 if (chunk_tree) {
2817 proto_item_set_len(chunk_item, DATA_CHUNK_HEADER_LENGTH);
2818 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_data_chunk_flags);
2819 proto_tree_add_item(flags_tree, hf_data_chunk_e_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
2820 proto_tree_add_item(flags_tree, hf_data_chunk_b_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
2821 proto_tree_add_item(flags_tree, hf_data_chunk_u_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
2822 proto_tree_add_item(flags_tree, hf_data_chunk_i_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
2823 tsn_item = proto_tree_add_item(chunk_tree, hf_data_chunk_tsn, chunk_tvb, DATA_CHUNK_TSN_OFFSET, DATA_CHUNK_TSN_LENGTH, ENC_BIG_ENDIAN);
2824 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);
2825 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);
2826 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);
2828 proto_item_append_text(chunk_item, "(%s, ", (u_bit) ? "unordered" : "ordered");
2829 if (b_bit) {
2830 if (e_bit)
2831 proto_item_append_text(chunk_item, "complete");
2832 else
2833 proto_item_append_text(chunk_item, "first");
2834 } else {
2835 if (e_bit)
2836 proto_item_append_text(chunk_item, "last");
2837 else
2838 proto_item_append_text(chunk_item, "middle");
2841 proto_item_append_text(chunk_item, " segment, TSN: %u, SID: %u, SSN: %u, PPID: %u, payload length: %u byte%s)",
2842 tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET),
2843 tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET),
2844 tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET),
2845 payload_proto_id,
2846 chunk_length - DATA_CHUNK_HEADER_LENGTH, plurality(chunk_length - DATA_CHUNK_HEADER_LENGTH, "", "s"));
2849 is_retransmission = sctp_tsn(pinfo, chunk_tvb, tsn_item, ha, tsn);
2851 payload_tvb = tvb_new_subset(chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET,
2852 MIN(chunk_length - DATA_CHUNK_HEADER_LENGTH, tvb_length_remaining(chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET)),
2853 MIN(chunk_length - DATA_CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, DATA_CHUNK_PAYLOAD_OFFSET)));
2855 /* Is this a fragment? */
2856 if (b_bit && e_bit) {
2857 /* No - just call the subdissector. */
2858 if (!is_retransmission)
2859 call_subdissector = TRUE;
2860 } else {
2861 /* Yes. */
2862 pinfo->fragmented = TRUE;
2864 /* if reassembly is off just mark as fragment for next dissector and proceed */
2865 if (!use_reassembly)
2867 /* Don't pass on non-first fragments since the next dissector will
2868 * almost certainly not understand the data.
2870 if (b_bit) {
2871 if (!is_retransmission)
2872 call_subdissector = TRUE;
2873 } else
2874 return FALSE;
2879 if (call_subdissector) {
2880 /* This isn't a fragment or reassembly is off and it's the first fragment */
2882 void *pd_save;
2883 volatile gboolean retval = FALSE;
2885 pd_save = pinfo->private_data;
2886 TRY {
2887 retval = dissect_payload(payload_tvb, pinfo, tree, payload_proto_id);
2889 CATCH_NONFATAL_ERRORS {
2891 * Somebody threw an exception that means that there was a problem
2892 * dissecting the payload; that means that a dissector was found,
2893 * so we don't need to dissect the payload as data or update the
2894 * protocol or info columns.
2896 * Just show the exception and then continue dissecting chunks.
2898 * Restore the private_data structure in case one of the
2899 * called dissectors modified it (and, due to the exception,
2900 * was unable to restore it).
2902 pinfo->private_data = pd_save;
2903 show_exception(payload_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2905 ENDTRY;
2907 return retval;
2909 } else if (is_retransmission) {
2910 col_append_str(pinfo->cinfo, COL_INFO, "(retransmission) ");
2911 return FALSE;
2912 } else {
2914 /* The logic above should ensure this... */
2915 DISSECTOR_ASSERT(use_reassembly);
2917 /* if unordered set stream_seq_num to 0 for easier handling */
2918 if (u_bit)
2919 stream_seq_num = 0;
2921 /* start reassembly */
2922 return dissect_fragmented_payload(payload_tvb, pinfo, tree, chunk_tree, tsn, payload_proto_id, stream_id, stream_seq_num, b_bit, e_bit);
2927 #define INIT_CHUNK_INITIATE_TAG_LENGTH 4
2928 #define INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4
2929 #define INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH 2
2930 #define INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH 2
2931 #define INIT_CHUNK_INITIAL_TSN_LENGTH 4
2932 #define INIT_CHUNK_FIXED_PARAMTERS_LENGTH (CHUNK_HEADER_LENGTH + \
2933 INIT_CHUNK_INITIATE_TAG_LENGTH + \
2934 INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH + \
2935 INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH + \
2936 INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH + \
2937 INIT_CHUNK_INITIAL_TSN_LENGTH)
2939 #define INIT_CHUNK_INITIATE_TAG_OFFSET CHUNK_VALUE_OFFSET
2940 #define INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (INIT_CHUNK_INITIATE_TAG_OFFSET + \
2941 INIT_CHUNK_INITIATE_TAG_LENGTH )
2942 #define INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET (INIT_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \
2943 INIT_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH )
2944 #define INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET (INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET + \
2945 INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_LENGTH )
2946 #define INIT_CHUNK_INITIAL_TSN_OFFSET (INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET + \
2947 INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_LENGTH )
2948 #define INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET (INIT_CHUNK_INITIAL_TSN_OFFSET + \
2949 INIT_CHUNK_INITIAL_TSN_LENGTH )
2951 static void
2952 dissect_init_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
2954 tvbuff_t *parameters_tvb;
2955 proto_item *hidden_item;
2957 if (chunk_length < INIT_CHUNK_FIXED_PARAMTERS_LENGTH) {
2958 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", chunk_length, INIT_CHUNK_FIXED_PARAMTERS_LENGTH);
2959 return;
2962 if (chunk_tree) {
2963 /* handle fixed parameters */
2964 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);
2965 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);
2966 PROTO_ITEM_SET_HIDDEN(hidden_item);
2967 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);
2968 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);
2969 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);
2970 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);
2972 proto_item_append_text(chunk_item, " (Outbound streams: %u, inbound streams: %u)",
2973 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET),
2974 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET));
2977 /* handle variable parameters */
2978 chunk_length -= INIT_CHUNK_FIXED_PARAMTERS_LENGTH;
2979 parameters_tvb = tvb_new_subset(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET,
2980 MIN(chunk_length, tvb_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)),
2981 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)));
2982 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, TRUE);
2985 static void
2986 dissect_init_ack_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
2988 tvbuff_t *parameters_tvb;
2989 proto_item *hidden_item;
2991 if (chunk_length < INIT_CHUNK_FIXED_PARAMTERS_LENGTH) {
2992 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
2993 chunk_length,
2994 INIT_CHUNK_FIXED_PARAMTERS_LENGTH);
2995 return;
2997 if (chunk_tree) {
2998 /* handle fixed parameters */
2999 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);
3000 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);
3001 PROTO_ITEM_SET_HIDDEN(hidden_item);
3002 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);
3003 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);
3004 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);
3005 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);
3007 proto_item_append_text(chunk_item, " (Outbound streams: %u, inbound streams: %u)",
3008 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_OUTBOUND_STREAMS_OFFSET),
3009 tvb_get_ntohs(chunk_tvb, INIT_CHUNK_NUMBER_OF_INBOUND_STREAMS_OFFSET));
3011 /* handle variable paramters */
3012 chunk_length -= INIT_CHUNK_FIXED_PARAMTERS_LENGTH;
3013 parameters_tvb = tvb_new_subset(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET,
3014 MIN(chunk_length, tvb_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)),
3015 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, INIT_CHUNK_VARIABLE_LENGTH_PARAMETER_OFFSET)));
3016 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, TRUE);
3019 #define SCTP_SACK_CHUNK_NS_BIT 0x01
3020 #define SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4
3021 #define SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4
3022 #define SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH 2
3023 #define SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH 2
3024 #define SACK_CHUNK_GAP_BLOCK_LENGTH 4
3025 #define SACK_CHUNK_GAP_BLOCK_START_LENGTH 2
3026 #define SACK_CHUNK_GAP_BLOCK_END_LENGTH 2
3027 #define SACK_CHUNK_DUP_TSN_LENGTH 4
3029 #define SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET (CHUNK_VALUE_OFFSET + 0)
3030 #define SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET + \
3031 SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH)
3032 #define SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET (SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \
3033 SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH)
3034 #define SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET (SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET + \
3035 SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH)
3036 #define SACK_CHUNK_GAP_BLOCK_OFFSET (SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET + \
3037 SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH)
3040 static void
3041 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)
3043 guint16 number_of_gap_blocks, number_of_dup_tsns;
3044 guint16 gap_block_number, dup_tsn_number, start, end;
3045 gint gap_block_offset, dup_tsn_offset;
3046 guint32 cum_tsn_ack;
3047 proto_item *block_item;
3048 proto_tree *block_tree;
3049 proto_tree *flags_tree;
3050 proto_item *ctsa_item;
3051 proto_item *a_rwnd_item;
3052 proto_tree *acks_tree;
3053 guint32 tsns_gap_acked = 0;
3054 guint32 a_rwnd;
3055 guint16 last_end;
3057 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_sack_chunk_flags);
3058 proto_tree_add_item(flags_tree, hf_sack_chunk_ns, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3059 ctsa_item = proto_tree_add_item(chunk_tree, hf_sack_chunk_cumulative_tsn_ack, chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET, SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH, ENC_BIG_ENDIAN);
3060 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);
3061 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);
3062 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);
3064 a_rwnd = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET);
3065 if (a_rwnd == 0)
3066 expert_add_info(pinfo, a_rwnd_item, &ei_sctp_sack_chunk_adv_rec_window_credit);
3069 /* handle the gap acknowledgement blocks */
3070 number_of_gap_blocks = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET);
3071 gap_block_offset = SACK_CHUNK_GAP_BLOCK_OFFSET;
3072 cum_tsn_ack = tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
3074 acks_tree = proto_item_add_subtree(ctsa_item,ett_sctp_ack);
3075 sctp_ack_block(pinfo, ha, chunk_tvb, acks_tree, NULL, cum_tsn_ack);
3077 last_end = 0;
3078 for(gap_block_number = 0; gap_block_number < number_of_gap_blocks; gap_block_number++) {
3079 proto_item *pi;
3080 proto_tree *pt;
3081 guint32 tsn_start;
3083 start = tvb_get_ntohs(chunk_tvb, gap_block_offset);
3084 end = tvb_get_ntohs(chunk_tvb, gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH);
3085 tsn_start = cum_tsn_ack + start;
3087 block_item = proto_tree_add_text(chunk_tree, chunk_tvb, gap_block_offset, SACK_CHUNK_GAP_BLOCK_LENGTH, "Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end);
3088 block_tree = proto_item_add_subtree(block_item, ett_sctp_sack_chunk_gap_block);
3090 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);
3091 pt = proto_item_add_subtree(pi, ett_sctp_sack_chunk_gap_block_start);
3092 pi = proto_tree_add_uint(pt, hf_sack_chunk_gap_block_start_tsn,
3093 chunk_tvb, gap_block_offset,SACK_CHUNK_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start);
3094 PROTO_ITEM_SET_GENERATED(pi);
3096 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);
3097 pt = proto_item_add_subtree(pi, ett_sctp_sack_chunk_gap_block_end);
3098 pi = proto_tree_add_uint(pt, hf_sack_chunk_gap_block_end_tsn, chunk_tvb,
3099 gap_block_offset + SACK_CHUNK_GAP_BLOCK_START_LENGTH, SACK_CHUNK_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end);
3100 PROTO_ITEM_SET_GENERATED(pi);
3102 sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end);
3103 gap_block_offset += SACK_CHUNK_GAP_BLOCK_LENGTH;
3105 tsns_gap_acked += (end+1 - start);
3107 /* Check validity */
3108 if (start > end) {
3109 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed);
3111 if (last_end > start) {
3112 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order);
3114 last_end = end;
3117 if (tsns_gap_acked) {
3118 proto_item *pi;
3120 pi = proto_tree_add_uint(chunk_tree, hf_sack_chunk_number_tsns_gap_acked, chunk_tvb, 0, 0, tsns_gap_acked);
3121 PROTO_ITEM_SET_GENERATED(pi);
3123 /* If there are a huge number of GAP ACKs, warn the user. 100 is a random
3124 * number: it could be tuned.
3126 if (tsns_gap_acked > 100)
3127 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_number_tsns_gap_acked_100);
3132 /* handle the duplicate TSNs */
3133 number_of_dup_tsns = tvb_get_ntohs(chunk_tvb, SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET);
3134 dup_tsn_offset = SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * SACK_CHUNK_GAP_BLOCK_LENGTH;
3135 for(dup_tsn_number = 0; dup_tsn_number < number_of_dup_tsns; dup_tsn_number++) {
3136 proto_tree_add_item(chunk_tree, hf_sack_chunk_duplicate_tsn, chunk_tvb, dup_tsn_offset, SACK_CHUNK_DUP_TSN_LENGTH, ENC_BIG_ENDIAN);
3137 dup_tsn_offset += SACK_CHUNK_DUP_TSN_LENGTH;
3140 proto_item_append_text(chunk_item, " (Cumulative TSN: %u, a_rwnd: %u, gaps: %u, duplicate TSNs: %u)",
3141 tvb_get_ntohl(chunk_tvb, SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET),
3142 a_rwnd,
3143 number_of_gap_blocks, number_of_dup_tsns);
3146 /* NE: Dissect nr-sack chunk */
3147 #define SCTP_NR_SACK_CHUNK_NS_BIT 0x01
3148 #define NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4
3149 #define NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH 4
3150 #define NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH 2
3151 #define NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH 2
3152 #define NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH 2
3153 #define NR_SACK_CHUNK_RESERVED_LENGTH 2
3154 #define NR_SACK_CHUNK_GAP_BLOCK_LENGTH 4
3155 #define NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH 2
3156 #define NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH 2
3157 #define NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH 4
3158 #define NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH 2
3159 #define NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH 2
3160 #define NR_SACK_CHUNK_DUP_TSN_LENGTH 4
3162 #define NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET (CHUNK_VALUE_OFFSET + 0)
3163 #define NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET (NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET + \
3164 NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_LENGTH)
3165 #define NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET (NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET + \
3166 NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_LENGTH)
3167 #define NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET (NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET + \
3168 NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_LENGTH)
3169 #define NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET (NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET + \
3170 NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_LENGTH)
3171 #define NR_SACK_CHUNK_RESERVED_OFFSET (NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET + \
3172 NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_LENGTH)
3173 #define NR_SACK_CHUNK_GAP_BLOCK_OFFSET (NR_SACK_CHUNK_RESERVED_OFFSET + \
3174 NR_SACK_CHUNK_RESERVED_LENGTH)
3176 static void
3177 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)
3179 guint16 number_of_gap_blocks, number_of_dup_tsns;
3180 guint16 number_of_nr_gap_blocks;
3181 guint16 gap_block_number, nr_gap_block_number, dup_tsn_number, start, end;
3182 gint gap_block_offset, nr_gap_block_offset, dup_tsn_offset;
3183 guint32 cum_tsn_ack;
3184 proto_item *block_item;
3185 proto_tree *block_tree;
3186 proto_tree *flags_tree;
3187 proto_item *ctsa_item;
3188 proto_tree *acks_tree;
3189 guint32 tsns_gap_acked = 0;
3190 guint32 tsns_nr_gap_acked = 0;
3191 guint16 last_end;
3193 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_nr_sack_chunk_flags);
3194 proto_tree_add_item(flags_tree, hf_nr_sack_chunk_ns, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3196 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);
3197 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);
3199 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);
3201 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);
3202 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);
3203 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);
3206 number_of_gap_blocks = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_GAP_BLOCKS_OFFSET);
3207 gap_block_offset = NR_SACK_CHUNK_GAP_BLOCK_OFFSET;
3208 cum_tsn_ack = tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET);
3210 acks_tree = proto_item_add_subtree(ctsa_item,ett_sctp_ack);
3211 sctp_ack_block(pinfo, ha, chunk_tvb, acks_tree, NULL, cum_tsn_ack);
3213 last_end = 0;
3214 for(gap_block_number = 0; gap_block_number < number_of_gap_blocks; gap_block_number++) {
3215 proto_item *pi;
3216 proto_tree *pt;
3217 guint32 tsn_start;
3219 start = tvb_get_ntohs(chunk_tvb, gap_block_offset);
3220 end = tvb_get_ntohs(chunk_tvb, gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH);
3221 tsn_start = cum_tsn_ack + start;
3223 block_item = proto_tree_add_text(chunk_tree, chunk_tvb, gap_block_offset, NR_SACK_CHUNK_GAP_BLOCK_LENGTH, "Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end);
3224 block_tree = proto_item_add_subtree(block_item, ett_sctp_nr_sack_chunk_gap_block);
3226 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);
3227 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_gap_block_start);
3228 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_gap_block_start_tsn,
3229 chunk_tvb, gap_block_offset,NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start);
3230 PROTO_ITEM_SET_GENERATED(pi);
3232 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);
3233 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_gap_block_end);
3234 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_gap_block_end_tsn, chunk_tvb,
3235 gap_block_offset + NR_SACK_CHUNK_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end);
3236 PROTO_ITEM_SET_GENERATED(pi);
3238 sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end);
3239 gap_block_offset += NR_SACK_CHUNK_GAP_BLOCK_LENGTH;
3240 tsns_gap_acked += (end - start) + 1;
3242 /* Check validity */
3243 if (start > end) {
3244 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed);
3246 if (last_end > start) {
3247 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order);
3249 last_end = end;
3252 if (tsns_gap_acked) {
3253 proto_item *pi;
3255 pi = proto_tree_add_uint(chunk_tree, hf_nr_sack_chunk_number_tsns_gap_acked, chunk_tvb, 0, 0, tsns_gap_acked);
3256 PROTO_ITEM_SET_GENERATED(pi);
3258 /* If there are a huge number of GAP ACKs, warn the user. 100 is a random
3259 * number: it could be tuned.
3261 if (tsns_gap_acked > 100)
3262 expert_add_info(pinfo, pi, &ei_sctp_nr_sack_chunk_number_tsns_gap_acked_100);
3266 /* NE: handle the nr-sack chunk's nr-gap blocks */
3267 number_of_nr_gap_blocks = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_NR_GAP_BLOCKS_OFFSET);
3268 nr_gap_block_offset = gap_block_offset;
3270 last_end = 0;
3271 for(nr_gap_block_number = 0; nr_gap_block_number < number_of_nr_gap_blocks; nr_gap_block_number++) {
3272 proto_item *pi;
3273 proto_tree *pt;
3274 /*guint32 tsn_start;*/
3276 start = tvb_get_ntohs(chunk_tvb, nr_gap_block_offset);
3277 end = tvb_get_ntohs(chunk_tvb, nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH);
3278 /*tsn_start = cum_tsn_ack + start;*/
3280 block_item = proto_tree_add_text(chunk_tree, chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH, "NR-Gap Acknowledgement for TSN %u to %u", cum_tsn_ack + start, cum_tsn_ack + end);
3281 block_tree = proto_item_add_subtree(block_item, ett_sctp_nr_sack_chunk_nr_gap_block);
3283 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);
3284 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_nr_gap_block_start);
3285 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_nr_gap_block_start_tsn,
3286 chunk_tvb, nr_gap_block_offset, NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, cum_tsn_ack + start);
3287 PROTO_ITEM_SET_GENERATED(pi);
3289 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);
3290 pt = proto_item_add_subtree(pi, ett_sctp_nr_sack_chunk_nr_gap_block_end);
3291 pi = proto_tree_add_uint(pt, hf_nr_sack_chunk_nr_gap_block_end_tsn, chunk_tvb,
3292 nr_gap_block_offset + NR_SACK_CHUNK_NR_GAP_BLOCK_START_LENGTH, NR_SACK_CHUNK_NR_GAP_BLOCK_END_LENGTH, cum_tsn_ack + end);
3293 PROTO_ITEM_SET_GENERATED(pi);
3295 /* sctp_ack_block(pinfo, ha, chunk_tvb, block_tree, &tsn_start, cum_tsn_ack + end); */
3296 nr_gap_block_offset += NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH;
3297 tsns_nr_gap_acked += (end - start) + 1;
3299 /* Check validity */
3300 if (start > end) {
3301 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_malformed);
3303 if (last_end > start) {
3304 expert_add_info(pinfo, pi, &ei_sctp_sack_chunk_gap_block_out_of_order);
3306 last_end = end;
3309 if (tsns_nr_gap_acked) {
3310 proto_item *pi;
3312 pi = proto_tree_add_uint(chunk_tree, hf_nr_sack_chunk_number_tsns_nr_gap_acked, chunk_tvb, 0, 0, tsns_nr_gap_acked);
3313 PROTO_ITEM_SET_GENERATED(pi);
3315 /* If there are a huge number of GAP ACKs, warn the user. 100 is a random
3316 * number: it could be tuned.
3318 if (tsns_nr_gap_acked > 100)
3319 expert_add_info(pinfo, pi, &ei_sctp_nr_sack_chunk_number_tsns_nr_gap_acked_100);
3322 /* handle the duplicate TSNs */
3323 number_of_dup_tsns = tvb_get_ntohs(chunk_tvb, NR_SACK_CHUNK_NUMBER_OF_DUP_TSNS_OFFSET);
3324 dup_tsn_offset = NR_SACK_CHUNK_GAP_BLOCK_OFFSET + number_of_gap_blocks * NR_SACK_CHUNK_GAP_BLOCK_LENGTH
3325 + number_of_nr_gap_blocks * NR_SACK_CHUNK_NR_GAP_BLOCK_LENGTH;
3328 for(dup_tsn_number = 0; dup_tsn_number < number_of_dup_tsns; dup_tsn_number++) {
3329 proto_tree_add_item(chunk_tree, hf_sack_chunk_duplicate_tsn, chunk_tvb, dup_tsn_offset, NR_SACK_CHUNK_DUP_TSN_LENGTH, ENC_BIG_ENDIAN);
3330 dup_tsn_offset += NR_SACK_CHUNK_DUP_TSN_LENGTH;
3333 proto_item_append_text(chunk_item, " (Cumulative TSN: %u, a_rwnd: %u, gaps: %u, nr-gaps: %u, duplicate TSNs: %u)",
3334 tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_CUMULATIVE_TSN_ACK_OFFSET),
3335 tvb_get_ntohl(chunk_tvb, NR_SACK_CHUNK_ADV_REC_WINDOW_CREDIT_OFFSET),
3336 number_of_gap_blocks, number_of_nr_gap_blocks, number_of_dup_tsns);
3339 #define HEARTBEAT_CHUNK_INFO_OFFSET CHUNK_VALUE_OFFSET
3341 static void
3342 dissect_heartbeat_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
3344 tvbuff_t *parameter_tvb;
3346 if (chunk_tree) {
3347 proto_item_append_text(chunk_item, " (Information: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
3348 parameter_tvb = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET,
3349 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET)),
3350 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET)));
3351 /* FIXME: Parameters or parameter? */
3352 dissect_parameter(parameter_tvb, pinfo, chunk_tree, NULL, FALSE, TRUE);
3356 static void
3357 dissect_heartbeat_ack_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
3359 tvbuff_t *parameter_tvb;
3361 if (chunk_tree) {
3362 proto_item_append_text(chunk_item, " (Information: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
3363 parameter_tvb = tvb_new_subset(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET,
3364 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET)),
3365 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, HEARTBEAT_CHUNK_INFO_OFFSET)));
3366 /* FIXME: Parameters or parameter? */
3367 dissect_parameter(parameter_tvb, pinfo, chunk_tree, NULL, FALSE, TRUE);
3371 #define ABORT_CHUNK_FIRST_ERROR_CAUSE_OFFSET 4
3372 #define SCTP_ABORT_CHUNK_T_BIT 0x01
3374 static void
3375 dissect_abort_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *flags_item)
3377 tvbuff_t *causes_tvb;
3378 proto_tree *flags_tree;
3380 sctp_info.vtag_reflected =
3381 (tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_ABORT_CHUNK_T_BIT) != 0;
3383 if (chunk_tree) {
3384 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_abort_chunk_flags);
3385 proto_tree_add_item(flags_tree, hf_abort_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3386 causes_tvb = tvb_new_subset(chunk_tvb, CHUNK_VALUE_OFFSET,
3387 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_length_remaining(chunk_tvb, CHUNK_VALUE_OFFSET)),
3388 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, CHUNK_VALUE_OFFSET)));
3389 dissect_error_causes(causes_tvb, pinfo, chunk_tree);
3393 #define SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET CHUNK_VALUE_OFFSET
3394 #define SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_LENGTH 4
3396 static void
3397 dissect_shutdown_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item)
3399 if (chunk_tree) {
3400 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);
3401 proto_item_append_text(chunk_item, " (Cumulative TSN ack: %u)", tvb_get_ntohl(chunk_tvb, SHUTDOWN_CHUNK_CUMULATIVE_TSN_ACK_OFFSET));
3405 static void
3406 dissect_shutdown_ack_chunk(tvbuff_t *chunk_tvb _U_)
3410 #define ERROR_CAUSE_IND_CAUSES_OFFSET CHUNK_VALUE_OFFSET
3412 static void
3413 dissect_error_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree)
3415 tvbuff_t *causes_tvb;
3417 if (chunk_tree) {
3418 causes_tvb = tvb_new_subset(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET,
3419 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_length_remaining(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET)),
3420 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, ERROR_CAUSE_IND_CAUSES_OFFSET)));
3421 dissect_error_causes(causes_tvb, pinfo, chunk_tree);
3425 #define COOKIE_OFFSET CHUNK_VALUE_OFFSET
3427 static void
3428 dissect_cookie_echo_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, proto_tree *chunk_tree, proto_item *chunk_item)
3430 if (chunk_tree) {
3431 proto_tree_add_item(chunk_tree, hf_cookie, chunk_tvb, COOKIE_OFFSET, chunk_length - CHUNK_HEADER_LENGTH, ENC_NA);
3432 proto_item_append_text(chunk_item, " (Cookie length: %u byte%s)", chunk_length - CHUNK_HEADER_LENGTH, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
3436 static void
3437 dissect_cookie_ack_chunk(tvbuff_t *chunk_tvb _U_)
3441 #define ECNE_CHUNK_LOWEST_TSN_OFFSET CHUNK_VALUE_OFFSET
3442 #define ECNE_CHUNK_LOWEST_TSN_LENGTH 4
3444 static void
3445 dissect_ecne_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item)
3447 if (chunk_tree)
3448 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);
3449 proto_item_append_text(chunk_item, " (Lowest TSN: %u)", tvb_get_ntohl(chunk_tvb, ECNE_CHUNK_LOWEST_TSN_OFFSET));
3452 #define CWR_CHUNK_LOWEST_TSN_OFFSET CHUNK_VALUE_OFFSET
3453 #define CWR_CHUNK_LOWEST_TSN_LENGTH 4
3455 static void
3456 dissect_cwr_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *chunk_item)
3458 if (chunk_tree)
3459 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);
3460 proto_item_append_text(chunk_item, " (Lowest TSN: %u)", tvb_get_ntohl(chunk_tvb, CWR_CHUNK_LOWEST_TSN_OFFSET));
3463 #define SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT 0x01
3466 static const true_false_string sctp_shutdown_complete_chunk_t_bit_value = {
3467 "Tag reflected",
3468 "Tag not reflected"
3472 static void
3473 dissect_shutdown_complete_chunk(tvbuff_t *chunk_tvb, proto_tree *chunk_tree, proto_item *flags_item)
3475 proto_tree *flags_tree;
3477 sctp_info.vtag_reflected =
3478 (tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_SHUTDOWN_COMPLETE_CHUNK_T_BIT) != 0;
3480 if (chunk_tree) {
3481 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_shutdown_complete_chunk_flags);
3482 proto_tree_add_item(flags_tree, hf_shutdown_complete_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3486 #define FORWARD_TSN_CHUNK_TSN_LENGTH 4
3487 #define FORWARD_TSN_CHUNK_SID_LENGTH 2
3488 #define FORWARD_TSN_CHUNK_SSN_LENGTH 2
3489 #define FORWARD_TSN_CHUNK_TSN_OFFSET CHUNK_VALUE_OFFSET
3490 #define FORWARD_TSN_CHUNK_SID_OFFSET 0
3491 #define FORWARD_TSN_CHUNK_SSN_OFFSET (FORWARD_TSN_CHUNK_SID_OFFSET + FORWARD_TSN_CHUNK_SID_LENGTH)
3493 static void
3494 dissect_forward_tsn_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, proto_tree *chunk_tree, proto_item *chunk_item)
3496 guint offset;
3497 guint16 number_of_affected_streams, affected_stream;
3499 /* FIXME */
3500 if (chunk_length < CHUNK_HEADER_LENGTH + FORWARD_TSN_CHUNK_TSN_LENGTH) {
3501 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
3502 chunk_length,
3503 CHUNK_HEADER_LENGTH + FORWARD_TSN_CHUNK_TSN_LENGTH);
3504 return;
3506 if (chunk_tree) {
3507 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);
3508 number_of_affected_streams = (chunk_length - CHUNK_HEADER_LENGTH - FORWARD_TSN_CHUNK_TSN_LENGTH) /
3509 (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH);
3510 offset = CHUNK_VALUE_OFFSET + FORWARD_TSN_CHUNK_TSN_LENGTH;
3512 for(affected_stream = 0; affected_stream < number_of_affected_streams; affected_stream++) {
3513 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);
3514 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);
3515 offset = offset + (FORWARD_TSN_CHUNK_SID_LENGTH + FORWARD_TSN_CHUNK_SSN_LENGTH);
3517 proto_item_append_text(chunk_item, "(Cumulative TSN: %u)", tvb_get_ntohl(chunk_tvb, FORWARD_TSN_CHUNK_TSN_OFFSET));
3521 #define RE_CONFIG_PARAMETERS_OFFSET CHUNK_HEADER_LENGTH
3523 static void
3524 dissect_re_config_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item _U_)
3526 tvbuff_t *parameters_tvb;
3528 parameters_tvb = tvb_new_subset(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET,
3529 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_length_remaining(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET)),
3530 MIN(chunk_length - CHUNK_HEADER_LENGTH, tvb_reported_length_remaining(chunk_tvb, RE_CONFIG_PARAMETERS_OFFSET)));
3531 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, FALSE);
3534 #define SHARED_KEY_ID_LENGTH 2
3536 #define SHARED_KEY_ID_OFFSET PARAMETER_VALUE_OFFSET
3537 #define HMAC_ID_OFFSET (SHARED_KEY_ID_OFFSET + SHARED_KEY_ID_LENGTH)
3538 #define HMAC_OFFSET (HMAC_ID_OFFSET + HMAC_ID_LENGTH)
3540 static void
3541 dissect_auth_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, proto_tree *chunk_tree, proto_item *chunk_item _U_)
3543 guint hmac_length;
3545 hmac_length = chunk_length - CHUNK_HEADER_LENGTH - HMAC_ID_LENGTH - SHARED_KEY_ID_LENGTH;
3546 proto_tree_add_item(chunk_tree, hf_shared_key_id, chunk_tvb, SHARED_KEY_ID_OFFSET, SHARED_KEY_ID_LENGTH, ENC_BIG_ENDIAN);
3547 proto_tree_add_item(chunk_tree, hf_hmac_id, chunk_tvb, HMAC_ID_OFFSET, HMAC_ID_LENGTH, ENC_BIG_ENDIAN);
3548 if (hmac_length > 0)
3549 proto_tree_add_item(chunk_tree, hf_hmac, chunk_tvb, HMAC_OFFSET, hmac_length, ENC_NA);
3552 #define SCTP_SEQUENCE_NUMBER_LENGTH 4
3553 #define SEQUENCE_NUMBER_OFFSET CHUNK_VALUE_OFFSET
3554 #define ASCONF_CHUNK_PARAMETERS_OFFSET (SEQUENCE_NUMBER_OFFSET + SCTP_SEQUENCE_NUMBER_LENGTH)
3556 static void
3557 dissect_asconf_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
3559 tvbuff_t *parameters_tvb;
3561 if (chunk_length < CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH) {
3562 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
3563 chunk_length,
3564 CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH);
3565 return;
3567 if (chunk_tree) {
3568 proto_tree_add_item(chunk_tree, hf_asconf_seq_nr, chunk_tvb, SEQUENCE_NUMBER_OFFSET, SCTP_SEQUENCE_NUMBER_LENGTH, ENC_BIG_ENDIAN);
3570 chunk_length -= CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH;
3571 parameters_tvb = tvb_new_subset(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET,
3572 MIN(chunk_length, tvb_length_remaining(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET)),
3573 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, ASCONF_CHUNK_PARAMETERS_OFFSET)));
3574 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, FALSE);
3577 #define ASCONF_ACK_CHUNK_PARAMETERS_OFFSET (SEQUENCE_NUMBER_OFFSET + SCTP_SEQUENCE_NUMBER_LENGTH)
3579 static void
3580 dissect_asconf_ack_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item)
3582 tvbuff_t *parameters_tvb;
3584 if (chunk_length < CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH) {
3585 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
3586 chunk_length + CHUNK_HEADER_LENGTH,
3587 CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH);
3588 return;
3590 if (chunk_tree) {
3591 proto_tree_add_item(chunk_tree, hf_asconf_ack_seq_nr, chunk_tvb, SEQUENCE_NUMBER_OFFSET, SCTP_SEQUENCE_NUMBER_LENGTH, ENC_BIG_ENDIAN);
3593 chunk_length -= CHUNK_HEADER_LENGTH + SCTP_SEQUENCE_NUMBER_LENGTH;
3594 parameters_tvb = tvb_new_subset(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET,
3595 MIN(chunk_length, tvb_length_remaining(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET)),
3596 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, ASCONF_ACK_CHUNK_PARAMETERS_OFFSET)));
3597 dissect_parameters(parameters_tvb, pinfo, chunk_tree, NULL, FALSE);
3600 #define PKTDROP_CHUNK_BANDWIDTH_LENGTH 4
3601 #define PKTDROP_CHUNK_QUEUESIZE_LENGTH 4
3602 #define PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH 2
3603 #define PKTDROP_CHUNK_RESERVED_SIZE_LENGTH 2
3605 #define PKTDROP_CHUNK_HEADER_LENGTH (CHUNK_HEADER_LENGTH + \
3606 PKTDROP_CHUNK_BANDWIDTH_LENGTH + \
3607 PKTDROP_CHUNK_QUEUESIZE_LENGTH + \
3608 PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH + \
3609 PKTDROP_CHUNK_RESERVED_SIZE_LENGTH)
3611 #define PKTDROP_CHUNK_BANDWIDTH_OFFSET CHUNK_VALUE_OFFSET
3612 #define PKTDROP_CHUNK_QUEUESIZE_OFFSET (PKTDROP_CHUNK_BANDWIDTH_OFFSET + PKTDROP_CHUNK_BANDWIDTH_LENGTH)
3613 #define PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET (PKTDROP_CHUNK_QUEUESIZE_OFFSET + PKTDROP_CHUNK_QUEUESIZE_LENGTH)
3614 #define PKTDROP_CHUNK_RESERVED_SIZE_OFFSET (PKTDROP_CHUNK_TRUNCATED_SIZE_OFFSET + PKTDROP_CHUNK_TRUNCATED_SIZE_LENGTH)
3615 #define PKTDROP_CHUNK_DATA_FIELD_OFFSET (PKTDROP_CHUNK_RESERVED_SIZE_OFFSET + PKTDROP_CHUNK_RESERVED_SIZE_LENGTH)
3617 #define SCTP_PKTDROP_CHUNK_M_BIT 0x01
3618 #define SCTP_PKTDROP_CHUNK_B_BIT 0x02
3619 #define SCTP_PKTDROP_CHUNK_T_BIT 0x04
3621 static const true_false_string sctp_pktdropk_m_bit_value = {
3622 "Source is a middlebox",
3623 "Source is an endhost"
3626 static const true_false_string sctp_pktdropk_b_bit_value = {
3627 "SCTP checksum was incorrect",
3628 "SCTP checksum was correct"
3631 static const true_false_string sctp_pktdropk_t_bit_value = {
3632 "Packet is truncated",
3633 "Packet is not truncated"
3636 static void
3637 dissect_pktdrop_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, packet_info *pinfo, proto_tree *chunk_tree, proto_item *chunk_item, proto_item *flags_item)
3639 tvbuff_t *data_field_tvb;
3640 proto_tree *flags_tree;
3642 if (chunk_length < PKTDROP_CHUNK_HEADER_LENGTH) {
3643 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)",
3644 chunk_length,
3645 PKTDROP_CHUNK_HEADER_LENGTH);
3646 return;
3648 chunk_length -= PKTDROP_CHUNK_HEADER_LENGTH;
3649 data_field_tvb = tvb_new_subset(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET,
3650 MIN(chunk_length, tvb_length_remaining(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET)),
3651 MIN(chunk_length, tvb_reported_length_remaining(chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET)));
3653 if (chunk_tree) {
3654 flags_tree = proto_item_add_subtree(flags_item, ett_sctp_pktdrop_chunk_flags);
3656 proto_tree_add_item(flags_tree, hf_pktdrop_chunk_m_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3657 proto_tree_add_item(flags_tree, hf_pktdrop_chunk_b_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3658 proto_tree_add_item(flags_tree, hf_pktdrop_chunk_t_bit, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3659 proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_bandwidth, chunk_tvb, PKTDROP_CHUNK_BANDWIDTH_OFFSET, PKTDROP_CHUNK_BANDWIDTH_LENGTH, ENC_BIG_ENDIAN);
3660 proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_queuesize, chunk_tvb, PKTDROP_CHUNK_QUEUESIZE_OFFSET, PKTDROP_CHUNK_QUEUESIZE_LENGTH, ENC_BIG_ENDIAN);
3661 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);
3662 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);
3663 /* XXX - set pinfo->flags.in_error_pkt? */
3664 if (chunk_length > 0) {
3665 if (tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_PKTDROP_CHUNK_T_BIT)
3666 proto_tree_add_item(chunk_tree, hf_pktdrop_chunk_data_field, chunk_tvb, PKTDROP_CHUNK_DATA_FIELD_OFFSET, chunk_length, ENC_NA);
3667 else
3668 dissect_sctp_packet(data_field_tvb, pinfo, chunk_tree, TRUE);
3673 static void
3674 dissect_unknown_chunk(tvbuff_t *chunk_tvb, guint16 chunk_length, guint8 chunk_type, proto_tree *chunk_tree, proto_item *chunk_item)
3676 if (chunk_tree) {
3677 if (chunk_length > CHUNK_HEADER_LENGTH)
3678 proto_tree_add_item(chunk_tree, hf_chunk_value, chunk_tvb, CHUNK_VALUE_OFFSET, chunk_length - CHUNK_HEADER_LENGTH, ENC_NA);
3679 proto_item_append_text(chunk_item, " (Type: %u, value length: %u byte%s)", chunk_type, chunk_length, plurality(chunk_length - CHUNK_HEADER_LENGTH, "", "s"));
3683 #define SCTP_CHUNK_BIT_1 0x80
3684 #define SCTP_CHUNK_BIT_2 0x40
3686 static const true_false_string sctp_chunk_bit_1_value = {
3687 "Skip chunk and continue processing of the packet",
3688 "Stop processing of the packet"
3691 static const true_false_string sctp_chunk_bit_2_value = {
3692 "Do report",
3693 "Do not report"
3697 static gboolean
3698 dissect_sctp_chunk(tvbuff_t *chunk_tvb,
3699 packet_info *pinfo,
3700 proto_tree *tree,
3701 proto_tree *sctp_tree,
3702 sctp_half_assoc_t *ha,
3703 gboolean useinfo)
3705 guint8 type;
3706 guint16 length, padding_length, reported_length;
3707 gboolean result;
3708 proto_item *flags_item, *chunk_item, *type_item, *length_item;
3709 proto_tree *chunk_tree, *type_tree;
3711 result = FALSE;
3713 /* first extract the chunk header */
3714 type = tvb_get_guint8(chunk_tvb, CHUNK_TYPE_OFFSET);
3715 length = tvb_get_ntohs(chunk_tvb, CHUNK_LENGTH_OFFSET);
3716 reported_length = tvb_reported_length(chunk_tvb);
3717 padding_length = reported_length - length;
3719 if (useinfo)
3720 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(type, chunk_type_values, "RESERVED"));
3722 /* create proto_tree stuff */
3723 chunk_item = proto_tree_add_text(sctp_tree, chunk_tvb, CHUNK_HEADER_OFFSET, reported_length, "%s chunk", val_to_str_const(type, chunk_type_values, "RESERVED"));
3724 chunk_tree = proto_item_add_subtree(chunk_item, ett_sctp_chunk);
3725 if (reported_length % 4)
3726 expert_add_info_format(pinfo, chunk_item, &ei_sctp_chunk_length_bad, "Chunk length is not padded to a multiple of 4 bytes (length=%d).", reported_length);
3728 if (tree) {
3729 /* then insert the chunk header components into the protocol tree */
3730 type_item = proto_tree_add_item(chunk_tree, hf_chunk_type, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
3731 type_tree = proto_item_add_subtree(type_item, ett_sctp_chunk_type);
3732 proto_tree_add_item(type_tree, hf_chunk_bit_1, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
3733 proto_tree_add_item(type_tree, hf_chunk_bit_2, chunk_tvb, CHUNK_TYPE_OFFSET, CHUNK_TYPE_LENGTH, ENC_BIG_ENDIAN);
3734 flags_item = proto_tree_add_item(chunk_tree, hf_chunk_flags, chunk_tvb, CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_LENGTH, ENC_BIG_ENDIAN);
3735 } else {
3736 chunk_tree = NULL;
3737 chunk_item = NULL;
3738 flags_item = NULL;
3741 if (length < CHUNK_HEADER_LENGTH) {
3742 if (tree) {
3743 proto_tree_add_uint_format_value(chunk_tree, hf_chunk_length, chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH, length,
3744 "%u (invalid, should be >= %u)", length, CHUNK_HEADER_LENGTH);
3745 proto_item_append_text(chunk_item, ", bogus chunk length %u < %u)", length, CHUNK_HEADER_LENGTH);
3748 if (type == SCTP_DATA_CHUNK_ID)
3749 result = TRUE;
3750 return result;
3753 length_item = proto_tree_add_uint(chunk_tree, hf_chunk_length, chunk_tvb, CHUNK_LENGTH_OFFSET, CHUNK_LENGTH_LENGTH, length);
3754 if (length > reported_length) {
3755 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);
3756 /* We'll almost certainly throw an exception shortly... */
3760 length -= CHUNK_HEADER_LENGTH;
3763 /* now dissect the chunk value */
3764 switch(type) {
3765 case SCTP_DATA_CHUNK_ID:
3766 result = dissect_data_chunk(chunk_tvb, length, pinfo, tree, chunk_tree, chunk_item, flags_item, ha);
3767 break;
3768 case SCTP_INIT_CHUNK_ID:
3769 dissect_init_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3770 break;
3771 case SCTP_INIT_ACK_CHUNK_ID:
3772 dissect_init_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3773 break;
3774 case SCTP_SACK_CHUNK_ID:
3775 dissect_sack_chunk(pinfo, chunk_tvb, chunk_tree, chunk_item, flags_item, ha);
3776 break;
3777 case SCTP_HEARTBEAT_CHUNK_ID:
3778 dissect_heartbeat_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3779 break;
3780 case SCTP_HEARTBEAT_ACK_CHUNK_ID:
3781 dissect_heartbeat_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3782 break;
3783 case SCTP_ABORT_CHUNK_ID:
3784 dissect_abort_chunk(chunk_tvb, length, pinfo, chunk_tree, flags_item);
3785 break;
3786 case SCTP_SHUTDOWN_CHUNK_ID:
3787 dissect_shutdown_chunk(chunk_tvb, chunk_tree, chunk_item);
3788 break;
3789 case SCTP_SHUTDOWN_ACK_CHUNK_ID:
3790 dissect_shutdown_ack_chunk(chunk_tvb);
3791 break;
3792 case SCTP_ERROR_CHUNK_ID:
3793 dissect_error_chunk(chunk_tvb, length, pinfo, chunk_tree);
3794 break;
3795 case SCTP_COOKIE_ECHO_CHUNK_ID:
3796 dissect_cookie_echo_chunk(chunk_tvb, length, chunk_tree, chunk_item);
3797 break;
3798 case SCTP_COOKIE_ACK_CHUNK_ID:
3799 dissect_cookie_ack_chunk(chunk_tvb);
3800 break;
3801 case SCTP_ECNE_CHUNK_ID:
3802 dissect_ecne_chunk(chunk_tvb, chunk_tree, chunk_item);
3803 break;
3804 case SCTP_CWR_CHUNK_ID:
3805 dissect_cwr_chunk(chunk_tvb, chunk_tree, chunk_item);
3806 break;
3807 case SCTP_SHUTDOWN_COMPLETE_CHUNK_ID:
3808 dissect_shutdown_complete_chunk(chunk_tvb, chunk_tree, flags_item);
3809 break;
3810 case SCTP_FORWARD_TSN_CHUNK_ID:
3811 dissect_forward_tsn_chunk(chunk_tvb, length, chunk_tree, chunk_item);
3812 break;
3813 case SCTP_RE_CONFIG_CHUNK_ID:
3814 dissect_re_config_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3815 break;
3816 case SCTP_AUTH_CHUNK_ID:
3817 dissect_auth_chunk(chunk_tvb, length, chunk_tree, chunk_item);
3818 break;
3819 case SCTP_NR_SACK_CHUNK_ID:
3820 dissect_nr_sack_chunk(pinfo, chunk_tvb, chunk_tree, chunk_item, flags_item, ha);
3821 break;
3822 case SCTP_ASCONF_ACK_CHUNK_ID:
3823 dissect_asconf_ack_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3824 break;
3825 case SCTP_ASCONF_CHUNK_ID:
3826 dissect_asconf_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item);
3827 break;
3828 case SCTP_PKTDROP_CHUNK_ID:
3829 col_set_writable(pinfo->cinfo, FALSE);
3830 dissect_pktdrop_chunk(chunk_tvb, length, pinfo, chunk_tree, chunk_item, flags_item);
3831 col_set_writable(pinfo->cinfo, TRUE);
3832 break;
3833 default:
3834 dissect_unknown_chunk(chunk_tvb, length, type, chunk_tree, chunk_item);
3835 break;
3838 if (padding_length > 0)
3839 proto_tree_add_item(chunk_tree, hf_chunk_padding, chunk_tvb, CHUNK_HEADER_OFFSET + length, padding_length, ENC_NA);
3841 if (useinfo && ((type == SCTP_DATA_CHUNK_ID) || show_always_control_chunks))
3842 col_set_fence(pinfo->cinfo, COL_INFO);
3844 return result;
3847 static void
3848 dissect_sctp_chunks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item *sctp_item, proto_tree *sctp_tree, sctp_half_assoc_t *ha, gboolean encapsulated)
3850 tvbuff_t *chunk_tvb;
3851 guint16 length, total_length, remaining_length;
3852 gint last_offset, offset;
3853 gboolean sctp_item_length_set;
3855 /* the common header of the datagram is already handled */
3856 last_offset = 0;
3857 offset = COMMON_HEADER_LENGTH;
3858 sctp_item_length_set = FALSE;
3860 while((remaining_length = tvb_reported_length_remaining(tvb, offset))) {
3861 /* extract the chunk length and compute number of padding bytes */
3862 length = tvb_get_ntohs(tvb, offset + CHUNK_LENGTH_OFFSET);
3863 total_length = ADD_PADDING(length);
3865 /* If we have less bytes than we need, throw an exception while dissecting
3866 * the chunk--not when generating the chunk_tvb below.
3868 total_length = MIN(total_length, remaining_length);
3870 /* create a tvb for the chunk including the padding bytes */
3871 chunk_tvb = tvb_new_subset(tvb, offset, MIN(total_length, tvb_length_remaining(tvb, offset)), total_length);
3873 /* save it in the sctp_info structure */
3874 if (!encapsulated) {
3875 if (sctp_info.number_of_tvbs < MAXIMUM_NUMBER_OF_TVBS)
3876 sctp_info.tvb[sctp_info.number_of_tvbs++] = chunk_tvb;
3877 else
3878 sctp_info.incomplete = TRUE;
3881 /* call dissect_sctp_chunk for the actual work */
3882 if (dissect_sctp_chunk(chunk_tvb, pinfo, tree, sctp_tree, ha, !encapsulated) && (tree)) {
3883 proto_item_set_len(sctp_item, offset - last_offset + DATA_CHUNK_HEADER_LENGTH);
3884 sctp_item_length_set = TRUE;
3885 offset += total_length;
3886 last_offset = offset;
3887 if (tvb_reported_length_remaining(tvb, offset) > 0) {
3888 sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, offset, -1, ENC_NA);
3889 sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
3890 sctp_item_length_set = FALSE;
3892 } else {
3893 /* get rid of the dissected chunk */
3894 offset += total_length;
3897 if (!sctp_item_length_set && (tree)) {
3898 proto_item_set_len(sctp_item, offset - last_offset);
3902 static void
3903 dissect_sctp_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean encapsulated)
3905 guint32 checksum = 0, calculated_crc32c = 0, calculated_adler32 = 0;
3906 guint16 source_port, destination_port;
3907 guint length, reported_length;
3908 gboolean crc32c_correct = FALSE, adler32_correct = FALSE;
3909 proto_item *sctp_item, *hidden_item, *item;
3910 proto_tree *sctp_tree;
3911 guint32 vtag;
3912 sctp_half_assoc_t *ha = NULL;
3914 length = tvb_length(tvb);
3915 reported_length = tvb_reported_length(tvb);
3916 checksum = tvb_get_ntohl(tvb, CHECKSUM_OFFSET);
3917 sctp_info.checksum_zero = (checksum == 0);
3919 /* Only try to checksum the packet if we have all of it */
3920 if (tvb_bytes_exist(tvb, 0, reported_length)) {
3922 switch(sctp_checksum) {
3923 case SCTP_CHECKSUM_NONE:
3924 break;
3925 case SCTP_CHECKSUM_ADLER32:
3926 calculated_adler32 = sctp_adler32(tvb_get_ptr(tvb, 0, length), length);
3927 adler32_correct = (checksum == calculated_adler32);
3928 sctp_info.adler32_calculated = TRUE;
3929 sctp_info.adler32_correct = adler32_correct;
3930 break;
3931 case SCTP_CHECKSUM_CRC32C:
3932 calculated_crc32c = sctp_crc32c(tvb_get_ptr(tvb, 0, length), length);
3933 crc32c_correct = (checksum == calculated_crc32c);
3934 sctp_info.crc32c_calculated = TRUE;
3935 sctp_info.crc32c_correct = crc32c_correct;
3936 break;
3937 case SCTP_CHECKSUM_AUTOMATIC:
3938 calculated_adler32 = sctp_adler32(tvb_get_ptr(tvb, 0, length), length);
3939 adler32_correct = (checksum == calculated_adler32);
3940 calculated_crc32c = sctp_crc32c(tvb_get_ptr(tvb, 0, length), length);
3941 crc32c_correct = (checksum == calculated_crc32c);
3942 sctp_info.adler32_calculated = TRUE;
3943 sctp_info.adler32_correct = adler32_correct;
3944 sctp_info.crc32c_calculated = TRUE;
3945 sctp_info.crc32c_correct = crc32c_correct;
3946 break;
3950 source_port = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET);
3951 destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET);
3952 vtag = tvb_get_ntohl(tvb,VERIFICATION_TAG_OFFSET);
3954 ha = get_half_assoc(pinfo, source_port, destination_port, vtag);
3956 /* In the interest of speed, if "tree" is NULL, don't do any work not
3957 necessary to generate protocol tree items. */
3958 if (tree) {
3960 /* create the sctp protocol tree */
3961 if (show_port_numbers)
3962 sctp_item = proto_tree_add_protocol_format(tree, proto_sctp, tvb, 0, -1,
3963 "Stream Control Transmission Protocol, Src Port: %s (%u), Dst Port: %s (%u)",
3964 get_sctp_port(source_port), source_port,
3965 get_sctp_port(destination_port), destination_port);
3966 else
3967 sctp_item = proto_tree_add_item(tree, proto_sctp, tvb, 0, -1, ENC_NA);
3969 sctp_tree = proto_item_add_subtree(sctp_item, ett_sctp);
3971 /* add the components of the common header to the protocol tree */
3972 proto_tree_add_item(sctp_tree, hf_source_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, ENC_BIG_ENDIAN);
3973 proto_tree_add_item(sctp_tree, hf_destination_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, ENC_BIG_ENDIAN);
3974 proto_tree_add_item(sctp_tree, hf_verification_tag, tvb, VERIFICATION_TAG_OFFSET, VERIFICATION_TAG_LENGTH, ENC_BIG_ENDIAN);
3975 hidden_item = proto_tree_add_item(sctp_tree, hf_port, tvb, SOURCE_PORT_OFFSET, SOURCE_PORT_LENGTH, ENC_BIG_ENDIAN);
3976 PROTO_ITEM_SET_HIDDEN(hidden_item);
3977 hidden_item = proto_tree_add_item(sctp_tree, hf_port, tvb, DESTINATION_PORT_OFFSET, DESTINATION_PORT_LENGTH, ENC_BIG_ENDIAN);
3978 PROTO_ITEM_SET_HIDDEN(hidden_item);
3979 } else {
3980 sctp_tree = NULL;
3981 sctp_item = NULL;
3984 if (tvb_bytes_exist(tvb, 0, reported_length)) {
3985 /* We have the whole packet */
3987 switch(sctp_checksum) {
3988 case SCTP_CHECKSUM_NONE:
3989 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum, "0x%08x (not verified)", checksum);
3990 break;
3991 case SCTP_CHECKSUM_ADLER32:
3992 if (adler32_correct)
3993 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
3994 checksum, "0x%08x [correct Adler32]", checksum);
3995 else {
3996 item = proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum,
3997 "0x%08x [incorrect Adler32, should be 0x%08x]",
3998 checksum, calculated_adler32);
3999 expert_add_info(pinfo, item, &ei_sctp_bad_sctp_checksum);
4001 hidden_item = proto_tree_add_boolean(sctp_tree, hf_checksum_bad, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, !(adler32_correct));
4002 PROTO_ITEM_SET_HIDDEN(hidden_item);
4003 break;
4004 case SCTP_CHECKSUM_CRC32C:
4005 if (crc32c_correct)
4006 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
4007 checksum, "0x%08x [correct CRC32C]", checksum);
4008 else {
4009 item = proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum,
4010 "0x%08x [incorrect CRC32C, should be 0x%08x]",
4011 checksum, calculated_crc32c);
4012 expert_add_info(pinfo, item, &ei_sctp_bad_sctp_checksum);
4014 hidden_item = proto_tree_add_boolean(sctp_tree, hf_checksum_bad, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, !(crc32c_correct));
4015 PROTO_ITEM_SET_HIDDEN(hidden_item);
4016 break;
4017 case SCTP_CHECKSUM_AUTOMATIC:
4018 if ((adler32_correct) && !(crc32c_correct))
4019 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
4020 checksum, "0x%08x [correct Adler32]", checksum);
4021 else if ((!adler32_correct) && (crc32c_correct))
4022 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
4023 checksum, "0x%08x [correct CRC32C]", checksum);
4024 else if ((adler32_correct) && (crc32c_correct))
4025 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
4026 checksum, "0x%08x [correct Adler32 and CRC32C]", checksum);
4027 else {
4028 item = proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, checksum,
4029 "0x%08x [incorrect, should be 0x%08x (Adler32) or 0x%08x (CRC32C)]",
4030 checksum, calculated_adler32, calculated_crc32c);
4031 expert_add_info(pinfo, item, &ei_sctp_bad_sctp_checksum);
4033 hidden_item = proto_tree_add_boolean(sctp_tree, hf_checksum_bad, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH, !(crc32c_correct || adler32_correct));
4034 PROTO_ITEM_SET_HIDDEN(hidden_item);
4035 break;
4037 } else {
4038 /* We don't have the whole packet so we can't verify the checksum */
4039 proto_tree_add_uint_format_value(sctp_tree, hf_checksum, tvb, CHECKSUM_OFFSET, CHECKSUM_LENGTH,
4040 checksum, "0x%08x [unchecked, not all data available]", checksum);
4043 /* add all chunks of the sctp datagram to the protocol tree */
4044 dissect_sctp_chunks(tvb, pinfo, tree, sctp_item, sctp_tree, ha, encapsulated);
4047 static void
4048 dissect_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4050 guint16 source_port, destination_port;
4051 guint number_of_ppid;
4053 /* Extract the common header */
4054 source_port = tvb_get_ntohs(tvb, SOURCE_PORT_OFFSET);
4055 destination_port = tvb_get_ntohs(tvb, DESTINATION_PORT_OFFSET);
4057 /* update pi structure */
4058 pinfo->ptype = PT_SCTP;
4059 pinfo->srcport = source_port;
4060 pinfo->destport = destination_port;
4062 /* make entry in the Protocol column on summary display */
4063 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCTP");
4065 /* Clear entries in Info column on summary display */
4066 col_set_str(pinfo->cinfo, COL_INFO, "");
4069 for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) {
4070 pinfo->ppids[number_of_ppid] = LAST_PPID;
4073 /* The tvb array in struct _sctp_info is huge: currently 2k pointers.
4074 * We know (by the value of 'number_of_tvbs') which of these entries have
4075 * been used, so don't memset() the array. This saves us from zeroing out
4076 * 8k (4-byte pointers) or 16k (8-byte pointers) of memory every time we
4077 * dissect a packet (saving quite a bit of time!).
4079 sctp_info.incomplete = 0;
4080 sctp_info.adler32_calculated = 0;
4081 sctp_info.adler32_correct = 0;
4082 sctp_info.crc32c_calculated = 0;
4083 sctp_info.crc32c_correct = 0;
4084 sctp_info.vtag_reflected = 0;
4085 sctp_info.number_of_tvbs = 0;
4086 sctp_info.verification_tag = tvb_get_ntohl(tvb, VERIFICATION_TAG_OFFSET);
4088 sctp_info.sport = pinfo->srcport;
4089 sctp_info.dport = pinfo->destport;
4090 SET_ADDRESS(&sctp_info.ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
4091 SET_ADDRESS(&sctp_info.ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
4093 dissect_sctp_packet(tvb, pinfo, tree, FALSE);
4094 if (!pinfo->flags.in_error_pkt)
4095 tap_queue_packet(sctp_tap, pinfo, &sctp_info);
4098 /* Register the protocol with Wireshark */
4099 void
4100 proto_register_sctp(void)
4103 /* Setup list of header fields */
4104 static hf_register_info hf[] = {
4105 { &hf_source_port, { "Source port", "sctp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4106 { &hf_destination_port, { "Destination port", "sctp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4107 { &hf_port, { "Port", "sctp.port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4108 { &hf_verification_tag, { "Verification tag", "sctp.verification_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4109 { &hf_checksum, { "Checksum", "sctp.checksum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4110 { &hf_checksum_bad, { "Bad checksum", "sctp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4111 { &hf_chunk_type, { "Chunk type", "sctp.chunk_type", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } },
4112 { &hf_chunk_flags, { "Chunk flags", "sctp.chunk_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4113 { &hf_chunk_bit_1, { "Bit", "sctp.chunk_bit_1", FT_BOOLEAN, 8, TFS(&sctp_chunk_bit_1_value), SCTP_CHUNK_BIT_1, NULL, HFILL } },
4114 { &hf_chunk_bit_2, { "Bit", "sctp.chunk_bit_2", FT_BOOLEAN, 8, TFS(&sctp_chunk_bit_2_value), SCTP_CHUNK_BIT_2, NULL, HFILL } },
4115 { &hf_chunk_length, { "Chunk length", "sctp.chunk_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4116 { &hf_chunk_padding, { "Chunk padding", "sctp.chunk_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4117 { &hf_chunk_value, { "Chunk value", "sctp.chunk_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4118 { &hf_cookie, { "Cookie", "sctp.cookie", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4119 { &hf_initiate_tag, { "Initiate tag", "sctp.initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4120 { &hf_init_chunk_initiate_tag, { "Initiate tag", "sctp.init_initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4121 { &hf_init_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.init_credit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4122 { &hf_init_chunk_number_of_outbound_streams, { "Number of outbound streams", "sctp.init_nr_out_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4123 { &hf_init_chunk_number_of_inbound_streams, { "Number of inbound streams", "sctp.init_nr_in_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4124 { &hf_init_chunk_initial_tsn, { "Initial TSN", "sctp.init_initial_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4125 { &hf_initack_chunk_initiate_tag, { "Initiate tag", "sctp.initack_initiate_tag", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4126 { &hf_initack_chunk_adv_rec_window_credit, { "Advertised receiver window credit (a_rwnd)", "sctp.initack_credit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4127 { &hf_initack_chunk_number_of_outbound_streams, { "Number of outbound streams", "sctp.initack_nr_out_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4128 { &hf_initack_chunk_number_of_inbound_streams, { "Number of inbound streams", "sctp.initack_nr_in_streams", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4129 { &hf_initack_chunk_initial_tsn, { "Initial TSN", "sctp.initack_initial_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4130 #if 0
4131 { &hf_cumulative_tsn_ack, { "Cumulative TSN Ack", "sctp.cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4132 #endif
4133 { &hf_data_chunk_tsn, { "TSN", "sctp.data_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4134 { &hf_data_chunk_stream_id, { "Stream Identifier", "sctp.data_sid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4135 { &hf_data_chunk_stream_seq_number, { "Stream sequence number", "sctp.data_ssn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4136 { &hf_data_chunk_payload_proto_id, { "Payload protocol identifier", "sctp.data_payload_proto_id", FT_UINT32, BASE_DEC, VALS(sctp_payload_proto_id_values), 0x0, NULL, HFILL } },
4137 { &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 } },
4138 { &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 } },
4139 { &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 } },
4140 { &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 } },
4141 { &hf_sack_chunk_ns, { "Nounce sum", "sctp.sack_nounce_sum", FT_UINT8, BASE_DEC, NULL, SCTP_SACK_CHUNK_NS_BIT, NULL, HFILL } },
4142 { &hf_sack_chunk_cumulative_tsn_ack, { "Cumulative TSN ACK", "sctp.sack_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4143 { &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 } },
4144 { &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 } },
4145 { &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 } },
4146 { &hf_sack_chunk_gap_block_start, { "Start", "sctp.sack_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4147 { &hf_sack_chunk_gap_block_start_tsn, { "Start TSN", "sctp.sack_gap_block_start_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4148 { &hf_sack_chunk_gap_block_end, { "End", "sctp.sack_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4149 { &hf_sack_chunk_gap_block_end_tsn, { "End TSN", "sctp.sack_gap_block_end_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4150 { &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 } },
4151 { &hf_sack_chunk_duplicate_tsn, { "Duplicate TSN", "sctp.sack_duplicate_tsn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4152 { &hf_nr_sack_chunk_ns, { "Nounce sum", "sctp.nr_sack_nounce_sum", FT_UINT8, BASE_DEC, NULL, SCTP_NR_SACK_CHUNK_NS_BIT, NULL, HFILL } },
4153 { &hf_nr_sack_chunk_cumulative_tsn_ack, { "Cumulative TSN ACK", "sctp.nr_sack_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4154 { &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 } },
4155 { &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 } },
4156 { &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 } },
4157 { &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 } },
4158 { &hf_nr_sack_chunk_reserved, { "Reserved", "sctp.nr_sack_reserved", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4159 { &hf_nr_sack_chunk_gap_block_start, { "Start", "sctp.nr_sack_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4160 { &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 } },
4161 { &hf_nr_sack_chunk_gap_block_end, { "End", "sctp.nr_sack_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4162 { &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 } },
4163 { &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 } },
4164 { &hf_nr_sack_chunk_nr_gap_block_start, { "Start", "sctp.nr_sack_nr_gap_block_start", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4165 { &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 } },
4166 { &hf_nr_sack_chunk_nr_gap_block_end, { "End", "sctp.nr_sack_nr_gap_block_end", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4167 { &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 } },
4168 { &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 } },
4169 #if 0
4170 { &hf_nr_sack_chunk_duplicate_tsn, { "Duplicate TSN", "sctp.nr_sack_duplicate_tsn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4171 #endif
4172 { &hf_shutdown_chunk_cumulative_tsn_ack, { "Cumulative TSN Ack", "sctp.shutdown_cumulative_tsn_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4173 { &hf_ecne_chunk_lowest_tsn, { "Lowest TSN", "sctp.ecne_lowest_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4174 { &hf_cwr_chunk_lowest_tsn, { "Lowest TSN", "sctp.cwr_lowest_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4175 { &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 } },
4176 { &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 } },
4177 { &hf_forward_tsn_chunk_tsn, { "New cumulative TSN", "sctp.forward_tsn_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4178 { &hf_forward_tsn_chunk_sid, { "Stream identifier", "sctp.forward_tsn_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4179 { &hf_forward_tsn_chunk_ssn, { "Stream sequence number", "sctp.forward_tsn_ssn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4180 { &hf_parameter_type, { "Parameter type", "sctp.parameter_type", FT_UINT16, BASE_HEX, VALS(parameter_identifier_values), 0x0, NULL, HFILL } },
4181 { &hf_parameter_length, { "Parameter length", "sctp.parameter_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4182 { &hf_parameter_value, { "Parameter value", "sctp.parameter_value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4183 { &hf_parameter_padding, { "Parameter padding", "sctp.parameter_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4184 { &hf_parameter_bit_1, { "Bit", "sctp.parameter_bit_1", FT_BOOLEAN, 16, TFS(&sctp_parameter_bit_1_value), SCTP_PARAMETER_BIT_1, NULL, HFILL } },
4185 { &hf_parameter_bit_2, { "Bit", "sctp.parameter_bit_2", FT_BOOLEAN, 16, TFS(&sctp_parameter_bit_2_value), SCTP_PARAMETER_BIT_2, NULL, HFILL } },
4186 { &hf_ipv4_address, { "IP Version 4 address", "sctp.parameter_ipv4_address", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4187 { &hf_ipv6_address, { "IP Version 6 address", "sctp.parameter_ipv6_address", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4188 { &hf_heartbeat_info, { "Heartbeat information", "sctp.parameter_heartbeat_information", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4189 { &hf_state_cookie, { "State cookie", "sctp.parameter_state_cookie", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4190 { &hf_cookie_preservative_increment, { "Suggested Cookie life-span increment (msec)", "sctp.parameter_cookie_preservative_incr", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4191 { &hf_hostname, { "Hostname", "sctp.parameter_hostname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4192 { &hf_supported_address_type, { "Supported address type", "sctp.parameter_supported_addres_type", FT_UINT16, BASE_DEC, VALS(address_types_values), 0x0, NULL, HFILL } },
4193 { &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 } },
4194 { &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 } },
4195 { &hf_senders_last_assigned_tsn, { "Senders last assigned TSN", "sctp.parameter_senders_last_assigned_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4196 { &hf_senders_next_tsn, { "Senders next TSN", "sctp.parameter_senders_next_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4197 { &hf_receivers_next_tsn, { "Receivers next TSN", "sctp.parameter_receivers_next_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4198 { &hf_stream_reset_rsp_result, { "Result", "sctp.parameter_reconfig_response_result", FT_UINT32, BASE_DEC, VALS(stream_reset_result_values), 0x0, NULL, HFILL } },
4199 { &hf_stream_reset_sid, { "Stream Identifier", "sctp.parameter_reconfig_sid", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4200 { &hf_add_outgoing_streams_number_streams, { "Number of streams", "sctp.parameter_add_outgoing_streams_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4201 { &hf_add_outgoing_streams_reserved, { "Reserved", "sctp.parameter_add_outgoing_streams_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4202 { &hf_add_incoming_streams_number_streams, { "Number of streams", "sctp.parameter_add_incoming_streams_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4203 { &hf_add_incoming_streams_reserved, { "Reserved", "sctp.parameter_add_incoming_streams_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4204 { &hf_asconf_seq_nr, { "Sequence number", "sctp.asconf_seq_nr_number", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4205 { &hf_asconf_ack_seq_nr, { "Sequence number", "sctp.asconf_ack_seq_nr_number", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4206 { &hf_correlation_id, { "Correlation_id", "sctp.correlation_id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4207 { &hf_adap_indication, { "Indication", "sctp.adapation_layer_indication", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
4208 { &hf_random_number, { "Random number", "sctp.random_number", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4209 { &hf_chunks_to_auth, { "Chunk type", "sctp.chunk_type_to_auth", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } },
4210 { &hf_hmac_id, { "HMAC identifier", "sctp.hmac_id", FT_UINT16, BASE_DEC, VALS(hmac_id_values), 0x0, NULL, HFILL } },
4211 { &hf_hmac, { "HMAC", "sctp.hmac", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4212 { &hf_shared_key_id, { "Shared key identifier", "sctp.shared_key_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4213 { &hf_supported_chunk_type, { "Supported chunk type", "sctp.supported_chunk_type", FT_UINT8, BASE_DEC, VALS(chunk_type_values), 0x0, NULL, HFILL } },
4214 { &hf_cause_code, { "Cause code", "sctp.cause_code", FT_UINT16, BASE_HEX, VALS(cause_code_values), 0x0, NULL, HFILL } },
4215 { &hf_cause_length, { "Cause length", "sctp.cause_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4216 { &hf_cause_info, { "Cause information", "sctp.cause_information", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4217 { &hf_cause_padding, { "Cause padding", "sctp.cause_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4218 { &hf_cause_stream_identifier, { "Stream identifier", "sctp.cause_stream_identifier", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4219 { &hf_cause_reserved, { "Reserved", "sctp.cause_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4220 { &hf_cause_number_of_missing_parameters, { "Number of missing parameters", "sctp.cause_nr_of_missing_parameters", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4221 { &hf_cause_missing_parameter_type, { "Missing parameter type", "sctp.cause_missing_parameter_type", FT_UINT16, BASE_HEX, VALS(parameter_identifier_values), 0x0, NULL, HFILL } },
4222 { &hf_cause_measure_of_staleness, { "Measure of staleness in usec", "sctp.cause_measure_of_staleness", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4223 { &hf_cause_tsn, { "TSN", "sctp.cause_tsn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4224 { &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 } },
4225 { &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 } },
4226 { &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 } },
4227 { &hf_pktdrop_chunk_bandwidth, { "Bandwidth", "sctp.pktdrop_bandwidth", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4228 { &hf_pktdrop_chunk_queuesize, { "Queuesize", "sctp.pktdrop_queuesize", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4229 { &hf_pktdrop_chunk_truncated_length, { "Truncated length", "sctp.pktdrop_truncated_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4230 { &hf_pktdrop_chunk_reserved, { "Reserved", "sctp.pktdrop_reserved", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4231 { &hf_pktdrop_chunk_data_field, { "Data field", "sctp.pktdrop_datafield", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4233 { &hf_sctp_fragment, { "SCTP Fragment", "sctp.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4234 { &hf_sctp_fragments, { "Reassembled SCTP Fragments", "sctp.fragments", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4235 { &hf_sctp_reassembled_in, { "Reassembled Message in frame", "sctp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4236 { &hf_sctp_duplicate, { "Fragment already seen in frame", "sctp.duplicate", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4238 { &hf_sctp_data_rtt, { "The RTT to SACK was", "sctp.data_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4239 { &hf_sctp_sack_rtt, { "The RTT since DATA was", "sctp.sack_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4240 { &hf_sctp_rto, { "Retransmitted after", "sctp.retransmission_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4241 { &hf_sctp_retransmission, { "This TSN is a retransmission of one in frame", "sctp.retransmission", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4242 { &hf_sctp_retransmitted, { "This TSN is retransmitted in frame", "sctp.retransmitted", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4243 { &hf_sctp_retransmitted_count, { "TSN was retransmitted this many times", "sctp.retransmitted_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4244 { &hf_sctp_acked, { "This chunk is acked in frame", "sctp.acked", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4245 { &hf_sctp_ack_tsn, { "Acknowledges TSN", "sctp.ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
4246 { &hf_sctp_ack_frame, { "Chunk acknowledged in frame", "sctp.ack_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
4247 { &hf_sctp_retransmitted_after_ack, { "Chunk was acked prior to retransmission", "sctp.retransmitted_after_ack", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }
4251 /* Setup protocol subtree array */
4252 static gint *ett[] = {
4253 &ett_sctp,
4254 &ett_sctp_chunk,
4255 &ett_sctp_chunk_parameter,
4256 &ett_sctp_chunk_cause,
4257 &ett_sctp_chunk_type,
4258 &ett_sctp_data_chunk_flags,
4259 &ett_sctp_sack_chunk_flags,
4260 &ett_sctp_nr_sack_chunk_flags,
4261 &ett_sctp_abort_chunk_flags,
4262 &ett_sctp_shutdown_complete_chunk_flags,
4263 &ett_sctp_pktdrop_chunk_flags,
4264 &ett_sctp_parameter_type,
4265 &ett_sctp_sack_chunk_gap_block,
4266 &ett_sctp_sack_chunk_gap_block_start,
4267 &ett_sctp_sack_chunk_gap_block_end,
4268 &ett_sctp_nr_sack_chunk_gap_block,
4269 &ett_sctp_nr_sack_chunk_gap_block_start,
4270 &ett_sctp_nr_sack_chunk_gap_block_end,
4271 &ett_sctp_nr_sack_chunk_nr_gap_block,
4272 &ett_sctp_nr_sack_chunk_nr_gap_block_start,
4273 &ett_sctp_nr_sack_chunk_nr_gap_block_end,
4274 &ett_sctp_unrecognized_parameter_parameter,
4275 &ett_sctp_fragments,
4276 &ett_sctp_fragment,
4277 &ett_sctp_ack,
4278 &ett_sctp_acked,
4279 &ett_sctp_tsn,
4280 &ett_sctp_tsn_retransmission,
4281 &ett_sctp_tsn_retransmitted_count,
4282 &ett_sctp_tsn_retransmitted
4285 static ei_register_info ei[] = {
4286 { &ei_sctp_tsn_retransmitted, { "sctp.retransmission.expert", PI_SEQUENCE, PI_NOTE, "Retransmitted TSN", EXPFILL }},
4287 { &ei_sctp_retransmitted_after_ack, { "retransmitted_after_ack.expert", PI_SEQUENCE, PI_WARN, "This TSN was acked prior to this retransmission (reneged ack?).", EXPFILL }},
4288 { &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 }},
4289 { &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 }},
4290 { &ei_sctp_parameter_length, { "sctp.parameter_length.bad", PI_MALFORMED, PI_ERROR, "Parameter length bad", EXPFILL }},
4291 { &ei_sctp_sack_chunk_adv_rec_window_credit, { "sctp.sack_a_rwnd.expert", PI_SEQUENCE, PI_NOTE, "Zero Advertised Receiver Window Credit", EXPFILL }},
4292 { &ei_sctp_sack_chunk_gap_block_malformed, { "sctp.sack_gap_block_malformed", PI_PROTOCOL, PI_ERROR, "Malformed gap block.", EXPFILL }},
4293 { &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 }},
4294 { &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 }},
4295 { &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 }},
4296 { &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 }},
4297 { &ei_sctp_chunk_length_bad, { "sctp.chunk_length.bad", PI_MALFORMED, PI_ERROR, "Chunk length bad", EXPFILL }},
4298 { &ei_sctp_bad_sctp_checksum, { "sctp.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad SCTP checksum.", EXPFILL }},
4301 static const enum_val_t sctp_checksum_options[] = {
4302 { "none", "None", SCTP_CHECKSUM_NONE },
4303 { "adler-32", "Adler 32", SCTP_CHECKSUM_ADLER32 },
4304 { "crc-32c", "CRC 32c", SCTP_CHECKSUM_CRC32C },
4305 { "automatic", "Automatic", SCTP_CHECKSUM_AUTOMATIC},
4306 { NULL, NULL, 0 }
4309 module_t *sctp_module;
4310 expert_module_t* expert_sctp;
4312 /* Register the protocol name and description */
4313 proto_sctp = proto_register_protocol("Stream Control Transmission Protocol", "SCTP", "sctp");
4314 sctp_module = prefs_register_protocol(proto_sctp, NULL);
4315 prefs_register_bool_preference(sctp_module, "show_port_numbers_in_tree",
4316 "Show port numbers in the protocol tree",
4317 "Show source and destination port numbers in the protocol tree",
4318 &show_port_numbers);
4319 /* FIXME
4320 prefs_register_bool_preference(sctp_module, "show_chunk_types_in_tree",
4321 "Show chunk types in the protocol tree",
4322 "Show chunk types in the protocol tree",
4323 &show_chunk_types);
4325 prefs_register_enum_preference(sctp_module, "checksum", "Checksum type",
4326 "The type of checksum used in SCTP packets",
4327 &sctp_checksum, sctp_checksum_options, FALSE);
4328 prefs_register_bool_preference(sctp_module, "show_always_control_chunks",
4329 "Show always control chunks",
4330 "Show always SCTP control chunks in the Info column",
4331 &show_always_control_chunks);
4332 prefs_register_bool_preference(sctp_module, "try_heuristic_first",
4333 "Try heuristic sub-dissectors first",
4334 "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port or PPI",
4335 &try_heuristic_first);
4336 prefs_register_bool_preference(sctp_module, "reassembly",
4337 "Reassemble fragmented SCTP user messages",
4338 "Whether fragmented SCTP user messages should be reassembled",
4339 &use_reassembly);
4340 prefs_register_bool_preference(sctp_module, "tsn_analysis",
4341 "Enable TSN analysis",
4342 "Match TSNs and their SACKs",
4343 &enable_tsn_analysis);
4344 prefs_register_bool_preference(sctp_module, "ulp_dissection",
4345 "Dissect upper layer protocols",
4346 "Dissect upper layer protocols",
4347 &enable_ulp_dissection);
4349 /* Required function calls to register the header fields and subtrees used */
4350 proto_register_field_array(proto_sctp, hf, array_length(hf));
4351 proto_register_subtree_array(ett, array_length(ett));
4352 expert_sctp = expert_register_protocol(proto_sctp);
4353 expert_register_field_array(expert_sctp, ei, array_length(ei));
4355 sctp_tap = register_tap("sctp");
4356 /* subdissector code */
4357 sctp_port_dissector_table = register_dissector_table("sctp.port", "SCTP port", FT_UINT16, BASE_DEC);
4358 sctp_ppi_dissector_table = register_dissector_table("sctp.ppi", "SCTP payload protocol identifier", FT_UINT32, BASE_HEX);
4360 register_dissector("sctp", dissect_sctp, proto_sctp);
4361 register_heur_dissector_list("sctp", &sctp_heur_subdissector_list);
4363 register_init_routine(frag_table_init);
4365 dirs_by_ptvtag = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
4366 dirs_by_ptaddr = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
4369 void
4370 proto_reg_handoff_sctp(void)
4372 dissector_handle_t sctp_handle;
4374 data_handle = find_dissector("data");
4375 sctp_handle = find_dissector("sctp");
4376 dissector_add_uint("wtap_encap", WTAP_ENCAP_SCTP, sctp_handle);
4377 dissector_add_uint("ip.proto", IP_PROTO_SCTP, sctp_handle);
4378 dissector_add_uint("udp.port", UDP_TUNNELING_PORT, sctp_handle);