diff options
author | Christoph Hellwig <hch@lst.de> | 2005-06-18 19:28:02 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-27 00:23:55 -0400 |
commit | 8f2abf4430ef2a131926a537ee6325dc43b0ec28 (patch) | |
tree | c476955d07cc82b14c1a5b004b25a3961c05a028 /drivers/net/wireless/orinoco.c | |
parent | 95dd91fbd8d3c788ef93bc94b4b600889e04dba1 (diff) |
[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
Diffstat (limited to 'drivers/net/wireless/orinoco.c')
-rw-r--r-- | drivers/net/wireless/orinoco.c | 105 |
1 files changed, 52 insertions, 53 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 38fd8623a444..96df2885728f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -619,7 +619,9 @@ struct hermes_tx_descriptor_802_11 { | |||
619 | u16 ethertype; | 619 | u16 ethertype; |
620 | } __attribute__ ((packed)); | 620 | } __attribute__ ((packed)); |
621 | 621 | ||
622 | /* Rx frame header except compatibility 802.3 header */ | ||
622 | struct hermes_rx_descriptor { | 623 | struct hermes_rx_descriptor { |
624 | /* Control */ | ||
623 | u16 status; | 625 | u16 status; |
624 | u32 time; | 626 | u32 time; |
625 | u8 silence; | 627 | u8 silence; |
@@ -627,6 +629,18 @@ struct hermes_rx_descriptor { | |||
627 | u8 rate; | 629 | u8 rate; |
628 | u8 rxflow; | 630 | u8 rxflow; |
629 | u32 reserved; | 631 | u32 reserved; |
632 | |||
633 | /* 802.11 header */ | ||
634 | u16 frame_ctl; | ||
635 | u16 duration_id; | ||
636 | u8 addr1[ETH_ALEN]; | ||
637 | u8 addr2[ETH_ALEN]; | ||
638 | u8 addr3[ETH_ALEN]; | ||
639 | u16 seq_ctl; | ||
640 | u8 addr4[ETH_ALEN]; | ||
641 | |||
642 | /* Data length */ | ||
643 | u16 data_len; | ||
630 | } __attribute__ ((packed)); | 644 | } __attribute__ ((packed)); |
631 | 645 | ||
632 | /********************************************************************/ | 646 | /********************************************************************/ |
@@ -1110,12 +1124,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1110 | struct net_device_stats *stats = &priv->stats; | 1124 | struct net_device_stats *stats = &priv->stats; |
1111 | struct iw_statistics *wstats = &priv->wstats; | 1125 | struct iw_statistics *wstats = &priv->wstats; |
1112 | struct sk_buff *skb = NULL; | 1126 | struct sk_buff *skb = NULL; |
1113 | u16 rxfid, status; | 1127 | u16 rxfid, status, fc; |
1114 | int length, data_len, data_off; | 1128 | int length; |
1115 | char *p; | ||
1116 | struct hermes_rx_descriptor desc; | 1129 | struct hermes_rx_descriptor desc; |
1117 | struct header_struct hdr; | 1130 | struct ethhdr *hdr; |
1118 | struct ethhdr *eh; | ||
1119 | int err; | 1131 | int err; |
1120 | 1132 | ||
1121 | rxfid = hermes_read_regn(hw, RXFID); | 1133 | rxfid = hermes_read_regn(hw, RXFID); |
@@ -1140,24 +1152,14 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1140 | stats->rx_crc_errors++; | 1152 | stats->rx_crc_errors++; |
1141 | DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); | 1153 | DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); |
1142 | } | 1154 | } |
1143 | stats->rx_errors++; | ||
1144 | goto drop; | ||
1145 | } | ||
1146 | 1155 | ||
1147 | /* For now we ignore the 802.11 header completely, assuming | ||
1148 | that the card's firmware has handled anything vital */ | ||
1149 | |||
1150 | err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), | ||
1151 | rxfid, HERMES_802_3_OFFSET); | ||
1152 | if (err) { | ||
1153 | printk(KERN_ERR "%s: error %d reading frame header. " | ||
1154 | "Frame dropped.\n", dev->name, err); | ||
1155 | stats->rx_errors++; | 1156 | stats->rx_errors++; |
1156 | goto drop; | 1157 | goto drop; |
1157 | } | 1158 | } |
1158 | 1159 | ||
1159 | length = ntohs(hdr.len); | 1160 | length = le16_to_cpu(desc.data_len); |
1160 | 1161 | fc = le16_to_cpu(desc.frame_ctl); | |
1162 | |||
1161 | /* Sanity checks */ | 1163 | /* Sanity checks */ |
1162 | if (length < 3) { /* No for even an 802.2 LLC header */ | 1164 | if (length < 3) { /* No for even an 802.2 LLC header */ |
1163 | /* At least on Symbol firmware with PCF we get quite a | 1165 | /* At least on Symbol firmware with PCF we get quite a |
@@ -1186,57 +1188,51 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1186 | goto drop; | 1188 | goto drop; |
1187 | } | 1189 | } |
1188 | 1190 | ||
1189 | skb_reserve(skb, 2); /* This way the IP header is aligned */ | 1191 | /* We'll prepend the header, so reserve space for it. The worst |
1192 | case is no decapsulation, when 802.3 header is prepended and | ||
1193 | nothing is removed. 2 is for aligning the IP header. */ | ||
1194 | skb_reserve(skb, ETH_HLEN + 2); | ||
1195 | |||
1196 | err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length), | ||
1197 | ALIGN(length, 2), rxfid, | ||
1198 | HERMES_802_2_OFFSET); | ||
1199 | if (err) { | ||
1200 | printk(KERN_ERR "%s: error %d reading frame. " | ||
1201 | "Frame dropped.\n", dev->name, err); | ||
1202 | stats->rx_errors++; | ||
1203 | goto drop; | ||
1204 | } | ||
1190 | 1205 | ||
1191 | /* Handle decapsulation | 1206 | /* Handle decapsulation |
1192 | * In most cases, the firmware tell us about SNAP frames. | 1207 | * In most cases, the firmware tell us about SNAP frames. |
1193 | * For some reason, the SNAP frames sent by LinkSys APs | 1208 | * For some reason, the SNAP frames sent by LinkSys APs |
1194 | * are not properly recognised by most firmwares. | 1209 | * are not properly recognised by most firmwares. |
1195 | * So, check ourselves */ | 1210 | * So, check ourselves */ |
1196 | if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || | 1211 | if (length >= ENCAPS_OVERHEAD && |
1197 | ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || | 1212 | (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || |
1198 | is_ethersnap(&hdr)) { | 1213 | ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || |
1214 | is_ethersnap(skb->data))) { | ||
1199 | /* These indicate a SNAP within 802.2 LLC within | 1215 | /* These indicate a SNAP within 802.2 LLC within |
1200 | 802.11 frame which we'll need to de-encapsulate to | 1216 | 802.11 frame which we'll need to de-encapsulate to |
1201 | the original EthernetII frame. */ | 1217 | the original EthernetII frame. */ |
1202 | 1218 | hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); | |
1203 | if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ | ||
1204 | stats->rx_length_errors++; | ||
1205 | goto drop; | ||
1206 | } | ||
1207 | |||
1208 | /* Remove SNAP header, reconstruct EthernetII frame */ | ||
1209 | data_len = length - ENCAPS_OVERHEAD; | ||
1210 | data_off = HERMES_802_3_OFFSET + sizeof(hdr); | ||
1211 | |||
1212 | eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); | ||
1213 | |||
1214 | memcpy(eh, &hdr, 2 * ETH_ALEN); | ||
1215 | eh->h_proto = hdr.ethertype; | ||
1216 | } else { | 1219 | } else { |
1217 | /* All other cases indicate a genuine 802.3 frame. No | 1220 | /* 802.3 frame - prepend 802.3 header as is */ |
1218 | decapsulation needed. We just throw the whole | 1221 | hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); |
1219 | thing in, and hope the protocol layer can deal with | 1222 | hdr->h_proto = htons(length); |
1220 | it as 802.3 */ | ||
1221 | data_len = length; | ||
1222 | data_off = HERMES_802_3_OFFSET; | ||
1223 | /* FIXME: we re-read from the card data we already read here */ | ||
1224 | } | ||
1225 | |||
1226 | p = skb_put(skb, data_len); | ||
1227 | err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2), | ||
1228 | rxfid, data_off); | ||
1229 | if (err) { | ||
1230 | printk(KERN_ERR "%s: error %d reading frame. " | ||
1231 | "Frame dropped.\n", dev->name, err); | ||
1232 | stats->rx_errors++; | ||
1233 | goto drop; | ||
1234 | } | 1223 | } |
1224 | memcpy(hdr->h_dest, desc.addr1, ETH_ALEN); | ||
1225 | if (fc & IEEE80211_FCTL_FROMDS) | ||
1226 | memcpy(hdr->h_source, desc.addr3, ETH_ALEN); | ||
1227 | else | ||
1228 | memcpy(hdr->h_source, desc.addr2, ETH_ALEN); | ||
1235 | 1229 | ||
1236 | dev->last_rx = jiffies; | 1230 | dev->last_rx = jiffies; |
1237 | skb->dev = dev; | 1231 | skb->dev = dev; |
1238 | skb->protocol = eth_type_trans(skb, dev); | 1232 | skb->protocol = eth_type_trans(skb, dev); |
1239 | skb->ip_summed = CHECKSUM_NONE; | 1233 | skb->ip_summed = CHECKSUM_NONE; |
1234 | if (fc & IEEE80211_FCTL_TODS) | ||
1235 | skb->pkt_type = PACKET_OTHERHOST; | ||
1240 | 1236 | ||
1241 | /* Process the wireless stats if needed */ | 1237 | /* Process the wireless stats if needed */ |
1242 | orinoco_stat_gather(dev, skb, &desc); | 1238 | orinoco_stat_gather(dev, skb, &desc); |
@@ -1457,6 +1453,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1457 | u16 newstatus; | 1453 | u16 newstatus; |
1458 | int connected; | 1454 | int connected; |
1459 | 1455 | ||
1456 | if (priv->iw_mode == IW_MODE_MONITOR) | ||
1457 | break; | ||
1458 | |||
1460 | if (len != sizeof(linkstatus)) { | 1459 | if (len != sizeof(linkstatus)) { |
1461 | printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", | 1460 | printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", |
1462 | dev->name, len); | 1461 | dev->name, len); |