aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-06 16:19:27 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-12 06:10:44 -0400
commitd48b296850f25cb559cb9b907d6d8c09eca3e89d (patch)
treeca2603b4ebfa210dda48c1a311996d826084835e /net/mac80211
parent5260a5b2c3524f198ea062fe0a6a4faa724e6a9d (diff)
mac80211: redesign scan RX
Scan receive is rather inefficient when there are multiple virtual interfaces. We iterate all of the virtual interfaces and then notify cfg80211 about each beacon many times. Redesign scan RX to happen before everything else. Then we can also get rid of IEEE80211_RX_IN_SCAN since we don't have to accept frames into the RX handlers for scanning or scheduled scanning any more. Overall, this simplifies the code. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/rx.c47
-rw-r--r--net/mac80211/scan.c57
4 files changed, 32 insertions, 80 deletions
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 778e5916d7c3..b8dfb440c8ef 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
325 local->rx_handlers_drop_defrag); 325 local->rx_handlers_drop_defrag);
326 DEBUGFS_STATS_ADD(rx_handlers_drop_short, 326 DEBUGFS_STATS_ADD(rx_handlers_drop_short,
327 local->rx_handlers_drop_short); 327 local->rx_handlers_drop_short);
328 DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan,
329 local->rx_handlers_drop_passive_scan);
330 DEBUGFS_STATS_ADD(tx_expand_skb_head, 328 DEBUGFS_STATS_ADD(tx_expand_skb_head,
331 local->tx_expand_skb_head); 329 local->tx_expand_skb_head);
332 DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, 330 DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e973a8f96c9b..2a97d668d2da 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -207,7 +207,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
207 * enum ieee80211_packet_rx_flags - packet RX flags 207 * enum ieee80211_packet_rx_flags - packet RX flags
208 * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed 208 * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
209 * (incl. multicast frames) 209 * (incl. multicast frames)
210 * @IEEE80211_RX_IN_SCAN: received while scanning
211 * @IEEE80211_RX_FRAGMENTED: fragmented frame 210 * @IEEE80211_RX_FRAGMENTED: fragmented frame
212 * @IEEE80211_RX_AMSDU: a-MSDU packet 211 * @IEEE80211_RX_AMSDU: a-MSDU packet
213 * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed 212 * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
@@ -217,7 +216,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
217 * @rx_flags field of &struct ieee80211_rx_status. 216 * @rx_flags field of &struct ieee80211_rx_status.
218 */ 217 */
219enum ieee80211_packet_rx_flags { 218enum ieee80211_packet_rx_flags {
220 IEEE80211_RX_IN_SCAN = BIT(0),
221 IEEE80211_RX_RA_MATCH = BIT(1), 219 IEEE80211_RX_RA_MATCH = BIT(1),
222 IEEE80211_RX_FRAGMENTED = BIT(2), 220 IEEE80211_RX_FRAGMENTED = BIT(2),
223 IEEE80211_RX_AMSDU = BIT(3), 221 IEEE80211_RX_AMSDU = BIT(3),
@@ -1014,7 +1012,6 @@ struct ieee80211_local {
1014 unsigned int rx_handlers_drop_nullfunc; 1012 unsigned int rx_handlers_drop_nullfunc;
1015 unsigned int rx_handlers_drop_defrag; 1013 unsigned int rx_handlers_drop_defrag;
1016 unsigned int rx_handlers_drop_short; 1014 unsigned int rx_handlers_drop_short;
1017 unsigned int rx_handlers_drop_passive_scan;
1018 unsigned int tx_expand_skb_head; 1015 unsigned int tx_expand_skb_head;
1019 unsigned int tx_expand_skb_head_cloned; 1016 unsigned int tx_expand_skb_head_cloned;
1020 unsigned int rx_expand_skb_head; 1017 unsigned int rx_expand_skb_head;
@@ -1247,8 +1244,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
1247 struct cfg80211_scan_request *req); 1244 struct cfg80211_scan_request *req);
1248void ieee80211_scan_cancel(struct ieee80211_local *local); 1245void ieee80211_scan_cancel(struct ieee80211_local *local);
1249void ieee80211_run_deferred_scan(struct ieee80211_local *local); 1246void ieee80211_run_deferred_scan(struct ieee80211_local *local);
1250ieee80211_rx_result 1247void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb);
1251ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
1252 1248
1253void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); 1249void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
1254struct ieee80211_bss * 1250struct ieee80211_bss *
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 17a56151be7f..1d7a58098e34 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
413 413
414/* rx handlers */ 414/* rx handlers */
415 415
416static ieee80211_rx_result debug_noinline
417ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
418{
419 struct ieee80211_local *local = rx->local;
420 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
421 struct sk_buff *skb = rx->skb;
422
423 if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
424 !rcu_access_pointer(local->sched_scan_sdata)))
425 return RX_CONTINUE;
426
427 if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
428 test_bit(SCAN_SW_SCANNING, &local->scanning) ||
429 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
430 rcu_access_pointer(local->sched_scan_sdata))
431 return ieee80211_scan_rx(rx->sdata, skb);
432
433 /* scanning finished during invoking of handlers */
434 I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
435 return RX_DROP_UNUSABLE;
436}
437
438
439static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) 416static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
440{ 417{
441 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 418 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -2692,7 +2669,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
2692 goto rxh_next; \ 2669 goto rxh_next; \
2693 } while (0); 2670 } while (0);
2694 2671
2695 CALL_RXH(ieee80211_rx_h_passive_scan)
2696 CALL_RXH(ieee80211_rx_h_check) 2672 CALL_RXH(ieee80211_rx_h_check)
2697 2673
2698 ieee80211_rx_reorder_ampdu(rx); 2674 ieee80211_rx_reorder_ampdu(rx);
@@ -2762,11 +2738,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
2762 return 0; 2738 return 0;
2763 if (ieee80211_is_beacon(hdr->frame_control)) { 2739 if (ieee80211_is_beacon(hdr->frame_control)) {
2764 return 1; 2740 return 1;
2765 } 2741 } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
2766 else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { 2742 return 0;
2767 if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
2768 return 0;
2769 status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
2770 } else if (!multicast && 2743 } else if (!multicast &&
2771 !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { 2744 !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
2772 if (!(sdata->dev->flags & IFF_PROMISC)) 2745 if (!(sdata->dev->flags & IFF_PROMISC))
@@ -2804,11 +2777,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
2804 * and location updates. Note that mac80211 2777 * and location updates. Note that mac80211
2805 * itself never looks at these frames. 2778 * itself never looks at these frames.
2806 */ 2779 */
2807 if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && 2780 if (ieee80211_is_public_action(hdr, skb->len))
2808 ieee80211_is_public_action(hdr, skb->len))
2809 return 1; 2781 return 1;
2810 if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && 2782 if (!ieee80211_is_beacon(hdr->frame_control))
2811 !ieee80211_is_beacon(hdr->frame_control))
2812 return 0; 2783 return 0;
2813 status->rx_flags &= ~IEEE80211_RX_RA_MATCH; 2784 status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
2814 } 2785 }
@@ -2874,7 +2845,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
2874static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, 2845static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2875 struct sk_buff *skb) 2846 struct sk_buff *skb)
2876{ 2847{
2877 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
2878 struct ieee80211_local *local = hw_to_local(hw); 2848 struct ieee80211_local *local = hw_to_local(hw);
2879 struct ieee80211_sub_if_data *sdata; 2849 struct ieee80211_sub_if_data *sdata;
2880 struct ieee80211_hdr *hdr; 2850 struct ieee80211_hdr *hdr;
@@ -2892,11 +2862,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2892 if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) 2862 if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
2893 local->dot11ReceivedFragmentCount++; 2863 local->dot11ReceivedFragmentCount++;
2894 2864
2895 if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
2896 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
2897 test_bit(SCAN_SW_SCANNING, &local->scanning)))
2898 status->rx_flags |= IEEE80211_RX_IN_SCAN;
2899
2900 if (ieee80211_is_mgmt(fc)) 2865 if (ieee80211_is_mgmt(fc))
2901 err = skb_linearize(skb); 2866 err = skb_linearize(skb);
2902 else 2867 else
@@ -2911,6 +2876,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2911 ieee80211_parse_qos(&rx); 2876 ieee80211_parse_qos(&rx);
2912 ieee80211_verify_alignment(&rx); 2877 ieee80211_verify_alignment(&rx);
2913 2878
2879 if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
2880 ieee80211_is_beacon(hdr->frame_control)))
2881 ieee80211_scan_rx(local, skb);
2882
2914 if (ieee80211_is_data(fc)) { 2883 if (ieee80211_is_data(fc)) {
2915 prev_sta = NULL; 2884 prev_sta = NULL;
2916 2885
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a619c1ea9bd5..1a893f3637c5 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -165,52 +165,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
165 return bss; 165 return bss;
166} 166}
167 167
168ieee80211_rx_result 168void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
169ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
170{ 169{
171 struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 170 struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
172 struct ieee80211_mgmt *mgmt; 171 struct ieee80211_sub_if_data *sdata1, *sdata2;
172 struct ieee80211_mgmt *mgmt = (void *)skb->data;
173 struct ieee80211_bss *bss; 173 struct ieee80211_bss *bss;
174 u8 *elements; 174 u8 *elements;
175 struct ieee80211_channel *channel; 175 struct ieee80211_channel *channel;
176 size_t baselen; 176 size_t baselen;
177 int freq; 177 int freq;
178 __le16 fc; 178 bool beacon;
179 bool presp, beacon = false;
180 struct ieee802_11_elems elems; 179 struct ieee802_11_elems elems;
181 180
182 if (skb->len < 2) 181 if (skb->len < 24 ||
183 return RX_DROP_UNUSABLE; 182 (!ieee80211_is_probe_resp(mgmt->frame_control) &&
184 183 !ieee80211_is_beacon(mgmt->frame_control)))
185 mgmt = (struct ieee80211_mgmt *) skb->data; 184 return;
186 fc = mgmt->frame_control;
187 185
188 if (ieee80211_is_ctl(fc)) 186 sdata1 = rcu_dereference(local->scan_sdata);
189 return RX_CONTINUE; 187 sdata2 = rcu_dereference(local->sched_scan_sdata);
190 188
191 if (skb->len < 24) 189 if (likely(!sdata1 && !sdata2))
192 return RX_CONTINUE; 190 return;
193 191
194 presp = ieee80211_is_probe_resp(fc); 192 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
195 if (presp) {
196 /* ignore ProbeResp to foreign address */ 193 /* ignore ProbeResp to foreign address */
197 if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) 194 if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) &&
198 return RX_DROP_MONITOR; 195 (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr)))
196 return;
199 197
200 presp = true;
201 elements = mgmt->u.probe_resp.variable; 198 elements = mgmt->u.probe_resp.variable;
202 baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); 199 baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
200 beacon = false;
203 } else { 201 } else {
204 beacon = ieee80211_is_beacon(fc);
205 baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); 202 baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
206 elements = mgmt->u.beacon.variable; 203 elements = mgmt->u.beacon.variable;
204 beacon = true;
207 } 205 }
208 206
209 if (!presp && !beacon)
210 return RX_CONTINUE;
211
212 if (baselen > skb->len) 207 if (baselen > skb->len)
213 return RX_DROP_MONITOR; 208 return;
214 209
215 ieee802_11_parse_elems(elements, skb->len - baselen, &elems); 210 ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
216 211
@@ -220,22 +215,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
220 else 215 else
221 freq = rx_status->freq; 216 freq = rx_status->freq;
222 217
223 channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); 218 channel = ieee80211_get_channel(local->hw.wiphy, freq);
224 219
225 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) 220 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
226 return RX_DROP_MONITOR; 221 return;
227 222
228 bss = ieee80211_bss_info_update(sdata->local, rx_status, 223 bss = ieee80211_bss_info_update(local, rx_status,
229 mgmt, skb->len, &elems, 224 mgmt, skb->len, &elems,
230 channel, beacon); 225 channel, beacon);
231 if (bss) 226 if (bss)
232 ieee80211_rx_bss_put(sdata->local, bss); 227 ieee80211_rx_bss_put(local, bss);
233
234 if (channel == sdata->local->oper_channel)
235 return RX_CONTINUE;
236
237 dev_kfree_skb(skb);
238 return RX_QUEUED;
239} 228}
240 229
241/* return false if no more work */ 230/* return false if no more work */