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