1 /* 2 * Copyright (c) 2001 Protocol Engineering Lab, University of Delaware 3 * 4 * Jerry Heinz <gheinz@astro.temple.edu> 5 * John Fiore <jfiore@joda.cis.temple.edu> 6 * Armando L. Caro Jr. <acaro@cis.udel.edu> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the University nor of the Laboratory may be used 20 * to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static const char rcsid[] _U_ = 40 "@(#) Header: /tcpdump/master/tcpdump/print-sctp.c,v 1.21 2007-09-13 18:03:49 guy Exp (NETLAB/PEL)"; 41 #else 42 __RCSID("$NetBSD: print-sctp.c,v 1.5 2013/12/31 17:33:31 christos Exp $"); 43 #endif 44 #endif 45 46 #ifdef HAVE_CONFIG_H 47 #include "config.h" 48 #endif 49 50 #include <tcpdump-stdinc.h> 51 52 #include "sctpHeader.h" 53 #include "sctpConstants.h" 54 #include <assert.h> 55 56 #include <stdio.h> 57 #include <string.h> 58 59 #include "interface.h" 60 #include "addrtoname.h" 61 #include "extract.h" /* must come after interface.h */ 62 #include "ip.h" 63 #ifdef INET6 64 #include "ip6.h" 65 #endif 66 67 #define CHAN_HP 6704 68 #define CHAN_MP 6705 69 #define CHAN_LP 6706 70 71 static const struct tok ForCES_channels[] = { 72 { CHAN_HP, "ForCES HP" }, 73 { CHAN_MP, "ForCES MP" }, 74 { CHAN_LP, "ForCES LP" }, 75 { 0, NULL } 76 }; 77 78 static inline int isForCES_port(u_short Port) 79 { 80 if (Port == CHAN_HP) 81 return 1; 82 if (Port == CHAN_MP) 83 return 1; 84 if (Port == CHAN_LP) 85 return 1; 86 87 return 0; 88 } 89 90 void sctp_print(const u_char *bp, /* beginning of sctp packet */ 91 const u_char *bp2, /* beginning of enclosing */ 92 u_int sctpPacketLength) /* ip packet */ 93 { 94 const struct sctpHeader *sctpPktHdr; 95 const struct ip *ip; 96 #ifdef INET6 97 const struct ip6_hdr *ip6; 98 #endif 99 const void *endPacketPtr; 100 u_short sourcePort, destPort; 101 int chunkCount; 102 const struct sctpChunkDesc *chunkDescPtr; 103 const void *nextChunk; 104 const char *sep; 105 int isforces = 0; 106 107 108 sctpPktHdr = (const struct sctpHeader*) bp; 109 endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength; 110 111 if( (u_long) endPacketPtr > (u_long) snapend) 112 endPacketPtr = (const void *) snapend; 113 ip = (struct ip *)bp2; 114 #ifdef INET6 115 if (IP_V(ip) == 6) 116 ip6 = (const struct ip6_hdr *)bp2; 117 else 118 ip6 = NULL; 119 #endif /*INET6*/ 120 TCHECK(*sctpPktHdr); 121 122 if (sctpPacketLength < sizeof(struct sctpHeader)) 123 { 124 (void)printf("truncated-sctp - %ld bytes missing!", 125 (long)sctpPacketLength-sizeof(struct sctpHeader)); 126 return; 127 } 128 129 /* sctpPacketLength -= sizeof(struct sctpHeader); packet length */ 130 /* is now only as long as the payload */ 131 132 sourcePort = EXTRACT_16BITS(&sctpPktHdr->source); 133 destPort = EXTRACT_16BITS(&sctpPktHdr->destination); 134 135 #ifdef INET6 136 if (ip6) { 137 (void)printf("%s.%d > %s.%d: sctp", 138 ip6addr_string(&ip6->ip6_src), 139 sourcePort, 140 ip6addr_string(&ip6->ip6_dst), 141 destPort); 142 } else 143 #endif /*INET6*/ 144 { 145 (void)printf("%s.%d > %s.%d: sctp", 146 ipaddr_string(&ip->ip_src), 147 sourcePort, 148 ipaddr_string(&ip->ip_dst), 149 destPort); 150 } 151 fflush(stdout); 152 153 if (isForCES_port(sourcePort)) { 154 printf("[%s]", tok2str(ForCES_channels, NULL, sourcePort)); 155 isforces = 1; 156 } 157 if (isForCES_port(destPort)) { 158 printf("[%s]", tok2str(ForCES_channels, NULL, destPort)); 159 isforces = 1; 160 } 161 162 if (vflag >= 2) 163 sep = "\n\t"; 164 else 165 sep = " ("; 166 /* cycle through all chunks, printing information on each one */ 167 for (chunkCount = 0, 168 chunkDescPtr = (const struct sctpChunkDesc *) 169 ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader)); 170 chunkDescPtr != NULL && 171 ( (const void *) 172 ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc)) 173 <= endPacketPtr); 174 175 chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++) 176 { 177 u_int16_t chunkLength; 178 const u_char *chunkEnd; 179 u_int16_t align; 180 181 TCHECK(*chunkDescPtr); 182 chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength); 183 if (chunkLength < sizeof(*chunkDescPtr)) { 184 printf("%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength); 185 break; 186 } 187 188 TCHECK2(*((u_int8_t *)chunkDescPtr), chunkLength); 189 chunkEnd = ((const u_char*)chunkDescPtr + chunkLength); 190 191 align=chunkLength % 4; 192 if (align != 0) 193 align = 4 - align; 194 195 nextChunk = (const void *) (chunkEnd + align); 196 197 printf("%s%d) ", sep, chunkCount+1); 198 switch (chunkDescPtr->chunkID) 199 { 200 case SCTP_DATA : 201 { 202 const struct sctpDataPart *dataHdrPtr; 203 204 printf("[DATA] "); 205 206 if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 207 == SCTP_DATA_UNORDERED) 208 printf("(U)"); 209 210 if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 211 == SCTP_DATA_FIRST_FRAG) 212 printf("(B)"); 213 214 if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 215 == SCTP_DATA_LAST_FRAG) 216 printf("(E)"); 217 218 if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 219 == SCTP_DATA_UNORDERED) 220 || 221 ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 222 == SCTP_DATA_FIRST_FRAG) 223 || 224 ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 225 == SCTP_DATA_LAST_FRAG) ) 226 printf(" "); 227 228 dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1); 229 230 printf("[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN)); 231 printf("[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId)); 232 printf("[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence)); 233 printf("[PPID 0x%x] ", EXTRACT_32BITS(&dataHdrPtr->payloadtype)); 234 fflush(stdout); 235 if (isforces) { 236 const u_char *payloadPtr; 237 u_int chunksize = sizeof(struct sctpDataPart)+ 238 sizeof(struct sctpChunkDesc); 239 payloadPtr = (const u_char *) (dataHdrPtr + 1); 240 if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < 241 sizeof(struct sctpDataPart)+ 242 sizeof(struct sctpChunkDesc)+1) { 243 /* Less than 1 byte of chunk payload */ 244 printf("bogus ForCES chunk length %u]", 245 EXTRACT_16BITS(&chunkDescPtr->chunkLength)); 246 return; 247 } 248 249 forces_print(payloadPtr, EXTRACT_16BITS(&chunkDescPtr->chunkLength)- chunksize); 250 } else if (vflag >= 2) { /* if verbose output is specified */ 251 /* at the command line */ 252 const u_char *payloadPtr; 253 254 printf("[Payload"); 255 256 if (!suppress_default_print) { 257 payloadPtr = (const u_char *) (++dataHdrPtr); 258 printf(":"); 259 if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < 260 sizeof(struct sctpDataPart)+ 261 sizeof(struct sctpChunkDesc)+1) { 262 /* Less than 1 byte of chunk payload */ 263 printf("bogus chunk length %u]", 264 EXTRACT_16BITS(&chunkDescPtr->chunkLength)); 265 return; 266 } 267 default_print(payloadPtr, 268 EXTRACT_16BITS(&chunkDescPtr->chunkLength) - 269 (sizeof(struct sctpDataPart)+ 270 sizeof(struct sctpChunkDesc))); 271 } else 272 printf("]"); 273 } 274 break; 275 } 276 case SCTP_INITIATION : 277 { 278 const struct sctpInitiation *init; 279 280 printf("[INIT] "); 281 init=(const struct sctpInitiation*)(chunkDescPtr+1); 282 printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag)); 283 printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)); 284 printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)); 285 printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)); 286 printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)); 287 288 #if(0) /* ALC you can add code for optional params here */ 289 if( (init+1) < chunkEnd ) 290 printf(" @@@@@ UNFINISHED @@@@@@%s\n", 291 "Optional params present, but not printed."); 292 #endif 293 break; 294 } 295 case SCTP_INITIATION_ACK : 296 { 297 const struct sctpInitiation *init; 298 299 printf("[INIT ACK] "); 300 init=(const struct sctpInitiation*)(chunkDescPtr+1); 301 printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag)); 302 printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)); 303 printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)); 304 printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)); 305 printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)); 306 307 #if(0) /* ALC you can add code for optional params here */ 308 if( (init+1) < chunkEnd ) 309 printf(" @@@@@ UNFINISHED @@@@@@%s\n", 310 "Optional params present, but not printed."); 311 #endif 312 break; 313 } 314 case SCTP_SELECTIVE_ACK: 315 { 316 const struct sctpSelectiveAck *sack; 317 const struct sctpSelectiveFrag *frag; 318 int fragNo, tsnNo; 319 const u_char *dupTSN; 320 321 printf("[SACK] "); 322 sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1); 323 printf("[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN)); 324 printf("[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd)); 325 printf("[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc)); 326 printf("[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns)); 327 328 329 /* print gaps */ 330 for (frag = ( (const struct sctpSelectiveFrag *) 331 ((const struct sctpSelectiveAck *) sack+1)), 332 fragNo=0; 333 (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc); 334 frag++, fragNo++) 335 printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ", 336 fragNo+1, 337 EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart), 338 EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd)); 339 340 341 /* print duplicate TSNs */ 342 for (dupTSN = (const u_char *)frag, tsnNo=0; 343 (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns); 344 dupTSN += 4, tsnNo++) 345 printf("\n\t\t[dup TSN #%u: %u] ", tsnNo+1, 346 EXTRACT_32BITS(dupTSN)); 347 348 break; 349 } 350 case SCTP_HEARTBEAT_REQUEST : 351 printf("[HB REQ] "); 352 break; 353 case SCTP_HEARTBEAT_ACK : 354 printf("[HB ACK] "); 355 break; 356 case SCTP_ABORT_ASSOCIATION : 357 printf("[ABORT] "); 358 break; 359 case SCTP_SHUTDOWN : 360 printf("[SHUTDOWN] "); 361 break; 362 case SCTP_SHUTDOWN_ACK : 363 printf("[SHUTDOWN ACK] "); 364 break; 365 case SCTP_OPERATION_ERR : 366 printf("[OP ERR] "); 367 break; 368 case SCTP_COOKIE_ECHO : 369 printf("[COOKIE ECHO] "); 370 break; 371 case SCTP_COOKIE_ACK : 372 printf("[COOKIE ACK] "); 373 break; 374 case SCTP_ECN_ECHO : 375 printf("[ECN ECHO] "); 376 break; 377 case SCTP_ECN_CWR : 378 printf("[ECN CWR] "); 379 break; 380 case SCTP_SHUTDOWN_COMPLETE : 381 printf("[SHUTDOWN COMPLETE] "); 382 break; 383 case SCTP_FORWARD_CUM_TSN : 384 printf("[FOR CUM TSN] "); 385 break; 386 case SCTP_RELIABLE_CNTL : 387 printf("[REL CTRL] "); 388 break; 389 case SCTP_RELIABLE_CNTL_ACK : 390 printf("[REL CTRL ACK] "); 391 break; 392 default : 393 printf("[Unknown chunk type: 0x%x]", chunkDescPtr->chunkID); 394 return; 395 } 396 397 if (vflag < 2) 398 sep = ", ("; 399 } 400 return; 401 402 trunc: 403 printf("[|sctp]"); 404 return; 405 } 406