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 2001/12/12 07:16:40 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 void *endPacketPtr; 78 u_short sourcePort, destPort; 79 int chunkCount; 80 struct sctpChunkDesc *chunkDescPtr; 81 void *nextChunk; 82 83 sctpPktHdr = (struct sctpHeader*) bp; 84 endPacketPtr = ((u_char*)((u_char*)sctpPktHdr+sctpPacketLength)); 85 86 if( (u_long) endPacketPtr > (u_long) snapend) 87 endPacketPtr = (void *) snapend; 88 ip = (struct ip *)bp2; 89 #ifdef INET6 90 if (IP_V(ip) == 6) 91 ip6 = (struct ip6_hdr *)bp2; 92 else 93 ip6 = NULL; 94 #endif /*INET6*/ 95 cp = (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 = (struct sctpChunkDesc *) ( (u_char*) sctpPktHdr + 149 sizeof(struct sctpHeader)); 150 chunkDescPtr != NULL && 151 ( (void *) ((u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc)) 152 <= endPacketPtr); 153 154 chunkDescPtr = (struct sctpChunkDesc *) nextChunk, chunkCount++) 155 { 156 u_short align; 157 u_char *chunkEnd; 158 159 chunkEnd = ((u_char*)chunkDescPtr + ntohs(chunkDescPtr->chunkLength)); 160 161 align=ntohs(chunkDescPtr->chunkLength) % 4; 162 if (align != 0) 163 align = 4 - align; 164 165 nextChunk = (void *) (chunkEnd + align); 166 167 printf("\n\t%d) ", chunkCount+1); 168 switch (chunkDescPtr->chunkID) 169 { 170 case SCTP_DATA : 171 { 172 struct sctpDataPart *dataHdrPtr; 173 174 printf("[DATA] "); 175 176 if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 177 == SCTP_DATA_UNORDERED) 178 printf("(U)"); 179 180 if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 181 == SCTP_DATA_FIRST_FRAG) 182 printf("(B)"); 183 184 if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 185 == SCTP_DATA_LAST_FRAG) 186 printf("(E)"); 187 188 if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 189 == SCTP_DATA_UNORDERED) 190 || 191 ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 192 == SCTP_DATA_FIRST_FRAG) 193 || 194 ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 195 == SCTP_DATA_LAST_FRAG) ) 196 printf(" "); 197 198 dataHdrPtr=(struct sctpDataPart*)(chunkDescPtr+1); 199 200 printf("[TSN: %u] ", (u_int32_t)ntohl(dataHdrPtr->TSN)); 201 printf("[SID: %u] ", ntohs(dataHdrPtr->streamId)); 202 printf("[SSEQ %u] ", ntohs(dataHdrPtr->sequence)); 203 printf("[PPID 0x%x] ", (u_int32_t)ntohl(dataHdrPtr->payloadtype)); 204 fflush(stdout); 205 206 if (vflag) /* if verbose output is specified */ 207 { /* at the command line */ 208 char *payloadPtr; 209 210 printf("[Payload"); 211 212 if (!xflag && !qflag) { 213 payloadPtr = (char *) (++dataHdrPtr); 214 printf(":"); 215 default_print(payloadPtr, 216 htons(chunkDescPtr->chunkLength)-1 - 217 sizeof(struct sctpDataPart)-sizeof(struct sctpChunkDesc)); 218 } else 219 printf("]"); 220 } 221 break; 222 } 223 case SCTP_INITIATION : 224 { 225 struct sctpInitiation *init; 226 227 printf("[INIT] "); 228 init=(struct sctpInitiation*)(chunkDescPtr+1); 229 printf("[init tag: %u] ", (u_int32_t)ntohl(init->initTag)); 230 printf("[rwnd: %u] ", (u_int32_t)ntohl(init->rcvWindowCredit)); 231 printf("[OS: %u] ", ntohs(init->NumPreopenStreams)); 232 printf("[MIS: %u] ", ntohs(init->MaxInboundStreams)); 233 printf("[init TSN: %u] ", (u_int32_t)ntohl(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 struct sctpInitiation *init; 245 246 printf("[INIT ACK] "); 247 init=(struct sctpInitiation*)(chunkDescPtr+1); 248 printf("[init tag: %u] ", (u_int32_t)ntohl(init->initTag)); 249 printf("[rwnd: %u] ", (u_int32_t)ntohl(init->rcvWindowCredit)); 250 printf("[OS: %u] ", ntohs(init->NumPreopenStreams)); 251 printf("[MIS: %u] ", ntohs(init->MaxInboundStreams)); 252 printf("[init TSN: %u] ", (u_int32_t)ntohl(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 struct sctpSelectiveAck *sack; 264 struct sctpSelectiveFrag *frag; 265 int fragNo, tsnNo; 266 u_long *dupTSN; 267 268 printf("[SACK] "); 269 sack=(struct sctpSelectiveAck*)(chunkDescPtr+1); 270 printf("[cum ack %u] ", (u_int32_t)ntohl(sack->highestConseqTSN)); 271 printf("[a_rwnd %u] ", (u_int32_t)ntohl(sack->updatedRwnd)); 272 printf("[#gap acks %u] ", ntohs(sack->numberOfdesc)); 273 printf("[#dup tsns %u] ", ntohs(sack->numDupTsns)); 274 275 276 /* print gaps */ 277 for (frag = ( (struct sctpSelectiveFrag *) 278 ((struct sctpSelectiveAck *) sack+1)), 279 fragNo=0; 280 (void *)frag < nextChunk && fragNo < ntohs(sack->numberOfdesc); 281 frag++, fragNo++) 282 printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ", 283 fragNo+1, 284 (u_int32_t)(ntohl(sack->highestConseqTSN) + ntohs(frag->fragmentStart)), 285 (u_int32_t)(ntohl(sack->highestConseqTSN) + ntohs(frag->fragmentEnd))); 286 287 288 /* print duplicate TSNs */ 289 for (dupTSN = (u_long*)frag, tsnNo=0; 290 (void *) dupTSN < nextChunk && tsnNo<ntohs(sack->numDupTsns); 291 dupTSN++, tsnNo++) 292 printf("\n\t\t[dup TSN #%u: %u] ", tsnNo+1, 293 (u_int32_t)ntohl(*dupTSN)); 294 295 break; 296 } 297 case SCTP_HEARTBEAT_REQUEST : 298 { 299 struct sctpHBsender *hb; 300 301 hb=(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 } 352