]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-sctp.c
More UNALIGNED_MEM{CPY,CMP} on IP addresses.
[tcpdump] / print-sctp.c
index 7fdf1c7d52b5b31c58fb6128cd2805c44d608e74..dc7916b3d1a18ca34a9b62684fc99890ace2a1f6 100644 (file)
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-"@(#) $Header: /tcpdump/master/tcpdump/print-sctp.c,v 1.4 2001-06-27 02:48:45 itojun Exp $ (NETLAB/PEL)";
-#endif
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/socket.h>
+#include <tcpdump-stdinc.h>
 
-#include <unistd.h>
-#include "sctpHeader.h"
-#include "sctpConstants.h"
 #include <assert.h>
 
-#if __STDC__
-struct mbuf;
-struct rtentry;
-#endif
-#include <net/if.h>
-
-#include <netinet/in.h>
-
 #include <stdio.h>
 #include <string.h>
 
@@ -70,172 +52,562 @@ struct rtentry;
 #include "ip6.h"
 #endif
 
+/* Definitions from:
+ *
+ * SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Cisco nor of Motorola may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the SCTP reference Implementation
+ *
+ *
+ * Please send any bug reports or fixes you make to one of the following email
+ * addresses:
+ *
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorperated into the next SCTP release.
+ */
+
+/* The valid defines for all message
+ * types know to SCTP. 0 is reserved
+ */
+#define SCTP_DATA              0x00
+#define SCTP_INITIATION                0x01
+#define SCTP_INITIATION_ACK    0x02
+#define SCTP_SELECTIVE_ACK     0x03
+#define SCTP_HEARTBEAT_REQUEST 0x04
+#define SCTP_HEARTBEAT_ACK     0x05
+#define SCTP_ABORT_ASSOCIATION 0x06
+#define SCTP_SHUTDOWN          0x07
+#define SCTP_SHUTDOWN_ACK      0x08
+#define SCTP_OPERATION_ERR     0x09
+#define SCTP_COOKIE_ECHO       0x0a
+#define SCTP_COOKIE_ACK         0x0b
+#define SCTP_ECN_ECHO          0x0c
+#define SCTP_ECN_CWR           0x0d
+#define SCTP_SHUTDOWN_COMPLETE 0x0e
+#define SCTP_FORWARD_CUM_TSN    0xc0
+#define SCTP_RELIABLE_CNTL      0xc1
+#define SCTP_RELIABLE_CNTL_ACK  0xc2
+
+/* Data Chuck Specific Flags */
+#define SCTP_DATA_FRAG_MASK    0x03
+#define SCTP_DATA_MIDDLE_FRAG  0x00
+#define SCTP_DATA_LAST_FRAG    0x01
+#define SCTP_DATA_FIRST_FRAG   0x02
+#define SCTP_DATA_NOT_FRAG     0x03
+#define SCTP_DATA_UNORDERED    0x04
+
+#define SCTP_ADDRMAX 60
+
+#define CHAN_HP 6704
+#define CHAN_MP 6705
+#define CHAN_LP 6706
+
+/* the sctp common header */
+
+struct sctpHeader{
+  u_int16_t source;
+  u_int16_t destination;
+  u_int32_t verificationTag;
+  u_int32_t adler32;
+};
+
+/* various descriptor parsers */
+
+struct sctpChunkDesc{
+  u_int8_t chunkID;
+  u_int8_t chunkFlg;
+  u_int16_t chunkLength;
+};
+
+struct sctpParamDesc{
+  u_int16_t paramType;
+  u_int16_t paramLength;
+};
+
+
+struct sctpRelChunkDesc{
+  struct sctpChunkDesc chk;
+  u_int32_t serialNumber;
+};
+
+struct sctpVendorSpecificParam {
+  struct sctpParamDesc p;  /* type must be 0xfffe */
+  u_int32_t vendorId;     /* vendor ID from RFC 1700 */
+  u_int16_t vendorSpecificType;
+  u_int16_t vendorSpecificLen;
+};
+
+
+/* Structures for the control parts */
+
+
+
+/* Sctp association init request/ack */
+
+/* this is used for init ack, too */
+struct sctpInitiation{
+  u_int32_t initTag;           /* tag of mine */
+  u_int32_t rcvWindowCredit;   /* rwnd */
+  u_int16_t NumPreopenStreams; /* OS */
+  u_int16_t MaxInboundStreams;     /* MIS */
+  u_int32_t initialTSN;
+  /* optional param's follow in sctpParamDesc form */
+};
+
+struct sctpV4IpAddress{
+  struct sctpParamDesc p;      /* type is set to SCTP_IPV4_PARAM_TYPE, len=10 */
+  u_int32_t  ipAddress;
+};
+
+
+struct sctpV6IpAddress{
+  struct sctpParamDesc p;      /* type is set to SCTP_IPV6_PARAM_TYPE, len=22 */
+  u_int8_t  ipAddress[16];
+};
+
+struct sctpDNSName{
+  struct sctpParamDesc param;
+  u_int8_t name[1];
+};
+
+
+struct sctpCookiePreserve{
+  struct sctpParamDesc p;      /* type is set to SCTP_COOKIE_PRESERVE, len=8 */
+  u_int32_t extraTime;
+};
+
+
+struct sctpTimeStamp{
+  u_int32_t ts_sec;
+  u_int32_t ts_usec;
+};
+
+/* wire structure of my cookie */
+struct cookieMessage{
+  u_int32_t TieTag_curTag;             /* copied from assoc if present */
+  u_int32_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 */
+  u_int32_t addressWhereISent[4];      /* I make this 4 ints so I get 128bits for future */
+  int32_t addrtype;                    /* address type */
+  u_int16_t locScope;                  /* V6 local scope flag */
+  u_int16_t siteScope;                 /* V6 site scope flag */
+  /* at the end is tacked on the INIT chunk sent in
+   * its entirety and of course our
+   * signature.
+   */
+};
+
+
+/* this guy is for use when
+ * I have a initiate message gloming the
+ * things together.
+
+ */
+struct sctpUnifiedInit{
+  struct sctpChunkDesc uh;
+  struct sctpInitiation initm;
+};
+
+struct sctpSendableInit{
+  struct sctpHeader mh;
+  struct sctpUnifiedInit msg;
+};
+
+
+/* Selective Acknowledgement
+ * has the following structure with
+ * a optional ammount of trailing int's
+ * on the last part (based on the numberOfDesc
+ * field).
+ */
+
+struct sctpSelectiveAck{
+  u_int32_t highestConseqTSN;
+  u_int32_t updatedRwnd;
+  u_int16_t numberOfdesc;
+  u_int16_t numDupTsns;
+};
+
+struct sctpSelectiveFrag{
+  u_int16_t fragmentStart;
+  u_int16_t fragmentEnd;
+};
+
+
+struct sctpUnifiedSack{
+  struct sctpChunkDesc uh;
+  struct sctpSelectiveAck sack;
+};
+
+/* for both RTT request/response the
+ * following is sent
+ */
+
+struct sctpHBrequest {
+  u_int32_t time_value_1;
+  u_int32_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];
+  u_int16_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.
+ */
+struct sctpUnifiedAbort{
+  struct sctpChunkDesc uh;
+};
+
+struct sctpUnifiedAbortLight{
+  struct sctpHeader mh;
+  struct sctpChunkDesc uh;
+};
+
+struct sctpUnifiedAbortHeavy{
+  struct sctpHeader mh;
+  struct sctpChunkDesc uh;
+  u_int16_t causeCode;
+  u_int16_t causeLen;
+};
+
+/* For the graceful shutdown we must carry
+ * the tag (in common header)  and the highest consequitive acking value
+ */
+struct sctpShutdown {
+  u_int32_t TSN_Seen;
+};
+
+struct sctpUnifiedShutdown{
+  struct sctpChunkDesc uh;
+  struct sctpShutdown shut;
+};
+
+/* in the unified message we add the trailing
+ * stream id since it is the only message
+ * that is defined as a operation error.
+ */
+struct sctpOpErrorCause{
+  u_int16_t cause;
+  u_int16_t causeLen;
+};
+
+struct sctpUnifiedOpError{
+  struct sctpChunkDesc uh;
+  struct sctpOpErrorCause c;
+};
+
+struct sctpUnifiedStreamError{
+  struct sctpHeader mh;
+  struct sctpChunkDesc uh;
+  struct sctpOpErrorCause c;
+  u_int16_t strmNum;
+  u_int16_t reserved;
+};
+
+struct staleCookieMsg{
+  struct sctpHeader mh;
+  struct sctpChunkDesc uh;
+  struct sctpOpErrorCause c;
+  u_int32_t moretime;
+};
+
+/* the following is used in all sends
+ * where nothing is needed except the
+ * chunk/type i.e. shutdownAck Abort */
+
+struct sctpUnifiedSingleMsg{
+  struct sctpHeader mh;
+  struct sctpChunkDesc uh;
+};
+
+struct sctpDataPart{
+  u_int32_t TSN;
+  u_int16_t streamId;
+  u_int16_t sequence;
+  u_int32_t payloadtype;
+};
+
+struct sctpUnifiedDatagram{
+  struct sctpChunkDesc uh;
+  struct sctpDataPart dp;
+};
+
+struct sctpECN_echo{
+  struct sctpChunkDesc uh;
+  u_int32_t Lowest_TSN;
+};
+
+
+struct sctpCWR{
+  struct sctpChunkDesc uh;
+  u_int32_t TSN_reduced_at;
+};
+
+static const struct tok ForCES_channels[] = {
+       { CHAN_HP, "ForCES HP" },
+       { CHAN_MP, "ForCES MP" },
+       { CHAN_LP, "ForCES LP" },
+       { 0, NULL }
+};
+
+static inline int isForCES_port(u_short Port)
+{
+       if (Port == CHAN_HP)
+               return 1;
+       if (Port == CHAN_MP)
+               return 1;
+       if (Port == CHAN_LP)
+               return 1;
+
+       return 0;
+}
+
 void sctp_print(const u_char *bp,        /* beginning of sctp packet */
                const u_char *bp2,       /* beginning of enclosing */
                u_int sctpPacketLength)  /* ip packet */
