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
62236192Sdelphij#define CHAN_HP 6704
63236192Sdelphij#define CHAN_MP 6705
64236192Sdelphij#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