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