diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 108 |
1 files changed, 105 insertions, 3 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ac28af74a414..4a3d5a414a25 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1059,6 +1059,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1059 | /* abort any running channel switch */ | 1059 | /* abort any running channel switch */ |
1060 | sdata->vif.csa_active = false; | 1060 | sdata->vif.csa_active = false; |
1061 | cancel_work_sync(&sdata->csa_finalize_work); | 1061 | cancel_work_sync(&sdata->csa_finalize_work); |
1062 | cancel_work_sync(&sdata->u.ap.request_smps_work); | ||
1062 | 1063 | ||
1063 | /* turn off carrier for this interface and dependent VLANs */ | 1064 | /* turn off carrier for this interface and dependent VLANs */ |
1064 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1065 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
@@ -1553,6 +1554,20 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1553 | 1554 | ||
1554 | mutex_unlock(&local->sta_mtx); | 1555 | mutex_unlock(&local->sta_mtx); |
1555 | 1556 | ||
1557 | if ((sdata->vif.type == NL80211_IFTYPE_AP || | ||
1558 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && | ||
1559 | sta->known_smps_mode != sta->sdata->bss->req_smps && | ||
1560 | test_sta_flag(sta, WLAN_STA_AUTHORIZED) && | ||
1561 | sta_info_tx_streams(sta) != 1) { | ||
1562 | ht_dbg(sta->sdata, | ||
1563 | "%pM just authorized and MIMO capable - update SMPS\n", | ||
1564 | sta->sta.addr); | ||
1565 | ieee80211_send_smps_action(sta->sdata, | ||
1566 | sta->sdata->bss->req_smps, | ||
1567 | sta->sta.addr, | ||
1568 | sta->sdata->vif.bss_conf.bssid); | ||
1569 | } | ||
1570 | |||
1556 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1571 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
1557 | params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | 1572 | params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { |
1558 | ieee80211_recalc_ps(local, -1); | 1573 | ieee80211_recalc_ps(local, -1); |
@@ -2337,8 +2352,92 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy, | |||
2337 | } | 2352 | } |
2338 | #endif | 2353 | #endif |
2339 | 2354 | ||
2340 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 2355 | int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, |
2341 | enum ieee80211_smps_mode smps_mode) | 2356 | enum ieee80211_smps_mode smps_mode) |
2357 | { | ||
2358 | struct sta_info *sta; | ||
2359 | enum ieee80211_smps_mode old_req; | ||
2360 | int i; | ||
2361 | |||
2362 | if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
2363 | return -EINVAL; | ||
2364 | |||
2365 | if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) | ||
2366 | return 0; | ||
2367 | |||
2368 | old_req = sdata->u.ap.req_smps; | ||
2369 | sdata->u.ap.req_smps = smps_mode; | ||
2370 | |||
2371 | /* AUTOMATIC doesn't mean much for AP - don't allow it */ | ||
2372 | if (old_req == smps_mode || | ||
2373 | smps_mode == IEEE80211_SMPS_AUTOMATIC) | ||
2374 | return 0; | ||
2375 | |||
2376 | /* If no associated stations, there's no need to do anything */ | ||
2377 | if (!atomic_read(&sdata->u.ap.num_mcast_sta)) { | ||
2378 | sdata->smps_mode = smps_mode; | ||
2379 | ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps); | ||
2380 | return 0; | ||
2381 | } | ||
2382 | |||
2383 | ht_dbg(sdata, | ||
2384 | "SMSP %d requested in AP mode, sending Action frame to %d stations\n", | ||
2385 | smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta)); | ||
2386 | |||
2387 | mutex_lock(&sdata->local->sta_mtx); | ||
2388 | for (i = 0; i < STA_HASH_SIZE; i++) { | ||
2389 | for (sta = rcu_dereference_protected(sdata->local->sta_hash[i], | ||
2390 | lockdep_is_held(&sdata->local->sta_mtx)); | ||
2391 | sta; | ||
2392 | sta = rcu_dereference_protected(sta->hnext, | ||
2393 | lockdep_is_held(&sdata->local->sta_mtx))) { | ||
2394 | /* | ||
2395 | * Only stations associated to our AP and | ||
2396 | * associated VLANs | ||
2397 | */ | ||
2398 | if (sta->sdata->bss != &sdata->u.ap) | ||
2399 | continue; | ||
2400 | |||
2401 | /* This station doesn't support MIMO - skip it */ | ||
2402 | if (sta_info_tx_streams(sta) == 1) | ||
2403 | continue; | ||
2404 | |||
2405 | /* | ||
2406 | * Don't wake up a STA just to send the action frame | ||
2407 | * unless we are getting more restrictive. | ||
2408 | */ | ||
2409 | if (test_sta_flag(sta, WLAN_STA_PS_STA) && | ||
2410 | !ieee80211_smps_is_restrictive(sta->known_smps_mode, | ||
2411 | smps_mode)) { | ||
2412 | ht_dbg(sdata, | ||
2413 | "Won't send SMPS to sleeping STA %pM\n", | ||
2414 | sta->sta.addr); | ||
2415 | continue; | ||
2416 | } | ||
2417 | |||
2418 | /* | ||
2419 | * If the STA is not authorized, wait until it gets | ||
2420 | * authorized and the action frame will be sent then. | ||
2421 | */ | ||
2422 | if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
2423 | continue; | ||
2424 | |||
2425 | ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr); | ||
2426 | ieee80211_send_smps_action(sdata, smps_mode, | ||
2427 | sta->sta.addr, | ||
2428 | sdata->vif.bss_conf.bssid); | ||
2429 | } | ||
2430 | } | ||
2431 | mutex_unlock(&sdata->local->sta_mtx); | ||
2432 | |||
2433 | sdata->smps_mode = smps_mode; | ||
2434 | ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps); | ||
2435 | |||
2436 | return 0; | ||
2437 | } | ||
2438 | |||
2439 | int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, | ||
2440 | enum ieee80211_smps_mode smps_mode) | ||
2342 | { | 2441 | { |
2343 | const u8 *ap; | 2442 | const u8 *ap; |
2344 | enum ieee80211_smps_mode old_req; | 2443 | enum ieee80211_smps_mode old_req; |
@@ -2346,6 +2445,9 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
2346 | 2445 | ||
2347 | lockdep_assert_held(&sdata->wdev.mtx); | 2446 | lockdep_assert_held(&sdata->wdev.mtx); |
2348 | 2447 | ||
2448 | if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
2449 | return -EINVAL; | ||
2450 | |||
2349 | old_req = sdata->u.mgd.req_smps; | 2451 | old_req = sdata->u.mgd.req_smps; |
2350 | sdata->u.mgd.req_smps = smps_mode; | 2452 | sdata->u.mgd.req_smps = smps_mode; |
2351 | 2453 | ||
@@ -2402,7 +2504,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
2402 | 2504 | ||
2403 | /* no change, but if automatic follow powersave */ | 2505 | /* no change, but if automatic follow powersave */ |
2404 | sdata_lock(sdata); | 2506 | sdata_lock(sdata); |
2405 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); | 2507 | __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.req_smps); |
2406 | sdata_unlock(sdata); | 2508 | sdata_unlock(sdata); |
2407 | 2509 | ||
2408 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 2510 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |