diff options
author | Denis Vlasenko <vda@ilport.com.ua> | 2006-01-24 16:57:11 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-03-22 22:16:58 -0500 |
commit | 1a995b45a52871af42aa1111da4c74c4b85e09c5 (patch) | |
tree | 59d43235b1e5bc76bbf2f108d4e7a9f016db0ea3 /net | |
parent | 4c718cfd7df4ac34ca8a4add555c374de61c42e8 (diff) |
[PATCH] ieee80211_rx_any: filter out packets, call ieee80211_rx or ieee80211_rx_mgt
Version 2 of the patch. Added checks for version 0
and proper from/to DS bits. Even in promisc
mode we won't receive packets from another BSSes.
bcm43xx_rx() contains code to filter out packets from
foreign BSSes and decide whether to call ieee80211_rx
or ieee80211_rx_mgt. This is not bcm specific.
Patch adapts that code and adds it to 80211
as ieee80211_rx_any() function.
Signed-off-by: Denis Vlasenko <vda@ilport.com.ua>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index a7f2a642a51..604b7b0097b 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -780,6 +780,80 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, return 0; } +/* Filter out unrelated packets, call ieee80211_rx[_mgt] */ +int ieee80211_rx_any(struct ieee80211_device *ieee, + struct sk_buff *skb, struct ieee80211_rx_stats *stats) +{ + struct ieee80211_hdr_4addr *hdr; + int is_packet_for_us; + u16 fc; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL; + + hdr = (struct ieee80211_hdr_4addr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + + if ((fc & IEEE80211_FCTL_VERS) != 0) + return -EINVAL; + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(ieee, hdr, stats); + return 0; + case IEEE80211_FTYPE_DATA: + break; + case IEEE80211_FTYPE_CTL: + return 0; + default: + return -EINVAL; + } + + is_packet_for_us = 0; + switch (ieee->iw_mode) { + case IW_MODE_ADHOC: + /* our BSS and not from/to DS */ + if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0) + if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) { + /* promisc: get all */ + if (ieee->dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + /* to us */ + else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0) + is_packet_for_us = 1; + /* mcast */ + else if (is_multicast_ether_addr(hdr->addr1)) + is_packet_for_us = 1; + } + break; + case IW_MODE_INFRA: + /* our BSS (== from our AP) and from DS */ + if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0) + if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) { + /* promisc: get all */ + if (ieee->dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + /* to us */ + else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0) + is_packet_for_us = 1; + /* mcast */ + else if (is_multicast_ether_addr(hdr->addr1)) { + /* not our own packet bcasted from AP */ + if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN)) + is_packet_for_us = 1; + } + } + break; + default: + /* ? */ + break; + } + + if (is_packet_for_us) + return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL); + return 0; +} + #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; |