aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-12-01 07:37:02 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-22 13:31:16 -0500
commit0f78231bffb868a30e8533aace142213266bb811 (patch)
tree317f65dc6d89e9a89ad83f94fadd780dd1e0ca83 /net/mac80211/ht.c
parent18974b5b0b5e758d416c550553b143e5c8038281 (diff)
mac80211: enable spatial multiplexing powersave
Enable spatial multiplexing in mac80211 by telling the driver what to do and, where necessary, sending action frames to the AP to update the requested SMPS mode. Also includes a trivial implementation for hwsim that just logs the requested mode. For now, the userspace interface is in debugfs only, and let you toggle the requested mode at any time. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 45ebd062a2fb..63b8f86b7f16 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -166,3 +166,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
166 spin_unlock_bh(&sta->lock); 166 spin_unlock_bh(&sta->lock);
167 } 167 }
168} 168}
169
170int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
171 enum ieee80211_smps_mode smps, const u8 *da,
172 const u8 *bssid)
173{
174 struct ieee80211_local *local = sdata->local;
175 struct sk_buff *skb;
176 struct ieee80211_mgmt *action_frame;
177
178 /* 27 = header + category + action + smps mode */
179 skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
180 if (!skb)
181 return -ENOMEM;
182
183 skb_reserve(skb, local->hw.extra_tx_headroom);
184 action_frame = (void *)skb_put(skb, 27);
185 memcpy(action_frame->da, da, ETH_ALEN);
186 memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
187 memcpy(action_frame->bssid, bssid, ETH_ALEN);
188 action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
189 IEEE80211_STYPE_ACTION);
190 action_frame->u.action.category = WLAN_CATEGORY_HT;
191 action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
192 switch (smps) {
193 case IEEE80211_SMPS_AUTOMATIC:
194 case IEEE80211_SMPS_NUM_MODES:
195 WARN_ON(1);
196 case IEEE80211_SMPS_OFF:
197 action_frame->u.action.u.ht_smps.smps_control =
198 WLAN_HT_SMPS_CONTROL_DISABLED;
199 break;
200 case IEEE80211_SMPS_STATIC:
201 action_frame->u.action.u.ht_smps.smps_control =
202 WLAN_HT_SMPS_CONTROL_STATIC;
203 break;
204 case IEEE80211_SMPS_DYNAMIC:
205 action_frame->u.action.u.ht_smps.smps_control =
206 WLAN_HT_SMPS_CONTROL_DYNAMIC;
207 break;
208 }
209
210 /* we'll do more on status of this frame */
211 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
212 ieee80211_tx_skb(sdata, skb);
213
214 return 0;
215}