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 6704
63 #define CHAN_MP 6705
64 #define CHAN_LP 6706
65
66 static 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
isForCES_port(u_short Port)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
sctp_print(const u_char * bp,const u_char * bp2,u_int sctpPacketLength)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 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
397 trunc:
398 printf("[|sctp]");
399 return;
400 }
401