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