mirror of
https://github.com/the-tcpdump-group/tcpdump.git
synced 2024-11-23 18:14:29 +08:00
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.
This commit is contained in:
parent
0b3880c91e
commit
48e290d807
@ -538,6 +538,7 @@ extern void egp_print(netdissect_options *, const u_char *, u_int);
|
||||
extern void eigrp_print(netdissect_options *, const u_char *, u_int);
|
||||
extern int esp_print(netdissect_options *, const u_char *, const int, const u_char *, u_int *, u_int *);
|
||||
extern u_int ether_print(netdissect_options *, const u_char *, u_int, u_int, void (*)(netdissect_options *, const u_char *), const u_char *);
|
||||
extern u_int ether_print_hdr_len(netdissect_options *, const u_char *, u_int, u_int, void (*)(netdissect_options *, const u_char *), const u_char *, u_int);
|
||||
extern int ethertype_print(netdissect_options *, u_short, const u_char *, u_int, u_int, const struct lladdr_info *, const struct lladdr_info *);
|
||||
extern u_int fddi_print(netdissect_options *, const u_char *, u_int, u_int);
|
||||
extern void forces_print(netdissect_options *, const u_char *, u_int);
|
||||
|
@ -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;
|
||||
|
||||
/* Unless specified otherwise, assume a standard Ethernet header */
|
||||
if (hdrlen == ETHER_HDRLEN)
|
||||
ndo->ndo_protocol = "ether";
|
||||
if (caplen < ETHER_HDRLEN) {
|
||||
|
||||
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)
|
||||
@ -268,6 +278,25 @@ recurse:
|
||||
return (hdrlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
Loading…
Reference in New Issue
Block a user