aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-10-01 09:45:43 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-28 10:05:11 -0400
commit687da132234feb70748df04a007bc1820f392254 (patch)
tree6255afe03b39518c2f83251fd0dd0afed647dd44 /net/mac80211/cfg.c
parent7ec7c4a9a686c608315739ab6a2b0527a240883c (diff)
mac80211: implement SMPS for AP
When the driver requests to move to STATIC or DYNAMIC SMPS, we send an action frame to each associated station and reconfigure the channel context / driver. Of course, non-MIMO stations are ignored. The beacon isn't updated. The association response will include the original capabilities. Stations that associate while in non-OFF SMPS mode will get an action frame right after association to inform them about our current state. Note that we wait until the end of the EAPOL. Sending an action frame before the EAPOL is finished can be an issue for a few clients. Clients aren't likely to send EAPOL frames in MIMO anyway. When the SMPS configuration gets more permissive (e.g. STATIC -> OFF), we don't wake up stations that are asleep We remember that they don't know about the change and send the action frame when they wake up. When the SMPS configuration gets more restrictive (e.g. OFF -> STATIC), we set the TIM bit for every sleeping STA. uAPSD stations might send MIMO until they poll the action frame, but this is for a short period of time. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> [fix vht streams loop, initialisation] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c108
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
2340int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, 2355int __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
2439int __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)