aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-10-01 11:12:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-01 11:12:36 -0400
commit41f4a6f71fe33faa7971c173c263fb431fe987fe (patch)
treefdc3e603162e3ad63f6ae4160f68eb803bb78d58 /net/mac80211/rx.c
parent94d57c4cfaa43e29ca5fa5ff874048cfc67276f5 (diff)
parent1728943d83e9fd919e454332fe344944123b3c3a (diff)
downloadkernel_samsung_smdk4412-41f4a6f71fe33faa7971c173c263fb431fe987fe.zip
kernel_samsung_smdk4412-41f4a6f71fe33faa7971c173c263fb431fe987fe.tar.gz
kernel_samsung_smdk4412-41f4a6f71fe33faa7971c173c263fb431fe987fe.tar.bz2
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c291
1 files changed, 155 insertions, 136 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c036815..0b0e83e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -315,6 +315,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
int tid;
/* does the frame have a qos control field? */
@@ -323,9 +324,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
/* frame has qos control */
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
- rx->flags |= IEEE80211_RX_AMSDU;
- else
- rx->flags &= ~IEEE80211_RX_AMSDU;
+ status->rx_flags |= IEEE80211_RX_AMSDU;
} else {
/*
* IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
@@ -387,26 +386,25 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
struct sk_buff *skb = rx->skb;
- if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
+ if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
+ return RX_CONTINUE;
+
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning))
return ieee80211_scan_rx(rx->sdata, skb);
- if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) &&
- (rx->flags & IEEE80211_RX_IN_SCAN))) {
+ if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
/* drop all the other packets during a software scan anyway */
if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
dev_kfree_skb(skb);
return RX_QUEUED;
}
- if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
- /* scanning finished during invoking of handlers */
- I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
- return RX_DROP_UNUSABLE;
- }
-
- return RX_CONTINUE;
+ /* scanning finished during invoking of handlers */
+ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+ return RX_DROP_UNUSABLE;
}
@@ -785,13 +783,14 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
rx->sta->last_seq_ctrl[rx->queue] ==
hdr->seq_ctrl)) {
- if (rx->flags & IEEE80211_RX_RA_MATCH) {
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
rx->local->dot11FrameDuplicateCount++;
rx->sta->num_duplicates++;
}
@@ -824,7 +823,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
if ((!ieee80211_has_fromds(hdr->frame_control) &&
!ieee80211_has_tods(hdr->frame_control) &&
ieee80211_is_data(hdr->frame_control)) ||
- !(rx->flags & IEEE80211_RX_RA_MATCH)) {
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)) {
/* Drop IBSS frames and frames for other hosts
* silently. */
return RX_DROP_MONITOR;
@@ -881,7 +880,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
* No point in finding a key and decrypting if the frame is neither
* addressed to us nor a multicast frame.
*/
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
/* start without a key */
@@ -1114,7 +1113,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->last_rx = jiffies;
}
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
@@ -1271,6 +1270,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
unsigned int frag, seq;
struct ieee80211_fragment_entry *entry;
struct sk_buff *skb;
+ struct ieee80211_rx_status *status;
hdr = (struct ieee80211_hdr *)rx->skb->data;
fc = hdr->frame_control;
@@ -1370,7 +1370,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
}
/* Complete frame has been reassembled - process it now */
- rx->flags |= IEEE80211_RX_FRAGMENTED;
+ status = IEEE80211_SKB_RXCB(rx->skb);
+ status->rx_flags |= IEEE80211_RX_FRAGMENTED;
out:
if (rx->sta)
@@ -1387,9 +1388,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
__le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
- !(rx->flags & IEEE80211_RX_RA_MATCH)))
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)))
return RX_CONTINUE;
if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
@@ -1550,6 +1552,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
struct sk_buff *skb, *xmit_skb;
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
struct sta_info *dsta;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
skb = rx->skb;
xmit_skb = NULL;
@@ -1557,7 +1560,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
- (rx->flags & IEEE80211_RX_RA_MATCH) &&
+ (status->rx_flags & IEEE80211_RX_RA_MATCH) &&
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
if (is_multicast_ether_addr(ehdr->h_dest)) {
/*
@@ -1634,6 +1637,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
struct sk_buff_head frame_list;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
if (unlikely(!ieee80211_is_data(fc)))
return RX_CONTINUE;
@@ -1641,7 +1645,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
if (unlikely(!ieee80211_is_data_present(fc)))
return RX_DROP_MONITOR;
- if (!(rx->flags & IEEE80211_RX_AMSDU))
+ if (!(status->rx_flags & IEEE80211_RX_AMSDU))
return RX_CONTINUE;
if (ieee80211_has_a4(hdr->frame_control) &&
@@ -1692,6 +1696,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct sk_buff *skb = rx->skb, *fwd_skb;
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -1737,7 +1742,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
mesh_hdr->ttl--;
- if (rx->flags & IEEE80211_RX_RA_MATCH) {
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
if (!mesh_hdr->ttl)
IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
dropped_frames_ttl);
@@ -1947,6 +1952,7 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
/*
* From here on, look only at management frames.
@@ -1959,7 +1965,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
if (!ieee80211_is_mgmt(mgmt->frame_control))
return RX_DROP_MONITOR;
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
if (ieee80211_drop_unencrypted_mgmt(rx))
@@ -1974,6 +1980,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
int len = rx->skb->len;
if (!ieee80211_is_action(mgmt->frame_control))
@@ -1986,7 +1993,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
return RX_DROP_UNUSABLE;
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_UNUSABLE;
switch (mgmt->u.action.category) {
@@ -2082,7 +2089,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
invalid:
- rx->flags |= IEEE80211_MALFORMED_ACTION_FRM;
+ status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
/* will return in the next handlers */
return RX_CONTINUE;
@@ -2104,10 +2111,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
{
- struct ieee80211_rx_status *status;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
/* skip known-bad action frames and return them in the next handler */
- if (rx->flags & IEEE80211_MALFORMED_ACTION_FRM)
+ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
return RX_CONTINUE;
/*
@@ -2116,7 +2123,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
* so userspace can register for those to know whether ones
* it transmitted were processed or returned.
*/
- status = IEEE80211_SKB_RXCB(rx->skb);
if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
rx->skb->data, rx->skb->len,
@@ -2138,6 +2144,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
struct sk_buff *nskb;
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
if (!ieee80211_is_action(mgmt->frame_control))
return RX_CONTINUE;
@@ -2152,7 +2159,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
* registration mechanisms, but older ones still use cooked
* monitor interfaces so push all frames there.
*/
- if (!(rx->flags & IEEE80211_MALFORMED_ACTION_FRM) &&
+ if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
(sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
return RX_DROP_MONITOR;
@@ -2286,8 +2293,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- if (status->flag & RX_FLAG_INTERNAL_CMTR)
+ /*
+ * If cooked monitor has been processed already, then
+ * don't do it again. If not, set the flag.
+ */
+ if (rx->flags & IEEE80211_RX_CMNTR)
goto out_free_skb;
+ rx->flags |= IEEE80211_RX_CMNTR;
if (skb_headroom(skb) < sizeof(*rthdr) &&
pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
@@ -2343,12 +2355,8 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
if (prev_dev) {
skb->dev = prev_dev;
netif_receive_skb(skb);
- skb = NULL;
- } else
- goto out_free_skb;
-
- status->flag |= RX_FLAG_INTERNAL_CMTR;
- return;
+ return;
+ }
out_free_skb:
dev_kfree_skb(skb);
@@ -2409,6 +2417,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
* same TID from the same station
*/
rx->skb = skb;
+ rx->flags = 0;
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
@@ -2443,18 +2452,13 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
}
}
-static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_rx_data *rx,
- struct sk_buff *skb)
+static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
{
struct sk_buff_head reorder_release;
ieee80211_rx_result res = RX_DROP_MONITOR;
__skb_queue_head_init(&reorder_release);
- rx->skb = skb;
- rx->sdata = sdata;
-
#define CALL_RXH(rxh) \
do { \
res = rxh(rx); \
@@ -2484,7 +2488,12 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
{
struct sk_buff_head frames;
- struct ieee80211_rx_data rx = { };
+ struct ieee80211_rx_data rx = {
+ .sta = sta,
+ .sdata = sta->sdata,
+ .local = sta->local,
+ .queue = tid,
+ };
struct tid_ampdu_rx *tid_agg_rx;
tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -2493,17 +2502,6 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
__skb_queue_head_init(&frames);
- /* construct rx struct */
- rx.sta = sta;
- rx.sdata = sta->sdata;
- rx.local = sta->local;
- rx.queue = tid;
- rx.flags |= IEEE80211_RX_RA_MATCH;
-
- if (unlikely(test_bit(SCAN_HW_SCANNING, &sta->local->scanning) ||
- test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning)))
- rx.flags |= IEEE80211_RX_IN_SCAN;
-
spin_lock(&tid_agg_rx->reorder_lock);
ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames);
spin_unlock(&tid_agg_rx->reorder_lock);
@@ -2513,10 +2511,10 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
/* main receive path */
-static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_rx_data *rx,
+static int prepare_for_handlers(struct ieee80211_rx_data *rx,
struct ieee80211_hdr *hdr)
{
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
struct sk_buff *skb = rx->skb;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
@@ -2530,7 +2528,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case NL80211_IFTYPE_ADHOC:
@@ -2540,15 +2538,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
return 1;
}
else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
compare_ether_addr(sdata->vif.addr,
hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!rx->sta) {
int rate_idx;
if (status->flag & RX_FLAG_HT)
@@ -2566,7 +2564,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case NL80211_IFTYPE_AP_VLAN:
@@ -2577,9 +2575,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
return 0;
} else if (!ieee80211_bssid_match(bssid,
sdata->vif.addr)) {
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case NL80211_IFTYPE_WDS:
@@ -2598,6 +2596,51 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
}
/*
+ * This function returns whether or not the SKB
+ * was destined for RX processing or not, which,
+ * if consume is true, is equivalent to whether
+ * or not the skb was consumed.
+ */
+static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
+ struct sk_buff *skb, bool consume)
+{
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ int prepares;
+
+ rx->skb = skb;
+ status->rx_flags |= IEEE80211_RX_RA_MATCH;
+ prepares = prepare_for_handlers(rx, hdr);
+
+ if (!prepares)
+ return false;
+
+ if (status->flag & RX_FLAG_MMIC_ERROR) {
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH)
+ ieee80211_rx_michael_mic_report(hdr, rx);
+ return false;
+ }
+
+ if (!consume) {
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb) {
+ if (net_ratelimit())
+ wiphy_debug(local->hw.wiphy,
+ "failed to copy multicast frame for %s\n",
+ sdata->name);
+ return true;
+ }
+
+ rx->skb = skb;
+ }
+
+ ieee80211_invoke_rx_handlers(rx);
+ return true;
+}
+
+/*
* This is the actual Rx frames handler. as it blongs to Rx path it must
* be called with rcu_read_lock protection.
*/
@@ -2610,11 +2653,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr;
__le16 fc;
struct ieee80211_rx_data rx;
- int prepares;
- struct ieee80211_sub_if_data *prev = NULL;
- struct sk_buff *skb_new;
- struct sta_info *sta, *tmp;
- bool found_sta = false;
+ struct ieee80211_sub_if_data *prev;
+ struct sta_info *sta, *tmp, *prev_sta;
int err = 0;
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
@@ -2627,7 +2667,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
- rx.flags |= IEEE80211_RX_IN_SCAN;
+ status->rx_flags |= IEEE80211_RX_IN_SCAN;
if (ieee80211_is_mgmt(fc))
err = skb_linearize(skb);
@@ -2644,90 +2684,67 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_verify_alignment(&rx);
if (ieee80211_is_data(fc)) {
+ prev_sta = NULL;
+
for_each_sta_info(local, hdr->addr2, sta, tmp) {
- rx.sta = sta;
- found_sta = true;
- rx.sdata = sta->sdata;
-
- rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
- if (prepares) {
- if (status->flag & RX_FLAG_MMIC_ERROR) {
- if (rx.flags & IEEE80211_RX_RA_MATCH)
- ieee80211_rx_michael_mic_report(hdr, &rx);
- } else
- prev = rx.sdata;
- }
- }
- }
- if (!found_sta) {
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (!ieee80211_sdata_running(sdata))
+ if (!prev_sta) {
+ prev_sta = sta;
continue;
+ }
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- continue;
+ rx.sta = prev_sta;
+ rx.sdata = prev_sta->sdata;
+ ieee80211_prepare_and_rx_handle(&rx, skb, false);
- /*
- * frame is destined for this interface, but if it's
- * not also for the previous one we handle that after
- * the loop to avoid copying the SKB once too much
- */
+ prev_sta = sta;
+ }
- if (!prev) {
- prev = sdata;
- continue;
- }
+ if (prev_sta) {
+ rx.sta = prev_sta;
+ rx.sdata = prev_sta->sdata;
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+ return;
+ }
+ }
- rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(prev, &rx, hdr);
+ prev = NULL;
- if (!prepares)
- goto next;
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata))
+ continue;
- if (status->flag & RX_FLAG_MMIC_ERROR) {
- rx.sdata = prev;
- if (rx.flags & IEEE80211_RX_RA_MATCH)
- ieee80211_rx_michael_mic_report(hdr,
- &rx);
- goto next;
- }
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ continue;
- /*
- * frame was destined for the previous interface
- * so invoke RX handlers for it
- */
+ /*
+ * frame is destined for this interface, but if it's
+ * not also for the previous one we handle that after
+ * the loop to avoid copying the SKB once too much
+ */
- skb_new = skb_copy(skb, GFP_ATOMIC);
- if (!skb_new) {
- if (net_ratelimit())
- wiphy_debug(local->hw.wiphy,
- "failed to copy multicast frame for %s\n",
- prev->name);
- goto next;
- }
- ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
-next:
+ if (!prev) {
prev = sdata;
+ continue;
}
- if (prev) {
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sdata = prev;
+ ieee80211_prepare_and_rx_handle(&rx, skb, false);
- rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(prev, &rx, hdr);
+ prev = sdata;
+ }
- if (!prepares)
- prev = NULL;
- }
+ if (prev) {
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sdata = prev;
+
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+ return;
}
- if (prev)
- ieee80211_invoke_rx_handlers(prev, &rx, skb);
- else
- dev_kfree_skb(skb);
+
+ dev_kfree_skb(skb);
}
/*
@@ -2801,6 +2818,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
}
+ status->rx_flags = 0;
+
/*
* key references and virtual interfaces are protected using RCU
* and this requires that we are in a read-side RCU section during