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 softmac as ieee80211_rx_any() function. Diffed against wireless-2.6.git Signed-off-by: Denis Vlasenko <[EMAIL PROTECTED]> -- vda
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 softmac. diff -urpN 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 13:12:30 2006 @@ -758,6 +758,79 @@ 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: + return ieee80211_rx_mgt(ieee, hdr, stats); + 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; }