]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-erspan.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-erspan.c
index 3bcf0acd749832545fd73c0aef5378ade07a7f05..498c0ba5f5b3fe3a0fa6f547c61ef4353defe9fd 100644 (file)
  * Specifications: I-D draft-foschiano-erspan-03.
  */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
 
 #include "netdissect-stdinc.h"
 
 #define ND_LONGJMP_FROM_TCHECK
 #include "netdissect.h"
 #include "extract.h"
+#include "gre.h"
 
+/*
+ * ERSPAN Type II.
+ */
 #define ERSPAN2_VER_SHIFT      28
 #define ERSPAN2_VER_MASK       (0xfU << ERSPAN2_VER_SHIFT)
 #define ERSPAN2_VER            (0x1U << ERSPAN2_VER_SHIFT)
 #define ERSPAN2_INDEX_SHIFT    0
 #define ERSPAN2_INDEX_MASK     (0xfffffU << ERSPAN2_INDEX_SHIFT)
 
-/*
- * XXX - eh?
- */
-#define        GRE_SP          0x1000          /* sequence# present */
-
 void
-erspan_print(netdissect_options *ndo, uint16_t flags, const u_char *bp, u_int len)
+erspan_i_ii_print(netdissect_options *ndo, uint16_t flags, const u_char *bp, u_int len)
 {
        uint32_t hdr, ver, vlan, cos, en, sid, index;
 
@@ -77,11 +74,17 @@ erspan_print(netdissect_options *ndo, uint16_t flags, const u_char *bp, u_int le
        nd_print_protocol(ndo);
 
        if (!(flags & GRE_SP)) {
-               ND_PRINT(" I: ");
+               /*
+                * ERSPAN Type I; no header, just a raw Ethernet frame.
+                */
+               ND_PRINT(" type1: ");
                ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
                return;
        }
 
+       /*
+        * ERSPAN Type II.
+        */
        ND_ICHECK_U(len, <, 4);
        hdr = GET_BE_U_4(bp);
        bp += 4;
@@ -89,13 +92,16 @@ erspan_print(netdissect_options *ndo, uint16_t flags, const u_char *bp, u_int le
 
        ver = hdr & ERSPAN2_VER_MASK;
        if (ver != ERSPAN2_VER) {
+               /*
+                * Not Type II.
+                */
                ver >>= ERSPAN2_VER_SHIFT;
                ND_PRINT(" erspan-unknown-version-%x", ver);
                return;
        }
 
        if (ndo->ndo_vflag)
-               ND_PRINT(" II");
+               ND_PRINT(" type2");
 
        sid = (hdr & ERSPAN2_SID_MASK) >> ERSPAN2_SID_SHIFT;
        ND_PRINT(" session %u", sid);
@@ -141,3 +147,147 @@ erspan_print(netdissect_options *ndo, uint16_t flags, const u_char *bp, u_int le
 invalid:
        nd_print_invalid(ndo);
 }
+
+/*
+ * ERSPAN Type III.
+ */
+#define ERSPAN3_VER_SHIFT              28
+#define ERSPAN3_VER_MASK               (0xfU << ERSPAN3_VER_SHIFT)
+#define ERSPAN3_VER                    (0x2U << ERSPAN3_VER_SHIFT)
+#define ERSPAN3_VLAN_SHIFT             16
+#define ERSPAN3_VLAN_MASK              (0xfffU << ERSPAN3_VLAN_SHIFT)
+#define ERSPAN3_COS_SHIFT              13
+#define ERSPAN3_COS_MASK               (0x7U << ERSPAN3_COS_SHIFT)
+#define ERSPAN3_BSO_SHIFT              11
+#define ERSPAN3_BSO_MASK               (0x3U << ERSPAN3_BSO_SHIFT)
+#define ERSPAN3_BSO_GOOD_UNKNOWN       0x0U
+#define ERSPAN3_BSO_BAD                        0x3U
+#define ERSPAN3_BSO_SHORT              0x1U
+#define ERSPAN3_BSO_OVERSIZED          0x2U
+#define ERSPAN3_T_SHIFT                        10
+#define ERSPAN3_T_MASK                 (0x1U << ERSPAN3_T_SHIFT)
+#define ERSPAN3_SID_SHIFT              0
+#define ERSPAN3_SID_MASK               (0x3ffU << ERSPAN3_SID_SHIFT)
+#define ERSPAN3_P_SHIFT                        15
+#define ERSPAN3_P_MASK                 (0x1U << ERSPAN3_P_SHIFT)
+#define ERSPAN3_FT_SHIFT               10
+#define ERSPAN3_FT_MASK                        (0x1fU << ERSPAN3_FT_SHIFT)
+#define ERSPAN3_FT_ETHERNET            0
+#define ERSPAN3_FT_IP                  2
+#define ERSPAN3_HW_ID_SHIFT            4
+#define ERSPAN3_HW_ID_MASK             (0x3fU << ERSPAN3_HW_ID_SHIFT)
+#define ERSPAN3_D_SHIFT                        3
+#define ERSPAN3_D_MASK                 (0x1U << ERSPAN3_D_SHIFT)
+#define ERSPAN3_GRA_SHIFT              1
+#define ERSPAN3_GRA_MASK               (0x3U << ERSPAN3_GRA_SHIFT)
+#define ERSPAN3_O_SHIFT                        0
+#define ERSPAN3_O_MASK                 (0x1U << ERSPAN3_O_SHIFT)
+
+static const struct tok erspan3_bso_values[] = {
+       { ERSPAN3_BSO_GOOD_UNKNOWN, "Good/unknown" },
+       { ERSPAN3_BSO_BAD,          "Bad" },
+       { ERSPAN3_BSO_SHORT,        "Short" },
+       { ERSPAN3_BSO_OVERSIZED,    "Oversized" },
+       { 0, NULL }
+};
+
+static const struct tok erspan3_ft_values[] = {
+       { ERSPAN3_FT_ETHERNET, "Ethernet" },
+       { ERSPAN3_FT_IP, "IP" },
+       { 0, NULL }
+};
+
+void
+erspan_iii_print(netdissect_options *ndo, const u_char *bp, u_int len)
+{
+       uint32_t hdr, hdr2, ver, cos, sid, ft;
+
+       ndo->ndo_protocol = "erspan";
+       nd_print_protocol(ndo);
+
+       /*
+        * We do not check the GRE flags; ERSPAN Type III always
+        * has an ERSPAN header.
+        */
+       ND_ICHECK_U(len, <, 4);
+       hdr = GET_BE_U_4(bp);
+       bp += 4;
+       len -= 4;
+
+       ver = hdr & ERSPAN3_VER_MASK;
+       if (ver != ERSPAN3_VER) {
+               /*
+                * Not Type III.
+                */
+               ver >>= ERSPAN3_VER_SHIFT;
+               ND_PRINT(" erspan-unknown-version-%x", ver);
+               return;
+       }
+
+       if (ndo->ndo_vflag)
+               ND_PRINT(" type3");
+
+       sid = (hdr & ERSPAN3_SID_MASK) >> ERSPAN3_SID_SHIFT;
+       ND_PRINT(" session %u", sid);
+
+       ND_PRINT(" bso %s",
+                tok2str(erspan3_bso_values, "unknown %x",
+                        (hdr & ERSPAN3_BSO_MASK) >> ERSPAN3_BSO_SHIFT));
+
+       if (ndo->ndo_vflag) {
+               cos = (hdr & ERSPAN3_COS_MASK) >> ERSPAN3_COS_SHIFT;
+               ND_PRINT(" cos %u", cos);
+
+               if (hdr & ERSPAN3_T_MASK)
+                       ND_PRINT(" truncated");
+       }
+
+       /* Skip timestamp */
+       ND_ICHECK_U(len, <, 4);
+       ND_TCHECK_4(bp);
+       bp += 4;
+       len -= 4;
+
+       /* Skip SGT */
+       ND_ICHECK_U(len, <, 2);
+       ND_TCHECK_2(bp);
+       bp += 2;
+       len -= 2;
+
+       /* Additional fields */
+       ND_ICHECK_U(len, <, 2);
+       hdr2 = GET_BE_U_2(bp);
+       bp += 2;
+       len -= 2;
+
+       ft = (hdr2 & ERSPAN3_FT_MASK) >> ERSPAN3_FT_SHIFT;
+       ND_PRINT(" ft %s",
+                tok2str(erspan3_ft_values, "unknown %x", ft));
+
+
+       /* Do we have the platform-specific header? */
+       if (hdr2 & ERSPAN3_O_MASK) {
+               /* Yes.  Skip it. */
+               ND_ICHECK_U(len, <, 8);
+               ND_TCHECK_8(bp);
+               bp += 8;
+               len -= 8;
+       }
+
+       ND_PRINT(": ");
+
+       switch (ft) {
+
+       case ERSPAN3_FT_ETHERNET:
+               ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
+               break;
+
+       default:
+               ND_PRINT("Frame type unknown");
+               break;
+       }
+       return;
+
+invalid:
+       nd_print_invalid(ndo);
+}