#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_MASK (0xfffffU << ERSPAN2_INDEX_SHIFT)
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;
nd_print_protocol(ndo);
if (!(flags & GRE_SP)) {
+ /*
+ * 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;
ver = hdr & ERSPAN2_VER_MASK;
if (ver != ERSPAN2_VER) {
+ /*
+ * Not Type II.
+ */
ver >>= ERSPAN2_VER_SHIFT;
ND_PRINT(" erspan-unknown-version-%x", ver);
return;
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);
+}