aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Roskin <proski@gnu.org>2007-07-12 02:53:49 -0400
committerGuido Guenther <agx@bogon.sigxcpu.org>2007-07-15 12:19:07 -0400
commit51ecefa1b4c8e24a1977ba4b682a2ecc0fdb1c12 (patch)
treea81108b11858deac41d170526830dcebcbb85c2c
parente6a1f3b8211852f9393d8bd4a9d73593e7318412 (diff)
[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 <proski@gnu.org>
-rw-r--r--at76_usb.c88
1 files 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),