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