-{ 
+{
   const struct sctpHeader *sctpPktHdr;
   const struct ip *ip;
 #ifdef INET6
   const struct ip6_hdr *ip6;
 #endif
-  const u_char *cp;
-  void *endPacketPtr;
+  const void *endPacketPtr;
   u_short sourcePort, destPort;
   int chunkCount;
-  struct sctpChunkDesc *chunkDescPtr;
-  void *nextChunk;
+  const struct sctpChunkDesc *chunkDescPtr;
+  const void *nextChunk;
+  const char *sep;
+  int isforces = 0;
+
+
+  sctpPktHdr = (const struct sctpHeader*) bp;
+  endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength;
 
-  sctpPktHdr = (struct sctpHeader*) bp;
-  endPacketPtr = ((u_char*)((u_char*)sctpPktHdr+sctpPacketLength));
-  
   if( (u_long) endPacketPtr > (u_long) snapend)
-    endPacketPtr = (void *) snapend;
+    endPacketPtr = (const void *) snapend;
   ip = (struct ip *)bp2;
 #ifdef INET6
   if (IP_V(ip) == 6)
-    ip6 = (struct ip6_hdr *)bp2;
+    ip6 = (const struct ip6_hdr *)bp2;
   else
     ip6 = NULL;
 #endif /*INET6*/
-  cp = (u_char *)(sctpPktHdr + 1);
-  if (cp > snapend)
-    { 
-      printf("[|sctp]");
-      return; 
-    } 
-
-  if (sctpPacketLength < sizeof(struct sctpHeader)) 
+  TCHECK(*sctpPktHdr);
+
+  if (sctpPacketLength < sizeof(struct sctpHeader))
     {
-      (void)printf("truncated-sctp - %ld bytes missing!", 
+      (void)printf("truncated-sctp - %ld bytes missing!",
                   (long)sctpPacketLength-sizeof(struct sctpHeader));
       return;
     }
-  
+
   /*    sctpPacketLength -= sizeof(struct sctpHeader);  packet length  */
   /*                         is now only as long as the payload  */
 
-  sourcePort = ntohs(sctpPktHdr->source);
-  destPort = ntohs(sctpPktHdr->destination);
-  
+  sourcePort = EXTRACT_16BITS(&sctpPktHdr->source);
+  destPort = EXTRACT_16BITS(&sctpPktHdr->destination);
+
 #ifdef INET6
   if (ip6) {
-    if (ip6->ip6_nxt == IPPROTO_SCTP) {
-      (void)printf("%s.%d > %s.%d: sctp",
-        ip6addr_string(&ip6->ip6_src),
-        sourcePort,
-        ip6addr_string(&ip6->ip6_dst),
-        destPort);
-    } else {
-      (void)printf("%d > %d: sctp",
-        sourcePort, destPort);
-    }
+    (void)printf("%s.%d > %s.%d: sctp",
+      ip6addr_string(&ip6->ip6_src),
+      sourcePort,
+      ip6addr_string(&ip6->ip6_dst),
+      destPort);
   } else
 #endif /*INET6*/
   {
-    if (ip->ip_p == IPPROTO_SCTP) {
-      (void)printf("%s.%d > %s.%d: sctp",
-        ipaddr_string(&ip->ip_src),
-        sourcePort,
-        ipaddr_string(&ip->ip_dst),
-        destPort);
-    } else {
-      (void)printf("%d > %d: sctp",
-        sourcePort, destPort);
-    }
+    (void)printf("%s.%d > %s.%d: sctp",
+      ipaddr_string(&ip->ip_src),
+      sourcePort,
+      ipaddr_string(&ip->ip_dst),
+      destPort);
   }
   fflush(stdout);
 
-  if (vflag < 2)
-       return;
-  
+  if (isForCES_port(sourcePort)) {
+         printf("[%s]", tok2str(ForCES_channels, NULL, sourcePort));
+         isforces = 1;
+  }
+  if (isForCES_port(destPort)) {
+         printf("[%s]", tok2str(ForCES_channels, NULL, destPort));
+         isforces = 1;
+  }
+
+  if (vflag >= 2)
+    sep = "\n\t";
+  else
+    sep = " (";
   /* cycle through all chunks, printing information on each one */
-  for (chunkCount = 0, 
-        chunkDescPtr = (struct sctpChunkDesc *) ( (u_char*) sctpPktHdr +
-                                                  sizeof(struct sctpHeader));
+  for (chunkCount = 0,
+        chunkDescPtr = (const struct sctpChunkDesc *)
+           ((const u_char*) sctpPktHdr + sizeof(struct sctpHeader));
        chunkDescPtr != NULL &&
-        ( (void *)  ((u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc))
+        ( (const void *)
+           ((const u_char *) chunkDescPtr + sizeof(struct sctpChunkDesc))
           <= endPacketPtr);
-       
-       chunkDescPtr = (struct sctpChunkDesc *) nextChunk, chunkCount++)
+
+       chunkDescPtr = (const struct sctpChunkDesc *) nextChunk, chunkCount++)
     {
-      u_short align;
-      u_char *chunkEnd;
-      
-      chunkEnd = ((u_char*)chunkDescPtr + ntohs(chunkDescPtr->chunkLength));
-      
-      align=ntohs(chunkDescPtr->chunkLength) % 4;
+      u_int16_t chunkLength;
+      const u_char *chunkEnd;
+      u_int16_t align;
+
+      TCHECK(*chunkDescPtr);
+      chunkLength = EXTRACT_16BITS(&chunkDescPtr->chunkLength);
+      if (chunkLength < sizeof(*chunkDescPtr)) {
+       printf("%s%d) [Bad chunk length %u]", sep, chunkCount+1, chunkLength);
+       break;
+      }
+
+      TCHECK2(*((u_int8_t *)chunkDescPtr), chunkLength);
+      chunkEnd = ((const u_char*)chunkDescPtr + chunkLength);
+
+      align=chunkLength % 4;
       if (align != 0)
        align = 4 - align;
 
-      nextChunk = (void *) (chunkEnd + align);
+      nextChunk = (const void *) (chunkEnd + align);
 
-      printf("\n\t%d) ", chunkCount+1);
+      printf("%s%d) ", sep, chunkCount+1);
       switch (chunkDescPtr->chunkID)
        {
        case SCTP_DATA :
          {
-           struct sctpDataPart *dataHdrPtr;
-           
+           const struct sctpDataPart *dataHdrPtr;
+
            printf("[DATA] ");
-           
-           if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 
+
+           if ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED)
                == SCTP_DATA_UNORDERED)
              printf("(U)");
 
-           if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 
+           if ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG)
                == SCTP_DATA_FIRST_FRAG)
              printf("(B)");
-           
-           if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 
+
+           if ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG)
                == SCTP_DATA_LAST_FRAG)
              printf("(E)");
 
-           if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED) 
-                == SCTP_DATA_UNORDERED) 
+           if( ((chunkDescPtr->chunkFlg & SCTP_DATA_UNORDERED)
+                == SCTP_DATA_UNORDERED)
                ||
-               ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG) 
+               ((chunkDescPtr->chunkFlg & SCTP_DATA_FIRST_FRAG)
                 == SCTP_DATA_FIRST_FRAG)
                ||
