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