aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/mlme.c7
-rw-r--r--net/mac80211/work.c239
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
103static 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
103static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, 199static 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}