aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-12-23 07:15:33 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-28 16:54:52 -0500
commit63f170e0c80a131cdd549fab7afb5036009944fc (patch)
tree38eea09fd8ac9a4199f30ff9f6fba39e6c8d58ed /net/mac80211/mlme.c
parenta80f7c0b088187c8471b441d461e937991870661 (diff)
mac80211: let cfg80211 manage auth state
mac80211 currently hangs on to the auth state by keeping it on the work list. That can lead to confusing behaviour like rejecting scans while authenticated to any AP (but not yet associated.) It also means that it needs to keep track of the work struct while associated for when it gets disassociated (or disassociates.) Change this to free the work struct after the authentication completed successfully and allocate a new one for associating, thereby letting cfg80211 manage the auth state. Another change necessary for this is to tell cfg80211 about all unicast deauth frames sent to mac80211 since now it can no longer check the auth state, but that check was racy anyway. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c173
1 files changed, 72 insertions, 101 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7f9909340c09..f060bc616203 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -949,11 +949,10 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
949} 949}
950 950
951static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, 951static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
952 struct ieee80211_mgd_work *wk, 952 struct ieee80211_bss *bss,
953 u32 bss_info_changed) 953 u32 bss_info_changed)
954{ 954{
955 struct ieee80211_local *local = sdata->local; 955 struct ieee80211_local *local = sdata->local;
956 struct ieee80211_bss *bss = wk->bss;
957 956
958 bss_info_changed |= BSS_CHANGED_ASSOC; 957 bss_info_changed |= BSS_CHANGED_ASSOC;
959 /* set timing information */ 958 /* set timing information */
@@ -966,7 +965,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
966 bss->cbss.capability, bss->has_erp_value, bss->erp_value); 965 bss->cbss.capability, bss->has_erp_value, bss->erp_value);
967 966
968 sdata->u.mgd.associated = bss; 967 sdata->u.mgd.associated = bss;
969 sdata->u.mgd.old_associate_work = wk;
970 memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); 968 memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
971 969
972 /* just to be sure */ 970 /* just to be sure */
@@ -1090,8 +1088,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
1090 return RX_MGMT_NONE; 1088 return RX_MGMT_NONE;
1091} 1089}
1092 1090
1093static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, 1091static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
1094 bool deauth)
1095{ 1092{
1096 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1093 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1097 struct ieee80211_local *local = sdata->local; 1094 struct ieee80211_local *local = sdata->local;
@@ -1109,16 +1106,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1109 ifmgd->associated = NULL; 1106 ifmgd->associated = NULL;
1110 memset(ifmgd->bssid, 0, ETH_ALEN); 1107 memset(ifmgd->bssid, 0, ETH_ALEN);
1111 1108
1112 if (deauth) {
1113 kfree(ifmgd->old_associate_work);
1114 ifmgd->old_associate_work = NULL;
1115 } else {
1116 struct ieee80211_mgd_work *wk = ifmgd->old_associate_work;
1117
1118 wk->state = IEEE80211_MGD_STATE_IDLE;
1119 list_add(&wk->list, &ifmgd->work_list);
1120 }
1121
1122 /* 1109 /*
1123 * we need to commit the associated = NULL change because the 1110 * we need to commit the associated = NULL change because the
1124 * scan code uses that to determine whether this iface should 1111 * scan code uses that to determine whether this iface should
@@ -1333,7 +1320,8 @@ EXPORT_SYMBOL(ieee80211_beacon_loss);
1333static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, 1320static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
1334 struct ieee80211_mgd_work *wk) 1321 struct ieee80211_mgd_work *wk)
1335{ 1322{
1336 wk->state = IEEE80211_MGD_STATE_IDLE; 1323 list_del(&wk->list);
1324 kfree(wk);
1337 printk(KERN_DEBUG "%s: authenticated\n", sdata->name); 1325 printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
1338} 1326}
1339 1327
@@ -1411,7 +1399,6 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
1411 1399
1412static enum rx_mgmt_action __must_check 1400static enum rx_mgmt_action __must_check
1413ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, 1401ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
1414 struct ieee80211_mgd_work *wk,
1415 struct ieee80211_mgmt *mgmt, size_t len) 1402 struct ieee80211_mgmt *mgmt, size_t len)
1416{ 1403{
1417 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1404 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1423,23 +1410,15 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
1423 1410
1424 ASSERT_MGD_MTX(ifmgd); 1411 ASSERT_MGD_MTX(ifmgd);
1425 1412
1426 if (wk) 1413 bssid = ifmgd->associated->cbss.bssid;
1427 bssid = wk->bss->cbss.bssid;
1428 else
1429 bssid = ifmgd->associated->cbss.bssid;
1430 1414
1431 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); 1415 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
1432 1416
1433 printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", 1417 printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
1434 sdata->name, bssid, reason_code); 1418 sdata->name, bssid, reason_code);
1435 1419
1436 if (!wk) { 1420 ieee80211_set_disassoc(sdata);
1437 ieee80211_set_disassoc(sdata, true); 1421 ieee80211_recalc_idle(sdata->local);
1438 ieee80211_recalc_idle(sdata->local);
1439 } else {
1440 list_del(&wk->list);
1441 kfree(wk);
1442 }
1443 1422
1444 return RX_MGMT_CFG80211_DEAUTH; 1423 return RX_MGMT_CFG80211_DEAUTH;
1445} 1424}
@@ -1468,7 +1447,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
1468 printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", 1447 printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
1469 sdata->name, mgmt->sa, reason_code); 1448 sdata->name, mgmt->sa, reason_code);
1470 1449
1471 ieee80211_set_disassoc(sdata, false); 1450 ieee80211_set_disassoc(sdata);
1472 ieee80211_recalc_idle(sdata->local); 1451 ieee80211_recalc_idle(sdata->local);
1473 return RX_MGMT_CFG80211_DISASSOC; 1452 return RX_MGMT_CFG80211_DISASSOC;
1474} 1453}
@@ -1484,6 +1463,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1484 struct ieee80211_local *local = sdata->local; 1463 struct ieee80211_local *local = sdata->local;
1485 struct ieee80211_supported_band *sband; 1464 struct ieee80211_supported_band *sband;
1486 struct sta_info *sta; 1465 struct sta_info *sta;
1466 struct ieee80211_bss *bss = wk->bss;
1487 u32 rates, basic_rates; 1467 u32 rates, basic_rates;
1488 u16 capab_info, status_code, aid; 1468 u16 capab_info, status_code, aid;
1489 struct ieee802_11_elems elems; 1469 struct ieee802_11_elems elems;
@@ -1502,7 +1482,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1502 if (len < 24 + 6) 1482 if (len < 24 + 6)
1503 return RX_MGMT_NONE; 1483 return RX_MGMT_NONE;
1504 1484
1505 if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) 1485 if (memcmp(bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
1506 return RX_MGMT_NONE; 1486 return RX_MGMT_NONE;
1507 1487
1508 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); 1488 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
@@ -1532,10 +1512,17 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1532 return RX_MGMT_NONE; 1512 return RX_MGMT_NONE;
1533 } 1513 }
1534 1514
1515 /*
1516 * Here the association was either successful or not.
1517 */
1518
1519 /* delete work item -- must be before set_associated for PS */
1520 list_del(&wk->list);
1521 kfree(wk);
1522
1535 if (status_code != WLAN_STATUS_SUCCESS) { 1523 if (status_code != WLAN_STATUS_SUCCESS) {
1536 printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", 1524 printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
1537 sdata->name, status_code); 1525 sdata->name, status_code);
1538 wk->state = IEEE80211_MGD_STATE_IDLE;
1539 return RX_MGMT_CFG80211_ASSOC; 1526 return RX_MGMT_CFG80211_ASSOC;
1540 } 1527 }
1541 1528
@@ -1553,7 +1540,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1553 printk(KERN_DEBUG "%s: associated\n", sdata->name); 1540 printk(KERN_DEBUG "%s: associated\n", sdata->name);
1554 ifmgd->aid = aid; 1541 ifmgd->aid = aid;
1555 1542
1556 sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); 1543 sta = sta_info_alloc(sdata, bss->cbss.bssid, GFP_KERNEL);
1557 if (!sta) { 1544 if (!sta) {
1558 printk(KERN_DEBUG "%s: failed to alloc STA entry for" 1545 printk(KERN_DEBUG "%s: failed to alloc STA entry for"
1559 " the AP\n", sdata->name); 1546 " the AP\n", sdata->name);
@@ -1645,18 +1632,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1645 (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && 1632 (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
1646 !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) 1633 !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
1647 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, 1634 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
1648 wk->bss->cbss.bssid, 1635 bss->cbss.bssid,
1649 ap_ht_cap_flags); 1636 ap_ht_cap_flags);
1650 1637
1651 /* delete work item -- must be before set_associated for PS */
1652 list_del(&wk->list);
1653
1654 /* set AID and assoc capability, 1638 /* set AID and assoc capability,
1655 * ieee80211_set_associated() will tell the driver */ 1639 * ieee80211_set_associated() will tell the driver */
1656 bss_conf->aid = aid; 1640 bss_conf->aid = aid;
1657 bss_conf->assoc_capability = capab_info; 1641 bss_conf->assoc_capability = capab_info;
1658 /* this will take ownership of wk */ 1642 ieee80211_set_associated(sdata, bss, changed);
1659 ieee80211_set_associated(sdata, wk, changed);
1660 1643
1661 /* 1644 /*
1662 * Start timer to probe the connection to the AP now. 1645 * Start timer to probe the connection to the AP now.
@@ -1999,8 +1982,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1999 skb->len, rx_status); 1982 skb->len, rx_status);
2000 break; 1983 break;
2001 case IEEE80211_STYPE_DEAUTH: 1984 case IEEE80211_STYPE_DEAUTH:
2002 rma = ieee80211_rx_mgmt_deauth(sdata, NULL, 1985 rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
2003 mgmt, skb->len);
2004 break; 1986 break;
2005 case IEEE80211_STYPE_DISASSOC: 1987 case IEEE80211_STYPE_DISASSOC:
2006 rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); 1988 rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
@@ -2051,8 +2033,15 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
2051 skb->len, true); 2033 skb->len, true);
2052 break; 2034 break;
2053 case IEEE80211_STYPE_DEAUTH: 2035 case IEEE80211_STYPE_DEAUTH:
2054 rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, 2036 if (skb->len >= 24 + 2 /* mgmt + deauth reason */) {
2055 skb->len); 2037 /*
2038 * We get here if we get deauth while
2039 * trying to auth/assoc. Telling cfg80211
2040 * is handled below, unconditionally.
2041 */
2042 list_del(&wk->list);
2043 kfree(wk);
2044 }
2056 break; 2045 break;
2057 } 2046 }
2058 /* 2047 /*
@@ -2066,6 +2055,12 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
2066 2055
2067 mutex_unlock(&ifmgd->mtx); 2056 mutex_unlock(&ifmgd->mtx);
2068 2057
2058 if (skb->len >= 24 + 2 /* mgmt + deauth reason */ &&
2059 (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) {
2060 WARN_ON(rma != RX_MGMT_NONE);
2061 rma = RX_MGMT_CFG80211_DEAUTH;
2062 }
2063
2069 switch (rma) { 2064 switch (rma) {
2070 case RX_MGMT_NONE: 2065 case RX_MGMT_NONE:
2071 /* no action */ 2066 /* no action */
@@ -2116,7 +2111,6 @@ static void ieee80211_sta_work(struct work_struct *work)
2116 struct ieee80211_mgd_work *wk, *tmp; 2111 struct ieee80211_mgd_work *wk, *tmp;
2117 LIST_HEAD(free_work); 2112 LIST_HEAD(free_work);
2118 enum rx_mgmt_action rma; 2113 enum rx_mgmt_action rma;
2119 bool anybusy = false;
2120 2114
2121 if (!ieee80211_sdata_running(sdata)) 2115 if (!ieee80211_sdata_running(sdata))
2122 return; 2116 return;
@@ -2171,7 +2165,7 @@ static void ieee80211_sta_work(struct work_struct *work)
2171 printk(KERN_DEBUG "No probe response from AP %pM" 2165 printk(KERN_DEBUG "No probe response from AP %pM"
2172 " after %dms, disconnecting.\n", 2166 " after %dms, disconnecting.\n",
2173 bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); 2167 bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
2174 ieee80211_set_disassoc(sdata, true); 2168 ieee80211_set_disassoc(sdata);
2175 ieee80211_recalc_idle(local); 2169 ieee80211_recalc_idle(local);
2176 mutex_unlock(&ifmgd->mtx); 2170 mutex_unlock(&ifmgd->mtx);
2177 /* 2171 /*
@@ -2203,8 +2197,6 @@ static void ieee80211_sta_work(struct work_struct *work)
2203 switch (wk->state) { 2197 switch (wk->state) {
2204 default: 2198 default:
2205 WARN_ON(1); 2199 WARN_ON(1);
2206 /* fall through */
2207 case IEEE80211_MGD_STATE_IDLE:
2208 /* nothing */ 2200 /* nothing */
2209 rma = RX_MGMT_NONE; 2201 rma = RX_MGMT_NONE;
2210 break; 2202 break;
@@ -2227,20 +2219,19 @@ static void ieee80211_sta_work(struct work_struct *work)
2227 case RX_MGMT_CFG80211_ASSOC_TO: 2219 case RX_MGMT_CFG80211_ASSOC_TO:
2228 list_del(&wk->list); 2220 list_del(&wk->list);
2229 list_add(&wk->list, &free_work); 2221 list_add(&wk->list, &free_work);
2230 wk->tries = rma; /* small abuse but only local */ 2222 /*
2223 * small abuse but only local -- keep the
2224 * action type in wk->timeout while the item
2225 * is on the cleanup list
2226 */
2227 wk->timeout = rma;
2231 break; 2228 break;
2232 default: 2229 default:
2233 WARN(1, "unexpected: %d", rma); 2230 WARN(1, "unexpected: %d", rma);
2234 } 2231 }
2235 } 2232 }
2236 2233
2237 list_for_each_entry(wk, &ifmgd->work_list, list) { 2234 if (list_empty(&ifmgd->work_list) &&
2238 if (wk->state != IEEE80211_MGD_STATE_IDLE) {
2239 anybusy = true;
2240 break;
2241 }
2242 }
2243 if (!anybusy &&
2244 test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) 2235 test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
2245 ieee80211_queue_delayed_work(&local->hw, 2236 ieee80211_queue_delayed_work(&local->hw,
2246 &local->scan_work, 2237 &local->scan_work,
@@ -2249,7 +2240,8 @@ static void ieee80211_sta_work(struct work_struct *work)
2249 mutex_unlock(&ifmgd->mtx); 2240 mutex_unlock(&ifmgd->mtx);
2250 2241
2251 list_for_each_entry_safe(wk, tmp, &free_work, list) { 2242 list_for_each_entry_safe(wk, tmp, &free_work, list) {
2252 switch (wk->tries) { 2243 /* see above how we're using wk->timeout */
2244 switch (wk->timeout) {
2253 case RX_MGMT_CFG80211_AUTH_TO: 2245 case RX_MGMT_CFG80211_AUTH_TO:
2254 cfg80211_send_auth_timeout(sdata->dev, 2246 cfg80211_send_auth_timeout(sdata->dev,
2255 wk->bss->cbss.bssid); 2247 wk->bss->cbss.bssid);
@@ -2259,7 +2251,7 @@ static void ieee80211_sta_work(struct work_struct *work)
2259 wk->bss->cbss.bssid); 2251 wk->bss->cbss.bssid);
2260 break; 2252 break;
2261 default: 2253 default:
2262 WARN(1, "unexpected: %d", wk->tries); 2254 WARN(1, "unexpected: %lu", wk->timeout);
2263 } 2255 }
2264 2256
2265 list_del(&wk->list); 2257 list_del(&wk->list);
@@ -2487,35 +2479,18 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2487 struct cfg80211_assoc_request *req) 2479 struct cfg80211_assoc_request *req)
2488{ 2480{
2489 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2481 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2490 struct ieee80211_mgd_work *wk, *found = NULL; 2482 struct ieee80211_mgd_work *wk;
2483 const u8 *ssid;
2491 int i, err; 2484 int i, err;
2492 2485
2493 mutex_lock(&ifmgd->mtx); 2486 mutex_lock(&ifmgd->mtx);
2494 2487
2495 list_for_each_entry(wk, &ifmgd->work_list, list) { 2488 wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL);
2496 if (&wk->bss->cbss == req->bss &&
2497 wk->state == IEEE80211_MGD_STATE_IDLE) {
2498 found = wk;
2499 break;
2500 }
2501 }
2502
2503 if (!found) {
2504 err = -ENOLINK;
2505 goto out;
2506 }
2507
2508 list_del(&found->list);
2509
2510 wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL);
2511 if (!wk) { 2489 if (!wk) {
2512 list_add(&found->list, &ifmgd->work_list);
2513 err = -ENOMEM; 2490 err = -ENOMEM;
2514 goto out; 2491 goto out;
2515 } 2492 }
2516 2493
2517 list_add(&wk->list, &ifmgd->work_list);
2518
2519 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; 2494 ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
2520 2495
2521 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) 2496 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
@@ -2524,8 +2499,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2524 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) 2499 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
2525 ifmgd->flags |= IEEE80211_STA_DISABLE_11N; 2500 ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
2526 2501
2527 sdata->local->oper_channel = req->bss->channel;
2528 ieee80211_hw_config(sdata->local, 0);
2529 2502
2530 if (req->ie && req->ie_len) { 2503 if (req->ie && req->ie_len) {
2531 memcpy(wk->ie, req->ie, req->ie_len); 2504 memcpy(wk->ie, req->ie, req->ie_len);
@@ -2533,11 +2506,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2533 } else 2506 } else
2534 wk->ie_len = 0; 2507 wk->ie_len = 0;
2535 2508
2509 wk->bss = (void *)req->bss;
2510
2511 ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
2512 memcpy(wk->ssid, ssid + 2, ssid[1]);
2513 wk->ssid_len = ssid[1];
2514
2536 if (req->prev_bssid) 2515 if (req->prev_bssid)
2537 memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); 2516 memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN);
2538 2517
2539 wk->state = IEEE80211_MGD_STATE_ASSOC; 2518 wk->state = IEEE80211_MGD_STATE_ASSOC;
2540 wk->tries = 0;
2541 wk->timeout = jiffies; /* run right away */ 2519 wk->timeout = jiffies; /* run right away */
2542 2520
2543 if (req->use_mfp) { 2521 if (req->use_mfp) {
@@ -2553,6 +2531,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2553 else 2531 else
2554 ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; 2532 ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
2555 2533
2534 sdata->local->oper_channel = req->bss->channel;
2535 ieee80211_hw_config(sdata->local, 0);
2536
2537 list_add(&wk->list, &ifmgd->work_list);
2556 ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); 2538 ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
2557 2539
2558 err = 0; 2540 err = 0;
@@ -2568,23 +2550,23 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2568{ 2550{
2569 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2551 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2570 struct ieee80211_mgd_work *wk; 2552 struct ieee80211_mgd_work *wk;
2571 const u8 *bssid = NULL; 2553 const u8 *bssid = req->bss->bssid;
2572 bool not_auth_yet = false; 2554 bool not_auth_yet = false;
2573 2555
2574 mutex_lock(&ifmgd->mtx); 2556 mutex_lock(&ifmgd->mtx);
2575 2557
2576 if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { 2558 if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
2577 bssid = req->bss->bssid; 2559 bssid = req->bss->bssid;
2578 ieee80211_set_disassoc(sdata, true); 2560 ieee80211_set_disassoc(sdata);
2579 } else list_for_each_entry(wk, &ifmgd->work_list, list) { 2561 } else list_for_each_entry(wk, &ifmgd->work_list, list) {
2580 if (&wk->bss->cbss == req->bss) { 2562 if (wk->state != IEEE80211_MGD_STATE_PROBE)
2581 bssid = req->bss->bssid; 2563 continue;
2582 if (wk->state == IEEE80211_MGD_STATE_PROBE) 2564 if (req->bss != &wk->bss->cbss)
2583 not_auth_yet = true; 2565 continue;
2584 list_del(&wk->list); 2566 not_auth_yet = true;
2585 kfree(wk); 2567 list_del(&wk->list);
2586 break; 2568 kfree(wk);
2587 } 2569 break;
2588 } 2570 }
2589 2571
2590 /* 2572 /*
@@ -2601,17 +2583,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2601 return 0; 2583 return 0;
2602 } 2584 }
2603 2585
2604 /*
2605 * cfg80211 should catch this ... but it's racy since
2606 * we can receive a deauth frame, process it, hand it
2607 * to cfg80211 while that's in a locked section already
2608 * trying to tell us that the user wants to disconnect.
2609 */
2610 if (!bssid) {
2611 mutex_unlock(&ifmgd->mtx);
2612 return -ENOLINK;
2613 }
2614
2615 mutex_unlock(&ifmgd->mtx); 2586 mutex_unlock(&ifmgd->mtx);
2616 2587
2617 printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", 2588 printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
@@ -2648,7 +2619,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2648 printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", 2619 printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
2649 sdata->name, req->bss->bssid, req->reason_code); 2620 sdata->name, req->bss->bssid, req->reason_code);
2650 2621
2651 ieee80211_set_disassoc(sdata, false); 2622 ieee80211_set_disassoc(sdata);
2652 2623
2653 mutex_unlock(&ifmgd->mtx); 2624 mutex_unlock(&ifmgd->mtx);
2654 2625