aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/cfg.c108
-rw-r--r--net/mac80211/debugfs_netdev.c25
-rw-r--r--net/mac80211/ht.c41
-rw-r--r--net/mac80211/ieee80211_i.h15
-rw-r--r--net/mac80211/iface.c3
-rw-r--r--net/mac80211/mlme.c2
-rw-r--r--net/mac80211/sta_info.c72
-rw-r--r--net/mac80211/sta_info.h5
-rw-r--r--net/mac80211/status.c31
-rw-r--r--net/mac80211/util.c25
10 files changed, 289 insertions, 38 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)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index cafe614ef93d..04b5a14c8a05 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -224,12 +224,15 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
224 smps_mode == IEEE80211_SMPS_AUTOMATIC)) 224 smps_mode == IEEE80211_SMPS_AUTOMATIC))
225 return -EINVAL; 225 return -EINVAL;
226 226
227 /* supported only on managed interfaces for now */ 227 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
228 if (sdata->vif.type != NL80211_IFTYPE_STATION) 228 sdata->vif.type != NL80211_IFTYPE_AP)
229 return -EOPNOTSUPP; 229 return -EOPNOTSUPP;
230 230
231 sdata_lock(sdata); 231 sdata_lock(sdata);
232 err = __ieee80211_request_smps(sdata, smps_mode); 232 if (sdata->vif.type == NL80211_IFTYPE_STATION)
233 err = __ieee80211_request_smps_mgd(sdata, smps_mode);
234 else
235 err = __ieee80211_request_smps_ap(sdata, smps_mode);
233 sdata_unlock(sdata); 236 sdata_unlock(sdata);
234 237
235 return err; 238 return err;
@@ -245,12 +248,15 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
245static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, 248static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
246 char *buf, int buflen) 249 char *buf, int buflen)
247{ 250{
248 if (sdata->vif.type != NL80211_IFTYPE_STATION) 251 if (sdata->vif.type == NL80211_IFTYPE_STATION)
249 return -EOPNOTSUPP; 252 return snprintf(buf, buflen, "request: %s\nused: %s\n",
250 253 smps_modes[sdata->u.mgd.req_smps],
251 return snprintf(buf, buflen, "request: %s\nused: %s\n", 254 smps_modes[sdata->smps_mode]);
252 smps_modes[sdata->u.mgd.req_smps], 255 if (sdata->vif.type == NL80211_IFTYPE_AP)
253 smps_modes[sdata->smps_mode]); 256 return snprintf(buf, buflen, "request: %s\nused: %s\n",
257 smps_modes[sdata->u.ap.req_smps],
258 smps_modes[sdata->smps_mode]);
259 return -EINVAL;
254} 260}
255 261
256static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, 262static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
@@ -563,6 +569,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
563static void add_ap_files(struct ieee80211_sub_if_data *sdata) 569static void add_ap_files(struct ieee80211_sub_if_data *sdata)
564{ 570{
565 DEBUGFS_ADD(num_mcast_sta); 571 DEBUGFS_ADD(num_mcast_sta);
572 DEBUGFS_ADD_MODE(smps, 0600);
566 DEBUGFS_ADD(num_sta_ps); 573 DEBUGFS_ADD(num_sta_ps);
567 DEBUGFS_ADD(dtim_count); 574 DEBUGFS_ADD(dtim_count);
568 DEBUGFS_ADD(num_buffered_multicast); 575 DEBUGFS_ADD(num_buffered_multicast);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 529bf58bc145..9a8be8f69224 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -448,14 +448,25 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
448 return 0; 448 return 0;
449} 449}
450 450
451void ieee80211_request_smps_work(struct work_struct *work) 451void ieee80211_request_smps_mgd_work(struct work_struct *work)
452{ 452{
453 struct ieee80211_sub_if_data *sdata = 453 struct ieee80211_sub_if_data *sdata =
454 container_of(work, struct ieee80211_sub_if_data, 454 container_of(work, struct ieee80211_sub_if_data,
455 u.mgd.request_smps_work); 455 u.mgd.request_smps_work);
456 456
457 sdata_lock(sdata); 457 sdata_lock(sdata);
458 __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode); 458 __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.driver_smps_mode);
459 sdata_unlock(sdata);
460}
461
462void ieee80211_request_smps_ap_work(struct work_struct *work)
463{
464 struct ieee80211_sub_if_data *sdata =
465 container_of(work, struct ieee80211_sub_if_data,
466 u.ap.request_smps_work);
467
468 sdata_lock(sdata);
469 __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode);
459 sdata_unlock(sdata); 470 sdata_unlock(sdata);
460} 471}
461 472
@@ -464,19 +475,29 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
464{ 475{
465 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 476 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
466 477
467 if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) 478 if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION &&
479 vif->type != NL80211_IFTYPE_AP))
468 return; 480 return;
469 481
470 if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) 482 if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
471 smps_mode = IEEE80211_SMPS_AUTOMATIC; 483 smps_mode = IEEE80211_SMPS_AUTOMATIC;
472 484
473 if (sdata->u.mgd.driver_smps_mode == smps_mode) 485 if (vif->type == NL80211_IFTYPE_STATION) {
474 return; 486 if (sdata->u.mgd.driver_smps_mode == smps_mode)
475 487 return;
476 sdata->u.mgd.driver_smps_mode = smps_mode; 488 sdata->u.mgd.driver_smps_mode = smps_mode;
477 489 ieee80211_queue_work(&sdata->local->hw,
478 ieee80211_queue_work(&sdata->local->hw, 490 &sdata->u.mgd.request_smps_work);
479 &sdata->u.mgd.request_smps_work); 491 } else {
492 /* AUTOMATIC is meaningless in AP mode */
493 if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
494 return;
495 if (sdata->u.ap.driver_smps_mode == smps_mode)
496 return;
497 sdata->u.ap.driver_smps_mode = smps_mode;
498 ieee80211_queue_work(&sdata->local->hw,
499 &sdata->u.ap.request_smps_work);
500 }
480} 501}
481/* this might change ... don't want non-open drivers using it */ 502/* this might change ... don't want non-open drivers using it */
482EXPORT_SYMBOL_GPL(ieee80211_request_smps); 503EXPORT_SYMBOL_GPL(ieee80211_request_smps);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3a87c8976a32..8340d4939f1b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -262,6 +262,10 @@ struct ieee80211_if_ap {
262 262
263 struct ps_data ps; 263 struct ps_data ps;
264 atomic_t num_mcast_sta; /* number of stations receiving multicast */ 264 atomic_t num_mcast_sta; /* number of stations receiving multicast */
265 enum ieee80211_smps_mode req_smps, /* requested smps mode */
266 driver_smps_mode; /* smps mode request */
267
268 struct work_struct request_smps_work;
265}; 269};
266 270
267struct ieee80211_if_wds { 271struct ieee80211_if_wds {
@@ -1435,7 +1439,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
1435int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, 1439int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
1436 enum ieee80211_smps_mode smps, const u8 *da, 1440 enum ieee80211_smps_mode smps, const u8 *da,
1437 const u8 *bssid); 1441 const u8 *bssid);
1438void ieee80211_request_smps_work(struct work_struct *work); 1442void ieee80211_request_smps_ap_work(struct work_struct *work);
1443void ieee80211_request_smps_mgd_work(struct work_struct *work);
1444bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
1445 enum ieee80211_smps_mode smps_mode_new);
1439 1446
1440void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 1447void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
1441 u16 initiator, u16 reason, bool stop); 1448 u16 initiator, u16 reason, bool stop);
@@ -1653,8 +1660,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
1653u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, 1660u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
1654 struct ieee802_11_elems *elems, 1661 struct ieee802_11_elems *elems,
1655 enum ieee80211_band band, u32 *basic_rates); 1662 enum ieee80211_band band, u32 *basic_rates);
1656int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, 1663int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
1657 enum ieee80211_smps_mode smps_mode); 1664 enum ieee80211_smps_mode smps_mode);
1665int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
1666 enum ieee80211_smps_mode smps_mode);
1658void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); 1667void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
1659 1668
1660size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 1669size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e48f103b9ade..ff101ea1d9ae 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1293,7 +1293,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
1293 case NL80211_IFTYPE_AP: 1293 case NL80211_IFTYPE_AP:
1294 skb_queue_head_init(&sdata->u.ap.ps.bc_buf); 1294 skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
1295 INIT_LIST_HEAD(&sdata->u.ap.vlans); 1295 INIT_LIST_HEAD(&sdata->u.ap.vlans);
1296 INIT_WORK(&sdata->u.ap.request_smps_work,
1297 ieee80211_request_smps_ap_work);
1296 sdata->vif.bss_conf.bssid = sdata->vif.addr; 1298 sdata->vif.bss_conf.bssid = sdata->vif.addr;
1299 sdata->u.ap.req_smps = IEEE80211_SMPS_OFF;
1297 break; 1300 break;
1298 case NL80211_IFTYPE_P2P_CLIENT: 1301 case NL80211_IFTYPE_P2P_CLIENT:
1299 type = NL80211_IFTYPE_STATION; 1302 type = NL80211_IFTYPE_STATION;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 91cc8281e266..5cc1c274dd61 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3499,7 +3499,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
3499 ieee80211_beacon_connection_loss_work); 3499 ieee80211_beacon_connection_loss_work);
3500 INIT_WORK(&ifmgd->csa_connection_drop_work, 3500 INIT_WORK(&ifmgd->csa_connection_drop_work,
3501 ieee80211_csa_connection_drop_work); 3501 ieee80211_csa_connection_drop_work);
3502 INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); 3502 INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
3503 setup_timer(&ifmgd->timer, ieee80211_sta_timer, 3503 setup_timer(&ifmgd->timer, ieee80211_sta_timer,
3504 (unsigned long) sdata); 3504 (unsigned long) sdata);
3505 setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 3505 setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index aeb967a0aeed..1eb66e26e49d 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -385,6 +385,30 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
385 sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); 385 sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
386 386
387 sta->sta.smps_mode = IEEE80211_SMPS_OFF; 387 sta->sta.smps_mode = IEEE80211_SMPS_OFF;
388 if (sdata->vif.type == NL80211_IFTYPE_AP ||
389 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
390 struct ieee80211_supported_band *sband =
391 local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
392 u8 smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >>
393 IEEE80211_HT_CAP_SM_PS_SHIFT;
394 /*
395 * Assume that hostapd advertises our caps in the beacon and
396 * this is the known_smps_mode for a station that just assciated
397 */
398 switch (smps) {
399 case WLAN_HT_SMPS_CONTROL_DISABLED:
400 sta->known_smps_mode = IEEE80211_SMPS_OFF;
401 break;
402 case WLAN_HT_SMPS_CONTROL_STATIC:
403 sta->known_smps_mode = IEEE80211_SMPS_STATIC;
404 break;
405 case WLAN_HT_SMPS_CONTROL_DYNAMIC:
406 sta->known_smps_mode = IEEE80211_SMPS_DYNAMIC;
407 break;
408 default:
409 WARN_ON(1);
410 }
411 }
388 412
389 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); 413 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
390 414
@@ -1069,6 +1093,19 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
1069 1093
1070 ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); 1094 ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
1071 1095
1096 /* This station just woke up and isn't aware of our SMPS state */
1097 if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
1098 sdata->smps_mode) &&
1099 sta->known_smps_mode != sdata->bss->req_smps &&
1100 sta_info_tx_streams(sta) != 1) {
1101 ht_dbg(sdata,
1102 "%pM just woke up and MIMO capable - update SMPS\n",
1103 sta->sta.addr);
1104 ieee80211_send_smps_action(sdata, sdata->bss->req_smps,
1105 sta->sta.addr,
1106 sdata->vif.bss_conf.bssid);
1107 }
1108
1072 local->total_ps_buffered -= buffered; 1109 local->total_ps_buffered -= buffered;
1073 1110
1074 sta_info_recalc_tim(sta); 1111 sta_info_recalc_tim(sta);
@@ -1520,3 +1557,38 @@ int sta_info_move_state(struct sta_info *sta,
1520 1557
1521 return 0; 1558 return 0;
1522} 1559}
1560
1561u8 sta_info_tx_streams(struct sta_info *sta)
1562{
1563 struct ieee80211_sta_ht_cap *ht_cap = &sta->sta.ht_cap;
1564 u8 rx_streams;
1565
1566 if (!sta->sta.ht_cap.ht_supported)
1567 return 1;
1568
1569 if (sta->sta.vht_cap.vht_supported) {
1570 int i;
1571 u16 tx_mcs_map =
1572 le16_to_cpu(sta->sta.vht_cap.vht_mcs.tx_mcs_map);
1573
1574 for (i = 7; i >= 0; i--)
1575 if ((tx_mcs_map & (0x3 << (i * 2))) !=
1576 IEEE80211_VHT_MCS_NOT_SUPPORTED)
1577 return i + 1;
1578 }
1579
1580 if (ht_cap->mcs.rx_mask[3])
1581 rx_streams = 4;
1582 else if (ht_cap->mcs.rx_mask[2])
1583 rx_streams = 3;
1584 else if (ht_cap->mcs.rx_mask[1])
1585 rx_streams = 2;
1586 else
1587 rx_streams = 1;
1588
1589 if (!(ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_RX_DIFF))
1590 return rx_streams;
1591
1592 return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
1593 >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
1594}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 4208dbd5861f..3ef06a26b9cb 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -301,6 +301,8 @@ struct sta_ampdu_mlme {
301 * @chains: chains ever used for RX from this station 301 * @chains: chains ever used for RX from this station
302 * @chain_signal_last: last signal (per chain) 302 * @chain_signal_last: last signal (per chain)
303 * @chain_signal_avg: signal average (per chain) 303 * @chain_signal_avg: signal average (per chain)
304 * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
305 * AP only.
304 */ 306 */
305struct sta_info { 307struct sta_info {
306 /* General information, mostly static */ 308 /* General information, mostly static */
@@ -411,6 +413,8 @@ struct sta_info {
411 unsigned int lost_packets; 413 unsigned int lost_packets;
412 unsigned int beacon_loss_count; 414 unsigned int beacon_loss_count;
413 415
416 enum ieee80211_smps_mode known_smps_mode;
417
414 /* keep last! */ 418 /* keep last! */
415 struct ieee80211_sta sta; 419 struct ieee80211_sta sta;
416}; 420};
@@ -613,6 +617,7 @@ void sta_set_rate_info_rx(struct sta_info *sta,
613 struct rate_info *rinfo); 617 struct rate_info *rinfo);
614void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, 618void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
615 unsigned long exp_time); 619 unsigned long exp_time);
620u8 sta_info_tx_streams(struct sta_info *sta);
616 621
617void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); 622void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
618void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); 623void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 368837fe3b80..1ced74c73d2f 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -191,29 +191,36 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
191 if (ieee80211_is_action(mgmt->frame_control) && 191 if (ieee80211_is_action(mgmt->frame_control) &&
192 mgmt->u.action.category == WLAN_CATEGORY_HT && 192 mgmt->u.action.category == WLAN_CATEGORY_HT &&
193 mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS && 193 mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
194 sdata->vif.type == NL80211_IFTYPE_STATION &&
195 ieee80211_sdata_running(sdata)) { 194 ieee80211_sdata_running(sdata)) {
196 /* 195 enum ieee80211_smps_mode smps_mode;
197 * This update looks racy, but isn't -- if we come 196
198 * here we've definitely got a station that we're
199 * talking to, and on a managed interface that can
200 * only be the AP. And the only other place updating
201 * this variable in managed mode is before association.
202 */
203 switch (mgmt->u.action.u.ht_smps.smps_control) { 197 switch (mgmt->u.action.u.ht_smps.smps_control) {
204 case WLAN_HT_SMPS_CONTROL_DYNAMIC: 198 case WLAN_HT_SMPS_CONTROL_DYNAMIC:
205 sdata->smps_mode = IEEE80211_SMPS_DYNAMIC; 199 smps_mode = IEEE80211_SMPS_DYNAMIC;
206 break; 200 break;
207 case WLAN_HT_SMPS_CONTROL_STATIC: 201 case WLAN_HT_SMPS_CONTROL_STATIC:
208 sdata->smps_mode = IEEE80211_SMPS_STATIC; 202 smps_mode = IEEE80211_SMPS_STATIC;
209 break; 203 break;
210 case WLAN_HT_SMPS_CONTROL_DISABLED: 204 case WLAN_HT_SMPS_CONTROL_DISABLED:
211 default: /* shouldn't happen since we don't send that */ 205 default: /* shouldn't happen since we don't send that */
212 sdata->smps_mode = IEEE80211_SMPS_OFF; 206 smps_mode = IEEE80211_SMPS_OFF;
213 break; 207 break;
214 } 208 }
215 209
216 ieee80211_queue_work(&local->hw, &sdata->recalc_smps); 210 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
211 /*
212 * This update looks racy, but isn't -- if we come
213 * here we've definitely got a station that we're
214 * talking to, and on a managed interface that can
215 * only be the AP. And the only other place updating
216 * this variable in managed mode is before association.
217 */
218 sdata->smps_mode = smps_mode;
219 ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
220 } else if (sdata->vif.type == NL80211_IFTYPE_AP ||
221 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
222 sta->known_smps_mode = smps_mode;
223 }
217 } 224 }
218} 225}
219 226
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 550a6880625d..b763e4ccaf5e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2353,3 +2353,28 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
2353 2353
2354 return ret; 2354 return ret;
2355} 2355}
2356
2357/*
2358 * Returns true if smps_mode_new is strictly more restrictive than
2359 * smps_mode_old.
2360 */
2361bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
2362 enum ieee80211_smps_mode smps_mode_new)
2363{
2364 if (WARN_ON_ONCE(smps_mode_old == IEEE80211_SMPS_AUTOMATIC ||
2365 smps_mode_new == IEEE80211_SMPS_AUTOMATIC))
2366 return false;
2367
2368 switch (smps_mode_old) {
2369 case IEEE80211_SMPS_STATIC:
2370 return false;
2371 case IEEE80211_SMPS_DYNAMIC:
2372 return smps_mode_new == IEEE80211_SMPS_STATIC;
2373 case IEEE80211_SMPS_OFF:
2374 return smps_mode_new != IEEE80211_SMPS_OFF;
2375 default:
2376 WARN_ON(1);
2377 }
2378
2379 return false;
2380}