diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 894 |
1 files changed, 635 insertions, 259 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 14559ffb1453..3aff36bad5d3 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -17,6 +17,12 @@ | |||
17 | #include "core.h" | 17 | #include "core.h" |
18 | #include "cfg80211.h" | 18 | #include "cfg80211.h" |
19 | #include "debug.h" | 19 | #include "debug.h" |
20 | #include "hif-ops.h" | ||
21 | #include "testmode.h" | ||
22 | |||
23 | static unsigned int ath6kl_p2p; | ||
24 | |||
25 | module_param(ath6kl_p2p, uint, 0644); | ||
20 | 26 | ||
21 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | 27 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ |
22 | .bitrate = (_rate), \ | 28 | .bitrate = (_rate), \ |
@@ -152,8 +158,7 @@ static int ath6kl_set_auth_type(struct ath6kl *ar, | |||
152 | break; | 158 | break; |
153 | 159 | ||
154 | case NL80211_AUTHTYPE_AUTOMATIC: | 160 | case NL80211_AUTHTYPE_AUTOMATIC: |
155 | ar->dot11_auth_mode = OPEN_AUTH; | 161 | ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH; |
156 | ar->auto_auth_stage = AUTH_OPEN_IN_PROGRESS; | ||
157 | break; | 162 | break; |
158 | 163 | ||
159 | default: | 164 | default: |
@@ -167,7 +172,8 @@ static int ath6kl_set_auth_type(struct ath6kl *ar, | |||
167 | static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast) | 172 | static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast) |
168 | { | 173 | { |
169 | u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto; | 174 | u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto; |
170 | u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : &ar->grp_crpto_len; | 175 | u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : |
176 | &ar->grp_crypto_len; | ||
171 | 177 | ||
172 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n", | 178 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n", |
173 | __func__, cipher, ucast); | 179 | __func__, cipher, ucast); |
@@ -354,6 +360,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
354 | } | 360 | } |
355 | 361 | ||
356 | if (!ar->usr_bss_filter) { | 362 | if (!ar->usr_bss_filter) { |
363 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); | ||
357 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { | 364 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { |
358 | ath6kl_err("couldn't set bss filtering\n"); | 365 | ath6kl_err("couldn't set bss filtering\n"); |
359 | up(&ar->sem); | 366 | up(&ar->sem); |
@@ -370,14 +377,14 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
370 | __func__, | 377 | __func__, |
371 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, | 378 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, |
372 | ar->prwise_crypto_len, ar->grp_crypto, | 379 | ar->prwise_crypto_len, ar->grp_crypto, |
373 | ar->grp_crpto_len, ar->ch_hint); | 380 | ar->grp_crypto_len, ar->ch_hint); |
374 | 381 | ||
375 | ar->reconnect_flag = 0; | 382 | ar->reconnect_flag = 0; |
376 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, | 383 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, |
377 | ar->dot11_auth_mode, ar->auth_mode, | 384 | ar->dot11_auth_mode, ar->auth_mode, |
378 | ar->prwise_crypto, | 385 | ar->prwise_crypto, |
379 | ar->prwise_crypto_len, | 386 | ar->prwise_crypto_len, |
380 | ar->grp_crypto, ar->grp_crpto_len, | 387 | ar->grp_crypto, ar->grp_crypto_len, |
381 | ar->ssid_len, ar->ssid, | 388 | ar->ssid_len, ar->ssid, |
382 | ar->req_bssid, ar->ch_hint, | 389 | ar->req_bssid, ar->ch_hint, |
383 | ar->connect_ctrl_flags); | 390 | ar->connect_ctrl_flags); |
@@ -407,6 +414,53 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
407 | return 0; | 414 | return 0; |
408 | } | 415 | } |
409 | 416 | ||
417 | static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid, | ||
418 | struct ieee80211_channel *chan, | ||
419 | const u8 *beacon_ie, size_t beacon_ie_len) | ||
420 | { | ||
421 | struct cfg80211_bss *bss; | ||
422 | u8 *ie; | ||
423 | |||
424 | bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid, | ||
425 | ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS, | ||
426 | WLAN_CAPABILITY_ESS); | ||
427 | if (bss == NULL) { | ||
428 | /* | ||
429 | * Since cfg80211 may not yet know about the BSS, | ||
430 | * generate a partial entry until the first BSS info | ||
431 | * event becomes available. | ||
432 | * | ||
433 | * Prepend SSID element since it is not included in the Beacon | ||
434 | * IEs from the target. | ||
435 | */ | ||
436 | ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL); | ||
437 | if (ie == NULL) | ||
438 | return -ENOMEM; | ||
439 | ie[0] = WLAN_EID_SSID; | ||
440 | ie[1] = ar->ssid_len; | ||
441 | memcpy(ie + 2, ar->ssid, ar->ssid_len); | ||
442 | memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len); | ||
443 | bss = cfg80211_inform_bss(ar->wdev->wiphy, chan, | ||
444 | bssid, 0, WLAN_CAPABILITY_ESS, 100, | ||
445 | ie, 2 + ar->ssid_len + beacon_ie_len, | ||
446 | 0, GFP_KERNEL); | ||
447 | if (bss) | ||
448 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for " | ||
449 | "%pM prior to indicating connect/roamed " | ||
450 | "event\n", bssid); | ||
451 | kfree(ie); | ||
452 | } else | ||
453 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " | ||
454 | "entry\n"); | ||
455 | |||
456 | if (bss == NULL) | ||
457 | return -ENOMEM; | ||
458 | |||
459 | cfg80211_put_bss(bss); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
410 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | 464 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, |
411 | u8 *bssid, u16 listen_intvl, | 465 | u8 *bssid, u16 listen_intvl, |
412 | u16 beacon_intvl, | 466 | u16 beacon_intvl, |
@@ -414,19 +468,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
414 | u8 beacon_ie_len, u8 assoc_req_len, | 468 | u8 beacon_ie_len, u8 assoc_req_len, |
415 | u8 assoc_resp_len, u8 *assoc_info) | 469 | u8 assoc_resp_len, u8 *assoc_info) |
416 | { | 470 | { |
417 | u16 size = 0; | 471 | struct ieee80211_channel *chan; |
418 | u16 capability = 0; | ||
419 | struct cfg80211_bss *bss = NULL; | ||
420 | struct ieee80211_mgmt *mgmt = NULL; | ||
421 | struct ieee80211_channel *ibss_ch = NULL; | ||
422 | s32 signal = 50 * 100; | ||
423 | u8 ie_buf_len = 0; | ||
424 | unsigned char ie_buf[256]; | ||
425 | unsigned char *ptr_ie_buf = ie_buf; | ||
426 | unsigned char *ieeemgmtbuf = NULL; | ||
427 | u8 source_mac[ETH_ALEN]; | ||
428 | u16 capa_mask; | ||
429 | u16 capa_val; | ||
430 | 472 | ||
431 | /* capinfo + listen interval */ | 473 | /* capinfo + listen interval */ |
432 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); | 474 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); |
@@ -441,7 +483,12 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
441 | assoc_req_len -= assoc_req_ie_offset; | 483 | assoc_req_len -= assoc_req_ie_offset; |
442 | assoc_resp_len -= assoc_resp_ie_offset; | 484 | assoc_resp_len -= assoc_resp_ie_offset; |
443 | 485 | ||
444 | ar->auto_auth_stage = AUTH_IDLE; | 486 | /* |
487 | * Store Beacon interval here; DTIM period will be available only once | ||
488 | * a Beacon frame from the AP is seen. | ||
489 | */ | ||
490 | ar->assoc_bss_beacon_int = beacon_intvl; | ||
491 | clear_bit(DTIM_PERIOD_AVAIL, &ar->flag); | ||
445 | 492 | ||
446 | if (nw_type & ADHOC_NETWORK) { | 493 | if (nw_type & ADHOC_NETWORK) { |
447 | if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { | 494 | if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { |
@@ -452,110 +499,26 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
452 | } | 499 | } |
453 | 500 | ||
454 | if (nw_type & INFRA_NETWORK) { | 501 | if (nw_type & INFRA_NETWORK) { |
455 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION) { | 502 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION && |
503 | ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { | ||
456 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 504 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
457 | "%s: ath6k not in station mode\n", __func__); | 505 | "%s: ath6k not in station mode\n", __func__); |
458 | return; | 506 | return; |
459 | } | 507 | } |
460 | } | 508 | } |
461 | 509 | ||
462 | if (nw_type & ADHOC_NETWORK) { | 510 | chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel); |
463 | capa_mask = WLAN_CAPABILITY_IBSS; | ||
464 | capa_val = WLAN_CAPABILITY_IBSS; | ||
465 | } else { | ||
466 | capa_mask = WLAN_CAPABILITY_ESS; | ||
467 | capa_val = WLAN_CAPABILITY_ESS; | ||
468 | } | ||
469 | 511 | ||
470 | /* Before informing the join/connect event, make sure that | ||
471 | * bss entry is present in scan list, if it not present | ||
472 | * construct and insert into scan list, otherwise that | ||
473 | * event will be dropped on the way by cfg80211, due to | ||
474 | * this keys will not be plumbed in case of WEP and | ||
475 | * application will not be aware of join/connect status. */ | ||
476 | bss = cfg80211_get_bss(ar->wdev->wiphy, NULL, bssid, | ||
477 | ar->wdev->ssid, ar->wdev->ssid_len, | ||
478 | capa_mask, capa_val); | ||
479 | |||
480 | /* | ||
481 | * Earlier we were updating the cfg about bss by making a beacon frame | ||
482 | * only if the entry for bss is not there. This can have some issue if | ||
483 | * ROAM event is generated and a heavy traffic is ongoing. The ROAM | ||
484 | * event is handled through a work queue and by the time it really gets | ||
485 | * handled, BSS would have been aged out. So it is better to update the | ||
486 | * cfg about BSS irrespective of its entry being present right now or | ||
487 | * not. | ||
488 | */ | ||
489 | 512 | ||
490 | if (nw_type & ADHOC_NETWORK) { | 513 | if (nw_type & ADHOC_NETWORK) { |
491 | /* construct 802.11 mgmt beacon */ | 514 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); |
492 | if (ptr_ie_buf) { | ||
493 | *ptr_ie_buf++ = WLAN_EID_SSID; | ||
494 | *ptr_ie_buf++ = ar->ssid_len; | ||
495 | memcpy(ptr_ie_buf, ar->ssid, ar->ssid_len); | ||
496 | ptr_ie_buf += ar->ssid_len; | ||
497 | |||
498 | *ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS; | ||
499 | *ptr_ie_buf++ = 2; /* length */ | ||
500 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
501 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
502 | |||
503 | /* TODO: update ibss params and include supported rates, | ||
504 | * DS param set, extened support rates, wmm. */ | ||
505 | |||
506 | ie_buf_len = ptr_ie_buf - ie_buf; | ||
507 | } | ||
508 | |||
509 | capability |= WLAN_CAPABILITY_IBSS; | ||
510 | |||
511 | if (ar->prwise_crypto == WEP_CRYPT) | ||
512 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
513 | |||
514 | memcpy(source_mac, ar->net_dev->dev_addr, ETH_ALEN); | ||
515 | ptr_ie_buf = ie_buf; | ||
516 | } else { | ||
517 | capability = *(u16 *) (&assoc_info[beacon_ie_len]); | ||
518 | memcpy(source_mac, bssid, ETH_ALEN); | ||
519 | ptr_ie_buf = assoc_req_ie; | ||
520 | ie_buf_len = assoc_req_len; | ||
521 | } | ||
522 | |||
523 | size = offsetof(struct ieee80211_mgmt, u) | ||
524 | + sizeof(mgmt->u.beacon) | ||
525 | + ie_buf_len; | ||
526 | |||
527 | ieeemgmtbuf = kzalloc(size, GFP_ATOMIC); | ||
528 | if (!ieeemgmtbuf) { | ||
529 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
530 | cfg80211_put_bss(bss); | ||
531 | return; | 515 | return; |
532 | } | 516 | } |
533 | 517 | ||
534 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | 518 | if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info, |
535 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 519 | beacon_ie_len) < 0) { |
536 | IEEE80211_STYPE_BEACON); | 520 | ath6kl_err("could not add cfg80211 bss entry for " |
537 | memset(mgmt->da, 0xff, ETH_ALEN); /* broadcast addr */ | 521 | "connect/roamed notification\n"); |
538 | memcpy(mgmt->sa, source_mac, ETH_ALEN); | ||
539 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
540 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_intvl); | ||
541 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
542 | memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len); | ||
543 | |||
544 | ibss_ch = ieee80211_get_channel(ar->wdev->wiphy, (int)channel); | ||
545 | |||
546 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
547 | "%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x\n", | ||
548 | __func__, mgmt->bssid, ibss_ch->hw_value, | ||
549 | beacon_intvl, capability); | ||
550 | |||
551 | bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, | ||
552 | ibss_ch, mgmt, | ||
553 | size, signal, GFP_KERNEL); | ||
554 | kfree(ieeemgmtbuf); | ||
555 | cfg80211_put_bss(bss); | ||
556 | |||
557 | if (nw_type & ADHOC_NETWORK) { | ||
558 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); | ||
559 | return; | 522 | return; |
560 | } | 523 | } |
561 | 524 | ||
@@ -568,7 +531,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
568 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | 531 | WLAN_STATUS_SUCCESS, GFP_KERNEL); |
569 | } else if (ar->sme_state == SME_CONNECTED) { | 532 | } else if (ar->sme_state == SME_CONNECTED) { |
570 | /* inform roam event to cfg80211 */ | 533 | /* inform roam event to cfg80211 */ |
571 | cfg80211_roamed(ar->net_dev, ibss_ch, bssid, | 534 | cfg80211_roamed(ar->net_dev, chan, bssid, |
572 | assoc_req_ie, assoc_req_len, | 535 | assoc_req_ie, assoc_req_len, |
573 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); | 536 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); |
574 | } | 537 | } |
@@ -605,6 +568,8 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy, | |||
605 | 568 | ||
606 | up(&ar->sem); | 569 | up(&ar->sem); |
607 | 570 | ||
571 | ar->sme_state = SME_DISCONNECTED; | ||
572 | |||
608 | return 0; | 573 | return 0; |
609 | } | 574 | } |
610 | 575 | ||
@@ -612,9 +577,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, | |||
612 | u8 *bssid, u8 assoc_resp_len, | 577 | u8 *bssid, u8 assoc_resp_len, |
613 | u8 *assoc_info, u16 proto_reason) | 578 | u8 *assoc_info, u16 proto_reason) |
614 | { | 579 | { |
615 | struct ath6kl_key *key = NULL; | ||
616 | u16 status; | ||
617 | |||
618 | if (ar->scan_req) { | 580 | if (ar->scan_req) { |
619 | cfg80211_scan_done(ar->scan_req, true); | 581 | cfg80211_scan_done(ar->scan_req, true); |
620 | ar->scan_req = NULL; | 582 | ar->scan_req = NULL; |
@@ -632,164 +594,64 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, | |||
632 | } | 594 | } |
633 | 595 | ||
634 | if (ar->nw_type & INFRA_NETWORK) { | 596 | if (ar->nw_type & INFRA_NETWORK) { |
635 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION) { | 597 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION && |
598 | ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { | ||
636 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 599 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
637 | "%s: ath6k not in station mode\n", __func__); | 600 | "%s: ath6k not in station mode\n", __func__); |
638 | return; | 601 | return; |
639 | } | 602 | } |
640 | } | 603 | } |
641 | 604 | ||
642 | if (!test_bit(CONNECT_PEND, &ar->flag)) { | ||
643 | if (reason != DISCONNECT_CMD) | ||
644 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
645 | |||
646 | return; | ||
647 | } | ||
648 | |||
649 | if (reason == NO_NETWORK_AVAIL) { | ||
650 | /* connect cmd failed */ | ||
651 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | if (reason != DISCONNECT_CMD) | ||
656 | return; | ||
657 | |||
658 | if (!ar->auto_auth_stage) { | ||
659 | clear_bit(CONNECT_PEND, &ar->flag); | ||
660 | |||
661 | if (ar->sme_state == SME_CONNECTING) { | ||
662 | cfg80211_connect_result(ar->net_dev, | ||
663 | bssid, NULL, 0, | ||
664 | NULL, 0, | ||
665 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
666 | GFP_KERNEL); | ||
667 | } else { | ||
668 | cfg80211_disconnected(ar->net_dev, reason, | ||
669 | NULL, 0, GFP_KERNEL); | ||
670 | } | ||
671 | |||
672 | ar->sme_state = SME_DISCONNECTED; | ||
673 | return; | ||
674 | } | ||
675 | |||
676 | if (ar->dot11_auth_mode != OPEN_AUTH) | ||
677 | return; | ||
678 | |||
679 | /* | 605 | /* |
680 | * If the current auth algorithm is open, try shared and | 606 | * Send a disconnect command to target when a disconnect event is |
681 | * make autoAuthStage idle. We do not make it leap for now | 607 | * received with reason code other than 3 (DISCONNECT_CMD - disconnect |
682 | * being. | 608 | * request from host) to make the firmware stop trying to connect even |
609 | * after giving disconnect event. There will be one more disconnect | ||
610 | * event for this disconnect command with reason code DISCONNECT_CMD | ||
611 | * which will be notified to cfg80211. | ||
683 | */ | 612 | */ |
684 | key = &ar->keys[ar->def_txkey_index]; | ||
685 | if (down_interruptible(&ar->sem)) { | ||
686 | ath6kl_err("busy, couldn't get access\n"); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | ar->dot11_auth_mode = SHARED_AUTH; | ||
691 | ar->auto_auth_stage = AUTH_IDLE; | ||
692 | 613 | ||
693 | ath6kl_wmi_addkey_cmd(ar->wmi, | 614 | if (reason != DISCONNECT_CMD) { |
694 | ar->def_txkey_index, | 615 | ath6kl_wmi_disconnect_cmd(ar->wmi); |
695 | ar->prwise_crypto, | ||
696 | GROUP_USAGE | TX_USAGE, | ||
697 | key->key_len, NULL, | ||
698 | key->key, | ||
699 | KEY_OP_INIT_VAL, NULL, | ||
700 | NO_SYNC_WMIFLAG); | ||
701 | |||
702 | status = ath6kl_wmi_connect_cmd(ar->wmi, | ||
703 | ar->nw_type, | ||
704 | ar->dot11_auth_mode, | ||
705 | ar->auth_mode, | ||
706 | ar->prwise_crypto, | ||
707 | ar->prwise_crypto_len, | ||
708 | ar->grp_crypto, | ||
709 | ar->grp_crpto_len, | ||
710 | ar->ssid_len, | ||
711 | ar->ssid, | ||
712 | ar->req_bssid, | ||
713 | ar->ch_hint, | ||
714 | ar->connect_ctrl_flags); | ||
715 | up(&ar->sem); | ||
716 | } | ||
717 | |||
718 | static inline bool is_ch_11a(u16 ch) | ||
719 | { | ||
720 | return (!((ch >= 2412) && (ch <= 2484))); | ||
721 | } | ||
722 | |||
723 | /* struct ath6kl_node_table::nt_nodelock is locked when calling this */ | ||
724 | void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni) | ||
725 | { | ||
726 | u16 size; | ||
727 | unsigned char *ieeemgmtbuf = NULL; | ||
728 | struct ieee80211_mgmt *mgmt; | ||
729 | struct ieee80211_channel *channel; | ||
730 | struct ieee80211_supported_band *band; | ||
731 | struct ath6kl_common_ie *cie; | ||
732 | s32 signal; | ||
733 | int freq; | ||
734 | |||
735 | cie = &ni->ni_cie; | ||
736 | |||
737 | if (is_ch_11a(cie->ie_chan)) | ||
738 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */ | ||
739 | else if ((cie->ie_erp) || (cie->ie_xrates)) | ||
740 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */ | ||
741 | else | ||
742 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */ | ||
743 | |||
744 | size = ni->ni_framelen + offsetof(struct ieee80211_mgmt, u); | ||
745 | ieeemgmtbuf = kmalloc(size, GFP_ATOMIC); | ||
746 | if (!ieeemgmtbuf) { | ||
747 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
748 | return; | 616 | return; |
749 | } | 617 | } |
750 | 618 | ||
751 | /* | 619 | clear_bit(CONNECT_PEND, &ar->flag); |
752 | * TODO: Update target to include 802.11 mac header while sending | ||
753 | * bss info. Target removes 802.11 mac header while sending the bss | ||
754 | * info to host, cfg80211 needs it, for time being just filling the | ||
755 | * da, sa and bssid fields alone. | ||
756 | */ | ||
757 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | ||
758 | memset(mgmt->da, 0xff, ETH_ALEN); /*broadcast addr */ | ||
759 | memcpy(mgmt->sa, ni->ni_macaddr, ETH_ALEN); | ||
760 | memcpy(mgmt->bssid, ni->ni_macaddr, ETH_ALEN); | ||
761 | memcpy(ieeemgmtbuf + offsetof(struct ieee80211_mgmt, u), | ||
762 | ni->ni_buf, ni->ni_framelen); | ||
763 | |||
764 | freq = cie->ie_chan; | ||
765 | channel = ieee80211_get_channel(wiphy, freq); | ||
766 | signal = ni->ni_snr * 100; | ||
767 | 620 | ||
768 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 621 | if (ar->sme_state == SME_CONNECTING) { |
769 | "%s: bssid %pM ch %d freq %d size %d\n", __func__, | 622 | cfg80211_connect_result(ar->net_dev, |
770 | mgmt->bssid, channel->hw_value, freq, size); | 623 | bssid, NULL, 0, |
771 | cfg80211_inform_bss_frame(wiphy, channel, mgmt, | 624 | NULL, 0, |
772 | size, signal, GFP_ATOMIC); | 625 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
626 | GFP_KERNEL); | ||
627 | } else if (ar->sme_state == SME_CONNECTED) { | ||
628 | cfg80211_disconnected(ar->net_dev, reason, | ||
629 | NULL, 0, GFP_KERNEL); | ||
630 | } | ||
773 | 631 | ||
774 | kfree(ieeemgmtbuf); | 632 | ar->sme_state = SME_DISCONNECTED; |
775 | } | 633 | } |
776 | 634 | ||
777 | static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | 635 | static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, |
778 | struct cfg80211_scan_request *request) | 636 | struct cfg80211_scan_request *request) |
779 | { | 637 | { |
780 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | 638 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); |
639 | s8 n_channels = 0; | ||
640 | u16 *channels = NULL; | ||
781 | int ret = 0; | 641 | int ret = 0; |
782 | 642 | ||
783 | if (!ath6kl_cfg80211_ready(ar)) | 643 | if (!ath6kl_cfg80211_ready(ar)) |
784 | return -EIO; | 644 | return -EIO; |
785 | 645 | ||
786 | if (!ar->usr_bss_filter) { | 646 | if (!ar->usr_bss_filter) { |
787 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, | 647 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); |
788 | (test_bit(CONNECTED, &ar->flag) ? | 648 | ret = ath6kl_wmi_bssfilter_cmd( |
789 | ALL_BUT_BSS_FILTER : | 649 | ar->wmi, |
790 | ALL_BSS_FILTER), 0) != 0) { | 650 | (test_bit(CONNECTED, &ar->flag) ? |
651 | ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0); | ||
652 | if (ret) { | ||
791 | ath6kl_err("couldn't set bss filtering\n"); | 653 | ath6kl_err("couldn't set bss filtering\n"); |
792 | return -EIO; | 654 | return ret; |
793 | } | 655 | } |
794 | } | 656 | } |
795 | 657 | ||
@@ -806,13 +668,46 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
806 | request->ssids[i].ssid); | 668 | request->ssids[i].ssid); |
807 | } | 669 | } |
808 | 670 | ||
809 | if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, | 671 | if (request->ie) { |
810 | false, 0, 0, 0, NULL) != 0) { | 672 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ, |
811 | ath6kl_err("wmi_startscan_cmd failed\n"); | 673 | request->ie, request->ie_len); |
812 | ret = -EIO; | 674 | if (ret) { |
675 | ath6kl_err("failed to set Probe Request appie for " | ||
676 | "scan"); | ||
677 | return ret; | ||
678 | } | ||
813 | } | 679 | } |
814 | 680 | ||
815 | ar->scan_req = request; | 681 | /* |
682 | * Scan only the requested channels if the request specifies a set of | ||
683 | * channels. If the list is longer than the target supports, do not | ||
684 | * configure the list and instead, scan all available channels. | ||
685 | */ | ||
686 | if (request->n_channels > 0 && | ||
687 | request->n_channels <= WMI_MAX_CHANNELS) { | ||
688 | u8 i; | ||
689 | |||
690 | n_channels = request->n_channels; | ||
691 | |||
692 | channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); | ||
693 | if (channels == NULL) { | ||
694 | ath6kl_warn("failed to set scan channels, " | ||
695 | "scan all channels"); | ||
696 | n_channels = 0; | ||
697 | } | ||
698 | |||
699 | for (i = 0; i < n_channels; i++) | ||
700 | channels[i] = request->channels[i]->center_freq; | ||
701 | } | ||
702 | |||
703 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, | ||
704 | false, 0, 0, n_channels, channels); | ||
705 | if (ret) | ||
706 | ath6kl_err("wmi_startscan_cmd failed\n"); | ||
707 | else | ||
708 | ar->scan_req = request; | ||
709 | |||
710 | kfree(channels); | ||
816 | 711 | ||
817 | return ret; | 712 | return ret; |
818 | } | 713 | } |
@@ -831,9 +726,6 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status) | |||
831 | goto out; | 726 | goto out; |
832 | } | 727 | } |
833 | 728 | ||
834 | /* Translate data to cfg80211 mgmt format */ | ||
835 | wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy); | ||
836 | |||
837 | cfg80211_scan_done(ar->scan_req, false); | 729 | cfg80211_scan_done(ar->scan_req, false); |
838 | 730 | ||
839 | if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { | 731 | if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { |
@@ -918,6 +810,40 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
918 | key_usage, key->seq_len); | 810 | key_usage, key->seq_len); |
919 | 811 | ||
920 | ar->def_txkey_index = key_index; | 812 | ar->def_txkey_index = key_index; |
813 | |||
814 | if (ar->nw_type == AP_NETWORK && !pairwise && | ||
815 | (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) { | ||
816 | ar->ap_mode_bkey.valid = true; | ||
817 | ar->ap_mode_bkey.key_index = key_index; | ||
818 | ar->ap_mode_bkey.key_type = key_type; | ||
819 | ar->ap_mode_bkey.key_len = key->key_len; | ||
820 | memcpy(ar->ap_mode_bkey.key, key->key, key->key_len); | ||
821 | if (!test_bit(CONNECTED, &ar->flag)) { | ||
822 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group " | ||
823 | "key configuration until AP mode has been " | ||
824 | "started\n"); | ||
825 | /* | ||
826 | * The key will be set in ath6kl_connect_ap_mode() once | ||
827 | * the connected event is received from the target. | ||
828 | */ | ||
829 | return 0; | ||
830 | } | ||
831 | } | ||
832 | |||
833 | if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT && | ||
834 | !test_bit(CONNECTED, &ar->flag)) { | ||
835 | /* | ||
836 | * Store the key locally so that it can be re-configured after | ||
837 | * the AP mode has properly started | ||
838 | * (ath6kl_install_statioc_wep_keys). | ||
839 | */ | ||
840 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration " | ||
841 | "until AP mode has been started\n"); | ||
842 | ar->wep_key_list[key_index].key_len = key->key_len; | ||
843 | memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len); | ||
844 | return 0; | ||
845 | } | ||
846 | |||
921 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, | 847 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, |
922 | key_type, key_usage, key->key_len, | 848 | key_type, key_usage, key->key_len, |
923 | key->seq, key->key, KEY_OP_INIT_VAL, | 849 | key->seq, key->key, KEY_OP_INIT_VAL, |
@@ -1002,6 +928,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, | |||
1002 | struct ath6kl_key *key = NULL; | 928 | struct ath6kl_key *key = NULL; |
1003 | int status = 0; | 929 | int status = 0; |
1004 | u8 key_usage; | 930 | u8 key_usage; |
931 | enum crypto_type key_type = NONE_CRYPT; | ||
1005 | 932 | ||
1006 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); | 933 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); |
1007 | 934 | ||
@@ -1026,9 +953,16 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, | |||
1026 | key_usage = GROUP_USAGE; | 953 | key_usage = GROUP_USAGE; |
1027 | if (ar->prwise_crypto == WEP_CRYPT) | 954 | if (ar->prwise_crypto == WEP_CRYPT) |
1028 | key_usage |= TX_USAGE; | 955 | key_usage |= TX_USAGE; |
956 | if (unicast) | ||
957 | key_type = ar->prwise_crypto; | ||
958 | if (multicast) | ||
959 | key_type = ar->grp_crypto; | ||
960 | |||
961 | if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag)) | ||
962 | return 0; /* Delay until AP mode has been started */ | ||
1029 | 963 | ||
1030 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, | 964 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, |
1031 | ar->prwise_crypto, key_usage, | 965 | key_type, key_usage, |
1032 | key->key_len, key->seq, key->key, | 966 | key->key_len, key->seq, key->key, |
1033 | KEY_OP_INIT_VAL, NULL, | 967 | KEY_OP_INIT_VAL, NULL, |
1034 | SYNC_BOTH_WMIFLAG); | 968 | SYNC_BOTH_WMIFLAG); |
@@ -1183,6 +1117,15 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, | |||
1183 | case NL80211_IFTYPE_ADHOC: | 1117 | case NL80211_IFTYPE_ADHOC: |
1184 | ar->next_mode = ADHOC_NETWORK; | 1118 | ar->next_mode = ADHOC_NETWORK; |
1185 | break; | 1119 | break; |
1120 | case NL80211_IFTYPE_AP: | ||
1121 | ar->next_mode = AP_NETWORK; | ||
1122 | break; | ||
1123 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1124 | ar->next_mode = INFRA_NETWORK; | ||
1125 | break; | ||
1126 | case NL80211_IFTYPE_P2P_GO: | ||
1127 | ar->next_mode = AP_NETWORK; | ||
1128 | break; | ||
1186 | default: | 1129 | default: |
1187 | ath6kl_err("invalid interface type %u\n", type); | 1130 | ath6kl_err("invalid interface type %u\n", type); |
1188 | return -EOPNOTSUPP; | 1131 | return -EOPNOTSUPP; |
@@ -1246,13 +1189,13 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy, | |||
1246 | __func__, | 1189 | __func__, |
1247 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, | 1190 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, |
1248 | ar->prwise_crypto_len, ar->grp_crypto, | 1191 | ar->prwise_crypto_len, ar->grp_crypto, |
1249 | ar->grp_crpto_len, ar->ch_hint); | 1192 | ar->grp_crypto_len, ar->ch_hint); |
1250 | 1193 | ||
1251 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, | 1194 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, |
1252 | ar->dot11_auth_mode, ar->auth_mode, | 1195 | ar->dot11_auth_mode, ar->auth_mode, |
1253 | ar->prwise_crypto, | 1196 | ar->prwise_crypto, |
1254 | ar->prwise_crypto_len, | 1197 | ar->prwise_crypto_len, |
1255 | ar->grp_crypto, ar->grp_crpto_len, | 1198 | ar->grp_crypto, ar->grp_crypto_len, |
1256 | ar->ssid_len, ar->ssid, | 1199 | ar->ssid_len, ar->ssid, |
1257 | ar->req_bssid, ar->ch_hint, | 1200 | ar->req_bssid, ar->ch_hint, |
1258 | ar->connect_ctrl_flags); | 1201 | ar->connect_ctrl_flags); |
@@ -1422,12 +1365,23 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
1422 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 1365 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
1423 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | 1366 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; |
1424 | } else { | 1367 | } else { |
1425 | ath6kl_warn("invalid rate: %d\n", rate); | 1368 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
1369 | "invalid rate from stats: %d\n", rate); | ||
1370 | ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE); | ||
1426 | return 0; | 1371 | return 0; |
1427 | } | 1372 | } |
1428 | 1373 | ||
1429 | sinfo->filled |= STATION_INFO_TX_BITRATE; | 1374 | sinfo->filled |= STATION_INFO_TX_BITRATE; |
1430 | 1375 | ||
1376 | if (test_bit(CONNECTED, &ar->flag) && | ||
1377 | test_bit(DTIM_PERIOD_AVAIL, &ar->flag) && | ||
1378 | ar->nw_type == INFRA_NETWORK) { | ||
1379 | sinfo->filled |= STATION_INFO_BSS_PARAM; | ||
1380 | sinfo->bss_param.flags = 0; | ||
1381 | sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period; | ||
1382 | sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int; | ||
1383 | } | ||
1384 | |||
1431 | return 0; | 1385 | return 0; |
1432 | } | 1386 | } |
1433 | 1387 | ||
@@ -1455,6 +1409,402 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | |||
1455 | return 0; | 1409 | return 0; |
1456 | } | 1410 | } |
1457 | 1411 | ||
1412 | #ifdef CONFIG_PM | ||
1413 | static int ar6k_cfg80211_suspend(struct wiphy *wiphy, | ||
1414 | struct cfg80211_wowlan *wow) | ||
1415 | { | ||
1416 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
1417 | |||
1418 | return ath6kl_hif_suspend(ar); | ||
1419 | } | ||
1420 | #endif | ||
1421 | |||
1422 | static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, | ||
1423 | struct ieee80211_channel *chan, | ||
1424 | enum nl80211_channel_type channel_type) | ||
1425 | { | ||
1426 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1427 | |||
1428 | if (!ath6kl_cfg80211_ready(ar)) | ||
1429 | return -EIO; | ||
1430 | |||
1431 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", | ||
1432 | __func__, chan->center_freq, chan->hw_value); | ||
1433 | ar->next_chan = chan->center_freq; | ||
1434 | |||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | static bool ath6kl_is_p2p_ie(const u8 *pos) | ||
1439 | { | ||
1440 | return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && | ||
1441 | pos[2] == 0x50 && pos[3] == 0x6f && | ||
1442 | pos[4] == 0x9a && pos[5] == 0x09; | ||
1443 | } | ||
1444 | |||
1445 | static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies, | ||
1446 | size_t ies_len) | ||
1447 | { | ||
1448 | const u8 *pos; | ||
1449 | u8 *buf = NULL; | ||
1450 | size_t len = 0; | ||
1451 | int ret; | ||
1452 | |||
1453 | /* | ||
1454 | * Filter out P2P IE(s) since they will be included depending on | ||
1455 | * the Probe Request frame in ath6kl_send_go_probe_resp(). | ||
1456 | */ | ||
1457 | |||
1458 | if (ies && ies_len) { | ||
1459 | buf = kmalloc(ies_len, GFP_KERNEL); | ||
1460 | if (buf == NULL) | ||
1461 | return -ENOMEM; | ||
1462 | pos = ies; | ||
1463 | while (pos + 1 < ies + ies_len) { | ||
1464 | if (pos + 2 + pos[1] > ies + ies_len) | ||
1465 | break; | ||
1466 | if (!ath6kl_is_p2p_ie(pos)) { | ||
1467 | memcpy(buf + len, pos, 2 + pos[1]); | ||
1468 | len += 2 + pos[1]; | ||
1469 | } | ||
1470 | pos += 2 + pos[1]; | ||
1471 | } | ||
1472 | } | ||
1473 | |||
1474 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP, | ||
1475 | buf, len); | ||
1476 | kfree(buf); | ||
1477 | return ret; | ||
1478 | } | ||
1479 | |||
1480 | static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
1481 | struct beacon_parameters *info, bool add) | ||
1482 | { | ||
1483 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1484 | struct ieee80211_mgmt *mgmt; | ||
1485 | u8 *ies; | ||
1486 | int ies_len; | ||
1487 | struct wmi_connect_cmd p; | ||
1488 | int res; | ||
1489 | int i; | ||
1490 | |||
1491 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); | ||
1492 | |||
1493 | if (!ath6kl_cfg80211_ready(ar)) | ||
1494 | return -EIO; | ||
1495 | |||
1496 | if (ar->next_mode != AP_NETWORK) | ||
1497 | return -EOPNOTSUPP; | ||
1498 | |||
1499 | if (info->beacon_ies) { | ||
1500 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON, | ||
1501 | info->beacon_ies, | ||
1502 | info->beacon_ies_len); | ||
1503 | if (res) | ||
1504 | return res; | ||
1505 | } | ||
1506 | if (info->proberesp_ies) { | ||
1507 | res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies, | ||
1508 | info->proberesp_ies_len); | ||
1509 | if (res) | ||
1510 | return res; | ||
1511 | } | ||
1512 | if (info->assocresp_ies) { | ||
1513 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP, | ||
1514 | info->assocresp_ies, | ||
1515 | info->assocresp_ies_len); | ||
1516 | if (res) | ||
1517 | return res; | ||
1518 | } | ||
1519 | |||
1520 | if (!add) | ||
1521 | return 0; | ||
1522 | |||
1523 | ar->ap_mode_bkey.valid = false; | ||
1524 | |||
1525 | /* TODO: | ||
1526 | * info->interval | ||
1527 | * info->dtim_period | ||
1528 | */ | ||
1529 | |||
1530 | if (info->head == NULL) | ||
1531 | return -EINVAL; | ||
1532 | mgmt = (struct ieee80211_mgmt *) info->head; | ||
1533 | ies = mgmt->u.beacon.variable; | ||
1534 | if (ies > info->head + info->head_len) | ||
1535 | return -EINVAL; | ||
1536 | ies_len = info->head + info->head_len - ies; | ||
1537 | |||
1538 | if (info->ssid == NULL) | ||
1539 | return -EINVAL; | ||
1540 | memcpy(ar->ssid, info->ssid, info->ssid_len); | ||
1541 | ar->ssid_len = info->ssid_len; | ||
1542 | if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) | ||
1543 | return -EOPNOTSUPP; /* TODO */ | ||
1544 | |||
1545 | ar->dot11_auth_mode = OPEN_AUTH; | ||
1546 | |||
1547 | memset(&p, 0, sizeof(p)); | ||
1548 | |||
1549 | for (i = 0; i < info->crypto.n_akm_suites; i++) { | ||
1550 | switch (info->crypto.akm_suites[i]) { | ||
1551 | case WLAN_AKM_SUITE_8021X: | ||
1552 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) | ||
1553 | p.auth_mode |= WPA_AUTH; | ||
1554 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) | ||
1555 | p.auth_mode |= WPA2_AUTH; | ||
1556 | break; | ||
1557 | case WLAN_AKM_SUITE_PSK: | ||
1558 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) | ||
1559 | p.auth_mode |= WPA_PSK_AUTH; | ||
1560 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) | ||
1561 | p.auth_mode |= WPA2_PSK_AUTH; | ||
1562 | break; | ||
1563 | } | ||
1564 | } | ||
1565 | if (p.auth_mode == 0) | ||
1566 | p.auth_mode = NONE_AUTH; | ||
1567 | ar->auth_mode = p.auth_mode; | ||
1568 | |||
1569 | for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) { | ||
1570 | switch (info->crypto.ciphers_pairwise[i]) { | ||
1571 | case WLAN_CIPHER_SUITE_WEP40: | ||
1572 | case WLAN_CIPHER_SUITE_WEP104: | ||
1573 | p.prwise_crypto_type |= WEP_CRYPT; | ||
1574 | break; | ||
1575 | case WLAN_CIPHER_SUITE_TKIP: | ||
1576 | p.prwise_crypto_type |= TKIP_CRYPT; | ||
1577 | break; | ||
1578 | case WLAN_CIPHER_SUITE_CCMP: | ||
1579 | p.prwise_crypto_type |= AES_CRYPT; | ||
1580 | break; | ||
1581 | } | ||
1582 | } | ||
1583 | if (p.prwise_crypto_type == 0) { | ||
1584 | p.prwise_crypto_type = NONE_CRYPT; | ||
1585 | ath6kl_set_cipher(ar, 0, true); | ||
1586 | } else if (info->crypto.n_ciphers_pairwise == 1) | ||
1587 | ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true); | ||
1588 | |||
1589 | switch (info->crypto.cipher_group) { | ||
1590 | case WLAN_CIPHER_SUITE_WEP40: | ||
1591 | case WLAN_CIPHER_SUITE_WEP104: | ||
1592 | p.grp_crypto_type = WEP_CRYPT; | ||
1593 | break; | ||
1594 | case WLAN_CIPHER_SUITE_TKIP: | ||
1595 | p.grp_crypto_type = TKIP_CRYPT; | ||
1596 | break; | ||
1597 | case WLAN_CIPHER_SUITE_CCMP: | ||
1598 | p.grp_crypto_type = AES_CRYPT; | ||
1599 | break; | ||
1600 | default: | ||
1601 | p.grp_crypto_type = NONE_CRYPT; | ||
1602 | break; | ||
1603 | } | ||
1604 | ath6kl_set_cipher(ar, info->crypto.cipher_group, false); | ||
1605 | |||
1606 | p.nw_type = AP_NETWORK; | ||
1607 | ar->nw_type = ar->next_mode; | ||
1608 | |||
1609 | p.ssid_len = ar->ssid_len; | ||
1610 | memcpy(p.ssid, ar->ssid, ar->ssid_len); | ||
1611 | p.dot11_auth_mode = ar->dot11_auth_mode; | ||
1612 | p.ch = cpu_to_le16(ar->next_chan); | ||
1613 | |||
1614 | res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p); | ||
1615 | if (res < 0) | ||
1616 | return res; | ||
1617 | |||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
1622 | struct beacon_parameters *info) | ||
1623 | { | ||
1624 | return ath6kl_ap_beacon(wiphy, dev, info, true); | ||
1625 | } | ||
1626 | |||
1627 | static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
1628 | struct beacon_parameters *info) | ||
1629 | { | ||
1630 | return ath6kl_ap_beacon(wiphy, dev, info, false); | ||
1631 | } | ||
1632 | |||
1633 | static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) | ||
1634 | { | ||
1635 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1636 | |||
1637 | if (ar->nw_type != AP_NETWORK) | ||
1638 | return -EOPNOTSUPP; | ||
1639 | if (!test_bit(CONNECTED, &ar->flag)) | ||
1640 | return -ENOTCONN; | ||
1641 | |||
1642 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
1643 | clear_bit(CONNECTED, &ar->flag); | ||
1644 | |||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, | ||
1649 | u8 *mac, struct station_parameters *params) | ||
1650 | { | ||
1651 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1652 | |||
1653 | if (ar->nw_type != AP_NETWORK) | ||
1654 | return -EOPNOTSUPP; | ||
1655 | |||
1656 | /* Use this only for authorizing/unauthorizing a station */ | ||
1657 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
1658 | return -EOPNOTSUPP; | ||
1659 | |||
1660 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
1661 | return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE, | ||
1662 | mac, 0); | ||
1663 | return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac, | ||
1664 | 0); | ||
1665 | } | ||
1666 | |||
1667 | static int ath6kl_remain_on_channel(struct wiphy *wiphy, | ||
1668 | struct net_device *dev, | ||
1669 | struct ieee80211_channel *chan, | ||
1670 | enum nl80211_channel_type channel_type, | ||
1671 | unsigned int duration, | ||
1672 | u64 *cookie) | ||
1673 | { | ||
1674 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1675 | |||
1676 | /* TODO: if already pending or ongoing remain-on-channel, | ||
1677 | * return -EBUSY */ | ||
1678 | *cookie = 1; /* only a single pending request is supported */ | ||
1679 | |||
1680 | return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq, | ||
1681 | duration); | ||
1682 | } | ||
1683 | |||
1684 | static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, | ||
1685 | struct net_device *dev, | ||
1686 | u64 cookie) | ||
1687 | { | ||
1688 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1689 | |||
1690 | if (cookie != 1) | ||
1691 | return -ENOENT; | ||
1692 | |||
1693 | return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi); | ||
1694 | } | ||
1695 | |||
1696 | static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf, | ||
1697 | size_t len, unsigned int freq) | ||
1698 | { | ||
1699 | const u8 *pos; | ||
1700 | u8 *p2p; | ||
1701 | int p2p_len; | ||
1702 | int ret; | ||
1703 | const struct ieee80211_mgmt *mgmt; | ||
1704 | |||
1705 | mgmt = (const struct ieee80211_mgmt *) buf; | ||
1706 | |||
1707 | /* Include P2P IE(s) from the frame generated in user space. */ | ||
1708 | |||
1709 | p2p = kmalloc(len, GFP_KERNEL); | ||
1710 | if (p2p == NULL) | ||
1711 | return -ENOMEM; | ||
1712 | p2p_len = 0; | ||
1713 | |||
1714 | pos = mgmt->u.probe_resp.variable; | ||
1715 | while (pos + 1 < buf + len) { | ||
1716 | if (pos + 2 + pos[1] > buf + len) | ||
1717 | break; | ||
1718 | if (ath6kl_is_p2p_ie(pos)) { | ||
1719 | memcpy(p2p + p2p_len, pos, 2 + pos[1]); | ||
1720 | p2p_len += 2 + pos[1]; | ||
1721 | } | ||
1722 | pos += 2 + pos[1]; | ||
1723 | } | ||
1724 | |||
1725 | ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da, | ||
1726 | p2p, p2p_len); | ||
1727 | kfree(p2p); | ||
1728 | return ret; | ||
1729 | } | ||
1730 | |||
1731 | static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | ||
1732 | struct ieee80211_channel *chan, bool offchan, | ||
1733 | enum nl80211_channel_type channel_type, | ||
1734 | bool channel_type_valid, unsigned int wait, | ||
1735 | const u8 *buf, size_t len, bool no_cck, u64 *cookie) | ||
1736 | { | ||
1737 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1738 | u32 id; | ||
1739 | const struct ieee80211_mgmt *mgmt; | ||
1740 | |||
1741 | mgmt = (const struct ieee80211_mgmt *) buf; | ||
1742 | if (buf + len >= mgmt->u.probe_resp.variable && | ||
1743 | ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) && | ||
1744 | ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
1745 | /* | ||
1746 | * Send Probe Response frame in AP mode using a separate WMI | ||
1747 | * command to allow the target to fill in the generic IEs. | ||
1748 | */ | ||
1749 | *cookie = 0; /* TX status not supported */ | ||
1750 | return ath6kl_send_go_probe_resp(ar, buf, len, | ||
1751 | chan->center_freq); | ||
1752 | } | ||
1753 | |||
1754 | id = ar->send_action_id++; | ||
1755 | if (id == 0) { | ||
1756 | /* | ||
1757 | * 0 is a reserved value in the WMI command and shall not be | ||
1758 | * used for the command. | ||
1759 | */ | ||
1760 | id = ar->send_action_id++; | ||
1761 | } | ||
1762 | |||
1763 | *cookie = id; | ||
1764 | return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait, | ||
1765 | buf, len); | ||
1766 | } | ||
1767 | |||
1768 | static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, | ||
1769 | struct net_device *dev, | ||
1770 | u16 frame_type, bool reg) | ||
1771 | { | ||
1772 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1773 | |||
1774 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", | ||
1775 | __func__, frame_type, reg); | ||
1776 | if (frame_type == IEEE80211_STYPE_PROBE_REQ) { | ||
1777 | /* | ||
1778 | * Note: This notification callback is not allowed to sleep, so | ||
1779 | * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we | ||
1780 | * hardcode target to report Probe Request frames all the time. | ||
1781 | */ | ||
1782 | ar->probe_req_report = reg; | ||
1783 | } | ||
1784 | } | ||
1785 | |||
1786 | static const struct ieee80211_txrx_stypes | ||
1787 | ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
1788 | [NL80211_IFTYPE_STATION] = { | ||
1789 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1790 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
1791 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1792 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
1793 | }, | ||
1794 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
1795 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1796 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
1797 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1798 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
1799 | }, | ||
1800 | [NL80211_IFTYPE_P2P_GO] = { | ||
1801 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1802 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
1803 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1804 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
1805 | }, | ||
1806 | }; | ||
1807 | |||
1458 | static struct cfg80211_ops ath6kl_cfg80211_ops = { | 1808 | static struct cfg80211_ops ath6kl_cfg80211_ops = { |
1459 | .change_virtual_intf = ath6kl_cfg80211_change_iface, | 1809 | .change_virtual_intf = ath6kl_cfg80211_change_iface, |
1460 | .scan = ath6kl_cfg80211_scan, | 1810 | .scan = ath6kl_cfg80211_scan, |
@@ -1474,12 +1824,26 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { | |||
1474 | .set_pmksa = ath6kl_set_pmksa, | 1824 | .set_pmksa = ath6kl_set_pmksa, |
1475 | .del_pmksa = ath6kl_del_pmksa, | 1825 | .del_pmksa = ath6kl_del_pmksa, |
1476 | .flush_pmksa = ath6kl_flush_pmksa, | 1826 | .flush_pmksa = ath6kl_flush_pmksa, |
1827 | CFG80211_TESTMODE_CMD(ath6kl_tm_cmd) | ||
1828 | #ifdef CONFIG_PM | ||
1829 | .suspend = ar6k_cfg80211_suspend, | ||
1830 | #endif | ||
1831 | .set_channel = ath6kl_set_channel, | ||
1832 | .add_beacon = ath6kl_add_beacon, | ||
1833 | .set_beacon = ath6kl_set_beacon, | ||
1834 | .del_beacon = ath6kl_del_beacon, | ||
1835 | .change_station = ath6kl_change_station, | ||
1836 | .remain_on_channel = ath6kl_remain_on_channel, | ||
1837 | .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, | ||
1838 | .mgmt_tx = ath6kl_mgmt_tx, | ||
1839 | .mgmt_frame_register = ath6kl_mgmt_frame_register, | ||
1477 | }; | 1840 | }; |
1478 | 1841 | ||
1479 | struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) | 1842 | struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) |
1480 | { | 1843 | { |
1481 | int ret = 0; | 1844 | int ret = 0; |
1482 | struct wireless_dev *wdev; | 1845 | struct wireless_dev *wdev; |
1846 | struct ath6kl *ar; | ||
1483 | 1847 | ||
1484 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 1848 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); |
1485 | if (!wdev) { | 1849 | if (!wdev) { |
@@ -1495,13 +1859,25 @@ struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) | |||
1495 | return NULL; | 1859 | return NULL; |
1496 | } | 1860 | } |
1497 | 1861 | ||
1862 | ar = wiphy_priv(wdev->wiphy); | ||
1863 | ar->p2p = !!ath6kl_p2p; | ||
1864 | |||
1865 | wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes; | ||
1866 | |||
1867 | wdev->wiphy->max_remain_on_channel_duration = 5000; | ||
1868 | |||
1498 | /* set device pointer for wiphy */ | 1869 | /* set device pointer for wiphy */ |
1499 | set_wiphy_dev(wdev->wiphy, dev); | 1870 | set_wiphy_dev(wdev->wiphy, dev); |
1500 | 1871 | ||
1501 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 1872 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
1502 | BIT(NL80211_IFTYPE_ADHOC); | 1873 | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); |
1874 | if (ar->p2p) { | ||
1875 | wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | | ||
1876 | BIT(NL80211_IFTYPE_P2P_CLIENT); | ||
1877 | } | ||
1503 | /* max num of ssids that can be probed during scanning */ | 1878 | /* max num of ssids that can be probed during scanning */ |
1504 | wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; | 1879 | wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; |
1880 | wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ | ||
1505 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; | 1881 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; |
1506 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; | 1882 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; |
1507 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 1883 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |