[PATCH] ieee80211_rx_any: filter out packets, call ieee80211_rx or ieee80211_rx_mgt

From: Denis Vlasenko
Date: Sun Jan 22 2006 - 07:03:46 EST


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.

Diffed against wireless-2.6.git

Signed-off-by: Denis Vlasenko <vda@xxxxxxxxxxxxx>
--
vda
diff -urp softmac-snapshot/net/ieee80211/ieee80211_rx.c softmac-snapshot.1/net/ieee80211/ieee80211_rx.c
--- softmac-snapshot/net/ieee80211/ieee80211_rx.c Wed Jan 18 07:27:03 2006
+++ softmac-snapshot.1/net/ieee80211/ieee80211_rx.c Sun Jan 22 14:01:43 2006
@@ -758,6 +758,80 @@ int ieee80211_rx(struct ieee80211_device
/* Returning 0 indicates to caller that we have not handled the SKB--
* so it is still allocated and can be used again by underlying
* hardware as a DMA target */
+ return 0;
+}
+
+/* Kernel doesn't have it, why? */
+static inline int is_mcast_or_bcast_ether_addr(const u8 *addr)
+{
+ return (0x01 & addr[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);
+
+ 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:
+ /* promisc: get all */
+ if (ieee->dev->flags & IFF_PROMISC)
+ is_packet_for_us = 1;
+ /* our BSS */
+ else if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0) {
+ /* to us */
+ if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+ is_packet_for_us = 1;
+ /* mcast */
+ else if (is_mcast_or_bcast_ether_addr(hdr->addr1))
+ is_packet_for_us = 1;
+ }
+ break;
+ case IW_MODE_INFRA:
+ /* promisc: get all */
+ if (ieee->dev->flags & IFF_PROMISC)
+ is_packet_for_us = 1;
+ /* our BSS (== from our AP) */
+ else if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0) {
+ /* to us */
+ if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+ is_packet_for_us = 1;
+ /* mcast */
+ else if (is_mcast_or_bcast_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;
}