aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c72
1 files changed, 72 insertions, 0 deletions
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}