diff options
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r-- | net/mac80211/ht.c | 80 |
1 files changed, 73 insertions, 7 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index cdc58e61d921..bb677a73b7c9 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -34,9 +34,28 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
34 | 34 | ||
35 | ht_cap->ht_supported = true; | 35 | ht_cap->ht_supported = true; |
36 | 36 | ||
37 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap; | 37 | /* |
38 | ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS; | 38 | * The bits listed in this expression should be |
39 | ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; | 39 | * the same for the peer and us, if the station |
40 | * advertises more then we can't use those thus | ||
41 | * we mask them out. | ||
42 | */ | ||
43 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & | ||
44 | (sband->ht_cap.cap | | ||
45 | ~(IEEE80211_HT_CAP_LDPC_CODING | | ||
46 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
47 | IEEE80211_HT_CAP_GRN_FLD | | ||
48 | IEEE80211_HT_CAP_SGI_20 | | ||
49 | IEEE80211_HT_CAP_SGI_40 | | ||
50 | IEEE80211_HT_CAP_DSSSCCK40)); | ||
51 | /* | ||
52 | * The STBC bits are asymmetric -- if we don't have | ||
53 | * TX then mask out the peer's RX and vice versa. | ||
54 | */ | ||
55 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) | ||
56 | ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; | ||
57 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) | ||
58 | ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; | ||
40 | 59 | ||
41 | ampdu_info = ht_cap_ie->ampdu_params_info; | 60 | ampdu_info = ht_cap_ie->ampdu_params_info; |
42 | ht_cap->ampdu_factor = | 61 | ht_cap->ampdu_factor = |
@@ -106,7 +125,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
106 | 125 | ||
107 | if (!skb) { | 126 | if (!skb) { |
108 | printk(KERN_ERR "%s: failed to allocate buffer " | 127 | printk(KERN_ERR "%s: failed to allocate buffer " |
109 | "for delba frame\n", sdata->dev->name); | 128 | "for delba frame\n", sdata->name); |
110 | return; | 129 | return; |
111 | } | 130 | } |
112 | 131 | ||
@@ -114,10 +133,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
114 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 133 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
115 | memset(mgmt, 0, 24); | 134 | memset(mgmt, 0, 24); |
116 | memcpy(mgmt->da, da, ETH_ALEN); | 135 | memcpy(mgmt->da, da, ETH_ALEN); |
117 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 136 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
118 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 137 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
119 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 138 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
120 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 139 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
121 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | 140 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
122 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | 141 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
123 | 142 | ||
@@ -134,7 +153,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
134 | mgmt->u.action.u.delba.params = cpu_to_le16(params); | 153 | mgmt->u.action.u.delba.params = cpu_to_le16(params); |
135 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); | 154 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); |
136 | 155 | ||
137 | ieee80211_tx_skb(sdata, skb, 1); | 156 | ieee80211_tx_skb(sdata, skb); |
138 | } | 157 | } |
139 | 158 | ||
140 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 159 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
@@ -166,3 +185,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | |||
166 | spin_unlock_bh(&sta->lock); | 185 | spin_unlock_bh(&sta->lock); |
167 | } | 186 | } |
168 | } | 187 | } |
188 | |||
189 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | ||
190 | enum ieee80211_smps_mode smps, const u8 *da, | ||
191 | const u8 *bssid) | ||
192 | { | ||
193 | struct ieee80211_local *local = sdata->local; | ||
194 | struct sk_buff *skb; | ||
195 | struct ieee80211_mgmt *action_frame; | ||
196 | |||
197 | /* 27 = header + category + action + smps mode */ | ||
198 | skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom); | ||
199 | if (!skb) | ||
200 | return -ENOMEM; | ||
201 | |||
202 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
203 | action_frame = (void *)skb_put(skb, 27); | ||
204 | memcpy(action_frame->da, da, ETH_ALEN); | ||
205 | memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
206 | memcpy(action_frame->bssid, bssid, ETH_ALEN); | ||
207 | action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
208 | IEEE80211_STYPE_ACTION); | ||
209 | action_frame->u.action.category = WLAN_CATEGORY_HT; | ||
210 | action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; | ||
211 | switch (smps) { | ||
212 | case IEEE80211_SMPS_AUTOMATIC: | ||
213 | case IEEE80211_SMPS_NUM_MODES: | ||
214 | WARN_ON(1); | ||
215 | case IEEE80211_SMPS_OFF: | ||
216 | action_frame->u.action.u.ht_smps.smps_control = | ||
217 | WLAN_HT_SMPS_CONTROL_DISABLED; | ||
218 | break; | ||
219 | case IEEE80211_SMPS_STATIC: | ||
220 | action_frame->u.action.u.ht_smps.smps_control = | ||
221 | WLAN_HT_SMPS_CONTROL_STATIC; | ||
222 | break; | ||
223 | case IEEE80211_SMPS_DYNAMIC: | ||
224 | action_frame->u.action.u.ht_smps.smps_control = | ||
225 | WLAN_HT_SMPS_CONTROL_DYNAMIC; | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | /* we'll do more on status of this frame */ | ||
230 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
231 | ieee80211_tx_skb(sdata, skb); | ||
232 | |||
233 | return 0; | ||
234 | } | ||