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