summaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index b4608f11a40..0c0850d37dd 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -134,6 +134,40 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
dev_kfree_skb(skb);
}
+static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *mgmt = (void *) skb->data;
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+ if (ieee80211_is_action(mgmt->frame_control) &&
+ sdata->vif.type == NL80211_IFTYPE_STATION &&
+ mgmt->u.action.category == WLAN_CATEGORY_HT &&
+ mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
+ /*
+ * This update looks racy, but isn't -- if we come
+ * here we've definitely got a station that we're
+ * talking to, and on a managed interface that can
+ * only be the AP. And the only other place updating
+ * this variable is before we're associated.
+ */
+ switch (mgmt->u.action.u.ht_smps.smps_control) {
+ case WLAN_HT_SMPS_CONTROL_DYNAMIC:
+ sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
+ break;
+ case WLAN_HT_SMPS_CONTROL_STATIC:
+ sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
+ break;
+ case WLAN_HT_SMPS_CONTROL_DISABLED:
+ default: /* shouldn't happen since we don't send that */
+ sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
+ break;
+ }
+
+ ieee80211_queue_work(&local->hw, &local->recalc_smps);
+ }
+}
+
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct sk_buff *skb2;
@@ -210,6 +244,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
rate_control_tx_status(local, sband, sta, skb);
if (ieee80211_vif_is_mesh(&sta->sdata->vif))
ieee80211s_update_metric(local, sta, skb);
+
+ if (!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+ (info->flags & IEEE80211_TX_STAT_ACK))
+ ieee80211_frame_acked(sta, skb);
}
rcu_read_unlock();