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