aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Eilam <guy@wizery.com>2011-08-17 08:18:15 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-26 10:47:55 -0400
commit2a33bee2753bf28411de8822e3e3c7501966eb1b (patch)
treedac6419b65bdd79da56c6855bbf4a439f424e05c
parent8c71df7a2f6a5345d6cad34e810c50edeca81521 (diff)
mac80211: fix race condition between assoc_done and first EAP packet
When associating to an AP, the station might miss the first EAP packet that the AP sends due to a race condition between the association success procedure and the rx flow in mac80211. In such cases, the packet might fall in ieee80211_rx_h_check due to the fact that the relevant rx->sta wasn't allocated yet. Allocation of the relevant station info struct before actually sending the association request and setting it with a new dummy_sta flag solve this problem. The station will accept only EAP packets from the AP while it is in the pre-association/dummy state. This dummy station entry is not seen by normal sta_info_get() calls, only by sta_info_get_bss_rx(). The driver is not notified for the first insertion of the dummy station. The driver is notified only after the association is complete and the dummy flag is removed from the station entry. That way, all the rest of the code flow should be untouched by this change. Signed-off-by: Guy Eilam <guy@wizery.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/mlme.c59
-rw-r--r--net/mac80211/rx.c21
-rw-r--r--net/mac80211/sta_info.c186
-rw-r--r--net/mac80211/sta_info.h30
4 files changed, 236 insertions, 60 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d6470c7fd6ce..60a6f273cd30 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1482,10 +1482,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
1482 1482
1483 ifmgd->aid = aid; 1483 ifmgd->aid = aid;
1484 1484
1485 sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); 1485 mutex_lock(&sdata->local->sta_mtx);
1486 if (!sta) { 1486 /*
1487 printk(KERN_DEBUG "%s: failed to alloc STA entry for" 1487 * station info was already allocated and inserted before
1488 " the AP\n", sdata->name); 1488 * the association and should be available to us
1489 */
1490 sta = sta_info_get_rx(sdata, cbss->bssid);
1491 if (WARN_ON(!sta)) {
1492 mutex_unlock(&sdata->local->sta_mtx);
1489 return false; 1493 return false;
1490 } 1494 }
1491 1495
@@ -1556,7 +1560,8 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
1556 if (elems.wmm_param) 1560 if (elems.wmm_param)
1557 set_sta_flags(sta, WLAN_STA_WME); 1561 set_sta_flags(sta, WLAN_STA_WME);
1558 1562
1559 err = sta_info_insert(sta); 1563 /* sta_info_reinsert will also unlock the mutex lock */
1564 err = sta_info_reinsert(sta);
1560 sta = NULL; 1565 sta = NULL;
1561 if (err) { 1566 if (err) {
1562 printk(KERN_DEBUG "%s: failed to insert STA entry for" 1567 printk(KERN_DEBUG "%s: failed to insert STA entry for"
@@ -2429,6 +2434,32 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
2429 return 0; 2434 return 0;
2430} 2435}
2431 2436
2437/* create and insert a dummy station entry */
2438static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata,
2439 u8 *bssid) {
2440 struct sta_info *sta;
2441 int err;
2442
2443 sta = sta_info_alloc(sdata, bssid, GFP_KERNEL);
2444 if (!sta) {
2445 printk(KERN_DEBUG "%s: failed to alloc STA entry for"
2446 " the AP\n", sdata->name);
2447 return -ENOMEM;
2448 }
2449
2450 sta->dummy = true;
2451
2452 err = sta_info_insert(sta);
2453 sta = NULL;
2454 if (err) {
2455 printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for"
2456 " the AP (error %d)\n", sdata->name, err);
2457 return err;
2458 }
2459
2460 return 0;
2461}
2462
2432static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, 2463static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2433 struct sk_buff *skb) 2464 struct sk_buff *skb)
2434{ 2465{
@@ -2436,9 +2467,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2436 struct ieee80211_mgmt *mgmt; 2467 struct ieee80211_mgmt *mgmt;
2437 struct ieee80211_rx_status *rx_status; 2468 struct ieee80211_rx_status *rx_status;
2438 struct ieee802_11_elems elems; 2469 struct ieee802_11_elems elems;
2470 struct cfg80211_bss *cbss = wk->assoc.bss;
2439 u16 status; 2471 u16 status;
2440 2472
2441 if (!skb) { 2473 if (!skb) {
2474 sta_info_destroy_addr(wk->sdata, cbss->bssid);
2442 cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); 2475 cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
2443 goto destroy; 2476 goto destroy;
2444 } 2477 }
@@ -2468,12 +2501,16 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2468 if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { 2501 if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
2469 mutex_unlock(&wk->sdata->u.mgd.mtx); 2502 mutex_unlock(&wk->sdata->u.mgd.mtx);
2470 /* oops -- internal error -- send timeout for now */ 2503 /* oops -- internal error -- send timeout for now */
2504 sta_info_destroy_addr(wk->sdata, cbss->bssid);
2471 cfg80211_send_assoc_timeout(wk->sdata->dev, 2505 cfg80211_send_assoc_timeout(wk->sdata->dev,
2472 wk->filter_ta); 2506 wk->filter_ta);
2473 return WORK_DONE_DESTROY; 2507 return WORK_DONE_DESTROY;
2474 } 2508 }
2475 2509
2476 mutex_unlock(&wk->sdata->u.mgd.mtx); 2510 mutex_unlock(&wk->sdata->u.mgd.mtx);
2511 } else {
2512 /* assoc failed - destroy the dummy station entry */
2513 sta_info_destroy_addr(wk->sdata, cbss->bssid);
2477 } 2514 }
2478 2515
2479 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); 2516 cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
@@ -2492,7 +2529,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2492 struct ieee80211_bss *bss = (void *)req->bss->priv; 2529 struct ieee80211_bss *bss = (void *)req->bss->priv;
2493 struct ieee80211_work *wk; 2530 struct ieee80211_work *wk;
2494 const u8 *ssid; 2531 const u8 *ssid;
2495 int i; 2532 int i, err;
2496 2533
2497 mutex_lock(&ifmgd->mtx); 2534 mutex_lock(&ifmgd->mtx);
2498 if (ifmgd->associated) { 2535 if (ifmgd->associated) {
@@ -2517,6 +2554,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2517 if (!wk) 2554 if (!wk)
2518 return -ENOMEM; 2555 return -ENOMEM;
2519 2556
2557 /*
2558 * create a dummy station info entry in order
2559 * to start accepting incoming EAPOL packets from the station
2560 */
2561 err = ieee80211_pre_assoc(sdata, req->bss->bssid);
2562 if (err) {
2563 kfree(wk);
2564 return err;
2565 }
2566
2520 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; 2567 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
2521 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; 2568 ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
2522 2569
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c4453fdd6e11..edd46193af6f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -850,8 +850,21 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
850 ieee80211_is_pspoll(hdr->frame_control)) && 850 ieee80211_is_pspoll(hdr->frame_control)) &&
851 rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && 851 rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
852 rx->sdata->vif.type != NL80211_IFTYPE_WDS && 852 rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
853 (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) 853 (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
854 if (rx->sta && rx->sta->dummy &&
855 ieee80211_is_data_present(hdr->frame_control)) {
856 u16 ethertype;
857 u8 *payload;
858
859 payload = rx->skb->data +
860 ieee80211_hdrlen(hdr->frame_control);
861 ethertype = (payload[6] << 8) | payload[7];
862 if (cpu_to_be16(ethertype) ==
863 rx->sdata->control_port_protocol)
864 return RX_CONTINUE;
865 }
854 return RX_DROP_MONITOR; 866 return RX_DROP_MONITOR;
867 }
855 868
856 return RX_CONTINUE; 869 return RX_CONTINUE;
857} 870}
@@ -2808,7 +2821,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2808 if (ieee80211_is_data(fc)) { 2821 if (ieee80211_is_data(fc)) {
2809 prev_sta = NULL; 2822 prev_sta = NULL;
2810 2823
2811 for_each_sta_info(local, hdr->addr2, sta, tmp) { 2824 for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
2812 if (!prev_sta) { 2825 if (!prev_sta) {
2813 prev_sta = sta; 2826 prev_sta = sta;
2814 continue; 2827 continue;
@@ -2852,7 +2865,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2852 continue; 2865 continue;
2853 } 2866 }
2854 2867
2855 rx.sta = sta_info_get_bss(prev, hdr->addr2); 2868 rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
2856 rx.sdata = prev; 2869 rx.sdata = prev;
2857 ieee80211_prepare_and_rx_handle(&rx, skb, false); 2870 ieee80211_prepare_and_rx_handle(&rx, skb, false);
2858 2871
@@ -2860,7 +2873,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2860 } 2873 }
2861 2874
2862 if (prev) { 2875 if (prev) {
2863 rx.sta = sta_info_get_bss(prev, hdr->addr2); 2876 rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
2864 rx.sdata = prev; 2877 rx.sdata = prev;
2865 2878
2866 if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) 2879 if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d469d9d2b499..17caba27040b 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -100,6 +100,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
100 lockdep_is_held(&local->sta_lock) || 100 lockdep_is_held(&local->sta_lock) ||
101 lockdep_is_held(&local->sta_mtx)); 101 lockdep_is_held(&local->sta_mtx));
102 while (sta) { 102 while (sta) {
103 if (sta->sdata == sdata && !sta->dummy &&
104 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
105 break;
106 sta = rcu_dereference_check(sta->hnext,
107 lockdep_is_held(&local->sta_lock) ||
108 lockdep_is_held(&local->sta_mtx));
109 }
110 return sta;
111}
112
113/* get a station info entry even if it is a dummy station*/
114struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
115 const u8 *addr)
116{
117 struct ieee80211_local *local = sdata->local;
118 struct sta_info *sta;
119
120 sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
121 lockdep_is_held(&local->sta_lock) ||
122 lockdep_is_held(&local->sta_mtx));
123 while (sta) {
103 if (sta->sdata == sdata && 124 if (sta->sdata == sdata &&
104 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) 125 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
105 break; 126 break;
@@ -126,6 +147,32 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
126 while (sta) { 147 while (sta) {
127 if ((sta->sdata == sdata || 148 if ((sta->sdata == sdata ||
128 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && 149 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
150 !sta->dummy &&
151 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
152 break;
153 sta = rcu_dereference_check(sta->hnext,
154 lockdep_is_held(&local->sta_lock) ||
155 lockdep_is_held(&local->sta_mtx));
156 }
157 return sta;
158}
159
160/*
161 * Get sta info either from the specified interface
162 * or from one of its vlans (including dummy stations)
163 */
164struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
165 const u8 *addr)
166{
167 struct ieee80211_local *local = sdata->local;
168 struct sta_info *sta;
169
170 sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
171 lockdep_is_held(&local->sta_lock) ||
172 lockdep_is_held(&local->sta_mtx));
173 while (sta) {
174 if ((sta->sdata == sdata ||
175 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
129 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) 176 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
130 break; 177 break;
131 sta = rcu_dereference_check(sta->hnext, 178 sta = rcu_dereference_check(sta->hnext,
@@ -280,7 +327,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
280 return sta; 327 return sta;
281} 328}
282 329
283static int sta_info_finish_insert(struct sta_info *sta, bool async) 330static int sta_info_finish_insert(struct sta_info *sta,
331 bool async, bool dummy_reinsert)
284{ 332{
285 struct ieee80211_local *local = sta->local; 333 struct ieee80211_local *local = sta->local;
286 struct ieee80211_sub_if_data *sdata = sta->sdata; 334 struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -290,51 +338,58 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
290 338
291 lockdep_assert_held(&local->sta_mtx); 339 lockdep_assert_held(&local->sta_mtx);
292 340
293 /* notify driver */ 341 if (!sta->dummy || dummy_reinsert) {
294 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 342 /* notify driver */
295 sdata = container_of(sdata->bss, 343 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
296 struct ieee80211_sub_if_data, 344 sdata = container_of(sdata->bss,
297 u.ap); 345 struct ieee80211_sub_if_data,
298 err = drv_sta_add(local, sdata, &sta->sta); 346 u.ap);
299 if (err) { 347 err = drv_sta_add(local, sdata, &sta->sta);
300 if (!async) 348 if (err) {
301 return err; 349 if (!async)
302 printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" 350 return err;
303 " - keeping it anyway.\n", 351 printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
304 sdata->name, sta->sta.addr, err); 352 "driver (%d) - keeping it anyway.\n",
305 } else { 353 sdata->name, sta->sta.addr, err);
306 sta->uploaded = true; 354 } else {
355 sta->uploaded = true;
307#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 356#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
308 if (async) 357 if (async)
309 wiphy_debug(local->hw.wiphy, 358 wiphy_debug(local->hw.wiphy,
310 "Finished adding IBSS STA %pM\n", 359 "Finished adding IBSS STA %pM\n",
311 sta->sta.addr); 360 sta->sta.addr);
312#endif 361#endif
362 }
363
364 sdata = sta->sdata;
313 } 365 }
314 366
315 sdata = sta->sdata; 367 if (!dummy_reinsert) {
368 if (!async) {
369 local->num_sta++;
370 local->sta_generation++;
371 smp_mb();
316 372
317 if (!async) { 373 /* make the station visible */
318 local->num_sta++; 374 spin_lock_irqsave(&local->sta_lock, flags);
319 local->sta_generation++; 375 sta_info_hash_add(local, sta);
320 smp_mb(); 376 spin_unlock_irqrestore(&local->sta_lock, flags);
377 }
321 378
322 /* make the station visible */ 379 list_add(&sta->list, &local->sta_list);
323 spin_lock_irqsave(&local->sta_lock, flags); 380 } else {
324 sta_info_hash_add(local, sta); 381 sta->dummy = false;
325 spin_unlock_irqrestore(&local->sta_lock, flags);
326 } 382 }
327 383
328 list_add(&sta->list, &local->sta_list); 384 if (!sta->dummy) {
329 385 ieee80211_sta_debugfs_add(sta);
330 ieee80211_sta_debugfs_add(sta); 386 rate_control_add_sta_debugfs(sta);
331 rate_control_add_sta_debugfs(sta);
332
333 memset(&sinfo, 0, sizeof(sinfo));
334 sinfo.filled = 0;
335 sinfo.generation = local->sta_generation;
336 cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
337 387
388 memset(&sinfo, 0, sizeof(sinfo));
389 sinfo.filled = 0;
390 sinfo.generation = local->sta_generation;
391 cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
392 }
338 393
339 return 0; 394 return 0;
340} 395}
@@ -351,7 +406,7 @@ static void sta_info_finish_pending(struct ieee80211_local *local)
351 list_del(&sta->list); 406 list_del(&sta->list);
352 spin_unlock_irqrestore(&local->sta_lock, flags); 407 spin_unlock_irqrestore(&local->sta_lock, flags);
353 408
354 sta_info_finish_insert(sta, true); 409 sta_info_finish_insert(sta, true, false);
355 410
356 spin_lock_irqsave(&local->sta_lock, flags); 411 spin_lock_irqsave(&local->sta_lock, flags);
357 } 412 }
@@ -395,7 +450,7 @@ static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU)
395 450
396 spin_lock_irqsave(&local->sta_lock, flags); 451 spin_lock_irqsave(&local->sta_lock, flags);
397 /* check if STA exists already */ 452 /* check if STA exists already */
398 if (sta_info_get_bss(sdata, sta->sta.addr)) { 453 if (sta_info_get_bss_rx(sdata, sta->sta.addr)) {
399 spin_unlock_irqrestore(&local->sta_lock, flags); 454 spin_unlock_irqrestore(&local->sta_lock, flags);
400 rcu_read_lock(); 455 rcu_read_lock();
401 return -EEXIST; 456 return -EEXIST;
@@ -431,6 +486,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
431 struct ieee80211_local *local = sta->local; 486 struct ieee80211_local *local = sta->local;
432 struct ieee80211_sub_if_data *sdata = sta->sdata; 487 struct ieee80211_sub_if_data *sdata = sta->sdata;
433 unsigned long flags; 488 unsigned long flags;
489 struct sta_info *exist_sta;
490 bool dummy_reinsert = false;
434 int err = 0; 491 int err = 0;
435 492
436 lockdep_assert_held(&local->sta_mtx); 493 lockdep_assert_held(&local->sta_mtx);
@@ -446,17 +503,28 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
446 */ 503 */
447 504
448 spin_lock_irqsave(&local->sta_lock, flags); 505 spin_lock_irqsave(&local->sta_lock, flags);
449 /* check if STA exists already */ 506 /*
450 if (sta_info_get_bss(sdata, sta->sta.addr)) { 507 * check if STA exists already.
451 spin_unlock_irqrestore(&local->sta_lock, flags); 508 * only accept a scenario of a second call to sta_info_insert_non_ibss
452 mutex_unlock(&local->sta_mtx); 509 * with a dummy station entry that was inserted earlier
453 rcu_read_lock(); 510 * in that case - assume that the dummy station flag should
454 return -EEXIST; 511 * be removed.
512 */
513 exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr);
514 if (exist_sta) {
515 if (exist_sta == sta && sta->dummy) {
516 dummy_reinsert = true;
517 } else {
518 spin_unlock_irqrestore(&local->sta_lock, flags);
519 mutex_unlock(&local->sta_mtx);
520 rcu_read_lock();
521 return -EEXIST;
522 }
455 } 523 }
456 524
457 spin_unlock_irqrestore(&local->sta_lock, flags); 525 spin_unlock_irqrestore(&local->sta_lock, flags);
458 526
459 err = sta_info_finish_insert(sta, false); 527 err = sta_info_finish_insert(sta, false, dummy_reinsert);
460 if (err) { 528 if (err) {
461 mutex_unlock(&local->sta_mtx); 529 mutex_unlock(&local->sta_mtx);
462 rcu_read_lock(); 530 rcu_read_lock();
@@ -464,7 +532,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
464 } 532 }
465 533
466#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 534#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
467 wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); 535 wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n",
536 sta->dummy ? "dummy " : "", sta->sta.addr);
468#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 537#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
469 538
470 /* move reference to rcu-protected */ 539 /* move reference to rcu-protected */
@@ -535,6 +604,25 @@ int sta_info_insert(struct sta_info *sta)
535 return err; 604 return err;
536} 605}
537 606
607/* Caller must hold sta->local->sta_mtx */
608int sta_info_reinsert(struct sta_info *sta)
609{
610 struct ieee80211_local *local = sta->local;
611 int err = 0;
612
613 err = sta_info_insert_check(sta);
614 if (err) {
615 mutex_unlock(&local->sta_mtx);
616 return err;
617 }
618
619 might_sleep();
620
621 err = sta_info_insert_non_ibss(sta);
622 rcu_read_unlock();
623 return err;
624}
625
538static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) 626static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
539{ 627{
540 /* 628 /*
@@ -775,7 +863,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr)
775 int ret; 863 int ret;
776 864
777 mutex_lock(&sdata->local->sta_mtx); 865 mutex_lock(&sdata->local->sta_mtx);
778 sta = sta_info_get(sdata, addr); 866 sta = sta_info_get_rx(sdata, addr);
779 ret = __sta_info_destroy(sta); 867 ret = __sta_info_destroy(sta);
780 mutex_unlock(&sdata->local->sta_mtx); 868 mutex_unlock(&sdata->local->sta_mtx);
781 869
@@ -789,7 +877,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
789 int ret; 877 int ret;
790 878
791 mutex_lock(&sdata->local->sta_mtx); 879 mutex_lock(&sdata->local->sta_mtx);
792 sta = sta_info_get_bss(sdata, addr); 880 sta = sta_info_get_bss_rx(sdata, addr);
793 ret = __sta_info_destroy(sta); 881 ret = __sta_info_destroy(sta);
794 mutex_unlock(&sdata->local->sta_mtx); 882 mutex_unlock(&sdata->local->sta_mtx);
795 883
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 28beb78e601e..e9eb565506da 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -238,10 +238,12 @@ struct sta_ampdu_mlme {
238 * @plink_timer: peer link watch timer 238 * @plink_timer: peer link watch timer
239 * @plink_timer_was_running: used by suspend/resume to restore timers 239 * @plink_timer_was_running: used by suspend/resume to restore timers
240 * @debugfs: debug filesystem info 240 * @debugfs: debug filesystem info
241 * @sta: station information we share with the driver
242 * @dead: set to true when sta is unlinked 241 * @dead: set to true when sta is unlinked
243 * @uploaded: set to true when sta is uploaded to the driver 242 * @uploaded: set to true when sta is uploaded to the driver
244 * @lost_packets: number of consecutive lost packets 243 * @lost_packets: number of consecutive lost packets
244 * @dummy: indicate a dummy station created for receiving
245 * EAP frames before association
246 * @sta: station information we share with the driver
245 */ 247 */
246struct sta_info { 248struct sta_info {
247 /* General information, mostly static */ 249 /* General information, mostly static */
@@ -336,6 +338,9 @@ struct sta_info {
336 338
337 unsigned int lost_packets; 339 unsigned int lost_packets;
338 340
341 /* should be right in front of sta to be in the same cache line */
342 bool dummy;
343
339 /* keep last! */ 344 /* keep last! */
340 struct ieee80211_sta sta; 345 struct ieee80211_sta sta;
341}; 346};
@@ -436,9 +441,15 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
436struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, 441struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
437 const u8 *addr); 442 const u8 *addr);
438 443
444struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
445 const u8 *addr);
446
439struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, 447struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
440 const u8 *addr); 448 const u8 *addr);
441 449
450struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
451 const u8 *addr);
452
442static inline 453static inline
443void for_each_sta_info_type_check(struct ieee80211_local *local, 454void for_each_sta_info_type_check(struct ieee80211_local *local,
444 const u8 *addr, 455 const u8 *addr,
@@ -459,6 +470,22 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
459 _sta = nxt, \ 470 _sta = nxt, \
460 nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ 471 nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \
461 ) \ 472 ) \
473 /* run code only if address matches and it's not a dummy sta */ \
474 if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 && \
475 !_sta->dummy)
476
477#define for_each_sta_info_rx(local, _addr, _sta, nxt) \
478 for ( /* initialise loop */ \
479 _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
480 nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \
481 /* typecheck */ \
482 for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
483 /* continue condition */ \
484 _sta; \
485 /* advance loop */ \
486 _sta = nxt, \
487 nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \
488 ) \
462 /* compare address and run code only if it matches */ \ 489 /* compare address and run code only if it matches */ \
463 if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0) 490 if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0)
464 491
@@ -484,6 +511,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
484int sta_info_insert(struct sta_info *sta); 511int sta_info_insert(struct sta_info *sta);
485int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); 512int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
486int sta_info_insert_atomic(struct sta_info *sta); 513int sta_info_insert_atomic(struct sta_info *sta);
514int sta_info_reinsert(struct sta_info *sta);
487 515
488int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, 516int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
489 const u8 *addr); 517 const u8 *addr);