]> The Tcpdump Group git mirrors - tcpdump/blob - print-sctp.c
CARP: NDOize
[tcpdump] / print-sctp.c
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 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <tcpdump-stdinc.h>
41
42 #include <assert.h>
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include "interface.h"
48 #include "addrtoname.h"
49 #include "extract.h" /* must come after interface.h */
50 #include "ip.h"
51 #ifdef INET6
52 #include "ip6.h"
53 #endif
54
55 /* Definitions from:
56 *
57 * SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola
58 *
59 * Redistribution and use in source and binary forms, with or without
60 * modification, are permitted provided that the following conditions
61 * are met:
62 *
63 * 1. Redistributions of source code must retain the above copyright
64 * notice, this list of conditions and the following disclaimer.
65 *
66 * 2. Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 *
70 * 3. Neither the name of Cisco nor of Motorola may be used
71 * to endorse or promote products derived from this software without
72 * specific prior written permission.
73 *
74 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
75 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
78 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
79 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
80 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
83 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
84 * SUCH DAMAGE.
85 *
86 * This file is part of the SCTP reference Implementation
87 *
88 *
89 * Please send any bug reports or fixes you make to one of the following email
90 * addresses:
91 *
92 * rstewar1@email.mot.com
93 * kmorneau@cisco.com
94 * qxie1@email.mot.com
95 *
96 * Any bugs reported given to us we will try to fix... any fixes shared will
97 * be incorperated into the next SCTP release.
98 */
99
100 /* The valid defines for all message
101 * types know to SCTP. 0 is reserved
102 */
103 #define SCTP_DATA 0x00
104 #define SCTP_INITIATION 0x01
105 #define SCTP_INITIATION_ACK 0x02
106 #define SCTP_SELECTIVE_ACK 0x03
107 #define SCTP_HEARTBEAT_REQUEST 0x04
108 #define SCTP_HEARTBEAT_ACK 0x05
109 #define SCTP_ABORT_ASSOCIATION 0x06
110 #define SCTP_SHUTDOWN 0x07
111 #define SCTP_SHUTDOWN_ACK 0x08
112 #define SCTP_OPERATION_ERR 0x09
113 #define SCTP_COOKIE_ECHO 0x0a
114 #define SCTP_COOKIE_ACK 0x0b
115 #define SCTP_ECN_ECHO 0x0c
116 #define SCTP_ECN_CWR 0x0d
117 #define SCTP_SHUTDOWN_COMPLETE 0x0e
118 #define SCTP_FORWARD_CUM_TSN 0xc0
119 #define SCTP_RELIABLE_CNTL 0xc1
120 #define SCTP_RELIABLE_CNTL_ACK 0xc2
121
122 /* Data Chuck Specific Flags */
123 #define SCTP_DATA_FRAG_MASK 0x03
124 #define SCTP_DATA_MIDDLE_FRAG 0x00
125 #define SCTP_DATA_LAST_FRAG 0x01
126 #define SCTP_DATA_FIRST_FRAG 0x02
127 #define SCTP_DATA_NOT_FRAG 0x03
128 #define SCTP_DATA_UNORDERED 0x04
129
130 #define SCTP_ADDRMAX 60
131
132 #define CHAN_HP 6704
133 #define CHAN_MP 6705
134 #define CHAN_LP 6706
135
136 /* the sctp common header */
137
138 struct sctpHeader{
139 u_int16_t source;
140 u_int16_t destination;
141 u_int32_t verificationTag;
142 u_int32_t adler32;
143 };
144
145 /* various descriptor parsers */
146
147 struct sctpChunkDesc{
148 u_int8_t chunkID;
149 u_int8_t chunkFlg;
150 u_int16_t chunkLength;
151 };
152
153 struct sctpParamDesc{
154 u_int16_t paramType;
155 u_int16_t paramLength;
156 };
157
158
159 struct sctpRelChunkDesc{
160 struct sctpChunkDesc chk;
161 u_int32_t serialNumber;
162 };
163
164 struct sctpVendorSpecificParam {
165 struct sctpParamDesc p; /* type must be 0xfffe */
166 u_int32_t vendorId; /* vendor ID from RFC 1700 */
167 u_int16_t vendorSpecificType;
168 u_int16_t vendorSpecificLen;
169 };
170
171
172 /* Structures for the control parts */
173
174
175
176 /* Sctp association init request/ack */
177
178 /* this is used for init ack, too */
179 struct sctpInitiation{
180 u_int32_t initTag; /* tag of mine */
181 u_int32_t rcvWindowCredit; /* rwnd */
182 u_int16_t NumPreopenStreams; /* OS */
183 u_int16_t MaxInboundStreams; /* MIS */
184 u_int32_t initialTSN;
185 /* optional param's follow in sctpParamDesc form */
186 };
187
188 struct sctpV4IpAddress{
189 struct sctpParamDesc p; /* type is set to SCTP_IPV4_PARAM_TYPE, len=10 */
190 u_int32_t ipAddress;
191 };
192
193
194 struct sctpV6IpAddress{
195 struct sctpParamDesc p; /* type is set to SCTP_IPV6_PARAM_TYPE, len=22 */
196 u_int8_t ipAddress[16];
197 };
198
199 struct sctpDNSName{
200 struct sctpParamDesc param;
201 u_int8_t name[1];
202 };
203
204
205 struct sctpCookiePreserve{
206 struct sctpParamDesc p; /* type is set to SCTP_COOKIE_PRESERVE, len=8 */
207 u_int32_t extraTime;
208 };
209
210
211 struct sctpTimeStamp{
212 u_int32_t ts_sec;
213 u_int32_t ts_usec;
214 };
215
216 /* wire structure of my cookie */
217 struct cookieMessage{
218 u_int32_t TieTag_curTag; /* copied from assoc if present */
219 u_int32_t TieTag_hisTag; /* copied from assoc if present */
220 int32_t cookieLife; /* life I will award this cookie */
221 struct sctpTimeStamp timeEnteringState; /* the time I built cookie */
222 struct sctpInitiation initAckISent; /* the INIT-ACK that I sent to my peer */
223 u_int32_t addressWhereISent[4]; /* I make this 4 ints so I get 128bits for future */
224 int32_t addrtype; /* address type */
225 u_int16_t locScope; /* V6 local scope flag */
226 u_int16_t siteScope; /* V6 site scope flag */
227 /* at the end is tacked on the INIT chunk sent in
228 * its entirety and of course our
229 * signature.
230 */
231 };
232
233
234 /* this guy is for use when
235 * I have a initiate message gloming the
236 * things together.
237
238 */
239 struct sctpUnifiedInit{
240 struct sctpChunkDesc uh;
241 struct sctpInitiation initm;
242 };
243
244 struct sctpSendableInit{
245 struct sctpHeader mh;
246 struct sctpUnifiedInit msg;
247 };
248
249
250 /* Selective Acknowledgement
251 * has the following structure with
252 * a optional ammount of trailing int's
253 * on the last part (based on the numberOfDesc
254 * field).
255 */
256
257 struct sctpSelectiveAck{
258 u_int32_t highestConseqTSN;
259 u_int32_t updatedRwnd;
260 u_int16_t numberOfdesc;
261 u_int16_t numDupTsns;
262 };
263
264 struct sctpSelectiveFrag{
265 u_int16_t fragmentStart;
266 u_int16_t fragmentEnd;
267 };
268
269
270 struct sctpUnifiedSack{
271 struct sctpChunkDesc uh;
272 struct sctpSelectiveAck sack;
273 };
274
275 /* for both RTT request/response the
276 * following is sent
277 */
278
279 struct sctpHBrequest {
280 u_int32_t time_value_1;
281 u_int32_t time_value_2;
282 };
283
284 /* here is what I read and respond with to. */
285 struct sctpHBunified{
286 struct sctpChunkDesc hdr;
287 struct sctpParamDesc hb;
288 };
289
290
291 /* here is what I send */
292 struct sctpHBsender{
293 struct sctpChunkDesc hdr;
294 struct sctpParamDesc hb;
295 struct sctpHBrequest rtt;
296 int8_t addrFmt[SCTP_ADDRMAX];
297 u_int16_t userreq;
298 };
299
300
301
302 /* for the abort and shutdown ACK
303 * we must carry the init tag in the common header. Just the
304 * common header is all that is needed with a chunk descriptor.
305 */
306 struct sctpUnifiedAbort{
307 struct sctpChunkDesc uh;
308 };
309
310 struct sctpUnifiedAbortLight{
311 struct sctpHeader mh;
312 struct sctpChunkDesc uh;
313 };
314
315 struct sctpUnifiedAbortHeavy{
316 struct sctpHeader mh;
317 struct sctpChunkDesc uh;
318 u_int16_t causeCode;
319 u_int16_t causeLen;
320 };
321
322 /* For the graceful shutdown we must carry
323 * the tag (in common header) and the highest consequitive acking value
324 */
325 struct sctpShutdown {
326 u_int32_t TSN_Seen;
327 };
328
329 struct sctpUnifiedShutdown{
330 struct sctpChunkDesc uh;
331 struct sctpShutdown shut;
332 };
333
334 /* in the unified message we add the trailing
335 * stream id since it is the only message
336 * that is defined as a operation error.
337 */
338 struct sctpOpErrorCause{
339 u_int16_t cause;
340 u_int16_t causeLen;
341 };
342
343 struct sctpUnifiedOpError{
344 struct sctpChunkDesc uh;
345 struct sctpOpErrorCause c;
346 };
347
348 struct sctpUnifiedStreamError{
349 struct sctpHeader mh;
350 struct sctpChunkDesc uh;
351 struct sctpOpErrorCause c;
352 u_int16_t strmNum;
353 u_int16_t reserved;
354 };
355
356 struct staleCookieMsg{
357 struct sctpHeader mh;
358 struct sctpChunkDesc uh;
359 struct sctpOpErrorCause c;
360 u_int32_t moretime;
361 };
362
363 /* the following is used in all sends
364 * where nothing is needed except the
365 * chunk/type i.e. shutdownAck Abort */
366
367 struct sctpUnifiedSingleMsg{
368 struct sctpHeader mh;
369 struct sctpChunkDesc uh;
370 };
371
372 struct sctpDataPart{
373 u_int32_t TSN;
374 u_int16_t streamId;
375 u_int16_t sequence;
376 u_int32_t payloadtype;
377 };
378
379 struct sctpUnifiedDatagram{
380 struct sctpChunkDesc uh;
381 struct sctpDataPart dp;
382 };
383
384 struct sctpECN_echo{
385 struct sctpChunkDesc uh;
386 u_int32_t Lowest_TSN;
387 };
388
389
390 struct sctpCWR{
391 struct sctpChunkDesc uh;
392 u_int32_t TSN_reduced_at;
393 };
394
395 static const struct tok ForCES_channels[] = {
396 { CHAN_HP, "ForCES HP" },
397 { CHAN_MP, "ForCES MP" },
398 { CHAN_LP, "ForCES LP" },
399 { 0, NULL }
400 };
401
402 static inline int isForCES_port(u_short Port)
403 {
404 if (Port == CHAN_HP)
405 return 1;
406 if (Port == CHAN_MP)
407 return 1;
408 if (Port == CHAN_LP)
409 return 1;
410
411 return 0;
412 }
413
414 void sctp_print(const u_char *bp, /* beginning of sctp packet */
415 const u_char *bp2, /* beginning of enclosing */
416 u_int sctpPacketLength) /* ip packet */
417 {
418 const struct sctpHeader *sctpPktHdr;
419 const struct ip *ip;
420 #ifdef INET6
421 const struct ip6_hdr *ip6;
422 #endif
423 const void *endPacketPtr;
424 u_short sourcePort, destPort;
425 int chunkCount;
426 const struct sctpChunkDesc *chunkDescPtr;
427 const void *nextChunk;
428 const char *sep;
429 int isforces = 0;
430
431
432 sctpPktHdr = (const struct sctpHeader*) bp;
433 endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength;
434
435 if( (u_long) endPacketPtr > (u_long) snapend)
436 endPacketPtr = (const void *) snapend;
437 ip = (struct ip *)bp2;
438 #ifdef INET6
439 if (IP_V(ip) == 6)
440 ip6 = (const struct ip6_hdr *)bp2;
441 else
442 ip6 = NULL;
443 #endif /*INET6*/
444 TCHECK(*sctpPktHdr);
445
446 if (sctpPacketLength < sizeof(struct sctpHeader))
447 {
448 (void)printf("truncated-sctp - %ld bytes missing!",
449 (long)sctpPacketLength-sizeof(struct sctpHeader));
450 return;
451 }
452
453 /* sctpPacketLength -= sizeof(struct sctpHeader); packet length */
454 /* is now only as long as the payload */
455
456 sourcePort = EXTRACT_16BITS(&sctpPktHdr->source);
457 destPort = EXTRACT_16BITS(&sctpPktHdr->destination);
458
459 #ifdef INET6
460 if (ip6) {
461 (void)printf("%s.%d > %s.%d: sctp",
462 ip6addr_string(&ip6->ip6_src),
463 sourcePort,
464 ip6addr_string(&ip6->ip6_dst),
465 destPort);
466 } else
467 #endif /*INET6*/
468 {
469 (void)printf("%s.%d > %s.%d: sctp",
470 ipaddr_string(&ip->ip_src),
471 sourcePort,
472 ipaddr_string(&ip->ip_dst),
473 destPort);
474 }
475 fflush(stdout);
476
477 if (isForCES_port(sourcePort)) {
478 printf("[%s]", tok2str(ForCES_channels, NULL, sourcePort));
479 isforces = 1;
480 }
481 if (isForCES_port(destPort)) {
482 printf("[%s]", tok2str(ForCES_channels, NULL, destPort));
483 isforces = 1;
484 }
485
486 if (vflag >= 2)
487 sep = "\n\t";
488 else
489 sep = " (";
490 /* cycle through all chunks, printing information on each one */
491 for (chunkCount = 0,
492 chunkDescPtr = (const struct sctpChunkDesc *)
493 ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader));
494 chunkDescPtr != NULL &&
495 ( (const void *)
496 ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc))
497 <= endPacketPtr);
498
499 chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++)
500 {
501 u_int16_t chunkLength;
502 const u_char *chunkEnd;
503 u_int16_t align;
504
505 TCHECK(*chunkDescPtr);
506 chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength);
507 if (chunkLength < sizeof(*chunkDescPtr)) {
508 printf("%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength);
509 break;
510 }
511
512 TCHECK2(*((u_int8_t *)chunkDescPtr), chunkLength);
513 chunkEnd = ((const u_char*)chunkDescPtr + chunkLength);
514
515 align=chunkLength % 4;
516 if (align != 0)
517 align = 4 - align;
518
519 nextChunk = (const void *) (chunkEnd + align);
520
521 printf("%s%d) ", sep, chunkCount+1);
522 switch (chunkDescPtr->chunkID)
523 {
524 case SCTP_DATA :
525 {
526 const struct sctpDataPart *dataHdrPtr;
527
528 printf("[DATA] ");
529
530 if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED)
531 == SCTP_DATA_UNORDERED)
532 printf("(U)");
533
534 if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG)
535 == SCTP_DATA_FIRST_FRAG)
536 printf("(B)");
537
538 if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG)
539 == SCTP_DATA_LAST_FRAG)
540 printf("(E)");
541
542 if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED)
543 == SCTP_DATA_UNORDERED)
544 ||
545 ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG)
546 == SCTP_DATA_FIRST_FRAG)
547 ||
548 ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG)
549 == SCTP_DATA_LAST_FRAG) )
550 printf(" ");
551
552 dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1);
553
554 printf("[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN));
555 printf("[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId));
556 printf("[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence));
557 printf("[PPID 0x%x] ", EXTRACT_32BITS(&dataHdrPtr->payloadtype));
558 fflush(stdout);
559 if (isforces) {
560 const u_char *payloadPtr;
561 u_int chunksize = sizeof(struct sctpDataPart)+
562 sizeof(struct sctpChunkDesc);
563 payloadPtr = (const u_char *) (dataHdrPtr + 1);
564 if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) <
565 sizeof(struct sctpDataPart)+
566 sizeof(struct sctpChunkDesc)+1) {
567 /* Less than 1 byte of chunk payload */
568 printf("bogus ForCES chunk length %u]",
569 EXTRACT_16BITS(&chunkDescPtr->chunkLength));
570 return;
571 }
572
573 forces_print(payloadPtr, EXTRACT_16BITS(&chunkDescPtr->chunkLength)- chunksize);
574 } else if (vflag >= 2) { /* if verbose output is specified */
575 /* at the command line */
576 const u_char *payloadPtr;
577
578 printf("[Payload");
579
580 if (!suppress_default_print) {
581 payloadPtr = (const u_char *) (++dataHdrPtr);
582 printf(":");
583 if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) <
584 sizeof(struct sctpDataPart)+
585 sizeof(struct sctpChunkDesc)+1) {
586 /* Less than 1 byte of chunk payload */
587 printf("bogus chunk length %u]",
588 EXTRACT_16BITS(&chunkDescPtr->chunkLength));
589 return;
590 }
591 default_print(payloadPtr,
592 EXTRACT_16BITS(&chunkDescPtr->chunkLength) -
593 (sizeof(struct sctpDataPart)+
594 sizeof(struct sctpChunkDesc)));
595 } else
596 printf("]");
597 }
598 break;
599 }
600 case SCTP_INITIATION :
601 {
602 const struct sctpInitiation *init;
603
604 printf("[INIT] ");
605 init=(const struct sctpInitiation*)(chunkDescPtr+1);
606 printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag));
607 printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit));
608 printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams));
609 printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams));
610 printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN));
611
612 #if(0) /* ALC you can add code for optional params here */
613 if( (init+1) < chunkEnd )
614 printf(" @@@@@ UNFINISHED @@@@@@%s\n",
615 "Optional params present, but not printed.");
616 #endif
617 break;
618 }
619 case SCTP_INITIATION_ACK :
620 {
621 const struct sctpInitiation *init;
622
623 printf("[INIT ACK] ");
624 init=(const struct sctpInitiation*)(chunkDescPtr+1);
625 printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag));
626 printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit));
627 printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams));
628 printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams));
629 printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN));
630
631 #if(0) /* ALC you can add code for optional params here */
632 if( (init+1) < chunkEnd )
633 printf(" @@@@@ UNFINISHED @@@@@@%s\n",
634 "Optional params present, but not printed.");
635 #endif
636 break;
637 }
638 case SCTP_SELECTIVE_ACK:
639 {
640 const struct sctpSelectiveAck *sack;
641 const struct sctpSelectiveFrag *frag;
642 int fragNo, tsnNo;
643 const u_char *dupTSN;
644
645 printf("[SACK] ");
646 sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1);
647 printf("[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN));
648 printf("[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd));
649 printf("[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc));
650 printf("[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns));
651
652
653 /* print gaps */
654 for (frag = ( (const struct sctpSelectiveFrag *)
655 ((const struct sctpSelectiveAck *) sack+1)),
656 fragNo=0;
657 (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc);
658 frag++, fragNo++)
659 printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ",
660 fragNo+1,
661 EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart),
662 EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd));
663
664
665 /* print duplicate TSNs */
666 for (dupTSN = (const u_char *)frag, tsnNo=0;
667 (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns);
668 dupTSN += 4, tsnNo++)
669 printf("\n\t\t[dup TSN #%u: %u] ", tsnNo+1,
670 EXTRACT_32BITS(dupTSN));
671
672 break;
673 }
674 case SCTP_HEARTBEAT_REQUEST :
675 printf("[HB REQ] ");
676 break;
677 case SCTP_HEARTBEAT_ACK :
678 printf("[HB ACK] ");
679 break;
680 case SCTP_ABORT_ASSOCIATION :
681 printf("[ABORT] ");
682 break;
683 case SCTP_SHUTDOWN :
684 printf("[SHUTDOWN] ");
685 break;
686 case SCTP_SHUTDOWN_ACK :
687 printf("[SHUTDOWN ACK] ");
688 break;
689 case SCTP_OPERATION_ERR :
690 printf("[OP ERR] ");
691 break;
692 case SCTP_COOKIE_ECHO :
693 printf("[COOKIE ECHO] ");
694 break;
695 case SCTP_COOKIE_ACK :
696 printf("[COOKIE ACK] ");
697 break;
698 case SCTP_ECN_ECHO :
699 printf("[ECN ECHO] ");
700 break;
701 case SCTP_ECN_CWR :
702 printf("[ECN CWR] ");
703 break;
704 case SCTP_SHUTDOWN_COMPLETE :
705 printf("[SHUTDOWN COMPLETE] ");
706 break;
707 case SCTP_FORWARD_CUM_TSN :
708 printf("[FOR CUM TSN] ");
709 break;
710 case SCTP_RELIABLE_CNTL :
711 printf("[REL CTRL] ");
712 break;
713 case SCTP_RELIABLE_CNTL_ACK :
714 printf("[REL CTRL ACK] ");
715 break;
716 default :
717 printf("[Unknown chunk type: 0x%x]", chunkDescPtr->chunkID);
718 return;
719 }
720
721 if (vflag < 2)
722 sep = ", (";
723 }
724 return;
725
726 trunc:
727 printf("[|sctp]");
728 return;
729 }