summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h5
-rw-r--r--net/mac80211/rx.c58
2 files changed, 62 insertions, 1 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5b5c8a7e26d7..2a7523edd9b5 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3502,9 +3502,12 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
*
* @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have
* changed, rate control algorithm can update its internal state if needed.
+ * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed, the rate
+ * control algorithm needs to adjust accordingly.
*/
enum rate_control_changed {
- IEEE80211_RC_HT_CHANGED = BIT(0)
+ IEEE80211_RC_HT_CHANGED = BIT(0),
+ IEEE80211_RC_SMPS_CHANGED = BIT(1),
};
/**
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2be5b7d69ad7..57832eb44f3e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -28,6 +28,7 @@
#include "wpa.h"
#include "tkip.h"
#include "wme.h"
+#include "rate.h"
/*
* monitor mode reception
@@ -2233,6 +2234,63 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
switch (mgmt->u.action.category) {
+ case WLAN_CATEGORY_HT:
+ /* reject HT action frames from stations not supporting HT */
+ if (!rx->sta->sta.ht_cap.ht_supported)
+ goto invalid;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ break;
+
+ /* verify action & smps_control are present */
+ if (len < IEEE80211_MIN_ACTION_SIZE + 2)
+ goto invalid;
+
+ switch (mgmt->u.action.u.ht_smps.action) {
+ case WLAN_HT_ACTION_SMPS: {
+ struct ieee80211_supported_band *sband;
+ u8 smps;
+
+ /* convert to HT capability */
+ switch (mgmt->u.action.u.ht_smps.smps_control) {
+ case WLAN_HT_SMPS_CONTROL_DISABLED:
+ smps = WLAN_HT_CAP_SM_PS_DISABLED;
+ break;
+ case WLAN_HT_SMPS_CONTROL_STATIC:
+ smps = WLAN_HT_CAP_SM_PS_STATIC;
+ break;
+ case WLAN_HT_SMPS_CONTROL_DYNAMIC:
+ smps = WLAN_HT_CAP_SM_PS_DYNAMIC;
+ break;
+ default:
+ goto invalid;
+ }
+ smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+ /* if no change do nothing */
+ if ((rx->sta->sta.ht_cap.cap &
+ IEEE80211_HT_CAP_SM_PS) == smps)
+ goto handled;
+
+ rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
+ rx->sta->sta.ht_cap.cap |= smps;
+
+ sband = rx->local->hw.wiphy->bands[status->band];
+
+ rate_control_rate_update(local, sband, rx->sta,
+ IEEE80211_RC_SMPS_CHANGED,
+ local->_oper_channel_type);
+ goto handled;
+ }
+ default:
+ goto invalid;
+ }
+
+ break;
case WLAN_CATEGORY_BACK:
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&