xref: /freebsd/contrib/tcpdump/print-sctp.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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[] _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 6700
63 #define CHAN_MP 6701
64 #define CHAN_LP 6702
65 
66 struct tok ForCES_channels[] = {
67 	{ CHAN_HP, "ForCES HP" },
68 	{ CHAN_MP, "ForCES MP" },
69 	{ CHAN_LP, "ForCES LP" },
70 	{ 0, NULL }
71 };
72 
73 static 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 
85 void 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 	  {
347 	    const struct sctpHBsender *hb;
348 
349 	    hb=(const struct sctpHBsender*)chunkDescPtr;
350 
351 	    printf("[HB REQ] ");
352 
353 	    break;
354 	  }
355 	case SCTP_HEARTBEAT_ACK :
356 	  printf("[HB ACK] ");
357 	  break;
358 	case SCTP_ABORT_ASSOCIATION :
359 	  printf("[ABORT] ");
360 	  break;
361 	case SCTP_SHUTDOWN :
362 	  printf("[SHUTDOWN] ");
363 	  break;
364 	case SCTP_SHUTDOWN_ACK :
365 	  printf("[SHUTDOWN ACK] ");
366 	  break;
367 	case SCTP_OPERATION_ERR :
368 	  printf("[OP ERR] ");
369 	  break;
370 	case SCTP_COOKIE_ECHO :
371 	  printf("[COOKIE ECHO] ");
372 	  break;
373 	case SCTP_COOKIE_ACK :
374 	  printf("[COOKIE ACK] ");
375 	  break;
376 	case SCTP_ECN_ECHO :
377 	  printf("[ECN ECHO] ");
378 	  break;
379 	case SCTP_ECN_CWR :
380 	  printf("[ECN CWR] ");
381 	  break;
382 	case SCTP_SHUTDOWN_COMPLETE :
383 	  printf("[SHUTDOWN COMPLETE] ");
384 	  break;
385 	case SCTP_FORWARD_CUM_TSN :
386 	  printf("[FOR CUM TSN] ");
387 	  break;
388 	case SCTP_RELIABLE_CNTL :
389 	  printf("[REL CTRL] ");
390 	  break;
391 	case SCTP_RELIABLE_CNTL_ACK :
392 	  printf("[REL CTRL ACK] ");
393 	  break;
394 	default :
395 	  printf("[Unknown chunk type: 0x%x]", chunkDescPtr->chunkID);
396 	  return;
397 	}
398 
399 	if (vflag < 2)
400 	  sep = ", (";
401     }
402     return;
403 
404 trunc:
405     printf("[|sctp]");
406     return;
407 }
408