-               ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG) 
+               ((chunkDescPtr->chunkFlg & SCTP_DATA_LAST_FRAG)
                 == SCTP_DATA_LAST_FRAG) )
              printf(" ");
 
-           dataHdrPtr=(struct sctpDataPart*)(chunkDescPtr+1);
-                            
-           printf("[TSN: %u] ", (u_int32_t)ntohl(dataHdrPtr->TSN));
-           printf("[SID: %u] ", ntohs(dataHdrPtr->streamId));
-           printf("[SSEQ %u] ", ntohs(dataHdrPtr->sequence));
-           printf("[PPID 0x%x] ", (u_int32_t)ntohl(dataHdrPtr->payloadtype));
+           dataHdrPtr=(const struct sctpDataPart*)(chunkDescPtr+1);
+
+           printf("[TSN: %u] ", EXTRACT_32BITS(&dataHdrPtr->TSN));
+           printf("[SID: %u] ", EXTRACT_16BITS(&dataHdrPtr->streamId));
+           printf("[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence));
+           printf("[PPID 0x%x] ", EXTRACT_32BITS(&dataHdrPtr->payloadtype));
            fflush(stdout);
+           if (isforces) {
+               const u_char *payloadPtr;
+               u_int chunksize = sizeof(struct sctpDataPart)+
+                                 sizeof(struct sctpChunkDesc);
+               payloadPtr = (const u_char *) (dataHdrPtr + 1);
+               if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) <
+                       sizeof(struct sctpDataPart)+
+                       sizeof(struct sctpChunkDesc)+1) {
+               /* Less than 1 byte of chunk payload */
+                       printf("bogus ForCES chunk length %u]",
+                           EXTRACT_16BITS(&chunkDescPtr->chunkLength));
+                       return;
+               }
+
+               forces_print(payloadPtr, EXTRACT_16BITS(&chunkDescPtr->chunkLength)- chunksize);
+          } else if (vflag >= 2) {     /* if verbose output is specified */
+                                       /* at the command line */
+               const u_char *payloadPtr;
+
+               printf("[Payload");
 
-           if (vflag)          /* if verbose output is specified */
-             {                    /* at the command line */
-               char *payloadPtr;
-               
-               printf("[Payload: {");
-               fflush(stdout);
-
-               payloadPtr = (char *) (++dataHdrPtr);
-               write(STDOUT_FILENO, payloadPtr, 
-                     htons(chunkDescPtr->chunkLength)-1 -
-                     sizeof(struct sctpDataPart)-sizeof(struct sctpChunkDesc));
-               printf("}] ");
-               fflush(stdout);
+               if (!suppress_default_print) {
+                       payloadPtr = (const u_char *) (++dataHdrPtr);
+                       printf(":");
+                       if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) <
+                           sizeof(struct sctpDataPart)+
+                           sizeof(struct sctpChunkDesc)+1) {
+                               /* Less than 1 byte of chunk payload */
+                               printf("bogus chunk length %u]",
+                                   EXTRACT_16BITS(&chunkDescPtr->chunkLength));
+                               return;
+                       }
+                       default_print(payloadPtr,
+                             EXTRACT_16BITS(&chunkDescPtr->chunkLength) -
+                             (sizeof(struct sctpDataPart)+
+                             sizeof(struct sctpChunkDesc)));
+               } else
+                       printf("]");
              }
            break;
          }
        case SCTP_INITIATION :
          {
-           struct sctpInitiation *init;
+           const struct sctpInitiation *init;
 
            printf("[INIT] ");
-           init=(struct sctpInitiation*)(chunkDescPtr+1);
-           printf("[init tag: %u] ", (u_int32_t)ntohl(init->initTag));
-           printf("[rwnd: %u] ", (u_int32_t)ntohl(init->rcvWindowCredit));
-           printf("[OS: %u] ", ntohs(init->NumPreopenStreams));
-           printf("[MIS: %u] ", ntohs(init->MaxInboundStreams));
-           printf("[init TSN: %u] ", (u_int32_t)ntohl(init->initialTSN));
+           init=(const struct sctpInitiation*)(chunkDescPtr+1);
+           printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag));
+           printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit));
+           printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams));
+           printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams));
+           printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN));
 
 #if(0) /* ALC you can add code for optional params here */
            if( (init+1) < chunkEnd )
