]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-sctp.c
More UNALIGNED_MEM{CPY,CMP} on IP addresses.
[tcpdump] / print-sctp.c
index 05c753a52e6cf892953ebbfc60ce1b207e58327a..dc7916b3d1a18ca34a9b62684fc99890ace2a1f6 100644 (file)
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static const char rcsid[] _U_ =
-"@(#) $Header: /tcpdump/master/tcpdump/print-sctp.c,v 1.21 2007-09-13 18:03:49 guy Exp $ (NETLAB/PEL)";
-#endif
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include <tcpdump-stdinc.h>
 
-#include "sctpHeader.h"
-#include "sctpConstants.h"
 #include <assert.h>
 
 #include <stdio.h>
@@ -59,6 +52,365 @@ static const char rcsid[] _U_ =
 #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 */
@@ -74,6 +426,8 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
   const struct sctpChunkDesc *chunkDescPtr;
   const void *nextChunk;
   const char *sep;
+  int isforces = 0;
+
 
   sctpPktHdr = (const struct sctpHeader*) bp;
   endPacketPtr = (const u_char*)sctpPktHdr+sctpPacketLength;
@@ -120,6 +474,15 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
   }
   fflush(stdout);
 
+  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
@@ -193,9 +556,23 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
            printf("[SSEQ %u] ", EXTRACT_16BITS(&dataHdrPtr->sequence));
            printf("[PPID 0x%x] ", EXTRACT_32BITS(&dataHdrPtr->payloadtype));
            fflush(stdout);
-
-           if (vflag >= 2)        /* if verbose output is specified */
-             {                    /* at the command line */
+           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");
@@ -203,16 +580,16 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
                if (!suppress_default_print) {
                        payloadPtr = (const u_char *) (++dataHdrPtr);
                        printf(":");
-                       if (htons(chunkDescPtr->chunkLength) <
+                       if (EXTRACT_16BITS(&chunkDescPtr->chunkLength) <
                            sizeof(struct sctpDataPart)+
                            sizeof(struct sctpChunkDesc)+1) {
                                /* Less than 1 byte of chunk payload */
                                printf("bogus chunk length %u]",
-                                   htons(chunkDescPtr->chunkLength));
+                                   EXTRACT_16BITS(&chunkDescPtr->chunkLength));
                                return;
                        }
                        default_print(payloadPtr,
-                             htons(chunkDescPtr->chunkLength) -
+                             EXTRACT_16BITS(&chunkDescPtr->chunkLength) -
                              (sizeof(struct sctpDataPart)+
                              sizeof(struct sctpChunkDesc)));
                } else
@@ -295,15 +672,8 @@ void sctp_print(const u_char *bp,        /* beginning of sctp packet */
            break;
          }
        case SCTP_HEARTBEAT_REQUEST :
-         {
-           const struct sctpHBsender *hb;
-
-           hb=(const struct sctpHBsender*)chunkDescPtr;
-
-           printf("[HB REQ] ");
-
-           break;
-         }
+         printf("[HB REQ] ");
+         break;
        case SCTP_HEARTBEAT_ACK :
          printf("[HB ACK] ");
          break;