diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-09-09 04:57:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-11 15:53:38 -0400 |
commit | 9ac19a9084001695479a6d6dd67443cc5fb1df2f (patch) | |
tree | 404a4a2b16235bb575dc366c2cc87b9f65d79cc5 /net/mac80211/mlme.c | |
parent | b079ada7dd11cf82c3157a51c205c3d88321c704 (diff) |
mac80211: reorder frame code in mlme
This reorders all frame sending functions to be at the top of the
file. When reading the file, I tend to be looking at either the
frame code or the state machine, and having them mixed in the file
is confusing. When all frame sending is at the top the remainder
of the file is more readable, in my opinion.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-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) |