1 /* Copyright (c) 2001 NETLAB, Temple University 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 #ifndef lint 37 static const char rcsid[] _U_ = 38 "@(#) $Header: /tcpdump/master/tcpdump/print-sctp.c,v 1.21 2007-09-13 18:03:49 guy Exp $ (NETLAB/PEL)"; 39 #endif 40 41 #ifdef HAVE_CONFIG_H 42 #include "config.h" 43 #endif 44 45 #include <tcpdump-stdinc.h> 46 47 #include "sctpHeader.h" 48 #include "sctpConstants.h" 49 #include <assert.h> 50 51 #include <stdio.h> 52 #include <string.h> 53 54 #include "interface.h" 55 #include "addrtoname.h" 56 #include "extract.h" /* must come after interface.h */ 57 #include "ip.h" 58 #ifdef INET6 59 #include "ip6.h" 60 #endif 61 62 #define CHAN_HP 6700 63 #define CHAN_MP 6701 64 #define CHAN_LP 6702 65 66 struct tok ForCES_channels[] = { 67 { CHAN_HP, "ForCES HP" }, 68 { CHAN_MP, "ForCES MP" }, 69 { CHAN_LP, "ForCES LP" }, 70 { 0, NULL } 71 }; 72 73 static inline int isForCES_port(u_short Port) 74 { 75 if (Port == CHAN_HP) 76 return 1; 77 if (Port == CHAN_MP) 78 return 1; 79 if (Port == CHAN_LP) 80 return 1; 81 82 return 0; 83 } 84 85 void sctp_print(const u_char *bp, /* beginning of sctp packet */ 86 const u_char *bp2, /* beginning of enclosing */ 87 u_int sctpPacketLength) /* ip packet */ 88 { 89 const struct sctpHeader *sctpPktHdr; 90 const struct ip *ip; 91 #ifdef INET6 92 const struct ip6_hdr *ip6; 93 #endif 94 const void *endPacketPtr; 95 u_short sourcePort, destPort; 96 int chunkCount; 97 const struct sctpChunkDesc *chunkDescPtr; 98 const void *nextChunk; 99 const char *sep; 100 int isforces = 0; 101 102 103 sctpPktHdr = (const struct sctpHeader*) bp; 104 endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength; 105 106 if( (u_long) endPacketPtr > (u_long) snapend) 107 endPacketPtr = (const void *) snapend; 108 ip = (struct ip *)bp2; 109 #ifdef INET6 110 if (IP_V(ip) == 6) 111 ip6 = (const struct ip6_hdr *)bp2; 112 else 113 ip6 = NULL; 114 #endif /*INET6*/ 115 TCHECK(*sctpPktHdr); 116 117 if (sctpPacketLength < sizeof(struct sctpHeader)) 118 { 119 (void)printf("truncated-sctp - %ld bytes missing!", 120 (long)sctpPacketLength-sizeof(struct sctpHeader)); 121 return; 122 } 123 124 /* sctpPacketLength -= sizeof(struct sctpHeader); packet length */ 125 /* is now only as long as the payload */ 126 127 sourcePort = EXTRACT_16BITS(&sctpPktHdr->source); 128 destPort = EXTRACT_16BITS(&sctpPktHdr->destination); 129 130 #ifdef INET6 131 if (ip6) { 132 (void)printf("%s.%d > %s.%d: sctp", 133 ip6addr_string(&ip6->ip6_src), 134 sourcePort, 135 ip6addr_string(&ip6->ip6_dst), 136 destPort); 137 } else 138 #endif /*INET6*/ 139 { 140 (void)printf("%s.%d > %s.%d: sctp", 141 ipaddr_string(&ip->ip_src), 142 sourcePort, 143 ipaddr_string(&ip->ip_dst), 144 destPort); 145 } 146 fflush(stdout); 147 148 if (isForCES_port(sourcePort)) { 149 printf("[%s]", tok2str(ForCES_channels, NULL, sourcePort)); 150 isforces = 1; 151 } 152 if (isForCES_port(destPort)) { 153 printf("[%s]", tok2str(ForCES_channels, NULL, destPort)); 154 isforces = 1; 155 } 156 157 if (vflag >= 2) 158 sep = "\n\t"; 159 else 160 sep = " ("; 161 /* cycle through all chunks, printing information on each one */ 162 for (chunkCount = 0, 163 chunkDescPtr = (const struct sctpChunkDesc *) 164 ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader)); 165 chunkDescPtr != NULL && 166 ( (const void *) 167 ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc)) 168 <= endPacketPtr); 169 170 chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++) 171 { 172 u_int16_t chunkLength; 173 const u_char *chunkEnd; 174 u_int16_t align; 175 176 TCHECK(*chunkDescPtr); 177 chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength); 178 if (chunkLength < sizeof(*chunkDescPtr)) { 179 printf("%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength); 180 break; 181 } 182 183 TCHECK2(*((u_int8_t *)chunkDescPtr), chunkLength); 184 chunkEnd = ((const u_char*)chunkDescPtr + chunkLength); 185 186 align=chunkLength % 4; 187 if (align != 0) 188 align = 4 - align; 189 190 nextChunk = (const void *) (chunkEnd + align); 191 192 printf("%s%d) ", sep, chunkCount+1); 193 switch (chunkDescPtr->chunkID) 194 { 195 case SCTP_DATA : 196 { 197 const struct sctpDataPart *dataHdrPtr; 198 199 printf("[DATA] "); 200 201 if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 202 == SCTP_DATA_UNORDERED) 203 printf("(U)"); 204 205 if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 206 == SCTP_DATA_FIRST_FRAG) 207 printf("(B)"); 208 209 if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 210 == SCTP_DATA_LAST_FRAG) 211 printf("(E)"); 212 213 if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 214 == SCTP_DATA_UNORDERED) 215 || 216 ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 217 == SCTP_DATA_FIRST_FRAG) 218 || 219 ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 220 == SCTP_DATA_LAST_FRAG) ) 221 printf(" "); 222 223 dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1); 224 225 printf("[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN)); 226 printf("[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId)); 227 printf("[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence)); 228 printf("[PPID 0x%x] ", EXTRACT_32BITS(&dataHdrPtr->payloadtype)); 229 fflush(stdout); 230 if (isforces) { 231 const u_char *payloadPtr; 232 u_int chunksize = sizeof(struct sctpDataPart)+ 233 sizeof(struct sctpChunkDesc); 234 payloadPtr = (const u_char *) (dataHdrPtr + 1); 235 if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < 236 sizeof(struct sctpDataPart)+ 237 sizeof(struct sctpChunkDesc)+1) { 238 /* Less than 1 byte of chunk payload */ 239 printf("bogus ForCES chunk length %u]", 240 EXTRACT_16BITS(&chunkDescPtr->chunkLength)); 241 return; 242 } 243 244 forces_print(payloadPtr, EXTRACT_16BITS(&chunkDescPtr->chunkLength)- chunksize); 245 } else if (vflag >= 2) { /* if verbose output is specified */ 246 /* at the command line */ 247 const u_char *payloadPtr; 248 249 printf("[Payload"); 250 251 if (!suppress_default_print) { 252 payloadPtr = (const u_char *) (++dataHdrPtr); 253 printf(":"); 254 if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < 255 sizeof(struct sctpDataPart)+ 256 sizeof(struct sctpChunkDesc)+1) { 257 /* Less than 1 byte of chunk payload */ 258 printf("bogus chunk length %u]", 259 EXTRACT_16BITS(&chunkDescPtr->chunkLength)); 260 return; 261 } 262 default_print(payloadPtr, 263 EXTRACT_16BITS(&chunkDescPtr->chunkLength) - 264 (sizeof(struct sctpDataPart)+ 265 sizeof(struct sctpChunkDesc))); 266 } else 267 printf("]"); 268 } 269 break; 270 } 271 case SCTP_INITIATION : 272 { 273 const struct sctpInitiation *init; 274 275 printf("[INIT] "); 276 init=(const struct sctpInitiation*)(chunkDescPtr+1); 277 printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag)); 278 printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)); 279 printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)); 280 printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)); 281 printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)); 282 283 #if(0) /* ALC you can add code for optional params here */ 284 if( (init+1) < chunkEnd ) 285 printf(" @@@@@ UNFINISHED @@@@@@%s\n", 286 "Optional params present, but not printed."); 287 #endif 288 break; 289 } 290 case SCTP_INITIATION_ACK : 291 { 292 const struct sctpInitiation *init; 293 294 printf("[INIT ACK] "); 295 init=(const struct sctpInitiation*)(chunkDescPtr+1); 296 printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag)); 297 printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)); 298 printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)); 299 printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)); 300 printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)); 301 302 #if(0) /* ALC you can add code for optional params here */ 303 if( (init+1) < chunkEnd ) 304 printf(" @@@@@ UNFINISHED @@@@@@%s\n", 305 "Optional params present, but not printed."); 306 #endif 307 break; 308 } 309 case SCTP_SELECTIVE_ACK: 310 { 311 const struct sctpSelectiveAck *sack; 312 const struct sctpSelectiveFrag *frag; 313 int fragNo, tsnNo; 314 const u_char *dupTSN; 315 316 printf("[SACK] "); 317 sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1); 318 printf("[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN)); 319 printf("[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd)); 320 printf("[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc)); 321 printf("[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns)); 322 323 324 /* print gaps */ 325 for (frag = ( (const struct sctpSelectiveFrag *) 326 ((const struct sctpSelectiveAck *) sack+1)), 327 fragNo=0; 328 (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc); 329 frag++, fragNo++) 330 printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ", 331 fragNo+1, 332 EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart), 333 EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd)); 334 335 336 /* print duplicate TSNs */ 337 for (dupTSN = (const u_char *)frag, tsnNo=0; 338 (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns); 339 dupTSN += 4, tsnNo++) 340 printf("\n\t\t[dup TSN #%u: %u] ", tsnNo+1, 341 EXTRACT_32BITS(dupTSN)); 342 343 break; 344 } 345 case SCTP_HEARTBEAT_REQUEST : 346 { 347 const struct sctpHBsender *hb; 348 349 hb=(const struct sctpHBsender*)chunkDescPtr; 350 351 printf("[HB REQ] "); 352 353 break; 354 } 355 case SCTP_HEARTBEAT_ACK : 356 printf("[HB ACK] "); 357 break; 358 case SCTP_ABORT_ASSOCIATION : 359 printf("[ABORT] "); 360 break; 361 case SCTP_SHUTDOWN : 362 printf("[SHUTDOWN] "); 363 break; 364 case SCTP_SHUTDOWN_ACK : 365 printf("[SHUTDOWN ACK] "); 366 break; 367 case SCTP_OPERATION_ERR : 368 printf("[OP ERR] "); 369 break; 370 case SCTP_COOKIE_ECHO : 371 printf("[COOKIE ECHO] "); 372 break; 373 case SCTP_COOKIE_ACK : 374 printf("[COOKIE ACK] "); 375 break; 376 case SCTP_ECN_ECHO : 377 printf("[ECN ECHO] "); 378 break; 379 case SCTP_ECN_CWR : 380 printf("[ECN CWR] "); 381 break; 382 case SCTP_SHUTDOWN_COMPLETE : 383 printf("[SHUTDOWN COMPLETE] "); 384 break; 385 case SCTP_FORWARD_CUM_TSN : 386 printf("[FOR CUM TSN] "); 387 break; 388 case SCTP_RELIABLE_CNTL : 389 printf("[REL CTRL] "); 390 break; 391 case SCTP_RELIABLE_CNTL_ACK : 392 printf("[REL CTRL ACK] "); 393 break; 394 default : 395 printf("[Unknown chunk type: 0x%x]", chunkDescPtr->chunkID); 396 return; 397 } 398 399 if (vflag < 2) 400 sep = ", ("; 401 } 402 return; 403 404 trunc: 405 printf("[|sctp]"); 406 return; 407 } 408