xref: /freebsd/contrib/tcpdump/print-sctp.c (revision ee67461e)
1a90e161bSBill Fenner /* Copyright (c) 2001 NETLAB, Temple University
2a90e161bSBill Fenner  * Copyright (c) 2001 Protocol Engineering Lab, University of Delaware
3a90e161bSBill Fenner  *
4a90e161bSBill Fenner  * Jerry Heinz <gheinz@astro.temple.edu>
5a90e161bSBill Fenner  * John Fiore <jfiore@joda.cis.temple.edu>
6a90e161bSBill Fenner  * Armando L. Caro Jr. <acaro@cis.udel.edu>
7a90e161bSBill Fenner  *
8a90e161bSBill Fenner  * Redistribution and use in source and binary forms, with or without
9a90e161bSBill Fenner  * modification, are permitted provided that the following conditions
10a90e161bSBill Fenner  * are met:
11a90e161bSBill Fenner  *
12a90e161bSBill Fenner  * 1. Redistributions of source code must retain the above copyright
13a90e161bSBill Fenner  *    notice, this list of conditions and the following disclaimer.
14a90e161bSBill Fenner  *
15a90e161bSBill Fenner  * 2. Redistributions in binary form must reproduce the above copyright
16a90e161bSBill Fenner  *    notice, this list of conditions and the following disclaimer in the
17a90e161bSBill Fenner  *    documentation and/or other materials provided with the distribution.
18a90e161bSBill Fenner  *
19a90e161bSBill Fenner  * 3. Neither the name of the University nor of the Laboratory may be used
20a90e161bSBill Fenner  *    to endorse or promote products derived from this software without
21a90e161bSBill Fenner  *    specific prior written permission.
22a90e161bSBill Fenner  *
23a90e161bSBill Fenner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24a90e161bSBill Fenner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25a90e161bSBill Fenner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26a90e161bSBill Fenner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27a90e161bSBill Fenner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28a90e161bSBill Fenner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29a90e161bSBill Fenner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30a90e161bSBill Fenner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31a90e161bSBill Fenner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32a90e161bSBill Fenner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33a90e161bSBill Fenner  * SUCH DAMAGE.
34a90e161bSBill Fenner  */
35a90e161bSBill Fenner 
363340d773SGleb Smirnoff /* \summary: Stream Control Transmission Protocol (SCTP) printer */
373340d773SGleb Smirnoff 
38a90e161bSBill Fenner #ifdef HAVE_CONFIG_H
39ee67461eSJoseph Mingrone #include <config.h>
40a90e161bSBill Fenner #endif
41a90e161bSBill Fenner 
42ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
43a90e161bSBill Fenner 
443340d773SGleb Smirnoff #include "netdissect.h"
45a90e161bSBill Fenner #include "addrtoname.h"
463340d773SGleb Smirnoff #include "extract.h"
47a90e161bSBill Fenner #include "ip.h"
48a90e161bSBill Fenner #include "ip6.h"
49a90e161bSBill Fenner 
503c602fabSXin LI /* Definitions from:
513c602fabSXin LI  *
523c602fabSXin LI  * SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola
533c602fabSXin LI  *
543c602fabSXin LI  * Redistribution and use in source and binary forms, with or without
553c602fabSXin LI  * modification, are permitted provided that the following conditions
563c602fabSXin LI  * are met:
573c602fabSXin LI  *
583c602fabSXin LI  * 1. Redistributions of source code must retain the above copyright
593c602fabSXin LI  *    notice, this list of conditions and the following disclaimer.
603c602fabSXin LI  *
613c602fabSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
623c602fabSXin LI  *    notice, this list of conditions and the following disclaimer in the
633c602fabSXin LI  *    documentation and/or other materials provided with the distribution.
643c602fabSXin LI  *
653c602fabSXin LI  * 3. Neither the name of Cisco nor of Motorola may be used
663c602fabSXin LI  *    to endorse or promote products derived from this software without
673c602fabSXin LI  *    specific prior written permission.
683c602fabSXin LI  *
693c602fabSXin LI  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
703c602fabSXin LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
713c602fabSXin LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
723c602fabSXin LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
733c602fabSXin LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
743c602fabSXin LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
753c602fabSXin LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
763c602fabSXin LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
773c602fabSXin LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
783c602fabSXin LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
793c602fabSXin LI  * SUCH DAMAGE.
803c602fabSXin LI  *
813c602fabSXin LI  * This file is part of the SCTP reference Implementation
823c602fabSXin LI  *
833c602fabSXin LI  *
843c602fabSXin LI  * Please send any bug reports or fixes you make to one of the following email
853c602fabSXin LI  * addresses:
863c602fabSXin LI  *
873c602fabSXin LI  * rstewar1@email.mot.com
883c602fabSXin LI  * kmorneau@cisco.com
893c602fabSXin LI  * qxie1@email.mot.com
903c602fabSXin LI  *
913c602fabSXin LI  * Any bugs reported given to us we will try to fix... any fixes shared will
92ee67461eSJoseph Mingrone  * be incorporated into the next SCTP release.
933c602fabSXin LI  */
943c602fabSXin LI 
953c602fabSXin LI /* The valid defines for all message
963c602fabSXin LI  * types know to SCTP. 0 is reserved
973c602fabSXin LI  */
983c602fabSXin LI #define SCTP_DATA		0x00
993c602fabSXin LI #define SCTP_INITIATION		0x01
1003c602fabSXin LI #define SCTP_INITIATION_ACK	0x02
1013c602fabSXin LI #define SCTP_SELECTIVE_ACK	0x03
1023c602fabSXin LI #define SCTP_HEARTBEAT_REQUEST	0x04
1033c602fabSXin LI #define SCTP_HEARTBEAT_ACK	0x05
1043c602fabSXin LI #define SCTP_ABORT_ASSOCIATION	0x06
1053c602fabSXin LI #define SCTP_SHUTDOWN		0x07
1063c602fabSXin LI #define SCTP_SHUTDOWN_ACK	0x08
1073c602fabSXin LI #define SCTP_OPERATION_ERR	0x09
1083c602fabSXin LI #define SCTP_COOKIE_ECHO	0x0a
1093c602fabSXin LI #define SCTP_COOKIE_ACK         0x0b
1103c602fabSXin LI #define SCTP_ECN_ECHO		0x0c
1113c602fabSXin LI #define SCTP_ECN_CWR		0x0d
1123c602fabSXin LI #define SCTP_SHUTDOWN_COMPLETE	0x0e
1133c602fabSXin LI #define SCTP_FORWARD_CUM_TSN    0xc0
1143c602fabSXin LI #define SCTP_RELIABLE_CNTL      0xc1
1153c602fabSXin LI #define SCTP_RELIABLE_CNTL_ACK  0xc2
1163c602fabSXin LI 
1173c602fabSXin LI static const struct tok sctp_chunkid_str[] = {
1183c602fabSXin LI 	{ SCTP_DATA,              "DATA"              },
1193c602fabSXin LI 	{ SCTP_INITIATION,        "INIT"              },
1203c602fabSXin LI 	{ SCTP_INITIATION_ACK,    "INIT ACK"          },
1213c602fabSXin LI 	{ SCTP_SELECTIVE_ACK,     "SACK"              },
1223c602fabSXin LI 	{ SCTP_HEARTBEAT_REQUEST, "HB REQ"            },
1233c602fabSXin LI 	{ SCTP_HEARTBEAT_ACK,     "HB ACK"            },
1243c602fabSXin LI 	{ SCTP_ABORT_ASSOCIATION, "ABORT"             },
1253c602fabSXin LI 	{ SCTP_SHUTDOWN,          "SHUTDOWN"          },
1263c602fabSXin LI 	{ SCTP_SHUTDOWN_ACK,      "SHUTDOWN ACK"      },
1273c602fabSXin LI 	{ SCTP_OPERATION_ERR,     "OP ERR"            },
1283c602fabSXin LI 	{ SCTP_COOKIE_ECHO,       "COOKIE ECHO"       },
1293c602fabSXin LI 	{ SCTP_COOKIE_ACK,        "COOKIE ACK"        },
1303c602fabSXin LI 	{ SCTP_ECN_ECHO,          "ECN ECHO"          },
1313c602fabSXin LI 	{ SCTP_ECN_CWR,           "ECN CWR"           },
1323c602fabSXin LI 	{ SCTP_SHUTDOWN_COMPLETE, "SHUTDOWN COMPLETE" },
1333c602fabSXin LI 	{ SCTP_FORWARD_CUM_TSN,   "FOR CUM TSN"       },
1343c602fabSXin LI 	{ SCTP_RELIABLE_CNTL,     "REL CTRL"          },
1353c602fabSXin LI 	{ SCTP_RELIABLE_CNTL_ACK, "REL CTRL ACK"      },
1363c602fabSXin LI 	{ 0, NULL }
1373c602fabSXin LI };
1383c602fabSXin LI 
1393c602fabSXin LI /* Data Chuck Specific Flags */
1403c602fabSXin LI #define SCTP_DATA_FRAG_MASK	0x03
1413c602fabSXin LI #define SCTP_DATA_MIDDLE_FRAG	0x00
1423c602fabSXin LI #define SCTP_DATA_LAST_FRAG	0x01
1433c602fabSXin LI #define SCTP_DATA_FIRST_FRAG	0x02
1443c602fabSXin LI #define SCTP_DATA_NOT_FRAG	0x03
1453c602fabSXin LI #define SCTP_DATA_UNORDERED	0x04
1463c602fabSXin LI 
1473c602fabSXin LI #define SCTP_ADDRMAX 60
1483c602fabSXin LI 
149cac3dcd5SXin LI #define CHAN_HP 6704
150cac3dcd5SXin LI #define CHAN_MP 6705
151cac3dcd5SXin LI #define CHAN_LP 6706
15227df3f5dSRui Paulo 
1533c602fabSXin LI /* the sctp common header */
1543c602fabSXin LI 
1553c602fabSXin LI struct sctpHeader{
156ee67461eSJoseph Mingrone   nd_uint16_t source;
157ee67461eSJoseph Mingrone   nd_uint16_t destination;
158ee67461eSJoseph Mingrone   nd_uint32_t verificationTag;
159ee67461eSJoseph Mingrone   nd_uint32_t adler32;
1603c602fabSXin LI };
1613c602fabSXin LI 
1623c602fabSXin LI /* various descriptor parsers */
1633c602fabSXin LI 
1643c602fabSXin LI struct sctpChunkDesc{
165ee67461eSJoseph Mingrone   nd_uint8_t  chunkID;
166ee67461eSJoseph Mingrone   nd_uint8_t  chunkFlg;
167ee67461eSJoseph Mingrone   nd_uint16_t chunkLength;
1683c602fabSXin LI };
1693c602fabSXin LI 
1703c602fabSXin LI struct sctpParamDesc{
171ee67461eSJoseph Mingrone   nd_uint16_t paramType;
172ee67461eSJoseph Mingrone   nd_uint16_t paramLength;
1733c602fabSXin LI };
1743c602fabSXin LI 
1753c602fabSXin LI 
1763c602fabSXin LI struct sctpRelChunkDesc{
1773c602fabSXin LI   struct sctpChunkDesc chk;
178ee67461eSJoseph Mingrone   nd_uint32_t serialNumber;
1793c602fabSXin LI };
1803c602fabSXin LI 
1813c602fabSXin LI struct sctpVendorSpecificParam {
1823c602fabSXin LI   struct sctpParamDesc p;  /* type must be 0xfffe */
183ee67461eSJoseph Mingrone   nd_uint32_t vendorId;	   /* vendor ID from RFC 1700 */
184ee67461eSJoseph Mingrone   nd_uint16_t vendorSpecificType;
185ee67461eSJoseph Mingrone   nd_uint16_t vendorSpecificLen;
1863c602fabSXin LI };
1873c602fabSXin LI 
1883c602fabSXin LI 
1893c602fabSXin LI /* Structures for the control parts */
1903c602fabSXin LI 
1913c602fabSXin LI 
1923c602fabSXin LI 
1933c602fabSXin LI /* Sctp association init request/ack */
1943c602fabSXin LI 
1953c602fabSXin LI /* this is used for init ack, too */
1963c602fabSXin LI struct sctpInitiation{
197ee67461eSJoseph Mingrone   nd_uint32_t initTag;			/* tag of mine */
198ee67461eSJoseph Mingrone   nd_uint32_t rcvWindowCredit;		/* rwnd */
199ee67461eSJoseph Mingrone   nd_uint16_t NumPreopenStreams;	/* OS */
200ee67461eSJoseph Mingrone   nd_uint16_t MaxInboundStreams;	/* MIS */
201ee67461eSJoseph Mingrone   nd_uint32_t initialTSN;
2023c602fabSXin LI   /* optional param's follow in sctpParamDesc form */
2033c602fabSXin LI };
2043c602fabSXin LI 
2053c602fabSXin LI struct sctpV4IpAddress{
2063c602fabSXin LI   struct sctpParamDesc p;	/* type is set to SCTP_IPV4_PARAM_TYPE, len=10 */
207ee67461eSJoseph Mingrone   nd_ipv4  ipAddress;
2083c602fabSXin LI };
2093c602fabSXin LI 
2103c602fabSXin LI 
2113c602fabSXin LI struct sctpV6IpAddress{
2123c602fabSXin LI   struct sctpParamDesc p;	/* type is set to SCTP_IPV6_PARAM_TYPE, len=22 */
213ee67461eSJoseph Mingrone   nd_ipv6  ipAddress;
2143c602fabSXin LI };
2153c602fabSXin LI 
2163c602fabSXin LI struct sctpDNSName{
2173c602fabSXin LI   struct sctpParamDesc param;
218ee67461eSJoseph Mingrone   nd_byte name[1];
2193c602fabSXin LI };
2203c602fabSXin LI 
2213c602fabSXin LI 
2223c602fabSXin LI struct sctpCookiePreserve{
2233c602fabSXin LI   struct sctpParamDesc p;	/* type is set to SCTP_COOKIE_PRESERVE, len=8 */
224ee67461eSJoseph Mingrone   nd_uint32_t extraTime;
2253c602fabSXin LI };
2263c602fabSXin LI 
2273c602fabSXin LI 
2283c602fabSXin LI struct sctpTimeStamp{
229ee67461eSJoseph Mingrone   nd_uint32_t ts_sec;
230ee67461eSJoseph Mingrone   nd_uint32_t ts_usec;
2313c602fabSXin LI };
2323c602fabSXin LI 
2333c602fabSXin LI 
2343c602fabSXin LI /* this guy is for use when
2353c602fabSXin LI  * I have a initiate message gloming the
2363c602fabSXin LI  * things together.
2373c602fabSXin LI 
2383c602fabSXin LI  */
2393c602fabSXin LI struct sctpUnifiedInit{
2403c602fabSXin LI   struct sctpChunkDesc uh;
2413c602fabSXin LI   struct sctpInitiation initm;
2423c602fabSXin LI };
2433c602fabSXin LI 
2443c602fabSXin LI struct sctpSendableInit{
2453c602fabSXin LI   struct sctpHeader mh;
2463c602fabSXin LI   struct sctpUnifiedInit msg;
2473c602fabSXin LI };
2483c602fabSXin LI 
2493c602fabSXin LI 
2503c602fabSXin LI /* Selective Acknowledgement
2513c602fabSXin LI  * has the following structure with
252ee67461eSJoseph Mingrone  * a optional amount of trailing int's
2533c602fabSXin LI  * on the last part (based on the numberOfDesc
2543c602fabSXin LI  * field).
2553c602fabSXin LI  */
2563c602fabSXin LI 
2573c602fabSXin LI struct sctpSelectiveAck{
258ee67461eSJoseph Mingrone   nd_uint32_t highestConseqTSN;
259ee67461eSJoseph Mingrone   nd_uint32_t updatedRwnd;
260ee67461eSJoseph Mingrone   nd_uint16_t numberOfdesc;
261ee67461eSJoseph Mingrone   nd_uint16_t numDupTsns;
2623c602fabSXin LI };
2633c602fabSXin LI 
2643c602fabSXin LI struct sctpSelectiveFrag{
265ee67461eSJoseph Mingrone   nd_uint16_t fragmentStart;
266ee67461eSJoseph Mingrone   nd_uint16_t fragmentEnd;
2673c602fabSXin LI };
2683c602fabSXin LI 
2693c602fabSXin LI 
2703c602fabSXin LI struct sctpUnifiedSack{
2713c602fabSXin LI   struct sctpChunkDesc uh;
2723c602fabSXin LI   struct sctpSelectiveAck sack;
2733c602fabSXin LI };
2743c602fabSXin LI 
2753c602fabSXin LI /* for the abort and shutdown ACK
2763c602fabSXin LI  * we must carry the init tag in the common header. Just the
2773c602fabSXin LI  * common header is all that is needed with a chunk descriptor.
2783c602fabSXin LI  */
2793c602fabSXin LI struct sctpUnifiedAbort{
2803c602fabSXin LI   struct sctpChunkDesc uh;
2813c602fabSXin LI };
2823c602fabSXin LI 
2833c602fabSXin LI struct sctpUnifiedAbortLight{
2843c602fabSXin LI   struct sctpHeader mh;
2853c602fabSXin LI   struct sctpChunkDesc uh;
2863c602fabSXin LI };
2873c602fabSXin LI 
2883c602fabSXin LI struct sctpUnifiedAbortHeavy{
2893c602fabSXin LI   struct sctpHeader mh;
2903c602fabSXin LI   struct sctpChunkDesc uh;
291ee67461eSJoseph Mingrone   nd_uint16_t causeCode;
292ee67461eSJoseph Mingrone   nd_uint16_t causeLen;
2933c602fabSXin LI };
2943c602fabSXin LI 
2953c602fabSXin LI /* For the graceful shutdown we must carry
2963c602fabSXin LI  * the tag (in common header)  and the highest consequitive acking value
2973c602fabSXin LI  */
2983c602fabSXin LI struct sctpShutdown {
299ee67461eSJoseph Mingrone   nd_uint32_t TSN_Seen;
3003c602fabSXin LI };
3013c602fabSXin LI 
3023c602fabSXin LI struct sctpUnifiedShutdown{
3033c602fabSXin LI   struct sctpChunkDesc uh;
3043c602fabSXin LI   struct sctpShutdown shut;
3053c602fabSXin LI };
3063c602fabSXin LI 
3073c602fabSXin LI /* in the unified message we add the trailing
3083c602fabSXin LI  * stream id since it is the only message
3093c602fabSXin LI  * that is defined as a operation error.
3103c602fabSXin LI  */
3113c602fabSXin LI struct sctpOpErrorCause{
312ee67461eSJoseph Mingrone   nd_uint16_t cause;
313ee67461eSJoseph Mingrone   nd_uint16_t causeLen;
3143c602fabSXin LI };
3153c602fabSXin LI 
3163c602fabSXin LI struct sctpUnifiedOpError{
3173c602fabSXin LI   struct sctpChunkDesc uh;
3183c602fabSXin LI   struct sctpOpErrorCause c;
3193c602fabSXin LI };
3203c602fabSXin LI 
3213c602fabSXin LI struct sctpUnifiedStreamError{
3223c602fabSXin LI   struct sctpHeader mh;
3233c602fabSXin LI   struct sctpChunkDesc uh;
3243c602fabSXin LI   struct sctpOpErrorCause c;
325ee67461eSJoseph Mingrone   nd_uint16_t strmNum;
326ee67461eSJoseph Mingrone   nd_uint16_t reserved;
3273c602fabSXin LI };
3283c602fabSXin LI 
3293c602fabSXin LI struct staleCookieMsg{
3303c602fabSXin LI   struct sctpHeader mh;
3313c602fabSXin LI   struct sctpChunkDesc uh;
3323c602fabSXin LI   struct sctpOpErrorCause c;
333ee67461eSJoseph Mingrone   nd_uint32_t moretime;
3343c602fabSXin LI };
3353c602fabSXin LI 
3363c602fabSXin LI /* the following is used in all sends
3373c602fabSXin LI  * where nothing is needed except the
3383c602fabSXin LI  * chunk/type i.e. shutdownAck Abort */
3393c602fabSXin LI 
3403c602fabSXin LI struct sctpUnifiedSingleMsg{
3413c602fabSXin LI   struct sctpHeader mh;
3423c602fabSXin LI   struct sctpChunkDesc uh;
3433c602fabSXin LI };
3443c602fabSXin LI 
3453c602fabSXin LI struct sctpDataPart{
346ee67461eSJoseph Mingrone   nd_uint32_t TSN;
347ee67461eSJoseph Mingrone   nd_uint16_t streamId;
348ee67461eSJoseph Mingrone   nd_uint16_t sequence;
349ee67461eSJoseph Mingrone   nd_uint32_t payloadtype;
3503c602fabSXin LI };
3513c602fabSXin LI 
3523c602fabSXin LI struct sctpUnifiedDatagram{
3533c602fabSXin LI   struct sctpChunkDesc uh;
3543c602fabSXin LI   struct sctpDataPart dp;
3553c602fabSXin LI };
3563c602fabSXin LI 
3573c602fabSXin LI struct sctpECN_echo{
3583c602fabSXin LI   struct sctpChunkDesc uh;
359ee67461eSJoseph Mingrone   nd_uint32_t Lowest_TSN;
3603c602fabSXin LI };
3613c602fabSXin LI 
3623c602fabSXin LI 
3633c602fabSXin LI struct sctpCWR{
3643c602fabSXin LI   struct sctpChunkDesc uh;
365ee67461eSJoseph Mingrone   nd_uint32_t TSN_reduced_at;
3663c602fabSXin LI };
3673c602fabSXin LI 
3683c602fabSXin LI static const struct tok ForCES_channels[] = {
36927df3f5dSRui Paulo 	{ CHAN_HP, "ForCES HP" },
37027df3f5dSRui Paulo 	{ CHAN_MP, "ForCES MP" },
37127df3f5dSRui Paulo 	{ CHAN_LP, "ForCES LP" },
37227df3f5dSRui Paulo 	{ 0, NULL }
37327df3f5dSRui Paulo };
37427df3f5dSRui Paulo 
3753c602fabSXin LI /* data chunk's payload protocol identifiers */
3763c602fabSXin LI 
3773c602fabSXin LI #define SCTP_PPID_IUA 1
3783c602fabSXin LI #define SCTP_PPID_M2UA 2
3793c602fabSXin LI #define SCTP_PPID_M3UA 3
3803c602fabSXin LI #define SCTP_PPID_SUA 4
3813c602fabSXin LI #define SCTP_PPID_M2PA 5
3823c602fabSXin LI #define SCTP_PPID_V5UA 6
3833c602fabSXin LI #define SCTP_PPID_H248 7
3843c602fabSXin LI #define SCTP_PPID_BICC 8
3853c602fabSXin LI #define SCTP_PPID_TALI 9
3863c602fabSXin LI #define SCTP_PPID_DUA 10
3873c602fabSXin LI #define SCTP_PPID_ASAP 11
3883c602fabSXin LI #define SCTP_PPID_ENRP 12
3893c602fabSXin LI #define SCTP_PPID_H323 13
3903c602fabSXin LI #define SCTP_PPID_QIPC 14
3913c602fabSXin LI #define SCTP_PPID_SIMCO 15
3923c602fabSXin LI #define SCTP_PPID_DDPSC 16
3933c602fabSXin LI #define SCTP_PPID_DDPSSC 17
3943c602fabSXin LI #define SCTP_PPID_S1AP 18
3953c602fabSXin LI #define SCTP_PPID_RUA 19
3963c602fabSXin LI #define SCTP_PPID_HNBAP 20
3973c602fabSXin LI #define SCTP_PPID_FORCES_HP 21
3983c602fabSXin LI #define SCTP_PPID_FORCES_MP 22
3993c602fabSXin LI #define SCTP_PPID_FORCES_LP 23
4003c602fabSXin LI #define SCTP_PPID_SBC_AP 24
4013c602fabSXin LI #define SCTP_PPID_NBAP 25
4023c602fabSXin LI /* 26 */
4033c602fabSXin LI #define SCTP_PPID_X2AP 27
4043c602fabSXin LI 
4053c602fabSXin LI static const struct tok PayloadProto_idents[] = {
4063c602fabSXin LI 	{ SCTP_PPID_IUA,    "ISDN Q.921" },
4073c602fabSXin LI 	{ SCTP_PPID_M2UA,   "M2UA"   },
4083c602fabSXin LI 	{ SCTP_PPID_M3UA,   "M3UA"   },
4093c602fabSXin LI 	{ SCTP_PPID_SUA,    "SUA"    },
4103c602fabSXin LI 	{ SCTP_PPID_M2PA,   "M2PA"   },
4113c602fabSXin LI 	{ SCTP_PPID_V5UA,   "V5.2"   },
4123c602fabSXin LI 	{ SCTP_PPID_H248,   "H.248"  },
4133c602fabSXin LI 	{ SCTP_PPID_BICC,   "BICC"   },
4143c602fabSXin LI 	{ SCTP_PPID_TALI,   "TALI"   },
4153c602fabSXin LI 	{ SCTP_PPID_DUA,    "DUA"    },
4163c602fabSXin LI 	{ SCTP_PPID_ASAP,   "ASAP"   },
4173c602fabSXin LI 	{ SCTP_PPID_ENRP,   "ENRP"   },
4183c602fabSXin LI 	{ SCTP_PPID_H323,   "H.323"  },
4193c602fabSXin LI 	{ SCTP_PPID_QIPC,   "Q.IPC"  },
4203c602fabSXin LI 	{ SCTP_PPID_SIMCO,  "SIMCO"  },
4213c602fabSXin LI 	{ SCTP_PPID_DDPSC,  "DDPSC"  },
4223c602fabSXin LI 	{ SCTP_PPID_DDPSSC, "DDPSSC" },
4233c602fabSXin LI 	{ SCTP_PPID_S1AP,   "S1AP"   },
4243c602fabSXin LI 	{ SCTP_PPID_RUA,    "RUA"    },
4253c602fabSXin LI 	{ SCTP_PPID_HNBAP,  "HNBAP"  },
4263c602fabSXin LI 	{ SCTP_PPID_FORCES_HP, "ForCES HP" },
4273c602fabSXin LI 	{ SCTP_PPID_FORCES_MP, "ForCES MP" },
4283c602fabSXin LI 	{ SCTP_PPID_FORCES_LP, "ForCES LP" },
4293c602fabSXin LI 	{ SCTP_PPID_SBC_AP, "SBc-AP" },
4303c602fabSXin LI 	{ SCTP_PPID_NBAP,   "NBAP"   },
4313c602fabSXin LI 	/* 26 */
4323c602fabSXin LI 	{ SCTP_PPID_X2AP,   "X2AP"   },
4333c602fabSXin LI 	{ 0, NULL }
4343c602fabSXin LI };
4353c602fabSXin LI 
4363c602fabSXin LI 
437ee67461eSJoseph Mingrone static int
isForCES_port(u_short Port)438ee67461eSJoseph Mingrone isForCES_port(u_short Port)
43927df3f5dSRui Paulo {
44027df3f5dSRui Paulo 	if (Port == CHAN_HP)
44127df3f5dSRui Paulo 		return 1;
44227df3f5dSRui Paulo 	if (Port == CHAN_MP)
44327df3f5dSRui Paulo 		return 1;
44427df3f5dSRui Paulo 	if (Port == CHAN_LP)
44527df3f5dSRui Paulo 		return 1;
44627df3f5dSRui Paulo 
44727df3f5dSRui Paulo 	return 0;
44827df3f5dSRui Paulo }
44927df3f5dSRui Paulo 
450ee67461eSJoseph Mingrone void
sctp_print(netdissect_options * ndo,const u_char * bp,const u_char * bp2,u_int sctpPacketLength)451ee67461eSJoseph Mingrone sctp_print(netdissect_options *ndo,
4523c602fabSXin LI 	   const u_char *bp,        /* beginning of sctp packet */
453a90e161bSBill Fenner 	   const u_char *bp2,       /* beginning of enclosing */
454a90e161bSBill Fenner 	   u_int sctpPacketLength)  /* ip packet */
455a90e161bSBill Fenner {
4563340d773SGleb Smirnoff   u_int sctpPacketLengthRemaining;
457a90e161bSBill Fenner   const struct sctpHeader *sctpPktHdr;
458a90e161bSBill Fenner   const struct ip *ip;
459a90e161bSBill Fenner   const struct ip6_hdr *ip6;
460ee67461eSJoseph Mingrone   uint8_t chunkID;
461a90e161bSBill Fenner   u_short sourcePort, destPort;
462ee67461eSJoseph Mingrone   u_int chunkCount;
4639afd0c29SBill Fenner   const struct sctpChunkDesc *chunkDescPtr;
4641de50e9fSSam Leffler   const char *sep;
46527df3f5dSRui Paulo   int isforces = 0;
46627df3f5dSRui Paulo 
467ee67461eSJoseph Mingrone   ndo->ndo_protocol = "sctp";
468a90e161bSBill Fenner   if (sctpPacketLength < sizeof(struct sctpHeader))
469a90e161bSBill Fenner     {
470ee67461eSJoseph Mingrone       ND_PRINT("truncated-sctp - %zu bytes missing!",
471ee67461eSJoseph Mingrone                sizeof(struct sctpHeader) - sctpPacketLength);
472a90e161bSBill Fenner       return;
473a90e161bSBill Fenner     }
4743340d773SGleb Smirnoff   sctpPktHdr = (const struct sctpHeader*) bp;
475ee67461eSJoseph Mingrone   ND_TCHECK_SIZE(sctpPktHdr);
4763340d773SGleb Smirnoff   sctpPacketLengthRemaining = sctpPacketLength;
477a90e161bSBill Fenner 
478ee67461eSJoseph Mingrone   sourcePort = GET_BE_U_2(sctpPktHdr->source);
479ee67461eSJoseph Mingrone   destPort = GET_BE_U_2(sctpPktHdr->destination);
480a90e161bSBill Fenner 
4813340d773SGleb Smirnoff   ip = (const struct ip *)bp2;
4823340d773SGleb Smirnoff   if (IP_V(ip) == 6)
4833340d773SGleb Smirnoff     ip6 = (const struct ip6_hdr *)bp2;
4843340d773SGleb Smirnoff   else
4853340d773SGleb Smirnoff     ip6 = NULL;
4863340d773SGleb Smirnoff 
487a90e161bSBill Fenner   if (ip6) {
488ee67461eSJoseph Mingrone     ND_PRINT("%s.%u > %s.%u: sctp",
489ee67461eSJoseph Mingrone       GET_IP6ADDR_STRING(ip6->ip6_src),
490a90e161bSBill Fenner       sourcePort,
491ee67461eSJoseph Mingrone       GET_IP6ADDR_STRING(ip6->ip6_dst),
492ee67461eSJoseph Mingrone       destPort);
493ee67461eSJoseph Mingrone   } else {
494ee67461eSJoseph Mingrone     ND_PRINT("%s.%u > %s.%u: sctp",
495ee67461eSJoseph Mingrone       GET_IPADDR_STRING(ip->ip_src),
496a90e161bSBill Fenner       sourcePort,
497ee67461eSJoseph Mingrone       GET_IPADDR_STRING(ip->ip_dst),
498ee67461eSJoseph Mingrone       destPort);
499a90e161bSBill Fenner   }
500a90e161bSBill Fenner 
50127df3f5dSRui Paulo   if (isForCES_port(sourcePort)) {
502ee67461eSJoseph Mingrone 	 ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, sourcePort));
50327df3f5dSRui Paulo 	 isforces = 1;
50427df3f5dSRui Paulo   }
50527df3f5dSRui Paulo   if (isForCES_port(destPort)) {
506ee67461eSJoseph Mingrone 	 ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, destPort));
50727df3f5dSRui Paulo 	 isforces = 1;
50827df3f5dSRui Paulo   }
50927df3f5dSRui Paulo 
5103340d773SGleb Smirnoff   bp += sizeof(struct sctpHeader);
5113340d773SGleb Smirnoff   sctpPacketLengthRemaining -= sizeof(struct sctpHeader);
5123340d773SGleb Smirnoff 
5133c602fabSXin LI   if (ndo->ndo_vflag >= 2)
5141de50e9fSSam Leffler     sep = "\n\t";
5151de50e9fSSam Leffler   else
5161de50e9fSSam Leffler     sep = " (";
517a90e161bSBill Fenner   /* cycle through all chunks, printing information on each one */
5183340d773SGleb Smirnoff   for (chunkCount = 0, chunkDescPtr = (const struct sctpChunkDesc *)bp;
5193340d773SGleb Smirnoff       sctpPacketLengthRemaining != 0;
5203340d773SGleb Smirnoff       chunkCount++)
521a90e161bSBill Fenner     {
5223340d773SGleb Smirnoff       uint16_t chunkLength, chunkLengthRemaining;
5233c602fabSXin LI       uint16_t align;
524a90e161bSBill Fenner 
5253340d773SGleb Smirnoff       chunkDescPtr = (const struct sctpChunkDesc *)bp;
5263340d773SGleb Smirnoff       if (sctpPacketLengthRemaining < sizeof(*chunkDescPtr)) {
527ee67461eSJoseph Mingrone 	ND_PRINT("%s%u) [chunk descriptor cut off at end of packet]", sep, chunkCount+1);
5283340d773SGleb Smirnoff 	break;
5293340d773SGleb Smirnoff       }
530ee67461eSJoseph Mingrone       ND_TCHECK_SIZE(chunkDescPtr);
531ee67461eSJoseph Mingrone       chunkLength = GET_BE_U_2(chunkDescPtr->chunkLength);
532f4d0c64aSSam Leffler       if (chunkLength < sizeof(*chunkDescPtr)) {
533ee67461eSJoseph Mingrone 	ND_PRINT("%s%u) [Bad chunk length %u, < size of chunk descriptor]", sep, chunkCount+1, chunkLength);
534f4d0c64aSSam Leffler 	break;
535f4d0c64aSSam Leffler       }
5363340d773SGleb Smirnoff       chunkLengthRemaining = chunkLength;
537f4d0c64aSSam Leffler 
538f4d0c64aSSam Leffler       align = chunkLength % 4;
539a90e161bSBill Fenner       if (align != 0)
540a90e161bSBill Fenner 	align = 4 - align;
541a90e161bSBill Fenner 
5423340d773SGleb Smirnoff       if (sctpPacketLengthRemaining < align) {
543ee67461eSJoseph Mingrone 	ND_PRINT("%s%u) [Bad chunk length %u, > remaining data in packet]", sep, chunkCount+1, chunkLength);
5443340d773SGleb Smirnoff 	break;
5453340d773SGleb Smirnoff       }
5463340d773SGleb Smirnoff 
547ee67461eSJoseph Mingrone       ND_TCHECK_LEN(bp, chunkLength);
5483340d773SGleb Smirnoff 
5493340d773SGleb Smirnoff       bp += sizeof(*chunkDescPtr);
5503340d773SGleb Smirnoff       sctpPacketLengthRemaining -= sizeof(*chunkDescPtr);
5513340d773SGleb Smirnoff       chunkLengthRemaining -= sizeof(*chunkDescPtr);
552a90e161bSBill Fenner 
553ee67461eSJoseph Mingrone       ND_PRINT("%s%u) ", sep, chunkCount+1);
554ee67461eSJoseph Mingrone       chunkID = GET_U_1(chunkDescPtr->chunkID);
555ee67461eSJoseph Mingrone       ND_PRINT("[%s] ", tok2str(sctp_chunkid_str, "Unknown chunk type: 0x%x",
556ee67461eSJoseph Mingrone 	       chunkID));
557ee67461eSJoseph Mingrone       switch (chunkID)
558a90e161bSBill Fenner 	{
559a90e161bSBill Fenner 	case SCTP_DATA :
560a90e161bSBill Fenner 	  {
5619afd0c29SBill Fenner 	    const struct sctpDataPart *dataHdrPtr;
562ee67461eSJoseph Mingrone 	    uint8_t chunkFlg;
5633c602fabSXin LI 	    uint32_t ppid;
564ee67461eSJoseph Mingrone 	    uint16_t payload_size;
565a90e161bSBill Fenner 
566ee67461eSJoseph Mingrone 	    chunkFlg = GET_U_1(chunkDescPtr->chunkFlg);
567ee67461eSJoseph Mingrone 	    if ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED)
568ee67461eSJoseph Mingrone 	      ND_PRINT("(U)");
569a90e161bSBill Fenner 
570ee67461eSJoseph Mingrone 	    if ((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG)
571ee67461eSJoseph Mingrone 	      ND_PRINT("(B)");
572a90e161bSBill Fenner 
573ee67461eSJoseph Mingrone 	    if ((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG)
574ee67461eSJoseph Mingrone 	      ND_PRINT("(E)");
575a90e161bSBill Fenner 
576ee67461eSJoseph Mingrone 	    if( ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) ||
577ee67461eSJoseph Mingrone 		((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) ||
578ee67461eSJoseph Mingrone 		((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) )
579ee67461eSJoseph Mingrone 	      ND_PRINT(" ");
580a90e161bSBill Fenner 
5813340d773SGleb Smirnoff 	    if (chunkLengthRemaining < sizeof(*dataHdrPtr)) {
582ee67461eSJoseph Mingrone 		ND_PRINT("bogus chunk length %u]", chunkLength);
5833340d773SGleb Smirnoff 		return;
5843340d773SGleb Smirnoff 	    }
5853340d773SGleb Smirnoff 	    dataHdrPtr=(const struct sctpDataPart*)bp;
586a90e161bSBill Fenner 
587ee67461eSJoseph Mingrone 	    ppid = GET_BE_U_4(dataHdrPtr->payloadtype);
588ee67461eSJoseph Mingrone 	    ND_PRINT("[TSN: %u] ", GET_BE_U_4(dataHdrPtr->TSN));
589ee67461eSJoseph Mingrone 	    ND_PRINT("[SID: %u] ", GET_BE_U_2(dataHdrPtr->streamId));
590ee67461eSJoseph Mingrone 	    ND_PRINT("[SSEQ %u] ", GET_BE_U_2(dataHdrPtr->sequence));
591ee67461eSJoseph Mingrone 	    ND_PRINT("[PPID %s] ",
592ee67461eSJoseph Mingrone 		    tok2str(PayloadProto_idents, "0x%x", ppid));
5933c602fabSXin LI 
5943c602fabSXin LI 	    if (!isforces) {
5953c602fabSXin LI 		isforces = (ppid == SCTP_PPID_FORCES_HP) ||
5963c602fabSXin LI 		    (ppid == SCTP_PPID_FORCES_MP) ||
5973c602fabSXin LI 		    (ppid == SCTP_PPID_FORCES_LP);
5983c602fabSXin LI 	    }
5993c602fabSXin LI 
6003340d773SGleb Smirnoff 	    bp += sizeof(*dataHdrPtr);
6013340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= sizeof(*dataHdrPtr);
6023340d773SGleb Smirnoff 	    chunkLengthRemaining -= sizeof(*dataHdrPtr);
6033340d773SGleb Smirnoff 	    payload_size = chunkLengthRemaining;
6043340d773SGleb Smirnoff 	    if (payload_size == 0) {
605ee67461eSJoseph Mingrone 		ND_PRINT("bogus chunk length %u]", chunkLength);
60627df3f5dSRui Paulo 		return;
60727df3f5dSRui Paulo 	    }
608a90e161bSBill Fenner 
6093c602fabSXin LI 	    if (isforces) {
6103340d773SGleb Smirnoff 		forces_print(ndo, bp, payload_size);
611ee67461eSJoseph Mingrone 		/* ndo_protocol reassignment after forces_print() call */
612ee67461eSJoseph Mingrone 		ndo->ndo_protocol = "sctp";
6133c602fabSXin LI 	    } else if (ndo->ndo_vflag >= 2) {	/* if verbose output is specified */
61427df3f5dSRui Paulo 					/* at the command line */
6153c602fabSXin LI 		switch (ppid) {
6163c602fabSXin LI 		case SCTP_PPID_M3UA :
6173340d773SGleb Smirnoff 			m3ua_print(ndo, bp, payload_size);
618ee67461eSJoseph Mingrone 			/* ndo_protocol reassignment after m3ua_print() call */
619ee67461eSJoseph Mingrone 			ndo->ndo_protocol = "sctp";
6203c602fabSXin LI 			break;
6213c602fabSXin LI 		default:
622ee67461eSJoseph Mingrone 			ND_PRINT("[Payload");
6233c602fabSXin LI 			if (!ndo->ndo_suppress_default_print) {
624ee67461eSJoseph Mingrone 				ND_PRINT(":");
6253340d773SGleb Smirnoff 				ND_DEFAULTPRINT(bp, payload_size);
6265b0fe478SBruce M Simpson 			}
627ee67461eSJoseph Mingrone 			ND_PRINT("]");
6283c602fabSXin LI 			break;
6293c602fabSXin LI 		}
630a90e161bSBill Fenner 	    }
6313340d773SGleb Smirnoff 	    bp += payload_size;
6323340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= payload_size;
6333340d773SGleb Smirnoff 	    chunkLengthRemaining -= payload_size;
634a90e161bSBill Fenner 	    break;
635a90e161bSBill Fenner 	  }
636a90e161bSBill Fenner 	case SCTP_INITIATION :
637a90e161bSBill Fenner 	  {
6389afd0c29SBill Fenner 	    const struct sctpInitiation *init;
639a90e161bSBill Fenner 
6403340d773SGleb Smirnoff 	    if (chunkLengthRemaining < sizeof(*init)) {
641ee67461eSJoseph Mingrone 		ND_PRINT("bogus chunk length %u]", chunkLength);
6423340d773SGleb Smirnoff 		return;
6433340d773SGleb Smirnoff 	    }
6443340d773SGleb Smirnoff 	    init=(const struct sctpInitiation*)bp;
645ee67461eSJoseph Mingrone 	    ND_PRINT("[init tag: %u] ", GET_BE_U_4(init->initTag));
646ee67461eSJoseph Mingrone 	    ND_PRINT("[rwnd: %u] ", GET_BE_U_4(init->rcvWindowCredit));
647ee67461eSJoseph Mingrone 	    ND_PRINT("[OS: %u] ", GET_BE_U_2(init->NumPreopenStreams));
648ee67461eSJoseph Mingrone 	    ND_PRINT("[MIS: %u] ", GET_BE_U_2(init->MaxInboundStreams));
649ee67461eSJoseph Mingrone 	    ND_PRINT("[init TSN: %u] ", GET_BE_U_4(init->initialTSN));
6503340d773SGleb Smirnoff 	    bp += sizeof(*init);
6513340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= sizeof(*init);
6523340d773SGleb Smirnoff 	    chunkLengthRemaining -= sizeof(*init);
653a90e161bSBill Fenner 
6543340d773SGleb Smirnoff #if 0 /* ALC you can add code for optional params here */
6553340d773SGleb Smirnoff 	    if( chunkLengthRemaining != 0 )
656ee67461eSJoseph Mingrone 	      ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n",
657ee67461eSJoseph Mingrone 		     "Optional params present, but not printed.");
658a90e161bSBill Fenner #endif
6593340d773SGleb Smirnoff 	    bp += chunkLengthRemaining;
6603340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= chunkLengthRemaining;
6613340d773SGleb Smirnoff 	    chunkLengthRemaining = 0;
662a90e161bSBill Fenner 	    break;
663a90e161bSBill Fenner 	  }
664a90e161bSBill Fenner 	case SCTP_INITIATION_ACK :
665a90e161bSBill Fenner 	  {
6669afd0c29SBill Fenner 	    const struct sctpInitiation *init;
667a90e161bSBill Fenner 
6683340d773SGleb Smirnoff 	    if (chunkLengthRemaining < sizeof(*init)) {
669ee67461eSJoseph Mingrone 		ND_PRINT("bogus chunk length %u]", chunkLength);
6703340d773SGleb Smirnoff 		return;
6713340d773SGleb Smirnoff 	    }
6723340d773SGleb Smirnoff 	    init=(const struct sctpInitiation*)bp;
673ee67461eSJoseph Mingrone 	    ND_PRINT("[init tag: %u] ", GET_BE_U_4(init->initTag));
674ee67461eSJoseph Mingrone 	    ND_PRINT("[rwnd: %u] ", GET_BE_U_4(init->rcvWindowCredit));
675ee67461eSJoseph Mingrone 	    ND_PRINT("[OS: %u] ", GET_BE_U_2(init->NumPreopenStreams));
676ee67461eSJoseph Mingrone 	    ND_PRINT("[MIS: %u] ", GET_BE_U_2(init->MaxInboundStreams));
677ee67461eSJoseph Mingrone 	    ND_PRINT("[init TSN: %u] ", GET_BE_U_4(init->initialTSN));
6783340d773SGleb Smirnoff 	    bp += sizeof(*init);
6793340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= sizeof(*init);
6803340d773SGleb Smirnoff 	    chunkLengthRemaining -= sizeof(*init);
681a90e161bSBill Fenner 
6823340d773SGleb Smirnoff #if 0 /* ALC you can add code for optional params here */
6833340d773SGleb Smirnoff 	    if( chunkLengthRemaining != 0 )
684ee67461eSJoseph Mingrone 	      ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n",
685ee67461eSJoseph Mingrone 		     "Optional params present, but not printed.");
686a90e161bSBill Fenner #endif
6873340d773SGleb Smirnoff 	    bp += chunkLengthRemaining;
6883340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= chunkLengthRemaining;
6893340d773SGleb Smirnoff 	    chunkLengthRemaining = 0;
690a90e161bSBill Fenner 	    break;
691a90e161bSBill Fenner 	  }
692a90e161bSBill Fenner 	case SCTP_SELECTIVE_ACK:
693a90e161bSBill Fenner 	  {
6949afd0c29SBill Fenner 	    const struct sctpSelectiveAck *sack;
6959afd0c29SBill Fenner 	    const struct sctpSelectiveFrag *frag;
696ee67461eSJoseph Mingrone 	    u_int fragNo, tsnNo;
697f4d0c64aSSam Leffler 	    const u_char *dupTSN;
698a90e161bSBill Fenner 
6993340d773SGleb Smirnoff 	    if (chunkLengthRemaining < sizeof(*sack)) {
700ee67461eSJoseph Mingrone 	      ND_PRINT("bogus chunk length %u]", chunkLength);
7013340d773SGleb Smirnoff 	      return;
7023340d773SGleb Smirnoff 	    }
7033340d773SGleb Smirnoff 	    sack=(const struct sctpSelectiveAck*)bp;
704ee67461eSJoseph Mingrone 	    ND_PRINT("[cum ack %u] ", GET_BE_U_4(sack->highestConseqTSN));
705ee67461eSJoseph Mingrone 	    ND_PRINT("[a_rwnd %u] ", GET_BE_U_4(sack->updatedRwnd));
706ee67461eSJoseph Mingrone 	    ND_PRINT("[#gap acks %u] ", GET_BE_U_2(sack->numberOfdesc));
707ee67461eSJoseph Mingrone 	    ND_PRINT("[#dup tsns %u] ", GET_BE_U_2(sack->numDupTsns));
7083340d773SGleb Smirnoff 	    bp += sizeof(*sack);
7093340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= sizeof(*sack);
7103340d773SGleb Smirnoff 	    chunkLengthRemaining -= sizeof(*sack);
711a90e161bSBill Fenner 
712a90e161bSBill Fenner 
713a90e161bSBill Fenner 	    /* print gaps */
7143340d773SGleb Smirnoff 	    for (fragNo=0;
715ee67461eSJoseph Mingrone 		 chunkLengthRemaining != 0 && fragNo < GET_BE_U_2(sack->numberOfdesc);
7163340d773SGleb Smirnoff 		 bp += sizeof(*frag), sctpPacketLengthRemaining -= sizeof(*frag), chunkLengthRemaining -= sizeof(*frag), fragNo++) {
7173340d773SGleb Smirnoff 	      if (chunkLengthRemaining < sizeof(*frag)) {
718ee67461eSJoseph Mingrone 		ND_PRINT("bogus chunk length %u]", chunkLength);
7193340d773SGleb Smirnoff 		return;
7203340d773SGleb Smirnoff 	      }
7213340d773SGleb Smirnoff 	      frag = (const struct sctpSelectiveFrag *)bp;
722ee67461eSJoseph Mingrone 	      ND_PRINT("\n\t\t[gap ack block #%u: start = %u, end = %u] ",
723a90e161bSBill Fenner 		     fragNo+1,
724ee67461eSJoseph Mingrone 		     GET_BE_U_4(sack->highestConseqTSN) + GET_BE_U_2(frag->fragmentStart),
725ee67461eSJoseph Mingrone 		     GET_BE_U_4(sack->highestConseqTSN) + GET_BE_U_2(frag->fragmentEnd));
7263340d773SGleb Smirnoff 	    }
727a90e161bSBill Fenner 
728a90e161bSBill Fenner 	    /* print duplicate TSNs */
7293340d773SGleb Smirnoff 	    for (tsnNo=0;
730ee67461eSJoseph Mingrone 		 chunkLengthRemaining != 0 && tsnNo<GET_BE_U_2(sack->numDupTsns);
7313340d773SGleb Smirnoff 		 bp += 4, sctpPacketLengthRemaining -= 4, chunkLengthRemaining -= 4, tsnNo++) {
7323340d773SGleb Smirnoff 	      if (chunkLengthRemaining < 4) {
733ee67461eSJoseph Mingrone 		ND_PRINT("bogus chunk length %u]", chunkLength);
7343340d773SGleb Smirnoff 		return;
7353340d773SGleb Smirnoff 	      }
7363340d773SGleb Smirnoff 	      dupTSN = (const u_char *)bp;
737ee67461eSJoseph Mingrone 	      ND_PRINT("\n\t\t[dup TSN #%u: %u] ", tsnNo+1,
738ee67461eSJoseph Mingrone 		       GET_BE_U_4(dupTSN));
7393340d773SGleb Smirnoff 	    }
7403340d773SGleb Smirnoff 	    break;
7413340d773SGleb Smirnoff 	  }
7423340d773SGleb Smirnoff 	default :
7433340d773SGleb Smirnoff 	  {
7443340d773SGleb Smirnoff 	    bp += chunkLengthRemaining;
7453340d773SGleb Smirnoff 	    sctpPacketLengthRemaining -= chunkLengthRemaining;
7463340d773SGleb Smirnoff 	    chunkLengthRemaining = 0;
747a90e161bSBill Fenner 	    break;
748a90e161bSBill Fenner 	  }
749a90e161bSBill Fenner 	}
7501de50e9fSSam Leffler 
7513340d773SGleb Smirnoff       /*
7523340d773SGleb Smirnoff        * Any extra stuff at the end of the chunk?
7533340d773SGleb Smirnoff        * XXX - report this?
7543340d773SGleb Smirnoff        */
7553340d773SGleb Smirnoff       bp += chunkLengthRemaining;
7563340d773SGleb Smirnoff       sctpPacketLengthRemaining -= chunkLengthRemaining;
7573340d773SGleb Smirnoff 
7583c602fabSXin LI       if (ndo->ndo_vflag < 2)
7591de50e9fSSam Leffler 	sep = ", (";
7603340d773SGleb Smirnoff 
7613340d773SGleb Smirnoff       if (align != 0) {
7623340d773SGleb Smirnoff 	/*
7633340d773SGleb Smirnoff 	 * Fail if the alignment padding isn't in the captured data.
7643340d773SGleb Smirnoff 	 * Otherwise, skip it.
7653340d773SGleb Smirnoff 	 */
766ee67461eSJoseph Mingrone 	ND_TCHECK_LEN(bp, align);
7673340d773SGleb Smirnoff 	bp += align;
7683340d773SGleb Smirnoff 	sctpPacketLengthRemaining -= align;
7693340d773SGleb Smirnoff       }
770a90e161bSBill Fenner     }
771f4d0c64aSSam Leffler     return;
772f4d0c64aSSam Leffler 
773f4d0c64aSSam Leffler trunc:
774ee67461eSJoseph Mingrone     nd_print_trunc(ndo);
775a90e161bSBill Fenner }
776