aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
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 /net/mac80211/mlme.c
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>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c59
1 files changed, 53 insertions, 6 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