xref: /netbsd-src/external/bsd/tcpdump/dist/print-sctp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
111b3aaa1Schristos /*
20f74e101Schristos  * Copyright (c) 2001 Protocol Engineering Lab, University of Delaware
30f74e101Schristos  *
40f74e101Schristos  * Jerry Heinz <gheinz@astro.temple.edu>
50f74e101Schristos  * John Fiore <jfiore@joda.cis.temple.edu>
60f74e101Schristos  * Armando L. Caro Jr. <acaro@cis.udel.edu>
70f74e101Schristos  *
80f74e101Schristos  * Redistribution and use in source and binary forms, with or without
90f74e101Schristos  * modification, are permitted provided that the following conditions
100f74e101Schristos  * are met:
110f74e101Schristos  *
120f74e101Schristos  * 1. Redistributions of source code must retain the above copyright
130f74e101Schristos  *    notice, this list of conditions and the following disclaimer.
140f74e101Schristos  *
150f74e101Schristos  * 2. Redistributions in binary form must reproduce the above copyright
160f74e101Schristos  *    notice, this list of conditions and the following disclaimer in the
170f74e101Schristos  *    documentation and/or other materials provided with the distribution.
180f74e101Schristos  *
190f74e101Schristos  * 3. Neither the name of the University nor of the Laboratory may be used
200f74e101Schristos  *    to endorse or promote products derived from this software without
210f74e101Schristos  *    specific prior written permission.
220f74e101Schristos  *
230f74e101Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
240f74e101Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
250f74e101Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
260f74e101Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
270f74e101Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
280f74e101Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
290f74e101Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
300f74e101Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
310f74e101Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
320f74e101Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
330f74e101Schristos  * SUCH DAMAGE.
340f74e101Schristos  */
350f74e101Schristos 
3611b3aaa1Schristos #include <sys/cdefs.h>
370f74e101Schristos #ifndef lint
38*26ba0b50Schristos __RCSID("$NetBSD: print-sctp.c,v 1.11 2024/09/02 16:15:33 christos Exp $");
390f74e101Schristos #endif
400f74e101Schristos 
41dc860a36Sspz /* \summary: Stream Control Transmission Protocol (SCTP) printer */
42dc860a36Sspz 
43c74ad251Schristos #include <config.h>
440f74e101Schristos 
45c74ad251Schristos #include "netdissect-stdinc.h"
460f74e101Schristos 
47fdccd7e4Schristos #include "netdissect.h"
480f74e101Schristos #include "addrtoname.h"
49fdccd7e4Schristos #include "extract.h"
500f74e101Schristos #include "ip.h"
510f74e101Schristos #include "ip6.h"
520f74e101Schristos 
53b3a00663Schristos /* Definitions from:
54b3a00663Schristos  *
55b3a00663Schristos  * SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola
56b3a00663Schristos  *
57b3a00663Schristos  * Redistribution and use in source and binary forms, with or without
58b3a00663Schristos  * modification, are permitted provided that the following conditions
59b3a00663Schristos  * are met:
60b3a00663Schristos  *
61b3a00663Schristos  * 1. Redistributions of source code must retain the above copyright
62b3a00663Schristos  *    notice, this list of conditions and the following disclaimer.
63b3a00663Schristos  *
64b3a00663Schristos  * 2. Redistributions in binary form must reproduce the above copyright
65b3a00663Schristos  *    notice, this list of conditions and the following disclaimer in the
66b3a00663Schristos  *    documentation and/or other materials provided with the distribution.
67b3a00663Schristos  *
68b3a00663Schristos  * 3. Neither the name of Cisco nor of Motorola may be used
69b3a00663Schristos  *    to endorse or promote products derived from this software without
70b3a00663Schristos  *    specific prior written permission.
71b3a00663Schristos  *
72b3a00663Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
73b3a00663Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
74b3a00663Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75b3a00663Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
76b3a00663Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
77b3a00663Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
78b3a00663Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
79b3a00663Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
80b3a00663Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
81b3a00663Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82b3a00663Schristos  * SUCH DAMAGE.
83b3a00663Schristos  *
84b3a00663Schristos  * This file is part of the SCTP reference Implementation
85b3a00663Schristos  *
86b3a00663Schristos  *
87b3a00663Schristos  * Please send any bug reports or fixes you make to one of the following email
88b3a00663Schristos  * addresses:
89b3a00663Schristos  *
90b3a00663Schristos  * rstewar1@email.mot.com
91b3a00663Schristos  * kmorneau@cisco.com
92b3a00663Schristos  * qxie1@email.mot.com
93b3a00663Schristos  *
94b3a00663Schristos  * Any bugs reported given to us we will try to fix... any fixes shared will
95c74ad251Schristos  * be incorporated into the next SCTP release.
96b3a00663Schristos  */
97b3a00663Schristos 
98b3a00663Schristos /* The valid defines for all message
99b3a00663Schristos  * types know to SCTP. 0 is reserved
100b3a00663Schristos  */
101b3a00663Schristos #define SCTP_DATA		0x00
102b3a00663Schristos #define SCTP_INITIATION		0x01
103b3a00663Schristos #define SCTP_INITIATION_ACK	0x02
104b3a00663Schristos #define SCTP_SELECTIVE_ACK	0x03
105b3a00663Schristos #define SCTP_HEARTBEAT_REQUEST	0x04
106b3a00663Schristos #define SCTP_HEARTBEAT_ACK	0x05
107b3a00663Schristos #define SCTP_ABORT_ASSOCIATION	0x06
108b3a00663Schristos #define SCTP_SHUTDOWN		0x07
109b3a00663Schristos #define SCTP_SHUTDOWN_ACK	0x08
110b3a00663Schristos #define SCTP_OPERATION_ERR	0x09
111b3a00663Schristos #define SCTP_COOKIE_ECHO	0x0a
112b3a00663Schristos #define SCTP_COOKIE_ACK         0x0b
113b3a00663Schristos #define SCTP_ECN_ECHO		0x0c
114b3a00663Schristos #define SCTP_ECN_CWR		0x0d
115b3a00663Schristos #define SCTP_SHUTDOWN_COMPLETE	0x0e
116b3a00663Schristos #define SCTP_FORWARD_CUM_TSN    0xc0
117b3a00663Schristos #define SCTP_RELIABLE_CNTL      0xc1
118b3a00663Schristos #define SCTP_RELIABLE_CNTL_ACK  0xc2
119b3a00663Schristos 
120b3a00663Schristos static const struct tok sctp_chunkid_str[] = {
121b3a00663Schristos 	{ SCTP_DATA,              "DATA"              },
122b3a00663Schristos 	{ SCTP_INITIATION,        "INIT"              },
123b3a00663Schristos 	{ SCTP_INITIATION_ACK,    "INIT ACK"          },
124b3a00663Schristos 	{ SCTP_SELECTIVE_ACK,     "SACK"              },
125b3a00663Schristos 	{ SCTP_HEARTBEAT_REQUEST, "HB REQ"            },
126b3a00663Schristos 	{ SCTP_HEARTBEAT_ACK,     "HB ACK"            },
127b3a00663Schristos 	{ SCTP_ABORT_ASSOCIATION, "ABORT"             },
128b3a00663Schristos 	{ SCTP_SHUTDOWN,          "SHUTDOWN"          },
129b3a00663Schristos 	{ SCTP_SHUTDOWN_ACK,      "SHUTDOWN ACK"      },
130b3a00663Schristos 	{ SCTP_OPERATION_ERR,     "OP ERR"            },
131b3a00663Schristos 	{ SCTP_COOKIE_ECHO,       "COOKIE ECHO"       },
132b3a00663Schristos 	{ SCTP_COOKIE_ACK,        "COOKIE ACK"        },
133b3a00663Schristos 	{ SCTP_ECN_ECHO,          "ECN ECHO"          },
134b3a00663Schristos 	{ SCTP_ECN_CWR,           "ECN CWR"           },
135b3a00663Schristos 	{ SCTP_SHUTDOWN_COMPLETE, "SHUTDOWN COMPLETE" },
136b3a00663Schristos 	{ SCTP_FORWARD_CUM_TSN,   "FOR CUM TSN"       },
137b3a00663Schristos 	{ SCTP_RELIABLE_CNTL,     "REL CTRL"          },
138b3a00663Schristos 	{ SCTP_RELIABLE_CNTL_ACK, "REL CTRL ACK"      },
139b3a00663Schristos 	{ 0, NULL }
140b3a00663Schristos };
141b3a00663Schristos 
142b3a00663Schristos /* Data Chuck Specific Flags */
143b3a00663Schristos #define SCTP_DATA_FRAG_MASK	0x03
144b3a00663Schristos #define SCTP_DATA_MIDDLE_FRAG	0x00
145b3a00663Schristos #define SCTP_DATA_LAST_FRAG	0x01
146b3a00663Schristos #define SCTP_DATA_FIRST_FRAG	0x02
147b3a00663Schristos #define SCTP_DATA_NOT_FRAG	0x03
148b3a00663Schristos #define SCTP_DATA_UNORDERED	0x04
149b3a00663Schristos 
150b3a00663Schristos #define SCTP_ADDRMAX 60
151b3a00663Schristos 
1520e9868baSchristos #define CHAN_HP 6704
1530e9868baSchristos #define CHAN_MP 6705
1540e9868baSchristos #define CHAN_LP 6706
1550f74e101Schristos 
156b3a00663Schristos /* the sctp common header */
157b3a00663Schristos 
158b3a00663Schristos struct sctpHeader{
159c74ad251Schristos   nd_uint16_t source;
160c74ad251Schristos   nd_uint16_t destination;
161c74ad251Schristos   nd_uint32_t verificationTag;
162c74ad251Schristos   nd_uint32_t adler32;
163b3a00663Schristos };
164b3a00663Schristos 
165b3a00663Schristos /* various descriptor parsers */
166b3a00663Schristos 
167b3a00663Schristos struct sctpChunkDesc{
168c74ad251Schristos   nd_uint8_t  chunkID;
169c74ad251Schristos   nd_uint8_t  chunkFlg;
170c74ad251Schristos   nd_uint16_t chunkLength;
171b3a00663Schristos };
172b3a00663Schristos 
173b3a00663Schristos struct sctpParamDesc{
174c74ad251Schristos   nd_uint16_t paramType;
175c74ad251Schristos   nd_uint16_t paramLength;
176b3a00663Schristos };
177b3a00663Schristos 
178b3a00663Schristos 
179b3a00663Schristos struct sctpRelChunkDesc{
180b3a00663Schristos   struct sctpChunkDesc chk;
181c74ad251Schristos   nd_uint32_t serialNumber;
182b3a00663Schristos };
183b3a00663Schristos 
184b3a00663Schristos struct sctpVendorSpecificParam {
185b3a00663Schristos   struct sctpParamDesc p;  /* type must be 0xfffe */
186c74ad251Schristos   nd_uint32_t vendorId;	   /* vendor ID from RFC 1700 */
187c74ad251Schristos   nd_uint16_t vendorSpecificType;
188c74ad251Schristos   nd_uint16_t vendorSpecificLen;
189b3a00663Schristos };
190b3a00663Schristos 
191b3a00663Schristos 
192b3a00663Schristos /* Structures for the control parts */
193b3a00663Schristos 
194b3a00663Schristos 
195b3a00663Schristos 
196b3a00663Schristos /* Sctp association init request/ack */
197b3a00663Schristos 
198b3a00663Schristos /* this is used for init ack, too */
199b3a00663Schristos struct sctpInitiation{
200c74ad251Schristos   nd_uint32_t initTag;			/* tag of mine */
201c74ad251Schristos   nd_uint32_t rcvWindowCredit;		/* rwnd */
202c74ad251Schristos   nd_uint16_t NumPreopenStreams;	/* OS */
203c74ad251Schristos   nd_uint16_t MaxInboundStreams;	/* MIS */
204c74ad251Schristos   nd_uint32_t initialTSN;
205b3a00663Schristos   /* optional param's follow in sctpParamDesc form */
206b3a00663Schristos };
207b3a00663Schristos 
208b3a00663Schristos struct sctpV4IpAddress{
209b3a00663Schristos   struct sctpParamDesc p;	/* type is set to SCTP_IPV4_PARAM_TYPE, len=10 */
210c74ad251Schristos   nd_ipv4  ipAddress;
211b3a00663Schristos };
212b3a00663Schristos 
213b3a00663Schristos 
214b3a00663Schristos struct sctpV6IpAddress{
215b3a00663Schristos   struct sctpParamDesc p;	/* type is set to SCTP_IPV6_PARAM_TYPE, len=22 */
216c74ad251Schristos   nd_ipv6  ipAddress;
217b3a00663Schristos };
218b3a00663Schristos 
219b3a00663Schristos struct sctpDNSName{
220b3a00663Schristos   struct sctpParamDesc param;
221c74ad251Schristos   nd_byte name[1];
222b3a00663Schristos };
223b3a00663Schristos 
224b3a00663Schristos 
225b3a00663Schristos struct sctpCookiePreserve{
226b3a00663Schristos   struct sctpParamDesc p;	/* type is set to SCTP_COOKIE_PRESERVE, len=8 */
227c74ad251Schristos   nd_uint32_t extraTime;
228b3a00663Schristos };
229b3a00663Schristos 
230b3a00663Schristos 
231b3a00663Schristos struct sctpTimeStamp{
232c74ad251Schristos   nd_uint32_t ts_sec;
233c74ad251Schristos   nd_uint32_t ts_usec;
234b3a00663Schristos };
235b3a00663Schristos 
236b3a00663Schristos 
237b3a00663Schristos /* this guy is for use when
238b3a00663Schristos  * I have a initiate message gloming the
239b3a00663Schristos  * things together.
240b3a00663Schristos 
241b3a00663Schristos  */
242b3a00663Schristos struct sctpUnifiedInit{
243b3a00663Schristos   struct sctpChunkDesc uh;
244b3a00663Schristos   struct sctpInitiation initm;
245b3a00663Schristos };
246b3a00663Schristos 
247b3a00663Schristos struct sctpSendableInit{
248b3a00663Schristos   struct sctpHeader mh;
249b3a00663Schristos   struct sctpUnifiedInit msg;
250b3a00663Schristos };
251b3a00663Schristos 
252b3a00663Schristos 
253b3a00663Schristos /* Selective Acknowledgement
254b3a00663Schristos  * has the following structure with
255c74ad251Schristos  * a optional amount of trailing int's
256b3a00663Schristos  * on the last part (based on the numberOfDesc
257b3a00663Schristos  * field).
258b3a00663Schristos  */
259b3a00663Schristos 
260b3a00663Schristos struct sctpSelectiveAck{
261c74ad251Schristos   nd_uint32_t highestConseqTSN;
262c74ad251Schristos   nd_uint32_t updatedRwnd;
263c74ad251Schristos   nd_uint16_t numberOfdesc;
264c74ad251Schristos   nd_uint16_t numDupTsns;
265b3a00663Schristos };
266b3a00663Schristos 
267b3a00663Schristos struct sctpSelectiveFrag{
268c74ad251Schristos   nd_uint16_t fragmentStart;
269c74ad251Schristos   nd_uint16_t fragmentEnd;
270b3a00663Schristos };
271b3a00663Schristos 
272b3a00663Schristos 
273b3a00663Schristos struct sctpUnifiedSack{
274b3a00663Schristos   struct sctpChunkDesc uh;
275b3a00663Schristos   struct sctpSelectiveAck sack;
276b3a00663Schristos };
277b3a00663Schristos 
278b3a00663Schristos /* for the abort and shutdown ACK
279b3a00663Schristos  * we must carry the init tag in the common header. Just the
280b3a00663Schristos  * common header is all that is needed with a chunk descriptor.
281b3a00663Schristos  */
282b3a00663Schristos struct sctpUnifiedAbort{
283b3a00663Schristos   struct sctpChunkDesc uh;
284b3a00663Schristos };
285b3a00663Schristos 
286b3a00663Schristos struct sctpUnifiedAbortLight{
287b3a00663Schristos   struct sctpHeader mh;
288b3a00663Schristos   struct sctpChunkDesc uh;
289b3a00663Schristos };
290b3a00663Schristos 
291b3a00663Schristos struct sctpUnifiedAbortHeavy{
292b3a00663Schristos   struct sctpHeader mh;
293b3a00663Schristos   struct sctpChunkDesc uh;
294c74ad251Schristos   nd_uint16_t causeCode;
295c74ad251Schristos   nd_uint16_t causeLen;
296b3a00663Schristos };
297b3a00663Schristos 
298b3a00663Schristos /* For the graceful shutdown we must carry
299*26ba0b50Schristos  * the tag (in common header)  and the highest consecutive acking value
300b3a00663Schristos  */
301b3a00663Schristos struct sctpShutdown {
302c74ad251Schristos   nd_uint32_t TSN_Seen;
303b3a00663Schristos };
304b3a00663Schristos 
305b3a00663Schristos struct sctpUnifiedShutdown{
306b3a00663Schristos   struct sctpChunkDesc uh;
307b3a00663Schristos   struct sctpShutdown shut;
308b3a00663Schristos };
309b3a00663Schristos 
310b3a00663Schristos /* in the unified message we add the trailing
311b3a00663Schristos  * stream id since it is the only message
312b3a00663Schristos  * that is defined as a operation error.
313b3a00663Schristos  */
314b3a00663Schristos struct sctpOpErrorCause{
315c74ad251Schristos   nd_uint16_t cause;
316c74ad251Schristos   nd_uint16_t causeLen;
317b3a00663Schristos };
318b3a00663Schristos 
319b3a00663Schristos struct sctpUnifiedOpError{
320b3a00663Schristos   struct sctpChunkDesc uh;
321b3a00663Schristos   struct sctpOpErrorCause c;
322b3a00663Schristos };
323b3a00663Schristos 
324b3a00663Schristos struct sctpUnifiedStreamError{
325b3a00663Schristos   struct sctpHeader mh;
326b3a00663Schristos   struct sctpChunkDesc uh;
327b3a00663Schristos   struct sctpOpErrorCause c;
328c74ad251Schristos   nd_uint16_t strmNum;
329c74ad251Schristos   nd_uint16_t reserved;
330b3a00663Schristos };
331b3a00663Schristos 
332b3a00663Schristos struct staleCookieMsg{
333b3a00663Schristos   struct sctpHeader mh;
334b3a00663Schristos   struct sctpChunkDesc uh;
335b3a00663Schristos   struct sctpOpErrorCause c;
336c74ad251Schristos   nd_uint32_t moretime;
337b3a00663Schristos };
338b3a00663Schristos 
339b3a00663Schristos /* the following is used in all sends
340b3a00663Schristos  * where nothing is needed except the
341b3a00663Schristos  * chunk/type i.e. shutdownAck Abort */
342b3a00663Schristos 
343b3a00663Schristos struct sctpUnifiedSingleMsg{
344b3a00663Schristos   struct sctpHeader mh;
345b3a00663Schristos   struct sctpChunkDesc uh;
346b3a00663Schristos };
347b3a00663Schristos 
348b3a00663Schristos struct sctpDataPart{
349c74ad251Schristos   nd_uint32_t TSN;
350c74ad251Schristos   nd_uint16_t streamId;
351c74ad251Schristos   nd_uint16_t sequence;
352c74ad251Schristos   nd_uint32_t payloadtype;
353b3a00663Schristos };
354b3a00663Schristos 
355b3a00663Schristos struct sctpUnifiedDatagram{
356b3a00663Schristos   struct sctpChunkDesc uh;
357b3a00663Schristos   struct sctpDataPart dp;
358b3a00663Schristos };
359b3a00663Schristos 
360b3a00663Schristos struct sctpECN_echo{
361b3a00663Schristos   struct sctpChunkDesc uh;
362c74ad251Schristos   nd_uint32_t Lowest_TSN;
363b3a00663Schristos };
364b3a00663Schristos 
365b3a00663Schristos 
366b3a00663Schristos struct sctpCWR{
367b3a00663Schristos   struct sctpChunkDesc uh;
368c74ad251Schristos   nd_uint32_t TSN_reduced_at;
369b3a00663Schristos };
370b3a00663Schristos 
371870189d2Schristos static const struct tok ForCES_channels[] = {
3720f74e101Schristos 	{ CHAN_HP, "ForCES HP" },
3730f74e101Schristos 	{ CHAN_MP, "ForCES MP" },
3740f74e101Schristos 	{ CHAN_LP, "ForCES LP" },
3750f74e101Schristos 	{ 0, NULL }
3760f74e101Schristos };
3770f74e101Schristos 
378b3a00663Schristos /* data chunk's payload protocol identifiers */
379b3a00663Schristos 
380b3a00663Schristos #define SCTP_PPID_IUA 1
381b3a00663Schristos #define SCTP_PPID_M2UA 2
382b3a00663Schristos #define SCTP_PPID_M3UA 3
383b3a00663Schristos #define SCTP_PPID_SUA 4
384b3a00663Schristos #define SCTP_PPID_M2PA 5
385b3a00663Schristos #define SCTP_PPID_V5UA 6
386b3a00663Schristos #define SCTP_PPID_H248 7
387b3a00663Schristos #define SCTP_PPID_BICC 8
388b3a00663Schristos #define SCTP_PPID_TALI 9
389b3a00663Schristos #define SCTP_PPID_DUA 10
390b3a00663Schristos #define SCTP_PPID_ASAP 11
391b3a00663Schristos #define SCTP_PPID_ENRP 12
392b3a00663Schristos #define SCTP_PPID_H323 13
393b3a00663Schristos #define SCTP_PPID_QIPC 14
394b3a00663Schristos #define SCTP_PPID_SIMCO 15
395b3a00663Schristos #define SCTP_PPID_DDPSC 16
396b3a00663Schristos #define SCTP_PPID_DDPSSC 17
397b3a00663Schristos #define SCTP_PPID_S1AP 18
398b3a00663Schristos #define SCTP_PPID_RUA 19
399b3a00663Schristos #define SCTP_PPID_HNBAP 20
400b3a00663Schristos #define SCTP_PPID_FORCES_HP 21
401b3a00663Schristos #define SCTP_PPID_FORCES_MP 22
402b3a00663Schristos #define SCTP_PPID_FORCES_LP 23
403b3a00663Schristos #define SCTP_PPID_SBC_AP 24
404b3a00663Schristos #define SCTP_PPID_NBAP 25
405b3a00663Schristos /* 26 */
406b3a00663Schristos #define SCTP_PPID_X2AP 27
407b3a00663Schristos 
408b3a00663Schristos static const struct tok PayloadProto_idents[] = {
409b3a00663Schristos 	{ SCTP_PPID_IUA,    "ISDN Q.921" },
410b3a00663Schristos 	{ SCTP_PPID_M2UA,   "M2UA"   },
411b3a00663Schristos 	{ SCTP_PPID_M3UA,   "M3UA"   },
412b3a00663Schristos 	{ SCTP_PPID_SUA,    "SUA"    },
413b3a00663Schristos 	{ SCTP_PPID_M2PA,   "M2PA"   },
414b3a00663Schristos 	{ SCTP_PPID_V5UA,   "V5.2"   },
415b3a00663Schristos 	{ SCTP_PPID_H248,   "H.248"  },
416b3a00663Schristos 	{ SCTP_PPID_BICC,   "BICC"   },
417b3a00663Schristos 	{ SCTP_PPID_TALI,   "TALI"   },
418b3a00663Schristos 	{ SCTP_PPID_DUA,    "DUA"    },
419b3a00663Schristos 	{ SCTP_PPID_ASAP,   "ASAP"   },
420b3a00663Schristos 	{ SCTP_PPID_ENRP,   "ENRP"   },
421b3a00663Schristos 	{ SCTP_PPID_H323,   "H.323"  },
422b3a00663Schristos 	{ SCTP_PPID_QIPC,   "Q.IPC"  },
423b3a00663Schristos 	{ SCTP_PPID_SIMCO,  "SIMCO"  },
424b3a00663Schristos 	{ SCTP_PPID_DDPSC,  "DDPSC"  },
425b3a00663Schristos 	{ SCTP_PPID_DDPSSC, "DDPSSC" },
426b3a00663Schristos 	{ SCTP_PPID_S1AP,   "S1AP"   },
427b3a00663Schristos 	{ SCTP_PPID_RUA,    "RUA"    },
428b3a00663Schristos 	{ SCTP_PPID_HNBAP,  "HNBAP"  },
429b3a00663Schristos 	{ SCTP_PPID_FORCES_HP, "ForCES HP" },
430b3a00663Schristos 	{ SCTP_PPID_FORCES_MP, "ForCES MP" },
431b3a00663Schristos 	{ SCTP_PPID_FORCES_LP, "ForCES LP" },
432b3a00663Schristos 	{ SCTP_PPID_SBC_AP, "SBc-AP" },
433b3a00663Schristos 	{ SCTP_PPID_NBAP,   "NBAP"   },
434b3a00663Schristos 	/* 26 */
435b3a00663Schristos 	{ SCTP_PPID_X2AP,   "X2AP"   },
436b3a00663Schristos 	{ 0, NULL }
437b3a00663Schristos };
438b3a00663Schristos 
439b3a00663Schristos 
440c74ad251Schristos static int
441c74ad251Schristos isForCES_port(u_short Port)
4420f74e101Schristos {
4430f74e101Schristos 	if (Port == CHAN_HP)
4440f74e101Schristos 		return 1;
4450f74e101Schristos 	if (Port == CHAN_MP)
4460f74e101Schristos 		return 1;
4470f74e101Schristos 	if (Port == CHAN_LP)
4480f74e101Schristos 		return 1;
4490f74e101Schristos 
4500f74e101Schristos 	return 0;
4510f74e101Schristos }
4520f74e101Schristos 
453c74ad251Schristos void
454c74ad251Schristos sctp_print(netdissect_options *ndo,
455b3a00663Schristos 	   const u_char *bp,        /* beginning of sctp packet */
4560f74e101Schristos 	   const u_char *bp2,       /* beginning of enclosing */
4570f74e101Schristos 	   u_int sctpPacketLength)  /* ip packet */
4580f74e101Schristos {
459fdccd7e4Schristos   u_int sctpPacketLengthRemaining;
4600f74e101Schristos   const struct sctpHeader *sctpPktHdr;
4610f74e101Schristos   const struct ip *ip;
4620f74e101Schristos   const struct ip6_hdr *ip6;
463c74ad251Schristos   uint8_t chunkID;
4640f74e101Schristos   u_short sourcePort, destPort;
465c74ad251Schristos   u_int chunkCount;
4660f74e101Schristos   const struct sctpChunkDesc *chunkDescPtr;
4670f74e101Schristos   const char *sep;
4680f74e101Schristos   int isforces = 0;
4690f74e101Schristos 
470c74ad251Schristos   ndo->ndo_protocol = "sctp";
4710f74e101Schristos   if (sctpPacketLength < sizeof(struct sctpHeader))
4720f74e101Schristos     {
473c74ad251Schristos       ND_PRINT("truncated-sctp - %zu bytes missing!",
474c74ad251Schristos                sizeof(struct sctpHeader) - sctpPacketLength);
4750f74e101Schristos       return;
4760f74e101Schristos     }
477fdccd7e4Schristos   sctpPktHdr = (const struct sctpHeader*) bp;
478c74ad251Schristos   ND_TCHECK_SIZE(sctpPktHdr);
479fdccd7e4Schristos   sctpPacketLengthRemaining = sctpPacketLength;
4800f74e101Schristos 
481c74ad251Schristos   sourcePort = GET_BE_U_2(sctpPktHdr->source);
482c74ad251Schristos   destPort = GET_BE_U_2(sctpPktHdr->destination);
4830f74e101Schristos 
484fdccd7e4Schristos   ip = (const struct ip *)bp2;
485fdccd7e4Schristos   if (IP_V(ip) == 6)
486fdccd7e4Schristos     ip6 = (const struct ip6_hdr *)bp2;
487fdccd7e4Schristos   else
488fdccd7e4Schristos     ip6 = NULL;
489fdccd7e4Schristos 
4900f74e101Schristos   if (ip6) {
491c74ad251Schristos     ND_PRINT("%s.%u > %s.%u: sctp",
492c74ad251Schristos       GET_IP6ADDR_STRING(ip6->ip6_src),
4930f74e101Schristos       sourcePort,
494c74ad251Schristos       GET_IP6ADDR_STRING(ip6->ip6_dst),
495c74ad251Schristos       destPort);
496c74ad251Schristos   } else {
497c74ad251Schristos     ND_PRINT("%s.%u > %s.%u: sctp",
498c74ad251Schristos       GET_IPADDR_STRING(ip->ip_src),
4990f74e101Schristos       sourcePort,
500c74ad251Schristos       GET_IPADDR_STRING(ip->ip_dst),
501c74ad251Schristos       destPort);
5020f74e101Schristos   }
5030f74e101Schristos 
5040f74e101Schristos   if (isForCES_port(sourcePort)) {
505c74ad251Schristos 	 ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, sourcePort));
5060f74e101Schristos 	 isforces = 1;
5070f74e101Schristos   }
5080f74e101Schristos   if (isForCES_port(destPort)) {
509c74ad251Schristos 	 ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, destPort));
5100f74e101Schristos 	 isforces = 1;
5110f74e101Schristos   }
5120f74e101Schristos 
513fdccd7e4Schristos   bp += sizeof(struct sctpHeader);
514fdccd7e4Schristos   sctpPacketLengthRemaining -= sizeof(struct sctpHeader);
515fdccd7e4Schristos 
516b3a00663Schristos   if (ndo->ndo_vflag >= 2)
5170f74e101Schristos     sep = "\n\t";
5180f74e101Schristos   else
5190f74e101Schristos     sep = " (";
5200f74e101Schristos   /* cycle through all chunks, printing information on each one */
521fdccd7e4Schristos   for (chunkCount = 0, chunkDescPtr = (const struct sctpChunkDesc *)bp;
522fdccd7e4Schristos       sctpPacketLengthRemaining != 0;
523fdccd7e4Schristos       chunkCount++)
5240f74e101Schristos     {
525fdccd7e4Schristos       uint16_t chunkLength, chunkLengthRemaining;
526b3a00663Schristos       uint16_t align;
5270f74e101Schristos 
528fdccd7e4Schristos       chunkDescPtr = (const struct sctpChunkDesc *)bp;
529fdccd7e4Schristos       if (sctpPacketLengthRemaining < sizeof(*chunkDescPtr)) {
530c74ad251Schristos 	ND_PRINT("%s%u) [chunk descriptor cut off at end of packet]", sep, chunkCount+1);
531fdccd7e4Schristos 	break;
532fdccd7e4Schristos       }
533c74ad251Schristos       ND_TCHECK_SIZE(chunkDescPtr);
534c74ad251Schristos       chunkLength = GET_BE_U_2(chunkDescPtr->chunkLength);
5350f74e101Schristos       if (chunkLength < sizeof(*chunkDescPtr)) {
536c74ad251Schristos 	ND_PRINT("%s%u) [Bad chunk length %u, < size of chunk descriptor]", sep, chunkCount+1, chunkLength);
5370f74e101Schristos 	break;
5380f74e101Schristos       }
539fdccd7e4Schristos       chunkLengthRemaining = chunkLength;
5400f74e101Schristos 
5410f74e101Schristos       align = chunkLength % 4;
5420f74e101Schristos       if (align != 0)
5430f74e101Schristos 	align = 4 - align;
5440f74e101Schristos 
545fdccd7e4Schristos       if (sctpPacketLengthRemaining < align) {
546c74ad251Schristos 	ND_PRINT("%s%u) [Bad chunk length %u, > remaining data in packet]", sep, chunkCount+1, chunkLength);
547fdccd7e4Schristos 	break;
548fdccd7e4Schristos       }
549fdccd7e4Schristos 
550c74ad251Schristos       ND_TCHECK_LEN(bp, chunkLength);
551fdccd7e4Schristos 
552fdccd7e4Schristos       bp += sizeof(*chunkDescPtr);
553fdccd7e4Schristos       sctpPacketLengthRemaining -= sizeof(*chunkDescPtr);
554fdccd7e4Schristos       chunkLengthRemaining -= sizeof(*chunkDescPtr);
5550f74e101Schristos 
556c74ad251Schristos       ND_PRINT("%s%u) ", sep, chunkCount+1);
557c74ad251Schristos       chunkID = GET_U_1(chunkDescPtr->chunkID);
558c74ad251Schristos       ND_PRINT("[%s] ", tok2str(sctp_chunkid_str, "Unknown chunk type: 0x%x",
559c74ad251Schristos 	       chunkID));
560*26ba0b50Schristos       switch (chunkID) {
5610f74e101Schristos 	case SCTP_DATA :
5620f74e101Schristos 	  {
5630f74e101Schristos 	    const struct sctpDataPart *dataHdrPtr;
564c74ad251Schristos 	    uint8_t chunkFlg;
565b3a00663Schristos 	    uint32_t ppid;
566c74ad251Schristos 	    uint16_t payload_size;
5670f74e101Schristos 
568c74ad251Schristos 	    chunkFlg = GET_U_1(chunkDescPtr->chunkFlg);
569c74ad251Schristos 	    if ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED)
570c74ad251Schristos 	      ND_PRINT("(U)");
5710f74e101Schristos 
572c74ad251Schristos 	    if ((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG)
573c74ad251Schristos 	      ND_PRINT("(B)");
5740f74e101Schristos 
575c74ad251Schristos 	    if ((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG)
576c74ad251Schristos 	      ND_PRINT("(E)");
5770f74e101Schristos 
578c74ad251Schristos 	    if( ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) ||
579c74ad251Schristos 		((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) ||
580c74ad251Schristos 		((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) )
581c74ad251Schristos 	      ND_PRINT(" ");
5820f74e101Schristos 
583fdccd7e4Schristos 	    if (chunkLengthRemaining < sizeof(*dataHdrPtr)) {
584c74ad251Schristos 		ND_PRINT("bogus chunk length %u]", chunkLength);
585fdccd7e4Schristos 		return;
586fdccd7e4Schristos 	    }
587fdccd7e4Schristos 	    dataHdrPtr=(const struct sctpDataPart*)bp;
5880f74e101Schristos 
589c74ad251Schristos 	    ppid = GET_BE_U_4(dataHdrPtr->payloadtype);
590c74ad251Schristos 	    ND_PRINT("[TSN: %u] ", GET_BE_U_4(dataHdrPtr->TSN));
591c74ad251Schristos 	    ND_PRINT("[SID: %u] ", GET_BE_U_2(dataHdrPtr->streamId));
592c74ad251Schristos 	    ND_PRINT("[SSEQ %u] ", GET_BE_U_2(dataHdrPtr->sequence));
593c74ad251Schristos 	    ND_PRINT("[PPID %s] ",
594c74ad251Schristos 		    tok2str(PayloadProto_idents, "0x%x", ppid));
595b3a00663Schristos 
596b3a00663Schristos 	    if (!isforces) {
597b3a00663Schristos 		isforces = (ppid == SCTP_PPID_FORCES_HP) ||
598b3a00663Schristos 		    (ppid == SCTP_PPID_FORCES_MP) ||
599b3a00663Schristos 		    (ppid == SCTP_PPID_FORCES_LP);
600b3a00663Schristos 	    }
601b3a00663Schristos 
602fdccd7e4Schristos 	    bp += sizeof(*dataHdrPtr);
603fdccd7e4Schristos 	    sctpPacketLengthRemaining -= sizeof(*dataHdrPtr);
604fdccd7e4Schristos 	    chunkLengthRemaining -= sizeof(*dataHdrPtr);
605fdccd7e4Schristos 	    payload_size = chunkLengthRemaining;
606fdccd7e4Schristos 	    if (payload_size == 0) {
607c74ad251Schristos 		ND_PRINT("bogus chunk length %u]", chunkLength);
6080f74e101Schristos 		return;
6090f74e101Schristos 	    }
6100f74e101Schristos 
611b3a00663Schristos 	    if (isforces) {
612fdccd7e4Schristos 		forces_print(ndo, bp, payload_size);
613c74ad251Schristos 		/* ndo_protocol reassignment after forces_print() call */
614c74ad251Schristos 		ndo->ndo_protocol = "sctp";
615b3a00663Schristos 	    } else if (ndo->ndo_vflag >= 2) {	/* if verbose output is specified */
6160f74e101Schristos 					/* at the command line */
617b3a00663Schristos 		switch (ppid) {
618b3a00663Schristos 		case SCTP_PPID_M3UA :
619fdccd7e4Schristos 			m3ua_print(ndo, bp, payload_size);
620c74ad251Schristos 			/* ndo_protocol reassignment after m3ua_print() call */
621c74ad251Schristos 			ndo->ndo_protocol = "sctp";
622b3a00663Schristos 			break;
623b3a00663Schristos 		default:
624c74ad251Schristos 			ND_PRINT("[Payload");
625b3a00663Schristos 			if (!ndo->ndo_suppress_default_print) {
626c74ad251Schristos 				ND_PRINT(":");
627fdccd7e4Schristos 				ND_DEFAULTPRINT(bp, payload_size);
6280f74e101Schristos 			}
629c74ad251Schristos 			ND_PRINT("]");
630b3a00663Schristos 			break;
631b3a00663Schristos 		}
6320f74e101Schristos 	    }
633fdccd7e4Schristos 	    bp += payload_size;
634fdccd7e4Schristos 	    sctpPacketLengthRemaining -= payload_size;
635fdccd7e4Schristos 	    chunkLengthRemaining -= payload_size;
6360f74e101Schristos 	    break;
6370f74e101Schristos 	  }
6380f74e101Schristos 	case SCTP_INITIATION :
6390f74e101Schristos 	  {
6400f74e101Schristos 	    const struct sctpInitiation *init;
6410f74e101Schristos 
642fdccd7e4Schristos 	    if (chunkLengthRemaining < sizeof(*init)) {
643c74ad251Schristos 		ND_PRINT("bogus chunk length %u]", chunkLength);
644fdccd7e4Schristos 		return;
645fdccd7e4Schristos 	    }
646fdccd7e4Schristos 	    init=(const struct sctpInitiation*)bp;
647c74ad251Schristos 	    ND_PRINT("[init tag: %u] ", GET_BE_U_4(init->initTag));
648c74ad251Schristos 	    ND_PRINT("[rwnd: %u] ", GET_BE_U_4(init->rcvWindowCredit));
649c74ad251Schristos 	    ND_PRINT("[OS: %u] ", GET_BE_U_2(init->NumPreopenStreams));
650c74ad251Schristos 	    ND_PRINT("[MIS: %u] ", GET_BE_U_2(init->MaxInboundStreams));
651c74ad251Schristos 	    ND_PRINT("[init TSN: %u] ", GET_BE_U_4(init->initialTSN));
652fdccd7e4Schristos 	    bp += sizeof(*init);
653fdccd7e4Schristos 	    sctpPacketLengthRemaining -= sizeof(*init);
654fdccd7e4Schristos 	    chunkLengthRemaining -= sizeof(*init);
6550f74e101Schristos 
656dc860a36Sspz #if 0 /* ALC you can add code for optional params here */
657fdccd7e4Schristos 	    if( chunkLengthRemaining != 0 )
658c74ad251Schristos 	      ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n",
659c74ad251Schristos 		     "Optional params present, but not printed.");
6600f74e101Schristos #endif
661fdccd7e4Schristos 	    bp += chunkLengthRemaining;
662fdccd7e4Schristos 	    sctpPacketLengthRemaining -= chunkLengthRemaining;
663fdccd7e4Schristos 	    chunkLengthRemaining = 0;
6640f74e101Schristos 	    break;
6650f74e101Schristos 	  }
6660f74e101Schristos 	case SCTP_INITIATION_ACK :
6670f74e101Schristos 	  {
6680f74e101Schristos 	    const struct sctpInitiation *init;
6690f74e101Schristos 
670fdccd7e4Schristos 	    if (chunkLengthRemaining < sizeof(*init)) {
671c74ad251Schristos 		ND_PRINT("bogus chunk length %u]", chunkLength);
672fdccd7e4Schristos 		return;
673fdccd7e4Schristos 	    }
674fdccd7e4Schristos 	    init=(const struct sctpInitiation*)bp;
675c74ad251Schristos 	    ND_PRINT("[init tag: %u] ", GET_BE_U_4(init->initTag));
676c74ad251Schristos 	    ND_PRINT("[rwnd: %u] ", GET_BE_U_4(init->rcvWindowCredit));
677c74ad251Schristos 	    ND_PRINT("[OS: %u] ", GET_BE_U_2(init->NumPreopenStreams));
678c74ad251Schristos 	    ND_PRINT("[MIS: %u] ", GET_BE_U_2(init->MaxInboundStreams));
679c74ad251Schristos 	    ND_PRINT("[init TSN: %u] ", GET_BE_U_4(init->initialTSN));
680fdccd7e4Schristos 	    bp += sizeof(*init);
681fdccd7e4Schristos 	    sctpPacketLengthRemaining -= sizeof(*init);
682fdccd7e4Schristos 	    chunkLengthRemaining -= sizeof(*init);
6830f74e101Schristos 
684dc860a36Sspz #if 0 /* ALC you can add code for optional params here */
685fdccd7e4Schristos 	    if( chunkLengthRemaining != 0 )
686c74ad251Schristos 	      ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n",
687c74ad251Schristos 		     "Optional params present, but not printed.");
6880f74e101Schristos #endif
689fdccd7e4Schristos 	    bp += chunkLengthRemaining;
690fdccd7e4Schristos 	    sctpPacketLengthRemaining -= chunkLengthRemaining;
691fdccd7e4Schristos 	    chunkLengthRemaining = 0;
6920f74e101Schristos 	    break;
6930f74e101Schristos 	  }
6940f74e101Schristos 	case SCTP_SELECTIVE_ACK:
6950f74e101Schristos 	  {
6960f74e101Schristos 	    const struct sctpSelectiveAck *sack;
6970f74e101Schristos 	    const struct sctpSelectiveFrag *frag;
698c74ad251Schristos 	    u_int fragNo, tsnNo;
6990f74e101Schristos 	    const u_char *dupTSN;
7000f74e101Schristos 
701fdccd7e4Schristos 	    if (chunkLengthRemaining < sizeof(*sack)) {
702c74ad251Schristos 	      ND_PRINT("bogus chunk length %u]", chunkLength);
703fdccd7e4Schristos 	      return;
704fdccd7e4Schristos 	    }
705fdccd7e4Schristos 	    sack=(const struct sctpSelectiveAck*)bp;
706c74ad251Schristos 	    ND_PRINT("[cum ack %u] ", GET_BE_U_4(sack->highestConseqTSN));
707c74ad251Schristos 	    ND_PRINT("[a_rwnd %u] ", GET_BE_U_4(sack->updatedRwnd));
708c74ad251Schristos 	    ND_PRINT("[#gap acks %u] ", GET_BE_U_2(sack->numberOfdesc));
709c74ad251Schristos 	    ND_PRINT("[#dup tsns %u] ", GET_BE_U_2(sack->numDupTsns));
710fdccd7e4Schristos 	    bp += sizeof(*sack);
711fdccd7e4Schristos 	    sctpPacketLengthRemaining -= sizeof(*sack);
712fdccd7e4Schristos 	    chunkLengthRemaining -= sizeof(*sack);
7130f74e101Schristos 
7140f74e101Schristos 
7150f74e101Schristos 	    /* print gaps */
716fdccd7e4Schristos 	    for (fragNo=0;
717c74ad251Schristos 		 chunkLengthRemaining != 0 && fragNo < GET_BE_U_2(sack->numberOfdesc);
718fdccd7e4Schristos 		 bp += sizeof(*frag), sctpPacketLengthRemaining -= sizeof(*frag), chunkLengthRemaining -= sizeof(*frag), fragNo++) {
719fdccd7e4Schristos 	      if (chunkLengthRemaining < sizeof(*frag)) {
720c74ad251Schristos 		ND_PRINT("bogus chunk length %u]", chunkLength);
721fdccd7e4Schristos 		return;
722fdccd7e4Schristos 	      }
723fdccd7e4Schristos 	      frag = (const struct sctpSelectiveFrag *)bp;
724c74ad251Schristos 	      ND_PRINT("\n\t\t[gap ack block #%u: start = %u, end = %u] ",
7250f74e101Schristos 		     fragNo+1,
726c74ad251Schristos 		     GET_BE_U_4(sack->highestConseqTSN) + GET_BE_U_2(frag->fragmentStart),
727c74ad251Schristos 		     GET_BE_U_4(sack->highestConseqTSN) + GET_BE_U_2(frag->fragmentEnd));
728fdccd7e4Schristos 	    }
7290f74e101Schristos 
7300f74e101Schristos 	    /* print duplicate TSNs */
731fdccd7e4Schristos 	    for (tsnNo=0;
732c74ad251Schristos 		 chunkLengthRemaining != 0 && tsnNo<GET_BE_U_2(sack->numDupTsns);
733fdccd7e4Schristos 		 bp += 4, sctpPacketLengthRemaining -= 4, chunkLengthRemaining -= 4, tsnNo++) {
734fdccd7e4Schristos 	      if (chunkLengthRemaining < 4) {
735c74ad251Schristos 		ND_PRINT("bogus chunk length %u]", chunkLength);
736fdccd7e4Schristos 		return;
737fdccd7e4Schristos 	      }
738fdccd7e4Schristos 	      dupTSN = (const u_char *)bp;
739c74ad251Schristos 	      ND_PRINT("\n\t\t[dup TSN #%u: %u] ", tsnNo+1,
740c74ad251Schristos 		       GET_BE_U_4(dupTSN));
741fdccd7e4Schristos 	    }
742fdccd7e4Schristos 	    break;
743fdccd7e4Schristos 	  }
744fdccd7e4Schristos 	default :
745fdccd7e4Schristos 	  {
746fdccd7e4Schristos 	    bp += chunkLengthRemaining;
747fdccd7e4Schristos 	    sctpPacketLengthRemaining -= chunkLengthRemaining;
748fdccd7e4Schristos 	    chunkLengthRemaining = 0;
7490f74e101Schristos 	    break;
7500f74e101Schristos 	  }
7510f74e101Schristos 	}
7520f74e101Schristos 
753fdccd7e4Schristos       /*
754fdccd7e4Schristos        * Any extra stuff at the end of the chunk?
755fdccd7e4Schristos        * XXX - report this?
756fdccd7e4Schristos        */
757fdccd7e4Schristos       bp += chunkLengthRemaining;
758fdccd7e4Schristos       sctpPacketLengthRemaining -= chunkLengthRemaining;
759fdccd7e4Schristos 
760b3a00663Schristos       if (ndo->ndo_vflag < 2)
7610f74e101Schristos 	sep = ", (";
762fdccd7e4Schristos 
763fdccd7e4Schristos       if (align != 0) {
764fdccd7e4Schristos 	/*
765fdccd7e4Schristos 	 * Fail if the alignment padding isn't in the captured data.
766fdccd7e4Schristos 	 * Otherwise, skip it.
767fdccd7e4Schristos 	 */
768c74ad251Schristos 	ND_TCHECK_LEN(bp, align);
769fdccd7e4Schristos 	bp += align;
770fdccd7e4Schristos 	sctpPacketLengthRemaining -= align;
771fdccd7e4Schristos       }
7720f74e101Schristos     }
7730f74e101Schristos     return;
7740f74e101Schristos 
7750f74e101Schristos trunc:
776c74ad251Schristos     nd_print_trunc(ndo);
7770f74e101Schristos }
778