aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-01-21 18:36:39 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-22 16:11:33 -0500
commit4bb29f8c390fb7be207ec3f11b9d30ccdf1cb6ac (patch)
tree27eea1536ee2272eeeb5bd85806e38a77cfe702a /net
parent58da1318ee92ad3fe7917278d596768bbe441850 (diff)
mac80211: fix rx data handling for non-data frames on multiple vifs
The loop that passes non-data frames to all relevant vifs inside the __ieee80211_rx_handle_packet keeps a pointer to the previous sdata to avoid having to make unnecessary copies of the frame it's handling. This led to a bug that caused it to apply the ieee80211_rx_data state to the wrong interface, thereby either missing the rx.sta pointer or having it assigned where it shouldn't be. This breaks (among other things) aggregation on some vifs, as action frame exchages are dropped to the cooked monitor interface due to rx->sta being NULL. Fix this by restructuring the loop so that it prepares the rx data just before making the skb copy and calling the rx handlers. Cc: stable@kernel.org Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/rx.c45
1 files changed, 28 insertions, 17 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a8e15b84c05b..7e0b3e340389 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2348,22 +2348,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2348 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 2348 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
2349 continue; 2349 continue;
2350 2350
2351 rx.sta = sta_info_get(sdata, hdr->addr2);
2352
2353 rx.flags |= IEEE80211_RX_RA_MATCH;
2354 prepares = prepare_for_handlers(sdata, &rx, hdr);
2355
2356 if (!prepares)
2357 continue;
2358
2359 if (status->flag & RX_FLAG_MMIC_ERROR) {
2360 rx.sdata = sdata;
2361 if (rx.flags & IEEE80211_RX_RA_MATCH)
2362 ieee80211_rx_michael_mic_report(hdr,
2363 &rx);
2364 continue;
2365 }
2366
2367 /* 2351 /*
2368 * frame is destined for this interface, but if it's 2352 * frame is destined for this interface, but if it's
2369 * not also for the previous one we handle that after 2353 * not also for the previous one we handle that after
@@ -2375,6 +2359,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2375 continue; 2359 continue;
2376 } 2360 }
2377 2361
2362 rx.sta = sta_info_get(prev, hdr->addr2);
2363
2364 rx.flags |= IEEE80211_RX_RA_MATCH;
2365 prepares = prepare_for_handlers(prev, &rx, hdr);
2366
2367 if (!prepares)
2368 goto next;
2369
2370 if (status->flag & RX_FLAG_MMIC_ERROR) {
2371 rx.sdata = prev;
2372 if (rx.flags & IEEE80211_RX_RA_MATCH)
2373 ieee80211_rx_michael_mic_report(hdr,
2374 &rx);
2375 goto next;
2376 }
2377
2378 /* 2378 /*
2379 * frame was destined for the previous interface 2379 * frame was destined for the previous interface
2380 * so invoke RX handlers for it 2380 * so invoke RX handlers for it
@@ -2387,11 +2387,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2387 "multicast frame for %s\n", 2387 "multicast frame for %s\n",
2388 wiphy_name(local->hw.wiphy), 2388 wiphy_name(local->hw.wiphy),
2389 prev->name); 2389 prev->name);
2390 continue; 2390 goto next;
2391 } 2391 }
2392 ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); 2392 ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
2393next:
2393 prev = sdata; 2394 prev = sdata;
2394 } 2395 }
2396
2397 if (prev) {
2398 rx.sta = sta_info_get(prev, hdr->addr2);
2399
2400 rx.flags |= IEEE80211_RX_RA_MATCH;
2401 prepares = prepare_for_handlers(prev, &rx, hdr);
2402
2403 if (!prepares)
2404 prev = NULL;
2405 }
2395 } 2406 }
2396 if (prev) 2407 if (prev)
2397 ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); 2408 ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);