@@ -246,16 +618,16 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
          }
        case SCTP_INITIATION_ACK :
          {
-           struct sctpInitiation *init;
-           
+           const struct sctpInitiation *init;
+
            printf("[INIT ACK] ");
-           init=(struct sctpInitiation*)(chunkDescPtr+1);
-           printf("[init tag: %u] ", (u_int32_t)ntohl(init->initTag));
-           printf("[rwnd: %u] ", (u_int32_t)ntohl(init->rcvWindowCredit));
-           printf("[OS: %u] ", ntohs(init->NumPreopenStreams));
-           printf("[MIS: %u] ", ntohs(init->MaxInboundStreams));
-           printf("[init TSN: %u] ", (u_int32_t)ntohl(init->initialTSN));
-           
+           init=(const struct sctpInitiation*)(chunkDescPtr+1);
+           printf("[init tag: %u] ", EXTRACT_32BITS(&init->initTag));
+           printf("[rwnd: %u] ", EXTRACT_32BITS(&init->rcvWindowCredit));
+           printf("[OS: %u] ", EXTRACT_16BITS(&init->NumPreopenStreams));
+           printf("[MIS: %u] ", EXTRACT_16BITS(&init->MaxInboundStreams));
+           printf("[init TSN: %u] ", EXTRACT_32BITS(&init->initialTSN));
+
 #if(0) /* ALC you can add code for optional params here */
            if( (init+1) < chunkEnd )
              printf(" @@@@@ UNFINISHED @@@@@@%s\n",
@@ -265,50 +637,43 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
          }
        case SCTP_SELECTIVE_ACK:
          {
-           struct sctpSelectiveAck *sack;
-           struct sctpSelectiveFrag *frag; 
+           const struct sctpSelectiveAck *sack;
+           const struct sctpSelectiveFrag *frag;
            int fragNo, tsnNo;
-           u_long *dupTSN;
+           const u_char *dupTSN;
 
            printf("[SACK] ");
-           sack=(struct sctpSelectiveAck*)(chunkDescPtr+1);
-           printf("[cum ack %u] ", (u_int32_t)ntohl(sack->highestConseqTSN));
-           printf("[a_rwnd %u] ", (u_int32_t)ntohl(sack->updatedRwnd));
-           printf("[#gap acks %u] ", ntohs(sack->numberOfdesc));
-           printf("[#dup tsns %u] ", ntohs(sack->numDupTsns));
-           
-           
+           sack=(const struct sctpSelectiveAck*)(chunkDescPtr+1);
+           printf("[cum ack %u] ", EXTRACT_32BITS(&sack->highestConseqTSN));
+           printf("[a_rwnd %u] ", EXTRACT_32BITS(&sack->updatedRwnd));
+           printf("[#gap acks %u] ", EXTRACT_16BITS(&sack->numberOfdesc));
+           printf("[#dup tsns %u] ", EXTRACT_16BITS(&sack->numDupTsns));
+
+
            /* print gaps */
-           for (frag = ( (struct sctpSelectiveFrag *)
-                         ((struct sctpSelectiveAck *) sack+1)),
+           for (frag = ( (const struct sctpSelectiveFrag *)
+                         ((const struct sctpSelectiveAck *) sack+1)),
                   fragNo=0;
-                (void *)frag < nextChunk && fragNo < ntohs(sack->numberOfdesc);
+                (const void *)frag < nextChunk && fragNo < EXTRACT_16BITS(&sack->numberOfdesc);
                 frag++, fragNo++)
-             printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ", 
+             printf("\n\t\t[gap ack block #%d: start = %u, end = %u] ",
                     fragNo+1,
-                    (u_int32_t)(ntohl(sack->highestConseqTSN) + ntohs(frag->fragmentStart)),
-                    (u_int32_t)(ntohl(sack->highestConseqTSN) + ntohs(frag->fragmentEnd)));
-           
+                    EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentStart),
+                    EXTRACT_32BITS(&sack->highestConseqTSN) + EXTRACT_16BITS(&frag->fragmentEnd));
+
 
            /* print duplicate TSNs */
-           for (dupTSN = (u_long*)frag, tsnNo=0; 
-                (void *) dupTSN < nextChunk && tsnNo<ntohs(sack->numDupTsns);
-                dupTSN++, tsnNo++)
+           for (dupTSN = (const u_char *)frag, tsnNo=0;
+                (const void *) dupTSN < nextChunk && tsnNo<EXTRACT_16BITS(&sack->numDupTsns);
+                dupTSN += 4, tsnNo++)
              printf("\n\t\t[dup TSN #%u: %u] ", tsnNo+1,
-                 (u_int32_t)ntohl(*dupTSN));
+                 EXTRACT_32BITS(dupTSN));
 
            break;
          }
        case SCTP_HEARTBEAT_REQUEST :
-         {
-           struct sctpHBsender *hb;
-
-           hb=(struct sctpHBsender*)chunkDescPtr;
-
-           printf("[HB REQ] ");
-           
-           break;
-         }
+         printf("[HB REQ] ");
+         break;
        case SCTP_HEARTBEAT_ACK :
          printf("[HB ACK] ");
          break;
@@ -333,7 +698,7 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
        case SCTP_ECN_ECHO :
          printf("[ECN ECHO] ");
          break;
-       case SCTP_ECN_CWR : 
+       case SCTP_ECN_CWR :
          printf("[ECN CWR] ");
          break;
        case SCTP_SHUTDOWN_COMPLETE :
@@ -352,5 +717,13 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
          printf("[Unknown chunk type: 0x%x]", chunkDescPtr->chunkID);
          return;
        }
+
+       if (vflag < 2)
+         sep = ", (";
     }
+    return;
+
+trunc:
+    printf("[|sctp]");
+    return;
 }