diff options
-rw-r--r-- | net/mac80211/mlme.c | 776 |
1 files changed, 387 insertions, 389 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b1815c1ee6d3..e917e1b72631 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -74,6 +74,27 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) | |||
74 | return NULL; | 74 | return NULL; |
75 | } | 75 | } |
76 | 76 | ||
77 | static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss, | ||
78 | struct ieee80211_supported_band *sband, | ||
79 | u64 *rates) | ||
80 | { | ||
81 | int i, j, count; | ||
82 | *rates = 0; | ||
83 | count = 0; | ||
84 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
85 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
86 | |||
87 | for (j = 0; j < sband->n_bitrates; j++) | ||
88 | if (sband->bitrates[j].bitrate == rate) { | ||
89 | *rates |= BIT(j); | ||
90 | count++; | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return count; | ||
96 | } | ||
97 | |||
77 | /* frame sending functions */ | 98 | /* frame sending functions */ |
78 | void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 99 | void ieee80211_sta_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
79 | int encrypt) | 100 | int encrypt) |
@@ -186,6 +207,364 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
186 | ieee80211_sta_tx(sdata, skb, 0); | 207 | ieee80211_sta_tx(sdata, skb, 0); |
187 | } | 208 | } |
188 | 209 | ||
210 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
211 | struct ieee80211_if_sta *ifsta) | ||
212 | { | ||
213 | struct ieee80211_local *local = sdata->local; | ||
214 | struct sk_buff *skb; | ||
215 | struct ieee80211_mgmt *mgmt; | ||
216 | u8 *pos, *ies, *ht_add_ie; | ||
217 | int i, len, count, rates_len, supp_rates_len; | ||
218 | u16 capab; | ||
219 | struct ieee80211_sta_bss *bss; | ||
220 | int wmm = 0; | ||
221 | struct ieee80211_supported_band *sband; | ||
222 | u64 rates = 0; | ||
223 | |||
224 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
225 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | ||
226 | ifsta->ssid_len); | ||
227 | if (!skb) { | ||
228 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
229 | "frame\n", sdata->dev->name); | ||
230 | return; | ||
231 | } | ||
232 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
233 | |||
234 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
235 | |||
236 | capab = ifsta->capab; | ||
237 | |||
238 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
239 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
240 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
241 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
242 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
243 | } | ||
244 | |||
245 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
246 | local->hw.conf.channel->center_freq, | ||
247 | ifsta->ssid, ifsta->ssid_len); | ||
248 | if (bss) { | ||
249 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
250 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
251 | if (bss->wmm_used) | ||
252 | wmm = 1; | ||
253 | |||
254 | /* get all rates supported by the device and the AP as | ||
255 | * some APs don't like getting a superset of their rates | ||
256 | * in the association request (e.g. D-Link DAP 1353 in | ||
257 | * b-only mode) */ | ||
258 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | ||
259 | |||
260 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
261 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
262 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
263 | |||
264 | ieee80211_rx_bss_put(local, bss); | ||
265 | } else { | ||
266 | rates = ~0; | ||
267 | rates_len = sband->n_bitrates; | ||
268 | } | ||
269 | |||
270 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
271 | memset(mgmt, 0, 24); | ||
272 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
273 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
274 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
275 | |||
276 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | ||
277 | skb_put(skb, 10); | ||
278 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
279 | IEEE80211_STYPE_REASSOC_REQ); | ||
280 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
281 | mgmt->u.reassoc_req.listen_interval = | ||
282 | cpu_to_le16(local->hw.conf.listen_interval); | ||
283 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | ||
284 | ETH_ALEN); | ||
285 | } else { | ||
286 | skb_put(skb, 4); | ||
287 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
288 | IEEE80211_STYPE_ASSOC_REQ); | ||
289 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
290 | mgmt->u.reassoc_req.listen_interval = | ||
291 | cpu_to_le16(local->hw.conf.listen_interval); | ||
292 | } | ||
293 | |||
294 | /* SSID */ | ||
295 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
296 | *pos++ = WLAN_EID_SSID; | ||
297 | *pos++ = ifsta->ssid_len; | ||
298 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
299 | |||
300 | /* add all rates which were marked to be used above */ | ||
301 | supp_rates_len = rates_len; | ||
302 | if (supp_rates_len > 8) | ||
303 | supp_rates_len = 8; | ||
304 | |||
305 | len = sband->n_bitrates; | ||
306 | pos = skb_put(skb, supp_rates_len + 2); | ||
307 | *pos++ = WLAN_EID_SUPP_RATES; | ||
308 | *pos++ = supp_rates_len; | ||
309 | |||
310 | count = 0; | ||
311 | for (i = 0; i < sband->n_bitrates; i++) { | ||
312 | if (BIT(i) & rates) { | ||
313 | int rate = sband->bitrates[i].bitrate; | ||
314 | *pos++ = (u8) (rate / 5); | ||
315 | if (++count == 8) | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | if (rates_len > count) { | ||
321 | pos = skb_put(skb, rates_len - count + 2); | ||
322 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
323 | *pos++ = rates_len - count; | ||
324 | |||
325 | for (i++; i < sband->n_bitrates; i++) { | ||
326 | if (BIT(i) & rates) { | ||
327 | int rate = sband->bitrates[i].bitrate; | ||
328 | *pos++ = (u8) (rate / 5); | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
334 | /* 1. power capabilities */ | ||
335 | pos = skb_put(skb, 4); | ||
336 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
337 | *pos++ = 2; | ||
338 | *pos++ = 0; /* min tx power */ | ||
339 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
340 | |||
341 | /* 2. supported channels */ | ||
342 | /* TODO: get this in reg domain format */ | ||
343 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
344 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
345 | *pos++ = 2 * sband->n_channels; | ||
346 | for (i = 0; i < sband->n_channels; i++) { | ||
347 | *pos++ = ieee80211_frequency_to_channel( | ||
348 | sband->channels[i].center_freq); | ||
349 | *pos++ = 1; /* one channel in the subband*/ | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (ifsta->extra_ie) { | ||
354 | pos = skb_put(skb, ifsta->extra_ie_len); | ||
355 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | ||
356 | } | ||
357 | |||
358 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | ||
359 | pos = skb_put(skb, 9); | ||
360 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
361 | *pos++ = 7; /* len */ | ||
362 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
363 | *pos++ = 0x50; | ||
364 | *pos++ = 0xf2; | ||
365 | *pos++ = 2; /* WME */ | ||
366 | *pos++ = 0; /* WME info */ | ||
367 | *pos++ = 1; /* WME ver */ | ||
368 | *pos++ = 0; | ||
369 | } | ||
370 | |||
371 | /* wmm support is a must to HT */ | ||
372 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | ||
373 | sband->ht_info.ht_supported && | ||
374 | (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { | ||
375 | struct ieee80211_ht_addt_info *ht_add_info = | ||
376 | (struct ieee80211_ht_addt_info *)ht_add_ie; | ||
377 | u16 cap = sband->ht_info.cap; | ||
378 | __le16 tmp; | ||
379 | u32 flags = local->hw.conf.channel->flags; | ||
380 | |||
381 | switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { | ||
382 | case IEEE80211_HT_IE_CHA_SEC_ABOVE: | ||
383 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | ||
384 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
385 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
386 | } | ||
387 | break; | ||
388 | case IEEE80211_HT_IE_CHA_SEC_BELOW: | ||
389 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | ||
390 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
391 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
392 | } | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | tmp = cpu_to_le16(cap); | ||
397 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); | ||
398 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
399 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
400 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
401 | memcpy(pos, &tmp, sizeof(u16)); | ||
402 | pos += sizeof(u16); | ||
403 | /* TODO: needs a define here for << 2 */ | ||
404 | *pos++ = sband->ht_info.ampdu_factor | | ||
405 | (sband->ht_info.ampdu_density << 2); | ||
406 | memcpy(pos, sband->ht_info.supp_mcs_set, 16); | ||
407 | } | ||
408 | |||
409 | kfree(ifsta->assocreq_ies); | ||
410 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | ||
411 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | ||
412 | if (ifsta->assocreq_ies) | ||
413 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | ||
414 | |||
415 | ieee80211_sta_tx(sdata, skb, 0); | ||
416 | } | ||
417 | |||
418 | |||
419 | static void ieee80211_send_deauth(struct ieee80211_sub_if_data *sdata, | ||
420 | struct ieee80211_if_sta *ifsta, u16 reason) | ||
421 | { | ||
422 | struct ieee80211_local *local = sdata->local; | ||
423 | struct sk_buff *skb; | ||
424 | struct ieee80211_mgmt *mgmt; | ||
425 | |||
426 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | ||
427 | if (!skb) { | ||
428 | printk(KERN_DEBUG "%s: failed to allocate buffer for deauth " | ||
429 | "frame\n", sdata->dev->name); | ||
430 | return; | ||
431 | } | ||
432 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
433 | |||
434 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
435 | memset(mgmt, 0, 24); | ||
436 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
437 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
438 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
439 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
440 | IEEE80211_STYPE_DEAUTH); | ||
441 | skb_put(skb, 2); | ||
442 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
443 | |||
444 | ieee80211_sta_tx(sdata, skb, 0); | ||
445 | } | ||
446 | |||
447 | static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata, | ||
448 | struct ieee80211_if_sta *ifsta, u16 reason) | ||
449 | { | ||
450 | struct ieee80211_local *local = sdata->local; | ||
451 | struct sk_buff *skb; | ||
452 | struct ieee80211_mgmt *mgmt; | ||
453 | |||
454 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | ||
455 | if (!skb) { | ||
456 | printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc " | ||
457 | "frame\n", sdata->dev->name); | ||
458 | return; | ||
459 | } | ||
460 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
461 | |||
462 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
463 | memset(mgmt, 0, 24); | ||
464 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
465 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
466 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
467 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
468 | IEEE80211_STYPE_DISASSOC); | ||
469 | skb_put(skb, 2); | ||
470 | mgmt->u.disassoc.reason_code = cpu_to_le16(reason); | ||
471 | |||
472 | ieee80211_sta_tx(sdata, skb, 0); | ||
473 | } | ||
474 | |||
475 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | ||
476 | u8 dialog_token, u16 status, u16 policy, | ||
477 | u16 buf_size, u16 timeout) | ||
478 | { | ||
479 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
480 | struct ieee80211_local *local = sdata->local; | ||
481 | struct sk_buff *skb; | ||
482 | struct ieee80211_mgmt *mgmt; | ||
483 | u16 capab; | ||
484 | |||
485 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
486 | |||
487 | if (!skb) { | ||
488 | printk(KERN_DEBUG "%s: failed to allocate buffer " | ||
489 | "for addba resp frame\n", sdata->dev->name); | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
494 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
495 | memset(mgmt, 0, 24); | ||
496 | memcpy(mgmt->da, da, ETH_ALEN); | ||
497 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
498 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
499 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
500 | else | ||
501 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
502 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
503 | IEEE80211_STYPE_ACTION); | ||
504 | |||
505 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | ||
506 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
507 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | ||
508 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | ||
509 | |||
510 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | ||
511 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
512 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | ||
513 | |||
514 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | ||
515 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | ||
516 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | ||
517 | |||
518 | ieee80211_sta_tx(sdata, skb, 0); | ||
519 | } | ||
520 | |||
521 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, | ||
522 | struct ieee80211_msrment_ie *request_ie, | ||
523 | const u8 *da, const u8 *bssid, | ||
524 | u8 dialog_token) | ||
525 | { | ||
526 | struct ieee80211_local *local = sdata->local; | ||
527 | struct sk_buff *skb; | ||
528 | struct ieee80211_mgmt *msr_report; | ||
529 | |||
530 | skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom + | ||
531 | sizeof(struct ieee80211_msrment_ie)); | ||
532 | |||
533 | if (!skb) { | ||
534 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
535 | "measurement report frame\n", sdata->dev->name); | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
540 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); | ||
541 | memset(msr_report, 0, 24); | ||
542 | memcpy(msr_report->da, da, ETH_ALEN); | ||
543 | memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
544 | memcpy(msr_report->bssid, bssid, ETH_ALEN); | ||
545 | msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
546 | IEEE80211_STYPE_ACTION); | ||
547 | |||
548 | skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement)); | ||
549 | msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
550 | msr_report->u.action.u.measurement.action_code = | ||
551 | WLAN_ACTION_SPCT_MSR_RPRT; | ||
552 | msr_report->u.action.u.measurement.dialog_token = dialog_token; | ||
553 | |||
554 | msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT; | ||
555 | msr_report->u.action.u.measurement.length = | ||
556 | sizeof(struct ieee80211_msrment_ie); | ||
557 | |||
558 | memset(&msr_report->u.action.u.measurement.msr_elem, 0, | ||
559 | sizeof(struct ieee80211_msrment_ie)); | ||
560 | msr_report->u.action.u.measurement.msr_elem.token = request_ie->token; | ||
561 | msr_report->u.action.u.measurement.msr_elem.mode |= | ||
562 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | ||
563 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | ||
564 | |||
565 | ieee80211_sta_tx(sdata, skb, 0); | ||
566 | } | ||
567 | |||
189 | /* MLME */ | 568 | /* MLME */ |
190 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 569 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
191 | struct ieee80211_sta_bss *bss) | 570 | struct ieee80211_sta_bss *bss) |
@@ -510,300 +889,6 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
510 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 889 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
511 | } | 890 | } |
512 | 891 | ||
513 | static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss, | ||
514 | struct ieee80211_supported_band *sband, | ||
515 | u64 *rates) | ||
516 | { | ||
517 | int i, j, count; | ||
518 | *rates = 0; | ||
519 | count = 0; | ||
520 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
521 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
522 | |||
523 | for (j = 0; j < sband->n_bitrates; j++) | ||
524 | if (sband->bitrates[j].bitrate == rate) { | ||
525 | *rates |= BIT(j); | ||
526 | count++; | ||
527 | break; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | return count; | ||
532 | } | ||
533 | |||
534 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
535 | struct ieee80211_if_sta *ifsta) | ||
536 | { | ||
537 | struct ieee80211_local *local = sdata->local; | ||
538 | struct sk_buff *skb; | ||
539 | struct ieee80211_mgmt *mgmt; | ||
540 | u8 *pos, *ies, *ht_add_ie; | ||
541 | int i, len, count, rates_len, supp_rates_len; | ||
542 | u16 capab; | ||
543 | struct ieee80211_sta_bss *bss; | ||
544 | int wmm = 0; | ||
545 | struct ieee80211_supported_band *sband; | ||
546 | u64 rates = 0; | ||
547 | |||
548 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
549 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | ||
550 | ifsta->ssid_len); | ||
551 | if (!skb) { | ||
552 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
553 | "frame\n", sdata->dev->name); | ||
554 | return; | ||
555 | } | ||
556 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
557 | |||
558 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
559 | |||
560 | capab = ifsta->capab; | ||
561 | |||
562 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
563 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
564 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
565 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
566 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
567 | } | ||
568 | |||
569 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
570 | local->hw.conf.channel->center_freq, | ||
571 | ifsta->ssid, ifsta->ssid_len); | ||
572 | if (bss) { | ||
573 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
574 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
575 | if (bss->wmm_used) | ||
576 | wmm = 1; | ||
577 | |||
578 | /* get all rates supported by the device and the AP as | ||
579 | * some APs don't like getting a superset of their rates | ||
580 | * in the association request (e.g. D-Link DAP 1353 in | ||
581 | * b-only mode) */ | ||
582 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | ||
583 | |||
584 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
585 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
586 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
587 | |||
588 | ieee80211_rx_bss_put(local, bss); | ||
589 | } else { | ||
590 | rates = ~0; | ||
591 | rates_len = sband->n_bitrates; | ||
592 | } | ||
593 | |||
594 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
595 | memset(mgmt, 0, 24); | ||
596 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
597 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
598 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
599 | |||
600 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | ||
601 | skb_put(skb, 10); | ||
602 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
603 | IEEE80211_STYPE_REASSOC_REQ); | ||
604 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
605 | mgmt->u.reassoc_req.listen_interval = | ||
606 | cpu_to_le16(local->hw.conf.listen_interval); | ||
607 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | ||
608 | ETH_ALEN); | ||
609 | } else { | ||
610 | skb_put(skb, 4); | ||
611 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
612 | IEEE80211_STYPE_ASSOC_REQ); | ||
613 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
614 | mgmt->u.reassoc_req.listen_interval = | ||
615 | cpu_to_le16(local->hw.conf.listen_interval); | ||
616 | } | ||
617 | |||
618 | /* SSID */ | ||
619 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
620 | *pos++ = WLAN_EID_SSID; | ||
621 | *pos++ = ifsta->ssid_len; | ||
622 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
623 | |||
624 | /* add all rates which were marked to be used above */ | ||
625 | supp_rates_len = rates_len; | ||
626 | if (supp_rates_len > 8) | ||
627 | supp_rates_len = 8; | ||
628 | |||
629 | len = sband->n_bitrates; | ||
630 | pos = skb_put(skb, supp_rates_len + 2); | ||
631 | *pos++ = WLAN_EID_SUPP_RATES; | ||
632 | *pos++ = supp_rates_len; | ||
633 | |||
634 | count = 0; | ||
635 | for (i = 0; i < sband->n_bitrates; i++) { | ||
636 | if (BIT(i) & rates) { | ||
637 | int rate = sband->bitrates[i].bitrate; | ||
638 | *pos++ = (u8) (rate / 5); | ||
639 | if (++count == 8) | ||
640 | break; | ||
641 | } | ||
642 | } | ||
643 | |||
644 | if (rates_len > count) { | ||
645 | pos = skb_put(skb, rates_len - count + 2); | ||
646 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
647 | *pos++ = rates_len - count; | ||
648 | |||
649 | for (i++; i < sband->n_bitrates; i++) { | ||
650 | if (BIT(i) & rates) { | ||
651 | int rate = sband->bitrates[i].bitrate; | ||
652 | *pos++ = (u8) (rate / 5); | ||
653 | } | ||
654 | } | ||
655 | } | ||
656 | |||
657 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
658 | /* 1. power capabilities */ | ||
659 | pos = skb_put(skb, 4); | ||
660 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
661 | *pos++ = 2; | ||
662 | *pos++ = 0; /* min tx power */ | ||
663 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
664 | |||
665 | /* 2. supported channels */ | ||
666 | /* TODO: get this in reg domain format */ | ||
667 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
668 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
669 | *pos++ = 2 * sband->n_channels; | ||
670 | for (i = 0; i < sband->n_channels; i++) { | ||
671 | *pos++ = ieee80211_frequency_to_channel( | ||
672 | sband->channels[i].center_freq); | ||
673 | *pos++ = 1; /* one channel in the subband*/ | ||
674 | } | ||
675 | } | ||
676 | |||
677 | if (ifsta->extra_ie) { | ||
678 | pos = skb_put(skb, ifsta->extra_ie_len); | ||
679 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | ||
680 | } | ||
681 | |||
682 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | ||
683 | pos = skb_put(skb, 9); | ||
684 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
685 | *pos++ = 7; /* len */ | ||
686 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
687 | *pos++ = 0x50; | ||
688 | *pos++ = 0xf2; | ||
689 | *pos++ = 2; /* WME */ | ||
690 | *pos++ = 0; /* WME info */ | ||
691 | *pos++ = 1; /* WME ver */ | ||
692 | *pos++ = 0; | ||
693 | } | ||
694 | |||
695 | /* wmm support is a must to HT */ | ||
696 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | ||
697 | sband->ht_info.ht_supported && | ||
698 | (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { | ||
699 | struct ieee80211_ht_addt_info *ht_add_info = | ||
700 | (struct ieee80211_ht_addt_info *)ht_add_ie; | ||
701 | u16 cap = sband->ht_info.cap; | ||
702 | __le16 tmp; | ||
703 | u32 flags = local->hw.conf.channel->flags; | ||
704 | |||
705 | switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { | ||
706 | case IEEE80211_HT_IE_CHA_SEC_ABOVE: | ||
707 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | ||
708 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
709 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
710 | } | ||
711 | break; | ||
712 | case IEEE80211_HT_IE_CHA_SEC_BELOW: | ||
713 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | ||
714 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; | ||
715 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
716 | } | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | tmp = cpu_to_le16(cap); | ||
721 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); | ||
722 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
723 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
724 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
725 | memcpy(pos, &tmp, sizeof(u16)); | ||
726 | pos += sizeof(u16); | ||
727 | /* TODO: needs a define here for << 2 */ | ||
728 | *pos++ = sband->ht_info.ampdu_factor | | ||
729 | (sband->ht_info.ampdu_density << 2); | ||
730 | memcpy(pos, sband->ht_info.supp_mcs_set, 16); | ||
731 | } | ||
732 | |||
733 | kfree(ifsta->assocreq_ies); | ||
734 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | ||
735 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | ||
736 | if (ifsta->assocreq_ies) | ||
737 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | ||
738 | |||
739 | ieee80211_sta_tx(sdata, skb, 0); | ||
740 | } | ||
741 | |||
742 | |||
743 | static void ieee80211_send_deauth(struct ieee80211_sub_if_data *sdata, | ||
744 | struct ieee80211_if_sta *ifsta, u16 reason) | ||
745 | { | ||
746 | struct ieee80211_local *local = sdata->local; | ||
747 | struct sk_buff *skb; | ||
748 | struct ieee80211_mgmt *mgmt; | ||
749 | |||
750 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | ||
751 | if (!skb) { | ||
752 | printk(KERN_DEBUG "%s: failed to allocate buffer for deauth " | ||
753 | "frame\n", sdata->dev->name); | ||
754 | return; | ||
755 | } | ||
756 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
757 | |||
758 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
759 | memset(mgmt, 0, 24); | ||
760 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
761 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
762 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
763 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
764 | IEEE80211_STYPE_DEAUTH); | ||
765 | skb_put(skb, 2); | ||
766 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
767 | |||
768 | ieee80211_sta_tx(sdata, skb, 0); | ||
769 | } | ||
770 | |||
771 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | ||
772 | { | ||
773 | if (!sdata || !sdata->default_key || | ||
774 | sdata->default_key->conf.alg != ALG_WEP) | ||
775 | return 0; | ||
776 | return 1; | ||
777 | } | ||
778 | |||
779 | static void ieee80211_send_disassoc(struct ieee80211_sub_if_data *sdata, | ||
780 | struct ieee80211_if_sta *ifsta, u16 reason) | ||
781 | { | ||
782 | struct ieee80211_local *local = sdata->local; | ||
783 | struct sk_buff *skb; | ||
784 | struct ieee80211_mgmt *mgmt; | ||
785 | |||
786 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | ||
787 | if (!skb) { | ||
788 | printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc " | ||
789 | "frame\n", sdata->dev->name); | ||
790 | return; | ||
791 | } | ||
792 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
793 | |||
794 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
795 | memset(mgmt, 0, 24); | ||
796 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
797 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
798 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
799 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
800 | IEEE80211_STYPE_DISASSOC); | ||
801 | skb_put(skb, 2); | ||
802 | mgmt->u.disassoc.reason_code = cpu_to_le16(reason); | ||
803 | |||
804 | ieee80211_sta_tx(sdata, skb, 0); | ||
805 | } | ||
806 | |||
807 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 892 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
808 | struct ieee80211_if_sta *ifsta, bool deauth, | 893 | struct ieee80211_if_sta *ifsta, bool deauth, |
809 | bool self_disconnected, u16 reason) | 894 | bool self_disconnected, u16 reason) |
@@ -864,6 +949,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
864 | sta_info_destroy(sta); | 949 | sta_info_destroy(sta); |
865 | } | 950 | } |
866 | 951 | ||
952 | static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | ||
953 | { | ||
954 | if (!sdata || !sdata->default_key || | ||
955 | sdata->default_key->conf.alg != ALG_WEP) | ||
956 | return 0; | ||
957 | return 1; | ||
958 | } | ||
959 | |||
867 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | 960 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, |
868 | struct ieee80211_if_sta *ifsta) | 961 | struct ieee80211_if_sta *ifsta) |
869 | { | 962 | { |
@@ -1009,54 +1102,6 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1009 | elems.challenge_len + 2, 1); | 1102 | elems.challenge_len + 2, 1); |
1010 | } | 1103 | } |
1011 | 1104 | ||
1012 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | ||
1013 | u8 dialog_token, u16 status, u16 policy, | ||
1014 | u16 buf_size, u16 timeout) | ||
1015 | { | ||
1016 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1017 | struct ieee80211_local *local = sdata->local; | ||
1018 | struct sk_buff *skb; | ||
1019 | struct ieee80211_mgmt *mgmt; | ||
1020 | u16 capab; | ||
1021 | |||
1022 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
1023 | |||
1024 | if (!skb) { | ||
1025 | printk(KERN_DEBUG "%s: failed to allocate buffer " | ||
1026 | "for addba resp frame\n", sdata->dev->name); | ||
1027 | return; | ||
1028 | } | ||
1029 | |||
1030 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1031 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1032 | memset(mgmt, 0, 24); | ||
1033 | memcpy(mgmt->da, da, ETH_ALEN); | ||
1034 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1035 | if (sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
1036 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
1037 | else | ||
1038 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1039 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1040 | IEEE80211_STYPE_ACTION); | ||
1041 | |||
1042 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | ||
1043 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
1044 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | ||
1045 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | ||
1046 | |||
1047 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | ||
1048 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
1049 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | ||
1050 | |||
1051 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | ||
1052 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | ||
1053 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | ||
1054 | |||
1055 | ieee80211_sta_tx(sdata, skb, 0); | ||
1056 | |||
1057 | return; | ||
1058 | } | ||
1059 | |||
1060 | /* | 1105 | /* |
1061 | * After accepting the AddBA Request we activated a timer, | 1106 | * After accepting the AddBA Request we activated a timer, |
1062 | * resetting it after each frame that arrives from the originator. | 1107 | * resetting it after each frame that arrives from the originator. |
@@ -1329,53 +1374,6 @@ static void ieee80211_sta_process_delba(struct ieee80211_sub_if_data *sdata, | |||
1329 | rcu_read_unlock(); | 1374 | rcu_read_unlock(); |
1330 | } | 1375 | } |
1331 | 1376 | ||
1332 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, | ||
1333 | struct ieee80211_msrment_ie *request_ie, | ||
1334 | const u8 *da, const u8 *bssid, | ||
1335 | u8 dialog_token) | ||
1336 | { | ||
1337 | struct ieee80211_local *local = sdata->local; | ||
1338 | struct sk_buff *skb; | ||
1339 | struct ieee80211_mgmt *msr_report; | ||
1340 | |||
1341 | skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom + | ||
1342 | sizeof(struct ieee80211_msrment_ie)); | ||
1343 | |||
1344 | if (!skb) { | ||
1345 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
1346 | "measurement report frame\n", sdata->dev->name); | ||
1347 | return; | ||
1348 | } | ||
1349 | |||
1350 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1351 | msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); | ||
1352 | memset(msr_report, 0, 24); | ||
1353 | memcpy(msr_report->da, da, ETH_ALEN); | ||
1354 | memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1355 | memcpy(msr_report->bssid, bssid, ETH_ALEN); | ||
1356 | msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1357 | IEEE80211_STYPE_ACTION); | ||
1358 | |||
1359 | skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement)); | ||
1360 | msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
1361 | msr_report->u.action.u.measurement.action_code = | ||
1362 | WLAN_ACTION_SPCT_MSR_RPRT; | ||
1363 | msr_report->u.action.u.measurement.dialog_token = dialog_token; | ||
1364 | |||
1365 | msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT; | ||
1366 | msr_report->u.action.u.measurement.length = | ||
1367 | sizeof(struct ieee80211_msrment_ie); | ||
1368 | |||
1369 | memset(&msr_report->u.action.u.measurement.msr_elem, 0, | ||
1370 | sizeof(struct ieee80211_msrment_ie)); | ||
1371 | msr_report->u.action.u.measurement.msr_elem.token = request_ie->token; | ||
1372 | msr_report->u.action.u.measurement.msr_elem.mode |= | ||
1373 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | ||
1374 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | ||
1375 | |||
1376 | ieee80211_sta_tx(sdata, skb, 0); | ||
1377 | } | ||
1378 | |||
1379 | static void ieee80211_sta_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1377 | static void ieee80211_sta_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
1380 | struct ieee80211_mgmt *mgmt, | 1378 | struct ieee80211_mgmt *mgmt, |
1381 | size_t len) | 1379 | size_t len) |