diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2011-09-19 12:14:59 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2011-09-22 03:07:58 -0400 |
commit | 01cac476a4bb07b5b6f205b15809e0a845574653 (patch) | |
tree | 6fb5e8c8ad8f18dc72f8555781bed663733b810d /drivers | |
parent | 9df337a104ab99c595cc4ede2c917ba1c2b66374 (diff) |
ath6kl: Fix BSS update on roaming
This fixes the BSS "update" just before the connected or roamed event.
The previous implementation was completely broken: it forced a hardcoded
signal strength and IEs from Association _Request_ frame instead of any
Beacon information. This broke various things, including PMKSA caching.
The current workaround for creating a dummy BSS entry before the roamed
event is not exactly ideal, but that is quite a bit better than the
previous state. As a future improvement, cfg80211 could potentially be
extended to allow this type of use or ath6kl could delay sending the
roamed event before receiving a BSS info event.
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 141 |
1 files changed, 56 insertions, 85 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index e196097e7524..5ede3d2f1f2a 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -413,6 +413,53 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
413 | return 0; | 413 | return 0; |
414 | } | 414 | } |
415 | 415 | ||
416 | static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid, | ||
417 | struct ieee80211_channel *chan, | ||
418 | const u8 *beacon_ie, size_t beacon_ie_len) | ||
419 | { | ||
420 | struct cfg80211_bss *bss; | ||
421 | u8 *ie; | ||
422 | |||
423 | bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid, | ||
424 | ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS, | ||
425 | WLAN_CAPABILITY_ESS); | ||
426 | if (bss == NULL) { | ||
427 | /* | ||
428 | * Since cfg80211 may not yet know about the BSS, | ||
429 | * generate a partial entry until the first BSS info | ||
430 | * event becomes available. | ||
431 | * | ||
432 | * Prepend SSID element since it is not included in the Beacon | ||
433 | * IEs from the target. | ||
434 | */ | ||
435 | ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL); | ||
436 | if (ie == NULL) | ||
437 | return -ENOMEM; | ||
438 | ie[0] = WLAN_EID_SSID; | ||
439 | ie[1] = ar->ssid_len; | ||
440 | memcpy(ie + 2, ar->ssid, ar->ssid_len); | ||
441 | memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len); | ||
442 | bss = cfg80211_inform_bss(ar->wdev->wiphy, chan, | ||
443 | bssid, 0, WLAN_CAPABILITY_ESS, 100, | ||
444 | ie, 2 + ar->ssid_len + beacon_ie_len, | ||
445 | 0, GFP_KERNEL); | ||
446 | if (bss) | ||
447 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for " | ||
448 | "%pM prior to indicating connect/roamed " | ||
449 | "event\n", bssid); | ||
450 | kfree(ie); | ||
451 | } else | ||
452 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " | ||
453 | "entry\n"); | ||
454 | |||
455 | if (bss == NULL) | ||
456 | return -ENOMEM; | ||
457 | |||
458 | cfg80211_put_bss(bss); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
416 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | 463 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, |
417 | u8 *bssid, u16 listen_intvl, | 464 | u8 *bssid, u16 listen_intvl, |
418 | u16 beacon_intvl, | 465 | u16 beacon_intvl, |
@@ -420,17 +467,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
420 | u8 beacon_ie_len, u8 assoc_req_len, | 467 | u8 beacon_ie_len, u8 assoc_req_len, |
421 | u8 assoc_resp_len, u8 *assoc_info) | 468 | u8 assoc_resp_len, u8 *assoc_info) |
422 | { | 469 | { |
423 | u16 size = 0; | 470 | struct ieee80211_channel *chan; |
424 | u16 capability = 0; | ||
425 | struct cfg80211_bss *bss = NULL; | ||
426 | struct ieee80211_mgmt *mgmt = NULL; | ||
427 | struct ieee80211_channel *ibss_ch = NULL; | ||
428 | s32 signal = 50 * 100; | ||
429 | u8 ie_buf_len = 0; | ||
430 | unsigned char ie_buf[256]; | ||
431 | unsigned char *ptr_ie_buf = ie_buf; | ||
432 | unsigned char *ieeemgmtbuf = NULL; | ||
433 | u8 source_mac[ETH_ALEN]; | ||
434 | 471 | ||
435 | /* capinfo + listen interval */ | 472 | /* capinfo + listen interval */ |
436 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); | 473 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); |
@@ -462,84 +499,18 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
462 | } | 499 | } |
463 | } | 500 | } |
464 | 501 | ||
465 | /* | 502 | chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel); |
466 | * Earlier we were updating the cfg about bss by making a beacon frame | ||
467 | * only if the entry for bss is not there. This can have some issue if | ||
468 | * ROAM event is generated and a heavy traffic is ongoing. The ROAM | ||
469 | * event is handled through a work queue and by the time it really gets | ||
470 | * handled, BSS would have been aged out. So it is better to update the | ||
471 | * cfg about BSS irrespective of its entry being present right now or | ||
472 | * not. | ||
473 | */ | ||
474 | |||
475 | if (nw_type & ADHOC_NETWORK) { | ||
476 | /* construct 802.11 mgmt beacon */ | ||
477 | if (ptr_ie_buf) { | ||
478 | *ptr_ie_buf++ = WLAN_EID_SSID; | ||
479 | *ptr_ie_buf++ = ar->ssid_len; | ||
480 | memcpy(ptr_ie_buf, ar->ssid, ar->ssid_len); | ||
481 | ptr_ie_buf += ar->ssid_len; | ||
482 | |||
483 | *ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS; | ||
484 | *ptr_ie_buf++ = 2; /* length */ | ||
485 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
486 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
487 | |||
488 | /* TODO: update ibss params and include supported rates, | ||
489 | * DS param set, extened support rates, wmm. */ | ||
490 | |||
491 | ie_buf_len = ptr_ie_buf - ie_buf; | ||
492 | } | ||
493 | |||
494 | capability |= WLAN_CAPABILITY_IBSS; | ||
495 | |||
496 | if (ar->prwise_crypto == WEP_CRYPT) | ||
497 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
498 | 503 | ||
499 | memcpy(source_mac, ar->net_dev->dev_addr, ETH_ALEN); | ||
500 | ptr_ie_buf = ie_buf; | ||
501 | } else { | ||
502 | capability = *(u16 *) (&assoc_info[beacon_ie_len]); | ||
503 | memcpy(source_mac, bssid, ETH_ALEN); | ||
504 | ptr_ie_buf = assoc_req_ie; | ||
505 | ie_buf_len = assoc_req_len; | ||
506 | } | ||
507 | 504 | ||
508 | size = offsetof(struct ieee80211_mgmt, u) | 505 | if (nw_type & ADHOC_NETWORK) { |
509 | + sizeof(mgmt->u.beacon) | 506 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); |
510 | + ie_buf_len; | ||
511 | |||
512 | ieeemgmtbuf = kzalloc(size, GFP_ATOMIC); | ||
513 | if (!ieeemgmtbuf) { | ||
514 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
515 | return; | 507 | return; |
516 | } | 508 | } |
517 | 509 | ||
518 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | 510 | if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info, |
519 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 511 | beacon_ie_len) < 0) { |
520 | IEEE80211_STYPE_BEACON); | 512 | ath6kl_err("could not add cfg80211 bss entry for " |
521 | memset(mgmt->da, 0xff, ETH_ALEN); /* broadcast addr */ | 513 | "connect/roamed notification\n"); |
522 | memcpy(mgmt->sa, source_mac, ETH_ALEN); | ||
523 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
524 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_intvl); | ||
525 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
526 | memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len); | ||
527 | |||
528 | ibss_ch = ieee80211_get_channel(ar->wdev->wiphy, (int)channel); | ||
529 | |||
530 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
531 | "%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x\n", | ||
532 | __func__, mgmt->bssid, ibss_ch->hw_value, | ||
533 | beacon_intvl, capability); | ||
534 | |||
535 | bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, | ||
536 | ibss_ch, mgmt, | ||
537 | size, signal, GFP_KERNEL); | ||
538 | kfree(ieeemgmtbuf); | ||
539 | cfg80211_put_bss(bss); | ||
540 | |||
541 | if (nw_type & ADHOC_NETWORK) { | ||
542 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); | ||
543 | return; | 514 | return; |
544 | } | 515 | } |
545 | 516 | ||
@@ -552,7 +523,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
552 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | 523 | WLAN_STATUS_SUCCESS, GFP_KERNEL); |
553 | } else if (ar->sme_state == SME_CONNECTED) { | 524 | } else if (ar->sme_state == SME_CONNECTED) { |
554 | /* inform roam event to cfg80211 */ | 525 | /* inform roam event to cfg80211 */ |
555 | cfg80211_roamed(ar->net_dev, ibss_ch, bssid, | 526 | cfg80211_roamed(ar->net_dev, chan, bssid, |
556 | assoc_req_ie, assoc_req_len, | 527 | assoc_req_ie, assoc_req_len, |
557 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); | 528 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); |
558 | } | 529 | } |