aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index d78f36c64c7b..0c0850d37dda 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,
134 dev_kfree_skb(skb); 134 dev_kfree_skb(skb);
135} 135}
136 136
137static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
138{
139 struct ieee80211_mgmt *mgmt = (void *) skb->data;
140 struct ieee80211_local *local = sta->local;
141 struct ieee80211_sub_if_data *sdata = sta->sdata;
142
143 if (ieee80211_is_action(mgmt->frame_control) &&
144 sdata->vif.type == NL80211_IFTYPE_STATION &&
145 mgmt->u.action.category == WLAN_CATEGORY_HT &&
146 mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
147 /*
148 * This update looks racy, but isn't -- if we come
149 * here we've definitely got a station that we're
150 * talking to, and on a managed interface that can
151 * only be the AP. And the only other place updating
152 * this variable is before we're associated.
153 */
154 switch (mgmt->u.action.u.ht_smps.smps_control) {
155 case WLAN_HT_SMPS_CONTROL_DYNAMIC:
156 sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
157 break;
158 case WLAN_HT_SMPS_CONTROL_STATIC:
159 sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
160 break;
161 case WLAN_HT_SMPS_CONTROL_DISABLED:
162 default: /* shouldn't happen since we don't send that */
163 sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
164 break;
165 }
166
167 ieee80211_queue_work(&local->hw, &local->recalc_smps);
168 }
169}
170
137void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) 171void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
138{ 172{
139 struct sk_buff *skb2; 173 struct sk_buff *skb2;
@@ -146,7 +180,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
146 struct ieee80211_tx_status_rtap_hdr *rthdr; 180 struct ieee80211_tx_status_rtap_hdr *rthdr;
147 struct ieee80211_sub_if_data *sdata; 181 struct ieee80211_sub_if_data *sdata;
148 struct net_device *prev_dev = NULL; 182 struct net_device *prev_dev = NULL;
149 struct sta_info *sta; 183 struct sta_info *sta, *tmp;
150 int retry_count = -1, i; 184 int retry_count = -1, i;
151 bool injected; 185 bool injected;
152 186
@@ -166,9 +200,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
166 200
167 sband = local->hw.wiphy->bands[info->band]; 201 sband = local->hw.wiphy->bands[info->band];
168 202
169 sta = sta_info_get(local, hdr->addr1); 203 for_each_sta_info(local, hdr->addr1, sta, tmp) {
204 /* skip wrong virtual interface */
205 if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
206 continue;
170 207
171 if (sta) {
172 if (!(info->flags & IEEE80211_TX_STAT_ACK) && 208 if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
173 test_sta_flags(sta, WLAN_STA_PS_STA)) { 209 test_sta_flags(sta, WLAN_STA_PS_STA)) {
174 /* 210 /*
@@ -208,6 +244,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
208 rate_control_tx_status(local, sband, sta, skb); 244 rate_control_tx_status(local, sband, sta, skb);
209 if (ieee80211_vif_is_mesh(&sta->sdata->vif)) 245 if (ieee80211_vif_is_mesh(&sta->sdata->vif))
210 ieee80211s_update_metric(local, sta, skb); 246 ieee80211s_update_metric(local, sta, skb);
247
248 if (!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
249 (info->flags & IEEE80211_TX_STAT_ACK))
250 ieee80211_frame_acked(sta, skb);
211 } 251 }
212 252
213 rcu_read_unlock(); 253 rcu_read_unlock();