diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2019-01-18 15:19:38 -0800 |
---|---|---|
committer | Florian Fainelli <f.fainelli@gmail.com> | 2019-01-25 17:00:24 -0800 |
commit | 48e290d807a535cdda391eef7e6992c3429c986a (patch) | |
tree | 41660cd54315117691caa9e236d2ee5df2fbc328 /print-ether.c | |
parent | 0b3880c91e169db7cfbdce1b18ef4f1e3fd277de (diff) | |
download | tcpdump-48e290d807a535cdda391eef7e6992c3429c986a.tar.gz |
Ethernet: Allow specifying non-standard Ethernet header length
A fair number of proprietary Ethernet switch tagging protocols, such as
Broadcom tags for instance, will place their tag between the MAC SA and
the Type/Length field.
Move the body of ether_print() into ether_print_hdr_len() and specify
the Ethernet header length as an argument to that function.
ether_print() calls ether_print_hdr_len() with a standard Ethernet
header lenght of 14 bytes, while other callers could specify an
arbitrary length. We still assume that the first Length/Type field to
parse is located 2 bytes before the end of that Ethernet header length.
This will be used in a subsequent commit to parse Broadcom tags.
Diffstat (limited to 'print-ether.c')
-rw-r--r-- | print-ether.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/print-ether.c b/print-ether.c index d6dd9572..ba488343 100644 --- a/print-ether.c +++ b/print-ether.c @@ -106,7 +106,8 @@ const struct tok ethertype_values[] = { static void ether_hdr_print(netdissect_options *ndo, - const u_char *bp, u_int length) + const u_char *bp, u_int length, + u_int hdrlen) { const struct ether_header *ehp; uint16_t length_type; @@ -117,7 +118,8 @@ ether_hdr_print(netdissect_options *ndo, etheraddr_string(ndo, ehp->ether_shost), etheraddr_string(ndo, ehp->ether_dhost)); - length_type = EXTRACT_BE_U_2(ehp->ether_length_type); + length_type = EXTRACT_BE_U_2(bp + + (hdrlen - sizeof(ehp->ether_length_type))); if (!ndo->ndo_qflag) { if (length_type <= MAX_ETHERNET_LENGTH_VAL) { ND_PRINT(", 802.3"); @@ -138,7 +140,8 @@ ether_hdr_print(netdissect_options *ndo, } /* - * Print an Ethernet frame. + * Print an Ethernet frame while specyfing a non-standard Ethernet header + * length. * This might be encapsulated within another frame; we might be passed * a pointer to a function that can print header information for that * frame's protocol, and an argument to pass to that function. @@ -146,46 +149,52 @@ ether_hdr_print(netdissect_options *ndo, * FIXME: caplen can and should be derived from ndo->ndo_snapend and p. */ u_int -ether_print(netdissect_options *ndo, +ether_print_hdr_len(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen, void (*print_encap_header)(netdissect_options *ndo, const u_char *), - const u_char *encap_header_arg) + const u_char *encap_header_arg, u_int hdrlen) { const struct ether_header *ehp; u_int orig_length; u_short length_type; - u_int hdrlen; int llc_hdrlen; struct lladdr_info src, dst; - ndo->ndo_protocol = "ether"; - if (caplen < ETHER_HDRLEN) { + /* Unless specified otherwise, assume a standard Ethernet header */ + if (hdrlen == ETHER_HDRLEN) + ndo->ndo_protocol = "ether"; + + if (caplen < hdrlen) { nd_print_trunc(ndo); return (caplen); } - if (length < ETHER_HDRLEN) { + if (length < hdrlen) { nd_print_trunc(ndo); return (length); } + /* If the offset is set, then the upper printer is responsible for + * printing the relevant part of the Ethernet header. + */ if (ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); - ether_hdr_print(ndo, p, length); + ether_hdr_print(ndo, p, length, hdrlen); } + orig_length = length; - length -= ETHER_HDRLEN; - caplen -= ETHER_HDRLEN; + length -= hdrlen; + caplen -= hdrlen; ehp = (const struct ether_header *)p; - p += ETHER_HDRLEN; - hdrlen = ETHER_HDRLEN; + p += hdrlen; src.addr = ehp->ether_shost; src.addr_string = etheraddr_string; dst.addr = ehp->ether_dhost; dst.addr_string = etheraddr_string; - length_type = EXTRACT_BE_U_2(ehp->ether_length_type); + length_type = EXTRACT_BE_U_2((const u_char *)ehp + + (hdrlen - sizeof(ehp->ether_length_type))); recurse: /* @@ -258,7 +267,8 @@ recurse: if (!ndo->ndo_eflag) { if (print_encap_header != NULL) (*print_encap_header)(ndo, encap_header_arg); - ether_hdr_print(ndo, (const u_char *)ehp, orig_length); + ether_hdr_print(ndo, (const u_char *)ehp, orig_length, + hdrlen); } if (!ndo->ndo_suppress_default_print) @@ -269,6 +279,25 @@ recurse: } /* + * Print an Ethernet frame. + * This might be encapsulated within another frame; we might be passed + * a pointer to a function that can print header information for that + * frame's protocol, and an argument to pass to that function. + * + * FIXME: caplen can and should be derived from ndo->ndo_snapend and p. + */ +u_int +ether_print(netdissect_options *ndo, + const u_char *p, u_int length, u_int caplen, + void (*print_encap_header)(netdissect_options *ndo, const u_char *), + const u_char *encap_header_arg) +{ + return (ether_print_hdr_len(ndo, p, length, caplen, + print_encap_header, encap_header_arg, + ETHER_HDRLEN)); +} + +/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->len' is the length * of the packet off the wire, and 'h->caplen' is the number |