aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mlme.c173
2 files changed, 73 insertions, 103 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index adeae03c26a3..e21e0301548b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -228,7 +228,7 @@ struct mesh_preq_queue {
228}; 228};
229 229
230enum ieee80211_mgd_state { 230enum ieee80211_mgd_state {
231 IEEE80211_MGD_STATE_IDLE, 231 IEEE80211_MGD_STATE_INVALID,
232 IEEE80211_MGD_STATE_PROBE, 232 IEEE80211_MGD_STATE_PROBE,
233 IEEE80211_MGD_STATE_AUTH, 233 IEEE80211_MGD_STATE_AUTH,
234 IEEE80211_MGD_STATE_ASSOC, 234 IEEE80211_MGD_STATE_ASSOC,
@@ -285,7 +285,6 @@ struct ieee80211_if_managed {
285 285
286 struct mutex mtx; 286 struct mutex mtx;
287 struct ieee80211_bss *associated; 287 struct ieee80211_bss *associated;
288 struct ieee80211_mgd_work *old_associate_work;
289 struct list_head work_list; 288 struct list_head work_list;
290 289
291 u8 bssid[ETH_ALEN]; 290 u8 bssid[ETH_ALEN];
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