]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-sctp.c
Revert partially the commit 21b1273
[tcpdump] / print-sctp.c
index 4b595f2e825e268473e769b96cc9e373b28f39ed..9384a93d2847db82f76e468291ccea278471c8bf 100644 (file)
  * SUCH DAMAGE.
  */
 
-#define NETDISSECT_REWORKED
+/* \summary: Stream Control Transmission Protocol (SCTP) printer */
+
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
-#include <tcpdump-stdinc.h>
+#include "netdissect-stdinc.h"
 
-#include "interface.h"
+#include "netdissect.h"
 #include "addrtoname.h"
-#include "extract.h"                   /* must come after interface.h */
+#include "extract.h"
 #include "ip.h"
-#ifdef INET6
 #include "ip6.h"
-#endif
 
 /* Definitions from:
  *
@@ -90,7 +89,7 @@
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
- * be incorperated into the next SCTP release.
+ * be incorporated into the next SCTP release.
  */
 
 /* The valid defines for all message
@@ -154,36 +153,36 @@ static const struct tok sctp_chunkid_str[] = {
 /* the sctp common header */
 
 struct sctpHeader{
-  uint16_t source;
-  uint16_t destination;
-  uint32_t verificationTag;
-  uint32_t adler32;
+  nd_uint16_t source;
+  nd_uint16_t destination;
+  nd_uint32_t verificationTag;
+  nd_uint32_t adler32;
 };
 
 /* various descriptor parsers */
 
 struct sctpChunkDesc{
-  uint8_t chunkID;
-  uint8_t chunkFlg;
-  uint16_t chunkLength;
+  nd_uint8_t  chunkID;
+  nd_uint8_t  chunkFlg;
+  nd_uint16_t chunkLength;
 };
 
 struct sctpParamDesc{
-  uint16_t paramType;
-  uint16_t paramLength;
+  nd_uint16_t paramType;
+  nd_uint16_t paramLength;
 };
 
 
 struct sctpRelChunkDesc{
   struct sctpChunkDesc chk;
-  uint32_t serialNumber;
+  nd_uint32_t serialNumber;
 };
 
 struct sctpVendorSpecificParam {
   struct sctpParamDesc p;  /* type must be 0xfffe */
-  uint32_t vendorId;      /* vendor ID from RFC 1700 */
-  uint16_t vendorSpecificType;
-  uint16_t vendorSpecificLen;
+  nd_uint32_t vendorId;           /* vendor ID from RFC 1700 */
+  nd_uint16_t vendorSpecificType;
+  nd_uint16_t vendorSpecificLen;
 };
 
 
