diff options
-rw-r--r-- | net/mac80211/mlme.c | 7 | ||||
-rw-r--r-- | net/mac80211/work.c | 239 |
2 files changed, 137 insertions, 109 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7c1f91bcc834..ea434b5a779e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1884,6 +1884,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1884 | ifmgd->ap_smps = ifmgd->req_smps; | 1884 | ifmgd->ap_smps = ifmgd->req_smps; |
1885 | 1885 | ||
1886 | wk->assoc.smps = ifmgd->ap_smps; | 1886 | wk->assoc.smps = ifmgd->ap_smps; |
1887 | /* | ||
1888 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. | ||
1889 | * We still associate in non-HT mode (11a/b/g) if any one of these | ||
1890 | * ciphers is configured as pairwise. | ||
1891 | * We can set this to true for non-11n hardware, that'll be checked | ||
1892 | * separately along with the peer capabilities. | ||
1893 | */ | ||
1887 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); | 1894 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); |
1888 | wk->assoc.capability = req->bss->capability; | 1895 | wk->assoc.capability = req->bss->capability; |
1889 | wk->assoc.wmm_used = wk->assoc.bss->wmm_used; | 1896 | wk->assoc.wmm_used = wk->assoc.bss->wmm_used; |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 874345918e83..c03c22d5bca3 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -100,6 +100,102 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | |||
100 | 100 | ||
101 | /* frame sending functions */ | 101 | /* frame sending functions */ |
102 | 102 | ||
103 | static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | ||
104 | struct ieee80211_supported_band *sband, | ||
105 | struct ieee80211_channel *channel, | ||
106 | enum ieee80211_smps_mode smps) | ||
107 | { | ||
108 | struct ieee80211_ht_info *ht_info; | ||
109 | u8 *pos; | ||
110 | u32 flags = channel->flags; | ||
111 | u16 cap = sband->ht_cap.cap; | ||
112 | __le16 tmp; | ||
113 | |||
114 | if (!sband->ht_cap.ht_supported) | ||
115 | return; | ||
116 | |||
117 | if (!ht_info_ie) | ||
118 | return; | ||
119 | |||
120 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | ||
121 | return; | ||
122 | |||
123 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | ||
124 | |||
125 | /* determine capability flags */ | ||
126 | |||
127 | if (ieee80211_disable_40mhz_24ghz && | ||
128 | sband->band == IEEE80211_BAND_2GHZ) { | ||
129 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
130 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
131 | } | ||
132 | |||
133 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
134 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
135 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
136 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
137 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
138 | } | ||
139 | break; | ||
140 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
141 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
142 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
143 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
144 | } | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | /* set SM PS mode properly */ | ||
149 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
150 | switch (smps) { | ||
151 | case IEEE80211_SMPS_AUTOMATIC: | ||
152 | case IEEE80211_SMPS_NUM_MODES: | ||
153 | WARN_ON(1); | ||
154 | case IEEE80211_SMPS_OFF: | ||
155 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
156 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
157 | break; | ||
158 | case IEEE80211_SMPS_STATIC: | ||
159 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
160 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
161 | break; | ||
162 | case IEEE80211_SMPS_DYNAMIC: | ||
163 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
164 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | /* reserve and fill IE */ | ||
169 | |||
170 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
171 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
172 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
173 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
174 | |||
175 | /* capability flags */ | ||
176 | tmp = cpu_to_le16(cap); | ||
177 | memcpy(pos, &tmp, sizeof(u16)); | ||
178 | pos += sizeof(u16); | ||
179 | |||
180 | /* AMPDU parameters */ | ||
181 | *pos++ = sband->ht_cap.ampdu_factor | | ||
182 | (sband->ht_cap.ampdu_density << | ||
183 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
184 | |||
185 | /* MCS set */ | ||
186 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
187 | pos += sizeof(sband->ht_cap.mcs); | ||
188 | |||
189 | /* extended capabilities */ | ||
190 | pos += sizeof(__le16); | ||
191 | |||
192 | /* BF capabilities */ | ||
193 | pos += sizeof(__le32); | ||
194 | |||
195 | /* antenna selection */ | ||
196 | pos += sizeof(u8); | ||
197 | } | ||
198 | |||
103 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | 199 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
104 | struct ieee80211_work *wk) | 200 | struct ieee80211_work *wk) |
105 | { | 201 | { |
@@ -107,15 +203,34 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
107 | struct sk_buff *skb; | 203 | struct sk_buff *skb; |
108 | struct ieee80211_mgmt *mgmt; | 204 | struct ieee80211_mgmt *mgmt; |
109 | u8 *pos; | 205 | u8 *pos; |
110 | const u8 *ies, *ht_ie; | 206 | const u8 *ies; |
111 | int i, len, count, rates_len, supp_rates_len; | 207 | int i, len, count, rates_len, supp_rates_len; |
112 | u16 capab; | 208 | u16 capab; |
113 | struct ieee80211_supported_band *sband; | 209 | struct ieee80211_supported_band *sband; |
114 | u32 rates = 0; | 210 | u32 rates = 0; |
115 | 211 | ||
116 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 212 | sband = local->hw.wiphy->bands[wk->chan->band]; |
117 | sizeof(*mgmt) + 200 + wk->ie_len + | 213 | |
118 | wk->assoc.ssid_len); | 214 | /* |
215 | * Get all rates supported by the device and the AP as | ||
216 | * some APs don't like getting a superset of their rates | ||
217 | * in the association request (e.g. D-Link DAP 1353 in | ||
218 | * b-only mode)... | ||
219 | */ | ||
220 | rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, | ||
221 | wk->assoc.supp_rates_len, | ||
222 | sband, &rates); | ||
223 | |||
224 | skb = alloc_skb(local->hw.extra_tx_headroom + | ||
225 | sizeof(*mgmt) + /* bit too much but doesn't matter */ | ||
226 | 2 + wk->assoc.ssid_len + /* SSID */ | ||
227 | 4 + rates_len + /* (extended) rates */ | ||
228 | 4 + /* power capability */ | ||
229 | 2 + 2 * sband->n_channels + /* supported channels */ | ||
230 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||
231 | wk->ie_len + /* extra IEs */ | ||
232 | 9, /* WMM */ | ||
233 | GFP_KERNEL); | ||
119 | if (!skb) { | 234 | if (!skb) { |
120 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 235 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
121 | "frame\n", sdata->name); | 236 | "frame\n", sdata->name); |
@@ -123,8 +238,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
123 | } | 238 | } |
124 | skb_reserve(skb, local->hw.extra_tx_headroom); | 239 | skb_reserve(skb, local->hw.extra_tx_headroom); |
125 | 240 | ||
126 | sband = local->hw.wiphy->bands[wk->chan->band]; | ||
127 | |||
128 | capab = WLAN_CAPABILITY_ESS; | 241 | capab = WLAN_CAPABILITY_ESS; |
129 | 242 | ||
130 | if (sband->band == IEEE80211_BAND_2GHZ) { | 243 | if (sband->band == IEEE80211_BAND_2GHZ) { |
@@ -137,16 +250,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
137 | if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) | 250 | if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) |
138 | capab |= WLAN_CAPABILITY_PRIVACY; | 251 | capab |= WLAN_CAPABILITY_PRIVACY; |
139 | 252 | ||
140 | /* | ||
141 | * Get all rates supported by the device and the AP as | ||
142 | * some APs don't like getting a superset of their rates | ||
143 | * in the association request (e.g. D-Link DAP 1353 in | ||
144 | * b-only mode)... | ||
145 | */ | ||
146 | rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, | ||
147 | wk->assoc.supp_rates_len, | ||
148 | sband, &rates); | ||
149 | |||
150 | if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | 253 | if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && |
151 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | 254 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) |
152 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | 255 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; |
@@ -220,7 +323,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
220 | *pos++ = WLAN_EID_PWR_CAPABILITY; | 323 | *pos++ = WLAN_EID_PWR_CAPABILITY; |
221 | *pos++ = 2; | 324 | *pos++ = 2; |
222 | *pos++ = 0; /* min tx power */ | 325 | *pos++ = 0; /* min tx power */ |
223 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | 326 | *pos++ = wk->chan->max_power; /* max tx power */ |
224 | 327 | ||
225 | /* 2. supported channels */ | 328 | /* 2. supported channels */ |
226 | /* TODO: get this in reg domain format */ | 329 | /* TODO: get this in reg domain format */ |
@@ -234,11 +337,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
234 | } | 337 | } |
235 | } | 338 | } |
236 | 339 | ||
340 | /* | ||
341 | * XXX: These IEs could contain (vendor-specified) | ||
342 | * IEs that belong after HT -- the buffer may | ||
343 | * need to be split up. | ||
344 | */ | ||
237 | if (wk->ie_len && wk->ie) { | 345 | if (wk->ie_len && wk->ie) { |
238 | pos = skb_put(skb, wk->ie_len); | 346 | pos = skb_put(skb, wk->ie_len); |
239 | memcpy(pos, wk->ie, wk->ie_len); | 347 | memcpy(pos, wk->ie, wk->ie_len); |
240 | } | 348 | } |
241 | 349 | ||
350 | if (wk->assoc.use_11n && wk->assoc.wmm_used && | ||
351 | local->hw.queues >= 4) | ||
352 | ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, | ||
353 | sband, wk->chan, wk->assoc.smps); | ||
354 | |||
242 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { | 355 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { |
243 | pos = skb_put(skb, 9); | 356 | pos = skb_put(skb, 9); |
244 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 357 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
@@ -252,98 +365,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
252 | *pos++ = 0; | 365 | *pos++ = 0; |
253 | } | 366 | } |
254 | 367 | ||
255 | /* wmm support is a must to HT */ | ||
256 | /* | ||
257 | * IEEE802.11n does not allow TKIP/WEP as pairwise | ||
258 | * ciphers in HT mode. We still associate in non-ht | ||
259 | * mode (11a/b/g) if any one of these ciphers is | ||
260 | * configured as pairwise. | ||
261 | */ | ||
262 | if (wk->assoc.use_11n && wk->assoc.wmm_used && | ||
263 | (local->hw.queues >= 4) && | ||
264 | sband->ht_cap.ht_supported && | ||
265 | (ht_ie = wk->assoc.ht_information_ie) && | ||
266 | ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { | ||
267 | struct ieee80211_ht_info *ht_info = | ||
268 | (struct ieee80211_ht_info *)(ht_ie + 2); | ||
269 | u16 cap = sband->ht_cap.cap; | ||
270 | __le16 tmp; | ||
271 | u32 flags = local->hw.conf.channel->flags; | ||
272 | |||
273 | /* determine capability flags */ | ||
274 | |||
275 | if (ieee80211_disable_40mhz_24ghz && | ||
276 | sband->band == IEEE80211_BAND_2GHZ) { | ||
277 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
278 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
279 | } | ||
280 | |||
281 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
282 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
283 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
284 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
285 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
286 | } | ||
287 | break; | ||
288 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
289 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
290 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
291 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
292 | } | ||
293 | break; | ||
294 | } | ||
295 | |||
296 | /* set SM PS mode properly */ | ||
297 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
298 | switch (wk->assoc.smps) { | ||
299 | case IEEE80211_SMPS_AUTOMATIC: | ||
300 | case IEEE80211_SMPS_NUM_MODES: | ||
301 | WARN_ON(1); | ||
302 | case IEEE80211_SMPS_OFF: | ||
303 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
304 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
305 | break; | ||
306 | case IEEE80211_SMPS_STATIC: | ||
307 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
308 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
309 | break; | ||
310 | case IEEE80211_SMPS_DYNAMIC: | ||
311 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
312 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | /* reserve and fill IE */ | ||
317 | |||
318 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
319 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
320 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
321 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
322 | |||
323 | /* capability flags */ | ||
324 | tmp = cpu_to_le16(cap); | ||
325 | memcpy(pos, &tmp, sizeof(u16)); | ||
326 | pos += sizeof(u16); | ||
327 | |||
328 | /* AMPDU parameters */ | ||
329 | *pos++ = sband->ht_cap.ampdu_factor | | ||
330 | (sband->ht_cap.ampdu_density << | ||
331 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
332 | |||
333 | /* MCS set */ | ||
334 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
335 | pos += sizeof(sband->ht_cap.mcs); | ||
336 | |||
337 | /* extended capabilities */ | ||
338 | pos += sizeof(__le16); | ||
339 | |||
340 | /* BF capabilities */ | ||
341 | pos += sizeof(__le32); | ||
342 | |||
343 | /* antenna selection */ | ||
344 | pos += sizeof(u8); | ||
345 | } | ||
346 | |||
347 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 368 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
348 | ieee80211_tx_skb(sdata, skb); | 369 | ieee80211_tx_skb(sdata, skb); |
349 | } | 370 | } |