diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 155 |
1 files changed, 129 insertions, 26 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d595265d6c2..0f48368c2e2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -613,6 +613,9 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
613 | if (!mgd->powersave) | 613 | if (!mgd->powersave) |
614 | return false; | 614 | return false; |
615 | 615 | ||
616 | if (mgd->broken_ap) | ||
617 | return false; | ||
618 | |||
616 | if (!mgd->associated) | 619 | if (!mgd->associated) |
617 | return false; | 620 | return false; |
618 | 621 | ||
@@ -749,7 +752,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
749 | container_of(work, struct ieee80211_local, | 752 | container_of(work, struct ieee80211_local, |
750 | dynamic_ps_enable_work); | 753 | dynamic_ps_enable_work); |
751 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 754 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 755 | struct ieee80211_if_managed *ifmgd; |
753 | unsigned long flags; | 756 | unsigned long flags; |
754 | int q; | 757 | int q; |
755 | 758 | ||
@@ -757,26 +760,39 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
757 | if (!sdata) | 760 | if (!sdata) |
758 | return; | 761 | return; |
759 | 762 | ||
763 | ifmgd = &sdata->u.mgd; | ||
764 | |||
760 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 765 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
761 | return; | 766 | return; |
762 | 767 | ||
763 | /* | 768 | if (!local->disable_dynamic_ps && |
764 | * transmission can be stopped by others which leads to | 769 | local->hw.conf.dynamic_ps_timeout > 0) { |
765 | * dynamic_ps_timer expiry. Postpond the ps timer if it | 770 | /* don't enter PS if TX frames are pending */ |
766 | * is not the actual idle state. | 771 | if (drv_tx_frames_pending(local)) { |
767 | */ | ||
768 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
769 | for (q = 0; q < local->hw.queues; q++) { | ||
770 | if (local->queue_stop_reasons[q]) { | ||
771 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
772 | flags); | ||
773 | mod_timer(&local->dynamic_ps_timer, jiffies + | 772 | mod_timer(&local->dynamic_ps_timer, jiffies + |
774 | msecs_to_jiffies( | 773 | msecs_to_jiffies( |
775 | local->hw.conf.dynamic_ps_timeout)); | 774 | local->hw.conf.dynamic_ps_timeout)); |
776 | return; | 775 | return; |
777 | } | 776 | } |
777 | |||
778 | /* | ||
779 | * transmission can be stopped by others which leads to | ||
780 | * dynamic_ps_timer expiry. Postpone the ps timer if it | ||
781 | * is not the actual idle state. | ||
782 | */ | ||
783 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
784 | for (q = 0; q < local->hw.queues; q++) { | ||
785 | if (local->queue_stop_reasons[q]) { | ||
786 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
787 | flags); | ||
788 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
789 | msecs_to_jiffies( | ||
790 | local->hw.conf.dynamic_ps_timeout)); | ||
791 | return; | ||
792 | } | ||
793 | } | ||
794 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
778 | } | 795 | } |
779 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
780 | 796 | ||
781 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 797 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
782 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { | 798 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { |
@@ -801,7 +817,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
801 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 817 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
802 | } | 818 | } |
803 | 819 | ||
804 | netif_tx_wake_all_queues(sdata->dev); | 820 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
821 | netif_tx_wake_all_queues(sdata->dev); | ||
805 | } | 822 | } |
806 | 823 | ||
807 | void ieee80211_dynamic_ps_timer(unsigned long data) | 824 | void ieee80211_dynamic_ps_timer(unsigned long data) |
@@ -903,6 +920,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
903 | params.aifs, params.cw_min, params.cw_max, | 920 | params.aifs, params.cw_min, params.cw_max, |
904 | params.txop, params.uapsd); | 921 | params.txop, params.uapsd); |
905 | #endif | 922 | #endif |
923 | local->tx_conf[queue] = params; | ||
906 | if (drv_conf_tx(local, queue, ¶ms)) | 924 | if (drv_conf_tx(local, queue, ¶ms)) |
907 | wiphy_debug(local->hw.wiphy, | 925 | wiphy_debug(local->hw.wiphy, |
908 | "failed to set TX queue parameters for queue %d\n", | 926 | "failed to set TX queue parameters for queue %d\n", |
@@ -1204,7 +1222,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1204 | ieee80211_send_nullfunc(sdata->local, sdata, 0); | 1222 | ieee80211_send_nullfunc(sdata->local, sdata, 0); |
1205 | } else { | 1223 | } else { |
1206 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1224 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1207 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | 1225 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, |
1226 | (u32) -1, true); | ||
1208 | } | 1227 | } |
1209 | 1228 | ||
1210 | ifmgd->probe_send_count++; | 1229 | ifmgd->probe_send_count++; |
@@ -1289,7 +1308,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1289 | 1308 | ||
1290 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1309 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1291 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | 1310 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, |
1292 | ssid + 2, ssid[1], NULL, 0); | 1311 | (u32) -1, ssid + 2, ssid[1], |
1312 | NULL, 0, true); | ||
1293 | 1313 | ||
1294 | return skb; | 1314 | return skb; |
1295 | } | 1315 | } |
@@ -1450,10 +1470,21 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1450 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1470 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
1451 | 1471 | ||
1452 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | 1472 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) |
1453 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | 1473 | printk(KERN_DEBUG |
1454 | "set\n", sdata->name, aid); | 1474 | "%s: invalid AID value 0x%x; bits 15:14 not set\n", |
1475 | sdata->name, aid); | ||
1455 | aid &= ~(BIT(15) | BIT(14)); | 1476 | aid &= ~(BIT(15) | BIT(14)); |
1456 | 1477 | ||
1478 | ifmgd->broken_ap = false; | ||
1479 | |||
1480 | if (aid == 0 || aid > IEEE80211_MAX_AID) { | ||
1481 | printk(KERN_DEBUG | ||
1482 | "%s: invalid AID value %d (out of range), turn off PS\n", | ||
1483 | sdata->name, aid); | ||
1484 | aid = 0; | ||
1485 | ifmgd->broken_ap = true; | ||
1486 | } | ||
1487 | |||
1457 | pos = mgmt->u.assoc_resp.variable; | 1488 | pos = mgmt->u.assoc_resp.variable; |
1458 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 1489 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1459 | 1490 | ||
@@ -1748,6 +1779,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1748 | ifmgd->ave_beacon_signal = rx_status->signal * 16; | 1779 | ifmgd->ave_beacon_signal = rx_status->signal * 16; |
1749 | ifmgd->last_cqm_event_signal = 0; | 1780 | ifmgd->last_cqm_event_signal = 0; |
1750 | ifmgd->count_beacon_signal = 1; | 1781 | ifmgd->count_beacon_signal = 1; |
1782 | ifmgd->last_ave_beacon_signal = 0; | ||
1751 | } else { | 1783 | } else { |
1752 | ifmgd->ave_beacon_signal = | 1784 | ifmgd->ave_beacon_signal = |
1753 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + | 1785 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + |
@@ -1755,6 +1787,28 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1755 | ifmgd->ave_beacon_signal) / 16; | 1787 | ifmgd->ave_beacon_signal) / 16; |
1756 | ifmgd->count_beacon_signal++; | 1788 | ifmgd->count_beacon_signal++; |
1757 | } | 1789 | } |
1790 | |||
1791 | if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && | ||
1792 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { | ||
1793 | int sig = ifmgd->ave_beacon_signal; | ||
1794 | int last_sig = ifmgd->last_ave_beacon_signal; | ||
1795 | |||
1796 | /* | ||
1797 | * if signal crosses either of the boundaries, invoke callback | ||
1798 | * with appropriate parameters | ||
1799 | */ | ||
1800 | if (sig > ifmgd->rssi_max_thold && | ||
1801 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { | ||
1802 | ifmgd->last_ave_beacon_signal = sig; | ||
1803 | drv_rssi_callback(local, RSSI_EVENT_HIGH); | ||
1804 | } else if (sig < ifmgd->rssi_min_thold && | ||
1805 | (last_sig >= ifmgd->rssi_max_thold || | ||
1806 | last_sig == 0)) { | ||
1807 | ifmgd->last_ave_beacon_signal = sig; | ||
1808 | drv_rssi_callback(local, RSSI_EVENT_LOW); | ||
1809 | } | ||
1810 | } | ||
1811 | |||
1758 | if (bss_conf->cqm_rssi_thold && | 1812 | if (bss_conf->cqm_rssi_thold && |
1759 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && | 1813 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && |
1760 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { | 1814 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { |
@@ -2014,7 +2068,7 @@ static void ieee80211_sta_timer(unsigned long data) | |||
2014 | } | 2068 | } |
2015 | 2069 | ||
2016 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | 2070 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
2017 | u8 *bssid) | 2071 | u8 *bssid, u8 reason) |
2018 | { | 2072 | { |
2019 | struct ieee80211_local *local = sdata->local; | 2073 | struct ieee80211_local *local = sdata->local; |
2020 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2074 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -2032,8 +2086,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2032 | * but that's not a problem. | 2086 | * but that's not a problem. |
2033 | */ | 2087 | */ |
2034 | ieee80211_send_deauth_disassoc(sdata, bssid, | 2088 | ieee80211_send_deauth_disassoc(sdata, bssid, |
2035 | IEEE80211_STYPE_DEAUTH, | 2089 | IEEE80211_STYPE_DEAUTH, reason, |
2036 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
2037 | NULL, true); | 2090 | NULL, true); |
2038 | mutex_lock(&ifmgd->mtx); | 2091 | mutex_lock(&ifmgd->mtx); |
2039 | } | 2092 | } |
@@ -2079,7 +2132,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2079 | " AP %pM, disconnecting.\n", | 2132 | " AP %pM, disconnecting.\n", |
2080 | sdata->name, bssid); | 2133 | sdata->name, bssid); |
2081 | #endif | 2134 | #endif |
2082 | ieee80211_sta_connection_lost(sdata, bssid); | 2135 | ieee80211_sta_connection_lost(sdata, bssid, |
2136 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
2083 | } | 2137 | } |
2084 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | 2138 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) |
2085 | run_again(ifmgd, ifmgd->probe_timeout); | 2139 | run_again(ifmgd, ifmgd->probe_timeout); |
@@ -2091,7 +2145,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2091 | sdata->name, | 2145 | sdata->name, |
2092 | bssid, probe_wait_ms); | 2146 | bssid, probe_wait_ms); |
2093 | #endif | 2147 | #endif |
2094 | ieee80211_sta_connection_lost(sdata, bssid); | 2148 | ieee80211_sta_connection_lost(sdata, bssid, |
2149 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
2095 | } else if (ifmgd->probe_send_count < max_tries) { | 2150 | } else if (ifmgd->probe_send_count < max_tries) { |
2096 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2151 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2097 | wiphy_debug(local->hw.wiphy, | 2152 | wiphy_debug(local->hw.wiphy, |
@@ -2113,7 +2168,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2113 | sdata->name, | 2168 | sdata->name, |
2114 | bssid, probe_wait_ms); | 2169 | bssid, probe_wait_ms); |
2115 | 2170 | ||
2116 | ieee80211_sta_connection_lost(sdata, bssid); | 2171 | ieee80211_sta_connection_lost(sdata, bssid, |
2172 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
2117 | } | 2173 | } |
2118 | } | 2174 | } |
2119 | 2175 | ||
@@ -2200,12 +2256,34 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
2200 | { | 2256 | { |
2201 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2257 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2202 | 2258 | ||
2259 | if (!ifmgd->associated) | ||
2260 | return; | ||
2261 | |||
2262 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { | ||
2263 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; | ||
2264 | mutex_lock(&ifmgd->mtx); | ||
2265 | if (ifmgd->associated) { | ||
2266 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2267 | wiphy_debug(sdata->local->hw.wiphy, | ||
2268 | "%s: driver requested disconnect after resume.\n", | ||
2269 | sdata->name); | ||
2270 | #endif | ||
2271 | ieee80211_sta_connection_lost(sdata, | ||
2272 | ifmgd->associated->bssid, | ||
2273 | WLAN_REASON_UNSPECIFIED); | ||
2274 | mutex_unlock(&ifmgd->mtx); | ||
2275 | return; | ||
2276 | } | ||
2277 | mutex_unlock(&ifmgd->mtx); | ||
2278 | } | ||
2279 | |||
2203 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | 2280 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) |
2204 | add_timer(&ifmgd->timer); | 2281 | add_timer(&ifmgd->timer); |
2205 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | 2282 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) |
2206 | add_timer(&ifmgd->chswitch_timer); | 2283 | add_timer(&ifmgd->chswitch_timer); |
2207 | ieee80211_sta_reset_beacon_monitor(sdata); | 2284 | ieee80211_sta_reset_beacon_monitor(sdata); |
2208 | ieee80211_restart_sta_timer(sdata); | 2285 | ieee80211_restart_sta_timer(sdata); |
2286 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); | ||
2209 | } | 2287 | } |
2210 | #endif | 2288 | #endif |
2211 | 2289 | ||
@@ -2271,14 +2349,16 @@ static enum work_done_result | |||
2271 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | 2349 | ieee80211_probe_auth_done(struct ieee80211_work *wk, |
2272 | struct sk_buff *skb) | 2350 | struct sk_buff *skb) |
2273 | { | 2351 | { |
2352 | struct ieee80211_local *local = wk->sdata->local; | ||
2353 | |||
2274 | if (!skb) { | 2354 | if (!skb) { |
2275 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | 2355 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); |
2276 | return WORK_DONE_DESTROY; | 2356 | goto destroy; |
2277 | } | 2357 | } |
2278 | 2358 | ||
2279 | if (wk->type == IEEE80211_WORK_AUTH) { | 2359 | if (wk->type == IEEE80211_WORK_AUTH) { |
2280 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | 2360 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); |
2281 | return WORK_DONE_DESTROY; | 2361 | goto destroy; |
2282 | } | 2362 | } |
2283 | 2363 | ||
2284 | mutex_lock(&wk->sdata->u.mgd.mtx); | 2364 | mutex_lock(&wk->sdata->u.mgd.mtx); |
@@ -2288,6 +2368,12 @@ ieee80211_probe_auth_done(struct ieee80211_work *wk, | |||
2288 | wk->type = IEEE80211_WORK_AUTH; | 2368 | wk->type = IEEE80211_WORK_AUTH; |
2289 | wk->probe_auth.tries = 0; | 2369 | wk->probe_auth.tries = 0; |
2290 | return WORK_DONE_REQUEUE; | 2370 | return WORK_DONE_REQUEUE; |
2371 | destroy: | ||
2372 | if (wk->probe_auth.synced) | ||
2373 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2374 | IEEE80211_TX_SYNC_AUTH); | ||
2375 | |||
2376 | return WORK_DONE_DESTROY; | ||
2291 | } | 2377 | } |
2292 | 2378 | ||
2293 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 2379 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
@@ -2360,6 +2446,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2360 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | 2446 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, |
2361 | struct sk_buff *skb) | 2447 | struct sk_buff *skb) |
2362 | { | 2448 | { |
2449 | struct ieee80211_local *local = wk->sdata->local; | ||
2363 | struct ieee80211_mgmt *mgmt; | 2450 | struct ieee80211_mgmt *mgmt; |
2364 | struct ieee80211_rx_status *rx_status; | 2451 | struct ieee80211_rx_status *rx_status; |
2365 | struct ieee802_11_elems elems; | 2452 | struct ieee802_11_elems elems; |
@@ -2367,7 +2454,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2367 | 2454 | ||
2368 | if (!skb) { | 2455 | if (!skb) { |
2369 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | 2456 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); |
2370 | return WORK_DONE_DESTROY; | 2457 | goto destroy; |
2371 | } | 2458 | } |
2372 | 2459 | ||
2373 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { | 2460 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { |
@@ -2387,6 +2474,10 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2387 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 2474 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
2388 | 2475 | ||
2389 | if (status == WLAN_STATUS_SUCCESS) { | 2476 | if (status == WLAN_STATUS_SUCCESS) { |
2477 | if (wk->assoc.synced) | ||
2478 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2479 | IEEE80211_TX_SYNC_ASSOC); | ||
2480 | |||
2390 | mutex_lock(&wk->sdata->u.mgd.mtx); | 2481 | mutex_lock(&wk->sdata->u.mgd.mtx); |
2391 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | 2482 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { |
2392 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 2483 | mutex_unlock(&wk->sdata->u.mgd.mtx); |
@@ -2400,6 +2491,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2400 | } | 2491 | } |
2401 | 2492 | ||
2402 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); | 2493 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); |
2494 | destroy: | ||
2495 | if (wk->assoc.synced) | ||
2496 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2497 | IEEE80211_TX_SYNC_ASSOC); | ||
2498 | |||
2403 | return WORK_DONE_DESTROY; | 2499 | return WORK_DONE_DESTROY; |
2404 | } | 2500 | } |
2405 | 2501 | ||
@@ -2652,3 +2748,10 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | |||
2652 | cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); | 2748 | cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); |
2653 | } | 2749 | } |
2654 | EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); | 2750 | EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); |
2751 | |||
2752 | unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif) | ||
2753 | { | ||
2754 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2755 | return sdata->dev->operstate; | ||
2756 | } | ||
2757 | EXPORT_SYMBOL(ieee80211_get_operstate); | ||