aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-10-01 09:45:43 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-28 10:05:11 -0400
commit687da132234feb70748df04a007bc1820f392254 (patch)
tree6255afe03b39518c2f83251fd0dd0afed647dd44 /net/mac80211/status.c
parent7ec7c4a9a686c608315739ab6a2b0527a240883c (diff)
mac80211: implement SMPS for AP
When the driver requests to move to STATIC or DYNAMIC SMPS, we send an action frame to each associated station and reconfigure the channel context / driver. Of course, non-MIMO stations are ignored. The beacon isn't updated. The association response will include the original capabilities. Stations that associate while in non-OFF SMPS mode will get an action frame right after association to inform them about our current state. Note that we wait until the end of the EAPOL. Sending an action frame before the EAPOL is finished can be an issue for a few clients. Clients aren't likely to send EAPOL frames in MIMO anyway. When the SMPS configuration gets more permissive (e.g. STATIC -> OFF), we don't wake up stations that are asleep We remember that they don't know about the change and send the action frame when they wake up. When the SMPS configuration gets more restrictive (e.g. OFF -> STATIC), we set the TIM bit for every sleeping STA. uAPSD stations might send MIMO until they poll the action frame, but this is for a short period of time. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> [fix vht streams loop, initialisation] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c31
1 files changed, 19 insertions, 12 deletions
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