aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2011-09-19 12:14:59 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2011-09-22 03:07:58 -0400
commit01cac476a4bb07b5b6f205b15809e0a845574653 (patch)
tree6fb5e8c8ad8f18dc72f8555781bed663733b810d /drivers
parent9df337a104ab99c595cc4ede2c917ba1c2b66374 (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.c141
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
416static 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
416void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, 463void 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 }