diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 173 |
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 | ||
230 | enum ieee80211_mgd_state { | 230 | enum 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 | ||
951 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 951 | static 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 | ||
1093 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 1091 | static 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); | |||
1333 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | 1320 | static 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 | ||
1412 | static enum rx_mgmt_action __must_check | 1400 | static enum rx_mgmt_action __must_check |
1413 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1401 | ieee80211_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 | ||