@@ -195,57 +194,40 @@ struct sctpVendorSpecificParam {
 
 /* this is used for init ack, too */
 struct sctpInitiation{
-  uint32_t initTag;            /* tag of mine */
-  uint32_t rcvWindowCredit;    /* rwnd */
-  uint16_t NumPreopenStreams;  /* OS */
-  uint16_t MaxInboundStreams;     /* MIS */
-  uint32_t initialTSN;
+  nd_uint32_t initTag;                 /* tag of mine */
+  nd_uint32_t rcvWindowCredit;         /* rwnd */
+  nd_uint16_t NumPreopenStreams;       /* OS */
+  nd_uint16_t MaxInboundStreams;       /* MIS */
+  nd_uint32_t initialTSN;
   /* optional param's follow in sctpParamDesc form */
 };
 
 struct sctpV4IpAddress{
   struct sctpParamDesc p;      /* type is set to SCTP_IPV4_PARAM_TYPE, len=10 */
-  uint32_t  ipAddress;
+  nd_ipv4  ipAddress;
 };
 
 
 struct sctpV6IpAddress{
   struct sctpParamDesc p;      /* type is set to SCTP_IPV6_PARAM_TYPE, len=22 */
-  uint8_t  ipAddress[16];
+  nd_ipv6  ipAddress;
 };
 
 struct sctpDNSName{
   struct sctpParamDesc param;
-  uint8_t name[1];
+  nd_byte name[1];
 };
 
 
 struct sctpCookiePreserve{
   struct sctpParamDesc p;      /* type is set to SCTP_COOKIE_PRESERVE, len=8 */
-  uint32_t extraTime;
+  nd_uint32_t extraTime;
 };
 
 
 struct sctpTimeStamp{
-  uint32_t ts_sec;
-  uint32_t ts_usec;
-};
-
-/* wire structure of my cookie */
-struct cookieMessage{
-  uint32_t TieTag_curTag;              /* copied from assoc if present */
-  uint32_t TieTag_hisTag;              /* copied from assoc if present */
-  int32_t cookieLife;                  /* life I will award this cookie */
-  struct sctpTimeStamp timeEnteringState; /* the time I built cookie */
-  struct sctpInitiation initAckISent;  /* the INIT-ACK that I sent to my peer */
-  uint32_t addressWhereISent[4];       /* I make this 4 ints so I get 128bits for future */
-  int32_t addrtype;                    /* address type */
-  uint16_t locScope;                   /* V6 local scope flag */
-  uint16_t siteScope;                  /* V6 site scope flag */
-  /* at the end is tacked on the INIT chunk sent in
-   * its entirety and of course our
-   * signature.
-   */
+  nd_uint32_t ts_sec;
+  nd_uint32_t ts_usec;
 };
 
 
@@ -267,21 +249,21 @@ struct sctpSendableInit{
 
 /* Selective Acknowledgement
  * has the following structure with
- * a optional ammount of trailing int's
+ * a optional amount of trailing int's
  * on the last part (based on the numberOfDesc
  * field).
  */
 
 struct sctpSelectiveAck{
-  uint32_t highestConseqTSN;
-  uint32_t updatedRwnd;
-  uint16_t numberOfdesc;
-  uint16_t numDupTsns;
+  nd_uint32_t highestConseqTSN;
+  nd_uint32_t updatedRwnd;
+  nd_uint16_t numberOfdesc;
+  nd_uint16_t numDupTsns;
 };
 
 struct sctpSelectiveFrag{
-  uint16_t fragmentStart;
-  uint16_t fragmentEnd;
+  nd_uint16_t fragmentStart;
+  nd_uint16_t fragmentEnd;
 };
 
 
@@ -290,33 +272,6 @@ struct sctpUnifiedSack{
   struct sctpSelectiveAck sack;
 };
 
-/* for both RTT request/response the
- * following is sent
- */
-
-struct sctpHBrequest {
-  uint32_t time_value_1;
-  uint32_t time_value_2;
-};
-
-/* here is what I read and respond with to. */
-struct sctpHBunified{
-  struct sctpChunkDesc hdr;
-  struct sctpParamDesc hb;
-};
-
-
-/* here is what I send */
-struct sctpHBsender{
-  struct sctpChunkDesc hdr;
-  struct sctpParamDesc hb;
-  struct sctpHBrequest rtt;
-  int8_t addrFmt[SCTP_ADDRMAX];
-  uint16_t userreq;
-};
-
-
-
 /* for the abort and shutdown ACK
  * we must carry the init tag in the common header. Just the
  * common header is all that is needed with a chunk descriptor.
@@ -333,15 +288,15 @@ struct sctpUnifiedAbortLight{
 struct sctpUnifiedAbortHeavy{
   struct sctpHeader mh;
   struct sctpChunkDesc uh;
-  uint16_t causeCode;
-  uint16_t causeLen;
+  nd_uint16_t causeCode;
+  nd_uint16_t causeLen;
 };
 
 /* For the graceful shutdown we must carry
  * the tag (in common header)  and the highest consequitive acking value
  */
 struct sctpShutdown {
-  uint32_t TSN_Seen;
+  nd_uint32_t TSN_Seen;
 };
 
 struct sctpUnifiedShutdown{
@@ -354,8 +309,8 @@ struct sctpUnifiedShutdown{
  * that is defined as a operation error.
  */
 struct sctpOpErrorCause{
-  uint16_t cause;
-  uint16_t causeLen;
+  nd_uint16_t cause;
+  nd_uint16_t causeLen;
 };
 
 struct sctpUnifiedOpError{
@@ -367,15 +322,15 @@ struct sctpUnifiedStreamError{
   struct sctpHeader mh;
   struct sctpChunkDesc uh;
   struct sctpOpErrorCause c;
-  uint16_t strmNum;
-  uint16_t reserved;
+  nd_uint16_t strmNum;
+  nd_uint16_t reserved;
 };
 
 struct staleCookieMsg{
   struct sctpHeader mh;
   struct sctpChunkDesc uh;
   struct sctpOpErrorCause c;
-  uint32_t moretime;
+  nd_uint32_t moretime;
 };
 
 /* the following is used in all sends
@@ -388,10 +343,10 @@ struct sctpUnifiedSingleMsg{
 };
 
 struct sctpDataPart{
-  uint32_t TSN;
-  uint16_t streamId;
-  uint16_t sequence;
-  uint32_t payloadtype;
+  nd_uint32_t TSN;
+  nd_uint16_t streamId;
+  nd_uint16_t sequence;
+  nd_uint32_t payloadtype;
 };
 
 struct sctpUnifiedDatagram{
@@ -401,13 +356,13 @@ struct sctpUnifiedDatagram{
 
 struct sctpECN_echo{
   struct sctpChunkDesc uh;
-  uint32_t Lowest_TSN;
+  nd_uint32_t Lowest_TSN;
 };
 
 
 struct sctpCWR{
   struct sctpChunkDesc uh;
-  uint32_t TSN_reduced_at;
+  nd_uint32_t TSN_reduced_at;
 };
 
 static const struct tok ForCES_channels[] = {
@@ -479,7 +434,8 @@ static const struct tok PayloadProto_idents[] = {
 };
 
 
-static inline int isForCES_port(u_short Port)
+static int
+isForCES_port(u_short Port)
 {
        if (Port == CHAN_HP)
                return 1;
@@ -491,155 +447,150 @@ static inline int isForCES_port(u_short Port)
        return 0;
 }
 
-void sctp_print(netdissect_options *ndo,
-                const u_char *bp,        /* beginning of sctp packet */
-                const u_char *bp2,       /* beginning of enclosing */
-                u_int sctpPacketLength)  /* ip packet */
+void
+sctp_print(netdissect_options *ndo,
+          const u_char *bp,        /* beginning of sctp packet */
+          const u_char *bp2,       /* beginning of enclosing */
+          u_int sctpPacketLength)  /* ip packet */
 {
+  u_int sctpPacketLengthRemaining;
   const struct sctpHeader *sctpPktHdr;
   const struct ip *ip;
-#ifdef INET6
   const struct ip6_hdr *ip6;
-#endif
-  const void *endPacketPtr;
+  uint8_t chunkID;
   u_short sourcePort, destPort;
-  int chunkCount;
+  u_int chunkCount;
   const struct sctpChunkDesc *chunkDescPtr;
-  const void *nextChunk;
   const char *sep;
   int isforces = 0;
 
-
-  sctpPktHdr = (const struct sctpHeader*) bp;
-  endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength;
-
-  if( (u_long) endPacketPtr > (u_long) ndo->ndo_snapend)
-    endPacketPtr = (const void *) ndo->ndo_snapend;
-  ip = (struct ip *)bp2;
-#ifdef INET6
-  if (IP_V(ip) == 6)
-    ip6 = (const struct ip6_hdr *)bp2;
-  else
-    ip6 = NULL;
-#endif /*INET6*/
-  ND_TCHECK(*sctpPktHdr);
-
+  ndo->ndo_protocol = "sctp";
   if (sctpPacketLength < sizeof(struct sctpHeader))
     {
-      ND_PRINT((ndo, "truncated-sctp - %ld bytes missing!",
-                  (long)sctpPacketLength-sizeof(struct sctpHeader)));
+      ND_PRINT("truncated-sctp - %ld bytes missing!",
+                  (long)(sizeof(struct sctpHeader) - sctpPacketLength));
       return;
     }
+  sctpPktHdr = (const struct sctpHeader*) bp;
+  ND_TCHECK_SIZE(sctpPktHdr);
+  sctpPacketLengthRemaining = sctpPacketLength;
 
-  /*    sctpPacketLength -= sizeof(struct sctpHeader);  packet length  */
-  /*                         is now only as long as the payload  */
+  sourcePort = GET_BE_U_2(sctpPktHdr->source);
+  destPort = GET_BE_U_2(sctpPktHdr->destination);
 
-  sourcePort = EXTRACT_16BITS(&sctpPktHdr->source);
-  destPort = EXTRACT_16BITS(&sctpPktHdr->destination);
+  ip = (const struct ip *)bp2;
+  if (IP_V(ip) == 6)
+    ip6 = (const struct ip6_hdr *)bp2;
+  else
+    ip6 = NULL;
 
-#ifdef INET6
   if (ip6) {
-    ND_PRINT((ndo, "%s.%d > %s.%d: sctp",
-      ip6addr_string(ndo, &ip6->ip6_src),
+    ND_PRINT("%s.%u > %s.%u: sctp",
+      ip6addr_string(ndo, ip6->ip6_src),
       sourcePort,
-      ip6addr_string(ndo, &ip6->ip6_dst),
-      destPort));
+      ip6addr_string(ndo, ip6->ip6_dst),
+      destPort);
   } else
-#endif /*INET6*/
   {
-    ND_PRINT((ndo, "%s.%d > %s.%d: sctp",
-      ipaddr_string(ndo, &ip->ip_src),
+    ND_PRINT("%s.%u > %s.%u: sctp",
+      ipaddr_string(ndo, ip->ip_src),
       sourcePort,
-      ipaddr_string(ndo, &ip->ip_dst),
-      destPort));
+      ipaddr_string(ndo, ip->ip_dst),
+      destPort);
   }
 
   if (isForCES_port(sourcePort)) {
-         ND_PRINT((ndo, "[%s]", tok2str(ForCES_channels, NULL, sourcePort)));
-         isforces = 1;
+        ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, sourcePort));
+        isforces = 1;
   }
   if (isForCES_port(destPort)) {
-         ND_PRINT((ndo, "[%s]", tok2str(ForCES_channels, NULL, destPort)));
-         isforces = 1;
+        ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, destPort));
+        isforces = 1;
   }
 
+  bp += sizeof(struct sctpHeader);
+  sctpPacketLengthRemaining -= sizeof(struct sctpHeader);
+
   if (ndo->ndo_vflag >= 2)
     sep = "\n\t";
   else
     sep = " (";
   /* cycle through all chunks, printing information on each one */
-  for (chunkCount = 0,
-        chunkDescPtr = (const struct sctpChunkDesc *)
-           ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader));
-       chunkDescPtr != NULL &&
-        ( (const void *)
-           ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc))
-          <= endPacketPtr);
-
-       chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++)
+  for (chunkCount = 0, chunkDescPtr = (const struct sctpChunkDesc *)bp;
+      sctpPacketLengthRemaining != 0;
+      chunkCount++)
     {
-      uint16_t chunkLength;
-      const u_char *chunkEnd;
+      uint16_t chunkLength, chunkLengthRemaining;
       uint16_t align;
 
-      ND_TCHECK(*chunkDescPtr);
-      chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength);
+      chunkDescPtr = (const struct sctpChunkDesc *)bp;
+      if (sctpPacketLengthRemaining < sizeof(*chunkDescPtr)) {
+       ND_PRINT("%s%u) [chunk descriptor cut off at end of packet]", sep, chunkCount+1);
+       break;
+      }
+      ND_TCHECK_SIZE(chunkDescPtr);
+      chunkLength = GET_BE_U_2(chunkDescPtr->chunkLength);
       if (chunkLength < sizeof(*chunkDescPtr)) {
-        ND_PRINT((ndo, "%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength));
-        break;
+       ND_PRINT("%s%u) [Bad chunk length %u, < size of chunk descriptor]", sep, chunkCount+1, chunkLength);
+       break;
       }
+      chunkLengthRemaining = chunkLength;
 
-      ND_TCHECK2(*((uint8_t *)chunkDescPtr), chunkLength);
-      chunkEnd = ((const u_char*)chunkDescPtr + chunkLength);
-
-      align=chunkLength % 4;
+      align = chunkLength % 4;
       if (align != 0)
        align = 4 - align;
 
-      nextChunk = (const void *) (chunkEnd + align);
+      if (sctpPacketLengthRemaining < align) {
+       ND_PRINT("%s%u) [Bad chunk length %u, > remaining data in packet]", sep, chunkCount+1, chunkLength);
+       break;
+      }
+
+      ND_TCHECK_LEN(bp, chunkLength);
+
+      bp += sizeof(*chunkDescPtr);
+      sctpPacketLengthRemaining -= sizeof(*chunkDescPtr);
+      chunkLengthRemaining -= sizeof(*chunkDescPtr);
 
-      ND_PRINT((ndo, "%s%d) ", sep, chunkCount+1));
-      ND_PRINT((ndo, "[%s] ", tok2str(sctp_chunkid_str, "Unknown chunk type: 0x%x",
-                                      chunkDescPtr->chunkID)));
-      switch (chunkDescPtr->chunkID)
+      ND_PRINT("%s%u) ", sep, chunkCount+1);
+      chunkID = GET_U_1(chunkDescPtr->chunkID);
+      ND_PRINT("[%s] ", tok2str(sctp_chunkid_str, "Unknown chunk type: 0x%x",
+              chunkID));
+      switch (chunkID)
        {
        case SCTP_DATA :
          {
            const struct sctpDataPart *dataHdrPtr;
+           uint8_t chunkFlg;
            uint32_t ppid;
-           const u_char *payloadPtr;
-           u_int payload_size;
-
-           if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED)
-               == SCTP_DATA_UNORDERED)
-             ND_PRINT((ndo, "(U)"));
-
-           if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG)
-               == SCTP_DATA_FIRST_FRAG)
-             ND_PRINT((ndo, "(B)"));
-
-           if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG)
-               == SCTP_DATA_LAST_FRAG)
-             ND_PRINT((ndo, "(E)"));
-
-           if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED)
-                == SCTP_DATA_UNORDERED)
-               ||
-               ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG)
-                == SCTP_DATA_FIRST_FRAG)
-               ||
-               ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG)
-                == SCTP_DATA_LAST_FRAG) )
-             ND_PRINT((ndo, " "));
-
-           dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1);
-
-           ppid = EXTRACT_32BITS(&dataHdrPtr->payloadtype);
-           ND_PRINT((ndo, "[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN)));
-           ND_PRINT((ndo, "[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId)));
-           ND_PRINT((ndo, "[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence)));
-           ND_PRINT((ndo, "[PPID %s] ",
-                   tok2str(PayloadProto_idents, "0x%x", ppid)));
+           uint16_t payload_size;
+
+           chunkFlg = GET_U_1(chunkDescPtr->chunkFlg);
+           if ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED)
+             ND_PRINT("(U)");
+
+           if ((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG)
+             ND_PRINT("(B)");
+
+           if ((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG)
+             ND_PRINT("(E)");
+
+           if( ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) ||
+               ((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) ||
+               ((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) )
+             ND_PRINT(" ");
+
+           if (chunkLengthRemaining < sizeof(*dataHdrPtr)) {
+               ND_PRINT("bogus chunk length %u]", chunkLength);
+               return;
+           }
+           dataHdrPtr=(const struct sctpDataPart*)bp;
+
+           ppid = GET_BE_U_4(dataHdrPtr->payloadtype);
+           ND_PRINT("[TSN: %u] ", GET_BE_U_4(dataHdrPtr->TSN));
+           ND_PRINT("[SID: %u] ", GET_BE_U_2(dataHdrPtr->streamId));
+           ND_PRINT("[SSEQ %u] ", GET_BE_U_2(dataHdrPtr->sequence));
+           ND_PRINT("[PPID %s] ",
+                   tok2str(PayloadProto_idents, "0x%x", ppid));
 
            if (!isforces) {
                isforces = (ppid == SCTP_PPID_FORCES_HP) ||
@@ -647,114 +598,179 @@ void sctp_print(netdissect_options *ndo,
                    (ppid == SCTP_PPID_FORCES_LP);
            }
 
-           payloadPtr = (const u_char *) (dataHdrPtr + 1);
-           if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) <
-                   sizeof(struct sctpDataPart) + sizeof(struct sctpChunkDesc) + 1) {
-               ND_PRINT((ndo, "bogus chunk length %u]", EXTRACT_16BITS(&chunkDescPtr->chunkLength)));
+           bp += sizeof(*dataHdrPtr);
+           sctpPacketLengthRemaining -= sizeof(*dataHdrPtr);
+           chunkLengthRemaining -= sizeof(*dataHdrPtr);
+           payload_size = chunkLengthRemaining;
+           if (payload_size == 0) {
+               ND_PRINT("bogus chunk length %u]", chunkLength);
                return;
            }
 
-           payload_size = EXTRACT_16BITS(&chunkDescPtr->chunkLength) -
-               (sizeof(struct sctpDataPart) + sizeof(struct sctpChunkDesc));
-
            if (isforces) {
-               forces_print(ndo, payloadPtr, payload_size);
+               forces_print(ndo, bp, payload_size);
+               /* ndo_protocol reassignment after forces_print() call */
+               ndo->ndo_protocol = "sctp";
            } else if (ndo->ndo_vflag >= 2) {   /* if verbose output is specified */
                                        /* at the command line */
                switch (ppid) {
                case SCTP_PPID_M3UA :
-                       m3ua_print(ndo, payloadPtr, payload_size);
+                       m3ua_print(ndo, bp, payload_size);
+                       /* ndo_protocol reassignment after m3ua_print() call */
+                       ndo->ndo_protocol = "sctp";
                        break;
                default:
-                       ND_PRINT((ndo, "[Payload"));
+                       ND_PRINT("[Payload");
                        if (!ndo->ndo_suppress_default_print) {
-                               ND_PRINT((ndo, ":"));
-                               ND_DEFAULTPRINT(payloadPtr, payload_size);
+                               ND_PRINT(":");
+                               ND_DEFAULTPRINT(bp, payload_size);
                        }
-                       ND_PRINT((ndo, "]"));
+                       ND_PRINT("]");
                        break;
                }
            }
+           bp += payload_size;
+           sctpPacketLengthRemaining -= payload_size;
+           chunkLengthRemaining -= payload_size;
            break;
          }
        case SCTP_INITIATION :
          {
            const struct sctpInitiation *init;
 
-           init=(const struct sctpInitiation*)(chunkDescPtr+1);
-           ND_PRINT((ndo, "[init tag: %u] ", EXTRACT_32BITS(&init->initTag)));
-           ND_PRINT((ndo, "[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)));
-           ND_PRINT((ndo, "[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)));
-           ND_PRINT((ndo, "[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)));
-           ND_PRINT((ndo, "[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)));
-
-#if(0) /* ALC you can add code for optional params here */
-           if( (init+1) < chunkEnd )
-             ND_PRINT((ndo, " @@@@@ UNFINISHED @@@@@@%s\n",
-                    "Optional params present, but not printed."));
+           if (chunkLengthRemaining < sizeof(*init)) {
+               ND_PRINT("bogus chunk length %u]", chunkLength);
+               return;
+           }
+           init=(const struct sctpInitiation*)bp;
+           ND_PRINT("[init tag: %u] ", GET_BE_U_4(init->initTag));
+           ND_PRINT("[rwnd: %u] ", GET_BE_U_4(init->rcvWindowCredit));
+           ND_PRINT("[OS: %u] ", GET_BE_U_2(init->NumPreopenStreams));
+           ND_PRINT("[MIS: %u] ", GET_BE_U_2(init->MaxInboundStreams));
+           ND_PRINT("[init TSN: %u] ", GET_BE_U_4(init->initialTSN));
+           bp += sizeof(*init);
+           sctpPacketLengthRemaining -= sizeof(*init);
+           chunkLengthRemaining -= sizeof(*init);
+
+#if 0 /* ALC you can add code for optional params here */
+           if( chunkLengthRemaining != 0 )
+             ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n",
+                    "Optional params present, but not printed.");
 #endif
+           bp += chunkLengthRemaining;
+           sctpPacketLengthRemaining -= chunkLengthRemaining;
+           chunkLengthRemaining = 0;
            break;
          }
        case SCTP_INITIATION_ACK :
          {
            const struct sctpInitiation *init;
 
-           init=(const struct sctpInitiation*)(chunkDescPtr+1);
-           ND_PRINT((ndo, "[init tag: %u] ", EXTRACT_32BITS(&init->initTag)));
-           ND_PRINT((ndo, "[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit)));
-           ND_PRINT((ndo, "[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams)));
-           ND_PRINT((ndo, "[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams)));
-           ND_PRINT((ndo, "[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN)));
-
-#if(0) /* ALC you can add code for optional params here */
-           if( (init+1) < chunkEnd )
-             ND_PRINT((ndo, " @@@@@ UNFINISHED @@@@@@%s\n",
-                    "Optional params present, but not printed."));
+           if (chunkLengthRemaining < sizeof(*init)) {
+               ND_PRINT("bogus chunk length %u]", chunkLength);
+               return;
+           }
+           init=(const struct sctpInitiation*)bp;
+           ND_PRINT("[init tag: %u] ", GET_BE_U_4(init->initTag));
+           ND_PRINT("[rwnd: %u] ", GET_BE_U_4(init->rcvWindowCredit));
+           ND_PRINT("[OS: %u] ", GET_BE_U_2(init->NumPreopenStreams));
+           ND_PRINT("[MIS: %u] ", GET_BE_U_2(init->MaxInboundStreams));
+           ND_PRINT("[init TSN: %u] ", GET_BE_U_4(init->initialTSN));
+           bp += sizeof(*init);
+           sctpPacketLengthRemaining -= sizeof(*init);
+           chunkLengthRemaining -= sizeof(*init);
+
+#if 0 /* ALC you can add code for optional params here */
+           if( chunkLengthRemaining != 0 )
+             ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n",
+                    "Optional params present, but not printed.");
 #endif
+           bp += chunkLengthRemaining;
+           sctpPacketLengthRemaining -= chunkLengthRemaining;
+           chunkLengthRemaining = 0;
            break;
          }
        case SCTP_SELECTIVE_ACK:
          {
            const struct sctpSelectiveAck *sack;
            const struct sctpSelectiveFrag *frag;
-           int fragNo, tsnNo;
+           u_int fragNo, tsnNo;
            const u_char *dupTSN;
 
-           sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1);
-           ND_PRINT((ndo, "[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN)));
-           ND_PRINT((ndo, "[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd)));
-           ND_PRINT((ndo, "[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc)));
-           ND_PRINT((ndo, "[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns)));
+           if (chunkLengthRemaining < sizeof(*sack)) {
+             ND_PRINT("bogus chunk length %u]", chunkLength);
+             return;
+           }
+           sack=(const struct sctpSelectiveAck*)bp;
+           ND_PRINT("[cum ack %u] ", GET_BE_U_4(sack->highestConseqTSN));
+           ND_PRINT("[a_rwnd %u] ", GET_BE_U_4(sack->updatedRwnd));
+           ND_PRINT("[#gap acks %u] ", GET_BE_U_2(sack->numberOfdesc));
+           ND_PRINT("[#dup tsns %u] ", GET_BE_U_2(sack->numDupTsns));
+           bp += sizeof(*sack);
+           sctpPacketLengthRemaining -= sizeof(*sack);
+           chunkLengthRemaining -= sizeof(*sack);
 
 
            /* print gaps */
-           for (frag = ( (const struct sctpSelectiveFrag *)
-                         ((const struct sctpSelectiveAck *) sack+1)),
-                  fragNo=0;
-                (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc);
-                frag++, fragNo++)
-             ND_PRINT((ndo, "\n\t\t[gap ack block #%d: start = %u, end = %u] ",
+           for (fragNo=0;
+                chunkLengthRemaining != 0 && fragNo < GET_BE_U_2(sack->numberOfdesc);
+                bp += sizeof(*frag), sctpPacketLengthRemaining -= sizeof(*frag), chunkLengthRemaining -= sizeof(*frag), fragNo++) {
+             if (chunkLengthRemaining < sizeof(*frag)) {
+               ND_PRINT("bogus chunk length %u]", chunkLength);
+               return;
+             }
+             frag = (const struct sctpSelectiveFrag *)bp;
+             ND_PRINT("\n\t\t[gap ack block #%u: start = %u, end = %u] ",
                     fragNo+1,
-                    EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart),
-                    EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd)));
-
+                    GET_BE_U_4(sack->highestConseqTSN) + GET_BE_U_2(frag->fragmentStart),
+                    GET_BE_U_4(sack->highestConseqTSN) + GET_BE_U_2(frag->fragmentEnd));
+           }
 
            /* print duplicate TSNs */
-           for (dupTSN = (const u_char *)frag, tsnNo=0;
-                (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns);
-                dupTSN += 4, tsnNo++)
-             ND_PRINT((ndo, "\n\t\t[dup TSN #%u: %u] ", tsnNo+1,
-                 EXTRACT_32BITS(dupTSN)));
-
+           for (tsnNo=0;
+                chunkLengthRemaining != 0 && tsnNo<GET_BE_U_2(sack->numDupTsns);
+                bp += 4, sctpPacketLengthRemaining -= 4, chunkLengthRemaining -= 4, tsnNo++) {
+             if (chunkLengthRemaining < 4) {
+               ND_PRINT("bogus chunk length %u]", chunkLength);
+               return;
+             }
+             dupTSN = (const u_char *)bp;
+             ND_PRINT("\n\t\t[dup TSN #%u: %u] ", tsnNo+1,
+                      GET_BE_U_4(dupTSN));
+           }
+           break;
+         }
+       default :
+         {
+           bp += chunkLengthRemaining;
+           sctpPacketLengthRemaining -= chunkLengthRemaining;
+           chunkLengthRemaining = 0;
            break;
          }
        }
 
-       if (ndo->ndo_vflag < 2)
-         sep = ", (";
+      /*
+       * Any extra stuff at the end of the chunk?
+       * XXX - report this?
+       */
+      bp += chunkLengthRemaining;
+      sctpPacketLengthRemaining -= chunkLengthRemaining;
+
+      if (ndo->ndo_vflag < 2)
+       sep = ", (";
+
+      if (align != 0) {
+       /*
+        * Fail if the alignment padding isn't in the captured data.
+        * Otherwise, skip it.
+        */
+       ND_TCHECK_LEN(bp, align);
+       bp += align;
+       sctpPacketLengthRemaining -= align;
+      }
     }
     return;
 
 trunc:
-    ND_PRINT((ndo, "[|sctp]"));
+    nd_print_trunc(ndo);
 }