198524Sfenner/* Copyright (c) 2001 NETLAB, Temple University 298524Sfenner * Copyright (c) 2001 Protocol Engineering Lab, University of Delaware 398524Sfenner * 498524Sfenner * Jerry Heinz <gheinz@astro.temple.edu> 598524Sfenner * John Fiore <jfiore@joda.cis.temple.edu> 698524Sfenner * Armando L. Caro Jr. <acaro@cis.udel.edu> 798524Sfenner * 898524Sfenner * Redistribution and use in source and binary forms, with or without 998524Sfenner * modification, are permitted provided that the following conditions 1098524Sfenner * are met: 1198524Sfenner * 1298524Sfenner * 1. Redistributions of source code must retain the above copyright 1398524Sfenner * notice, this list of conditions and the following disclaimer. 1498524Sfenner * 1598524Sfenner * 2. Redistributions in binary form must reproduce the above copyright 1698524Sfenner * notice, this list of conditions and the following disclaimer in the 1798524Sfenner * documentation and/or other materials provided with the distribution. 1898524Sfenner * 1998524Sfenner * 3. Neither the name of the University nor of the Laboratory may be used 2098524Sfenner * to endorse or promote products derived from this software without 2198524Sfenner * specific prior written permission. 2298524Sfenner * 2398524Sfenner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2498524Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2598524Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2698524Sfenner * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2798524Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2898524Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2998524Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3098524Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3198524Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3298524Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3398524Sfenner * SUCH DAMAGE. 3498524Sfenner */ 3598524Sfenner 3698524Sfenner#ifndef lint 37127668Sbmsstatic const char rcsid[] _U_ = 38190207Srpaulo"@(#) $Header: /tcpdump/master/tcpdump/print-sctp.c,v 1.21 2007-09-13 18:03:49 guy Exp $ (NETLAB/PEL)"; 3998524Sfenner#endif 4098524Sfenner 4198524Sfenner#ifdef HAVE_CONFIG_H 4298524Sfenner#include "config.h" 4398524Sfenner#endif 4498524Sfenner 45127668Sbms#include <tcpdump-stdinc.h> 4698524Sfenner 4798524Sfenner#include "sctpHeader.h" 4898524Sfenner#include "sctpConstants.h" 4998524Sfenner#include <assert.h> 5098524Sfenner 5198524Sfenner#include <stdio.h> 5298524Sfenner#include <string.h> 5398524Sfenner 5498524Sfenner#include "interface.h" 5598524Sfenner#include "addrtoname.h" 5698524Sfenner#include "extract.h" /* must come after interface.h */ 5798524Sfenner#include "ip.h" 5898524Sfenner#ifdef INET6 5998524Sfenner#include "ip6.h" 6098524Sfenner#endif 6198524Sfenner 62235530Sdelphij#define CHAN_HP 6704 63235530Sdelphij#define CHAN_MP 6705 64235530Sdelphij#define CHAN_LP 6706 65214478Srpaulo 66214478Srpaulostruct tok ForCES_channels[] = { 67214478Srpaulo { CHAN_HP, "ForCES HP" }, 68214478Srpaulo { CHAN_MP, "ForCES MP" }, 69214478Srpaulo { CHAN_LP, "ForCES LP" }, 70214478Srpaulo { 0, NULL } 71214478Srpaulo}; 72214478Srpaulo 73214478Srpaulostatic inline int isForCES_port(u_short Port) 74214478Srpaulo{ 75214478Srpaulo if (Port == CHAN_HP) 76214478Srpaulo return 1; 77214478Srpaulo if (Port == CHAN_MP) 78214478Srpaulo return 1; 79214478Srpaulo if (Port == CHAN_LP) 80214478Srpaulo return 1; 81214478Srpaulo 82214478Srpaulo return 0; 83214478Srpaulo} 84214478Srpaulo 8598524Sfennervoid sctp_print(const u_char *bp, /* beginning of sctp packet */ 8698524Sfenner const u_char *bp2, /* beginning of enclosing */ 8798524Sfenner u_int sctpPacketLength) /* ip packet */ 88127668Sbms{ 8998524Sfenner const struct sctpHeader *sctpPktHdr; 9098524Sfenner const struct ip *ip; 9198524Sfenner#ifdef INET6 9298524Sfenner const struct ip6_hdr *ip6; 9398524Sfenner#endif 94111726Sfenner const void *endPacketPtr; 9598524Sfenner u_short sourcePort, destPort; 9698524Sfenner int chunkCount; 97111726Sfenner const struct sctpChunkDesc *chunkDescPtr; 98111726Sfenner const void *nextChunk; 99146773Ssam const char *sep; 100214478Srpaulo int isforces = 0; 10198524Sfenner 102214478Srpaulo 103111726Sfenner sctpPktHdr = (const struct sctpHeader*) bp; 104111726Sfenner endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength; 105127668Sbms 10698524Sfenner if( (u_long) endPacketPtr > (u_long) snapend) 107111726Sfenner endPacketPtr = (const void *) snapend; 10898524Sfenner ip = (struct ip *)bp2; 10998524Sfenner#ifdef INET6 11098524Sfenner if (IP_V(ip) == 6) 111111726Sfenner ip6 = (const struct ip6_hdr *)bp2; 11298524Sfenner else 11398524Sfenner ip6 = NULL; 11498524Sfenner#endif /*INET6*/ 115147899Ssam TCHECK(*sctpPktHdr); 11698524Sfenner 117127668Sbms if (sctpPacketLength < sizeof(struct sctpHeader)) 11898524Sfenner { 119127668Sbms (void)printf("truncated-sctp - %ld bytes missing!", 12098524Sfenner (long)sctpPacketLength-sizeof(struct sctpHeader)); 12198524Sfenner return; 12298524Sfenner } 123127668Sbms 12498524Sfenner /* sctpPacketLength -= sizeof(struct sctpHeader); packet length */ 12598524Sfenner /* is now only as long as the payload */ 12698524Sfenner 127127668Sbms sourcePort = EXTRACT_16BITS(&sctpPktHdr->source); 128127668Sbms destPort = EXTRACT_16BITS(&sctpPktHdr->destination); 129127668Sbms 13098524Sfenner#ifdef INET6 13198524Sfenner if (ip6) { 132127668Sbms (void)printf("%s.%d > %s.%d: sctp", 133127668Sbms ip6addr_string(&ip6->ip6_src), 134127668Sbms sourcePort, 135127668Sbms ip6addr_string(&ip6->ip6_dst), 136127668Sbms destPort); 13798524Sfenner } else 13898524Sfenner#endif /*INET6*/ 13998524Sfenner { 140127668Sbms (void)printf("%s.%d > %s.%d: sctp", 141127668Sbms ipaddr_string(&ip->ip_src), 142127668Sbms sourcePort, 143127668Sbms ipaddr_string(&ip->ip_dst), 144127668Sbms destPort); 14598524Sfenner } 14698524Sfenner fflush(stdout); 14798524Sfenner 148214478Srpaulo if (isForCES_port(sourcePort)) { 149214478Srpaulo printf("[%s]", tok2str(ForCES_channels, NULL, sourcePort)); 150214478Srpaulo isforces = 1; 151214478Srpaulo } 152214478Srpaulo if (isForCES_port(destPort)) { 153214478Srpaulo printf("[%s]", tok2str(ForCES_channels, NULL, destPort)); 154214478Srpaulo isforces = 1; 155214478Srpaulo } 156214478Srpaulo 157146773Ssam if (vflag >= 2) 158146773Ssam sep = "\n\t"; 159146773Ssam else 160146773Ssam sep = " ("; 16198524Sfenner /* cycle through all chunks, printing information on each one */ 162127668Sbms for (chunkCount = 0, 163111726Sfenner chunkDescPtr = (const struct sctpChunkDesc *) 164111726Sfenner ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader)); 16598524Sfenner chunkDescPtr != NULL && 166111726Sfenner ( (const void *) 167111726Sfenner ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc)) 16898524Sfenner <= endPacketPtr); 169127668Sbms 170111726Sfenner chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++) 17198524Sfenner { 172147899Ssam u_int16_t chunkLength; 173111726Sfenner const u_char *chunkEnd; 174147899Ssam u_int16_t align; 175127668Sbms 176147899Ssam TCHECK(*chunkDescPtr); 177147899Ssam chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength); 178147899Ssam if (chunkLength < sizeof(*chunkDescPtr)) { 179147899Ssam printf("%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength); 180147899Ssam break; 181147899Ssam } 182127668Sbms 183147899Ssam TCHECK2(*((u_int8_t *)chunkDescPtr), chunkLength); 184147899Ssam chunkEnd = ((const u_char*)chunkDescPtr + chunkLength); 185147899Ssam 186147899Ssam align=chunkLength % 4; 18798524Sfenner if (align != 0) 18898524Sfenner align = 4 - align; 18998524Sfenner 190111726Sfenner nextChunk = (const void *) (chunkEnd + align); 19198524Sfenner 192146773Ssam printf("%s%d) ", sep, chunkCount+1); 19398524Sfenner switch (chunkDescPtr->chunkID) 19498524Sfenner { 19598524Sfenner case SCTP_DATA : 19698524Sfenner { 197111726Sfenner const struct sctpDataPart *dataHdrPtr; 198127668Sbms 19998524Sfenner printf("[DATA] "); 200127668Sbms 201127668Sbms if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 20298524Sfenner == SCTP_DATA_UNORDERED) 20398524Sfenner printf("(U)"); 20498524Sfenner 205127668Sbms if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 20698524Sfenner == SCTP_DATA_FIRST_FRAG) 20798524Sfenner printf("(B)"); 208127668Sbms 209127668Sbms if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 21098524Sfenner == SCTP_DATA_LAST_FRAG) 21198524Sfenner printf("(E)"); 21298524Sfenner 213127668Sbms if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 214127668Sbms == SCTP_DATA_UNORDERED) 21598524Sfenner || 216127668Sbms ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 21798524Sfenner == SCTP_DATA_FIRST_FRAG) 21898524Sfenner || 219127668Sbms ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 22098524Sfenner == SCTP_DATA_LAST_FRAG) ) 22198524Sfenner printf(" "); 22298524Sfenner 223111726Sfenner dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1); 224127668Sbms 225127668Sbms printf("[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN)); 226127668Sbms printf("[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId)); 227127668Sbms printf("[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence)); 228127668Sbms printf("[PPID 0x%x] ", EXTRACT_32BITS(&dataHdrPtr->payloadtype)); 22998524Sfenner fflush(stdout); 230214478Srpaulo if (isforces) { 231214478Srpaulo const u_char *payloadPtr; 232214478Srpaulo u_int chunksize = sizeof(struct sctpDataPart)+ 233214478Srpaulo sizeof(struct sctpChunkDesc); 234214478Srpaulo payloadPtr = (const u_char *) (dataHdrPtr + 1); 235214478Srpaulo if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < 236214478Srpaulo sizeof(struct sctpDataPart)+ 237214478Srpaulo sizeof(struct sctpChunkDesc)+1) { 238214478Srpaulo /* Less than 1 byte of chunk payload */ 239214478Srpaulo printf("bogus ForCES chunk length %u]", 240214478Srpaulo EXTRACT_16BITS(&chunkDescPtr->chunkLength)); 241214478Srpaulo return; 242214478Srpaulo } 24398524Sfenner 244214478Srpaulo forces_print(payloadPtr, EXTRACT_16BITS(&chunkDescPtr->chunkLength)- chunksize); 245214478Srpaulo } else if (vflag >= 2) { /* if verbose output is specified */ 246214478Srpaulo /* at the command line */ 247111726Sfenner const u_char *payloadPtr; 248127668Sbms 24998524Sfenner printf("[Payload"); 25098524Sfenner 251162017Ssam if (!suppress_default_print) { 252111726Sfenner payloadPtr = (const u_char *) (++dataHdrPtr); 25398524Sfenner printf(":"); 254214478Srpaulo if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) < 255127668Sbms sizeof(struct sctpDataPart)+ 256127668Sbms sizeof(struct sctpChunkDesc)+1) { 257172683Smlaier /* Less than 1 byte of chunk payload */ 258127668Sbms printf("bogus chunk length %u]", 259214478Srpaulo EXTRACT_16BITS(&chunkDescPtr->chunkLength)); 260127668Sbms return; 261127668Sbms } 26298524Sfenner default_print(payloadPtr, 263214478Srpaulo EXTRACT_16BITS(&chunkDescPtr->chunkLength) - 264127668Sbms (sizeof(struct sctpDataPart)+ 265172683Smlaier sizeof(struct sctpChunkDesc))); 26698524Sfenner } else 26798524Sfenner printf("]"); 26898524Sfenner } 26998524Sfenner break; 27098524Sfenner } 27198524Sfenner case SCTP_INITIATION : 27298524Sfenner { 273111726Sfenner const struct sctpInitiation *init; 27498524Sfenner 27598524Sfenner printf("[INIT] "); 276111726Sfenner init=(const struct sctpInitiation*)(chunkDescPtr+1); 277127668Sbms printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag)); 278127668Sbms printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)); 279127668Sbms printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)); 280127668Sbms printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)); 281127668Sbms printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)); 28298524Sfenner 28398524Sfenner#if(0) /* ALC you can add code for optional params here */ 28498524Sfenner if( (init+1) < chunkEnd ) 28598524Sfenner printf(" @@@@@ UNFINISHED @@@@@@%s\n", 28698524Sfenner "Optional params present, but not printed."); 28798524Sfenner#endif 28898524Sfenner break; 28998524Sfenner } 29098524Sfenner case SCTP_INITIATION_ACK : 29198524Sfenner { 292111726Sfenner const struct sctpInitiation *init; 293127668Sbms 29498524Sfenner printf("[INIT ACK] "); 295111726Sfenner init=(const struct sctpInitiation*)(chunkDescPtr+1); 296127668Sbms printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag)); 297127668Sbms printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)); 298127668Sbms printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)); 299127668Sbms printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)); 300127668Sbms printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)); 301127668Sbms 30298524Sfenner#if(0) /* ALC you can add code for optional params here */ 30398524Sfenner if( (init+1) < chunkEnd ) 30498524Sfenner printf(" @@@@@ UNFINISHED @@@@@@%s\n", 30598524Sfenner "Optional params present, but not printed."); 30698524Sfenner#endif 30798524Sfenner break; 30898524Sfenner } 30998524Sfenner case SCTP_SELECTIVE_ACK: 31098524Sfenner { 311111726Sfenner const struct sctpSelectiveAck *sack; 312127668Sbms const struct sctpSelectiveFrag *frag; 31398524Sfenner int fragNo, tsnNo; 314147899Ssam const u_char *dupTSN; 31598524Sfenner 31698524Sfenner printf("[SACK] "); 317111726Sfenner sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1); 318127668Sbms printf("[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN)); 319127668Sbms printf("[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd)); 320127668Sbms printf("[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc)); 321127668Sbms printf("[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns)); 322127668Sbms 323127668Sbms 32498524Sfenner /* print gaps */ 325111726Sfenner for (frag = ( (const struct sctpSelectiveFrag *) 326111726Sfenner ((const struct sctpSelectiveAck *) sack+1)), 32798524Sfenner fragNo=0; 328127668Sbms (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc); 32998524Sfenner frag++, fragNo++) 330127668Sbms printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ", 33198524Sfenner fragNo+1, 332127668Sbms EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart), 333127668Sbms EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd)); 33498524Sfenner 335127668Sbms 33698524Sfenner /* print duplicate TSNs */ 337147899Ssam for (dupTSN = (const u_char *)frag, tsnNo=0; 338127668Sbms (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns); 339147899Ssam dupTSN += 4, tsnNo++) 34098524Sfenner printf("\n\t\t[dup TSN #%u: %u] ", tsnNo+1, 341127668Sbms EXTRACT_32BITS(dupTSN)); 34298524Sfenner 34398524Sfenner break; 34498524Sfenner } 34598524Sfenner case SCTP_HEARTBEAT_REQUEST : 34698524Sfenner { 347111726Sfenner const struct sctpHBsender *hb; 34898524Sfenner 349111726Sfenner hb=(const struct sctpHBsender*)chunkDescPtr; 35098524Sfenner 35198524Sfenner printf("[HB REQ] "); 352127668Sbms 35398524Sfenner break; 35498524Sfenner } 35598524Sfenner case SCTP_HEARTBEAT_ACK : 35698524Sfenner printf("[HB ACK] "); 35798524Sfenner break; 35898524Sfenner case SCTP_ABORT_ASSOCIATION : 35998524Sfenner printf("[ABORT] "); 36098524Sfenner break; 36198524Sfenner case SCTP_SHUTDOWN : 36298524Sfenner printf("[SHUTDOWN] "); 36398524Sfenner break; 36498524Sfenner case SCTP_SHUTDOWN_ACK : 36598524Sfenner printf("[SHUTDOWN ACK] "); 36698524Sfenner break; 36798524Sfenner case SCTP_OPERATION_ERR : 36898524Sfenner printf("[OP ERR] "); 36998524Sfenner break; 37098524Sfenner case SCTP_COOKIE_ECHO : 37198524Sfenner printf("[COOKIE ECHO] "); 37298524Sfenner break; 37398524Sfenner case SCTP_COOKIE_ACK : 37498524Sfenner printf("[COOKIE ACK] "); 37598524Sfenner break; 37698524Sfenner case SCTP_ECN_ECHO : 37798524Sfenner printf("[ECN ECHO] "); 37898524Sfenner break; 379127668Sbms case SCTP_ECN_CWR : 38098524Sfenner printf("[ECN CWR] "); 38198524Sfenner break; 38298524Sfenner case SCTP_SHUTDOWN_COMPLETE : 38398524Sfenner printf("[SHUTDOWN COMPLETE] "); 38498524Sfenner break; 38598524Sfenner case SCTP_FORWARD_CUM_TSN : 38698524Sfenner printf("[FOR CUM TSN] "); 38798524Sfenner break; 38898524Sfenner case SCTP_RELIABLE_CNTL : 38998524Sfenner printf("[REL CTRL] "); 39098524Sfenner break; 39198524Sfenner case SCTP_RELIABLE_CNTL_ACK : 39298524Sfenner printf("[REL CTRL ACK] "); 39398524Sfenner break; 39498524Sfenner default : 39598524Sfenner printf("[Unknown chunk type: 0x%x]", chunkDescPtr->chunkID); 39698524Sfenner return; 39798524Sfenner } 398146773Ssam 399146773Ssam if (vflag < 2) 400146773Ssam sep = ", ("; 40198524Sfenner } 402147899Ssam return; 403147899Ssam 404147899Ssamtrunc: 405147899Ssam printf("[|sctp]"); 406147899Ssam return; 40798524Sfenner} 408