X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/e0787e5d8ce80ea53f447057c466a65759c4d56c..c50f3934dacc4bd3fe16a900d4c63c05acb50ce3:/print-erspan.c diff --git a/print-erspan.c b/print-erspan.c index 3bcf0acd..1f8c9f00 100644 --- a/print-erspan.c +++ b/print-erspan.c @@ -32,16 +32,18 @@ * Specifications: I-D draft-foschiano-erspan-03. */ -#ifdef HAVE_CONFIG_H #include -#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) @@ -63,13 +65,8 @@ #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_LEN(bp, 4); + bp += 4; + len -= 4; + + /* Skip SGT */ + ND_ICHECK_U(len, <, 2); + ND_TCHECK_LEN(bp, 2); + 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_LEN(bp, 8); + 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); +}