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