summaryrefslogtreecommitdiff
path: root/print-ether.c
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2019-01-18 15:19:38 -0800
committerFlorian Fainelli <f.fainelli@gmail.com>2019-01-25 17:00:24 -0800
commit48e290d807a535cdda391eef7e6992c3429c986a (patch)
tree41660cd54315117691caa9e236d2ee5df2fbc328 /print-ether.c
parent0b3880c91e169db7cfbdce1b18ef4f1e3fd277de (diff)
downloadtcpdump-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.c61
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