From 51ecefa1b4c8e24a1977ba4b682a2ecc0fdb1c12 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 12 Jul 2007 02:53:49 -0400 Subject: [PATCH] Clean up eth frame conversion in the rx path Stop badmouthing the implementations and follow the standard for 802.3 frames. Make it clear that if the ethernet header already exists, it was done by the local hardware (i.e. it's not an encapsulation method). Use eth_type_trans() to set skb->protocol. Signed-off-by: Pavel Roskin --- at76_usb.c | 88 ++++++++++++++++++++++---------------------------------------- 1 file changed, 31 insertions(+), 57 deletions(-) diff --git a/at76_usb.c b/at76_usb.c index d843771..a4d10f8 100644 --- a/at76_usb.c +++ b/at76_usb.c @@ -5252,87 +5252,61 @@ static void at76_dbg_dumpbuf(const char *tag, const u8 *buf, int size) pr_debug("\n"); } -/* Convert the 802.11 header on a packet into an ethernet-style header - * (basically, pretend we're an ethernet card receiving ethernet packets) - * - * This routine returns with the skbuff pointing to the actual data (just past - * the end of the newly-created ethernet header). - */ +/* Convert the 802.11 header into an ethernet-style header, make skb + * ready for consumption by netif_rx() */ static void at76_ieee80211_to_eth(struct sk_buff *skb, int iw_mode) { struct ieee80211_hdr_3addr *i802_11_hdr; struct ethhdr *eth_hdr_p; u8 *src_addr; u8 *dest_addr; - __be16 proto = 0; - int build_ethhdr = 1; i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data; dbg("%s: ENTRY skb len %d data %s", __func__, skb->len, hex2str(skb->data, 64)); - skb_pull(skb, IEEE80211_3ADDR_LEN); + /* That would be the ethernet header if the hardware converted + * the frame for us. Make sure the source and the destination + * match the 802.11 header. Which hardware does it? */ + eth_hdr_p = (struct ethhdr *)skb_pull(skb, IEEE80211_3ADDR_LEN); - src_addr = iw_mode == IW_MODE_ADHOC ? i802_11_hdr->addr2 - : i802_11_hdr->addr3; dest_addr = i802_11_hdr->addr1; + if (iw_mode == IW_MODE_ADHOC) + src_addr = i802_11_hdr->addr2; + else + src_addr = i802_11_hdr->addr3; - eth_hdr_p = (struct ethhdr *)skb->data; if (!compare_ether_addr(eth_hdr_p->h_source, src_addr) && !compare_ether_addr(eth_hdr_p->h_dest, dest_addr)) { - /* An ethernet frame is encapsulated within the data portion. - * Just use its header instead. */ - skb_pull(skb, ETH_HLEN); - build_ethhdr = 0; - } else if (!memcmp(skb->data, snapsig, sizeof(snapsig))) { - /* SNAP frame - collapse it */ - skb_pull(skb, sizeof(rfc1042sig) + 2); - proto = *(__be16 *)(skb->data - 2); + /* Yes, we already have an ethernet header */ + skb_reset_mac_header(skb); } else { -#ifdef IEEE_STANDARD - /* According to all standards, we should assume the data - * portion contains 802.2 LLC information, so we should give it - * an 802.3 header (which has the same implications) */ - proto = htons(skb->len); -#else /* IEEE_STANDARD */ - /* Unfortunately, it appears no actual 802.11 implementations - * follow any standards specs. They all appear to put a - * 16-bit ethertype after the 802.11 header instead, so we take - * that value and make it into an Ethernet-II packet. */ - /* Note that this means we can never support non-SNAP 802.2 - * frames (because we can't tell when we get one) */ - - /* jal: This isn't true. My WRT54G happily sends SNAP. - Difficult to speak for all APs, so I don't dare to define - IEEE_STANDARD ... */ - proto = *(__be16 *)(skb->data); - skb_pull(skb, 2); -#endif /* IEEE_STANDARD */ - } - - skb_set_mac_header(skb, -ETH_HLEN); - eth_hdr_p = (struct ethhdr *)skb_mac_header(skb); - - if (build_ethhdr) { + u16 len; + + /* Need to build an ethernet header */ + if (!memcmp(skb->data, snapsig, sizeof(snapsig))) { + /* SNAP frame - decapsulate, keep proto */ + skb_push(skb, offsetof(struct ethhdr, h_proto) - + sizeof(rfc1042sig)); + len = 0; + } else { + /* 802.3 frame, proto is length */ + len = skb->len; + skb_push(skb, ETH_HLEN); + } + + skb_reset_mac_header(skb); + eth_hdr_p = eth_hdr(skb); /* This needs to be done in this order (eth_hdr_p->h_dest may * overlap src_addr) */ memcpy(eth_hdr_p->h_source, src_addr, ETH_ALEN); memcpy(eth_hdr_p->h_dest, dest_addr, ETH_ALEN); - /* make an 802.3 header (proto = length) */ - eth_hdr_p->h_proto = proto; + if (len) + eth_hdr_p->h_proto = htons(len); } - if (ntohs(eth_hdr_p->h_proto) > 1518) { - skb->protocol = eth_hdr_p->h_proto; - } else if (*(unsigned short *)skb->data == 0xFFFF) { - /* Magic hack for Novell IPX-in-802.3 packets */ - skb->protocol = htons(ETH_P_802_3); - } else { - /* Assume it's an 802.2 packet (it should be, and we have no - * good way to tell if it isn't) */ - skb->protocol = htons(ETH_P_802_2); - } + skb->protocol = eth_type_trans(skb, skb->dev); dbg("%s: EXIT skb da %s sa %s proto 0x%04x len %d data %s", __func__, mac2str(eth_hdr(skb)->h_dest), -- cgit v1.2.3