Commit 8f2abf44 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jeff Garzik

[PATCH] orinoco: always use 802.11 header for rx processing

If the frame has ToDS flag set, mark it by setting skb->pkt_type to
PACKET_OTHERHOST, so that applications unaware of promiscous mode won't get
uplink (STA->AP) packets for STA->STA transmissions relayed by the AP.
Thanks to John Denker and David Gibson for finding the problem and the
solution.

Patch from Pavel Roskin
parent 95dd91fb
...@@ -619,7 +619,9 @@ struct hermes_tx_descriptor_802_11 { ...@@ -619,7 +619,9 @@ struct hermes_tx_descriptor_802_11 {
u16 ethertype; u16 ethertype;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor { struct hermes_rx_descriptor {
/* Control */
u16 status; u16 status;
u32 time; u32 time;
u8 silence; u8 silence;
...@@ -627,6 +629,18 @@ struct hermes_rx_descriptor { ...@@ -627,6 +629,18 @@ struct hermes_rx_descriptor {
u8 rate; u8 rate;
u8 rxflow; u8 rxflow;
u32 reserved; u32 reserved;
/* 802.11 header */
u16 frame_ctl;
u16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
u16 seq_ctl;
u8 addr4[ETH_ALEN];
/* Data length */
u16 data_len;
} __attribute__ ((packed)); } __attribute__ ((packed));
/********************************************************************/ /********************************************************************/
...@@ -1110,12 +1124,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) ...@@ -1110,12 +1124,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
struct net_device_stats *stats = &priv->stats; struct net_device_stats *stats = &priv->stats;
struct iw_statistics *wstats = &priv->wstats; struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
u16 rxfid, status; u16 rxfid, status, fc;
int length, data_len, data_off; int length;
char *p;
struct hermes_rx_descriptor desc; struct hermes_rx_descriptor desc;
struct header_struct hdr; struct ethhdr *hdr;
struct ethhdr *eh;
int err; int err;
rxfid = hermes_read_regn(hw, RXFID); rxfid = hermes_read_regn(hw, RXFID);
...@@ -1140,23 +1152,13 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) ...@@ -1140,23 +1152,13 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
stats->rx_crc_errors++; stats->rx_crc_errors++;
DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
} }
stats->rx_errors++;
goto drop;
}
/* For now we ignore the 802.11 header completely, assuming
that the card's firmware has handled anything vital */
err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
rxfid, HERMES_802_3_OFFSET);
if (err) {
printk(KERN_ERR "%s: error %d reading frame header. "
"Frame dropped.\n", dev->name, err);
stats->rx_errors++; stats->rx_errors++;
goto drop; goto drop;
} }
length = ntohs(hdr.len); length = le16_to_cpu(desc.data_len);
fc = le16_to_cpu(desc.frame_ctl);
/* Sanity checks */ /* Sanity checks */
if (length < 3) { /* No for even an 802.2 LLC header */ if (length < 3) { /* No for even an 802.2 LLC header */
...@@ -1186,57 +1188,51 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) ...@@ -1186,57 +1188,51 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
goto drop; goto drop;
} }
skb_reserve(skb, 2); /* This way the IP header is aligned */ /* We'll prepend the header, so reserve space for it. The worst
case is no decapsulation, when 802.3 header is prepended and
nothing is removed. 2 is for aligning the IP header. */
skb_reserve(skb, ETH_HLEN + 2);
err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
ALIGN(length, 2), rxfid,
HERMES_802_2_OFFSET);
if (err) {
printk(KERN_ERR "%s: error %d reading frame. "
"Frame dropped.\n", dev->name, err);
stats->rx_errors++;
goto drop;
}
/* Handle decapsulation /* Handle decapsulation
* In most cases, the firmware tell us about SNAP frames. * In most cases, the firmware tell us about SNAP frames.
* For some reason, the SNAP frames sent by LinkSys APs * For some reason, the SNAP frames sent by LinkSys APs
* are not properly recognised by most firmwares. * are not properly recognised by most firmwares.
* So, check ourselves */ * So, check ourselves */
if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || if (length >= ENCAPS_OVERHEAD &&
(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
is_ethersnap(&hdr)) { is_ethersnap(skb->data))) {
/* These indicate a SNAP within 802.2 LLC within /* These indicate a SNAP within 802.2 LLC within
802.11 frame which we'll need to de-encapsulate to 802.11 frame which we'll need to de-encapsulate to
the original EthernetII frame. */ the original EthernetII frame. */
hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
stats->rx_length_errors++;
goto drop;
}
/* Remove SNAP header, reconstruct EthernetII frame */
data_len = length - ENCAPS_OVERHEAD;
data_off = HERMES_802_3_OFFSET + sizeof(hdr);
eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
memcpy(eh, &hdr, 2 * ETH_ALEN);
eh->h_proto = hdr.ethertype;
} else { } else {
/* All other cases indicate a genuine 802.3 frame. No /* 802.3 frame - prepend 802.3 header as is */
decapsulation needed. We just throw the whole hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
thing in, and hope the protocol layer can deal with hdr->h_proto = htons(length);
it as 802.3 */
data_len = length;
data_off = HERMES_802_3_OFFSET;
/* FIXME: we re-read from the card data we already read here */
}
p = skb_put(skb, data_len);
err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
rxfid, data_off);
if (err) {
printk(KERN_ERR "%s: error %d reading frame. "
"Frame dropped.\n", dev->name, err);
stats->rx_errors++;
goto drop;
} }
memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
if (fc & IEEE80211_FCTL_FROMDS)
memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
else
memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
dev->last_rx = jiffies; dev->last_rx = jiffies;
skb->dev = dev; skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
if (fc & IEEE80211_FCTL_TODS)
skb->pkt_type = PACKET_OTHERHOST;
/* Process the wireless stats if needed */ /* Process the wireless stats if needed */
orinoco_stat_gather(dev, skb, &desc); orinoco_stat_gather(dev, skb, &desc);
...@@ -1457,6 +1453,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) ...@@ -1457,6 +1453,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus; u16 newstatus;
int connected; int connected;
if (priv->iw_mode == IW_MODE_MONITOR)
break;
if (len != sizeof(linkstatus)) { if (len != sizeof(linkstatus)) {
printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
dev->name, len); dev->name, len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment