diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-02-18 13:47:13 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-18 13:47:13 -0500 |
commit | 98d5fac2330779e6eea6431a90b44c7476260dcc (patch) | |
tree | 99870656d835fc6c12093bc67517956cc7b3d6ec | |
parent | 4153577a8d318ae02b3791341e10e78416de402f (diff) | |
parent | 9e97d14b4923da524d202f2e005d5d30b70db9d6 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/ti/wlcore/sdio.c
drivers/net/wireless/ti/wlcore/spi.c
189 files changed, 12384 insertions, 3233 deletions
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 3985f35aee06..a4ca63ba7faa 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c | |||
@@ -309,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] = { | |||
309 | .gpio_wp = 63, | 309 | .gpio_wp = 63, |
310 | .deferred = true, | 310 | .deferred = true, |
311 | }, | 311 | }, |
312 | #ifdef CONFIG_WL12XX_PLATFORM_DATA | 312 | #ifdef CONFIG_WILINK_PLATFORM_DATA |
313 | { | 313 | { |
314 | .name = "wl1271", | 314 | .name = "wl1271", |
315 | .mmc = 2, | 315 | .mmc = 2, |
@@ -450,7 +450,7 @@ static struct regulator_init_data omap3evm_vio = { | |||
450 | .consumer_supplies = omap3evm_vio_supply, | 450 | .consumer_supplies = omap3evm_vio_supply, |
451 | }; | 451 | }; |
452 | 452 | ||
453 | #ifdef CONFIG_WL12XX_PLATFORM_DATA | 453 | #ifdef CONFIG_WILINK_PLATFORM_DATA |
454 | 454 | ||
455 | #define OMAP3EVM_WLAN_PMENA_GPIO (150) | 455 | #define OMAP3EVM_WLAN_PMENA_GPIO (150) |
456 | #define OMAP3EVM_WLAN_IRQ_GPIO (149) | 456 | #define OMAP3EVM_WLAN_IRQ_GPIO (149) |
@@ -563,7 +563,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = { | |||
563 | OMAP_PIN_OFF_NONE), | 563 | OMAP_PIN_OFF_NONE), |
564 | OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | | 564 | OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | |
565 | OMAP_PIN_OFF_NONE), | 565 | OMAP_PIN_OFF_NONE), |
566 | #ifdef CONFIG_WL12XX_PLATFORM_DATA | 566 | #ifdef CONFIG_WILINK_PLATFORM_DATA |
567 | /* WLAN IRQ - GPIO 149 */ | 567 | /* WLAN IRQ - GPIO 149 */ |
568 | OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), | 568 | OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), |
569 | 569 | ||
@@ -601,7 +601,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = { | |||
601 | OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | 601 | OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), |
602 | OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | 602 | OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), |
603 | OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | 603 | OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), |
604 | #ifdef CONFIG_WL12XX_PLATFORM_DATA | 604 | #ifdef CONFIG_WILINK_PLATFORM_DATA |
605 | /* WLAN IRQ - GPIO 149 */ | 605 | /* WLAN IRQ - GPIO 149 */ |
606 | OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), | 606 | OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), |
607 | 607 | ||
@@ -637,7 +637,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = { | |||
637 | 637 | ||
638 | static void __init omap3_evm_wl12xx_init(void) | 638 | static void __init omap3_evm_wl12xx_init(void) |
639 | { | 639 | { |
640 | #ifdef CONFIG_WL12XX_PLATFORM_DATA | 640 | #ifdef CONFIG_WILINK_PLATFORM_DATA |
641 | int ret; | 641 | int ret; |
642 | 642 | ||
643 | /* WL12xx WLAN Init */ | 643 | /* WL12xx WLAN Init */ |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index ab363f34b4df..a78afa98c650 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -1613,6 +1613,10 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah) | |||
1613 | ah->ah_cal_mask |= AR5K_CALIBRATION_NF; | 1613 | ah->ah_cal_mask |= AR5K_CALIBRATION_NF; |
1614 | 1614 | ||
1615 | ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); | 1615 | ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); |
1616 | if (WARN_ON(ee_mode < 0)) { | ||
1617 | ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF; | ||
1618 | return; | ||
1619 | } | ||
1616 | 1620 | ||
1617 | /* completed NF calibration, test threshold */ | 1621 | /* completed NF calibration, test threshold */ |
1618 | nf = ath5k_hw_read_measured_noise_floor(ah); | 1622 | nf = ath5k_hw_read_measured_noise_floor(ah); |
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 4084b1076286..e2d8b2cf19eb 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c | |||
@@ -985,6 +985,8 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, | |||
985 | return; | 985 | return; |
986 | 986 | ||
987 | ee_mode = ath5k_eeprom_mode_from_channel(channel); | 987 | ee_mode = ath5k_eeprom_mode_from_channel(channel); |
988 | if (WARN_ON(ee_mode < 0)) | ||
989 | return; | ||
988 | 990 | ||
989 | /* Adjust power delta for channel 14 */ | 991 | /* Adjust power delta for channel 14 */ |
990 | if (channel->center_freq == 2484) | 992 | if (channel->center_freq == 2484) |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 4225cca0f198..752ffc4f4166 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -427,6 +427,30 @@ static bool ath6kl_is_tx_pending(struct ath6kl *ar) | |||
427 | return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; | 427 | return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; |
428 | } | 428 | } |
429 | 429 | ||
430 | static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, | ||
431 | bool enable) | ||
432 | { | ||
433 | int err; | ||
434 | |||
435 | if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag))) | ||
436 | return; | ||
437 | |||
438 | if (vif->nw_type != INFRA_NETWORK) | ||
439 | return; | ||
440 | |||
441 | if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, | ||
442 | vif->ar->fw_capabilities)) | ||
443 | return; | ||
444 | |||
445 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n", | ||
446 | enable ? "enable" : "disable"); | ||
447 | |||
448 | err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi, | ||
449 | vif->fw_vif_idx, enable); | ||
450 | if (err) | ||
451 | ath6kl_err("failed to %s enhanced bmiss detection: %d\n", | ||
452 | enable ? "enable" : "disable", err); | ||
453 | } | ||
430 | 454 | ||
431 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | 455 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, |
432 | struct cfg80211_connect_params *sme) | 456 | struct cfg80211_connect_params *sme) |
@@ -616,13 +640,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
616 | vif->req_bssid, vif->ch_hint, | 640 | vif->req_bssid, vif->ch_hint, |
617 | ar->connect_ctrl_flags, nw_subtype); | 641 | ar->connect_ctrl_flags, nw_subtype); |
618 | 642 | ||
619 | /* disable background scan if period is 0 */ | 643 | if (sme->bg_scan_period == 0) { |
620 | if (sme->bg_scan_period == 0) | 644 | /* disable background scan if period is 0 */ |
621 | sme->bg_scan_period = 0xffff; | 645 | sme->bg_scan_period = 0xffff; |
622 | 646 | } else if (sme->bg_scan_period == -1) { | |
623 | /* configure default value if not specified */ | 647 | /* configure default value if not specified */ |
624 | if (sme->bg_scan_period == -1) | ||
625 | sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; | 648 | sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; |
649 | } | ||
626 | 650 | ||
627 | ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, | 651 | ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, |
628 | sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); | 652 | sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); |
@@ -767,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
767 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", | 791 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", |
768 | nw_type & ADHOC_CREATOR ? "creator" : "joiner"); | 792 | nw_type & ADHOC_CREATOR ? "creator" : "joiner"); |
769 | cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); | 793 | cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); |
770 | cfg80211_put_bss(bss); | 794 | cfg80211_put_bss(ar->wiphy, bss); |
771 | return; | 795 | return; |
772 | } | 796 | } |
773 | 797 | ||
@@ -778,7 +802,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
778 | assoc_req_ie, assoc_req_len, | 802 | assoc_req_ie, assoc_req_len, |
779 | assoc_resp_ie, assoc_resp_len, | 803 | assoc_resp_ie, assoc_resp_len, |
780 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | 804 | WLAN_STATUS_SUCCESS, GFP_KERNEL); |
781 | cfg80211_put_bss(bss); | 805 | cfg80211_put_bss(ar->wiphy, bss); |
782 | } else if (vif->sme_state == SME_CONNECTED) { | 806 | } else if (vif->sme_state == SME_CONNECTED) { |
783 | /* inform roam event to cfg80211 */ | 807 | /* inform roam event to cfg80211 */ |
784 | cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, | 808 | cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, |
@@ -1454,10 +1478,10 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | |||
1454 | return -EIO; | 1478 | return -EIO; |
1455 | 1479 | ||
1456 | if (pmgmt) { | 1480 | if (pmgmt) { |
1457 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); | 1481 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); |
1458 | mode.pwr_mode = REC_POWER; | 1482 | mode.pwr_mode = REC_POWER; |
1459 | } else { | 1483 | } else { |
1460 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); | 1484 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); |
1461 | mode.pwr_mode = MAX_PERF_POWER; | 1485 | mode.pwr_mode = MAX_PERF_POWER; |
1462 | } | 1486 | } |
1463 | 1487 | ||
@@ -1509,7 +1533,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, | |||
1509 | list_del(&vif->list); | 1533 | list_del(&vif->list); |
1510 | spin_unlock_bh(&ar->list_lock); | 1534 | spin_unlock_bh(&ar->list_lock); |
1511 | 1535 | ||
1512 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | 1536 | ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag)); |
1513 | 1537 | ||
1514 | ath6kl_cfg80211_vif_cleanup(vif); | 1538 | ath6kl_cfg80211_vif_cleanup(vif); |
1515 | 1539 | ||
@@ -1559,17 +1583,13 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, | |||
1559 | set_iface_type: | 1583 | set_iface_type: |
1560 | switch (type) { | 1584 | switch (type) { |
1561 | case NL80211_IFTYPE_STATION: | 1585 | case NL80211_IFTYPE_STATION: |
1586 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1562 | vif->next_mode = INFRA_NETWORK; | 1587 | vif->next_mode = INFRA_NETWORK; |
1563 | break; | 1588 | break; |
1564 | case NL80211_IFTYPE_ADHOC: | 1589 | case NL80211_IFTYPE_ADHOC: |
1565 | vif->next_mode = ADHOC_NETWORK; | 1590 | vif->next_mode = ADHOC_NETWORK; |
1566 | break; | 1591 | break; |
1567 | case NL80211_IFTYPE_AP: | 1592 | case NL80211_IFTYPE_AP: |
1568 | vif->next_mode = AP_NETWORK; | ||
1569 | break; | ||
1570 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1571 | vif->next_mode = INFRA_NETWORK; | ||
1572 | break; | ||
1573 | case NL80211_IFTYPE_P2P_GO: | 1593 | case NL80211_IFTYPE_P2P_GO: |
1574 | vif->next_mode = AP_NETWORK; | 1594 | vif->next_mode = AP_NETWORK; |
1575 | break; | 1595 | break; |
@@ -1778,14 +1798,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
1778 | 1798 | ||
1779 | if (vif->target_stats.rx_byte) { | 1799 | if (vif->target_stats.rx_byte) { |
1780 | sinfo->rx_bytes = vif->target_stats.rx_byte; | 1800 | sinfo->rx_bytes = vif->target_stats.rx_byte; |
1781 | sinfo->filled |= STATION_INFO_RX_BYTES; | 1801 | sinfo->filled |= STATION_INFO_RX_BYTES64; |
1782 | sinfo->rx_packets = vif->target_stats.rx_pkt; | 1802 | sinfo->rx_packets = vif->target_stats.rx_pkt; |
1783 | sinfo->filled |= STATION_INFO_RX_PACKETS; | 1803 | sinfo->filled |= STATION_INFO_RX_PACKETS; |
1784 | } | 1804 | } |
1785 | 1805 | ||
1786 | if (vif->target_stats.tx_byte) { | 1806 | if (vif->target_stats.tx_byte) { |
1787 | sinfo->tx_bytes = vif->target_stats.tx_byte; | 1807 | sinfo->tx_bytes = vif->target_stats.tx_byte; |
1788 | sinfo->filled |= STATION_INFO_TX_BYTES; | 1808 | sinfo->filled |= STATION_INFO_TX_BYTES64; |
1789 | sinfo->tx_packets = vif->target_stats.tx_pkt; | 1809 | sinfo->tx_packets = vif->target_stats.tx_pkt; |
1790 | sinfo->filled |= STATION_INFO_TX_PACKETS; | 1810 | sinfo->filled |= STATION_INFO_TX_PACKETS; |
1791 | } | 1811 | } |
@@ -2673,30 +2693,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, | |||
2673 | return 0; | 2693 | return 0; |
2674 | } | 2694 | } |
2675 | 2695 | ||
2676 | void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable) | ||
2677 | { | ||
2678 | int err; | ||
2679 | |||
2680 | if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag))) | ||
2681 | return; | ||
2682 | |||
2683 | if (vif->nw_type != INFRA_NETWORK) | ||
2684 | return; | ||
2685 | |||
2686 | if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, | ||
2687 | vif->ar->fw_capabilities)) | ||
2688 | return; | ||
2689 | |||
2690 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n", | ||
2691 | enable ? "enable" : "disable"); | ||
2692 | |||
2693 | err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi, | ||
2694 | vif->fw_vif_idx, enable); | ||
2695 | if (err) | ||
2696 | ath6kl_err("failed to %s enhanced bmiss detection: %d\n", | ||
2697 | enable ? "enable" : "disable", err); | ||
2698 | } | ||
2699 | |||
2700 | static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, | 2696 | static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, |
2701 | u8 *rsn_capab) | 2697 | u8 *rsn_capab) |
2702 | { | 2698 | { |
@@ -2776,9 +2772,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2776 | 2772 | ||
2777 | ar->ap_mode_bkey.valid = false; | 2773 | ar->ap_mode_bkey.valid = false; |
2778 | 2774 | ||
2779 | /* TODO: | 2775 | ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx, |
2780 | * info->interval | 2776 | info->beacon_interval); |
2781 | */ | 2777 | |
2778 | if (ret) | ||
2779 | ath6kl_warn("Failed to set beacon interval: %d\n", ret); | ||
2782 | 2780 | ||
2783 | ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx, | 2781 | ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx, |
2784 | info->dtim_period); | 2782 | info->dtim_period); |
@@ -3557,6 +3555,37 @@ static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) | |||
3557 | return 0; | 3555 | return 0; |
3558 | } | 3556 | } |
3559 | 3557 | ||
3558 | void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready) | ||
3559 | { | ||
3560 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
3561 | bool discon_issued; | ||
3562 | |||
3563 | netif_stop_queue(vif->ndev); | ||
3564 | |||
3565 | clear_bit(WLAN_ENABLED, &vif->flags); | ||
3566 | |||
3567 | if (wmi_ready) { | ||
3568 | discon_issued = test_bit(CONNECTED, &vif->flags) || | ||
3569 | test_bit(CONNECT_PEND, &vif->flags); | ||
3570 | ath6kl_disconnect(vif); | ||
3571 | del_timer(&vif->disconnect_timer); | ||
3572 | |||
3573 | if (discon_issued) | ||
3574 | ath6kl_disconnect_event(vif, DISCONNECT_CMD, | ||
3575 | (vif->nw_type & AP_NETWORK) ? | ||
3576 | bcast_mac : vif->bssid, | ||
3577 | 0, NULL, 0); | ||
3578 | } | ||
3579 | |||
3580 | if (vif->scan_req) { | ||
3581 | cfg80211_scan_done(vif->scan_req, true); | ||
3582 | vif->scan_req = NULL; | ||
3583 | } | ||
3584 | |||
3585 | /* need to clean up enhanced bmiss detection fw state */ | ||
3586 | ath6kl_cfg80211_sta_bmiss_enhance(vif, false); | ||
3587 | } | ||
3588 | |||
3560 | void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) | 3589 | void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) |
3561 | { | 3590 | { |
3562 | struct ath6kl *ar = vif->ar; | 3591 | struct ath6kl *ar = vif->ar; |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index e5e70f3a8ca8..b59becd91aea 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -61,7 +61,5 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar); | |||
61 | 61 | ||
62 | struct ath6kl *ath6kl_cfg80211_create(void); | 62 | struct ath6kl *ath6kl_cfg80211_create(void); |
63 | void ath6kl_cfg80211_destroy(struct ath6kl *ar); | 63 | void ath6kl_cfg80211_destroy(struct ath6kl *ar); |
64 | /* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */ | ||
65 | void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable); | ||
66 | 64 | ||
67 | #endif /* ATH6KL_CFG80211_H */ | 65 | #endif /* ATH6KL_CFG80211_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 189d8faf8c87..61b2f98b4e77 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -940,7 +940,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | |||
940 | bool wait_fot_compltn, bool cold_reset); | 940 | bool wait_fot_compltn, bool cold_reset); |
941 | void ath6kl_init_control_info(struct ath6kl_vif *vif); | 941 | void ath6kl_init_control_info(struct ath6kl_vif *vif); |
942 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); | 942 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); |
943 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); | 943 | void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready); |
944 | int ath6kl_init_hw_start(struct ath6kl *ar); | 944 | int ath6kl_init_hw_start(struct ath6kl *ar); |
945 | int ath6kl_init_hw_stop(struct ath6kl *ar); | 945 | int ath6kl_init_hw_stop(struct ath6kl *ar); |
946 | int ath6kl_init_fetch_firmwares(struct ath6kl *ar); | 946 | int ath6kl_init_fetch_firmwares(struct ath6kl *ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index ba6bd497b787..281390178e3d 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c | |||
@@ -509,9 +509,7 @@ static void destroy_htc_txctrl_packet(struct htc_packet *packet) | |||
509 | { | 509 | { |
510 | struct sk_buff *skb; | 510 | struct sk_buff *skb; |
511 | skb = packet->skb; | 511 | skb = packet->skb; |
512 | if (skb != NULL) | 512 | dev_kfree_skb(skb); |
513 | dev_kfree_skb(skb); | ||
514 | |||
515 | kfree(packet); | 513 | kfree(packet); |
516 | } | 514 | } |
517 | 515 | ||
@@ -969,6 +967,22 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, | |||
969 | u16 payload_len; | 967 | u16 payload_len; |
970 | int status = 0; | 968 | int status = 0; |
971 | 969 | ||
970 | /* | ||
971 | * ar->htc_target can be NULL due to a race condition that can occur | ||
972 | * during driver initialization(we do 'ath6kl_hif_power_on' before | ||
973 | * initializing 'ar->htc_target' via 'ath6kl_htc_create'). | ||
974 | * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as | ||
975 | * usb_complete_t/callback function for 'usb_fill_bulk_urb'. | ||
976 | * Thus the possibility of ar->htc_target being NULL | ||
977 | * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work. | ||
978 | */ | ||
979 | if (WARN_ON_ONCE(!target)) { | ||
980 | ath6kl_err("Target not yet initialized\n"); | ||
981 | status = -EINVAL; | ||
982 | goto free_skb; | ||
983 | } | ||
984 | |||
985 | |||
972 | netdata = skb->data; | 986 | netdata = skb->data; |
973 | netlen = skb->len; | 987 | netlen = skb->len; |
974 | 988 | ||
@@ -1054,6 +1068,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, | |||
1054 | 1068 | ||
1055 | dev_kfree_skb(skb); | 1069 | dev_kfree_skb(skb); |
1056 | skb = NULL; | 1070 | skb = NULL; |
1071 | |||
1057 | goto free_skb; | 1072 | goto free_skb; |
1058 | } | 1073 | } |
1059 | 1074 | ||
@@ -1089,8 +1104,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, | |||
1089 | skb = NULL; | 1104 | skb = NULL; |
1090 | 1105 | ||
1091 | free_skb: | 1106 | free_skb: |
1092 | if (skb != NULL) | 1107 | dev_kfree_skb(skb); |
1093 | dev_kfree_skb(skb); | ||
1094 | 1108 | ||
1095 | return status; | 1109 | return status; |
1096 | 1110 | ||
@@ -1184,7 +1198,7 @@ static void reset_endpoint_states(struct htc_target *target) | |||
1184 | INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue); | 1198 | INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue); |
1185 | INIT_LIST_HEAD(&ep->rx_bufq); | 1199 | INIT_LIST_HEAD(&ep->rx_bufq); |
1186 | ep->target = target; | 1200 | ep->target = target; |
1187 | ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */ | 1201 | ep->pipe.tx_credit_flow_enabled = true; |
1188 | } | 1202 | } |
1189 | } | 1203 | } |
1190 | 1204 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index f21fa322e5ca..5d434cf88f35 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -1715,38 +1715,6 @@ void ath6kl_init_hw_restart(struct ath6kl *ar) | |||
1715 | } | 1715 | } |
1716 | } | 1716 | } |
1717 | 1717 | ||
1718 | /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ | ||
1719 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) | ||
1720 | { | ||
1721 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
1722 | bool discon_issued; | ||
1723 | |||
1724 | netif_stop_queue(vif->ndev); | ||
1725 | |||
1726 | clear_bit(WLAN_ENABLED, &vif->flags); | ||
1727 | |||
1728 | if (wmi_ready) { | ||
1729 | discon_issued = test_bit(CONNECTED, &vif->flags) || | ||
1730 | test_bit(CONNECT_PEND, &vif->flags); | ||
1731 | ath6kl_disconnect(vif); | ||
1732 | del_timer(&vif->disconnect_timer); | ||
1733 | |||
1734 | if (discon_issued) | ||
1735 | ath6kl_disconnect_event(vif, DISCONNECT_CMD, | ||
1736 | (vif->nw_type & AP_NETWORK) ? | ||
1737 | bcast_mac : vif->bssid, | ||
1738 | 0, NULL, 0); | ||
1739 | } | ||
1740 | |||
1741 | if (vif->scan_req) { | ||
1742 | cfg80211_scan_done(vif->scan_req, true); | ||
1743 | vif->scan_req = NULL; | ||
1744 | } | ||
1745 | |||
1746 | /* need to clean up enhanced bmiss detection fw state */ | ||
1747 | ath6kl_cfg80211_sta_bmiss_enhance(vif, false); | ||
1748 | } | ||
1749 | |||
1750 | void ath6kl_stop_txrx(struct ath6kl *ar) | 1718 | void ath6kl_stop_txrx(struct ath6kl *ar) |
1751 | { | 1719 | { |
1752 | struct ath6kl_vif *vif, *tmp_vif; | 1720 | struct ath6kl_vif *vif, *tmp_vif; |
@@ -1766,7 +1734,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | |||
1766 | list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { | 1734 | list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { |
1767 | list_del(&vif->list); | 1735 | list_del(&vif->list); |
1768 | spin_unlock_bh(&ar->list_lock); | 1736 | spin_unlock_bh(&ar->list_lock); |
1769 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | 1737 | ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag)); |
1770 | rtnl_lock(); | 1738 | rtnl_lock(); |
1771 | ath6kl_cfg80211_vif_cleanup(vif); | 1739 | ath6kl_cfg80211_vif_cleanup(vif); |
1772 | rtnl_unlock(); | 1740 | rtnl_unlock(); |
@@ -1801,8 +1769,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | |||
1801 | "attempting to reset target on instance destroy\n"); | 1769 | "attempting to reset target on instance destroy\n"); |
1802 | ath6kl_reset_device(ar, ar->target_type, true, true); | 1770 | ath6kl_reset_device(ar, ar->target_type, true, true); |
1803 | 1771 | ||
1804 | clear_bit(WLAN_ENABLED, &ar->flag); | ||
1805 | |||
1806 | up(&ar->sem); | 1772 | up(&ar->sem); |
1807 | } | 1773 | } |
1808 | EXPORT_SYMBOL(ath6kl_stop_txrx); | 1774 | EXPORT_SYMBOL(ath6kl_stop_txrx); |
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 62bcc0d5bc23..5fcd342762de 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c | |||
@@ -159,10 +159,8 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, | |||
159 | 159 | ||
160 | static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) | 160 | static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) |
161 | { | 161 | { |
162 | if (urb_context->skb != NULL) { | 162 | dev_kfree_skb(urb_context->skb); |
163 | dev_kfree_skb(urb_context->skb); | 163 | urb_context->skb = NULL; |
164 | urb_context->skb = NULL; | ||
165 | } | ||
166 | 164 | ||
167 | ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); | 165 | ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); |
168 | } | 166 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 998f8b0f62fd..d76b5bd81a0d 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -751,6 +751,23 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid) | |||
751 | NO_SYNC_WMIFLAG); | 751 | NO_SYNC_WMIFLAG); |
752 | } | 752 | } |
753 | 753 | ||
754 | int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx, | ||
755 | u32 beacon_intvl) | ||
756 | { | ||
757 | struct sk_buff *skb; | ||
758 | struct set_beacon_int_cmd *cmd; | ||
759 | |||
760 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
761 | if (!skb) | ||
762 | return -ENOMEM; | ||
763 | |||
764 | cmd = (struct set_beacon_int_cmd *) skb->data; | ||
765 | |||
766 | cmd->beacon_intvl = cpu_to_le32(beacon_intvl); | ||
767 | return ath6kl_wmi_cmd_send(wmi, if_idx, skb, | ||
768 | WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG); | ||
769 | } | ||
770 | |||
754 | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period) | 771 | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period) |
755 | { | 772 | { |
756 | struct sk_buff *skb; | 773 | struct sk_buff *skb; |
@@ -1108,7 +1125,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, | |||
1108 | kfree(mgmt); | 1125 | kfree(mgmt); |
1109 | if (bss == NULL) | 1126 | if (bss == NULL) |
1110 | return -ENOMEM; | 1127 | return -ENOMEM; |
1111 | cfg80211_put_bss(bss); | 1128 | cfg80211_put_bss(ar->wiphy, bss); |
1112 | 1129 | ||
1113 | /* | 1130 | /* |
1114 | * Firmware doesn't return any event when scheduled scan has | 1131 | * Firmware doesn't return any event when scheduled scan has |
@@ -2480,16 +2497,11 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) | |||
2480 | 2497 | ||
2481 | free_cmd_skb: | 2498 | free_cmd_skb: |
2482 | /* free up any resources left over (possibly due to an error) */ | 2499 | /* free up any resources left over (possibly due to an error) */ |
2483 | if (skb) | 2500 | dev_kfree_skb(skb); |
2484 | dev_kfree_skb(skb); | ||
2485 | 2501 | ||
2486 | free_data_skb: | 2502 | free_data_skb: |
2487 | for (index = 0; index < num_pri_streams; index++) { | 2503 | for (index = 0; index < num_pri_streams; index++) |
2488 | if (data_sync_bufs[index].skb != NULL) { | 2504 | dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb); |
2489 | dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. | ||
2490 | skb); | ||
2491 | } | ||
2492 | } | ||
2493 | 2505 | ||
2494 | return ret; | 2506 | return ret; |
2495 | } | 2507 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 98b1755e67f4..b5f226503baf 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -1660,6 +1660,10 @@ struct roam_ctrl_cmd { | |||
1660 | u8 roam_ctrl; | 1660 | u8 roam_ctrl; |
1661 | } __packed; | 1661 | } __packed; |
1662 | 1662 | ||
1663 | struct set_beacon_int_cmd { | ||
1664 | __le32 beacon_intvl; | ||
1665 | } __packed; | ||
1666 | |||
1663 | struct set_dtim_cmd { | 1667 | struct set_dtim_cmd { |
1664 | __le32 dtim_period; | 1668 | __le32 dtim_period; |
1665 | } __packed; | 1669 | } __packed; |
@@ -2649,6 +2653,8 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | |||
2649 | int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); | 2653 | int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); |
2650 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); | 2654 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); |
2651 | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); | 2655 | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); |
2656 | int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx, | ||
2657 | u32 beacon_interval); | ||
2652 | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); | 2658 | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); |
2653 | int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); | 2659 | int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); |
2654 | int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); | 2660 | int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 97c90b21e1cb..a56b2416e2f9 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -389,6 +389,7 @@ struct ath_beacon_config { | |||
389 | u16 bmiss_timeout; | 389 | u16 bmiss_timeout; |
390 | u8 dtim_count; | 390 | u8 dtim_count; |
391 | bool enable_beacon; | 391 | bool enable_beacon; |
392 | bool ibss_creator; | ||
392 | }; | 393 | }; |
393 | 394 | ||
394 | struct ath_beacon { | 395 | struct ath_beacon { |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index dd3771954bd7..5f05c26d1ec4 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -407,12 +407,17 @@ void ath9k_beacon_tasklet(unsigned long data) | |||
407 | } | 407 | } |
408 | } | 408 | } |
409 | 409 | ||
410 | static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval) | 410 | /* |
411 | * Both nexttbtt and intval have to be in usecs. | ||
412 | */ | ||
413 | static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, | ||
414 | u32 intval, bool reset_tsf) | ||
411 | { | 415 | { |
412 | struct ath_hw *ah = sc->sc_ah; | 416 | struct ath_hw *ah = sc->sc_ah; |
413 | 417 | ||
414 | ath9k_hw_disable_interrupts(ah); | 418 | ath9k_hw_disable_interrupts(ah); |
415 | ath9k_hw_reset_tsf(ah); | 419 | if (reset_tsf) |
420 | ath9k_hw_reset_tsf(ah); | ||
416 | ath9k_beaconq_config(sc); | 421 | ath9k_beaconq_config(sc); |
417 | ath9k_hw_beaconinit(ah, nexttbtt, intval); | 422 | ath9k_hw_beaconinit(ah, nexttbtt, intval); |
418 | sc->beacon.bmisscnt = 0; | 423 | sc->beacon.bmisscnt = 0; |
@@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, | |||
442 | else | 447 | else |
443 | ah->imask &= ~ATH9K_INT_SWBA; | 448 | ah->imask &= ~ATH9K_INT_SWBA; |
444 | 449 | ||
445 | ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n", | 450 | ath_dbg(common, BEACON, |
451 | "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", | ||
452 | (conf->enable_beacon) ? "Enable" : "Disable", | ||
446 | nexttbtt, intval, conf->beacon_interval); | 453 | nexttbtt, intval, conf->beacon_interval); |
447 | 454 | ||
448 | ath9k_beacon_init(sc, nexttbtt, intval); | 455 | ath9k_beacon_init(sc, nexttbtt, intval, true); |
449 | } | 456 | } |
450 | 457 | ||
451 | /* | 458 | /* |
@@ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, | |||
586 | ath9k_reset_beacon_status(sc); | 593 | ath9k_reset_beacon_status(sc); |
587 | 594 | ||
588 | intval = TU_TO_USEC(conf->beacon_interval); | 595 | intval = TU_TO_USEC(conf->beacon_interval); |
589 | nexttbtt = intval; | 596 | |
597 | if (conf->ibss_creator) { | ||
598 | nexttbtt = intval; | ||
599 | } else { | ||
600 | u32 tbtt, offset, tsftu; | ||
601 | u64 tsf; | ||
602 | |||
603 | /* | ||
604 | * Pull nexttbtt forward to reflect the current | ||
605 | * sync'd TSF. | ||
606 | */ | ||
607 | tsf = ath9k_hw_gettsf64(ah); | ||
608 | tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; | ||
609 | offset = tsftu % conf->beacon_interval; | ||
610 | tbtt = tsftu - offset; | ||
611 | if (offset) | ||
612 | tbtt += conf->beacon_interval; | ||
613 | |||
614 | nexttbtt = TU_TO_USEC(tbtt); | ||
615 | } | ||
590 | 616 | ||
591 | if (conf->enable_beacon) | 617 | if (conf->enable_beacon) |
592 | ah->imask |= ATH9K_INT_SWBA; | 618 | ah->imask |= ATH9K_INT_SWBA; |
593 | else | 619 | else |
594 | ah->imask &= ~ATH9K_INT_SWBA; | 620 | ah->imask &= ~ATH9K_INT_SWBA; |
595 | 621 | ||
596 | ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n", | 622 | ath_dbg(common, BEACON, |
623 | "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", | ||
624 | (conf->enable_beacon) ? "Enable" : "Disable", | ||
597 | nexttbtt, intval, conf->beacon_interval); | 625 | nexttbtt, intval, conf->beacon_interval); |
598 | 626 | ||
599 | ath9k_beacon_init(sc, nexttbtt, intval); | 627 | ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); |
628 | |||
629 | /* | ||
630 | * Set the global 'beacon has been configured' flag for the | ||
631 | * joiner case in IBSS mode. | ||
632 | */ | ||
633 | if (!conf->ibss_creator && conf->enable_beacon) | ||
634 | set_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
600 | } | 635 | } |
601 | 636 | ||
602 | bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | 637 | bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) |
@@ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, | |||
639 | cur_conf->dtim_period = bss_conf->dtim_period; | 674 | cur_conf->dtim_period = bss_conf->dtim_period; |
640 | cur_conf->listen_interval = 1; | 675 | cur_conf->listen_interval = 1; |
641 | cur_conf->dtim_count = 1; | 676 | cur_conf->dtim_count = 1; |
677 | cur_conf->ibss_creator = bss_conf->ibss_creator; | ||
642 | cur_conf->bmiss_timeout = | 678 | cur_conf->bmiss_timeout = |
643 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | 679 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; |
644 | 680 | ||
@@ -666,34 +702,59 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
666 | { | 702 | { |
667 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 703 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
668 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 704 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; |
705 | unsigned long flags; | ||
706 | bool skip_beacon = false; | ||
669 | 707 | ||
670 | if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { | 708 | if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { |
671 | ath9k_cache_beacon_config(sc, bss_conf); | 709 | ath9k_cache_beacon_config(sc, bss_conf); |
672 | ath9k_set_beacon(sc); | 710 | ath9k_set_beacon(sc); |
673 | set_bit(SC_OP_BEACONS, &sc->sc_flags); | 711 | set_bit(SC_OP_BEACONS, &sc->sc_flags); |
674 | } else { | 712 | return; |
675 | /* | 713 | |
676 | * Take care of multiple interfaces when | 714 | } |
677 | * enabling/disabling SWBA. | 715 | |
678 | */ | 716 | /* |
679 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 717 | * Take care of multiple interfaces when |
680 | if (!bss_conf->enable_beacon && | 718 | * enabling/disabling SWBA. |
681 | (sc->nbcnvifs <= 1)) { | 719 | */ |
682 | cur_conf->enable_beacon = false; | 720 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
683 | } else if (bss_conf->enable_beacon) { | 721 | if (!bss_conf->enable_beacon && |
684 | cur_conf->enable_beacon = true; | 722 | (sc->nbcnvifs <= 1)) { |
685 | ath9k_cache_beacon_config(sc, bss_conf); | 723 | cur_conf->enable_beacon = false; |
686 | } | 724 | } else if (bss_conf->enable_beacon) { |
725 | cur_conf->enable_beacon = true; | ||
726 | ath9k_cache_beacon_config(sc, bss_conf); | ||
687 | } | 727 | } |
728 | } | ||
688 | 729 | ||
689 | if (cur_conf->beacon_interval) { | 730 | /* |
731 | * Configure the HW beacon registers only when we have a valid | ||
732 | * beacon interval. | ||
733 | */ | ||
734 | if (cur_conf->beacon_interval) { | ||
735 | /* | ||
736 | * If we are joining an existing IBSS network, start beaconing | ||
737 | * only after a TSF-sync has taken place. Ensure that this | ||
738 | * happens by setting the appropriate flags. | ||
739 | */ | ||
740 | if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator && | ||
741 | bss_conf->enable_beacon) { | ||
742 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | ||
743 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | ||
744 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
745 | skip_beacon = true; | ||
746 | } else { | ||
690 | ath9k_set_beacon(sc); | 747 | ath9k_set_beacon(sc); |
691 | |||
692 | if (cur_conf->enable_beacon) | ||
693 | set_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
694 | else | ||
695 | clear_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
696 | } | 748 | } |
749 | |||
750 | /* | ||
751 | * Do not set the SC_OP_BEACONS flag for IBSS joiner mode | ||
752 | * here, it is done in ath9k_beacon_config_adhoc(). | ||
753 | */ | ||
754 | if (cur_conf->enable_beacon && !skip_beacon) | ||
755 | set_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
756 | else | ||
757 | clear_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
697 | } | 758 | } |
698 | } | 759 | } |
699 | 760 | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5432f1247e2e..6e66f9c6782b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -320,28 +320,25 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
320 | struct ieee80211_vif *vif) | 320 | struct ieee80211_vif *vif) |
321 | { | 321 | { |
322 | struct ath_node *an; | 322 | struct ath_node *an; |
323 | u8 density; | ||
324 | an = (struct ath_node *)sta->drv_priv; | 323 | an = (struct ath_node *)sta->drv_priv; |
325 | 324 | ||
326 | an->sc = sc; | 325 | an->sc = sc; |
327 | an->sta = sta; | 326 | an->sta = sta; |
328 | an->vif = vif; | 327 | an->vif = vif; |
329 | 328 | ||
330 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 329 | ath_tx_node_init(sc, an); |
331 | ath_tx_node_init(sc, an); | 330 | |
331 | if (sta->ht_cap.ht_supported) { | ||
332 | an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | 332 | an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + |
333 | sta->ht_cap.ampdu_factor); | 333 | sta->ht_cap.ampdu_factor); |
334 | density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); | 334 | an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); |
335 | an->mpdudensity = density; | ||
336 | } | 335 | } |
337 | } | 336 | } |
338 | 337 | ||
339 | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | 338 | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) |
340 | { | 339 | { |
341 | struct ath_node *an = (struct ath_node *)sta->drv_priv; | 340 | struct ath_node *an = (struct ath_node *)sta->drv_priv; |
342 | 341 | ath_tx_node_cleanup(sc, an); | |
343 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | ||
344 | ath_tx_node_cleanup(sc, an); | ||
345 | } | 342 | } |
346 | 343 | ||
347 | void ath9k_tasklet(unsigned long data) | 344 | void ath9k_tasklet(unsigned long data) |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index faa752b95d5a..96ac433ba7f6 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
1204 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; | 1204 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; |
1205 | else if (sta->ht_cap.mcs.rx_mask[1]) | 1205 | else if (sta->ht_cap.mcs.rx_mask[1]) |
1206 | caps |= WLAN_RC_DS_FLAG; | 1206 | caps |= WLAN_RC_DS_FLAG; |
1207 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 1207 | if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { |
1208 | caps |= WLAN_RC_40_FLAG; | 1208 | caps |= WLAN_RC_40_FLAG; |
1209 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | 1209 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) |
1210 | caps |= WLAN_RC_SGI_FLAG; | 1210 | caps |= WLAN_RC_SGI_FLAG; |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2d0fd17a1917..ee156e543147 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
533 | if (sc->ps_flags & PS_BEACON_SYNC) { | 533 | if (sc->ps_flags & PS_BEACON_SYNC) { |
534 | sc->ps_flags &= ~PS_BEACON_SYNC; | 534 | sc->ps_flags &= ~PS_BEACON_SYNC; |
535 | ath_dbg(common, PS, | 535 | ath_dbg(common, PS, |
536 | "Reconfigure Beacon timers based on timestamp from the AP\n"); | 536 | "Reconfigure beacon timers based on synchronized timestamp\n"); |
537 | ath9k_set_beacon(sc); | 537 | ath9k_set_beacon(sc); |
538 | } | 538 | } |
539 | 539 | ||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index feacaafee959..89a64411b82e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1233,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
1233 | * in HT IBSS when a beacon with HT-info is received after the station | 1233 | * in HT IBSS when a beacon with HT-info is received after the station |
1234 | * has already been added. | 1234 | * has already been added. |
1235 | */ | 1235 | */ |
1236 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 1236 | if (sta->ht_cap.ht_supported) { |
1237 | an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | 1237 | an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + |
1238 | sta->ht_cap.ampdu_factor); | 1238 | sta->ht_cap.ampdu_factor); |
1239 | density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); | 1239 | density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); |
@@ -1904,8 +1904,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, | |||
1904 | struct ath_buf *bf; | 1904 | struct ath_buf *bf; |
1905 | u8 tidno; | 1905 | u8 tidno; |
1906 | 1906 | ||
1907 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an && | 1907 | if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { |
1908 | ieee80211_is_data_qos(hdr->frame_control)) { | ||
1909 | tidno = ieee80211_get_qos_ctl(hdr)[0] & | 1908 | tidno = ieee80211_get_qos_ctl(hdr)[0] & |
1910 | IEEE80211_QOS_CTL_TID_MASK; | 1909 | IEEE80211_QOS_CTL_TID_MASK; |
1911 | tid = ATH_AN_2_TID(txctl->an, tidno); | 1910 | tid = ATH_AN_2_TID(txctl->an, tidno); |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ef82751722e0..f293b3ff4756 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1853,7 +1853,7 @@ void *carl9170_alloc(size_t priv_size) | |||
1853 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 1853 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
1854 | IEEE80211_HW_SUPPORTS_PS | | 1854 | IEEE80211_HW_SUPPORTS_PS | |
1855 | IEEE80211_HW_PS_NULLFUNC_STACK | | 1855 | IEEE80211_HW_PS_NULLFUNC_STACK | |
1856 | IEEE80211_HW_NEED_DTIM_PERIOD | | 1856 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | |
1857 | IEEE80211_HW_SIGNAL_DBM; | 1857 | IEEE80211_HW_SIGNAL_DBM; |
1858 | 1858 | ||
1859 | if (!modparam_noht) { | 1859 | if (!modparam_noht) { |
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 002851fceb2f..9ecc1968262c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -341,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, | |||
341 | } | 341 | } |
342 | 342 | ||
343 | out: | 343 | out: |
344 | cfg80211_put_bss(bss); | 344 | cfg80211_put_bss(wiphy, bss); |
345 | 345 | ||
346 | return rc; | 346 | return rc; |
347 | } | 347 | } |
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c8aca3d50089..0bb3b76b4b58 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -338,7 +338,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
338 | if (bss) { | 338 | if (bss) { |
339 | wil_dbg_wmi(wil, "Added BSS %pM\n", | 339 | wil_dbg_wmi(wil, "Added BSS %pM\n", |
340 | rx_mgmt_frame->bssid); | 340 | rx_mgmt_frame->bssid); |
341 | cfg80211_put_bss(bss); | 341 | cfg80211_put_bss(wiphy, bss); |
342 | } else { | 342 | } else { |
343 | wil_err(wil, "cfg80211_inform_bss() failed\n"); | 343 | wil_err(wil, "cfg80211_inform_bss() failed\n"); |
344 | } | 344 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 1a6661a9f008..756e19fc2795 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile | |||
@@ -26,6 +26,7 @@ brcmfmac-objs += \ | |||
26 | wl_cfg80211.o \ | 26 | wl_cfg80211.o \ |
27 | fwil.o \ | 27 | fwil.o \ |
28 | fweh.o \ | 28 | fweh.o \ |
29 | p2p.o \ | ||
29 | dhd_cdc.o \ | 30 | dhd_cdc.o \ |
30 | dhd_common.o \ | 31 | dhd_common.o \ |
31 | dhd_linux.o | 32 | dhd_linux.o |
@@ -37,4 +38,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ | |||
37 | brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ | 38 | brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ |
38 | usb.o | 39 | usb.o |
39 | brcmfmac-$(CONFIG_BRCMDBG) += \ | 40 | brcmfmac-$(CONFIG_BRCMDBG) += \ |
40 | dhd_dbg.o \ No newline at end of file | 41 | dhd_dbg.o |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index a2f32fb990fa..ef6f23be6d32 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h | |||
@@ -72,6 +72,7 @@ | |||
72 | #define BRCMF_C_SET_WSEC 134 | 72 | #define BRCMF_C_SET_WSEC 134 |
73 | #define BRCMF_C_GET_PHY_NOISE 135 | 73 | #define BRCMF_C_GET_PHY_NOISE 135 |
74 | #define BRCMF_C_GET_BSS_INFO 136 | 74 | #define BRCMF_C_GET_BSS_INFO 136 |
75 | #define BRCMF_C_SET_SCB_TIMEOUT 158 | ||
75 | #define BRCMF_C_GET_PHYLIST 180 | 76 | #define BRCMF_C_GET_PHYLIST 180 |
76 | #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 | 77 | #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 |
77 | #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 | 78 | #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 |
@@ -149,6 +150,7 @@ | |||
149 | #define BRCMF_E_REASON_MINTXRATE 9 | 150 | #define BRCMF_E_REASON_MINTXRATE 9 |
150 | #define BRCMF_E_REASON_TXFAIL 10 | 151 | #define BRCMF_E_REASON_TXFAIL 10 |
151 | 152 | ||
153 | #define BRCMF_E_REASON_LINK_BSSCFG_DIS 4 | ||
152 | #define BRCMF_E_REASON_FAST_ROAM_FAILED 5 | 154 | #define BRCMF_E_REASON_FAST_ROAM_FAILED 5 |
153 | #define BRCMF_E_REASON_DIRECTED_ROAM 6 | 155 | #define BRCMF_E_REASON_DIRECTED_ROAM 6 |
154 | #define BRCMF_E_REASON_TSPEC_REJECTED 7 | 156 | #define BRCMF_E_REASON_TSPEC_REJECTED 7 |
@@ -375,6 +377,28 @@ struct brcmf_join_params { | |||
375 | struct brcmf_assoc_params_le params_le; | 377 | struct brcmf_assoc_params_le params_le; |
376 | }; | 378 | }; |
377 | 379 | ||
380 | /* scan params for extended join */ | ||
381 | struct brcmf_join_scan_params_le { | ||
382 | u8 scan_type; /* 0 use default, active or passive scan */ | ||
383 | __le32 nprobes; /* -1 use default, nr of probes per channel */ | ||
384 | __le32 active_time; /* -1 use default, dwell time per channel for | ||
385 | * active scanning | ||
386 | */ | ||
387 | __le32 passive_time; /* -1 use default, dwell time per channel | ||
388 | * for passive scanning | ||
389 | */ | ||
390 | __le32 home_time; /* -1 use default, dwell time for the home | ||
391 | * channel between channel scans | ||
392 | */ | ||
393 | }; | ||
394 | |||
395 | /* extended join params */ | ||
396 | struct brcmf_ext_join_params_le { | ||
397 | struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */ | ||
398 | struct brcmf_join_scan_params_le scan_le; | ||
399 | struct brcmf_assoc_params_le assoc_le; | ||
400 | }; | ||
401 | |||
378 | struct brcmf_wsec_key { | 402 | struct brcmf_wsec_key { |
379 | u32 index; /* key index */ | 403 | u32 index; /* key index */ |
380 | u32 len; /* key length */ | 404 | u32 len; /* key length */ |
@@ -451,6 +475,19 @@ struct brcmf_sta_info_le { | |||
451 | __le32 rx_decrypt_failures; /* # of packet decrypted failed */ | 475 | __le32 rx_decrypt_failures; /* # of packet decrypted failed */ |
452 | }; | 476 | }; |
453 | 477 | ||
478 | /* | ||
479 | * WLC_E_PROBRESP_MSG | ||
480 | * WLC_E_P2P_PROBREQ_MSG | ||
481 | * WLC_E_ACTION_FRAME_RX | ||
482 | */ | ||
483 | struct brcmf_rx_mgmt_data { | ||
484 | __be16 version; | ||
485 | __be16 chanspec; | ||
486 | __be32 rssi; | ||
487 | __be32 mactime; | ||
488 | __be32 rate; | ||
489 | }; | ||
490 | |||
454 | /* Bus independent dongle command */ | 491 | /* Bus independent dongle command */ |
455 | struct brcmf_dcmd { | 492 | struct brcmf_dcmd { |
456 | uint cmd; /* common dongle cmd definition */ | 493 | uint cmd; /* common dongle cmd definition */ |
@@ -489,9 +526,6 @@ struct brcmf_pub { | |||
489 | struct mutex proto_block; | 526 | struct mutex proto_block; |
490 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; | 527 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; |
491 | 528 | ||
492 | atomic_t pend_8021x_cnt; | ||
493 | wait_queue_head_t pend_8021x_wait; | ||
494 | |||
495 | struct brcmf_fweh_info fweh; | 529 | struct brcmf_fweh_info fweh; |
496 | #ifdef DEBUG | 530 | #ifdef DEBUG |
497 | struct dentry *dbgfs_dir; | 531 | struct dentry *dbgfs_dir; |
@@ -515,9 +549,11 @@ struct brcmf_cfg80211_vif; | |||
515 | * @vif: points to cfg80211 specific interface information. | 549 | * @vif: points to cfg80211 specific interface information. |
516 | * @ndev: associated network device. | 550 | * @ndev: associated network device. |
517 | * @stats: interface specific network statistics. | 551 | * @stats: interface specific network statistics. |
518 | * @idx: interface index in device firmware. | 552 | * @ifidx: interface index in device firmware. |
519 | * @bssidx: index of bss associated with this interface. | 553 | * @bssidx: index of bss associated with this interface. |
520 | * @mac_addr: assigned mac address. | 554 | * @mac_addr: assigned mac address. |
555 | * @pend_8021x_cnt: tracks outstanding number of 802.1x frames. | ||
556 | * @pend_8021x_wait: used for signalling change in count. | ||
521 | */ | 557 | */ |
522 | struct brcmf_if { | 558 | struct brcmf_if { |
523 | struct brcmf_pub *drvr; | 559 | struct brcmf_pub *drvr; |
@@ -526,9 +562,11 @@ struct brcmf_if { | |||
526 | struct net_device_stats stats; | 562 | struct net_device_stats stats; |
527 | struct work_struct setmacaddr_work; | 563 | struct work_struct setmacaddr_work; |
528 | struct work_struct multicast_work; | 564 | struct work_struct multicast_work; |
529 | int idx; | 565 | int ifidx; |
530 | s32 bssidx; | 566 | s32 bssidx; |
531 | u8 mac_addr[ETH_ALEN]; | 567 | u8 mac_addr[ETH_ALEN]; |
568 | atomic_t pend_8021x_cnt; | ||
569 | wait_queue_head_t pend_8021x_wait; | ||
532 | }; | 570 | }; |
533 | 571 | ||
534 | 572 | ||
@@ -547,9 +585,10 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, | |||
547 | extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | 585 | extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, |
548 | struct sk_buff *rxp); | 586 | struct sk_buff *rxp); |
549 | 587 | ||
550 | extern int brcmf_net_attach(struct brcmf_if *ifp); | 588 | extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); |
551 | extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, | 589 | extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, |
552 | s32 bssidx, char *name, u8 *mac_addr); | 590 | s32 ifidx, char *name, u8 *mac_addr); |
553 | extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); | 591 | extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); |
592 | extern u32 brcmf_get_chip_info(struct brcmf_if *ifp); | ||
554 | 593 | ||
555 | #endif /* _BRCMF_H_ */ | 594 | #endif /* _BRCMF_H_ */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 64c38f4226a3..ad25c3408b59 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | |||
@@ -24,18 +24,6 @@ enum brcmf_bus_state { | |||
24 | BRCMF_BUS_DATA /* Ready for frame transfers */ | 24 | BRCMF_BUS_DATA /* Ready for frame transfers */ |
25 | }; | 25 | }; |
26 | 26 | ||
27 | struct dngl_stats { | ||
28 | unsigned long rx_packets; /* total packets received */ | ||
29 | unsigned long tx_packets; /* total packets transmitted */ | ||
30 | unsigned long rx_bytes; /* total bytes received */ | ||
31 | unsigned long tx_bytes; /* total bytes transmitted */ | ||
32 | unsigned long rx_errors; /* bad packets received */ | ||
33 | unsigned long tx_errors; /* packet transmit problems */ | ||
34 | unsigned long rx_dropped; /* packets dropped by dongle */ | ||
35 | unsigned long tx_dropped; /* packets dropped by dongle */ | ||
36 | unsigned long multicast; /* multicast packets received */ | ||
37 | }; | ||
38 | |||
39 | struct brcmf_bus_dcmd { | 27 | struct brcmf_bus_dcmd { |
40 | char *name; | 28 | char *name; |
41 | char *param; | 29 | char *param; |
@@ -72,11 +60,12 @@ struct brcmf_bus_ops { | |||
72 | * @drvr: public driver information. | 60 | * @drvr: public driver information. |
73 | * @state: operational state of the bus interface. | 61 | * @state: operational state of the bus interface. |
74 | * @maxctl: maximum size for rxctl request message. | 62 | * @maxctl: maximum size for rxctl request message. |
75 | * @drvr_up: indicates driver up/down status. | ||
76 | * @tx_realloc: number of tx packets realloced for headroom. | 63 | * @tx_realloc: number of tx packets realloced for headroom. |
77 | * @dstats: dongle-based statistical data. | 64 | * @dstats: dongle-based statistical data. |
78 | * @align: alignment requirement for the bus. | 65 | * @align: alignment requirement for the bus. |
79 | * @dcmd_list: bus/device specific dongle initialization commands. | 66 | * @dcmd_list: bus/device specific dongle initialization commands. |
67 | * @chip: device identifier of the dongle chip. | ||
68 | * @chiprev: revision of the dongle chip. | ||
80 | */ | 69 | */ |
81 | struct brcmf_bus { | 70 | struct brcmf_bus { |
82 | union { | 71 | union { |
@@ -87,10 +76,10 @@ struct brcmf_bus { | |||
87 | struct brcmf_pub *drvr; | 76 | struct brcmf_pub *drvr; |
88 | enum brcmf_bus_state state; | 77 | enum brcmf_bus_state state; |
89 | uint maxctl; | 78 | uint maxctl; |
90 | bool drvr_up; | ||
91 | unsigned long tx_realloc; | 79 | unsigned long tx_realloc; |
92 | struct dngl_stats dstats; | ||
93 | u8 align; | 80 | u8 align; |
81 | u32 chip; | ||
82 | u32 chiprev; | ||
94 | struct list_head dcmd_list; | 83 | struct list_head dcmd_list; |
95 | 84 | ||
96 | struct brcmf_bus_ops *ops; | 85 | struct brcmf_bus_ops *ops; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index bb454cdab29d..a2354d951dd7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c | |||
@@ -303,6 +303,14 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | |||
303 | brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); | 303 | brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); |
304 | return -EBADE; | 304 | return -EBADE; |
305 | } | 305 | } |
306 | /* The ifidx is the idx to map to matching netdev/ifp. When receiving | ||
307 | * events this is easy because it contains the bssidx which maps | ||
308 | * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. | ||
309 | * bssidx 1 is used for p2p0 and no data can be received or | ||
310 | * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 | ||
311 | */ | ||
312 | if (*ifidx) | ||
313 | (*ifidx)++; | ||
306 | 314 | ||
307 | if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != | 315 | if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != |
308 | BDC_PROTO_VER) { | 316 | BDC_PROTO_VER) { |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 14b8fdde6954..c06cea88df0d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include "dhd_bus.h" | 26 | #include "dhd_bus.h" |
27 | #include "dhd_proto.h" | 27 | #include "dhd_proto.h" |
28 | #include "dhd_dbg.h" | 28 | #include "dhd_dbg.h" |
29 | #include "fwil_types.h" | ||
30 | #include "p2p.h" | ||
29 | #include "wl_cfg80211.h" | 31 | #include "wl_cfg80211.h" |
30 | #include "fwil.h" | 32 | #include "fwil.h" |
31 | 33 | ||
@@ -40,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL"); | |||
40 | int brcmf_msg_level; | 42 | int brcmf_msg_level; |
41 | module_param(brcmf_msg_level, int, 0); | 43 | module_param(brcmf_msg_level, int, 0); |
42 | 44 | ||
45 | /* P2P0 enable */ | ||
46 | static int brcmf_p2p_enable; | ||
47 | #ifdef CONFIG_BRCMDBG | ||
48 | module_param_named(p2pon, brcmf_p2p_enable, int, 0); | ||
49 | MODULE_PARM_DESC(p2pon, "enable p2p management functionality"); | ||
50 | #endif | ||
43 | 51 | ||
44 | char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) | 52 | char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) |
45 | { | 53 | { |
@@ -70,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) | |||
70 | u32 buflen; | 78 | u32 buflen; |
71 | s32 err; | 79 | s32 err; |
72 | 80 | ||
73 | brcmf_dbg(TRACE, "enter\n"); | ||
74 | |||
75 | ifp = container_of(work, struct brcmf_if, multicast_work); | 81 | ifp = container_of(work, struct brcmf_if, multicast_work); |
82 | |||
83 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||
84 | |||
76 | ndev = ifp->ndev; | 85 | ndev = ifp->ndev; |
77 | 86 | ||
78 | /* Determine initial value of allmulti flag */ | 87 | /* Determine initial value of allmulti flag */ |
@@ -129,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work) | |||
129 | struct brcmf_if *ifp; | 138 | struct brcmf_if *ifp; |
130 | s32 err; | 139 | s32 err; |
131 | 140 | ||
132 | brcmf_dbg(TRACE, "enter\n"); | ||
133 | |||
134 | ifp = container_of(work, struct brcmf_if, setmacaddr_work); | 141 | ifp = container_of(work, struct brcmf_if, setmacaddr_work); |
142 | |||
143 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||
144 | |||
135 | err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, | 145 | err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, |
136 | ETH_ALEN); | 146 | ETH_ALEN); |
137 | if (err < 0) { | 147 | if (err < 0) { |
@@ -168,7 +178,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
168 | struct brcmf_pub *drvr = ifp->drvr; | 178 | struct brcmf_pub *drvr = ifp->drvr; |
169 | struct ethhdr *eh; | 179 | struct ethhdr *eh; |
170 | 180 | ||
171 | brcmf_dbg(TRACE, "Enter\n"); | 181 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
172 | 182 | ||
173 | /* Can the device send data? */ | 183 | /* Can the device send data? */ |
174 | if (drvr->bus_if->state != BRCMF_BUS_DATA) { | 184 | if (drvr->bus_if->state != BRCMF_BUS_DATA) { |
@@ -179,8 +189,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
179 | goto done; | 189 | goto done; |
180 | } | 190 | } |
181 | 191 | ||
182 | if (!drvr->iflist[ifp->idx]) { | 192 | if (!drvr->iflist[ifp->bssidx]) { |
183 | brcmf_err("bad ifidx %d\n", ifp->idx); | 193 | brcmf_err("bad ifidx %d\n", ifp->bssidx); |
184 | netif_stop_queue(ndev); | 194 | netif_stop_queue(ndev); |
185 | dev_kfree_skb(skb); | 195 | dev_kfree_skb(skb); |
186 | ret = -ENODEV; | 196 | ret = -ENODEV; |
@@ -192,14 +202,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
192 | struct sk_buff *skb2; | 202 | struct sk_buff *skb2; |
193 | 203 | ||
194 | brcmf_dbg(INFO, "%s: insufficient headroom\n", | 204 | brcmf_dbg(INFO, "%s: insufficient headroom\n", |
195 | brcmf_ifname(drvr, ifp->idx)); | 205 | brcmf_ifname(drvr, ifp->bssidx)); |
196 | drvr->bus_if->tx_realloc++; | 206 | drvr->bus_if->tx_realloc++; |
197 | skb2 = skb_realloc_headroom(skb, drvr->hdrlen); | 207 | skb2 = skb_realloc_headroom(skb, drvr->hdrlen); |
198 | dev_kfree_skb(skb); | 208 | dev_kfree_skb(skb); |
199 | skb = skb2; | 209 | skb = skb2; |
200 | if (skb == NULL) { | 210 | if (skb == NULL) { |
201 | brcmf_err("%s: skb_realloc_headroom failed\n", | 211 | brcmf_err("%s: skb_realloc_headroom failed\n", |
202 | brcmf_ifname(drvr, ifp->idx)); | 212 | brcmf_ifname(drvr, ifp->bssidx)); |
203 | ret = -ENOMEM; | 213 | ret = -ENOMEM; |
204 | goto done; | 214 | goto done; |
205 | } | 215 | } |
@@ -217,19 +227,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
217 | if (is_multicast_ether_addr(eh->h_dest)) | 227 | if (is_multicast_ether_addr(eh->h_dest)) |
218 | drvr->tx_multicast++; | 228 | drvr->tx_multicast++; |
219 | if (ntohs(eh->h_proto) == ETH_P_PAE) | 229 | if (ntohs(eh->h_proto) == ETH_P_PAE) |
220 | atomic_inc(&drvr->pend_8021x_cnt); | 230 | atomic_inc(&ifp->pend_8021x_cnt); |
221 | 231 | ||
222 | /* If the protocol uses a data header, apply it */ | 232 | /* If the protocol uses a data header, apply it */ |
223 | brcmf_proto_hdrpush(drvr, ifp->idx, skb); | 233 | brcmf_proto_hdrpush(drvr, ifp->ifidx, skb); |
224 | 234 | ||
225 | /* Use bus module to send data frame */ | 235 | /* Use bus module to send data frame */ |
226 | ret = brcmf_bus_txdata(drvr->bus_if, skb); | 236 | ret = brcmf_bus_txdata(drvr->bus_if, skb); |
227 | 237 | ||
228 | done: | 238 | done: |
229 | if (ret) | 239 | if (ret) { |
230 | drvr->bus_if->dstats.tx_dropped++; | 240 | ifp->stats.tx_dropped++; |
231 | else | 241 | } else { |
232 | drvr->bus_if->dstats.tx_packets++; | 242 | ifp->stats.tx_packets++; |
243 | ifp->stats.tx_bytes += skb->len; | ||
244 | } | ||
233 | 245 | ||
234 | /* Return ok: we always eat the packet */ | 246 | /* Return ok: we always eat the packet */ |
235 | return NETDEV_TX_OK; | 247 | return NETDEV_TX_OK; |
@@ -270,12 +282,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |||
270 | skb_queue_walk_safe(skb_list, skb, pnext) { | 282 | skb_queue_walk_safe(skb_list, skb, pnext) { |
271 | skb_unlink(skb, skb_list); | 283 | skb_unlink(skb, skb_list); |
272 | 284 | ||
273 | /* process and remove protocol-specific header | 285 | /* process and remove protocol-specific header */ |
274 | */ | ||
275 | ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); | 286 | ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); |
276 | if (ret < 0) { | 287 | ifp = drvr->iflist[ifidx]; |
277 | if (ret != -ENODATA) | 288 | |
278 | bus_if->dstats.rx_errors++; | 289 | if (ret || !ifp || !ifp->ndev) { |
290 | if ((ret != -ENODATA) && ifp) | ||
291 | ifp->stats.rx_errors++; | ||
279 | brcmu_pkt_buf_free_skb(skb); | 292 | brcmu_pkt_buf_free_skb(skb); |
280 | continue; | 293 | continue; |
281 | } | 294 | } |
@@ -295,21 +308,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |||
295 | eth = skb->data; | 308 | eth = skb->data; |
296 | len = skb->len; | 309 | len = skb->len; |
297 | 310 | ||
298 | ifp = drvr->iflist[ifidx]; | ||
299 | if (ifp == NULL) | ||
300 | ifp = drvr->iflist[0]; | ||
301 | |||
302 | if (!ifp || !ifp->ndev || | ||
303 | ifp->ndev->reg_state != NETREG_REGISTERED) { | ||
304 | brcmu_pkt_buf_free_skb(skb); | ||
305 | continue; | ||
306 | } | ||
307 | |||
308 | skb->dev = ifp->ndev; | 311 | skb->dev = ifp->ndev; |
309 | skb->protocol = eth_type_trans(skb, skb->dev); | 312 | skb->protocol = eth_type_trans(skb, skb->dev); |
310 | 313 | ||
311 | if (skb->pkt_type == PACKET_MULTICAST) | 314 | if (skb->pkt_type == PACKET_MULTICAST) |
312 | bus_if->dstats.multicast++; | 315 | ifp->stats.multicast++; |
313 | 316 | ||
314 | skb->data = eth; | 317 | skb->data = eth; |
315 | skb->len = len; | 318 | skb->len = len; |
@@ -325,8 +328,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |||
325 | ifp->ndev->last_rx = jiffies; | 328 | ifp->ndev->last_rx = jiffies; |
326 | } | 329 | } |
327 | 330 | ||
328 | bus_if->dstats.rx_bytes += skb->len; | 331 | if (!(ifp->ndev->flags & IFF_UP)) { |
329 | bus_if->dstats.rx_packets++; /* Local count */ | 332 | brcmu_pkt_buf_free_skb(skb); |
333 | continue; | ||
334 | } | ||
335 | |||
336 | ifp->stats.rx_bytes += skb->len; | ||
337 | ifp->stats.rx_packets++; | ||
330 | 338 | ||
331 | if (in_interrupt()) | 339 | if (in_interrupt()) |
332 | netif_rx(skb); | 340 | netif_rx(skb); |
@@ -348,36 +356,31 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) | |||
348 | u16 type; | 356 | u16 type; |
349 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 357 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
350 | struct brcmf_pub *drvr = bus_if->drvr; | 358 | struct brcmf_pub *drvr = bus_if->drvr; |
359 | struct brcmf_if *ifp; | ||
351 | 360 | ||
352 | brcmf_proto_hdrpull(drvr, &ifidx, txp); | 361 | brcmf_proto_hdrpull(drvr, &ifidx, txp); |
353 | 362 | ||
363 | ifp = drvr->iflist[ifidx]; | ||
364 | if (!ifp) | ||
365 | return; | ||
366 | |||
354 | eh = (struct ethhdr *)(txp->data); | 367 | eh = (struct ethhdr *)(txp->data); |
355 | type = ntohs(eh->h_proto); | 368 | type = ntohs(eh->h_proto); |
356 | 369 | ||
357 | if (type == ETH_P_PAE) { | 370 | if (type == ETH_P_PAE) { |
358 | atomic_dec(&drvr->pend_8021x_cnt); | 371 | atomic_dec(&ifp->pend_8021x_cnt); |
359 | if (waitqueue_active(&drvr->pend_8021x_wait)) | 372 | if (waitqueue_active(&ifp->pend_8021x_wait)) |
360 | wake_up(&drvr->pend_8021x_wait); | 373 | wake_up(&ifp->pend_8021x_wait); |
361 | } | 374 | } |
375 | if (!success) | ||
376 | ifp->stats.tx_errors++; | ||
362 | } | 377 | } |
363 | 378 | ||
364 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) | 379 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) |
365 | { | 380 | { |
366 | struct brcmf_if *ifp = netdev_priv(ndev); | 381 | struct brcmf_if *ifp = netdev_priv(ndev); |
367 | struct brcmf_bus *bus_if = ifp->drvr->bus_if; | ||
368 | |||
369 | brcmf_dbg(TRACE, "Enter\n"); | ||
370 | 382 | ||
371 | /* Copy dongle stats to net device stats */ | 383 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
372 | ifp->stats.rx_packets = bus_if->dstats.rx_packets; | ||
373 | ifp->stats.tx_packets = bus_if->dstats.tx_packets; | ||
374 | ifp->stats.rx_bytes = bus_if->dstats.rx_bytes; | ||
375 | ifp->stats.tx_bytes = bus_if->dstats.tx_bytes; | ||
376 | ifp->stats.rx_errors = bus_if->dstats.rx_errors; | ||
377 | ifp->stats.tx_errors = bus_if->dstats.tx_errors; | ||
378 | ifp->stats.rx_dropped = bus_if->dstats.rx_dropped; | ||
379 | ifp->stats.tx_dropped = bus_if->dstats.tx_dropped; | ||
380 | ifp->stats.multicast = bus_if->dstats.multicast; | ||
381 | 384 | ||
382 | return &ifp->stats; | 385 | return &ifp->stats; |
383 | } | 386 | } |
@@ -431,7 +434,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) | |||
431 | u32 toe_cmpnt, csum_dir; | 434 | u32 toe_cmpnt, csum_dir; |
432 | int ret; | 435 | int ret; |
433 | 436 | ||
434 | brcmf_dbg(TRACE, "Enter\n"); | 437 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
435 | 438 | ||
436 | /* all ethtool calls start with a cmd word */ | 439 | /* all ethtool calls start with a cmd word */ |
437 | if (copy_from_user(&cmd, uaddr, sizeof(u32))) | 440 | if (copy_from_user(&cmd, uaddr, sizeof(u32))) |
@@ -454,13 +457,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) | |||
454 | sprintf(info.driver, "dhd"); | 457 | sprintf(info.driver, "dhd"); |
455 | strcpy(info.version, BRCMF_VERSION_STR); | 458 | strcpy(info.version, BRCMF_VERSION_STR); |
456 | } | 459 | } |
457 | 460 | /* report dongle driver type */ | |
458 | /* otherwise, require dongle to be up */ | ||
459 | else if (!drvr->bus_if->drvr_up) { | ||
460 | brcmf_err("dongle is not up\n"); | ||
461 | return -ENODEV; | ||
462 | } | ||
463 | /* finally, report dongle driver type */ | ||
464 | else | 461 | else |
465 | sprintf(info.driver, "wl"); | 462 | sprintf(info.driver, "wl"); |
466 | 463 | ||
@@ -534,9 +531,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | |||
534 | struct brcmf_if *ifp = netdev_priv(ndev); | 531 | struct brcmf_if *ifp = netdev_priv(ndev); |
535 | struct brcmf_pub *drvr = ifp->drvr; | 532 | struct brcmf_pub *drvr = ifp->drvr; |
536 | 533 | ||
537 | brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); | 534 | brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); |
538 | 535 | ||
539 | if (!drvr->iflist[ifp->idx]) | 536 | if (!drvr->iflist[ifp->bssidx]) |
540 | return -1; | 537 | return -1; |
541 | 538 | ||
542 | if (cmd == SIOCETHTOOL) | 539 | if (cmd == SIOCETHTOOL) |
@@ -548,17 +545,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | |||
548 | static int brcmf_netdev_stop(struct net_device *ndev) | 545 | static int brcmf_netdev_stop(struct net_device *ndev) |
549 | { | 546 | { |
550 | struct brcmf_if *ifp = netdev_priv(ndev); | 547 | struct brcmf_if *ifp = netdev_priv(ndev); |
551 | struct brcmf_pub *drvr = ifp->drvr; | ||
552 | |||
553 | brcmf_dbg(TRACE, "Enter\n"); | ||
554 | 548 | ||
555 | if (drvr->bus_if->drvr_up == 0) | 549 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
556 | return 0; | ||
557 | 550 | ||
558 | brcmf_cfg80211_down(ndev); | 551 | brcmf_cfg80211_down(ndev); |
559 | 552 | ||
560 | /* Set state and stop OS transmissions */ | 553 | /* Set state and stop OS transmissions */ |
561 | drvr->bus_if->drvr_up = false; | ||
562 | netif_stop_queue(ndev); | 554 | netif_stop_queue(ndev); |
563 | 555 | ||
564 | return 0; | 556 | return 0; |
@@ -572,7 +564,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
572 | u32 toe_ol; | 564 | u32 toe_ol; |
573 | s32 ret = 0; | 565 | s32 ret = 0; |
574 | 566 | ||
575 | brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); | 567 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
576 | 568 | ||
577 | /* If bus is not ready, can't continue */ | 569 | /* If bus is not ready, can't continue */ |
578 | if (bus_if->state != BRCMF_BUS_DATA) { | 570 | if (bus_if->state != BRCMF_BUS_DATA) { |
@@ -580,9 +572,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
580 | return -EAGAIN; | 572 | return -EAGAIN; |
581 | } | 573 | } |
582 | 574 | ||
583 | atomic_set(&drvr->pend_8021x_cnt, 0); | 575 | atomic_set(&ifp->pend_8021x_cnt, 0); |
584 | |||
585 | memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); | ||
586 | 576 | ||
587 | /* Get current TOE mode from dongle */ | 577 | /* Get current TOE mode from dongle */ |
588 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 | 578 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 |
@@ -593,7 +583,6 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
593 | 583 | ||
594 | /* Allow transmit calls */ | 584 | /* Allow transmit calls */ |
595 | netif_start_queue(ndev); | 585 | netif_start_queue(ndev); |
596 | drvr->bus_if->drvr_up = true; | ||
597 | if (brcmf_cfg80211_up(ndev)) { | 586 | if (brcmf_cfg80211_up(ndev)) { |
598 | brcmf_err("failed to bring up cfg80211\n"); | 587 | brcmf_err("failed to bring up cfg80211\n"); |
599 | return -1; | 588 | return -1; |
@@ -612,29 +601,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { | |||
612 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | 601 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list |
613 | }; | 602 | }; |
614 | 603 | ||
615 | static const struct net_device_ops brcmf_netdev_ops_virt = { | 604 | int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) |
616 | .ndo_open = brcmf_cfg80211_up, | ||
617 | .ndo_stop = brcmf_cfg80211_down, | ||
618 | .ndo_get_stats = brcmf_netdev_get_stats, | ||
619 | .ndo_do_ioctl = brcmf_netdev_ioctl_entry, | ||
620 | .ndo_start_xmit = brcmf_netdev_start_xmit, | ||
621 | .ndo_set_mac_address = brcmf_netdev_set_mac_address, | ||
622 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | ||
623 | }; | ||
624 | |||
625 | int brcmf_net_attach(struct brcmf_if *ifp) | ||
626 | { | 605 | { |
627 | struct brcmf_pub *drvr = ifp->drvr; | 606 | struct brcmf_pub *drvr = ifp->drvr; |
628 | struct net_device *ndev; | 607 | struct net_device *ndev; |
608 | s32 err; | ||
629 | 609 | ||
630 | brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); | 610 | brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, |
611 | ifp->mac_addr); | ||
631 | ndev = ifp->ndev; | 612 | ndev = ifp->ndev; |
632 | 613 | ||
633 | /* set appropriate operations */ | 614 | /* set appropriate operations */ |
634 | if (!ifp->idx) | 615 | ndev->netdev_ops = &brcmf_netdev_ops_pri; |
635 | ndev->netdev_ops = &brcmf_netdev_ops_pri; | ||
636 | else | ||
637 | ndev->netdev_ops = &brcmf_netdev_ops_virt; | ||
638 | 616 | ||
639 | ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; | 617 | ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; |
640 | ndev->ethtool_ops = &brcmf_ethtool_ops; | 618 | ndev->ethtool_ops = &brcmf_ethtool_ops; |
@@ -645,7 +623,14 @@ int brcmf_net_attach(struct brcmf_if *ifp) | |||
645 | /* set the mac address */ | 623 | /* set the mac address */ |
646 | memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | 624 | memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); |
647 | 625 | ||
648 | if (register_netdev(ndev) != 0) { | 626 | INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); |
627 | INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); | ||
628 | |||
629 | if (rtnl_locked) | ||
630 | err = register_netdevice(ndev); | ||
631 | else | ||
632 | err = register_netdev(ndev); | ||
633 | if (err != 0) { | ||
649 | brcmf_err("couldn't register the net device\n"); | 634 | brcmf_err("couldn't register the net device\n"); |
650 | goto fail; | 635 | goto fail; |
651 | } | 636 | } |
@@ -659,16 +644,78 @@ fail: | |||
659 | return -EBADE; | 644 | return -EBADE; |
660 | } | 645 | } |
661 | 646 | ||
662 | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | 647 | static int brcmf_net_p2p_open(struct net_device *ndev) |
663 | char *name, u8 *addr_mask) | 648 | { |
649 | brcmf_dbg(TRACE, "Enter\n"); | ||
650 | |||
651 | return brcmf_cfg80211_up(ndev); | ||
652 | } | ||
653 | |||
654 | static int brcmf_net_p2p_stop(struct net_device *ndev) | ||
655 | { | ||
656 | brcmf_dbg(TRACE, "Enter\n"); | ||
657 | |||
658 | return brcmf_cfg80211_down(ndev); | ||
659 | } | ||
660 | |||
661 | static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, | ||
662 | struct ifreq *ifr, int cmd) | ||
663 | { | ||
664 | brcmf_dbg(TRACE, "Enter\n"); | ||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb, | ||
669 | struct net_device *ndev) | ||
670 | { | ||
671 | if (skb) | ||
672 | dev_kfree_skb_any(skb); | ||
673 | |||
674 | return NETDEV_TX_OK; | ||
675 | } | ||
676 | |||
677 | static const struct net_device_ops brcmf_netdev_ops_p2p = { | ||
678 | .ndo_open = brcmf_net_p2p_open, | ||
679 | .ndo_stop = brcmf_net_p2p_stop, | ||
680 | .ndo_do_ioctl = brcmf_net_p2p_do_ioctl, | ||
681 | .ndo_start_xmit = brcmf_net_p2p_start_xmit | ||
682 | }; | ||
683 | |||
684 | static int brcmf_net_p2p_attach(struct brcmf_if *ifp) | ||
685 | { | ||
686 | struct net_device *ndev; | ||
687 | |||
688 | brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, | ||
689 | ifp->mac_addr); | ||
690 | ndev = ifp->ndev; | ||
691 | |||
692 | ndev->netdev_ops = &brcmf_netdev_ops_p2p; | ||
693 | |||
694 | /* set the mac address */ | ||
695 | memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | ||
696 | |||
697 | if (register_netdev(ndev) != 0) { | ||
698 | brcmf_err("couldn't register the p2p net device\n"); | ||
699 | goto fail; | ||
700 | } | ||
701 | |||
702 | brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); | ||
703 | |||
704 | return 0; | ||
705 | |||
706 | fail: | ||
707 | return -EBADE; | ||
708 | } | ||
709 | |||
710 | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, | ||
711 | char *name, u8 *mac_addr) | ||
664 | { | 712 | { |
665 | struct brcmf_if *ifp; | 713 | struct brcmf_if *ifp; |
666 | struct net_device *ndev; | 714 | struct net_device *ndev; |
667 | int i; | ||
668 | 715 | ||
669 | brcmf_dbg(TRACE, "idx %d\n", ifidx); | 716 | brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx); |
670 | 717 | ||
671 | ifp = drvr->iflist[ifidx]; | 718 | ifp = drvr->iflist[bssidx]; |
672 | /* | 719 | /* |
673 | * Delete the existing interface before overwriting it | 720 | * Delete the existing interface before overwriting it |
674 | * in case we missed the BRCMF_E_IF_DEL event. | 721 | * in case we missed the BRCMF_E_IF_DEL event. |
@@ -680,7 +727,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
680 | netif_stop_queue(ifp->ndev); | 727 | netif_stop_queue(ifp->ndev); |
681 | unregister_netdev(ifp->ndev); | 728 | unregister_netdev(ifp->ndev); |
682 | free_netdev(ifp->ndev); | 729 | free_netdev(ifp->ndev); |
683 | drvr->iflist[ifidx] = NULL; | 730 | drvr->iflist[bssidx] = NULL; |
684 | } else { | 731 | } else { |
685 | brcmf_err("ignore IF event\n"); | 732 | brcmf_err("ignore IF event\n"); |
686 | return ERR_PTR(-EINVAL); | 733 | return ERR_PTR(-EINVAL); |
@@ -697,16 +744,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
697 | ifp = netdev_priv(ndev); | 744 | ifp = netdev_priv(ndev); |
698 | ifp->ndev = ndev; | 745 | ifp->ndev = ndev; |
699 | ifp->drvr = drvr; | 746 | ifp->drvr = drvr; |
700 | drvr->iflist[ifidx] = ifp; | 747 | drvr->iflist[bssidx] = ifp; |
701 | ifp->idx = ifidx; | 748 | ifp->ifidx = ifidx; |
702 | ifp->bssidx = bssidx; | 749 | ifp->bssidx = bssidx; |
703 | 750 | ||
704 | INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); | ||
705 | INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); | ||
706 | 751 | ||
707 | if (addr_mask != NULL) | 752 | init_waitqueue_head(&ifp->pend_8021x_wait); |
708 | for (i = 0; i < ETH_ALEN; i++) | 753 | |
709 | ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; | 754 | if (mac_addr != NULL) |
755 | memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); | ||
710 | 756 | ||
711 | brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", | 757 | brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", |
712 | current->pid, ifp->ndev->name, ifp->mac_addr); | 758 | current->pid, ifp->ndev->name, ifp->mac_addr); |
@@ -714,19 +760,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
714 | return ifp; | 760 | return ifp; |
715 | } | 761 | } |
716 | 762 | ||
717 | void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | 763 | void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) |
718 | { | 764 | { |
719 | struct brcmf_if *ifp; | 765 | struct brcmf_if *ifp; |
720 | 766 | ||
721 | brcmf_dbg(TRACE, "idx %d\n", ifidx); | 767 | ifp = drvr->iflist[bssidx]; |
722 | |||
723 | ifp = drvr->iflist[ifidx]; | ||
724 | if (!ifp) { | 768 | if (!ifp) { |
725 | brcmf_err("Null interface\n"); | 769 | brcmf_err("Null interface, idx=%d\n", bssidx); |
726 | return; | 770 | return; |
727 | } | 771 | } |
772 | brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx); | ||
728 | if (ifp->ndev) { | 773 | if (ifp->ndev) { |
729 | if (ifidx == 0) { | 774 | if (bssidx == 0) { |
730 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | 775 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { |
731 | rtnl_lock(); | 776 | rtnl_lock(); |
732 | brcmf_netdev_stop(ifp->ndev); | 777 | brcmf_netdev_stop(ifp->ndev); |
@@ -736,12 +781,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | |||
736 | netif_stop_queue(ifp->ndev); | 781 | netif_stop_queue(ifp->ndev); |
737 | } | 782 | } |
738 | 783 | ||
739 | cancel_work_sync(&ifp->setmacaddr_work); | 784 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { |
740 | cancel_work_sync(&ifp->multicast_work); | 785 | cancel_work_sync(&ifp->setmacaddr_work); |
786 | cancel_work_sync(&ifp->multicast_work); | ||
787 | } | ||
741 | 788 | ||
742 | unregister_netdev(ifp->ndev); | 789 | unregister_netdev(ifp->ndev); |
743 | drvr->iflist[ifidx] = NULL; | 790 | drvr->iflist[bssidx] = NULL; |
744 | if (ifidx == 0) | 791 | if (bssidx == 0) |
745 | brcmf_cfg80211_detach(drvr->config); | 792 | brcmf_cfg80211_detach(drvr->config); |
746 | free_netdev(ifp->ndev); | 793 | free_netdev(ifp->ndev); |
747 | } | 794 | } |
@@ -781,8 +828,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) | |||
781 | 828 | ||
782 | INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); | 829 | INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); |
783 | 830 | ||
784 | init_waitqueue_head(&drvr->pend_8021x_wait); | ||
785 | |||
786 | return ret; | 831 | return ret; |
787 | 832 | ||
788 | fail: | 833 | fail: |
@@ -797,6 +842,7 @@ int brcmf_bus_start(struct device *dev) | |||
797 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 842 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
798 | struct brcmf_pub *drvr = bus_if->drvr; | 843 | struct brcmf_pub *drvr = bus_if->drvr; |
799 | struct brcmf_if *ifp; | 844 | struct brcmf_if *ifp; |
845 | struct brcmf_if *p2p_ifp; | ||
800 | 846 | ||
801 | brcmf_dbg(TRACE, "\n"); | 847 | brcmf_dbg(TRACE, "\n"); |
802 | 848 | ||
@@ -812,6 +858,13 @@ int brcmf_bus_start(struct device *dev) | |||
812 | if (IS_ERR(ifp)) | 858 | if (IS_ERR(ifp)) |
813 | return PTR_ERR(ifp); | 859 | return PTR_ERR(ifp); |
814 | 860 | ||
861 | if (brcmf_p2p_enable) | ||
862 | p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); | ||
863 | else | ||
864 | p2p_ifp = NULL; | ||
865 | if (IS_ERR(p2p_ifp)) | ||
866 | p2p_ifp = NULL; | ||
867 | |||
815 | /* signal bus ready */ | 868 | /* signal bus ready */ |
816 | bus_if->state = BRCMF_BUS_DATA; | 869 | bus_if->state = BRCMF_BUS_DATA; |
817 | 870 | ||
@@ -830,16 +883,22 @@ int brcmf_bus_start(struct device *dev) | |||
830 | if (ret < 0) | 883 | if (ret < 0) |
831 | goto fail; | 884 | goto fail; |
832 | 885 | ||
833 | ret = brcmf_net_attach(ifp); | 886 | ret = brcmf_net_attach(ifp, false); |
834 | fail: | 887 | fail: |
835 | if (ret < 0) { | 888 | if (ret < 0) { |
836 | brcmf_err("failed: %d\n", ret); | 889 | brcmf_err("failed: %d\n", ret); |
837 | if (drvr->config) | 890 | if (drvr->config) |
838 | brcmf_cfg80211_detach(drvr->config); | 891 | brcmf_cfg80211_detach(drvr->config); |
839 | free_netdev(drvr->iflist[0]->ndev); | 892 | free_netdev(ifp->ndev); |
840 | drvr->iflist[0] = NULL; | 893 | drvr->iflist[0] = NULL; |
894 | if (p2p_ifp) { | ||
895 | free_netdev(p2p_ifp->ndev); | ||
896 | drvr->iflist[1] = NULL; | ||
897 | } | ||
841 | return ret; | 898 | return ret; |
842 | } | 899 | } |
900 | if ((brcmf_p2p_enable) && (p2p_ifp)) | ||
901 | brcmf_net_p2p_attach(p2p_ifp); | ||
843 | 902 | ||
844 | return 0; | 903 | return 0; |
845 | } | 904 | } |
@@ -865,12 +924,13 @@ void brcmf_dev_reset(struct device *dev) | |||
865 | if (drvr == NULL) | 924 | if (drvr == NULL) |
866 | return; | 925 | return; |
867 | 926 | ||
868 | brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | 927 | if (drvr->iflist[0]) |
928 | brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | ||
869 | } | 929 | } |
870 | 930 | ||
871 | void brcmf_detach(struct device *dev) | 931 | void brcmf_detach(struct device *dev) |
872 | { | 932 | { |
873 | int i; | 933 | s32 i; |
874 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 934 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
875 | struct brcmf_pub *drvr = bus_if->drvr; | 935 | struct brcmf_pub *drvr = bus_if->drvr; |
876 | 936 | ||
@@ -897,19 +957,18 @@ void brcmf_detach(struct device *dev) | |||
897 | kfree(drvr); | 957 | kfree(drvr); |
898 | } | 958 | } |
899 | 959 | ||
900 | static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr) | 960 | static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) |
901 | { | 961 | { |
902 | return atomic_read(&drvr->pend_8021x_cnt); | 962 | return atomic_read(&ifp->pend_8021x_cnt); |
903 | } | 963 | } |
904 | 964 | ||
905 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | 965 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) |
906 | { | 966 | { |
907 | struct brcmf_if *ifp = netdev_priv(ndev); | 967 | struct brcmf_if *ifp = netdev_priv(ndev); |
908 | struct brcmf_pub *drvr = ifp->drvr; | ||
909 | int err; | 968 | int err; |
910 | 969 | ||
911 | err = wait_event_timeout(drvr->pend_8021x_wait, | 970 | err = wait_event_timeout(ifp->pend_8021x_wait, |
912 | !brcmf_get_pend_8021x_cnt(drvr), | 971 | !brcmf_get_pend_8021x_cnt(ifp), |
913 | msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); | 972 | msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); |
914 | 973 | ||
915 | WARN_ON(!err); | 974 | WARN_ON(!err); |
@@ -917,6 +976,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | |||
917 | return !err; | 976 | return !err; |
918 | } | 977 | } |
919 | 978 | ||
979 | /* | ||
980 | * return chip id and rev of the device encoded in u32. | ||
981 | */ | ||
982 | u32 brcmf_get_chip_info(struct brcmf_if *ifp) | ||
983 | { | ||
984 | struct brcmf_bus *bus = ifp->drvr->bus_if; | ||
985 | |||
986 | return bus->chip << 4 | bus->chiprev; | ||
987 | } | ||
988 | |||
920 | static void brcmf_driver_init(struct work_struct *work) | 989 | static void brcmf_driver_init(struct work_struct *work) |
921 | { | 990 | { |
922 | brcmf_debugfs_init(); | 991 | brcmf_debugfs_init(); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 6d786a281f1e..4469321c0eb3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |||
@@ -1096,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, | |||
1096 | if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && | 1096 | if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && |
1097 | type != BRCMF_SDIO_FT_SUPER) { | 1097 | type != BRCMF_SDIO_FT_SUPER) { |
1098 | brcmf_err("HW header length too long\n"); | 1098 | brcmf_err("HW header length too long\n"); |
1099 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1100 | bus->sdcnt.rx_toolong++; | 1099 | bus->sdcnt.rx_toolong++; |
1101 | brcmf_sdbrcm_rxfail(bus, false, false); | 1100 | brcmf_sdbrcm_rxfail(bus, false, false); |
1102 | rd->len = 0; | 1101 | rd->len = 0; |
@@ -1298,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1298 | if (errcode < 0) { | 1297 | if (errcode < 0) { |
1299 | brcmf_err("glom read of %d bytes failed: %d\n", | 1298 | brcmf_err("glom read of %d bytes failed: %d\n", |
1300 | dlen, errcode); | 1299 | dlen, errcode); |
1301 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1302 | 1300 | ||
1303 | sdio_claim_host(bus->sdiodev->func[1]); | 1301 | sdio_claim_host(bus->sdiodev->func[1]); |
1304 | if (bus->glomerr++ < 3) { | 1302 | if (bus->glomerr++ < 3) { |
@@ -1477,7 +1475,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) | |||
1477 | if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { | 1475 | if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { |
1478 | brcmf_err("%d-byte control read exceeds %d-byte buffer\n", | 1476 | brcmf_err("%d-byte control read exceeds %d-byte buffer\n", |
1479 | rdlen, bus->sdiodev->bus_if->maxctl); | 1477 | rdlen, bus->sdiodev->bus_if->maxctl); |
1480 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1481 | brcmf_sdbrcm_rxfail(bus, false, false); | 1478 | brcmf_sdbrcm_rxfail(bus, false, false); |
1482 | goto done; | 1479 | goto done; |
1483 | } | 1480 | } |
@@ -1485,7 +1482,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) | |||
1485 | if ((len - doff) > bus->sdiodev->bus_if->maxctl) { | 1482 | if ((len - doff) > bus->sdiodev->bus_if->maxctl) { |
1486 | brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", | 1483 | brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", |
1487 | len, len - doff, bus->sdiodev->bus_if->maxctl); | 1484 | len, len - doff, bus->sdiodev->bus_if->maxctl); |
1488 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1489 | bus->sdcnt.rx_toolong++; | 1485 | bus->sdcnt.rx_toolong++; |
1490 | brcmf_sdbrcm_rxfail(bus, false, false); | 1486 | brcmf_sdbrcm_rxfail(bus, false, false); |
1491 | goto done; | 1487 | goto done; |
@@ -1633,7 +1629,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) | |||
1633 | if (!pkt) { | 1629 | if (!pkt) { |
1634 | /* Give up on data, request rtx of events */ | 1630 | /* Give up on data, request rtx of events */ |
1635 | brcmf_err("brcmu_pkt_buf_get_skb failed\n"); | 1631 | brcmf_err("brcmu_pkt_buf_get_skb failed\n"); |
1636 | bus->sdiodev->bus_if->dstats.rx_dropped++; | ||
1637 | brcmf_sdbrcm_rxfail(bus, false, | 1632 | brcmf_sdbrcm_rxfail(bus, false, |
1638 | RETRYCHAN(rd->channel)); | 1633 | RETRYCHAN(rd->channel)); |
1639 | sdio_release_host(bus->sdiodev->func[1]); | 1634 | sdio_release_host(bus->sdiodev->func[1]); |
@@ -1651,7 +1646,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) | |||
1651 | brcmf_err("read %d bytes from channel %d failed: %d\n", | 1646 | brcmf_err("read %d bytes from channel %d failed: %d\n", |
1652 | rd->len, rd->channel, sdret); | 1647 | rd->len, rd->channel, sdret); |
1653 | brcmu_pkt_buf_free_skb(pkt); | 1648 | brcmu_pkt_buf_free_skb(pkt); |
1654 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1655 | sdio_claim_host(bus->sdiodev->func[1]); | 1649 | sdio_claim_host(bus->sdiodev->func[1]); |
1656 | brcmf_sdbrcm_rxfail(bus, true, | 1650 | brcmf_sdbrcm_rxfail(bus, true, |
1657 | RETRYCHAN(rd->channel)); | 1651 | RETRYCHAN(rd->channel)); |
@@ -1939,10 +1933,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
1939 | datalen = pkt->len - SDPCM_HDRLEN; | 1933 | datalen = pkt->len - SDPCM_HDRLEN; |
1940 | 1934 | ||
1941 | ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); | 1935 | ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); |
1942 | if (ret) | ||
1943 | bus->sdiodev->bus_if->dstats.tx_errors++; | ||
1944 | else | ||
1945 | bus->sdiodev->bus_if->dstats.tx_bytes += datalen; | ||
1946 | 1936 | ||
1947 | /* In poll mode, need to check for other events */ | 1937 | /* In poll mode, need to check for other events */ |
1948 | if (!bus->intr && cnt) { | 1938 | if (!bus->intr && cnt) { |
@@ -1961,8 +1951,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
1961 | } | 1951 | } |
1962 | 1952 | ||
1963 | /* Deflow-control stack if needed */ | 1953 | /* Deflow-control stack if needed */ |
1964 | if (bus->sdiodev->bus_if->drvr_up && | 1954 | if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && |
1965 | (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && | ||
1966 | bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { | 1955 | bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { |
1967 | bus->txoff = false; | 1956 | bus->txoff = false; |
1968 | brcmf_txflowblock(bus->sdiodev->dev, false); | 1957 | brcmf_txflowblock(bus->sdiodev->dev, false); |
@@ -2709,9 +2698,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | |||
2709 | * address of sdpcm_shared structure | 2698 | * address of sdpcm_shared structure |
2710 | */ | 2699 | */ |
2711 | sdio_claim_host(bus->sdiodev->func[1]); | 2700 | sdio_claim_host(bus->sdiodev->func[1]); |
2701 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
2712 | rv = brcmf_sdbrcm_membytes(bus, false, shaddr, | 2702 | rv = brcmf_sdbrcm_membytes(bus, false, shaddr, |
2713 | (u8 *)&addr_le, 4); | 2703 | (u8 *)&addr_le, 4); |
2714 | sdio_claim_host(bus->sdiodev->func[1]); | 2704 | sdio_release_host(bus->sdiodev->func[1]); |
2715 | if (rv < 0) | 2705 | if (rv < 0) |
2716 | return rv; | 2706 | return rv; |
2717 | 2707 | ||
@@ -2730,10 +2720,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | |||
2730 | } | 2720 | } |
2731 | 2721 | ||
2732 | /* Read hndrte_shared structure */ | 2722 | /* Read hndrte_shared structure */ |
2733 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2734 | rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, | 2723 | rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, |
2735 | sizeof(struct sdpcm_shared_le)); | 2724 | sizeof(struct sdpcm_shared_le)); |
2736 | sdio_release_host(bus->sdiodev->func[1]); | ||
2737 | if (rv < 0) | 2725 | if (rv < 0) |
2738 | return rv; | 2726 | return rv; |
2739 | 2727 | ||
@@ -2835,14 +2823,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, | |||
2835 | if ((sh->flags & SDPCM_SHARED_TRAP) == 0) | 2823 | if ((sh->flags & SDPCM_SHARED_TRAP) == 0) |
2836 | return 0; | 2824 | return 0; |
2837 | 2825 | ||
2838 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2839 | error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, | 2826 | error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, |
2840 | sizeof(struct brcmf_trap_info)); | 2827 | sizeof(struct brcmf_trap_info)); |
2841 | if (error < 0) | 2828 | if (error < 0) |
2842 | return error; | 2829 | return error; |
2843 | 2830 | ||
2844 | nbytes = brcmf_sdio_dump_console(bus, sh, data, count); | 2831 | nbytes = brcmf_sdio_dump_console(bus, sh, data, count); |
2845 | sdio_release_host(bus->sdiodev->func[1]); | ||
2846 | if (nbytes < 0) | 2832 | if (nbytes < 0) |
2847 | return nbytes; | 2833 | return nbytes; |
2848 | 2834 | ||
@@ -3307,9 +3293,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) | |||
3307 | { | 3293 | { |
3308 | int ret; | 3294 | int ret; |
3309 | 3295 | ||
3310 | if (bus->sdiodev->bus_if->drvr_up) | ||
3311 | return -EISCONN; | ||
3312 | |||
3313 | ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, | 3296 | ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, |
3314 | &bus->sdiodev->func[2]->dev); | 3297 | &bus->sdiodev->func[2]->dev); |
3315 | if (ret) { | 3298 | if (ret) { |
@@ -3940,6 +3923,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) | |||
3940 | /* Assign bus interface call back */ | 3923 | /* Assign bus interface call back */ |
3941 | bus->sdiodev->bus_if->dev = bus->sdiodev->dev; | 3924 | bus->sdiodev->bus_if->dev = bus->sdiodev->dev; |
3942 | bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; | 3925 | bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; |
3926 | bus->sdiodev->bus_if->chip = bus->ci->chip; | ||
3927 | bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; | ||
3943 | 3928 | ||
3944 | /* Attach to the brcmf/OS/network interface */ | 3929 | /* Attach to the brcmf/OS/network interface */ |
3945 | ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); | 3930 | ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index ba0b22512f12..e9d6f91a1f2b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c | |||
@@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, | |||
189 | return; | 189 | return; |
190 | } | 190 | } |
191 | 191 | ||
192 | ifp = drvr->iflist[ifevent->ifidx]; | 192 | ifp = drvr->iflist[ifevent->bssidx]; |
193 | 193 | ||
194 | if (ifevent->action == BRCMF_E_IF_ADD) { | 194 | if (ifevent->action == BRCMF_E_IF_ADD) { |
195 | brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, | 195 | brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, |
196 | emsg->addr); | 196 | emsg->addr); |
197 | ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, | 197 | ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, |
198 | emsg->ifname, emsg->addr); | 198 | emsg->ifname, emsg->addr); |
199 | if (IS_ERR(ifp)) | 199 | if (IS_ERR(ifp)) |
200 | return; | 200 | return; |
201 | 201 | ||
202 | if (!drvr->fweh.evt_handler[BRCMF_E_IF]) | 202 | if (!drvr->fweh.evt_handler[BRCMF_E_IF]) |
203 | err = brcmf_net_attach(ifp); | 203 | err = brcmf_net_attach(ifp, false); |
204 | } | 204 | } |
205 | 205 | ||
206 | err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); | 206 | err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); |
207 | 207 | ||
208 | if (ifevent->action == BRCMF_E_IF_DEL) | 208 | if (ifevent->action == BRCMF_E_IF_DEL) |
209 | brcmf_del_if(drvr, ifevent->ifidx); | 209 | brcmf_del_if(drvr, ifevent->bssidx); |
210 | } | 210 | } |
211 | 211 | ||
212 | /** | 212 | /** |
@@ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work) | |||
250 | drvr = container_of(fweh, struct brcmf_pub, fweh); | 250 | drvr = container_of(fweh, struct brcmf_pub, fweh); |
251 | 251 | ||
252 | while ((event = brcmf_fweh_dequeue_event(fweh))) { | 252 | while ((event = brcmf_fweh_dequeue_event(fweh))) { |
253 | ifp = drvr->iflist[event->ifidx]; | ||
254 | |||
255 | brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", | 253 | brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", |
256 | brcmf_fweh_event_name(event->code), event->code, | 254 | brcmf_fweh_event_name(event->code), event->code, |
257 | event->emsg.ifidx, event->emsg.bsscfgidx, | 255 | event->emsg.ifidx, event->emsg.bsscfgidx, |
@@ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) | |||
283 | goto event_free; | 281 | goto event_free; |
284 | } | 282 | } |
285 | 283 | ||
284 | ifp = drvr->iflist[emsg.bsscfgidx]; | ||
286 | err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, | 285 | err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, |
287 | event->data); | 286 | event->data); |
288 | if (err) { | 287 | if (err) { |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index 36901f76a3b5..8c39b51dcccf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h | |||
@@ -83,6 +83,7 @@ struct brcmf_event; | |||
83 | BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ | 83 | BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ |
84 | BRCMF_ENUM_DEF(TRACE, 52) \ | 84 | BRCMF_ENUM_DEF(TRACE, 52) \ |
85 | BRCMF_ENUM_DEF(IF, 54) \ | 85 | BRCMF_ENUM_DEF(IF, 54) \ |
86 | BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ | ||
86 | BRCMF_ENUM_DEF(RSSI, 56) \ | 87 | BRCMF_ENUM_DEF(RSSI, 56) \ |
87 | BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ | 88 | BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ |
88 | BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ | 89 | BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ |
@@ -96,8 +97,11 @@ struct brcmf_event; | |||
96 | BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ | 97 | BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ |
97 | BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ | 98 | BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ |
98 | BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ | 99 | BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ |
100 | BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \ | ||
101 | BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \ | ||
99 | BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ | 102 | BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ |
100 | BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) | 103 | BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ |
104 | BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) | ||
101 | 105 | ||
102 | #define BRCMF_ENUM_DEF(id, val) \ | 106 | #define BRCMF_ENUM_DEF(id, val) \ |
103 | BRCMF_E_##id = (val), | 107 | BRCMF_E_##id = (val), |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index d8d8b6549dc5..8d1def935b8d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c | |||
@@ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) | |||
45 | if (data != NULL) | 45 | if (data != NULL) |
46 | len = min_t(uint, len, BRCMF_DCMD_MAXLEN); | 46 | len = min_t(uint, len, BRCMF_DCMD_MAXLEN); |
47 | if (set) | 47 | if (set) |
48 | err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len); | 48 | err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data, |
49 | len); | ||
49 | else | 50 | else |
50 | err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data, | 51 | err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, |
51 | len); | 52 | len); |
52 | 53 | ||
53 | if (err >= 0) | 54 | if (err >= 0) |
@@ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) | |||
100 | __le32 data_le = cpu_to_le32(data); | 101 | __le32 data_le = cpu_to_le32(data); |
101 | 102 | ||
102 | mutex_lock(&ifp->drvr->proto_block); | 103 | mutex_lock(&ifp->drvr->proto_block); |
104 | brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data); | ||
103 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); | 105 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); |
104 | mutex_unlock(&ifp->drvr->proto_block); | 106 | mutex_unlock(&ifp->drvr->proto_block); |
105 | 107 | ||
@@ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) | |||
116 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); | 118 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); |
117 | mutex_unlock(&ifp->drvr->proto_block); | 119 | mutex_unlock(&ifp->drvr->proto_block); |
118 | *data = le32_to_cpu(data_le); | 120 | *data = le32_to_cpu(data_le); |
121 | brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data); | ||
119 | 122 | ||
120 | return err; | 123 | return err; |
121 | } | 124 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h new file mode 100644 index 000000000000..0f2c83bc95dc --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | |||
18 | #ifndef FWIL_TYPES_H_ | ||
19 | #define FWIL_TYPES_H_ | ||
20 | |||
21 | #include <linux/if_ether.h> | ||
22 | |||
23 | |||
24 | #define BRCMF_FIL_ACTION_FRAME_SIZE 1800 | ||
25 | |||
26 | |||
27 | enum brcmf_fil_p2p_if_types { | ||
28 | BRCMF_FIL_P2P_IF_CLIENT, | ||
29 | BRCMF_FIL_P2P_IF_GO, | ||
30 | BRCMF_FIL_P2P_IF_DYNBCN_GO, | ||
31 | BRCMF_FIL_P2P_IF_DEV, | ||
32 | }; | ||
33 | |||
34 | struct brcmf_fil_p2p_if_le { | ||
35 | u8 addr[ETH_ALEN]; | ||
36 | __le16 type; | ||
37 | __le16 chspec; | ||
38 | }; | ||
39 | |||
40 | struct brcmf_fil_chan_info_le { | ||
41 | __le32 hw_channel; | ||
42 | __le32 target_channel; | ||
43 | __le32 scan_channel; | ||
44 | }; | ||
45 | |||
46 | struct brcmf_fil_action_frame_le { | ||
47 | u8 da[ETH_ALEN]; | ||
48 | __le16 len; | ||
49 | __le32 packet_id; | ||
50 | u8 data[BRCMF_FIL_ACTION_FRAME_SIZE]; | ||
51 | }; | ||
52 | |||
53 | struct brcmf_fil_af_params_le { | ||
54 | __le32 channel; | ||
55 | __le32 dwell_time; | ||
56 | u8 bssid[ETH_ALEN]; | ||
57 | u8 pad[2]; | ||
58 | struct brcmf_fil_action_frame_le action_frame; | ||
59 | }; | ||
60 | |||
61 | struct brcmf_fil_bss_enable_le { | ||
62 | __le32 bsscfg_idx; | ||
63 | __le32 enable; | ||
64 | }; | ||
65 | |||
66 | #endif /* FWIL_TYPES_H_ */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c new file mode 100644 index 000000000000..4166e642068b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |||
@@ -0,0 +1,2277 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <net/cfg80211.h> | ||
19 | |||
20 | #include <brcmu_wifi.h> | ||
21 | #include <brcmu_utils.h> | ||
22 | #include <defs.h> | ||
23 | #include <dhd.h> | ||
24 | #include <dhd_dbg.h> | ||
25 | #include "fwil.h" | ||
26 | #include "fwil_types.h" | ||
27 | #include "p2p.h" | ||
28 | #include "wl_cfg80211.h" | ||
29 | |||
30 | /* parameters used for p2p escan */ | ||
31 | #define P2PAPI_SCAN_NPROBES 1 | ||
32 | #define P2PAPI_SCAN_DWELL_TIME_MS 80 | ||
33 | #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 | ||
34 | #define P2PAPI_SCAN_HOME_TIME_MS 60 | ||
35 | #define P2PAPI_SCAN_NPROBS_TIME_MS 30 | ||
36 | #define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 | ||
37 | #define WL_SCAN_CONNECT_DWELL_TIME_MS 200 | ||
38 | #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 | ||
39 | |||
40 | #define BRCMF_P2P_WILDCARD_SSID "DIRECT-" | ||
41 | #define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1) | ||
42 | |||
43 | #define SOCIAL_CHAN_1 1 | ||
44 | #define SOCIAL_CHAN_2 6 | ||
45 | #define SOCIAL_CHAN_3 11 | ||
46 | #define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ | ||
47 | (channel == SOCIAL_CHAN_2) || \ | ||
48 | (channel == SOCIAL_CHAN_3)) | ||
49 | #define SOCIAL_CHAN_CNT 3 | ||
50 | #define AF_PEER_SEARCH_CNT 2 | ||
51 | |||
52 | #define BRCMF_SCB_TIMEOUT_VALUE 20 | ||
53 | |||
54 | #define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */ | ||
55 | #define P2P_PUB_AF_CATEGORY 0x04 | ||
56 | #define P2P_PUB_AF_ACTION 0x09 | ||
57 | #define P2P_AF_CATEGORY 0x7f | ||
58 | #define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */ | ||
59 | #define P2P_OUI_LEN 3 /* P2P OUI length */ | ||
60 | |||
61 | /* Action Frame Constants */ | ||
62 | #define DOT11_ACTION_HDR_LEN 2 /* action frame category + action */ | ||
63 | #define DOT11_ACTION_CAT_OFF 0 /* category offset */ | ||
64 | #define DOT11_ACTION_ACT_OFF 1 /* action offset */ | ||
65 | |||
66 | #define P2P_AF_DWELL_TIME 200 | ||
67 | #define P2P_AF_MIN_DWELL_TIME 100 | ||
68 | #define P2P_AF_MED_DWELL_TIME 400 | ||
69 | #define P2P_AF_LONG_DWELL_TIME 1000 | ||
70 | #define P2P_AF_TX_MAX_RETRY 1 | ||
71 | #define P2P_AF_MAX_WAIT_TIME 2000 | ||
72 | #define P2P_INVALID_CHANNEL -1 | ||
73 | #define P2P_CHANNEL_SYNC_RETRY 5 | ||
74 | #define P2P_AF_FRM_SCAN_MAX_WAIT 1500 | ||
75 | #define P2P_DEFAULT_SLEEP_TIME_VSDB 200 | ||
76 | |||
77 | /* WiFi P2P Public Action Frame OUI Subtypes */ | ||
78 | #define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ | ||
79 | #define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ | ||
80 | #define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ | ||
81 | #define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ | ||
82 | #define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ | ||
83 | #define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ | ||
84 | #define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ | ||
85 | #define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ | ||
86 | #define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ | ||
87 | #define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ | ||
88 | |||
89 | /* WiFi P2P Action Frame OUI Subtypes */ | ||
90 | #define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ | ||
91 | #define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ | ||
92 | #define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ | ||
93 | #define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ | ||
94 | |||
95 | /* P2P Service Discovery related */ | ||
96 | #define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */ | ||
97 | #define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */ | ||
98 | #define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */ | ||
99 | #define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */ | ||
100 | #define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */ | ||
101 | |||
102 | /** | ||
103 | * struct brcmf_p2p_disc_st_le - set discovery state in firmware. | ||
104 | * | ||
105 | * @state: requested discovery state (see enum brcmf_p2p_disc_state). | ||
106 | * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state. | ||
107 | * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state. | ||
108 | */ | ||
109 | struct brcmf_p2p_disc_st_le { | ||
110 | u8 state; | ||
111 | __le16 chspec; | ||
112 | __le16 dwell; | ||
113 | }; | ||
114 | |||
115 | /** | ||
116 | * enum brcmf_p2p_disc_state - P2P discovery state values | ||
117 | * | ||
118 | * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE. | ||
119 | * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time. | ||
120 | * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE. | ||
121 | */ | ||
122 | enum brcmf_p2p_disc_state { | ||
123 | WL_P2P_DISC_ST_SCAN, | ||
124 | WL_P2P_DISC_ST_LISTEN, | ||
125 | WL_P2P_DISC_ST_SEARCH | ||
126 | }; | ||
127 | |||
128 | /** | ||
129 | * struct brcmf_p2p_scan_le - P2P specific scan request. | ||
130 | * | ||
131 | * @type: type of scan method requested (values: 'E' or 'S'). | ||
132 | * @reserved: reserved (ignored). | ||
133 | * @eparams: parameters used for type 'E'. | ||
134 | * @sparams: parameters used for type 'S'. | ||
135 | */ | ||
136 | struct brcmf_p2p_scan_le { | ||
137 | u8 type; | ||
138 | u8 reserved[3]; | ||
139 | union { | ||
140 | struct brcmf_escan_params_le eparams; | ||
141 | struct brcmf_scan_params_le sparams; | ||
142 | }; | ||
143 | }; | ||
144 | |||
145 | /** | ||
146 | * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame | ||
147 | * | ||
148 | * @category: P2P_PUB_AF_CATEGORY | ||
149 | * @action: P2P_PUB_AF_ACTION | ||
150 | * @oui[3]: P2P_OUI | ||
151 | * @oui_type: OUI type - P2P_VER | ||
152 | * @subtype: OUI subtype - P2P_TYPE_* | ||
153 | * @dialog_token: nonzero, identifies req/rsp transaction | ||
154 | * @elts[1]: Variable length information elements. | ||
155 | */ | ||
156 | struct brcmf_p2p_pub_act_frame { | ||
157 | u8 category; | ||
158 | u8 action; | ||
159 | u8 oui[3]; | ||
160 | u8 oui_type; | ||
161 | u8 subtype; | ||
162 | u8 dialog_token; | ||
163 | u8 elts[1]; | ||
164 | }; | ||
165 | |||
166 | /** | ||
167 | * struct brcmf_p2p_action_frame - WiFi P2P Action Frame | ||
168 | * | ||
169 | * @category: P2P_AF_CATEGORY | ||
170 | * @OUI[3]: OUI - P2P_OUI | ||
171 | * @type: OUI Type - P2P_VER | ||
172 | * @subtype: OUI Subtype - P2P_AF_* | ||
173 | * @dialog_token: nonzero, identifies req/resp tranaction | ||
174 | * @elts[1]: Variable length information elements. | ||
175 | */ | ||
176 | struct brcmf_p2p_action_frame { | ||
177 | u8 category; | ||
178 | u8 oui[3]; | ||
179 | u8 type; | ||
180 | u8 subtype; | ||
181 | u8 dialog_token; | ||
182 | u8 elts[1]; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame | ||
187 | * | ||
188 | * @category: 0x04 Public Action Frame | ||
189 | * @action: 0x6c Advertisement Protocol | ||
190 | * @dialog_token: nonzero, identifies req/rsp transaction | ||
191 | * @query_data[1]: Query Data. SD gas ireq SD gas iresp | ||
192 | */ | ||
193 | struct brcmf_p2psd_gas_pub_act_frame { | ||
194 | u8 category; | ||
195 | u8 action; | ||
196 | u8 dialog_token; | ||
197 | u8 query_data[1]; | ||
198 | }; | ||
199 | |||
200 | /** | ||
201 | * struct brcmf_config_af_params - Action Frame Parameters for tx. | ||
202 | * | ||
203 | * @mpc_onoff: To make sure to send successfully action frame, we have to | ||
204 | * turn off mpc 0: off, 1: on, (-1): do nothing | ||
205 | * @search_channel: 1: search peer's channel to send af | ||
206 | * extra_listen: keep the dwell time to get af response frame. | ||
207 | */ | ||
208 | struct brcmf_config_af_params { | ||
209 | s32 mpc_onoff; | ||
210 | bool search_channel; | ||
211 | bool extra_listen; | ||
212 | }; | ||
213 | |||
214 | /** | ||
215 | * brcmf_p2p_is_pub_action() - true if p2p public type frame. | ||
216 | * | ||
217 | * @frame: action frame data. | ||
218 | * @frame_len: length of action frame data. | ||
219 | * | ||
220 | * Determine if action frame is p2p public action type | ||
221 | */ | ||
222 | static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len) | ||
223 | { | ||
224 | struct brcmf_p2p_pub_act_frame *pact_frm; | ||
225 | |||
226 | if (frame == NULL) | ||
227 | return false; | ||
228 | |||
229 | pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; | ||
230 | if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1) | ||
231 | return false; | ||
232 | |||
233 | if (pact_frm->category == P2P_PUB_AF_CATEGORY && | ||
234 | pact_frm->action == P2P_PUB_AF_ACTION && | ||
235 | pact_frm->oui_type == P2P_VER && | ||
236 | memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) | ||
237 | return true; | ||
238 | |||
239 | return false; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * brcmf_p2p_is_p2p_action() - true if p2p action type frame. | ||
244 | * | ||
245 | * @frame: action frame data. | ||
246 | * @frame_len: length of action frame data. | ||
247 | * | ||
248 | * Determine if action frame is p2p action type | ||
249 | */ | ||
250 | static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len) | ||
251 | { | ||
252 | struct brcmf_p2p_action_frame *act_frm; | ||
253 | |||
254 | if (frame == NULL) | ||
255 | return false; | ||
256 | |||
257 | act_frm = (struct brcmf_p2p_action_frame *)frame; | ||
258 | if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1) | ||
259 | return false; | ||
260 | |||
261 | if (act_frm->category == P2P_AF_CATEGORY && | ||
262 | act_frm->type == P2P_VER && | ||
263 | memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) | ||
264 | return true; | ||
265 | |||
266 | return false; | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * brcmf_p2p_is_gas_action() - true if p2p gas action type frame. | ||
271 | * | ||
272 | * @frame: action frame data. | ||
273 | * @frame_len: length of action frame data. | ||
274 | * | ||
275 | * Determine if action frame is p2p gas action type | ||
276 | */ | ||
277 | static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len) | ||
278 | { | ||
279 | struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; | ||
280 | |||
281 | if (frame == NULL) | ||
282 | return false; | ||
283 | |||
284 | sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; | ||
285 | if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1) | ||
286 | return false; | ||
287 | |||
288 | if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) | ||
289 | return false; | ||
290 | |||
291 | if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || | ||
292 | sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || | ||
293 | sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || | ||
294 | sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) | ||
295 | return true; | ||
296 | |||
297 | return false; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * brcmf_p2p_print_actframe() - debug print routine. | ||
302 | * | ||
303 | * @tx: Received or to be transmitted | ||
304 | * @frame: action frame data. | ||
305 | * @frame_len: length of action frame data. | ||
306 | * | ||
307 | * Print information about the p2p action frame | ||
308 | */ | ||
309 | |||
310 | #ifdef DEBUG | ||
311 | |||
312 | static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) | ||
313 | { | ||
314 | struct brcmf_p2p_pub_act_frame *pact_frm; | ||
315 | struct brcmf_p2p_action_frame *act_frm; | ||
316 | struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; | ||
317 | |||
318 | if (!frame || frame_len <= 2) | ||
319 | return; | ||
320 | |||
321 | if (brcmf_p2p_is_pub_action(frame, frame_len)) { | ||
322 | pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; | ||
323 | switch (pact_frm->subtype) { | ||
324 | case P2P_PAF_GON_REQ: | ||
325 | brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n", | ||
326 | (tx) ? "TX" : "RX"); | ||
327 | break; | ||
328 | case P2P_PAF_GON_RSP: | ||
329 | brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n", | ||
330 | (tx) ? "TX" : "RX"); | ||
331 | break; | ||
332 | case P2P_PAF_GON_CONF: | ||
333 | brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n", | ||
334 | (tx) ? "TX" : "RX"); | ||
335 | break; | ||
336 | case P2P_PAF_INVITE_REQ: | ||
337 | brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n", | ||
338 | (tx) ? "TX" : "RX"); | ||
339 | break; | ||
340 | case P2P_PAF_INVITE_RSP: | ||
341 | brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n", | ||
342 | (tx) ? "TX" : "RX"); | ||
343 | break; | ||
344 | case P2P_PAF_DEVDIS_REQ: | ||
345 | brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n", | ||
346 | (tx) ? "TX" : "RX"); | ||
347 | break; | ||
348 | case P2P_PAF_DEVDIS_RSP: | ||
349 | brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n", | ||
350 | (tx) ? "TX" : "RX"); | ||
351 | break; | ||
352 | case P2P_PAF_PROVDIS_REQ: | ||
353 | brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n", | ||
354 | (tx) ? "TX" : "RX"); | ||
355 | break; | ||
356 | case P2P_PAF_PROVDIS_RSP: | ||
357 | brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n", | ||
358 | (tx) ? "TX" : "RX"); | ||
359 | break; | ||
360 | default: | ||
361 | brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n", | ||
362 | (tx) ? "TX" : "RX"); | ||
363 | break; | ||
364 | } | ||
365 | } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) { | ||
366 | act_frm = (struct brcmf_p2p_action_frame *)frame; | ||
367 | switch (act_frm->subtype) { | ||
368 | case P2P_AF_NOTICE_OF_ABSENCE: | ||
369 | brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n", | ||
370 | (tx) ? "TX" : "RX"); | ||
371 | break; | ||
372 | case P2P_AF_PRESENCE_REQ: | ||
373 | brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n", | ||
374 | (tx) ? "TX" : "RX"); | ||
375 | break; | ||
376 | case P2P_AF_PRESENCE_RSP: | ||
377 | brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n", | ||
378 | (tx) ? "TX" : "RX"); | ||
379 | break; | ||
380 | case P2P_AF_GO_DISC_REQ: | ||
381 | brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n", | ||
382 | (tx) ? "TX" : "RX"); | ||
383 | break; | ||
384 | default: | ||
385 | brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n", | ||
386 | (tx) ? "TX" : "RX"); | ||
387 | } | ||
388 | |||
389 | } else if (brcmf_p2p_is_gas_action(frame, frame_len)) { | ||
390 | sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; | ||
391 | switch (sd_act_frm->action) { | ||
392 | case P2PSD_ACTION_ID_GAS_IREQ: | ||
393 | brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n", | ||
394 | (tx) ? "TX" : "RX"); | ||
395 | break; | ||
396 | case P2PSD_ACTION_ID_GAS_IRESP: | ||
397 | brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n", | ||
398 | (tx) ? "TX" : "RX"); | ||
399 | break; | ||
400 | case P2PSD_ACTION_ID_GAS_CREQ: | ||
401 | brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n", | ||
402 | (tx) ? "TX" : "RX"); | ||
403 | break; | ||
404 | case P2PSD_ACTION_ID_GAS_CRESP: | ||
405 | brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n", | ||
406 | (tx) ? "TX" : "RX"); | ||
407 | break; | ||
408 | default: | ||
409 | brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n", | ||
410 | (tx) ? "TX" : "RX"); | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | #else | ||
417 | |||
418 | static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) | ||
419 | { | ||
420 | } | ||
421 | |||
422 | #endif | ||
423 | |||
424 | |||
425 | /** | ||
426 | * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec. | ||
427 | * | ||
428 | * @channel: channel number | ||
429 | */ | ||
430 | static u16 brcmf_p2p_chnr_to_chspec(u16 channel) | ||
431 | { | ||
432 | u16 chanspec; | ||
433 | |||
434 | chanspec = channel & WL_CHANSPEC_CHAN_MASK; | ||
435 | |||
436 | if (channel <= CH_MAX_2G_CHANNEL) | ||
437 | chanspec |= WL_CHANSPEC_BAND_2G; | ||
438 | else | ||
439 | chanspec |= WL_CHANSPEC_BAND_5G; | ||
440 | |||
441 | chanspec |= WL_CHANSPEC_BW_20; | ||
442 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | ||
443 | |||
444 | return chanspec; | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation. | ||
450 | * | ||
451 | * @ifp: ifp to use for iovars (primary). | ||
452 | * @p2p_mac: mac address to configure for p2p_da_override | ||
453 | */ | ||
454 | static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) | ||
455 | { | ||
456 | s32 ret = 0; | ||
457 | |||
458 | brcmf_fil_iovar_int_set(ifp, "apsta", 1); | ||
459 | |||
460 | /* In case of COB type, firmware has default mac address | ||
461 | * After Initializing firmware, we have to set current mac address to | ||
462 | * firmware for P2P device address | ||
463 | */ | ||
464 | ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac, | ||
465 | ETH_ALEN); | ||
466 | if (ret) | ||
467 | brcmf_err("failed to update device address ret %d\n", ret); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P. | ||
474 | * | ||
475 | * @p2p: P2P specific data. | ||
476 | * | ||
477 | * P2P needs mac addresses for P2P device and interface. These are | ||
478 | * derived from the primary net device, ie. the permanent ethernet | ||
479 | * address of the device. | ||
480 | */ | ||
481 | static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p) | ||
482 | { | ||
483 | struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
484 | struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; | ||
485 | |||
486 | /* Generate the P2P Device Address. This consists of the device's | ||
487 | * primary MAC address with the locally administered bit set. | ||
488 | */ | ||
489 | memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN); | ||
490 | p2p->dev_addr[0] |= 0x02; | ||
491 | memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); | ||
492 | |||
493 | /* Generate the P2P Interface Address. If the discovery and connection | ||
494 | * BSSCFGs need to simultaneously co-exist, then this address must be | ||
495 | * different from the P2P Device Address, but also locally administered. | ||
496 | */ | ||
497 | memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN); | ||
498 | p2p->int_addr[4] ^= 0x80; | ||
499 | } | ||
500 | |||
501 | /** | ||
502 | * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan. | ||
503 | * | ||
504 | * @request: the scan request as received from cfg80211. | ||
505 | * | ||
506 | * returns true if one of the ssids in the request matches the | ||
507 | * P2P wildcard ssid; otherwise returns false. | ||
508 | */ | ||
509 | static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request) | ||
510 | { | ||
511 | struct cfg80211_ssid *ssids = request->ssids; | ||
512 | int i; | ||
513 | |||
514 | for (i = 0; i < request->n_ssids; i++) { | ||
515 | if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN) | ||
516 | continue; | ||
517 | |||
518 | brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid); | ||
519 | if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid, | ||
520 | BRCMF_P2P_WILDCARD_SSID_LEN)) | ||
521 | return true; | ||
522 | } | ||
523 | return false; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * brcmf_p2p_set_discover_state - set discover state in firmware. | ||
528 | * | ||
529 | * @ifp: low-level interface object. | ||
530 | * @state: discover state to set. | ||
531 | * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only). | ||
532 | * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only). | ||
533 | */ | ||
534 | static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state, | ||
535 | u16 chanspec, u16 listen_ms) | ||
536 | { | ||
537 | struct brcmf_p2p_disc_st_le discover_state; | ||
538 | s32 ret = 0; | ||
539 | brcmf_dbg(TRACE, "enter\n"); | ||
540 | |||
541 | discover_state.state = state; | ||
542 | discover_state.chspec = cpu_to_le16(chanspec); | ||
543 | discover_state.dwell = cpu_to_le16(listen_ms); | ||
544 | ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state, | ||
545 | sizeof(discover_state)); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * brcmf_p2p_deinit_discovery() - disable P2P device discovery. | ||
551 | * | ||
552 | * @p2p: P2P specific data. | ||
553 | * | ||
554 | * Resets the discovery state and disables it in firmware. | ||
555 | */ | ||
556 | static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) | ||
557 | { | ||
558 | struct brcmf_cfg80211_vif *vif; | ||
559 | |||
560 | brcmf_dbg(TRACE, "enter\n"); | ||
561 | |||
562 | /* Set the discovery state to SCAN */ | ||
563 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
564 | (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
565 | |||
566 | /* Disable P2P discovery in the firmware */ | ||
567 | vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
568 | (void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * brcmf_p2p_enable_discovery() - initialize and configure discovery. | ||
575 | * | ||
576 | * @p2p: P2P specific data. | ||
577 | * | ||
578 | * Initializes the discovery device and configure the virtual interface. | ||
579 | */ | ||
580 | static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) | ||
581 | { | ||
582 | struct brcmf_cfg80211_vif *vif; | ||
583 | s32 ret = 0; | ||
584 | |||
585 | brcmf_dbg(TRACE, "enter\n"); | ||
586 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
587 | if (!vif) { | ||
588 | brcmf_err("P2P config device not available\n"); | ||
589 | ret = -EPERM; | ||
590 | goto exit; | ||
591 | } | ||
592 | |||
593 | if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) { | ||
594 | brcmf_dbg(INFO, "P2P config device already configured\n"); | ||
595 | goto exit; | ||
596 | } | ||
597 | |||
598 | /* Re-initialize P2P Discovery in the firmware */ | ||
599 | vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
600 | ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1); | ||
601 | if (ret < 0) { | ||
602 | brcmf_err("set p2p_disc error\n"); | ||
603 | goto exit; | ||
604 | } | ||
605 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
606 | ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
607 | if (ret < 0) { | ||
608 | brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n"); | ||
609 | goto exit; | ||
610 | } | ||
611 | |||
612 | /* | ||
613 | * Set wsec to any non-zero value in the discovery bsscfg | ||
614 | * to ensure our P2P probe responses have the privacy bit | ||
615 | * set in the 802.11 WPA IE. Some peer devices may not | ||
616 | * initiate WPS with us if this bit is not set. | ||
617 | */ | ||
618 | ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED); | ||
619 | if (ret < 0) { | ||
620 | brcmf_err("wsec error %d\n", ret); | ||
621 | goto exit; | ||
622 | } | ||
623 | |||
624 | set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status); | ||
625 | exit: | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | /** | ||
630 | * brcmf_p2p_escan() - initiate a P2P scan. | ||
631 | * | ||
632 | * @p2p: P2P specific data. | ||
633 | * @num_chans: number of channels to scan. | ||
634 | * @chanspecs: channel parameters for @num_chans channels. | ||
635 | * @search_state: P2P discover state to use. | ||
636 | * @action: scan action to pass to firmware. | ||
637 | * @bss_type: type of P2P bss. | ||
638 | */ | ||
639 | static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, | ||
640 | u16 chanspecs[], s32 search_state, u16 action, | ||
641 | enum p2p_bss_type bss_type) | ||
642 | { | ||
643 | s32 ret = 0; | ||
644 | s32 memsize = offsetof(struct brcmf_p2p_scan_le, | ||
645 | eparams.params_le.channel_list); | ||
646 | s32 nprobes; | ||
647 | s32 active; | ||
648 | u32 i; | ||
649 | u8 *memblk; | ||
650 | struct brcmf_cfg80211_vif *vif; | ||
651 | struct brcmf_p2p_scan_le *p2p_params; | ||
652 | struct brcmf_scan_params_le *sparams; | ||
653 | struct brcmf_ssid ssid; | ||
654 | |||
655 | memsize += num_chans * sizeof(__le16); | ||
656 | memblk = kzalloc(memsize, GFP_KERNEL); | ||
657 | if (!memblk) | ||
658 | return -ENOMEM; | ||
659 | |||
660 | vif = p2p->bss_idx[bss_type].vif; | ||
661 | if (vif == NULL) { | ||
662 | brcmf_err("no vif for bss type %d\n", bss_type); | ||
663 | ret = -EINVAL; | ||
664 | goto exit; | ||
665 | } | ||
666 | |||
667 | switch (search_state) { | ||
668 | case WL_P2P_DISC_ST_SEARCH: | ||
669 | /* | ||
670 | * If we in SEARCH STATE, we don't need to set SSID explictly | ||
671 | * because dongle use P2P WILDCARD internally by default | ||
672 | */ | ||
673 | /* use null ssid */ | ||
674 | ssid.SSID_len = 0; | ||
675 | memset(ssid.SSID, 0, sizeof(ssid.SSID)); | ||
676 | break; | ||
677 | case WL_P2P_DISC_ST_SCAN: | ||
678 | /* | ||
679 | * wpa_supplicant has p2p_find command with type social or | ||
680 | * progressive. For progressive, we need to set the ssid to | ||
681 | * P2P WILDCARD because we just do broadcast scan unless | ||
682 | * setting SSID. | ||
683 | */ | ||
684 | ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN; | ||
685 | memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len); | ||
686 | break; | ||
687 | default: | ||
688 | brcmf_err(" invalid search state %d\n", search_state); | ||
689 | ret = -EINVAL; | ||
690 | goto exit; | ||
691 | } | ||
692 | |||
693 | brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0); | ||
694 | |||
695 | /* | ||
696 | * set p2p scan parameters. | ||
697 | */ | ||
698 | p2p_params = (struct brcmf_p2p_scan_le *)memblk; | ||
699 | p2p_params->type = 'E'; | ||
700 | |||
701 | /* determine the scan engine parameters */ | ||
702 | sparams = &p2p_params->eparams.params_le; | ||
703 | sparams->bss_type = DOT11_BSSTYPE_ANY; | ||
704 | if (p2p->cfg->active_scan) | ||
705 | sparams->scan_type = 0; | ||
706 | else | ||
707 | sparams->scan_type = 1; | ||
708 | |||
709 | memset(&sparams->bssid, 0xFF, ETH_ALEN); | ||
710 | if (ssid.SSID_len) | ||
711 | memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len); | ||
712 | sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); | ||
713 | sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS); | ||
714 | |||
715 | /* | ||
716 | * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan | ||
717 | * supported by the supplicant. | ||
718 | */ | ||
719 | if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1)) | ||
720 | active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS; | ||
721 | else if (num_chans == AF_PEER_SEARCH_CNT) | ||
722 | active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS; | ||
723 | else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED)) | ||
724 | active = -1; | ||
725 | else | ||
726 | active = P2PAPI_SCAN_DWELL_TIME_MS; | ||
727 | |||
728 | /* Override scan params to find a peer for a connection */ | ||
729 | if (num_chans == 1) { | ||
730 | active = WL_SCAN_CONNECT_DWELL_TIME_MS; | ||
731 | /* WAR to sync with presence period of VSDB GO. | ||
732 | * send probe request more frequently | ||
733 | */ | ||
734 | nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS; | ||
735 | } else { | ||
736 | nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS; | ||
737 | } | ||
738 | |||
739 | if (nprobes <= 0) | ||
740 | nprobes = 1; | ||
741 | |||
742 | brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active); | ||
743 | sparams->active_time = cpu_to_le32(active); | ||
744 | sparams->nprobes = cpu_to_le32(nprobes); | ||
745 | sparams->passive_time = cpu_to_le32(-1); | ||
746 | sparams->channel_num = cpu_to_le32(num_chans & | ||
747 | BRCMF_SCAN_PARAMS_COUNT_MASK); | ||
748 | for (i = 0; i < num_chans; i++) | ||
749 | sparams->channel_list[i] = cpu_to_le16(chanspecs[i]); | ||
750 | |||
751 | /* set the escan specific parameters */ | ||
752 | p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); | ||
753 | p2p_params->eparams.action = cpu_to_le16(action); | ||
754 | p2p_params->eparams.sync_id = cpu_to_le16(0x1234); | ||
755 | /* perform p2p scan on primary device */ | ||
756 | ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize); | ||
757 | if (!ret) | ||
758 | set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status); | ||
759 | exit: | ||
760 | kfree(memblk); | ||
761 | return ret; | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * brcmf_p2p_run_escan() - escan callback for peer-to-peer. | ||
766 | * | ||
767 | * @cfg: driver private data for cfg80211 interface. | ||
768 | * @ndev: net device for which scan is requested. | ||
769 | * @request: scan request from cfg80211. | ||
770 | * @action: scan action. | ||
771 | * | ||
772 | * Determines the P2P discovery state based to scan request parameters and | ||
773 | * validates the channels in the request. | ||
774 | */ | ||
775 | static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, | ||
776 | struct net_device *ndev, | ||
777 | struct cfg80211_scan_request *request, | ||
778 | u16 action) | ||
779 | { | ||
780 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
781 | s32 err = 0; | ||
782 | s32 search_state = WL_P2P_DISC_ST_SCAN; | ||
783 | struct brcmf_cfg80211_vif *vif; | ||
784 | struct net_device *dev = NULL; | ||
785 | int i, num_nodfs = 0; | ||
786 | u16 *chanspecs; | ||
787 | |||
788 | brcmf_dbg(TRACE, "enter\n"); | ||
789 | |||
790 | if (!request) { | ||
791 | err = -EINVAL; | ||
792 | goto exit; | ||
793 | } | ||
794 | |||
795 | if (request->n_channels) { | ||
796 | chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs), | ||
797 | GFP_KERNEL); | ||
798 | if (!chanspecs) { | ||
799 | err = -ENOMEM; | ||
800 | goto exit; | ||
801 | } | ||
802 | vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; | ||
803 | if (vif) | ||
804 | dev = vif->wdev.netdev; | ||
805 | if (request->n_channels == 3 && | ||
806 | request->channels[0]->hw_value == SOCIAL_CHAN_1 && | ||
807 | request->channels[1]->hw_value == SOCIAL_CHAN_2 && | ||
808 | request->channels[2]->hw_value == SOCIAL_CHAN_3) { | ||
809 | /* SOCIAL CHANNELS 1, 6, 11 */ | ||
810 | search_state = WL_P2P_DISC_ST_SEARCH; | ||
811 | brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); | ||
812 | } else if (dev != NULL && vif->mode == WL_MODE_AP) { | ||
813 | /* If you are already a GO, then do SEARCH only */ | ||
814 | brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n"); | ||
815 | search_state = WL_P2P_DISC_ST_SEARCH; | ||
816 | } else { | ||
817 | brcmf_dbg(INFO, "P2P SCAN STATE START\n"); | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * no P2P scanning on passive or DFS channels. | ||
822 | */ | ||
823 | for (i = 0; i < request->n_channels; i++) { | ||
824 | struct ieee80211_channel *chan = request->channels[i]; | ||
825 | |||
826 | if (chan->flags & (IEEE80211_CHAN_RADAR | | ||
827 | IEEE80211_CHAN_PASSIVE_SCAN)) | ||
828 | continue; | ||
829 | |||
830 | chanspecs[i] = channel_to_chanspec(chan); | ||
831 | brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n", | ||
832 | num_nodfs, chan->hw_value, chanspecs[i]); | ||
833 | num_nodfs++; | ||
834 | } | ||
835 | err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state, | ||
836 | action, P2PAPI_BSSCFG_DEVICE); | ||
837 | } | ||
838 | exit: | ||
839 | if (err) | ||
840 | brcmf_err("error (%d)\n", err); | ||
841 | return err; | ||
842 | } | ||
843 | |||
844 | |||
845 | /** | ||
846 | * brcmf_p2p_find_listen_channel() - find listen channel in ie string. | ||
847 | * | ||
848 | * @ie: string of information elements. | ||
849 | * @ie_len: length of string. | ||
850 | * | ||
851 | * Scan ie for p2p ie and look for attribute 6 channel. If available determine | ||
852 | * channel and return it. | ||
853 | */ | ||
854 | static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len) | ||
855 | { | ||
856 | u8 channel_ie[5]; | ||
857 | s32 listen_channel; | ||
858 | s32 err; | ||
859 | |||
860 | err = cfg80211_get_p2p_attr(ie, ie_len, | ||
861 | IEEE80211_P2P_ATTR_LISTEN_CHANNEL, | ||
862 | channel_ie, sizeof(channel_ie)); | ||
863 | if (err < 0) | ||
864 | return err; | ||
865 | |||
866 | /* listen channel subel length format: */ | ||
867 | /* 3(country) + 1(op. class) + 1(chan num) */ | ||
868 | listen_channel = (s32)channel_ie[3 + 1]; | ||
869 | |||
870 | if (listen_channel == SOCIAL_CHAN_1 || | ||
871 | listen_channel == SOCIAL_CHAN_2 || | ||
872 | listen_channel == SOCIAL_CHAN_3) { | ||
873 | brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel); | ||
874 | return listen_channel; | ||
875 | } | ||
876 | |||
877 | return -EPERM; | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * brcmf_p2p_scan_prep() - prepare scan based on request. | ||
883 | * | ||
884 | * @wiphy: wiphy device. | ||
885 | * @request: scan request from cfg80211. | ||
886 | * @vif: vif on which scan request is to be executed. | ||
887 | * | ||
888 | * Prepare the scan appropriately for type of scan requested. Overrides the | ||
889 | * escan .run() callback for peer-to-peer scanning. | ||
890 | */ | ||
891 | int brcmf_p2p_scan_prep(struct wiphy *wiphy, | ||
892 | struct cfg80211_scan_request *request, | ||
893 | struct brcmf_cfg80211_vif *vif) | ||
894 | { | ||
895 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
896 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
897 | int err = 0; | ||
898 | |||
899 | if (brcmf_p2p_scan_is_p2p_request(request)) { | ||
900 | /* find my listen channel */ | ||
901 | err = brcmf_p2p_find_listen_channel(request->ie, | ||
902 | request->ie_len); | ||
903 | if (err < 0) | ||
904 | return err; | ||
905 | |||
906 | p2p->afx_hdl.my_listen_chan = err; | ||
907 | |||
908 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
909 | brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); | ||
910 | |||
911 | err = brcmf_p2p_enable_discovery(p2p); | ||
912 | if (err) | ||
913 | return err; | ||
914 | |||
915 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
916 | |||
917 | /* override .run_escan() callback. */ | ||
918 | cfg->escan_info.run = brcmf_p2p_run_escan; | ||
919 | } | ||
920 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG, | ||
921 | request->ie, request->ie_len); | ||
922 | return err; | ||
923 | } | ||
924 | |||
925 | |||
926 | /** | ||
927 | * brcmf_p2p_discover_listen() - set firmware to discover listen state. | ||
928 | * | ||
929 | * @p2p: p2p device. | ||
930 | * @channel: channel nr for discover listen. | ||
931 | * @duration: time in ms to stay on channel. | ||
932 | * | ||
933 | */ | ||
934 | static s32 | ||
935 | brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration) | ||
936 | { | ||
937 | struct brcmf_cfg80211_vif *vif; | ||
938 | s32 err = 0; | ||
939 | u16 chanspec; | ||
940 | |||
941 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
942 | if (!vif) { | ||
943 | brcmf_err("Discovery is not set, so we have nothing to do\n"); | ||
944 | err = -EPERM; | ||
945 | goto exit; | ||
946 | } | ||
947 | |||
948 | if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) { | ||
949 | brcmf_err("Previous LISTEN is not completed yet\n"); | ||
950 | /* WAR: prevent cookie mismatch in wpa_supplicant return OK */ | ||
951 | goto exit; | ||
952 | } | ||
953 | |||
954 | chanspec = brcmf_p2p_chnr_to_chspec(channel); | ||
955 | err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN, | ||
956 | chanspec, (u16)duration); | ||
957 | if (!err) { | ||
958 | set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status); | ||
959 | p2p->remain_on_channel_cookie++; | ||
960 | } | ||
961 | exit: | ||
962 | return err; | ||
963 | } | ||
964 | |||
965 | |||
966 | /** | ||
967 | * brcmf_p2p_remain_on_channel() - put device on channel and stay there. | ||
968 | * | ||
969 | * @wiphy: wiphy device. | ||
970 | * @channel: channel to stay on. | ||
971 | * @duration: time in ms to remain on channel. | ||
972 | * | ||
973 | */ | ||
974 | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
975 | struct ieee80211_channel *channel, | ||
976 | unsigned int duration, u64 *cookie) | ||
977 | { | ||
978 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
979 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
980 | s32 err; | ||
981 | u16 channel_nr; | ||
982 | |||
983 | channel_nr = ieee80211_frequency_to_channel(channel->center_freq); | ||
984 | brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr, | ||
985 | duration); | ||
986 | |||
987 | err = brcmf_p2p_enable_discovery(p2p); | ||
988 | if (err) | ||
989 | goto exit; | ||
990 | err = brcmf_p2p_discover_listen(p2p, channel_nr, duration); | ||
991 | if (err) | ||
992 | goto exit; | ||
993 | |||
994 | memcpy(&p2p->remain_on_channel, channel, sizeof(*channel)); | ||
995 | *cookie = p2p->remain_on_channel_cookie; | ||
996 | cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL); | ||
997 | |||
998 | exit: | ||
999 | return err; | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | /** | ||
1004 | * brcmf_p2p_notify_listen_complete() - p2p listen has completed. | ||
1005 | * | ||
1006 | * @ifp: interfac control. | ||
1007 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
1008 | * @data: payload of message. Not used. | ||
1009 | * | ||
1010 | */ | ||
1011 | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||
1012 | const struct brcmf_event_msg *e, | ||
1013 | void *data) | ||
1014 | { | ||
1015 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1016 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1017 | |||
1018 | brcmf_dbg(TRACE, "Enter\n"); | ||
1019 | if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, | ||
1020 | &p2p->status)) { | ||
1021 | if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1022 | &p2p->status)) { | ||
1023 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
1024 | &p2p->status); | ||
1025 | brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n"); | ||
1026 | complete(&p2p->wait_next_af); | ||
1027 | } | ||
1028 | |||
1029 | cfg80211_remain_on_channel_expired(&ifp->vif->wdev, | ||
1030 | p2p->remain_on_channel_cookie, | ||
1031 | &p2p->remain_on_channel, | ||
1032 | GFP_KERNEL); | ||
1033 | } | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | |||
1038 | /** | ||
1039 | * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state. | ||
1040 | * | ||
1041 | * @ifp: interfac control. | ||
1042 | * | ||
1043 | */ | ||
1044 | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp) | ||
1045 | { | ||
1046 | if (!ifp) | ||
1047 | return; | ||
1048 | brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
1049 | brcmf_p2p_notify_listen_complete(ifp, NULL, NULL); | ||
1050 | } | ||
1051 | |||
1052 | |||
1053 | /** | ||
1054 | * brcmf_p2p_act_frm_search() - search function for action frame. | ||
1055 | * | ||
1056 | * @p2p: p2p device. | ||
1057 | * channel: channel on which action frame is to be trasmitted. | ||
1058 | * | ||
1059 | * search function to reach at common channel to send action frame. When | ||
1060 | * channel is 0 then all social channels will be used to send af | ||
1061 | */ | ||
1062 | static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel) | ||
1063 | { | ||
1064 | s32 err; | ||
1065 | u32 channel_cnt; | ||
1066 | u16 *default_chan_list; | ||
1067 | u32 i; | ||
1068 | |||
1069 | brcmf_dbg(TRACE, "Enter\n"); | ||
1070 | |||
1071 | if (channel) | ||
1072 | channel_cnt = AF_PEER_SEARCH_CNT; | ||
1073 | else | ||
1074 | channel_cnt = SOCIAL_CHAN_CNT; | ||
1075 | default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list), | ||
1076 | GFP_KERNEL); | ||
1077 | if (default_chan_list == NULL) { | ||
1078 | brcmf_err("channel list allocation failed\n"); | ||
1079 | err = -ENOMEM; | ||
1080 | goto exit; | ||
1081 | } | ||
1082 | if (channel) { | ||
1083 | /* insert same channel to the chan_list */ | ||
1084 | for (i = 0; i < channel_cnt; i++) | ||
1085 | default_chan_list[i] = | ||
1086 | brcmf_p2p_chnr_to_chspec(channel); | ||
1087 | } else { | ||
1088 | default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1); | ||
1089 | default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2); | ||
1090 | default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3); | ||
1091 | } | ||
1092 | err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list, | ||
1093 | WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START, | ||
1094 | P2PAPI_BSSCFG_DEVICE); | ||
1095 | kfree(default_chan_list); | ||
1096 | exit: | ||
1097 | return err; | ||
1098 | } | ||
1099 | |||
1100 | |||
1101 | /** | ||
1102 | * brcmf_p2p_afx_handler() - afx worker thread. | ||
1103 | * | ||
1104 | * @work: | ||
1105 | * | ||
1106 | */ | ||
1107 | static void brcmf_p2p_afx_handler(struct work_struct *work) | ||
1108 | { | ||
1109 | struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work); | ||
1110 | struct brcmf_p2p_info *p2p = container_of(afx_hdl, | ||
1111 | struct brcmf_p2p_info, | ||
1112 | afx_hdl); | ||
1113 | s32 err; | ||
1114 | |||
1115 | if (!afx_hdl->is_active) | ||
1116 | return; | ||
1117 | |||
1118 | if (afx_hdl->is_listen && afx_hdl->my_listen_chan) | ||
1119 | /* 100ms ~ 300ms */ | ||
1120 | err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan, | ||
1121 | 100 * (1 + (random32() % 3))); | ||
1122 | else | ||
1123 | err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan); | ||
1124 | |||
1125 | if (err) { | ||
1126 | brcmf_err("ERROR occurred! value is (%d)\n", err); | ||
1127 | if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1128 | &p2p->status)) | ||
1129 | complete(&afx_hdl->act_frm_scan); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | /** | ||
1135 | * brcmf_p2p_af_searching_channel() - search channel. | ||
1136 | * | ||
1137 | * @p2p: p2p device info struct. | ||
1138 | * | ||
1139 | */ | ||
1140 | static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) | ||
1141 | { | ||
1142 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1143 | struct brcmf_cfg80211_vif *pri_vif; | ||
1144 | unsigned long duration; | ||
1145 | s32 retry; | ||
1146 | |||
1147 | brcmf_dbg(TRACE, "Enter\n"); | ||
1148 | |||
1149 | pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
1150 | |||
1151 | INIT_COMPLETION(afx_hdl->act_frm_scan); | ||
1152 | set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); | ||
1153 | afx_hdl->is_active = true; | ||
1154 | afx_hdl->peer_chan = P2P_INVALID_CHANNEL; | ||
1155 | |||
1156 | /* Loop to wait until we find a peer's channel or the | ||
1157 | * pending action frame tx is cancelled. | ||
1158 | */ | ||
1159 | retry = 0; | ||
1160 | duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT); | ||
1161 | while ((retry < P2P_CHANNEL_SYNC_RETRY) && | ||
1162 | (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) { | ||
1163 | afx_hdl->is_listen = false; | ||
1164 | brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n", | ||
1165 | retry); | ||
1166 | /* search peer on peer's listen channel */ | ||
1167 | schedule_work(&afx_hdl->afx_work); | ||
1168 | wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration); | ||
1169 | if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || | ||
1170 | (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1171 | &p2p->status))) | ||
1172 | break; | ||
1173 | |||
1174 | if (afx_hdl->my_listen_chan) { | ||
1175 | brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n", | ||
1176 | afx_hdl->my_listen_chan); | ||
1177 | /* listen on my listen channel */ | ||
1178 | afx_hdl->is_listen = true; | ||
1179 | schedule_work(&afx_hdl->afx_work); | ||
1180 | wait_for_completion_timeout(&afx_hdl->act_frm_scan, | ||
1181 | duration); | ||
1182 | } | ||
1183 | if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || | ||
1184 | (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1185 | &p2p->status))) | ||
1186 | break; | ||
1187 | retry++; | ||
1188 | |||
1189 | /* if sta is connected or connecting, sleep for a while before | ||
1190 | * retry af tx or finding a peer | ||
1191 | */ | ||
1192 | if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) || | ||
1193 | test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state)) | ||
1194 | msleep(P2P_DEFAULT_SLEEP_TIME_VSDB); | ||
1195 | } | ||
1196 | |||
1197 | brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n", | ||
1198 | afx_hdl->peer_chan); | ||
1199 | afx_hdl->is_active = false; | ||
1200 | |||
1201 | clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); | ||
1202 | |||
1203 | return afx_hdl->peer_chan; | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | /** | ||
1208 | * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel | ||
1209 | * | ||
1210 | * @cfg: common configuration struct. | ||
1211 | * @bi: bss info struct, result from scan. | ||
1212 | * | ||
1213 | */ | ||
1214 | bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, | ||
1215 | struct brcmf_bss_info_le *bi) | ||
1216 | |||
1217 | { | ||
1218 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1219 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1220 | u8 *ie; | ||
1221 | s32 err; | ||
1222 | u8 p2p_dev_addr[ETH_ALEN]; | ||
1223 | |||
1224 | if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status)) | ||
1225 | return false; | ||
1226 | |||
1227 | if (bi == NULL) { | ||
1228 | brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n"); | ||
1229 | if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL) | ||
1230 | complete(&afx_hdl->act_frm_scan); | ||
1231 | return true; | ||
1232 | } | ||
1233 | |||
1234 | ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); | ||
1235 | memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr)); | ||
1236 | err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length), | ||
1237 | IEEE80211_P2P_ATTR_DEVICE_INFO, | ||
1238 | p2p_dev_addr, sizeof(p2p_dev_addr)); | ||
1239 | if (err < 0) | ||
1240 | err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length), | ||
1241 | IEEE80211_P2P_ATTR_DEVICE_ID, | ||
1242 | p2p_dev_addr, sizeof(p2p_dev_addr)); | ||
1243 | if ((err >= 0) && | ||
1244 | (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) { | ||
1245 | afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch : | ||
1246 | CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); | ||
1247 | brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n", | ||
1248 | afx_hdl->tx_dst_addr, afx_hdl->peer_chan); | ||
1249 | complete(&afx_hdl->act_frm_scan); | ||
1250 | } | ||
1251 | return true; | ||
1252 | } | ||
1253 | |||
1254 | /** | ||
1255 | * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete. | ||
1256 | * | ||
1257 | * @cfg: common configuration struct. | ||
1258 | * | ||
1259 | */ | ||
1260 | static void | ||
1261 | brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) | ||
1262 | { | ||
1263 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1264 | struct net_device *ndev = cfg->escan_info.ndev; | ||
1265 | |||
1266 | if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) && | ||
1267 | (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) || | ||
1268 | test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) { | ||
1269 | brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n"); | ||
1270 | /* if channel is not zero, "actfame" uses off channel scan. | ||
1271 | * So abort scan for off channel completion. | ||
1272 | */ | ||
1273 | if (p2p->af_sent_channel) | ||
1274 | brcmf_notify_escan_complete(cfg, ndev, true, true); | ||
1275 | } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1276 | &p2p->status)) { | ||
1277 | brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n"); | ||
1278 | /* So abort scan to cancel listen */ | ||
1279 | brcmf_notify_escan_complete(cfg, ndev, true, true); | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | |||
1284 | /** | ||
1285 | * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission | ||
1286 | * | ||
1287 | * @p2p: p2p device info struct. | ||
1288 | * | ||
1289 | * return true if recevied action frame is to be dropped. | ||
1290 | */ | ||
1291 | static bool | ||
1292 | brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac) | ||
1293 | { | ||
1294 | struct brcmf_cfg80211_info *cfg = p2p->cfg; | ||
1295 | struct brcmf_if *ifp; | ||
1296 | |||
1297 | brcmf_dbg(TRACE, "Enter\n"); | ||
1298 | |||
1299 | if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) || | ||
1300 | !p2p->gon_req_action) | ||
1301 | return false; | ||
1302 | |||
1303 | brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n"); | ||
1304 | /* if sa(peer) addr is less than da(my) addr, then this device | ||
1305 | * process peer's gon request and block to send gon req. | ||
1306 | * if not (sa addr > da addr), | ||
1307 | * this device will process gon request and drop gon req of peer. | ||
1308 | */ | ||
1309 | ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; | ||
1310 | if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) { | ||
1311 | brcmf_dbg(INFO, "Block transmit gon req !!!\n"); | ||
1312 | p2p->block_gon_req_tx = true; | ||
1313 | /* if we are finding a common channel for sending af, | ||
1314 | * do not scan more to block to send current gon req | ||
1315 | */ | ||
1316 | if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1317 | &p2p->status)) | ||
1318 | complete(&p2p->afx_hdl.act_frm_scan); | ||
1319 | if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
1320 | &p2p->status)) | ||
1321 | brcmf_p2p_stop_wait_next_action_frame(cfg); | ||
1322 | return false; | ||
1323 | } | ||
1324 | |||
1325 | /* drop gon request of peer to process gon request by this device. */ | ||
1326 | brcmf_dbg(INFO, "Drop received gon req !!!\n"); | ||
1327 | |||
1328 | return true; | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | /** | ||
1333 | * brcmf_p2p_notify_action_frame_rx() - received action frame. | ||
1334 | * | ||
1335 | * @ifp: interfac control. | ||
1336 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
1337 | * @data: payload of message, containing action frame data. | ||
1338 | * | ||
1339 | */ | ||
1340 | int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, | ||
1341 | const struct brcmf_event_msg *e, | ||
1342 | void *data) | ||
1343 | { | ||
1344 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1345 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1346 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1347 | struct wireless_dev *wdev; | ||
1348 | u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data); | ||
1349 | struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; | ||
1350 | u8 *frame = (u8 *)(rxframe + 1); | ||
1351 | struct brcmf_p2p_pub_act_frame *act_frm; | ||
1352 | struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; | ||
1353 | u16 chanspec = be16_to_cpu(rxframe->chanspec); | ||
1354 | struct ieee80211_mgmt *mgmt_frame; | ||
1355 | s32 freq; | ||
1356 | u16 mgmt_type; | ||
1357 | u8 action; | ||
1358 | |||
1359 | /* Check if wpa_supplicant has registered for this frame */ | ||
1360 | brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg); | ||
1361 | mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4; | ||
1362 | if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) | ||
1363 | return 0; | ||
1364 | |||
1365 | brcmf_p2p_print_actframe(false, frame, mgmt_frame_len); | ||
1366 | |||
1367 | action = P2P_PAF_SUBTYPE_INVALID; | ||
1368 | if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) { | ||
1369 | act_frm = (struct brcmf_p2p_pub_act_frame *)frame; | ||
1370 | action = act_frm->subtype; | ||
1371 | if ((action == P2P_PAF_GON_REQ) && | ||
1372 | (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) { | ||
1373 | if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1374 | &p2p->status) && | ||
1375 | (memcmp(afx_hdl->tx_dst_addr, e->addr, | ||
1376 | ETH_ALEN) == 0)) { | ||
1377 | afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec); | ||
1378 | brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n", | ||
1379 | afx_hdl->peer_chan); | ||
1380 | complete(&afx_hdl->act_frm_scan); | ||
1381 | } | ||
1382 | return 0; | ||
1383 | } | ||
1384 | /* After complete GO Negotiation, roll back to mpc mode */ | ||
1385 | if ((action == P2P_PAF_GON_CONF) || | ||
1386 | (action == P2P_PAF_PROVDIS_RSP)) | ||
1387 | brcmf_set_mpc(ifp->ndev, 1); | ||
1388 | if (action == P2P_PAF_GON_CONF) { | ||
1389 | brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n"); | ||
1390 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1391 | } | ||
1392 | } else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) { | ||
1393 | sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; | ||
1394 | action = sd_act_frm->action; | ||
1395 | } | ||
1396 | |||
1397 | if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) && | ||
1398 | (p2p->next_af_subtype == action)) { | ||
1399 | brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action); | ||
1400 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
1401 | &p2p->status); | ||
1402 | /* Stop waiting for next AF. */ | ||
1403 | brcmf_p2p_stop_wait_next_action_frame(cfg); | ||
1404 | } | ||
1405 | |||
1406 | mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) + | ||
1407 | mgmt_frame_len, GFP_KERNEL); | ||
1408 | if (!mgmt_frame) { | ||
1409 | brcmf_err("No memory available for action frame\n"); | ||
1410 | return -ENOMEM; | ||
1411 | } | ||
1412 | memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); | ||
1413 | brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid, | ||
1414 | ETH_ALEN); | ||
1415 | memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); | ||
1416 | mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); | ||
1417 | memcpy(&mgmt_frame->u, frame, mgmt_frame_len); | ||
1418 | mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); | ||
1419 | |||
1420 | freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), | ||
1421 | CHSPEC_IS2G(chanspec) ? | ||
1422 | IEEE80211_BAND_2GHZ : | ||
1423 | IEEE80211_BAND_5GHZ); | ||
1424 | wdev = ifp->ndev->ieee80211_ptr; | ||
1425 | cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, | ||
1426 | GFP_ATOMIC); | ||
1427 | |||
1428 | kfree(mgmt_frame); | ||
1429 | return 0; | ||
1430 | } | ||
1431 | |||
1432 | |||
1433 | /** | ||
1434 | * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete | ||
1435 | * | ||
1436 | * @ifp: interfac control. | ||
1437 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
1438 | * @data: not used. | ||
1439 | * | ||
1440 | */ | ||
1441 | int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, | ||
1442 | const struct brcmf_event_msg *e, | ||
1443 | void *data) | ||
1444 | { | ||
1445 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1446 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1447 | |||
1448 | brcmf_dbg(INFO, "Enter: event %s, status=%d\n", | ||
1449 | e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ? | ||
1450 | "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE", | ||
1451 | e->status); | ||
1452 | |||
1453 | if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status)) | ||
1454 | return 0; | ||
1455 | |||
1456 | if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) { | ||
1457 | if (e->status == BRCMF_E_STATUS_SUCCESS) | ||
1458 | set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, | ||
1459 | &p2p->status); | ||
1460 | else { | ||
1461 | set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); | ||
1462 | /* If there is no ack, we don't need to wait for | ||
1463 | * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event | ||
1464 | */ | ||
1465 | brcmf_p2p_stop_wait_next_action_frame(cfg); | ||
1466 | } | ||
1467 | |||
1468 | } else { | ||
1469 | complete(&p2p->send_af_done); | ||
1470 | } | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | |||
1475 | /** | ||
1476 | * brcmf_p2p_tx_action_frame() - send action frame over fil. | ||
1477 | * | ||
1478 | * @p2p: p2p info struct for vif. | ||
1479 | * @af_params: action frame data/info. | ||
1480 | * | ||
1481 | * Send an action frame immediately without doing channel synchronization. | ||
1482 | * | ||
1483 | * This function waits for a completion event before returning. | ||
1484 | * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action | ||
1485 | * frame is transmitted. | ||
1486 | */ | ||
1487 | static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, | ||
1488 | struct brcmf_fil_af_params_le *af_params) | ||
1489 | { | ||
1490 | struct brcmf_cfg80211_vif *vif; | ||
1491 | s32 err = 0; | ||
1492 | s32 timeout = 0; | ||
1493 | |||
1494 | brcmf_dbg(TRACE, "Enter\n"); | ||
1495 | |||
1496 | INIT_COMPLETION(p2p->send_af_done); | ||
1497 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); | ||
1498 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); | ||
1499 | |||
1500 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
1501 | err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params, | ||
1502 | sizeof(*af_params)); | ||
1503 | if (err) { | ||
1504 | brcmf_err(" sending action frame has failed\n"); | ||
1505 | goto exit; | ||
1506 | } | ||
1507 | |||
1508 | p2p->af_sent_channel = le32_to_cpu(af_params->channel); | ||
1509 | p2p->af_tx_sent_jiffies = jiffies; | ||
1510 | |||
1511 | timeout = wait_for_completion_timeout(&p2p->send_af_done, | ||
1512 | msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME)); | ||
1513 | |||
1514 | if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) { | ||
1515 | brcmf_dbg(TRACE, "TX action frame operation is success\n"); | ||
1516 | } else { | ||
1517 | err = -EIO; | ||
1518 | brcmf_dbg(TRACE, "TX action frame operation has failed\n"); | ||
1519 | } | ||
1520 | /* clear status bit for action tx */ | ||
1521 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); | ||
1522 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); | ||
1523 | |||
1524 | exit: | ||
1525 | return err; | ||
1526 | } | ||
1527 | |||
1528 | |||
1529 | /** | ||
1530 | * brcmf_p2p_pub_af_tx() - public action frame tx routine. | ||
1531 | * | ||
1532 | * @cfg: driver private data for cfg80211 interface. | ||
1533 | * @af_params: action frame data/info. | ||
1534 | * @config_af_params: configuration data for action frame. | ||
1535 | * | ||
1536 | * routine which transmits ation frame public type. | ||
1537 | */ | ||
1538 | static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg, | ||
1539 | struct brcmf_fil_af_params_le *af_params, | ||
1540 | struct brcmf_config_af_params *config_af_params) | ||
1541 | { | ||
1542 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1543 | struct brcmf_fil_action_frame_le *action_frame; | ||
1544 | struct brcmf_p2p_pub_act_frame *act_frm; | ||
1545 | s32 err = 0; | ||
1546 | u16 ie_len; | ||
1547 | |||
1548 | action_frame = &af_params->action_frame; | ||
1549 | act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data); | ||
1550 | |||
1551 | config_af_params->extra_listen = true; | ||
1552 | |||
1553 | switch (act_frm->subtype) { | ||
1554 | case P2P_PAF_GON_REQ: | ||
1555 | brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n"); | ||
1556 | set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1557 | config_af_params->mpc_onoff = 0; | ||
1558 | config_af_params->search_channel = true; | ||
1559 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1560 | p2p->gon_req_action = true; | ||
1561 | /* increase dwell time to wait for RESP frame */ | ||
1562 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1563 | break; | ||
1564 | case P2P_PAF_GON_RSP: | ||
1565 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1566 | /* increase dwell time to wait for CONF frame */ | ||
1567 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1568 | break; | ||
1569 | case P2P_PAF_GON_CONF: | ||
1570 | /* If we reached till GO Neg confirmation reset the filter */ | ||
1571 | brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n"); | ||
1572 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1573 | /* turn on mpc again if go nego is done */ | ||
1574 | config_af_params->mpc_onoff = 1; | ||
1575 | /* minimize dwell time */ | ||
1576 | af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1577 | config_af_params->extra_listen = false; | ||
1578 | break; | ||
1579 | case P2P_PAF_INVITE_REQ: | ||
1580 | config_af_params->search_channel = true; | ||
1581 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1582 | /* increase dwell time */ | ||
1583 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1584 | break; | ||
1585 | case P2P_PAF_INVITE_RSP: | ||
1586 | /* minimize dwell time */ | ||
1587 | af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1588 | config_af_params->extra_listen = false; | ||
1589 | break; | ||
1590 | case P2P_PAF_DEVDIS_REQ: | ||
1591 | config_af_params->search_channel = true; | ||
1592 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1593 | /* maximize dwell time to wait for RESP frame */ | ||
1594 | af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME); | ||
1595 | break; | ||
1596 | case P2P_PAF_DEVDIS_RSP: | ||
1597 | /* minimize dwell time */ | ||
1598 | af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1599 | config_af_params->extra_listen = false; | ||
1600 | break; | ||
1601 | case P2P_PAF_PROVDIS_REQ: | ||
1602 | ie_len = le16_to_cpu(action_frame->len) - | ||
1603 | offsetof(struct brcmf_p2p_pub_act_frame, elts); | ||
1604 | if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len, | ||
1605 | IEEE80211_P2P_ATTR_GROUP_ID, | ||
1606 | NULL, 0) < 0) | ||
1607 | config_af_params->search_channel = true; | ||
1608 | config_af_params->mpc_onoff = 0; | ||
1609 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1610 | /* increase dwell time to wait for RESP frame */ | ||
1611 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1612 | break; | ||
1613 | case P2P_PAF_PROVDIS_RSP: | ||
1614 | /* wpa_supplicant send go nego req right after prov disc */ | ||
1615 | p2p->next_af_subtype = P2P_PAF_GON_REQ; | ||
1616 | /* increase dwell time to MED level */ | ||
1617 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1618 | config_af_params->extra_listen = false; | ||
1619 | break; | ||
1620 | default: | ||
1621 | brcmf_err("Unknown p2p pub act frame subtype: %d\n", | ||
1622 | act_frm->subtype); | ||
1623 | err = -EINVAL; | ||
1624 | } | ||
1625 | return err; | ||
1626 | } | ||
1627 | |||
1628 | /** | ||
1629 | * brcmf_p2p_send_action_frame() - send action frame . | ||
1630 | * | ||
1631 | * @cfg: driver private data for cfg80211 interface. | ||
1632 | * @ndev: net device to transmit on. | ||
1633 | * @af_params: configuration data for action frame. | ||
1634 | */ | ||
1635 | bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, | ||
1636 | struct net_device *ndev, | ||
1637 | struct brcmf_fil_af_params_le *af_params) | ||
1638 | { | ||
1639 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1640 | struct brcmf_fil_action_frame_le *action_frame; | ||
1641 | struct brcmf_config_af_params config_af_params; | ||
1642 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1643 | u16 action_frame_len; | ||
1644 | bool ack = false; | ||
1645 | u8 category; | ||
1646 | u8 action; | ||
1647 | s32 tx_retry; | ||
1648 | s32 extra_listen_time; | ||
1649 | uint delta_ms; | ||
1650 | |||
1651 | action_frame = &af_params->action_frame; | ||
1652 | action_frame_len = le16_to_cpu(action_frame->len); | ||
1653 | |||
1654 | brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len); | ||
1655 | |||
1656 | /* Add the default dwell time. Dwell time to stay off-channel */ | ||
1657 | /* to wait for a response action frame after transmitting an */ | ||
1658 | /* GO Negotiation action frame */ | ||
1659 | af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME); | ||
1660 | |||
1661 | category = action_frame->data[DOT11_ACTION_CAT_OFF]; | ||
1662 | action = action_frame->data[DOT11_ACTION_ACT_OFF]; | ||
1663 | |||
1664 | /* initialize variables */ | ||
1665 | p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; | ||
1666 | p2p->gon_req_action = false; | ||
1667 | |||
1668 | /* config parameters */ | ||
1669 | config_af_params.mpc_onoff = -1; | ||
1670 | config_af_params.search_channel = false; | ||
1671 | config_af_params.extra_listen = false; | ||
1672 | |||
1673 | if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) { | ||
1674 | /* p2p public action frame process */ | ||
1675 | if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) { | ||
1676 | /* Just send unknown subtype frame with */ | ||
1677 | /* default parameters. */ | ||
1678 | brcmf_err("P2P Public action frame, unknown subtype.\n"); | ||
1679 | } | ||
1680 | } else if (brcmf_p2p_is_gas_action(action_frame->data, | ||
1681 | action_frame_len)) { | ||
1682 | /* service discovery process */ | ||
1683 | if (action == P2PSD_ACTION_ID_GAS_IREQ || | ||
1684 | action == P2PSD_ACTION_ID_GAS_CREQ) { | ||
1685 | /* configure service discovery query frame */ | ||
1686 | config_af_params.search_channel = true; | ||
1687 | |||
1688 | /* save next af suptype to cancel */ | ||
1689 | /* remaining dwell time */ | ||
1690 | p2p->next_af_subtype = action + 1; | ||
1691 | |||
1692 | af_params->dwell_time = | ||
1693 | cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1694 | } else if (action == P2PSD_ACTION_ID_GAS_IRESP || | ||
1695 | action == P2PSD_ACTION_ID_GAS_CRESP) { | ||
1696 | /* configure service discovery response frame */ | ||
1697 | af_params->dwell_time = | ||
1698 | cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1699 | } else { | ||
1700 | brcmf_err("Unknown action type: %d\n", action); | ||
1701 | goto exit; | ||
1702 | } | ||
1703 | } else if (brcmf_p2p_is_p2p_action(action_frame->data, | ||
1704 | action_frame_len)) { | ||
1705 | /* do not configure anything. it will be */ | ||
1706 | /* sent with a default configuration */ | ||
1707 | } else { | ||
1708 | brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n", | ||
1709 | category, action); | ||
1710 | return false; | ||
1711 | } | ||
1712 | |||
1713 | /* if connecting on primary iface, sleep for a while before sending | ||
1714 | * af tx for VSDB | ||
1715 | */ | ||
1716 | if (test_bit(BRCMF_VIF_STATUS_CONNECTING, | ||
1717 | &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state)) | ||
1718 | msleep(50); | ||
1719 | |||
1720 | /* if scan is ongoing, abort current scan. */ | ||
1721 | if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) | ||
1722 | brcmf_abort_scanning(cfg); | ||
1723 | |||
1724 | memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN); | ||
1725 | |||
1726 | /* To make sure to send successfully action frame, turn off mpc */ | ||
1727 | if (config_af_params.mpc_onoff == 0) | ||
1728 | brcmf_set_mpc(ndev, 0); | ||
1729 | |||
1730 | /* set status and destination address before sending af */ | ||
1731 | if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { | ||
1732 | /* set status to cancel the remained dwell time in rx process */ | ||
1733 | set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); | ||
1734 | } | ||
1735 | |||
1736 | p2p->af_sent_channel = 0; | ||
1737 | set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status); | ||
1738 | /* validate channel and p2p ies */ | ||
1739 | if (config_af_params.search_channel && | ||
1740 | IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) && | ||
1741 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) { | ||
1742 | afx_hdl = &p2p->afx_hdl; | ||
1743 | afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel); | ||
1744 | |||
1745 | if (brcmf_p2p_af_searching_channel(p2p) == | ||
1746 | P2P_INVALID_CHANNEL) { | ||
1747 | brcmf_err("Couldn't find peer's channel.\n"); | ||
1748 | goto exit; | ||
1749 | } | ||
1750 | |||
1751 | /* Abort scan even for VSDB scenarios. Scan gets aborted in | ||
1752 | * firmware but after the check of piggyback algorithm. To take | ||
1753 | * care of current piggback algo, lets abort the scan here | ||
1754 | * itself. | ||
1755 | */ | ||
1756 | brcmf_notify_escan_complete(cfg, ndev, true, true); | ||
1757 | |||
1758 | /* update channel */ | ||
1759 | af_params->channel = cpu_to_le32(afx_hdl->peer_chan); | ||
1760 | } | ||
1761 | |||
1762 | tx_retry = 0; | ||
1763 | while (!p2p->block_gon_req_tx && | ||
1764 | (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) { | ||
1765 | ack = !brcmf_p2p_tx_action_frame(p2p, af_params); | ||
1766 | tx_retry++; | ||
1767 | } | ||
1768 | if (ack == false) { | ||
1769 | brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry); | ||
1770 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1771 | } | ||
1772 | |||
1773 | exit: | ||
1774 | clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status); | ||
1775 | |||
1776 | /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. | ||
1777 | * if we coundn't get the next action response frame and dongle does | ||
1778 | * not keep the dwell time, go to listen state again to get next action | ||
1779 | * response frame. | ||
1780 | */ | ||
1781 | if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx && | ||
1782 | test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) && | ||
1783 | p2p->af_sent_channel == afx_hdl->my_listen_chan) { | ||
1784 | delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies); | ||
1785 | if (le32_to_cpu(af_params->dwell_time) > delta_ms) | ||
1786 | extra_listen_time = le32_to_cpu(af_params->dwell_time) - | ||
1787 | delta_ms; | ||
1788 | else | ||
1789 | extra_listen_time = 0; | ||
1790 | if (extra_listen_time > 50) { | ||
1791 | set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1792 | &p2p->status); | ||
1793 | brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n", | ||
1794 | le32_to_cpu(af_params->dwell_time), | ||
1795 | extra_listen_time); | ||
1796 | extra_listen_time += 100; | ||
1797 | if (!brcmf_p2p_discover_listen(p2p, | ||
1798 | p2p->af_sent_channel, | ||
1799 | extra_listen_time)) { | ||
1800 | unsigned long duration; | ||
1801 | |||
1802 | extra_listen_time += 100; | ||
1803 | duration = msecs_to_jiffies(extra_listen_time); | ||
1804 | wait_for_completion_timeout(&p2p->wait_next_af, | ||
1805 | duration); | ||
1806 | } | ||
1807 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1808 | &p2p->status); | ||
1809 | } | ||
1810 | } | ||
1811 | |||
1812 | if (p2p->block_gon_req_tx) { | ||
1813 | /* if ack is true, supplicant will wait more time(100ms). | ||
1814 | * so we will return it as a success to get more time . | ||
1815 | */ | ||
1816 | p2p->block_gon_req_tx = false; | ||
1817 | ack = true; | ||
1818 | } | ||
1819 | |||
1820 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); | ||
1821 | /* if all done, turn mpc on again */ | ||
1822 | if (config_af_params.mpc_onoff == 1) | ||
1823 | brcmf_set_mpc(ndev, 1); | ||
1824 | |||
1825 | return ack; | ||
1826 | } | ||
1827 | |||
1828 | /** | ||
1829 | * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req. | ||
1830 | * | ||
1831 | * @ifp: interface pointer for which event was received. | ||
1832 | * @e: even message. | ||
1833 | * @data: payload of event message (probe request). | ||
1834 | */ | ||
1835 | s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, | ||
1836 | const struct brcmf_event_msg *e, | ||
1837 | void *data) | ||
1838 | { | ||
1839 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1840 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1841 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1842 | struct wireless_dev *wdev; | ||
1843 | struct brcmf_cfg80211_vif *vif = ifp->vif; | ||
1844 | struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; | ||
1845 | u16 chanspec = be16_to_cpu(rxframe->chanspec); | ||
1846 | u8 *mgmt_frame; | ||
1847 | u32 mgmt_frame_len; | ||
1848 | s32 freq; | ||
1849 | u16 mgmt_type; | ||
1850 | |||
1851 | brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, | ||
1852 | e->reason); | ||
1853 | |||
1854 | if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && | ||
1855 | (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) { | ||
1856 | afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec); | ||
1857 | brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n", | ||
1858 | afx_hdl->peer_chan); | ||
1859 | complete(&afx_hdl->act_frm_scan); | ||
1860 | } | ||
1861 | |||
1862 | /* Firmware sends us two proberesponses for each idx one. At the */ | ||
1863 | /* moment anything but bsscfgidx 0 is passed up to supplicant */ | ||
1864 | if (e->bsscfgidx == 0) | ||
1865 | return 0; | ||
1866 | |||
1867 | /* Filter any P2P probe reqs arriving during the GO-NEG Phase */ | ||
1868 | if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) { | ||
1869 | brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n"); | ||
1870 | return 0; | ||
1871 | } | ||
1872 | |||
1873 | /* Check if wpa_supplicant has registered for this frame */ | ||
1874 | brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg); | ||
1875 | mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4; | ||
1876 | if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) | ||
1877 | return 0; | ||
1878 | |||
1879 | mgmt_frame = (u8 *)(rxframe + 1); | ||
1880 | mgmt_frame_len = e->datalen - sizeof(*rxframe); | ||
1881 | freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), | ||
1882 | CHSPEC_IS2G(chanspec) ? | ||
1883 | IEEE80211_BAND_2GHZ : | ||
1884 | IEEE80211_BAND_5GHZ); | ||
1885 | wdev = ifp->ndev->ieee80211_ptr; | ||
1886 | cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); | ||
1887 | |||
1888 | brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", | ||
1889 | mgmt_frame_len, e->datalen, chanspec, freq); | ||
1890 | |||
1891 | return 0; | ||
1892 | } | ||
1893 | |||
1894 | |||
1895 | /** | ||
1896 | * brcmf_p2p_attach() - attach for P2P. | ||
1897 | * | ||
1898 | * @cfg: driver private data for cfg80211 interface. | ||
1899 | */ | ||
1900 | s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) | ||
1901 | { | ||
1902 | struct brcmf_if *pri_ifp; | ||
1903 | struct brcmf_if *p2p_ifp; | ||
1904 | struct brcmf_cfg80211_vif *p2p_vif; | ||
1905 | struct brcmf_p2p_info *p2p; | ||
1906 | struct brcmf_pub *drvr; | ||
1907 | s32 bssidx; | ||
1908 | s32 err = 0; | ||
1909 | |||
1910 | p2p = &cfg->p2p; | ||
1911 | p2p->cfg = cfg; | ||
1912 | |||
1913 | drvr = cfg->pub; | ||
1914 | |||
1915 | pri_ifp = drvr->iflist[0]; | ||
1916 | p2p_ifp = drvr->iflist[1]; | ||
1917 | |||
1918 | p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; | ||
1919 | |||
1920 | if (p2p_ifp) { | ||
1921 | p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE, | ||
1922 | false); | ||
1923 | if (IS_ERR(p2p_vif)) { | ||
1924 | brcmf_err("could not create discovery vif\n"); | ||
1925 | err = -ENOMEM; | ||
1926 | goto exit; | ||
1927 | } | ||
1928 | |||
1929 | p2p_vif->ifp = p2p_ifp; | ||
1930 | p2p_ifp->vif = p2p_vif; | ||
1931 | p2p_vif->wdev.netdev = p2p_ifp->ndev; | ||
1932 | p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev; | ||
1933 | SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy)); | ||
1934 | |||
1935 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; | ||
1936 | |||
1937 | brcmf_p2p_generate_bss_mac(p2p); | ||
1938 | brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); | ||
1939 | |||
1940 | /* Initialize P2P Discovery in the firmware */ | ||
1941 | err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); | ||
1942 | if (err < 0) { | ||
1943 | brcmf_err("set p2p_disc error\n"); | ||
1944 | brcmf_free_vif(p2p_vif); | ||
1945 | goto exit; | ||
1946 | } | ||
1947 | /* obtain bsscfg index for P2P discovery */ | ||
1948 | err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); | ||
1949 | if (err < 0) { | ||
1950 | brcmf_err("retrieving discover bsscfg index failed\n"); | ||
1951 | brcmf_free_vif(p2p_vif); | ||
1952 | goto exit; | ||
1953 | } | ||
1954 | /* Verify that firmware uses same bssidx as driver !! */ | ||
1955 | if (p2p_ifp->bssidx != bssidx) { | ||
1956 | brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", | ||
1957 | bssidx, p2p_ifp->bssidx); | ||
1958 | brcmf_free_vif(p2p_vif); | ||
1959 | goto exit; | ||
1960 | } | ||
1961 | |||
1962 | init_completion(&p2p->send_af_done); | ||
1963 | INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); | ||
1964 | init_completion(&p2p->afx_hdl.act_frm_scan); | ||
1965 | init_completion(&p2p->wait_next_af); | ||
1966 | } | ||
1967 | exit: | ||
1968 | return err; | ||
1969 | } | ||
1970 | |||
1971 | |||
1972 | /** | ||
1973 | * brcmf_p2p_detach() - detach P2P. | ||
1974 | * | ||
1975 | * @p2p: P2P specific data. | ||
1976 | */ | ||
1977 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) | ||
1978 | { | ||
1979 | struct brcmf_cfg80211_vif *vif; | ||
1980 | |||
1981 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
1982 | if (vif != NULL) { | ||
1983 | brcmf_p2p_cancel_remain_on_channel(vif->ifp); | ||
1984 | brcmf_p2p_deinit_discovery(p2p); | ||
1985 | /* remove discovery interface */ | ||
1986 | brcmf_free_vif(vif); | ||
1987 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; | ||
1988 | } | ||
1989 | /* just set it all to zero */ | ||
1990 | memset(p2p, 0, sizeof(*p2p)); | ||
1991 | } | ||
1992 | |||
1993 | /** | ||
1994 | * brcmf_p2p_get_current_chanspec() - Get current operation channel. | ||
1995 | * | ||
1996 | * @p2p: P2P specific data. | ||
1997 | * @chanspec: chanspec to be returned. | ||
1998 | */ | ||
1999 | static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p, | ||
2000 | u16 *chanspec) | ||
2001 | { | ||
2002 | struct brcmf_if *ifp; | ||
2003 | struct brcmf_fil_chan_info_le ci; | ||
2004 | s32 err; | ||
2005 | |||
2006 | ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
2007 | |||
2008 | *chanspec = 11 & WL_CHANSPEC_CHAN_MASK; | ||
2009 | |||
2010 | err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci)); | ||
2011 | if (!err) { | ||
2012 | *chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK; | ||
2013 | if (*chanspec < CH_MAX_2G_CHANNEL) | ||
2014 | *chanspec |= WL_CHANSPEC_BAND_2G; | ||
2015 | else | ||
2016 | *chanspec |= WL_CHANSPEC_BAND_5G; | ||
2017 | } | ||
2018 | *chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; | ||
2019 | } | ||
2020 | |||
2021 | /** | ||
2022 | * Change a P2P Role. | ||
2023 | * Parameters: | ||
2024 | * @mac: MAC address of the BSS to change a role | ||
2025 | * Returns 0 if success. | ||
2026 | */ | ||
2027 | int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, | ||
2028 | enum brcmf_fil_p2p_if_types if_type) | ||
2029 | { | ||
2030 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
2031 | struct brcmf_cfg80211_vif *vif; | ||
2032 | struct brcmf_fil_p2p_if_le if_request; | ||
2033 | s32 err; | ||
2034 | u16 chanspec; | ||
2035 | |||
2036 | brcmf_dbg(TRACE, "Enter\n"); | ||
2037 | |||
2038 | vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
2039 | if (!vif) { | ||
2040 | brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n"); | ||
2041 | return -EPERM; | ||
2042 | } | ||
2043 | brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true); | ||
2044 | vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; | ||
2045 | if (!vif) { | ||
2046 | brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n"); | ||
2047 | return -EPERM; | ||
2048 | } | ||
2049 | brcmf_set_mpc(vif->ifp->ndev, 0); | ||
2050 | |||
2051 | /* In concurrency case, STA may be already associated in a particular */ | ||
2052 | /* channel. so retrieve the current channel of primary interface and */ | ||
2053 | /* then start the virtual interface on that. */ | ||
2054 | brcmf_p2p_get_current_chanspec(p2p, &chanspec); | ||
2055 | |||
2056 | if_request.type = cpu_to_le16((u16)if_type); | ||
2057 | if_request.chspec = cpu_to_le16(chanspec); | ||
2058 | memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr)); | ||
2059 | |||
2060 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
2061 | err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request, | ||
2062 | sizeof(if_request)); | ||
2063 | if (err) { | ||
2064 | brcmf_err("p2p_ifupd FAILED, err=%d\n", err); | ||
2065 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2066 | return err; | ||
2067 | } | ||
2068 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE, | ||
2069 | msecs_to_jiffies(1500)); | ||
2070 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2071 | if (!err) { | ||
2072 | brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); | ||
2073 | return -EIO; | ||
2074 | } | ||
2075 | |||
2076 | err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT, | ||
2077 | BRCMF_SCB_TIMEOUT_VALUE); | ||
2078 | |||
2079 | return err; | ||
2080 | } | ||
2081 | |||
2082 | static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p, | ||
2083 | struct brcmf_if *ifp, u8 ea[ETH_ALEN], | ||
2084 | enum brcmf_fil_p2p_if_types iftype) | ||
2085 | { | ||
2086 | struct brcmf_fil_p2p_if_le if_request; | ||
2087 | int err; | ||
2088 | u16 chanspec; | ||
2089 | |||
2090 | /* we need a default channel */ | ||
2091 | brcmf_p2p_get_current_chanspec(p2p, &chanspec); | ||
2092 | |||
2093 | /* fill the firmware request */ | ||
2094 | memcpy(if_request.addr, ea, ETH_ALEN); | ||
2095 | if_request.type = cpu_to_le16((u16)iftype); | ||
2096 | if_request.chspec = cpu_to_le16(chanspec); | ||
2097 | |||
2098 | err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request, | ||
2099 | sizeof(if_request)); | ||
2100 | if (err) | ||
2101 | return err; | ||
2102 | |||
2103 | return err; | ||
2104 | } | ||
2105 | |||
2106 | static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif) | ||
2107 | { | ||
2108 | struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); | ||
2109 | struct net_device *pri_ndev = cfg_to_ndev(cfg); | ||
2110 | struct brcmf_if *ifp = netdev_priv(pri_ndev); | ||
2111 | u8 *addr = vif->wdev.netdev->dev_addr; | ||
2112 | |||
2113 | return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN); | ||
2114 | } | ||
2115 | |||
2116 | static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif) | ||
2117 | { | ||
2118 | struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); | ||
2119 | struct net_device *pri_ndev = cfg_to_ndev(cfg); | ||
2120 | struct brcmf_if *ifp = netdev_priv(pri_ndev); | ||
2121 | u8 *addr = vif->wdev.netdev->dev_addr; | ||
2122 | |||
2123 | return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN); | ||
2124 | } | ||
2125 | |||
2126 | /** | ||
2127 | * brcmf_p2p_add_vif() - create a new P2P virtual interface. | ||
2128 | * | ||
2129 | * @wiphy: wiphy device of new interface. | ||
2130 | * @name: name of the new interface. | ||
2131 | * @type: nl80211 interface type. | ||
2132 | * @flags: TBD | ||
2133 | * @params: TBD | ||
2134 | */ | ||
2135 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | ||
2136 | enum nl80211_iftype type, u32 *flags, | ||
2137 | struct vif_params *params) | ||
2138 | { | ||
2139 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
2140 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | ||
2141 | struct brcmf_cfg80211_vif *vif; | ||
2142 | enum brcmf_fil_p2p_if_types iftype; | ||
2143 | enum wl_mode mode; | ||
2144 | int err; | ||
2145 | |||
2146 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
2147 | return ERR_PTR(-EBUSY); | ||
2148 | |||
2149 | brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type); | ||
2150 | |||
2151 | switch (type) { | ||
2152 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2153 | iftype = BRCMF_FIL_P2P_IF_CLIENT; | ||
2154 | mode = WL_MODE_BSS; | ||
2155 | break; | ||
2156 | case NL80211_IFTYPE_P2P_GO: | ||
2157 | iftype = BRCMF_FIL_P2P_IF_GO; | ||
2158 | mode = WL_MODE_AP; | ||
2159 | break; | ||
2160 | default: | ||
2161 | return ERR_PTR(-EOPNOTSUPP); | ||
2162 | } | ||
2163 | |||
2164 | vif = brcmf_alloc_vif(cfg, type, false); | ||
2165 | if (IS_ERR(vif)) | ||
2166 | return (struct wireless_dev *)vif; | ||
2167 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
2168 | |||
2169 | err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr, | ||
2170 | iftype); | ||
2171 | if (err) { | ||
2172 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2173 | goto fail; | ||
2174 | } | ||
2175 | |||
2176 | /* wait for firmware event */ | ||
2177 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, | ||
2178 | msecs_to_jiffies(1500)); | ||
2179 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2180 | if (!err) { | ||
2181 | brcmf_err("timeout occurred\n"); | ||
2182 | err = -EIO; | ||
2183 | goto fail; | ||
2184 | } | ||
2185 | |||
2186 | /* interface created in firmware */ | ||
2187 | ifp = vif->ifp; | ||
2188 | if (!ifp) { | ||
2189 | brcmf_err("no if pointer provided\n"); | ||
2190 | err = -ENOENT; | ||
2191 | goto fail; | ||
2192 | } | ||
2193 | |||
2194 | strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); | ||
2195 | err = brcmf_net_attach(ifp, true); | ||
2196 | if (err) { | ||
2197 | brcmf_err("Registering netdevice failed\n"); | ||
2198 | goto fail; | ||
2199 | } | ||
2200 | cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; | ||
2201 | /* Disable firmware roaming for P2P interface */ | ||
2202 | brcmf_fil_iovar_int_set(ifp, "roam_off", 1); | ||
2203 | if (iftype == BRCMF_FIL_P2P_IF_GO) { | ||
2204 | /* set station timeout for p2p */ | ||
2205 | brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT, | ||
2206 | BRCMF_SCB_TIMEOUT_VALUE); | ||
2207 | } | ||
2208 | return &ifp->vif->wdev; | ||
2209 | |||
2210 | fail: | ||
2211 | brcmf_free_vif(vif); | ||
2212 | return ERR_PTR(err); | ||
2213 | } | ||
2214 | |||
2215 | /** | ||
2216 | * brcmf_p2p_del_vif() - delete a P2P virtual interface. | ||
2217 | * | ||
2218 | * @wiphy: wiphy device of interface. | ||
2219 | * @wdev: wireless device of interface. | ||
2220 | * | ||
2221 | * TODO: not yet supported. | ||
2222 | */ | ||
2223 | int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
2224 | { | ||
2225 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | ||
2226 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
2227 | struct brcmf_cfg80211_vif *vif; | ||
2228 | unsigned long jiffie_timeout = msecs_to_jiffies(1500); | ||
2229 | bool wait_for_disable = false; | ||
2230 | int err; | ||
2231 | |||
2232 | brcmf_dbg(TRACE, "delete P2P vif\n"); | ||
2233 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); | ||
2234 | |||
2235 | switch (vif->wdev.iftype) { | ||
2236 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2237 | if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state)) | ||
2238 | wait_for_disable = true; | ||
2239 | break; | ||
2240 | |||
2241 | case NL80211_IFTYPE_P2P_GO: | ||
2242 | if (!brcmf_p2p_disable_p2p_if(vif)) | ||
2243 | wait_for_disable = true; | ||
2244 | break; | ||
2245 | |||
2246 | case NL80211_IFTYPE_P2P_DEVICE: | ||
2247 | default: | ||
2248 | return -ENOTSUPP; | ||
2249 | break; | ||
2250 | } | ||
2251 | |||
2252 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
2253 | brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); | ||
2254 | |||
2255 | if (wait_for_disable) | ||
2256 | wait_for_completion_timeout(&cfg->vif_disabled, | ||
2257 | msecs_to_jiffies(500)); | ||
2258 | |||
2259 | brcmf_vif_clear_mgmt_ies(vif); | ||
2260 | |||
2261 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
2262 | err = brcmf_p2p_release_p2p_if(vif); | ||
2263 | if (!err) { | ||
2264 | /* wait for firmware event */ | ||
2265 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, | ||
2266 | jiffie_timeout); | ||
2267 | if (!err) | ||
2268 | err = -EIO; | ||
2269 | else | ||
2270 | err = 0; | ||
2271 | } | ||
2272 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2273 | brcmf_free_vif(vif); | ||
2274 | p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; | ||
2275 | |||
2276 | return err; | ||
2277 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h new file mode 100644 index 000000000000..6821b26224be --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #ifndef WL_CFGP2P_H_ | ||
17 | #define WL_CFGP2P_H_ | ||
18 | |||
19 | #include <net/cfg80211.h> | ||
20 | |||
21 | struct brcmf_cfg80211_info; | ||
22 | |||
23 | /** | ||
24 | * enum p2p_bss_type - different type of BSS configurations. | ||
25 | * | ||
26 | * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg. | ||
27 | * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg. | ||
28 | * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg. | ||
29 | * @P2PAPI_BSSCFG_MAX: used for range checking. | ||
30 | */ | ||
31 | enum p2p_bss_type { | ||
32 | P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ | ||
33 | P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ | ||
34 | P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ | ||
35 | P2PAPI_BSSCFG_MAX | ||
36 | }; | ||
37 | |||
38 | /** | ||
39 | * struct p2p_bss - peer-to-peer bss related information. | ||
40 | * | ||
41 | * @vif: virtual interface of this P2P bss. | ||
42 | * @private_data: TBD | ||
43 | */ | ||
44 | struct p2p_bss { | ||
45 | struct brcmf_cfg80211_vif *vif; | ||
46 | void *private_data; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * enum brcmf_p2p_status - P2P specific dongle status. | ||
51 | * | ||
52 | * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle. | ||
53 | * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED? | ||
54 | * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle. | ||
55 | * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle. | ||
56 | * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle. | ||
57 | * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed. | ||
58 | * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked. | ||
59 | * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing. | ||
60 | * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel. | ||
61 | * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame. | ||
62 | * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx. | ||
63 | * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response. | ||
64 | * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active. | ||
65 | */ | ||
66 | enum brcmf_p2p_status { | ||
67 | BRCMF_P2P_STATUS_ENABLED, | ||
68 | BRCMF_P2P_STATUS_IF_ADD, | ||
69 | BRCMF_P2P_STATUS_IF_DEL, | ||
70 | BRCMF_P2P_STATUS_IF_DELETING, | ||
71 | BRCMF_P2P_STATUS_IF_CHANGING, | ||
72 | BRCMF_P2P_STATUS_IF_CHANGED, | ||
73 | BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, | ||
74 | BRCMF_P2P_STATUS_ACTION_TX_NOACK, | ||
75 | BRCMF_P2P_STATUS_GO_NEG_PHASE, | ||
76 | BRCMF_P2P_STATUS_DISCOVER_LISTEN, | ||
77 | BRCMF_P2P_STATUS_SENDING_ACT_FRAME, | ||
78 | BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
79 | BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
80 | BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * struct afx_hdl - action frame off channel storage. | ||
85 | * | ||
86 | * @afx_work: worker thread for searching channel | ||
87 | * @act_frm_scan: thread synchronizing struct. | ||
88 | * @is_active: channel searching active. | ||
89 | * @peer_chan: current channel. | ||
90 | * @is_listen: sets mode for afx worker. | ||
91 | * @my_listen_chan: this peers listen channel. | ||
92 | * @peer_listen_chan: remote peers listen channel. | ||
93 | * @tx_dst_addr: mac address where tx af should be sent to. | ||
94 | */ | ||
95 | struct afx_hdl { | ||
96 | struct work_struct afx_work; | ||
97 | struct completion act_frm_scan; | ||
98 | bool is_active; | ||
99 | s32 peer_chan; | ||
100 | bool is_listen; | ||
101 | u16 my_listen_chan; | ||
102 | u16 peer_listen_chan; | ||
103 | u8 tx_dst_addr[ETH_ALEN]; | ||
104 | }; | ||
105 | |||
106 | /** | ||
107 | * struct brcmf_p2p_info - p2p specific driver information. | ||
108 | * | ||
109 | * @cfg: driver private data for cfg80211 interface. | ||
110 | * @status: status of P2P (see enum brcmf_p2p_status). | ||
111 | * @dev_addr: P2P device address. | ||
112 | * @int_addr: P2P interface address. | ||
113 | * @bss_idx: informate for P2P bss types. | ||
114 | * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state. | ||
115 | * @ssid: ssid for P2P GO. | ||
116 | * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state. | ||
117 | * @remain_on_channel: contains copy of struct used by cfg80211. | ||
118 | * @remain_on_channel_cookie: cookie counter for remain on channel cmd | ||
119 | * @next_af_subtype: expected action frame subtype. | ||
120 | * @send_af_done: indication that action frame tx is complete. | ||
121 | * @afx_hdl: action frame search handler info. | ||
122 | * @af_sent_channel: channel action frame is sent. | ||
123 | * @af_tx_sent_jiffies: jiffies time when af tx was transmitted. | ||
124 | * @wait_next_af: thread synchronizing struct. | ||
125 | * @gon_req_action: about to send go negotiation requets frame. | ||
126 | * @block_gon_req_tx: drop tx go negotiation requets frame. | ||
127 | */ | ||
128 | struct brcmf_p2p_info { | ||
129 | struct brcmf_cfg80211_info *cfg; | ||
130 | unsigned long status; | ||
131 | u8 dev_addr[ETH_ALEN]; | ||
132 | u8 int_addr[ETH_ALEN]; | ||
133 | struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; | ||
134 | struct timer_list listen_timer; | ||
135 | struct brcmf_ssid ssid; | ||
136 | u8 listen_channel; | ||
137 | struct ieee80211_channel remain_on_channel; | ||
138 | u32 remain_on_channel_cookie; | ||
139 | u8 next_af_subtype; | ||
140 | struct completion send_af_done; | ||
141 | struct afx_hdl afx_hdl; | ||
142 | u32 af_sent_channel; | ||
143 | unsigned long af_tx_sent_jiffies; | ||
144 | struct completion wait_next_af; | ||
145 | bool gon_req_action; | ||
146 | bool block_gon_req_tx; | ||
147 | }; | ||
148 | |||
149 | s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); | ||
150 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p); | ||
151 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | ||
152 | enum nl80211_iftype type, u32 *flags, | ||
153 | struct vif_params *params); | ||
154 | int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
155 | int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, | ||
156 | enum brcmf_fil_p2p_if_types if_type); | ||
157 | int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
158 | void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
159 | int brcmf_p2p_scan_prep(struct wiphy *wiphy, | ||
160 | struct cfg80211_scan_request *request, | ||
161 | struct brcmf_cfg80211_vif *vif); | ||
162 | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
163 | struct ieee80211_channel *channel, | ||
164 | unsigned int duration, u64 *cookie); | ||
165 | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||
166 | const struct brcmf_event_msg *e, | ||
167 | void *data); | ||
168 | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp); | ||
169 | int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, | ||
170 | const struct brcmf_event_msg *e, | ||
171 | void *data); | ||
172 | int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, | ||
173 | const struct brcmf_event_msg *e, | ||
174 | void *data); | ||
175 | bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, | ||
176 | struct net_device *ndev, | ||
177 | struct brcmf_fil_af_params_le *af_params); | ||
178 | bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, | ||
179 | struct brcmf_bss_info_le *bi); | ||
180 | s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, | ||
181 | const struct brcmf_event_msg *e, | ||
182 | void *data); | ||
183 | #endif /* WL_CFGP2P_H_ */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index bc5a042c9a96..42289e9ea886 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c | |||
@@ -420,10 +420,6 @@ static void brcmf_usb_tx_complete(struct urb *urb) | |||
420 | brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, | 420 | brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, |
421 | req->skb); | 421 | req->skb); |
422 | brcmf_usb_del_fromq(devinfo, req); | 422 | brcmf_usb_del_fromq(devinfo, req); |
423 | if (urb->status == 0) | ||
424 | devinfo->bus_pub.bus->dstats.tx_packets++; | ||
425 | else | ||
426 | devinfo->bus_pub.bus->dstats.tx_errors++; | ||
427 | 423 | ||
428 | brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); | 424 | brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); |
429 | 425 | ||
@@ -450,10 +446,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
450 | req->skb = NULL; | 446 | req->skb = NULL; |
451 | 447 | ||
452 | /* zero lenght packets indicate usb "failure". Do not refill */ | 448 | /* zero lenght packets indicate usb "failure". Do not refill */ |
453 | if (urb->status == 0 && urb->actual_length) { | 449 | if (urb->status != 0 || !urb->actual_length) { |
454 | devinfo->bus_pub.bus->dstats.rx_packets++; | ||
455 | } else { | ||
456 | devinfo->bus_pub.bus->dstats.rx_errors++; | ||
457 | brcmu_pkt_buf_free_skb(skb); | 450 | brcmu_pkt_buf_free_skb(skb); |
458 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); | 451 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
459 | return; | 452 | return; |
@@ -1256,6 +1249,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) | |||
1256 | bus->bus_priv.usb = bus_pub; | 1249 | bus->bus_priv.usb = bus_pub; |
1257 | dev_set_drvdata(dev, bus); | 1250 | dev_set_drvdata(dev, bus); |
1258 | bus->ops = &brcmf_usb_bus_ops; | 1251 | bus->ops = &brcmf_usb_bus_ops; |
1252 | bus->chip = bus_pub->devid; | ||
1253 | bus->chiprev = bus_pub->chiprev; | ||
1259 | 1254 | ||
1260 | /* Attach to the common driver interface */ | 1255 | /* Attach to the common driver interface */ |
1261 | ret = brcmf_attach(0, dev); | 1256 | ret = brcmf_attach(0, dev); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 62a528e8b958..cecc3eff72e9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <brcmu_wifi.h> | 26 | #include <brcmu_wifi.h> |
27 | #include "dhd.h" | 27 | #include "dhd.h" |
28 | #include "dhd_dbg.h" | 28 | #include "dhd_dbg.h" |
29 | #include "fwil_types.h" | ||
30 | #include "p2p.h" | ||
29 | #include "wl_cfg80211.h" | 31 | #include "wl_cfg80211.h" |
30 | #include "fwil.h" | 32 | #include "fwil.h" |
31 | 33 | ||
@@ -41,16 +43,13 @@ | |||
41 | #define BRCMF_PNO_SCAN_COMPLETE 1 | 43 | #define BRCMF_PNO_SCAN_COMPLETE 1 |
42 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 | 44 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 |
43 | 45 | ||
44 | #define BRCMF_IFACE_MAX_CNT 2 | 46 | #define BRCMF_IFACE_MAX_CNT 3 |
45 | 47 | ||
46 | #define TLV_LEN_OFF 1 /* length offset */ | ||
47 | #define TLV_HDR_LEN 2 /* header length */ | ||
48 | #define TLV_BODY_OFF 2 /* body offset */ | ||
49 | #define TLV_OUI_LEN 3 /* oui id length */ | ||
50 | #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ | 48 | #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ |
51 | #define WPA_OUI_TYPE 1 | 49 | #define WPA_OUI_TYPE 1 |
52 | #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ | 50 | #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ |
53 | #define WME_OUI_TYPE 2 | 51 | #define WME_OUI_TYPE 2 |
52 | #define WPS_OUI_TYPE 4 | ||
54 | 53 | ||
55 | #define VS_IE_FIXED_HDR_LEN 6 | 54 | #define VS_IE_FIXED_HDR_LEN 6 |
56 | #define WPA_IE_VERSION_LEN 2 | 55 | #define WPA_IE_VERSION_LEN 2 |
@@ -76,13 +75,15 @@ | |||
76 | #define VNDR_IE_PKTFLAG_OFFSET 8 | 75 | #define VNDR_IE_PKTFLAG_OFFSET 8 |
77 | #define VNDR_IE_VSIE_OFFSET 12 | 76 | #define VNDR_IE_VSIE_OFFSET 12 |
78 | #define VNDR_IE_HDR_SIZE 12 | 77 | #define VNDR_IE_HDR_SIZE 12 |
79 | #define VNDR_IE_BEACON_FLAG 0x1 | 78 | #define VNDR_IE_PARSE_LIMIT 5 |
80 | #define VNDR_IE_PRBRSP_FLAG 0x2 | ||
81 | #define MAX_VNDR_IE_NUMBER 5 | ||
82 | 79 | ||
83 | #define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ | 80 | #define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ |
84 | #define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ | 81 | #define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ |
85 | 82 | ||
83 | #define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 | ||
84 | #define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 | ||
85 | #define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20 | ||
86 | |||
86 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ | 87 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ |
87 | (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) | 88 | (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) |
88 | 89 | ||
@@ -271,13 +272,6 @@ static const u32 __wl_cipher_suites[] = { | |||
271 | WLAN_CIPHER_SUITE_AES_CMAC, | 272 | WLAN_CIPHER_SUITE_AES_CMAC, |
272 | }; | 273 | }; |
273 | 274 | ||
274 | /* tag_ID/length/value_buffer tuple */ | ||
275 | struct brcmf_tlv { | ||
276 | u8 id; | ||
277 | u8 len; | ||
278 | u8 data[1]; | ||
279 | }; | ||
280 | |||
281 | /* Vendor specific ie. id = 221, oui and type defines exact ie */ | 275 | /* Vendor specific ie. id = 221, oui and type defines exact ie */ |
282 | struct brcmf_vs_tlv { | 276 | struct brcmf_vs_tlv { |
283 | u8 id; | 277 | u8 id; |
@@ -294,7 +288,7 @@ struct parsed_vndr_ie_info { | |||
294 | 288 | ||
295 | struct parsed_vndr_ies { | 289 | struct parsed_vndr_ies { |
296 | u32 count; | 290 | u32 count; |
297 | struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; | 291 | struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; |
298 | }; | 292 | }; |
299 | 293 | ||
300 | /* Quarter dBm units to mW | 294 | /* Quarter dBm units to mW |
@@ -381,7 +375,7 @@ static u8 brcmf_mw_to_qdbm(u16 mw) | |||
381 | return qdbm; | 375 | return qdbm; |
382 | } | 376 | } |
383 | 377 | ||
384 | static u16 channel_to_chanspec(struct ieee80211_channel *ch) | 378 | u16 channel_to_chanspec(struct ieee80211_channel *ch) |
385 | { | 379 | { |
386 | u16 chanspec; | 380 | u16 chanspec; |
387 | 381 | ||
@@ -393,19 +387,92 @@ static u16 channel_to_chanspec(struct ieee80211_channel *ch) | |||
393 | else | 387 | else |
394 | chanspec |= WL_CHANSPEC_BAND_5G; | 388 | chanspec |= WL_CHANSPEC_BAND_5G; |
395 | 389 | ||
396 | if (ch->flags & IEEE80211_CHAN_NO_HT40) { | 390 | chanspec |= WL_CHANSPEC_BW_20; |
397 | chanspec |= WL_CHANSPEC_BW_20; | 391 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; |
398 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | 392 | |
399 | } else { | ||
400 | chanspec |= WL_CHANSPEC_BW_40; | ||
401 | if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
402 | chanspec |= WL_CHANSPEC_CTL_SB_LOWER; | ||
403 | else | ||
404 | chanspec |= WL_CHANSPEC_CTL_SB_UPPER; | ||
405 | } | ||
406 | return chanspec; | 393 | return chanspec; |
407 | } | 394 | } |
408 | 395 | ||
396 | /* Traverse a string of 1-byte tag/1-byte length/variable-length value | ||
397 | * triples, returning a pointer to the substring whose first element | ||
398 | * matches tag | ||
399 | */ | ||
400 | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) | ||
401 | { | ||
402 | struct brcmf_tlv *elt; | ||
403 | int totlen; | ||
404 | |||
405 | elt = (struct brcmf_tlv *)buf; | ||
406 | totlen = buflen; | ||
407 | |||
408 | /* find tagged parameter */ | ||
409 | while (totlen >= TLV_HDR_LEN) { | ||
410 | int len = elt->len; | ||
411 | |||
412 | /* validate remaining totlen */ | ||
413 | if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) | ||
414 | return elt; | ||
415 | |||
416 | elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN)); | ||
417 | totlen -= (len + TLV_HDR_LEN); | ||
418 | } | ||
419 | |||
420 | return NULL; | ||
421 | } | ||
422 | |||
423 | /* Is any of the tlvs the expected entry? If | ||
424 | * not update the tlvs buffer pointer/length. | ||
425 | */ | ||
426 | static bool | ||
427 | brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, | ||
428 | u8 *oui, u32 oui_len, u8 type) | ||
429 | { | ||
430 | /* If the contents match the OUI and the type */ | ||
431 | if (ie[TLV_LEN_OFF] >= oui_len + 1 && | ||
432 | !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && | ||
433 | type == ie[TLV_BODY_OFF + oui_len]) { | ||
434 | return true; | ||
435 | } | ||
436 | |||
437 | if (tlvs == NULL) | ||
438 | return false; | ||
439 | /* point to the next ie */ | ||
440 | ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; | ||
441 | /* calculate the length of the rest of the buffer */ | ||
442 | *tlvs_len -= (int)(ie - *tlvs); | ||
443 | /* update the pointer to the start of the buffer */ | ||
444 | *tlvs = ie; | ||
445 | |||
446 | return false; | ||
447 | } | ||
448 | |||
449 | static struct brcmf_vs_tlv * | ||
450 | brcmf_find_wpaie(u8 *parse, u32 len) | ||
451 | { | ||
452 | struct brcmf_tlv *ie; | ||
453 | |||
454 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | ||
455 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | ||
456 | WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) | ||
457 | return (struct brcmf_vs_tlv *)ie; | ||
458 | } | ||
459 | return NULL; | ||
460 | } | ||
461 | |||
462 | static struct brcmf_vs_tlv * | ||
463 | brcmf_find_wpsie(u8 *parse, u32 len) | ||
464 | { | ||
465 | struct brcmf_tlv *ie; | ||
466 | |||
467 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | ||
468 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | ||
469 | WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE)) | ||
470 | return (struct brcmf_vs_tlv *)ie; | ||
471 | } | ||
472 | return NULL; | ||
473 | } | ||
474 | |||
475 | |||
409 | static void convert_key_from_CPU(struct brcmf_wsec_key *key, | 476 | static void convert_key_from_CPU(struct brcmf_wsec_key *key, |
410 | struct brcmf_wsec_key_le *key_le) | 477 | struct brcmf_wsec_key_le *key_le) |
411 | { | 478 | { |
@@ -438,11 +505,153 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) | |||
438 | return err; | 505 | return err; |
439 | } | 506 | } |
440 | 507 | ||
508 | static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, | ||
509 | const char *name, | ||
510 | enum nl80211_iftype type, | ||
511 | u32 *flags, | ||
512 | struct vif_params *params) | ||
513 | { | ||
514 | brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); | ||
515 | switch (type) { | ||
516 | case NL80211_IFTYPE_ADHOC: | ||
517 | case NL80211_IFTYPE_STATION: | ||
518 | case NL80211_IFTYPE_AP: | ||
519 | case NL80211_IFTYPE_AP_VLAN: | ||
520 | case NL80211_IFTYPE_WDS: | ||
521 | case NL80211_IFTYPE_MONITOR: | ||
522 | case NL80211_IFTYPE_MESH_POINT: | ||
523 | return ERR_PTR(-EOPNOTSUPP); | ||
524 | case NL80211_IFTYPE_P2P_CLIENT: | ||
525 | case NL80211_IFTYPE_P2P_GO: | ||
526 | return brcmf_p2p_add_vif(wiphy, name, type, flags, params); | ||
527 | case NL80211_IFTYPE_UNSPECIFIED: | ||
528 | case NL80211_IFTYPE_P2P_DEVICE: | ||
529 | default: | ||
530 | return ERR_PTR(-EINVAL); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | void brcmf_set_mpc(struct net_device *ndev, int mpc) | ||
535 | { | ||
536 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
537 | s32 err = 0; | ||
538 | |||
539 | if (check_vif_up(ifp->vif)) { | ||
540 | err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); | ||
541 | if (err) { | ||
542 | brcmf_err("fail to set mpc\n"); | ||
543 | return; | ||
544 | } | ||
545 | brcmf_dbg(INFO, "MPC : %d\n", mpc); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | s32 | ||
550 | brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||
551 | struct net_device *ndev, | ||
552 | bool aborted, bool fw_abort) | ||
553 | { | ||
554 | struct brcmf_scan_params_le params_le; | ||
555 | struct cfg80211_scan_request *scan_request; | ||
556 | s32 err = 0; | ||
557 | |||
558 | brcmf_dbg(SCAN, "Enter\n"); | ||
559 | |||
560 | /* clear scan request, because the FW abort can cause a second call */ | ||
561 | /* to this functon and might cause a double cfg80211_scan_done */ | ||
562 | scan_request = cfg->scan_request; | ||
563 | cfg->scan_request = NULL; | ||
564 | |||
565 | if (timer_pending(&cfg->escan_timeout)) | ||
566 | del_timer_sync(&cfg->escan_timeout); | ||
567 | |||
568 | if (fw_abort) { | ||
569 | /* Do a scan abort to stop the driver's scan engine */ | ||
570 | brcmf_dbg(SCAN, "ABORT scan in firmware\n"); | ||
571 | memset(¶ms_le, 0, sizeof(params_le)); | ||
572 | memset(params_le.bssid, 0xFF, ETH_ALEN); | ||
573 | params_le.bss_type = DOT11_BSSTYPE_ANY; | ||
574 | params_le.scan_type = 0; | ||
575 | params_le.channel_num = cpu_to_le32(1); | ||
576 | params_le.nprobes = cpu_to_le32(1); | ||
577 | params_le.active_time = cpu_to_le32(-1); | ||
578 | params_le.passive_time = cpu_to_le32(-1); | ||
579 | params_le.home_time = cpu_to_le32(-1); | ||
580 | /* Scan is aborted by setting channel_list[0] to -1 */ | ||
581 | params_le.channel_list[0] = cpu_to_le16(-1); | ||
582 | /* E-Scan (or anyother type) can be aborted by SCAN */ | ||
583 | err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, | ||
584 | ¶ms_le, sizeof(params_le)); | ||
585 | if (err) | ||
586 | brcmf_err("Scan abort failed\n"); | ||
587 | } | ||
588 | /* | ||
589 | * e-scan can be initiated by scheduled scan | ||
590 | * which takes precedence. | ||
591 | */ | ||
592 | if (cfg->sched_escan) { | ||
593 | brcmf_dbg(SCAN, "scheduled scan completed\n"); | ||
594 | cfg->sched_escan = false; | ||
595 | if (!aborted) | ||
596 | cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); | ||
597 | brcmf_set_mpc(ndev, 1); | ||
598 | } else if (scan_request) { | ||
599 | brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", | ||
600 | aborted ? "Aborted" : "Done"); | ||
601 | cfg80211_scan_done(scan_request, aborted); | ||
602 | brcmf_set_mpc(ndev, 1); | ||
603 | } | ||
604 | if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) | ||
605 | brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); | ||
606 | |||
607 | return err; | ||
608 | } | ||
609 | |||
610 | static | ||
611 | int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
612 | { | ||
613 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | ||
614 | struct net_device *ndev = wdev->netdev; | ||
615 | |||
616 | /* vif event pending in firmware */ | ||
617 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
618 | return -EBUSY; | ||
619 | |||
620 | if (ndev) { | ||
621 | if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) && | ||
622 | cfg->escan_info.ndev == ndev) | ||
623 | brcmf_notify_escan_complete(cfg, ndev, true, | ||
624 | true); | ||
625 | |||
626 | brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1); | ||
627 | } | ||
628 | |||
629 | switch (wdev->iftype) { | ||
630 | case NL80211_IFTYPE_ADHOC: | ||
631 | case NL80211_IFTYPE_STATION: | ||
632 | case NL80211_IFTYPE_AP: | ||
633 | case NL80211_IFTYPE_AP_VLAN: | ||
634 | case NL80211_IFTYPE_WDS: | ||
635 | case NL80211_IFTYPE_MONITOR: | ||
636 | case NL80211_IFTYPE_MESH_POINT: | ||
637 | return -EOPNOTSUPP; | ||
638 | case NL80211_IFTYPE_P2P_CLIENT: | ||
639 | case NL80211_IFTYPE_P2P_GO: | ||
640 | return brcmf_p2p_del_vif(wiphy, wdev); | ||
641 | case NL80211_IFTYPE_UNSPECIFIED: | ||
642 | case NL80211_IFTYPE_P2P_DEVICE: | ||
643 | default: | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | return -EOPNOTSUPP; | ||
647 | } | ||
648 | |||
441 | static s32 | 649 | static s32 |
442 | brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | 650 | brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, |
443 | enum nl80211_iftype type, u32 *flags, | 651 | enum nl80211_iftype type, u32 *flags, |
444 | struct vif_params *params) | 652 | struct vif_params *params) |
445 | { | 653 | { |
654 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | ||
446 | struct brcmf_if *ifp = netdev_priv(ndev); | 655 | struct brcmf_if *ifp = netdev_priv(ndev); |
447 | struct brcmf_cfg80211_vif *vif = ifp->vif; | 656 | struct brcmf_cfg80211_vif *vif = ifp->vif; |
448 | s32 infra = 0; | 657 | s32 infra = 0; |
@@ -462,10 +671,23 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
462 | infra = 0; | 671 | infra = 0; |
463 | break; | 672 | break; |
464 | case NL80211_IFTYPE_STATION: | 673 | case NL80211_IFTYPE_STATION: |
674 | /* Ignore change for p2p IF. Unclear why supplicant does this */ | ||
675 | if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) || | ||
676 | (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) { | ||
677 | brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n"); | ||
678 | /* WAR: It is unexpected to get a change of VIF for P2P | ||
679 | * IF, but it happens. The request can not be handled | ||
680 | * but returning EPERM causes a crash. Returning 0 | ||
681 | * without setting ieee80211_ptr->iftype causes trace | ||
682 | * (WARN_ON) but it works with wpa_supplicant | ||
683 | */ | ||
684 | return 0; | ||
685 | } | ||
465 | vif->mode = WL_MODE_BSS; | 686 | vif->mode = WL_MODE_BSS; |
466 | infra = 1; | 687 | infra = 1; |
467 | break; | 688 | break; |
468 | case NL80211_IFTYPE_AP: | 689 | case NL80211_IFTYPE_AP: |
690 | case NL80211_IFTYPE_P2P_GO: | ||
469 | vif->mode = WL_MODE_AP; | 691 | vif->mode = WL_MODE_AP; |
470 | ap = 1; | 692 | ap = 1; |
471 | break; | 693 | break; |
@@ -475,8 +697,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
475 | } | 697 | } |
476 | 698 | ||
477 | if (ap) { | 699 | if (ap) { |
478 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); | 700 | if (type == NL80211_IFTYPE_P2P_GO) { |
479 | brcmf_dbg(INFO, "IF Type = AP\n"); | 701 | brcmf_dbg(INFO, "IF Type = P2P GO\n"); |
702 | err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO); | ||
703 | } | ||
704 | if (!err) { | ||
705 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); | ||
706 | brcmf_dbg(INFO, "IF Type = AP\n"); | ||
707 | } | ||
480 | } else { | 708 | } else { |
481 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); | 709 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); |
482 | if (err) { | 710 | if (err) { |
@@ -495,21 +723,6 @@ done: | |||
495 | return err; | 723 | return err; |
496 | } | 724 | } |
497 | 725 | ||
498 | static void brcmf_set_mpc(struct net_device *ndev, int mpc) | ||
499 | { | ||
500 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
501 | s32 err = 0; | ||
502 | |||
503 | if (check_vif_up(ifp->vif)) { | ||
504 | err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); | ||
505 | if (err) { | ||
506 | brcmf_err("fail to set mpc\n"); | ||
507 | return; | ||
508 | } | ||
509 | brcmf_dbg(INFO, "MPC : %d\n", mpc); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | 726 | static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, |
514 | struct cfg80211_scan_request *request) | 727 | struct cfg80211_scan_request *request) |
515 | { | 728 | { |
@@ -590,69 +803,6 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | |||
590 | } | 803 | } |
591 | 804 | ||
592 | static s32 | 805 | static s32 |
593 | brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||
594 | struct net_device *ndev, | ||
595 | bool aborted, bool fw_abort) | ||
596 | { | ||
597 | struct brcmf_scan_params_le params_le; | ||
598 | struct cfg80211_scan_request *scan_request; | ||
599 | s32 err = 0; | ||
600 | |||
601 | brcmf_dbg(SCAN, "Enter\n"); | ||
602 | |||
603 | /* clear scan request, because the FW abort can cause a second call */ | ||
604 | /* to this functon and might cause a double cfg80211_scan_done */ | ||
605 | scan_request = cfg->scan_request; | ||
606 | cfg->scan_request = NULL; | ||
607 | |||
608 | if (timer_pending(&cfg->escan_timeout)) | ||
609 | del_timer_sync(&cfg->escan_timeout); | ||
610 | |||
611 | if (fw_abort) { | ||
612 | /* Do a scan abort to stop the driver's scan engine */ | ||
613 | brcmf_dbg(SCAN, "ABORT scan in firmware\n"); | ||
614 | memset(¶ms_le, 0, sizeof(params_le)); | ||
615 | memset(params_le.bssid, 0xFF, ETH_ALEN); | ||
616 | params_le.bss_type = DOT11_BSSTYPE_ANY; | ||
617 | params_le.scan_type = 0; | ||
618 | params_le.channel_num = cpu_to_le32(1); | ||
619 | params_le.nprobes = cpu_to_le32(1); | ||
620 | params_le.active_time = cpu_to_le32(-1); | ||
621 | params_le.passive_time = cpu_to_le32(-1); | ||
622 | params_le.home_time = cpu_to_le32(-1); | ||
623 | /* Scan is aborted by setting channel_list[0] to -1 */ | ||
624 | params_le.channel_list[0] = cpu_to_le16(-1); | ||
625 | /* E-Scan (or anyother type) can be aborted by SCAN */ | ||
626 | err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, | ||
627 | ¶ms_le, sizeof(params_le)); | ||
628 | if (err) | ||
629 | brcmf_err("Scan abort failed\n"); | ||
630 | } | ||
631 | /* | ||
632 | * e-scan can be initiated by scheduled scan | ||
633 | * which takes precedence. | ||
634 | */ | ||
635 | if (cfg->sched_escan) { | ||
636 | brcmf_dbg(SCAN, "scheduled scan completed\n"); | ||
637 | cfg->sched_escan = false; | ||
638 | if (!aborted) | ||
639 | cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); | ||
640 | brcmf_set_mpc(ndev, 1); | ||
641 | } else if (scan_request) { | ||
642 | brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", | ||
643 | aborted ? "Aborted" : "Done"); | ||
644 | cfg80211_scan_done(scan_request, aborted); | ||
645 | brcmf_set_mpc(ndev, 1); | ||
646 | } | ||
647 | if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { | ||
648 | brcmf_err("Scan complete while device not scanning\n"); | ||
649 | return -EPERM; | ||
650 | } | ||
651 | |||
652 | return err; | ||
653 | } | ||
654 | |||
655 | static s32 | ||
656 | brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, | 806 | brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, |
657 | struct cfg80211_scan_request *request, u16 action) | 807 | struct cfg80211_scan_request *request, u16 action) |
658 | { | 808 | { |
@@ -703,11 +853,12 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, | |||
703 | s32 err; | 853 | s32 err; |
704 | u32 passive_scan; | 854 | u32 passive_scan; |
705 | struct brcmf_scan_results *results; | 855 | struct brcmf_scan_results *results; |
856 | struct escan_info *escan = &cfg->escan_info; | ||
706 | 857 | ||
707 | brcmf_dbg(SCAN, "Enter\n"); | 858 | brcmf_dbg(SCAN, "Enter\n"); |
708 | cfg->escan_info.ndev = ndev; | 859 | escan->ndev = ndev; |
709 | cfg->escan_info.wiphy = wiphy; | 860 | escan->wiphy = wiphy; |
710 | cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; | 861 | escan->escan_state = WL_ESCAN_STATE_SCANNING; |
711 | passive_scan = cfg->active_scan ? 0 : 1; | 862 | passive_scan = cfg->active_scan ? 0 : 1; |
712 | err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN, | 863 | err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN, |
713 | passive_scan); | 864 | passive_scan); |
@@ -721,7 +872,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, | |||
721 | results->count = 0; | 872 | results->count = 0; |
722 | results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; | 873 | results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; |
723 | 874 | ||
724 | err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START); | 875 | err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START); |
725 | if (err) | 876 | if (err) |
726 | brcmf_set_mpc(ndev, 1); | 877 | brcmf_set_mpc(ndev, 1); |
727 | return err; | 878 | return err; |
@@ -758,6 +909,12 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, | |||
758 | return -EAGAIN; | 909 | return -EAGAIN; |
759 | } | 910 | } |
760 | 911 | ||
912 | /* If scan req comes for p2p0, send it over primary I/F */ | ||
913 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) { | ||
914 | ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
915 | ndev = ifp->ndev; | ||
916 | } | ||
917 | |||
761 | /* Arm scan timeout timer */ | 918 | /* Arm scan timeout timer */ |
762 | mod_timer(&cfg->escan_timeout, jiffies + | 919 | mod_timer(&cfg->escan_timeout, jiffies + |
763 | WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); | 920 | WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); |
@@ -776,6 +933,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, | |||
776 | cfg->scan_request = request; | 933 | cfg->scan_request = request; |
777 | set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); | 934 | set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); |
778 | if (escan_req) { | 935 | if (escan_req) { |
936 | cfg->escan_info.run = brcmf_run_escan; | ||
937 | err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif); | ||
938 | if (err) | ||
939 | goto scan_out; | ||
940 | |||
779 | err = brcmf_do_escan(cfg, wiphy, ndev, request); | 941 | err = brcmf_do_escan(cfg, wiphy, ndev, request); |
780 | if (err) | 942 | if (err) |
781 | goto scan_out; | 943 | goto scan_out; |
@@ -933,31 +1095,6 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) | |||
933 | memset(prof, 0, sizeof(*prof)); | 1095 | memset(prof, 0, sizeof(*prof)); |
934 | } | 1096 | } |
935 | 1097 | ||
936 | static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, | ||
937 | size_t *join_params_size) | ||
938 | { | ||
939 | u16 chanspec = 0; | ||
940 | |||
941 | if (ch != 0) { | ||
942 | if (ch <= CH_MAX_2G_CHANNEL) | ||
943 | chanspec |= WL_CHANSPEC_BAND_2G; | ||
944 | else | ||
945 | chanspec |= WL_CHANSPEC_BAND_5G; | ||
946 | |||
947 | chanspec |= WL_CHANSPEC_BW_20; | ||
948 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | ||
949 | |||
950 | *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + | ||
951 | sizeof(u16); | ||
952 | |||
953 | chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); | ||
954 | join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); | ||
955 | join_params->params_le.chanspec_num = cpu_to_le32(1); | ||
956 | |||
957 | brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec); | ||
958 | } | ||
959 | } | ||
960 | |||
961 | static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) | 1098 | static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) |
962 | { | 1099 | { |
963 | s32 err = 0; | 1100 | s32 err = 0; |
@@ -988,6 +1125,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, | |||
988 | s32 err = 0; | 1125 | s32 err = 0; |
989 | s32 wsec = 0; | 1126 | s32 wsec = 0; |
990 | s32 bcnprd; | 1127 | s32 bcnprd; |
1128 | u16 chanspec; | ||
991 | 1129 | ||
992 | brcmf_dbg(TRACE, "Enter\n"); | 1130 | brcmf_dbg(TRACE, "Enter\n"); |
993 | if (!check_vif_up(ifp->vif)) | 1131 | if (!check_vif_up(ifp->vif)) |
@@ -1091,8 +1229,11 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, | |||
1091 | params->chandef.chan->center_freq); | 1229 | params->chandef.chan->center_freq); |
1092 | if (params->channel_fixed) { | 1230 | if (params->channel_fixed) { |
1093 | /* adding chanspec */ | 1231 | /* adding chanspec */ |
1094 | brcmf_ch_to_chanspec(cfg->channel, | 1232 | chanspec = channel_to_chanspec(params->chandef.chan); |
1095 | &join_params, &join_params_size); | 1233 | join_params.params_le.chanspec_list[0] = |
1234 | cpu_to_le16(chanspec); | ||
1235 | join_params.params_le.chanspec_num = cpu_to_le32(1); | ||
1236 | join_params_size += sizeof(join_params.params_le); | ||
1096 | } | 1237 | } |
1097 | 1238 | ||
1098 | /* set channel for starter */ | 1239 | /* set channel for starter */ |
@@ -1155,7 +1296,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, | |||
1155 | else | 1296 | else |
1156 | val = WPA_AUTH_DISABLED; | 1297 | val = WPA_AUTH_DISABLED; |
1157 | brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); | 1298 | brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); |
1158 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val); | 1299 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); |
1159 | if (err) { | 1300 | if (err) { |
1160 | brcmf_err("set wpa_auth failed (%d)\n", err); | 1301 | brcmf_err("set wpa_auth failed (%d)\n", err); |
1161 | return err; | 1302 | return err; |
@@ -1194,7 +1335,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, | |||
1194 | break; | 1335 | break; |
1195 | } | 1336 | } |
1196 | 1337 | ||
1197 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val); | 1338 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); |
1198 | if (err) { | 1339 | if (err) { |
1199 | brcmf_err("set auth failed (%d)\n", err); | 1340 | brcmf_err("set auth failed (%d)\n", err); |
1200 | return err; | 1341 | return err; |
@@ -1258,7 +1399,12 @@ brcmf_set_set_cipher(struct net_device *ndev, | |||
1258 | } | 1399 | } |
1259 | 1400 | ||
1260 | brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval); | 1401 | brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval); |
1261 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval); | 1402 | /* In case of privacy, but no security and WPS then simulate */ |
1403 | /* setting AES. WPS-2.0 allows no security */ | ||
1404 | if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval && | ||
1405 | sme->privacy) | ||
1406 | pval = AES_ENABLED; | ||
1407 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval); | ||
1262 | if (err) { | 1408 | if (err) { |
1263 | brcmf_err("error (%d)\n", err); | 1409 | brcmf_err("error (%d)\n", err); |
1264 | return err; | 1410 | return err; |
@@ -1280,8 +1426,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) | |||
1280 | s32 err = 0; | 1426 | s32 err = 0; |
1281 | 1427 | ||
1282 | if (sme->crypto.n_akm_suites) { | 1428 | if (sme->crypto.n_akm_suites) { |
1283 | err = brcmf_fil_iovar_int_get(netdev_priv(ndev), | 1429 | err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), |
1284 | "wpa_auth", &val); | 1430 | "wpa_auth", &val); |
1285 | if (err) { | 1431 | if (err) { |
1286 | brcmf_err("could not get wpa_auth (%d)\n", err); | 1432 | brcmf_err("could not get wpa_auth (%d)\n", err); |
1287 | return err; | 1433 | return err; |
@@ -1315,8 +1461,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) | |||
1315 | } | 1461 | } |
1316 | 1462 | ||
1317 | brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); | 1463 | brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); |
1318 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), | 1464 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), |
1319 | "wpa_auth", val); | 1465 | "wpa_auth", val); |
1320 | if (err) { | 1466 | if (err) { |
1321 | brcmf_err("could not set wpa_auth (%d)\n", err); | 1467 | brcmf_err("could not set wpa_auth (%d)\n", err); |
1322 | return err; | 1468 | return err; |
@@ -1393,9 +1539,28 @@ brcmf_set_sharedkey(struct net_device *ndev, | |||
1393 | return err; | 1539 | return err; |
1394 | } | 1540 | } |
1395 | 1541 | ||
1542 | static | ||
1543 | enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp, | ||
1544 | enum nl80211_auth_type type) | ||
1545 | { | ||
1546 | u32 ci; | ||
1547 | if (type == NL80211_AUTHTYPE_AUTOMATIC) { | ||
1548 | /* shift to ignore chip revision */ | ||
1549 | ci = brcmf_get_chip_info(ifp) >> 4; | ||
1550 | switch (ci) { | ||
1551 | case 43236: | ||
1552 | brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n"); | ||
1553 | return NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
1554 | default: | ||
1555 | break; | ||
1556 | } | ||
1557 | } | ||
1558 | return type; | ||
1559 | } | ||
1560 | |||
1396 | static s32 | 1561 | static s32 |
1397 | brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | 1562 | brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, |
1398 | struct cfg80211_connect_params *sme) | 1563 | struct cfg80211_connect_params *sme) |
1399 | { | 1564 | { |
1400 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 1565 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
1401 | struct brcmf_if *ifp = netdev_priv(ndev); | 1566 | struct brcmf_if *ifp = netdev_priv(ndev); |
@@ -1403,7 +1568,12 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1403 | struct ieee80211_channel *chan = sme->channel; | 1568 | struct ieee80211_channel *chan = sme->channel; |
1404 | struct brcmf_join_params join_params; | 1569 | struct brcmf_join_params join_params; |
1405 | size_t join_params_size; | 1570 | size_t join_params_size; |
1406 | struct brcmf_ssid ssid; | 1571 | struct brcmf_tlv *rsn_ie; |
1572 | struct brcmf_vs_tlv *wpa_ie; | ||
1573 | void *ie; | ||
1574 | u32 ie_len; | ||
1575 | struct brcmf_ext_join_params_le *ext_join_params; | ||
1576 | u16 chanspec; | ||
1407 | 1577 | ||
1408 | s32 err = 0; | 1578 | s32 err = 0; |
1409 | 1579 | ||
@@ -1416,15 +1586,46 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1416 | return -EOPNOTSUPP; | 1586 | return -EOPNOTSUPP; |
1417 | } | 1587 | } |
1418 | 1588 | ||
1589 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) { | ||
1590 | /* A normal (non P2P) connection request setup. */ | ||
1591 | ie = NULL; | ||
1592 | ie_len = 0; | ||
1593 | /* find the WPA_IE */ | ||
1594 | wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len); | ||
1595 | if (wpa_ie) { | ||
1596 | ie = wpa_ie; | ||
1597 | ie_len = wpa_ie->len + TLV_HDR_LEN; | ||
1598 | } else { | ||
1599 | /* find the RSN_IE */ | ||
1600 | rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len, | ||
1601 | WLAN_EID_RSN); | ||
1602 | if (rsn_ie) { | ||
1603 | ie = rsn_ie; | ||
1604 | ie_len = rsn_ie->len + TLV_HDR_LEN; | ||
1605 | } | ||
1606 | } | ||
1607 | brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len); | ||
1608 | } | ||
1609 | |||
1610 | err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG, | ||
1611 | sme->ie, sme->ie_len); | ||
1612 | if (err) | ||
1613 | brcmf_err("Set Assoc REQ IE Failed\n"); | ||
1614 | else | ||
1615 | brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n"); | ||
1616 | |||
1419 | set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); | 1617 | set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); |
1420 | 1618 | ||
1421 | if (chan) { | 1619 | if (chan) { |
1422 | cfg->channel = | 1620 | cfg->channel = |
1423 | ieee80211_frequency_to_channel(chan->center_freq); | 1621 | ieee80211_frequency_to_channel(chan->center_freq); |
1424 | brcmf_dbg(CONN, "channel (%d), center_req (%d)\n", | 1622 | chanspec = channel_to_chanspec(chan); |
1425 | cfg->channel, chan->center_freq); | 1623 | brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n", |
1426 | } else | 1624 | cfg->channel, chan->center_freq, chanspec); |
1625 | } else { | ||
1427 | cfg->channel = 0; | 1626 | cfg->channel = 0; |
1627 | chanspec = 0; | ||
1628 | } | ||
1428 | 1629 | ||
1429 | brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); | 1630 | brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); |
1430 | 1631 | ||
@@ -1434,6 +1635,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1434 | goto done; | 1635 | goto done; |
1435 | } | 1636 | } |
1436 | 1637 | ||
1638 | sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type); | ||
1437 | err = brcmf_set_auth_type(ndev, sme); | 1639 | err = brcmf_set_auth_type(ndev, sme); |
1438 | if (err) { | 1640 | if (err) { |
1439 | brcmf_err("wl_set_auth_type failed (%d)\n", err); | 1641 | brcmf_err("wl_set_auth_type failed (%d)\n", err); |
@@ -1458,27 +1660,88 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1458 | goto done; | 1660 | goto done; |
1459 | } | 1661 | } |
1460 | 1662 | ||
1663 | profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID), | ||
1664 | (u32)sme->ssid_len); | ||
1665 | memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); | ||
1666 | if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { | ||
1667 | profile->ssid.SSID[profile->ssid.SSID_len] = 0; | ||
1668 | brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID, | ||
1669 | profile->ssid.SSID_len); | ||
1670 | } | ||
1671 | |||
1672 | /* Join with specific BSSID and cached SSID | ||
1673 | * If SSID is zero join based on BSSID only | ||
1674 | */ | ||
1675 | join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) + | ||
1676 | offsetof(struct brcmf_assoc_params_le, chanspec_list); | ||
1677 | if (cfg->channel) | ||
1678 | join_params_size += sizeof(u16); | ||
1679 | ext_join_params = kzalloc(join_params_size, GFP_KERNEL); | ||
1680 | if (ext_join_params == NULL) { | ||
1681 | err = -ENOMEM; | ||
1682 | goto done; | ||
1683 | } | ||
1684 | ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); | ||
1685 | memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, | ||
1686 | profile->ssid.SSID_len); | ||
1687 | /*increase dwell time to receive probe response or detect Beacon | ||
1688 | * from target AP at a noisy air only during connect command | ||
1689 | */ | ||
1690 | ext_join_params->scan_le.active_time = | ||
1691 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); | ||
1692 | ext_join_params->scan_le.passive_time = | ||
1693 | cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); | ||
1694 | /* Set up join scan parameters */ | ||
1695 | ext_join_params->scan_le.scan_type = -1; | ||
1696 | /* to sync with presence period of VSDB GO. | ||
1697 | * Send probe request more frequently. Probe request will be stopped | ||
1698 | * when it gets probe response from target AP/GO. | ||
1699 | */ | ||
1700 | ext_join_params->scan_le.nprobes = | ||
1701 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / | ||
1702 | BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); | ||
1703 | ext_join_params->scan_le.home_time = cpu_to_le32(-1); | ||
1704 | |||
1705 | if (sme->bssid) | ||
1706 | memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN); | ||
1707 | else | ||
1708 | memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN); | ||
1709 | |||
1710 | if (cfg->channel) { | ||
1711 | ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1); | ||
1712 | |||
1713 | ext_join_params->assoc_le.chanspec_list[0] = | ||
1714 | cpu_to_le16(chanspec); | ||
1715 | } | ||
1716 | |||
1717 | err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, | ||
1718 | join_params_size); | ||
1719 | kfree(ext_join_params); | ||
1720 | if (!err) | ||
1721 | /* This is it. join command worked, we are done */ | ||
1722 | goto done; | ||
1723 | |||
1724 | /* join command failed, fallback to set ssid */ | ||
1461 | memset(&join_params, 0, sizeof(join_params)); | 1725 | memset(&join_params, 0, sizeof(join_params)); |
1462 | join_params_size = sizeof(join_params.ssid_le); | 1726 | join_params_size = sizeof(join_params.ssid_le); |
1463 | 1727 | ||
1464 | profile->ssid.SSID_len = min_t(u32, | ||
1465 | sizeof(ssid.SSID), (u32)sme->ssid_len); | ||
1466 | memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); | 1728 | memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); |
1467 | memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); | ||
1468 | join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); | 1729 | join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); |
1469 | 1730 | ||
1470 | memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); | 1731 | if (sme->bssid) |
1471 | 1732 | memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN); | |
1472 | if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) | 1733 | else |
1473 | brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n", | 1734 | memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); |
1474 | ssid.SSID, ssid.SSID_len); | ||
1475 | 1735 | ||
1476 | brcmf_ch_to_chanspec(cfg->channel, | 1736 | if (cfg->channel) { |
1477 | &join_params, &join_params_size); | 1737 | join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec); |
1738 | join_params.params_le.chanspec_num = cpu_to_le32(1); | ||
1739 | join_params_size += sizeof(join_params.params_le); | ||
1740 | } | ||
1478 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | 1741 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, |
1479 | &join_params, join_params_size); | 1742 | &join_params, join_params_size); |
1480 | if (err) | 1743 | if (err) |
1481 | brcmf_err("WLC_SET_SSID failed (%d)\n", err); | 1744 | brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err); |
1482 | 1745 | ||
1483 | done: | 1746 | done: |
1484 | if (err) | 1747 | if (err) |
@@ -1937,7 +2200,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | |||
1937 | goto done; | 2200 | goto done; |
1938 | } | 2201 | } |
1939 | /* Report the current tx rate */ | 2202 | /* Report the current tx rate */ |
1940 | err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); | 2203 | err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); |
1941 | if (err) { | 2204 | if (err) { |
1942 | brcmf_err("Could not get rate (%d)\n", err); | 2205 | brcmf_err("Could not get rate (%d)\n", err); |
1943 | goto done; | 2206 | goto done; |
@@ -2060,7 +2323,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, | |||
2060 | if (!bss) | 2323 | if (!bss) |
2061 | return -ENOMEM; | 2324 | return -ENOMEM; |
2062 | 2325 | ||
2063 | cfg80211_put_bss(bss); | 2326 | cfg80211_put_bss(wiphy, bss); |
2064 | 2327 | ||
2065 | return err; | 2328 | return err; |
2066 | } | 2329 | } |
@@ -2166,7 +2429,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, | |||
2166 | goto CleanUp; | 2429 | goto CleanUp; |
2167 | } | 2430 | } |
2168 | 2431 | ||
2169 | cfg80211_put_bss(bss); | 2432 | cfg80211_put_bss(wiphy, bss); |
2170 | 2433 | ||
2171 | CleanUp: | 2434 | CleanUp: |
2172 | 2435 | ||
@@ -2182,78 +2445,10 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) | |||
2182 | return vif->mode == WL_MODE_IBSS; | 2445 | return vif->mode == WL_MODE_IBSS; |
2183 | } | 2446 | } |
2184 | 2447 | ||
2185 | /* | 2448 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, |
2186 | * Traverse a string of 1-byte tag/1-byte length/variable-length value | 2449 | struct brcmf_if *ifp) |
2187 | * triples, returning a pointer to the substring whose first element | ||
2188 | * matches tag | ||
2189 | */ | ||
2190 | static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) | ||
2191 | { | ||
2192 | struct brcmf_tlv *elt; | ||
2193 | int totlen; | ||
2194 | |||
2195 | elt = (struct brcmf_tlv *) buf; | ||
2196 | totlen = buflen; | ||
2197 | |||
2198 | /* find tagged parameter */ | ||
2199 | while (totlen >= TLV_HDR_LEN) { | ||
2200 | int len = elt->len; | ||
2201 | |||
2202 | /* validate remaining totlen */ | ||
2203 | if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) | ||
2204 | return elt; | ||
2205 | |||
2206 | elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN)); | ||
2207 | totlen -= (len + TLV_HDR_LEN); | ||
2208 | } | ||
2209 | |||
2210 | return NULL; | ||
2211 | } | ||
2212 | |||
2213 | /* Is any of the tlvs the expected entry? If | ||
2214 | * not update the tlvs buffer pointer/length. | ||
2215 | */ | ||
2216 | static bool | ||
2217 | brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, | ||
2218 | u8 *oui, u32 oui_len, u8 type) | ||
2219 | { | ||
2220 | /* If the contents match the OUI and the type */ | ||
2221 | if (ie[TLV_LEN_OFF] >= oui_len + 1 && | ||
2222 | !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && | ||
2223 | type == ie[TLV_BODY_OFF + oui_len]) { | ||
2224 | return true; | ||
2225 | } | ||
2226 | |||
2227 | if (tlvs == NULL) | ||
2228 | return false; | ||
2229 | /* point to the next ie */ | ||
2230 | ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; | ||
2231 | /* calculate the length of the rest of the buffer */ | ||
2232 | *tlvs_len -= (int)(ie - *tlvs); | ||
2233 | /* update the pointer to the start of the buffer */ | ||
2234 | *tlvs = ie; | ||
2235 | |||
2236 | return false; | ||
2237 | } | ||
2238 | |||
2239 | static struct brcmf_vs_tlv * | ||
2240 | brcmf_find_wpaie(u8 *parse, u32 len) | ||
2241 | { | 2450 | { |
2242 | struct brcmf_tlv *ie; | 2451 | struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); |
2243 | |||
2244 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | ||
2245 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | ||
2246 | WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) | ||
2247 | return (struct brcmf_vs_tlv *)ie; | ||
2248 | } | ||
2249 | return NULL; | ||
2250 | } | ||
2251 | |||
2252 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) | ||
2253 | { | ||
2254 | struct net_device *ndev = cfg_to_ndev(cfg); | ||
2255 | struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); | ||
2256 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
2257 | struct brcmf_bss_info_le *bi; | 2452 | struct brcmf_bss_info_le *bi; |
2258 | struct brcmf_ssid *ssid; | 2453 | struct brcmf_ssid *ssid; |
2259 | struct brcmf_tlv *tim; | 2454 | struct brcmf_tlv *tim; |
@@ -2309,7 +2504,7 @@ update_bss_info_out: | |||
2309 | return err; | 2504 | return err; |
2310 | } | 2505 | } |
2311 | 2506 | ||
2312 | static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) | 2507 | void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) |
2313 | { | 2508 | { |
2314 | struct escan_info *escan = &cfg->escan_info; | 2509 | struct escan_info *escan = &cfg->escan_info; |
2315 | 2510 | ||
@@ -2328,8 +2523,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) | |||
2328 | container_of(work, struct brcmf_cfg80211_info, | 2523 | container_of(work, struct brcmf_cfg80211_info, |
2329 | escan_timeout_work); | 2524 | escan_timeout_work); |
2330 | 2525 | ||
2331 | brcmf_notify_escan_complete(cfg, | 2526 | brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); |
2332 | cfg->escan_info.ndev, true, true); | ||
2333 | } | 2527 | } |
2334 | 2528 | ||
2335 | static void brcmf_escan_timeout(unsigned long data) | 2529 | static void brcmf_escan_timeout(unsigned long data) |
@@ -2406,11 +2600,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2406 | brcmf_err("Invalid escan result (NULL pointer)\n"); | 2600 | brcmf_err("Invalid escan result (NULL pointer)\n"); |
2407 | goto exit; | 2601 | goto exit; |
2408 | } | 2602 | } |
2409 | if (!cfg->scan_request) { | ||
2410 | brcmf_dbg(SCAN, "result without cfg80211 request\n"); | ||
2411 | goto exit; | ||
2412 | } | ||
2413 | |||
2414 | if (le16_to_cpu(escan_result_le->bss_count) != 1) { | 2603 | if (le16_to_cpu(escan_result_le->bss_count) != 1) { |
2415 | brcmf_err("Invalid bss_count %d: ignoring\n", | 2604 | brcmf_err("Invalid bss_count %d: ignoring\n", |
2416 | escan_result_le->bss_count); | 2605 | escan_result_le->bss_count); |
@@ -2418,6 +2607,14 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2418 | } | 2607 | } |
2419 | bss_info_le = &escan_result_le->bss_info_le; | 2608 | bss_info_le = &escan_result_le->bss_info_le; |
2420 | 2609 | ||
2610 | if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) | ||
2611 | goto exit; | ||
2612 | |||
2613 | if (!cfg->scan_request) { | ||
2614 | brcmf_dbg(SCAN, "result without cfg80211 request\n"); | ||
2615 | goto exit; | ||
2616 | } | ||
2617 | |||
2421 | bi_length = le32_to_cpu(bss_info_le->length); | 2618 | bi_length = le32_to_cpu(bss_info_le->length); |
2422 | if (bi_length != (le32_to_cpu(escan_result_le->buflen) - | 2619 | if (bi_length != (le32_to_cpu(escan_result_le->buflen) - |
2423 | WL_ESCAN_RESULTS_FIXED_SIZE)) { | 2620 | WL_ESCAN_RESULTS_FIXED_SIZE)) { |
@@ -2456,6 +2653,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2456 | list->count++; | 2653 | list->count++; |
2457 | } else { | 2654 | } else { |
2458 | cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; | 2655 | cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; |
2656 | if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) | ||
2657 | goto exit; | ||
2459 | if (cfg->scan_request) { | 2658 | if (cfg->scan_request) { |
2460 | cfg->bss_list = (struct brcmf_scan_results *) | 2659 | cfg->bss_list = (struct brcmf_scan_results *) |
2461 | cfg->escan_info.escan_buf; | 2660 | cfg->escan_info.escan_buf; |
@@ -2464,7 +2663,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2464 | brcmf_notify_escan_complete(cfg, ndev, aborted, | 2663 | brcmf_notify_escan_complete(cfg, ndev, aborted, |
2465 | false); | 2664 | false); |
2466 | } else | 2665 | } else |
2467 | brcmf_err("Unexpected scan result 0x%x\n", status); | 2666 | brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n", |
2667 | status); | ||
2468 | } | 2668 | } |
2469 | exit: | 2669 | exit: |
2470 | return err; | 2670 | return err; |
@@ -2968,9 +3168,8 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) | |||
2968 | } | 3168 | } |
2969 | #endif | 3169 | #endif |
2970 | 3170 | ||
2971 | static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx) | 3171 | static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) |
2972 | { | 3172 | { |
2973 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
2974 | s32 err; | 3173 | s32 err; |
2975 | 3174 | ||
2976 | /* set auth */ | 3175 | /* set auth */ |
@@ -3229,7 +3428,7 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, | |||
3229 | parsed_info->vndrie.oui[2], | 3428 | parsed_info->vndrie.oui[2], |
3230 | parsed_info->vndrie.oui_type); | 3429 | parsed_info->vndrie.oui_type); |
3231 | 3430 | ||
3232 | if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) | 3431 | if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT) |
3233 | break; | 3432 | break; |
3234 | next: | 3433 | next: |
3235 | remaining_len -= (ie->len + TLV_HDR_LEN); | 3434 | remaining_len -= (ie->len + TLV_HDR_LEN); |
@@ -3263,7 +3462,6 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) | |||
3263 | return ie_len + VNDR_IE_HDR_SIZE; | 3462 | return ie_len + VNDR_IE_HDR_SIZE; |
3264 | } | 3463 | } |
3265 | 3464 | ||
3266 | static | ||
3267 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | 3465 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, |
3268 | const u8 *vndr_ie_buf, u32 vndr_ie_len) | 3466 | const u8 *vndr_ie_buf, u32 vndr_ie_len) |
3269 | { | 3467 | { |
@@ -3295,24 +3493,28 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | |||
3295 | if (!iovar_ie_buf) | 3493 | if (!iovar_ie_buf) |
3296 | return -ENOMEM; | 3494 | return -ENOMEM; |
3297 | curr_ie_buf = iovar_ie_buf; | 3495 | curr_ie_buf = iovar_ie_buf; |
3298 | if (ifp->vif->mode == WL_MODE_AP) { | 3496 | switch (pktflag) { |
3299 | switch (pktflag) { | 3497 | case BRCMF_VNDR_IE_PRBREQ_FLAG: |
3300 | case VNDR_IE_PRBRSP_FLAG: | 3498 | mgmt_ie_buf = saved_ie->probe_req_ie; |
3301 | mgmt_ie_buf = saved_ie->probe_res_ie; | 3499 | mgmt_ie_len = &saved_ie->probe_req_ie_len; |
3302 | mgmt_ie_len = &saved_ie->probe_res_ie_len; | 3500 | mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie); |
3303 | mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); | 3501 | break; |
3304 | break; | 3502 | case BRCMF_VNDR_IE_PRBRSP_FLAG: |
3305 | case VNDR_IE_BEACON_FLAG: | 3503 | mgmt_ie_buf = saved_ie->probe_res_ie; |
3306 | mgmt_ie_buf = saved_ie->beacon_ie; | 3504 | mgmt_ie_len = &saved_ie->probe_res_ie_len; |
3307 | mgmt_ie_len = &saved_ie->beacon_ie_len; | 3505 | mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); |
3308 | mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); | 3506 | break; |
3309 | break; | 3507 | case BRCMF_VNDR_IE_BEACON_FLAG: |
3310 | default: | 3508 | mgmt_ie_buf = saved_ie->beacon_ie; |
3311 | err = -EPERM; | 3509 | mgmt_ie_len = &saved_ie->beacon_ie_len; |
3312 | brcmf_err("not suitable type\n"); | 3510 | mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); |
3313 | goto exit; | 3511 | break; |
3314 | } | 3512 | case BRCMF_VNDR_IE_ASSOCREQ_FLAG: |
3315 | } else { | 3513 | mgmt_ie_buf = saved_ie->assoc_req_ie; |
3514 | mgmt_ie_len = &saved_ie->assoc_req_ie_len; | ||
3515 | mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie); | ||
3516 | break; | ||
3517 | default: | ||
3316 | err = -EPERM; | 3518 | err = -EPERM; |
3317 | brcmf_err("not suitable type\n"); | 3519 | brcmf_err("not suitable type\n"); |
3318 | goto exit; | 3520 | goto exit; |
@@ -3421,6 +3623,49 @@ exit: | |||
3421 | return err; | 3623 | return err; |
3422 | } | 3624 | } |
3423 | 3625 | ||
3626 | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif) | ||
3627 | { | ||
3628 | s32 pktflags[] = { | ||
3629 | BRCMF_VNDR_IE_PRBREQ_FLAG, | ||
3630 | BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3631 | BRCMF_VNDR_IE_BEACON_FLAG | ||
3632 | }; | ||
3633 | int i; | ||
3634 | |||
3635 | for (i = 0; i < ARRAY_SIZE(pktflags); i++) | ||
3636 | brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0); | ||
3637 | |||
3638 | memset(&vif->saved_ie, 0, sizeof(vif->saved_ie)); | ||
3639 | return 0; | ||
3640 | } | ||
3641 | |||
3642 | static s32 | ||
3643 | brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, | ||
3644 | struct cfg80211_beacon_data *beacon) | ||
3645 | { | ||
3646 | s32 err; | ||
3647 | |||
3648 | /* Set Beacon IEs to FW */ | ||
3649 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG, | ||
3650 | beacon->tail, beacon->tail_len); | ||
3651 | if (err) { | ||
3652 | brcmf_err("Set Beacon IE Failed\n"); | ||
3653 | return err; | ||
3654 | } | ||
3655 | brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); | ||
3656 | |||
3657 | /* Set Probe Response IEs to FW */ | ||
3658 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3659 | beacon->proberesp_ies, | ||
3660 | beacon->proberesp_ies_len); | ||
3661 | if (err) | ||
3662 | brcmf_err("Set Probe Resp IE Failed\n"); | ||
3663 | else | ||
3664 | brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); | ||
3665 | |||
3666 | return err; | ||
3667 | } | ||
3668 | |||
3424 | static s32 | 3669 | static s32 |
3425 | brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | 3670 | brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, |
3426 | struct cfg80211_ap_settings *settings) | 3671 | struct cfg80211_ap_settings *settings) |
@@ -3433,7 +3678,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3433 | struct brcmf_tlv *rsn_ie; | 3678 | struct brcmf_tlv *rsn_ie; |
3434 | struct brcmf_vs_tlv *wpa_ie; | 3679 | struct brcmf_vs_tlv *wpa_ie; |
3435 | struct brcmf_join_params join_params; | 3680 | struct brcmf_join_params join_params; |
3436 | s32 bssidx = 0; | 3681 | enum nl80211_iftype dev_role; |
3682 | struct brcmf_fil_bss_enable_le bss_enable; | ||
3437 | 3683 | ||
3438 | brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", | 3684 | brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", |
3439 | cfg80211_get_chandef_type(&settings->chandef), | 3685 | cfg80211_get_chandef_type(&settings->chandef), |
@@ -3443,10 +3689,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3443 | settings->ssid, settings->ssid_len, settings->auth_type, | 3689 | settings->ssid, settings->ssid_len, settings->auth_type, |
3444 | settings->inactivity_timeout); | 3690 | settings->inactivity_timeout); |
3445 | 3691 | ||
3446 | if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) { | 3692 | dev_role = ifp->vif->wdev.iftype; |
3447 | brcmf_err("Not in AP creation mode\n"); | ||
3448 | return -EPERM; | ||
3449 | } | ||
3450 | 3693 | ||
3451 | memset(&ssid_le, 0, sizeof(ssid_le)); | 3694 | memset(&ssid_le, 0, sizeof(ssid_le)); |
3452 | if (settings->ssid == NULL || settings->ssid_len == 0) { | 3695 | if (settings->ssid == NULL || settings->ssid_len == 0) { |
@@ -3467,21 +3710,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3467 | } | 3710 | } |
3468 | 3711 | ||
3469 | brcmf_set_mpc(ndev, 0); | 3712 | brcmf_set_mpc(ndev, 0); |
3470 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); | ||
3471 | if (err < 0) { | ||
3472 | brcmf_err("BRCMF_C_DOWN error %d\n", err); | ||
3473 | goto exit; | ||
3474 | } | ||
3475 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); | ||
3476 | if (err < 0) { | ||
3477 | brcmf_err("SET INFRA error %d\n", err); | ||
3478 | goto exit; | ||
3479 | } | ||
3480 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); | ||
3481 | if (err < 0) { | ||
3482 | brcmf_err("setting AP mode failed %d\n", err); | ||
3483 | goto exit; | ||
3484 | } | ||
3485 | 3713 | ||
3486 | /* find the RSN_IE */ | 3714 | /* find the RSN_IE */ |
3487 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, | 3715 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, |
@@ -3507,27 +3735,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3507 | } | 3735 | } |
3508 | } else { | 3736 | } else { |
3509 | brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); | 3737 | brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); |
3510 | brcmf_configure_opensecurity(ndev, bssidx); | 3738 | brcmf_configure_opensecurity(ifp); |
3511 | } | 3739 | } |
3512 | /* Set Beacon IEs to FW */ | ||
3513 | err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), | ||
3514 | VNDR_IE_BEACON_FLAG, | ||
3515 | settings->beacon.tail, | ||
3516 | settings->beacon.tail_len); | ||
3517 | if (err) | ||
3518 | brcmf_err("Set Beacon IE Failed\n"); | ||
3519 | else | ||
3520 | brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); | ||
3521 | 3740 | ||
3522 | /* Set Probe Response IEs to FW */ | 3741 | brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); |
3523 | err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), | ||
3524 | VNDR_IE_PRBRSP_FLAG, | ||
3525 | settings->beacon.proberesp_ies, | ||
3526 | settings->beacon.proberesp_ies_len); | ||
3527 | if (err) | ||
3528 | brcmf_err("Set Probe Resp IE Failed\n"); | ||
3529 | else | ||
3530 | brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); | ||
3531 | 3742 | ||
3532 | if (settings->beacon_interval) { | 3743 | if (settings->beacon_interval) { |
3533 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, | 3744 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, |
@@ -3545,22 +3756,62 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3545 | goto exit; | 3756 | goto exit; |
3546 | } | 3757 | } |
3547 | } | 3758 | } |
3548 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); | 3759 | |
3549 | if (err < 0) { | 3760 | if (dev_role == NL80211_IFTYPE_AP) { |
3550 | brcmf_err("BRCMF_C_UP error (%d)\n", err); | 3761 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); |
3551 | goto exit; | 3762 | if (err < 0) { |
3763 | brcmf_err("BRCMF_C_DOWN error %d\n", err); | ||
3764 | goto exit; | ||
3765 | } | ||
3766 | brcmf_fil_iovar_int_set(ifp, "apsta", 0); | ||
3552 | } | 3767 | } |
3553 | 3768 | ||
3554 | memset(&join_params, 0, sizeof(join_params)); | 3769 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); |
3555 | /* join parameters starts with ssid */ | ||
3556 | memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); | ||
3557 | /* create softap */ | ||
3558 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | ||
3559 | &join_params, sizeof(join_params)); | ||
3560 | if (err < 0) { | 3770 | if (err < 0) { |
3561 | brcmf_err("SET SSID error (%d)\n", err); | 3771 | brcmf_err("SET INFRA error %d\n", err); |
3562 | goto exit; | 3772 | goto exit; |
3563 | } | 3773 | } |
3774 | if (dev_role == NL80211_IFTYPE_AP) { | ||
3775 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); | ||
3776 | if (err < 0) { | ||
3777 | brcmf_err("setting AP mode failed %d\n", err); | ||
3778 | goto exit; | ||
3779 | } | ||
3780 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); | ||
3781 | if (err < 0) { | ||
3782 | brcmf_err("BRCMF_C_UP error (%d)\n", err); | ||
3783 | goto exit; | ||
3784 | } | ||
3785 | |||
3786 | memset(&join_params, 0, sizeof(join_params)); | ||
3787 | /* join parameters starts with ssid */ | ||
3788 | memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); | ||
3789 | /* create softap */ | ||
3790 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | ||
3791 | &join_params, sizeof(join_params)); | ||
3792 | if (err < 0) { | ||
3793 | brcmf_err("SET SSID error (%d)\n", err); | ||
3794 | goto exit; | ||
3795 | } | ||
3796 | brcmf_dbg(TRACE, "AP mode configuration complete\n"); | ||
3797 | } else { | ||
3798 | err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, | ||
3799 | sizeof(ssid_le)); | ||
3800 | if (err < 0) { | ||
3801 | brcmf_err("setting ssid failed %d\n", err); | ||
3802 | goto exit; | ||
3803 | } | ||
3804 | bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); | ||
3805 | bss_enable.enable = cpu_to_le32(1); | ||
3806 | err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, | ||
3807 | sizeof(bss_enable)); | ||
3808 | if (err < 0) { | ||
3809 | brcmf_err("bss_enable config failed %d\n", err); | ||
3810 | goto exit; | ||
3811 | } | ||
3812 | |||
3813 | brcmf_dbg(TRACE, "GO mode configuration complete\n"); | ||
3814 | } | ||
3564 | clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | 3815 | clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); |
3565 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 3816 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); |
3566 | 3817 | ||
@@ -3574,10 +3825,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | |||
3574 | { | 3825 | { |
3575 | struct brcmf_if *ifp = netdev_priv(ndev); | 3826 | struct brcmf_if *ifp = netdev_priv(ndev); |
3576 | s32 err = -EPERM; | 3827 | s32 err = -EPERM; |
3828 | struct brcmf_fil_bss_enable_le bss_enable; | ||
3577 | 3829 | ||
3578 | brcmf_dbg(TRACE, "Enter\n"); | 3830 | brcmf_dbg(TRACE, "Enter\n"); |
3579 | 3831 | ||
3580 | if (ifp->vif->mode == WL_MODE_AP) { | 3832 | if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) { |
3581 | /* Due to most likely deauths outstanding we sleep */ | 3833 | /* Due to most likely deauths outstanding we sleep */ |
3582 | /* first to make sure they get processed by fw. */ | 3834 | /* first to make sure they get processed by fw. */ |
3583 | msleep(400); | 3835 | msleep(400); |
@@ -3591,18 +3843,41 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | |||
3591 | brcmf_err("BRCMF_C_UP error %d\n", err); | 3843 | brcmf_err("BRCMF_C_UP error %d\n", err); |
3592 | goto exit; | 3844 | goto exit; |
3593 | } | 3845 | } |
3594 | brcmf_set_mpc(ndev, 1); | 3846 | } else { |
3595 | clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | 3847 | bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); |
3596 | clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 3848 | bss_enable.enable = cpu_to_le32(0); |
3849 | err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, | ||
3850 | sizeof(bss_enable)); | ||
3851 | if (err < 0) | ||
3852 | brcmf_err("bss_enable config failed %d\n", err); | ||
3597 | } | 3853 | } |
3854 | brcmf_set_mpc(ndev, 1); | ||
3855 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | ||
3856 | clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | ||
3857 | |||
3598 | exit: | 3858 | exit: |
3599 | return err; | 3859 | return err; |
3600 | } | 3860 | } |
3601 | 3861 | ||
3862 | static s32 | ||
3863 | brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, | ||
3864 | struct cfg80211_beacon_data *info) | ||
3865 | { | ||
3866 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
3867 | s32 err; | ||
3868 | |||
3869 | brcmf_dbg(TRACE, "Enter\n"); | ||
3870 | |||
3871 | err = brcmf_config_ap_mgmt_ie(ifp->vif, info); | ||
3872 | |||
3873 | return err; | ||
3874 | } | ||
3875 | |||
3602 | static int | 3876 | static int |
3603 | brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | 3877 | brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, |
3604 | u8 *mac) | 3878 | u8 *mac) |
3605 | { | 3879 | { |
3880 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3606 | struct brcmf_scb_val_le scbval; | 3881 | struct brcmf_scb_val_le scbval; |
3607 | struct brcmf_if *ifp = netdev_priv(ndev); | 3882 | struct brcmf_if *ifp = netdev_priv(ndev); |
3608 | s32 err; | 3883 | s32 err; |
@@ -3612,6 +3887,8 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | |||
3612 | 3887 | ||
3613 | brcmf_dbg(TRACE, "Enter %pM\n", mac); | 3888 | brcmf_dbg(TRACE, "Enter %pM\n", mac); |
3614 | 3889 | ||
3890 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) | ||
3891 | ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
3615 | if (!check_vif_up(ifp->vif)) | 3892 | if (!check_vif_up(ifp->vif)) |
3616 | return -EIO; | 3893 | return -EIO; |
3617 | 3894 | ||
@@ -3626,7 +3903,147 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | |||
3626 | return err; | 3903 | return err; |
3627 | } | 3904 | } |
3628 | 3905 | ||
3906 | |||
3907 | static void | ||
3908 | brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, | ||
3909 | struct wireless_dev *wdev, | ||
3910 | u16 frame_type, bool reg) | ||
3911 | { | ||
3912 | struct brcmf_if *ifp = netdev_priv(wdev->netdev); | ||
3913 | struct brcmf_cfg80211_vif *vif = ifp->vif; | ||
3914 | u16 mgmt_type; | ||
3915 | |||
3916 | brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg); | ||
3917 | |||
3918 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
3919 | if (reg) | ||
3920 | vif->mgmt_rx_reg |= BIT(mgmt_type); | ||
3921 | else | ||
3922 | vif->mgmt_rx_reg &= ~BIT(mgmt_type); | ||
3923 | } | ||
3924 | |||
3925 | |||
3926 | static int | ||
3927 | brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3928 | struct ieee80211_channel *chan, bool offchan, | ||
3929 | unsigned int wait, const u8 *buf, size_t len, | ||
3930 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
3931 | { | ||
3932 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3933 | const struct ieee80211_mgmt *mgmt; | ||
3934 | struct brcmf_if *ifp; | ||
3935 | struct brcmf_cfg80211_vif *vif; | ||
3936 | s32 err = 0; | ||
3937 | s32 ie_offset; | ||
3938 | s32 ie_len; | ||
3939 | struct brcmf_fil_action_frame_le *action_frame; | ||
3940 | struct brcmf_fil_af_params_le *af_params; | ||
3941 | bool ack; | ||
3942 | s32 chan_nr; | ||
3943 | |||
3944 | brcmf_dbg(TRACE, "Enter\n"); | ||
3945 | |||
3946 | *cookie = 0; | ||
3947 | |||
3948 | mgmt = (const struct ieee80211_mgmt *)buf; | ||
3949 | |||
3950 | if (!ieee80211_is_mgmt(mgmt->frame_control)) { | ||
3951 | brcmf_err("Driver only allows MGMT packet type\n"); | ||
3952 | return -EPERM; | ||
3953 | } | ||
3954 | |||
3955 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
3956 | /* Right now the only reason to get a probe response */ | ||
3957 | /* is for p2p listen response or for p2p GO from */ | ||
3958 | /* wpa_supplicant. Unfortunately the probe is send */ | ||
3959 | /* on primary ndev, while dongle wants it on the p2p */ | ||
3960 | /* vif. Since this is only reason for a probe */ | ||
3961 | /* response to be sent, the vif is taken from cfg. */ | ||
3962 | /* If ever desired to send proberesp for non p2p */ | ||
3963 | /* response then data should be checked for */ | ||
3964 | /* "DIRECT-". Note in future supplicant will take */ | ||
3965 | /* dedicated p2p wdev to do this and then this 'hack'*/ | ||
3966 | /* is not needed anymore. */ | ||
3967 | ie_offset = DOT11_MGMT_HDR_LEN + | ||
3968 | DOT11_BCN_PRB_FIXED_LEN; | ||
3969 | ie_len = len - ie_offset; | ||
3970 | ifp = netdev_priv(wdev->netdev); | ||
3971 | vif = ifp->vif; | ||
3972 | if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) | ||
3973 | vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
3974 | err = brcmf_vif_set_mgmt_ie(vif, | ||
3975 | BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3976 | &buf[ie_offset], | ||
3977 | ie_len); | ||
3978 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, | ||
3979 | GFP_KERNEL); | ||
3980 | } else if (ieee80211_is_action(mgmt->frame_control)) { | ||
3981 | af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); | ||
3982 | if (af_params == NULL) { | ||
3983 | brcmf_err("unable to allocate frame\n"); | ||
3984 | err = -ENOMEM; | ||
3985 | goto exit; | ||
3986 | } | ||
3987 | action_frame = &af_params->action_frame; | ||
3988 | /* Add the packet Id */ | ||
3989 | action_frame->packet_id = cpu_to_le32(*cookie); | ||
3990 | /* Add BSSID */ | ||
3991 | memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN); | ||
3992 | memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN); | ||
3993 | /* Add the length exepted for 802.11 header */ | ||
3994 | action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); | ||
3995 | /* Add the channel */ | ||
3996 | chan_nr = ieee80211_frequency_to_channel(chan->center_freq); | ||
3997 | af_params->channel = cpu_to_le32(chan_nr); | ||
3998 | |||
3999 | memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], | ||
4000 | le16_to_cpu(action_frame->len)); | ||
4001 | |||
4002 | brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n", | ||
4003 | *cookie, le16_to_cpu(action_frame->len), | ||
4004 | chan->center_freq); | ||
4005 | |||
4006 | ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev, | ||
4007 | af_params); | ||
4008 | |||
4009 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, | ||
4010 | GFP_KERNEL); | ||
4011 | kfree(af_params); | ||
4012 | } else { | ||
4013 | brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); | ||
4014 | brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len); | ||
4015 | } | ||
4016 | |||
4017 | exit: | ||
4018 | return err; | ||
4019 | } | ||
4020 | |||
4021 | |||
4022 | static int | ||
4023 | brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, | ||
4024 | struct wireless_dev *wdev, | ||
4025 | u64 cookie) | ||
4026 | { | ||
4027 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
4028 | struct brcmf_cfg80211_vif *vif; | ||
4029 | int err = 0; | ||
4030 | |||
4031 | brcmf_dbg(TRACE, "Enter p2p listen cancel\n"); | ||
4032 | |||
4033 | vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
4034 | if (vif == NULL) { | ||
4035 | brcmf_err("No p2p device available for probe response\n"); | ||
4036 | err = -ENODEV; | ||
4037 | goto exit; | ||
4038 | } | ||
4039 | brcmf_p2p_cancel_remain_on_channel(vif->ifp); | ||
4040 | exit: | ||
4041 | return err; | ||
4042 | } | ||
4043 | |||
3629 | static struct cfg80211_ops wl_cfg80211_ops = { | 4044 | static struct cfg80211_ops wl_cfg80211_ops = { |
4045 | .add_virtual_intf = brcmf_cfg80211_add_iface, | ||
4046 | .del_virtual_intf = brcmf_cfg80211_del_iface, | ||
3630 | .change_virtual_intf = brcmf_cfg80211_change_iface, | 4047 | .change_virtual_intf = brcmf_cfg80211_change_iface, |
3631 | .scan = brcmf_cfg80211_scan, | 4048 | .scan = brcmf_cfg80211_scan, |
3632 | .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, | 4049 | .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, |
@@ -3650,28 +4067,43 @@ static struct cfg80211_ops wl_cfg80211_ops = { | |||
3650 | .flush_pmksa = brcmf_cfg80211_flush_pmksa, | 4067 | .flush_pmksa = brcmf_cfg80211_flush_pmksa, |
3651 | .start_ap = brcmf_cfg80211_start_ap, | 4068 | .start_ap = brcmf_cfg80211_start_ap, |
3652 | .stop_ap = brcmf_cfg80211_stop_ap, | 4069 | .stop_ap = brcmf_cfg80211_stop_ap, |
4070 | .change_beacon = brcmf_cfg80211_change_beacon, | ||
3653 | .del_station = brcmf_cfg80211_del_station, | 4071 | .del_station = brcmf_cfg80211_del_station, |
3654 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, | 4072 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, |
3655 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, | 4073 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, |
4074 | .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, | ||
4075 | .mgmt_tx = brcmf_cfg80211_mgmt_tx, | ||
4076 | .remain_on_channel = brcmf_p2p_remain_on_channel, | ||
4077 | .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, | ||
3656 | #ifdef CONFIG_NL80211_TESTMODE | 4078 | #ifdef CONFIG_NL80211_TESTMODE |
3657 | .testmode_cmd = brcmf_cfg80211_testmode | 4079 | .testmode_cmd = brcmf_cfg80211_testmode |
3658 | #endif | 4080 | #endif |
3659 | }; | 4081 | }; |
3660 | 4082 | ||
3661 | static s32 brcmf_mode_to_nl80211_iftype(s32 mode) | 4083 | static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) |
3662 | { | 4084 | { |
3663 | s32 err = 0; | 4085 | switch (type) { |
3664 | 4086 | case NL80211_IFTYPE_AP_VLAN: | |
3665 | switch (mode) { | 4087 | case NL80211_IFTYPE_WDS: |
3666 | case WL_MODE_BSS: | 4088 | case NL80211_IFTYPE_MONITOR: |
3667 | return NL80211_IFTYPE_STATION; | 4089 | case NL80211_IFTYPE_MESH_POINT: |
3668 | case WL_MODE_IBSS: | 4090 | return -ENOTSUPP; |
3669 | return NL80211_IFTYPE_ADHOC; | 4091 | case NL80211_IFTYPE_ADHOC: |
4092 | return WL_MODE_IBSS; | ||
4093 | case NL80211_IFTYPE_STATION: | ||
4094 | case NL80211_IFTYPE_P2P_CLIENT: | ||
4095 | return WL_MODE_BSS; | ||
4096 | case NL80211_IFTYPE_AP: | ||
4097 | case NL80211_IFTYPE_P2P_GO: | ||
4098 | return WL_MODE_AP; | ||
4099 | case NL80211_IFTYPE_P2P_DEVICE: | ||
4100 | return WL_MODE_P2P; | ||
4101 | case NL80211_IFTYPE_UNSPECIFIED: | ||
3670 | default: | 4102 | default: |
3671 | return NL80211_IFTYPE_UNSPECIFIED; | 4103 | break; |
3672 | } | 4104 | } |
3673 | 4105 | ||
3674 | return err; | 4106 | return -EINVAL; |
3675 | } | 4107 | } |
3676 | 4108 | ||
3677 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | 4109 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) |
@@ -3683,6 +4115,56 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | |||
3683 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 4115 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
3684 | } | 4116 | } |
3685 | 4117 | ||
4118 | static const struct ieee80211_iface_limit brcmf_iface_limits[] = { | ||
4119 | { | ||
4120 | .max = 2, | ||
4121 | .types = BIT(NL80211_IFTYPE_STATION) | | ||
4122 | BIT(NL80211_IFTYPE_ADHOC) | | ||
4123 | BIT(NL80211_IFTYPE_AP) | ||
4124 | }, | ||
4125 | { | ||
4126 | .max = 1, | ||
4127 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE) | ||
4128 | }, | ||
4129 | { | ||
4130 | .max = 1, | ||
4131 | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
4132 | BIT(NL80211_IFTYPE_P2P_GO) | ||
4133 | }, | ||
4134 | }; | ||
4135 | static const struct ieee80211_iface_combination brcmf_iface_combos[] = { | ||
4136 | { | ||
4137 | .max_interfaces = BRCMF_IFACE_MAX_CNT, | ||
4138 | .num_different_channels = 1, /* no multi-channel for now */ | ||
4139 | .n_limits = ARRAY_SIZE(brcmf_iface_limits), | ||
4140 | .limits = brcmf_iface_limits | ||
4141 | } | ||
4142 | }; | ||
4143 | |||
4144 | static const struct ieee80211_txrx_stypes | ||
4145 | brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { | ||
4146 | [NL80211_IFTYPE_STATION] = { | ||
4147 | .tx = 0xffff, | ||
4148 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
4149 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
4150 | }, | ||
4151 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
4152 | .tx = 0xffff, | ||
4153 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
4154 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
4155 | }, | ||
4156 | [NL80211_IFTYPE_P2P_GO] = { | ||
4157 | .tx = 0xffff, | ||
4158 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
4159 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
4160 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
4161 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
4162 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
4163 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
4164 | BIT(IEEE80211_STYPE_ACTION >> 4) | ||
4165 | } | ||
4166 | }; | ||
4167 | |||
3686 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | 4168 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) |
3687 | { | 4169 | { |
3688 | struct wiphy *wiphy; | 4170 | struct wiphy *wiphy; |
@@ -3695,10 +4177,16 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3695 | } | 4177 | } |
3696 | set_wiphy_dev(wiphy, phydev); | 4178 | set_wiphy_dev(wiphy, phydev); |
3697 | wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; | 4179 | wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; |
4180 | wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; | ||
3698 | wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; | 4181 | wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; |
3699 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 4182 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
3700 | BIT(NL80211_IFTYPE_ADHOC) | | 4183 | BIT(NL80211_IFTYPE_ADHOC) | |
3701 | BIT(NL80211_IFTYPE_AP); | 4184 | BIT(NL80211_IFTYPE_AP) | |
4185 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
4186 | BIT(NL80211_IFTYPE_P2P_GO) | | ||
4187 | BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
4188 | wiphy->iface_combinations = brcmf_iface_combos; | ||
4189 | wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); | ||
3702 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; | 4190 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; |
3703 | wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set | 4191 | wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set |
3704 | * it as 11a by default. | 4192 | * it as 11a by default. |
@@ -3710,10 +4198,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3710 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 4198 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
3711 | wiphy->cipher_suites = __wl_cipher_suites; | 4199 | wiphy->cipher_suites = __wl_cipher_suites; |
3712 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); | 4200 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); |
3713 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power | 4201 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | |
3714 | * save mode | 4202 | WIPHY_FLAG_OFFCHAN_TX | |
3715 | * by default | 4203 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
3716 | */ | 4204 | wiphy->mgmt_stypes = brcmf_txrx_stypes; |
4205 | wiphy->max_remain_on_channel_duration = 5000; | ||
3717 | brcmf_wiphy_pno_params(wiphy); | 4206 | brcmf_wiphy_pno_params(wiphy); |
3718 | err = wiphy_register(wiphy); | 4207 | err = wiphy_register(wiphy); |
3719 | if (err < 0) { | 4208 | if (err < 0) { |
@@ -3724,31 +4213,25 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3724 | return wiphy; | 4213 | return wiphy; |
3725 | } | 4214 | } |
3726 | 4215 | ||
3727 | static | ||
3728 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | 4216 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, |
3729 | struct net_device *netdev, | 4217 | enum nl80211_iftype type, |
3730 | s32 mode, bool pm_block) | 4218 | bool pm_block) |
3731 | { | 4219 | { |
3732 | struct brcmf_cfg80211_vif *vif; | 4220 | struct brcmf_cfg80211_vif *vif; |
3733 | 4221 | ||
3734 | if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) | 4222 | if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) |
3735 | return ERR_PTR(-ENOSPC); | 4223 | return ERR_PTR(-ENOSPC); |
3736 | 4224 | ||
4225 | brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", | ||
4226 | sizeof(*vif)); | ||
3737 | vif = kzalloc(sizeof(*vif), GFP_KERNEL); | 4227 | vif = kzalloc(sizeof(*vif), GFP_KERNEL); |
3738 | if (!vif) | 4228 | if (!vif) |
3739 | return ERR_PTR(-ENOMEM); | 4229 | return ERR_PTR(-ENOMEM); |
3740 | 4230 | ||
3741 | vif->wdev.wiphy = cfg->wiphy; | 4231 | vif->wdev.wiphy = cfg->wiphy; |
3742 | vif->wdev.netdev = netdev; | 4232 | vif->wdev.iftype = type; |
3743 | vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode); | ||
3744 | |||
3745 | if (netdev) { | ||
3746 | vif->ifp = netdev_priv(netdev); | ||
3747 | netdev->ieee80211_ptr = &vif->wdev; | ||
3748 | SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy)); | ||
3749 | } | ||
3750 | 4233 | ||
3751 | vif->mode = mode; | 4234 | vif->mode = brcmf_nl80211_iftype_to_mode(type); |
3752 | vif->pm_block = pm_block; | 4235 | vif->pm_block = pm_block; |
3753 | vif->roam_off = -1; | 4236 | vif->roam_off = -1; |
3754 | 4237 | ||
@@ -3759,7 +4242,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | |||
3759 | return vif; | 4242 | return vif; |
3760 | } | 4243 | } |
3761 | 4244 | ||
3762 | static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) | 4245 | void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) |
3763 | { | 4246 | { |
3764 | struct brcmf_cfg80211_info *cfg; | 4247 | struct brcmf_cfg80211_info *cfg; |
3765 | struct wiphy *wiphy; | 4248 | struct wiphy *wiphy; |
@@ -3833,9 +4316,9 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) | |||
3833 | conn_info->resp_ie_len = 0; | 4316 | conn_info->resp_ie_len = 0; |
3834 | } | 4317 | } |
3835 | 4318 | ||
3836 | static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) | 4319 | static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, |
4320 | struct brcmf_if *ifp) | ||
3837 | { | 4321 | { |
3838 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | ||
3839 | struct brcmf_cfg80211_assoc_ielen_le *assoc_info; | 4322 | struct brcmf_cfg80211_assoc_ielen_le *assoc_info; |
3840 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); | 4323 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); |
3841 | u32 req_len; | 4324 | u32 req_len; |
@@ -3911,9 +4394,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, | |||
3911 | 4394 | ||
3912 | brcmf_dbg(TRACE, "Enter\n"); | 4395 | brcmf_dbg(TRACE, "Enter\n"); |
3913 | 4396 | ||
3914 | brcmf_get_assoc_ies(cfg); | 4397 | brcmf_get_assoc_ies(cfg, ifp); |
3915 | memcpy(profile->bssid, e->addr, ETH_ALEN); | 4398 | memcpy(profile->bssid, e->addr, ETH_ALEN); |
3916 | brcmf_update_bss_info(cfg); | 4399 | brcmf_update_bss_info(cfg, ifp); |
3917 | 4400 | ||
3918 | buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); | 4401 | buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); |
3919 | if (buf == NULL) { | 4402 | if (buf == NULL) { |
@@ -3968,9 +4451,11 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, | |||
3968 | if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, | 4451 | if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, |
3969 | &ifp->vif->sme_state)) { | 4452 | &ifp->vif->sme_state)) { |
3970 | if (completed) { | 4453 | if (completed) { |
3971 | brcmf_get_assoc_ies(cfg); | 4454 | brcmf_get_assoc_ies(cfg, ifp); |
3972 | memcpy(profile->bssid, e->addr, ETH_ALEN); | 4455 | memcpy(profile->bssid, e->addr, ETH_ALEN); |
3973 | brcmf_update_bss_info(cfg); | 4456 | brcmf_update_bss_info(cfg, ifp); |
4457 | set_bit(BRCMF_VIF_STATUS_CONNECTED, | ||
4458 | &ifp->vif->sme_state); | ||
3974 | } | 4459 | } |
3975 | cfg80211_connect_result(ndev, | 4460 | cfg80211_connect_result(ndev, |
3976 | (u8 *)profile->bssid, | 4461 | (u8 *)profile->bssid, |
@@ -3981,9 +4466,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, | |||
3981 | completed ? WLAN_STATUS_SUCCESS : | 4466 | completed ? WLAN_STATUS_SUCCESS : |
3982 | WLAN_STATUS_AUTH_TIMEOUT, | 4467 | WLAN_STATUS_AUTH_TIMEOUT, |
3983 | GFP_KERNEL); | 4468 | GFP_KERNEL); |
3984 | if (completed) | ||
3985 | set_bit(BRCMF_VIF_STATUS_CONNECTED, | ||
3986 | &ifp->vif->sme_state); | ||
3987 | brcmf_dbg(CONN, "Report connect result - connection %s\n", | 4469 | brcmf_dbg(CONN, "Report connect result - connection %s\n", |
3988 | completed ? "succeeded" : "failed"); | 4470 | completed ? "succeeded" : "failed"); |
3989 | } | 4471 | } |
@@ -3996,38 +4478,38 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, | |||
3996 | struct net_device *ndev, | 4478 | struct net_device *ndev, |
3997 | const struct brcmf_event_msg *e, void *data) | 4479 | const struct brcmf_event_msg *e, void *data) |
3998 | { | 4480 | { |
3999 | s32 err = 0; | 4481 | static int generation; |
4000 | u32 event = e->event_code; | 4482 | u32 event = e->event_code; |
4001 | u32 reason = e->reason; | 4483 | u32 reason = e->reason; |
4002 | u32 len = e->datalen; | ||
4003 | static int generation; | ||
4004 | |||
4005 | struct station_info sinfo; | 4484 | struct station_info sinfo; |
4006 | 4485 | ||
4007 | brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); | 4486 | brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); |
4008 | memset(&sinfo, 0, sizeof(sinfo)); | 4487 | if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS && |
4488 | ndev != cfg_to_ndev(cfg)) { | ||
4489 | brcmf_dbg(CONN, "AP mode link down\n"); | ||
4490 | complete(&cfg->vif_disabled); | ||
4491 | return 0; | ||
4492 | } | ||
4009 | 4493 | ||
4010 | sinfo.filled = 0; | ||
4011 | if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && | 4494 | if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && |
4012 | reason == BRCMF_E_STATUS_SUCCESS) { | 4495 | (reason == BRCMF_E_STATUS_SUCCESS)) { |
4496 | memset(&sinfo, 0, sizeof(sinfo)); | ||
4013 | sinfo.filled = STATION_INFO_ASSOC_REQ_IES; | 4497 | sinfo.filled = STATION_INFO_ASSOC_REQ_IES; |
4014 | if (!data) { | 4498 | if (!data) { |
4015 | brcmf_err("No IEs present in ASSOC/REASSOC_IND"); | 4499 | brcmf_err("No IEs present in ASSOC/REASSOC_IND"); |
4016 | return -EINVAL; | 4500 | return -EINVAL; |
4017 | } | 4501 | } |
4018 | sinfo.assoc_req_ies = data; | 4502 | sinfo.assoc_req_ies = data; |
4019 | sinfo.assoc_req_ies_len = len; | 4503 | sinfo.assoc_req_ies_len = e->datalen; |
4020 | generation++; | 4504 | generation++; |
4021 | sinfo.generation = generation; | 4505 | sinfo.generation = generation; |
4022 | cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC); | 4506 | cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL); |
4023 | } else if ((event == BRCMF_E_DISASSOC_IND) || | 4507 | } else if ((event == BRCMF_E_DISASSOC_IND) || |
4024 | (event == BRCMF_E_DEAUTH_IND) || | 4508 | (event == BRCMF_E_DEAUTH_IND) || |
4025 | (event == BRCMF_E_DEAUTH)) { | 4509 | (event == BRCMF_E_DEAUTH)) { |
4026 | generation++; | 4510 | cfg80211_del_sta(ndev, e->addr, GFP_KERNEL); |
4027 | sinfo.generation = generation; | ||
4028 | cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC); | ||
4029 | } | 4511 | } |
4030 | return err; | 4512 | return 0; |
4031 | } | 4513 | } |
4032 | 4514 | ||
4033 | static s32 | 4515 | static s32 |
@@ -4064,6 +4546,8 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, | |||
4064 | } | 4546 | } |
4065 | brcmf_link_down(ifp->vif); | 4547 | brcmf_link_down(ifp->vif); |
4066 | brcmf_init_prof(ndev_to_prof(ndev)); | 4548 | brcmf_init_prof(ndev_to_prof(ndev)); |
4549 | if (ndev != cfg_to_ndev(cfg)) | ||
4550 | complete(&cfg->vif_disabled); | ||
4067 | } else if (brcmf_is_nonetwork(cfg, e)) { | 4551 | } else if (brcmf_is_nonetwork(cfg, e)) { |
4068 | if (brcmf_is_ibssmode(ifp->vif)) | 4552 | if (brcmf_is_ibssmode(ifp->vif)) |
4069 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, | 4553 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, |
@@ -4112,6 +4596,57 @@ brcmf_notify_mic_status(struct brcmf_if *ifp, | |||
4112 | return 0; | 4596 | return 0; |
4113 | } | 4597 | } |
4114 | 4598 | ||
4599 | static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, | ||
4600 | const struct brcmf_event_msg *e, void *data) | ||
4601 | { | ||
4602 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
4603 | struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data; | ||
4604 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
4605 | struct brcmf_cfg80211_vif *vif; | ||
4606 | |||
4607 | brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n", | ||
4608 | ifevent->action, ifevent->flags, ifevent->ifidx, | ||
4609 | ifevent->bssidx); | ||
4610 | |||
4611 | mutex_lock(&event->vif_event_lock); | ||
4612 | event->action = ifevent->action; | ||
4613 | vif = event->vif; | ||
4614 | |||
4615 | switch (ifevent->action) { | ||
4616 | case BRCMF_E_IF_ADD: | ||
4617 | /* waiting process may have timed out */ | ||
4618 | if (!cfg->vif_event.vif) | ||
4619 | return -EBADF; | ||
4620 | |||
4621 | ifp->vif = vif; | ||
4622 | vif->ifp = ifp; | ||
4623 | vif->wdev.netdev = ifp->ndev; | ||
4624 | ifp->ndev->ieee80211_ptr = &vif->wdev; | ||
4625 | SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy)); | ||
4626 | mutex_unlock(&event->vif_event_lock); | ||
4627 | wake_up(&event->vif_wq); | ||
4628 | return 0; | ||
4629 | |||
4630 | case BRCMF_E_IF_DEL: | ||
4631 | ifp->vif = NULL; | ||
4632 | mutex_unlock(&event->vif_event_lock); | ||
4633 | /* event may not be upon user request */ | ||
4634 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
4635 | wake_up(&event->vif_wq); | ||
4636 | return 0; | ||
4637 | |||
4638 | case BRCMF_E_IF_CHANGE: | ||
4639 | mutex_unlock(&event->vif_event_lock); | ||
4640 | wake_up(&event->vif_wq); | ||
4641 | return 0; | ||
4642 | |||
4643 | default: | ||
4644 | mutex_unlock(&event->vif_event_lock); | ||
4645 | break; | ||
4646 | } | ||
4647 | return -EINVAL; | ||
4648 | } | ||
4649 | |||
4115 | static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) | 4650 | static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) |
4116 | { | 4651 | { |
4117 | conf->frag_threshold = (u32)-1; | 4652 | conf->frag_threshold = (u32)-1; |
@@ -4143,6 +4678,18 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) | |||
4143 | brcmf_notify_connect_status); | 4678 | brcmf_notify_connect_status); |
4144 | brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, | 4679 | brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, |
4145 | brcmf_notify_sched_scan_results); | 4680 | brcmf_notify_sched_scan_results); |
4681 | brcmf_fweh_register(cfg->pub, BRCMF_E_IF, | ||
4682 | brcmf_notify_vif_event); | ||
4683 | brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG, | ||
4684 | brcmf_p2p_notify_rx_mgmt_p2p_probereq); | ||
4685 | brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE, | ||
4686 | brcmf_p2p_notify_listen_complete); | ||
4687 | brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX, | ||
4688 | brcmf_p2p_notify_action_frame_rx); | ||
4689 | brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE, | ||
4690 | brcmf_p2p_notify_action_tx_complete); | ||
4691 | brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, | ||
4692 | brcmf_p2p_notify_action_tx_complete); | ||
4146 | } | 4693 | } |
4147 | 4694 | ||
4148 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) | 4695 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) |
@@ -4198,7 +4745,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) | |||
4198 | mutex_init(&cfg->usr_sync); | 4745 | mutex_init(&cfg->usr_sync); |
4199 | brcmf_init_escan(cfg); | 4746 | brcmf_init_escan(cfg); |
4200 | brcmf_init_conf(cfg->conf); | 4747 | brcmf_init_conf(cfg->conf); |
4201 | 4748 | init_completion(&cfg->vif_disabled); | |
4202 | return err; | 4749 | return err; |
4203 | } | 4750 | } |
4204 | 4751 | ||
@@ -4209,6 +4756,12 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) | |||
4209 | brcmf_deinit_priv_mem(cfg); | 4756 | brcmf_deinit_priv_mem(cfg); |
4210 | } | 4757 | } |
4211 | 4758 | ||
4759 | static void init_vif_event(struct brcmf_cfg80211_vif_event *event) | ||
4760 | { | ||
4761 | init_waitqueue_head(&event->vif_wq); | ||
4762 | mutex_init(&event->vif_event_lock); | ||
4763 | } | ||
4764 | |||
4212 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, | 4765 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, |
4213 | struct device *busdev) | 4766 | struct device *busdev) |
4214 | { | 4767 | { |
@@ -4232,25 +4785,41 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, | |||
4232 | cfg = wiphy_priv(wiphy); | 4785 | cfg = wiphy_priv(wiphy); |
4233 | cfg->wiphy = wiphy; | 4786 | cfg->wiphy = wiphy; |
4234 | cfg->pub = drvr; | 4787 | cfg->pub = drvr; |
4788 | init_vif_event(&cfg->vif_event); | ||
4235 | INIT_LIST_HEAD(&cfg->vif_list); | 4789 | INIT_LIST_HEAD(&cfg->vif_list); |
4236 | 4790 | ||
4237 | vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false); | 4791 | vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); |
4238 | if (IS_ERR(vif)) { | 4792 | if (IS_ERR(vif)) { |
4239 | wiphy_free(wiphy); | 4793 | wiphy_free(wiphy); |
4240 | return NULL; | 4794 | return NULL; |
4241 | } | 4795 | } |
4242 | 4796 | ||
4797 | vif->ifp = ifp; | ||
4798 | vif->wdev.netdev = ndev; | ||
4799 | ndev->ieee80211_ptr = &vif->wdev; | ||
4800 | SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); | ||
4801 | |||
4243 | err = wl_init_priv(cfg); | 4802 | err = wl_init_priv(cfg); |
4244 | if (err) { | 4803 | if (err) { |
4245 | brcmf_err("Failed to init iwm_priv (%d)\n", err); | 4804 | brcmf_err("Failed to init iwm_priv (%d)\n", err); |
4246 | goto cfg80211_attach_out; | 4805 | goto cfg80211_attach_out; |
4247 | } | 4806 | } |
4248 | |||
4249 | ifp->vif = vif; | 4807 | ifp->vif = vif; |
4808 | |||
4809 | err = brcmf_p2p_attach(cfg); | ||
4810 | if (err) { | ||
4811 | brcmf_err("P2P initilisation failed (%d)\n", err); | ||
4812 | goto cfg80211_p2p_attach_out; | ||
4813 | } | ||
4814 | |||
4250 | return cfg; | 4815 | return cfg; |
4251 | 4816 | ||
4817 | cfg80211_p2p_attach_out: | ||
4818 | wl_deinit_priv(cfg); | ||
4819 | |||
4252 | cfg80211_attach_out: | 4820 | cfg80211_attach_out: |
4253 | brcmf_free_vif(vif); | 4821 | brcmf_free_vif(vif); |
4822 | wiphy_free(wiphy); | ||
4254 | return NULL; | 4823 | return NULL; |
4255 | } | 4824 | } |
4256 | 4825 | ||
@@ -4489,3 +5058,57 @@ s32 brcmf_cfg80211_down(struct net_device *ndev) | |||
4489 | return err; | 5058 | return err; |
4490 | } | 5059 | } |
4491 | 5060 | ||
5061 | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state) | ||
5062 | { | ||
5063 | struct brcmf_cfg80211_vif *vif; | ||
5064 | bool result = 0; | ||
5065 | |||
5066 | list_for_each_entry(vif, &cfg->vif_list, list) { | ||
5067 | if (test_bit(state, &vif->sme_state)) | ||
5068 | result++; | ||
5069 | } | ||
5070 | return result; | ||
5071 | } | ||
5072 | |||
5073 | static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event, | ||
5074 | u8 action) | ||
5075 | { | ||
5076 | u8 evt_action; | ||
5077 | |||
5078 | mutex_lock(&event->vif_event_lock); | ||
5079 | evt_action = event->action; | ||
5080 | mutex_unlock(&event->vif_event_lock); | ||
5081 | return evt_action == action; | ||
5082 | } | ||
5083 | |||
5084 | void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, | ||
5085 | struct brcmf_cfg80211_vif *vif) | ||
5086 | { | ||
5087 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
5088 | |||
5089 | mutex_lock(&event->vif_event_lock); | ||
5090 | event->vif = vif; | ||
5091 | event->action = 0; | ||
5092 | mutex_unlock(&event->vif_event_lock); | ||
5093 | } | ||
5094 | |||
5095 | bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) | ||
5096 | { | ||
5097 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
5098 | bool armed; | ||
5099 | |||
5100 | mutex_lock(&event->vif_event_lock); | ||
5101 | armed = event->vif != NULL; | ||
5102 | mutex_unlock(&event->vif_event_lock); | ||
5103 | |||
5104 | return armed; | ||
5105 | } | ||
5106 | int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, | ||
5107 | u8 action, ulong timeout) | ||
5108 | { | ||
5109 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
5110 | |||
5111 | return wait_event_timeout(event->vif_wq, | ||
5112 | vif_event_equals(event, action), timeout); | ||
5113 | } | ||
5114 | |||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index e4d9cc7a8e63..8b5d4989906c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -41,6 +41,38 @@ | |||
41 | #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ | 41 | #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ |
42 | #define IE_MAX_LEN 512 | 42 | #define IE_MAX_LEN 512 |
43 | 43 | ||
44 | /* IE TLV processing */ | ||
45 | #define TLV_LEN_OFF 1 /* length offset */ | ||
46 | #define TLV_HDR_LEN 2 /* header length */ | ||
47 | #define TLV_BODY_OFF 2 /* body offset */ | ||
48 | #define TLV_OUI_LEN 3 /* oui id length */ | ||
49 | |||
50 | /* 802.11 Mgmt Packet flags */ | ||
51 | #define BRCMF_VNDR_IE_BEACON_FLAG 0x1 | ||
52 | #define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2 | ||
53 | #define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4 | ||
54 | #define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8 | ||
55 | #define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10 | ||
56 | #define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20 | ||
57 | /* vendor IE in IW advertisement protocol ID field */ | ||
58 | #define BRCMF_VNDR_IE_IWAPID_FLAG 0x40 | ||
59 | /* allow custom IE id */ | ||
60 | #define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100 | ||
61 | |||
62 | /* P2P Action Frames flags (spec ordered) */ | ||
63 | #define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000 | ||
64 | #define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000 | ||
65 | #define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000 | ||
66 | #define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000 | ||
67 | #define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000 | ||
68 | #define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000 | ||
69 | #define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000 | ||
70 | #define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000 | ||
71 | #define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000 | ||
72 | |||
73 | #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 | ||
74 | |||
75 | |||
44 | /** | 76 | /** |
45 | * enum brcmf_scan_status - dongle scan status | 77 | * enum brcmf_scan_status - dongle scan status |
46 | * | 78 | * |
@@ -52,11 +84,19 @@ enum brcmf_scan_status { | |||
52 | BRCMF_SCAN_STATUS_ABORT, | 84 | BRCMF_SCAN_STATUS_ABORT, |
53 | }; | 85 | }; |
54 | 86 | ||
55 | /* wi-fi mode */ | 87 | /** |
88 | * enum wl_mode - driver mode of virtual interface. | ||
89 | * | ||
90 | * @WL_MODE_BSS: connects to BSS. | ||
91 | * @WL_MODE_IBSS: operate as ad-hoc. | ||
92 | * @WL_MODE_AP: operate as access-point. | ||
93 | * @WL_MODE_P2P: provide P2P discovery. | ||
94 | */ | ||
56 | enum wl_mode { | 95 | enum wl_mode { |
57 | WL_MODE_BSS, | 96 | WL_MODE_BSS, |
58 | WL_MODE_IBSS, | 97 | WL_MODE_IBSS, |
59 | WL_MODE_AP | 98 | WL_MODE_AP, |
99 | WL_MODE_P2P | ||
60 | }; | 100 | }; |
61 | 101 | ||
62 | /* dongle configuration */ | 102 | /* dongle configuration */ |
@@ -108,6 +148,7 @@ struct brcmf_cfg80211_profile { | |||
108 | * @BRCMF_VIF_STATUS_READY: ready for operation. | 148 | * @BRCMF_VIF_STATUS_READY: ready for operation. |
109 | * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. | 149 | * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. |
110 | * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. | 150 | * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. |
151 | * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. | ||
111 | * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. | 152 | * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. |
112 | * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. | 153 | * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. |
113 | */ | 154 | */ |
@@ -115,6 +156,7 @@ enum brcmf_vif_status { | |||
115 | BRCMF_VIF_STATUS_READY, | 156 | BRCMF_VIF_STATUS_READY, |
116 | BRCMF_VIF_STATUS_CONNECTING, | 157 | BRCMF_VIF_STATUS_CONNECTING, |
117 | BRCMF_VIF_STATUS_CONNECTED, | 158 | BRCMF_VIF_STATUS_CONNECTED, |
159 | BRCMF_VIF_STATUS_DISCONNECTING, | ||
118 | BRCMF_VIF_STATUS_AP_CREATING, | 160 | BRCMF_VIF_STATUS_AP_CREATING, |
119 | BRCMF_VIF_STATUS_AP_CREATED | 161 | BRCMF_VIF_STATUS_AP_CREATED |
120 | }; | 162 | }; |
@@ -122,16 +164,22 @@ enum brcmf_vif_status { | |||
122 | /** | 164 | /** |
123 | * struct vif_saved_ie - holds saved IEs for a virtual interface. | 165 | * struct vif_saved_ie - holds saved IEs for a virtual interface. |
124 | * | 166 | * |
167 | * @probe_req_ie: IE info for probe request. | ||
125 | * @probe_res_ie: IE info for probe response. | 168 | * @probe_res_ie: IE info for probe response. |
126 | * @beacon_ie: IE info for beacon frame. | 169 | * @beacon_ie: IE info for beacon frame. |
170 | * @probe_req_ie_len: IE info length for probe request. | ||
127 | * @probe_res_ie_len: IE info length for probe response. | 171 | * @probe_res_ie_len: IE info length for probe response. |
128 | * @beacon_ie_len: IE info length for beacon frame. | 172 | * @beacon_ie_len: IE info length for beacon frame. |
129 | */ | 173 | */ |
130 | struct vif_saved_ie { | 174 | struct vif_saved_ie { |
175 | u8 probe_req_ie[IE_MAX_LEN]; | ||
131 | u8 probe_res_ie[IE_MAX_LEN]; | 176 | u8 probe_res_ie[IE_MAX_LEN]; |
132 | u8 beacon_ie[IE_MAX_LEN]; | 177 | u8 beacon_ie[IE_MAX_LEN]; |
178 | u8 assoc_req_ie[IE_MAX_LEN]; | ||
179 | u32 probe_req_ie_len; | ||
133 | u32 probe_res_ie_len; | 180 | u32 probe_res_ie_len; |
134 | u32 beacon_ie_len; | 181 | u32 beacon_ie_len; |
182 | u32 assoc_req_ie_len; | ||
135 | }; | 183 | }; |
136 | 184 | ||
137 | /** | 185 | /** |
@@ -145,6 +193,7 @@ struct vif_saved_ie { | |||
145 | * @sme_state: SME state using enum brcmf_vif_status bits. | 193 | * @sme_state: SME state using enum brcmf_vif_status bits. |
146 | * @pm_block: power-management blocked. | 194 | * @pm_block: power-management blocked. |
147 | * @list: linked list. | 195 | * @list: linked list. |
196 | * @mgmt_rx_reg: registered rx mgmt frame types. | ||
148 | */ | 197 | */ |
149 | struct brcmf_cfg80211_vif { | 198 | struct brcmf_cfg80211_vif { |
150 | struct brcmf_if *ifp; | 199 | struct brcmf_if *ifp; |
@@ -156,6 +205,7 @@ struct brcmf_cfg80211_vif { | |||
156 | bool pm_block; | 205 | bool pm_block; |
157 | struct vif_saved_ie saved_ie; | 206 | struct vif_saved_ie saved_ie; |
158 | struct list_head list; | 207 | struct list_head list; |
208 | u16 mgmt_rx_reg; | ||
159 | }; | 209 | }; |
160 | 210 | ||
161 | /* association inform */ | 211 | /* association inform */ |
@@ -189,6 +239,9 @@ struct escan_info { | |||
189 | u8 escan_buf[WL_ESCAN_BUF_SIZE]; | 239 | u8 escan_buf[WL_ESCAN_BUF_SIZE]; |
190 | struct wiphy *wiphy; | 240 | struct wiphy *wiphy; |
191 | struct net_device *ndev; | 241 | struct net_device *ndev; |
242 | s32 (*run)(struct brcmf_cfg80211_info *cfg, | ||
243 | struct net_device *ndev, | ||
244 | struct cfg80211_scan_request *request, u16 action); | ||
192 | }; | 245 | }; |
193 | 246 | ||
194 | /** | 247 | /** |
@@ -273,10 +326,27 @@ struct brcmf_pno_scanresults_le { | |||
273 | }; | 326 | }; |
274 | 327 | ||
275 | /** | 328 | /** |
329 | * struct brcmf_cfg80211_vif_event - virtual interface event information. | ||
330 | * | ||
331 | * @vif_wq: waitqueue awaiting interface event from firmware. | ||
332 | * @vif_event_lock: protects other members in this structure. | ||
333 | * @vif_complete: completion for net attach. | ||
334 | * @action: either add, change, or delete. | ||
335 | * @vif: virtual interface object related to the event. | ||
336 | */ | ||
337 | struct brcmf_cfg80211_vif_event { | ||
338 | wait_queue_head_t vif_wq; | ||
339 | struct mutex vif_event_lock; | ||
340 | u8 action; | ||
341 | struct brcmf_cfg80211_vif *vif; | ||
342 | }; | ||
343 | |||
344 | /** | ||
276 | * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface | 345 | * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface |
277 | * | 346 | * |
278 | * @wiphy: wiphy object for cfg80211 interface. | 347 | * @wiphy: wiphy object for cfg80211 interface. |
279 | * @conf: dongle configuration. | 348 | * @conf: dongle configuration. |
349 | * @p2p: peer-to-peer specific information. | ||
280 | * @scan_request: cfg80211 scan request object. | 350 | * @scan_request: cfg80211 scan request object. |
281 | * @usr_sync: mainly for dongle up/down synchronization. | 351 | * @usr_sync: mainly for dongle up/down synchronization. |
282 | * @bss_list: bss_list holding scanned ap information. | 352 | * @bss_list: bss_list holding scanned ap information. |
@@ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le { | |||
304 | * @escan_ioctl_buf: dongle command buffer for escan commands. | 374 | * @escan_ioctl_buf: dongle command buffer for escan commands. |
305 | * @vif_list: linked list of vif instances. | 375 | * @vif_list: linked list of vif instances. |
306 | * @vif_cnt: number of vif instances. | 376 | * @vif_cnt: number of vif instances. |
377 | * @vif_event: vif event signalling. | ||
307 | */ | 378 | */ |
308 | struct brcmf_cfg80211_info { | 379 | struct brcmf_cfg80211_info { |
309 | struct wiphy *wiphy; | 380 | struct wiphy *wiphy; |
310 | struct brcmf_cfg80211_conf *conf; | 381 | struct brcmf_cfg80211_conf *conf; |
382 | struct brcmf_p2p_info p2p; | ||
311 | struct cfg80211_scan_request *scan_request; | 383 | struct cfg80211_scan_request *scan_request; |
312 | struct mutex usr_sync; | 384 | struct mutex usr_sync; |
313 | struct brcmf_scan_results *bss_list; | 385 | struct brcmf_scan_results *bss_list; |
@@ -335,6 +407,21 @@ struct brcmf_cfg80211_info { | |||
335 | u8 *escan_ioctl_buf; | 407 | u8 *escan_ioctl_buf; |
336 | struct list_head vif_list; | 408 | struct list_head vif_list; |
337 | u8 vif_cnt; | 409 | u8 vif_cnt; |
410 | struct brcmf_cfg80211_vif_event vif_event; | ||
411 | struct completion vif_disabled; | ||
412 | }; | ||
413 | |||
414 | /** | ||
415 | * struct brcmf_tlv - tag_ID/length/value_buffer tuple. | ||
416 | * | ||
417 | * @id: tag identifier. | ||
418 | * @len: number of bytes in value buffer. | ||
419 | * @data: value buffer. | ||
420 | */ | ||
421 | struct brcmf_tlv { | ||
422 | u8 id; | ||
423 | u8 len; | ||
424 | u8 data[1]; | ||
338 | }; | 425 | }; |
339 | 426 | ||
340 | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) | 427 | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) |
@@ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); | |||
389 | s32 brcmf_cfg80211_up(struct net_device *ndev); | 476 | s32 brcmf_cfg80211_up(struct net_device *ndev); |
390 | s32 brcmf_cfg80211_down(struct net_device *ndev); | 477 | s32 brcmf_cfg80211_down(struct net_device *ndev); |
391 | 478 | ||
479 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | ||
480 | enum nl80211_iftype type, | ||
481 | bool pm_block); | ||
482 | void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); | ||
483 | |||
484 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | ||
485 | const u8 *vndr_ie_buf, u32 vndr_ie_len); | ||
486 | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); | ||
487 | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); | ||
488 | u16 channel_to_chanspec(struct ieee80211_channel *ch); | ||
489 | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); | ||
490 | void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, | ||
491 | struct brcmf_cfg80211_vif *vif); | ||
492 | bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); | ||
493 | int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, | ||
494 | u8 action, ulong timeout); | ||
495 | s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||
496 | struct net_device *ndev, | ||
497 | bool aborted, bool fw_abort); | ||
498 | void brcmf_set_mpc(struct net_device *ndev, int mpc); | ||
499 | void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); | ||
500 | |||
392 | #endif /* _wl_cfg80211_h_ */ | 501 | #endif /* _wl_cfg80211_h_ */ |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index cdb62b8ccc79..10ee314c4229 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c | |||
@@ -183,8 +183,7 @@ static bool brcms_c_country_valid(const char *ccode) | |||
183 | * chars. | 183 | * chars. |
184 | */ | 184 | */ |
185 | if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && | 185 | if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && |
186 | (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A && | 186 | (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A)) |
187 | ccode[2] == '\0')) | ||
188 | return false; | 187 | return false; |
189 | 188 | ||
190 | /* | 189 | /* |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 62be5502b95d..8ef02dca8f8c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c | |||
@@ -101,8 +101,6 @@ | |||
101 | #define DOT11_RTS_LEN 16 | 101 | #define DOT11_RTS_LEN 16 |
102 | #define DOT11_CTS_LEN 10 | 102 | #define DOT11_CTS_LEN 10 |
103 | #define DOT11_BA_BITMAP_LEN 128 | 103 | #define DOT11_BA_BITMAP_LEN 128 |
104 | #define DOT11_MIN_BEACON_PERIOD 1 | ||
105 | #define DOT11_MAX_BEACON_PERIOD 0xFFFF | ||
106 | #define DOT11_MAXNUMFRAGS 16 | 104 | #define DOT11_MAXNUMFRAGS 16 |
107 | #define DOT11_MAX_FRAG_LEN 2346 | 105 | #define DOT11_MAX_FRAG_LEN 2346 |
108 | 106 | ||
@@ -3140,8 +3138,7 @@ void brcms_c_reset(struct brcms_c_info *wlc) | |||
3140 | brcms_c_statsupd(wlc); | 3138 | brcms_c_statsupd(wlc); |
3141 | 3139 | ||
3142 | /* reset our snapshot of macstat counters */ | 3140 | /* reset our snapshot of macstat counters */ |
3143 | memset((char *)wlc->core->macstat_snapshot, 0, | 3141 | memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat)); |
3144 | sizeof(struct macstat)); | ||
3145 | 3142 | ||
3146 | brcms_b_reset(wlc->hw); | 3143 | brcms_b_reset(wlc->hw); |
3147 | } | 3144 | } |
@@ -4054,7 +4051,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, | |||
4054 | return; | 4051 | return; |
4055 | } | 4052 | } |
4056 | 4053 | ||
4057 | memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); | 4054 | memset(&acp_shm, 0, sizeof(struct shm_acparams)); |
4058 | /* fill in shm ac params struct */ | 4055 | /* fill in shm ac params struct */ |
4059 | acp_shm.txop = params->txop; | 4056 | acp_shm.txop = params->txop; |
4060 | /* convert from units of 32us to us for ucode */ | 4057 | /* convert from units of 32us to us for ucode */ |
@@ -4770,7 +4767,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc) | |||
4770 | struct brcms_bss_info *bi = wlc->default_bss; | 4767 | struct brcms_bss_info *bi = wlc->default_bss; |
4771 | 4768 | ||
4772 | /* init default and target BSS with some sane initial values */ | 4769 | /* init default and target BSS with some sane initial values */ |
4773 | memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); | 4770 | memset(bi, 0, sizeof(*bi)); |
4774 | bi->beacon_period = BEACON_INTERVAL_DEFAULT; | 4771 | bi->beacon_period = BEACON_INTERVAL_DEFAULT; |
4775 | 4772 | ||
4776 | /* fill the default channel as the first valid channel | 4773 | /* fill the default channel as the first valid channel |
@@ -5299,7 +5296,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) | |||
5299 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); | 5296 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); |
5300 | 5297 | ||
5301 | /* Clear rateset override */ | 5298 | /* Clear rateset override */ |
5302 | memset(&rs, 0, sizeof(struct brcms_c_rateset)); | 5299 | memset(&rs, 0, sizeof(rs)); |
5303 | 5300 | ||
5304 | switch (gmode) { | 5301 | switch (gmode) { |
5305 | case GMODE_LEGACY_B: | 5302 | case GMODE_LEGACY_B: |
@@ -5522,7 +5519,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) | |||
5522 | if (rs->count > BRCMS_NUMRATES) | 5519 | if (rs->count > BRCMS_NUMRATES) |
5523 | return -ENOBUFS; | 5520 | return -ENOBUFS; |
5524 | 5521 | ||
5525 | memset(&internal_rs, 0, sizeof(struct brcms_c_rateset)); | 5522 | memset(&internal_rs, 0, sizeof(internal_rs)); |
5526 | 5523 | ||
5527 | /* Copy only legacy rateset section */ | 5524 | /* Copy only legacy rateset section */ |
5528 | internal_rs.count = rs->count; | 5525 | internal_rs.count = rs->count; |
@@ -5548,8 +5545,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) | |||
5548 | 5545 | ||
5549 | int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) | 5546 | int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) |
5550 | { | 5547 | { |
5551 | if (period < DOT11_MIN_BEACON_PERIOD || | 5548 | if (period == 0) |
5552 | period > DOT11_MAX_BEACON_PERIOD) | ||
5553 | return -EINVAL; | 5549 | return -EINVAL; |
5554 | 5550 | ||
5555 | wlc->default_bss->beacon_period = period; | 5551 | wlc->default_bss->beacon_period = period; |
@@ -5626,7 +5622,7 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, | |||
5626 | for (i = 0; i < BRCMS_MAXMODULES; i++) { | 5622 | for (i = 0; i < BRCMS_MAXMODULES; i++) { |
5627 | if (!strcmp(wlc->modulecb[i].name, name) && | 5623 | if (!strcmp(wlc->modulecb[i].name, name) && |
5628 | (wlc->modulecb[i].hdl == hdl)) { | 5624 | (wlc->modulecb[i].hdl == hdl)) { |
5629 | memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); | 5625 | memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i])); |
5630 | return 0; | 5626 | return 0; |
5631 | } | 5627 | } |
5632 | } | 5628 | } |
@@ -6446,10 +6442,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |||
6446 | 6442 | ||
6447 | if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) | 6443 | if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) |
6448 | && (!is_mcs_rate(rspec[k]))) { | 6444 | && (!is_mcs_rate(rspec[k]))) { |
6449 | brcms_err(wlc->hw->d11core, | 6445 | brcms_warn(wlc->hw->d11core, |
6450 | "wl%d: %s: IEEE80211_TX_" | 6446 | "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n", |
6451 | "RC_MCS != is_mcs_rate(rspec)\n", | 6447 | wlc->pub->unit, __func__); |
6452 | wlc->pub->unit, __func__); | ||
6453 | } | 6448 | } |
6454 | 6449 | ||
6455 | if (is_mcs_rate(rspec[k])) { | 6450 | if (is_mcs_rate(rspec[k])) { |
@@ -6682,11 +6677,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |||
6682 | (struct ofdm_phy_hdr *) rts_plcp) : | 6677 | (struct ofdm_phy_hdr *) rts_plcp) : |
6683 | rts_plcp[0]) << 8; | 6678 | rts_plcp[0]) << 8; |
6684 | } else { | 6679 | } else { |
6685 | memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); | 6680 | memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); |
6686 | memset((char *)&txh->rts_frame, 0, | 6681 | memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts)); |
6687 | sizeof(struct ieee80211_rts)); | 6682 | memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback)); |
6688 | memset((char *)txh->RTSPLCPFallback, 0, | ||
6689 | sizeof(txh->RTSPLCPFallback)); | ||
6690 | txh->RTSDurFallback = 0; | 6683 | txh->RTSDurFallback = 0; |
6691 | } | 6684 | } |
6692 | 6685 | ||
@@ -6841,21 +6834,19 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |||
6841 | wlc->fragthresh[queue] = | 6834 | wlc->fragthresh[queue] = |
6842 | (u16) newfragthresh; | 6835 | (u16) newfragthresh; |
6843 | } else { | 6836 | } else { |
6844 | brcms_err(wlc->hw->d11core, | 6837 | brcms_warn(wlc->hw->d11core, |
6845 | "wl%d: %s txop invalid " | 6838 | "wl%d: %s txop invalid for rate %d\n", |
6846 | "for rate %d\n", | 6839 | wlc->pub->unit, fifo_names[queue], |
6847 | wlc->pub->unit, fifo_names[queue], | 6840 | rspec2rate(rspec[0])); |
6848 | rspec2rate(rspec[0])); | ||
6849 | } | 6841 | } |
6850 | 6842 | ||
6851 | if (dur > wlc->edcf_txop[ac]) | 6843 | if (dur > wlc->edcf_txop[ac]) |
6852 | brcms_err(wlc->hw->d11core, | 6844 | brcms_warn(wlc->hw->d11core, |
6853 | "wl%d: %s: %s txop " | 6845 | "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", |
6854 | "exceeded phylen %d/%d dur %d/%d\n", | 6846 | wlc->pub->unit, __func__, |
6855 | wlc->pub->unit, __func__, | 6847 | fifo_names[queue], |
6856 | fifo_names[queue], | 6848 | phylen, wlc->fragthresh[queue], |
6857 | phylen, wlc->fragthresh[queue], | 6849 | dur, wlc->edcf_txop[ac]); |
6858 | dur, wlc->edcf_txop[ac]); | ||
6859 | } | 6850 | } |
6860 | } | 6851 | } |
6861 | 6852 | ||
@@ -7330,7 +7321,7 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, | |||
7330 | *len = hdr_len + body_len; | 7321 | *len = hdr_len + body_len; |
7331 | 7322 | ||
7332 | /* format PHY and MAC headers */ | 7323 | /* format PHY and MAC headers */ |
7333 | memset((char *)buf, 0, hdr_len); | 7324 | memset(buf, 0, hdr_len); |
7334 | 7325 | ||
7335 | plcp = (struct cck_phy_hdr *) buf; | 7326 | plcp = (struct cck_phy_hdr *) buf; |
7336 | 7327 | ||
@@ -7401,9 +7392,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, | |||
7401 | struct brcms_bss_cfg *cfg, | 7392 | struct brcms_bss_cfg *cfg, |
7402 | bool suspend) | 7393 | bool suspend) |
7403 | { | 7394 | { |
7404 | u16 prb_resp[BCN_TMPL_LEN / 2]; | 7395 | u16 *prb_resp; |
7405 | int len = BCN_TMPL_LEN; | 7396 | int len = BCN_TMPL_LEN; |
7406 | 7397 | ||
7398 | prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC); | ||
7399 | if (!prb_resp) | ||
7400 | return; | ||
7401 | |||
7407 | /* | 7402 | /* |
7408 | * write the probe response to hardware, or save in | 7403 | * write the probe response to hardware, or save in |
7409 | * the config structure | 7404 | * the config structure |
@@ -7437,6 +7432,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, | |||
7437 | 7432 | ||
7438 | if (suspend) | 7433 | if (suspend) |
7439 | brcms_c_enable_mac(wlc); | 7434 | brcms_c_enable_mac(wlc); |
7435 | |||
7436 | kfree(prb_resp); | ||
7440 | } | 7437 | } |
7441 | 7438 | ||
7442 | void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) | 7439 | void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) |
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 83856d1a6101..3630a41df50d 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c | |||
@@ -572,26 +572,11 @@ il3945_tx_skb(struct il_priv *il, | |||
572 | il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id); | 572 | il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id); |
573 | 573 | ||
574 | /* Total # bytes to be transmitted */ | 574 | /* Total # bytes to be transmitted */ |
575 | len = (u16) skb->len; | 575 | tx_cmd->len = cpu_to_le16((u16) skb->len); |
576 | tx_cmd->len = cpu_to_le16(len); | ||
577 | 576 | ||
578 | il_update_stats(il, true, fc, len); | ||
579 | tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; | 577 | tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; |
580 | tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; | 578 | tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; |
581 | 579 | ||
582 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||
583 | txq->need_update = 1; | ||
584 | } else { | ||
585 | wait_write_ptr = 1; | ||
586 | txq->need_update = 0; | ||
587 | } | ||
588 | |||
589 | D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); | ||
590 | D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | ||
591 | il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd)); | ||
592 | il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr, | ||
593 | ieee80211_hdrlen(fc)); | ||
594 | |||
595 | /* | 580 | /* |
596 | * Use the first empty entry in this queue's command buffer array | 581 | * Use the first empty entry in this queue's command buffer array |
597 | * to contain the Tx command and MAC header concatenated together | 582 | * to contain the Tx command and MAC header concatenated together |
@@ -610,14 +595,8 @@ il3945_tx_skb(struct il_priv *il, | |||
610 | * within command buffer array. */ | 595 | * within command buffer array. */ |
611 | txcmd_phys = | 596 | txcmd_phys = |
612 | pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); | 597 | pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); |
613 | /* we do not map meta data ... so we can safely access address to | 598 | if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) |
614 | * provide to unmap command*/ | 599 | goto drop_unlock; |
615 | dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | ||
616 | dma_unmap_len_set(out_meta, len, len); | ||
617 | |||
618 | /* Add buffer containing Tx command and MAC(!) header to TFD's | ||
619 | * first entry */ | ||
620 | il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); | ||
621 | 600 | ||
622 | /* Set up TFD's 2nd entry to point directly to remainder of skb, | 601 | /* Set up TFD's 2nd entry to point directly to remainder of skb, |
623 | * if any (802.11 null frames have no payload). */ | 602 | * if any (802.11 null frames have no payload). */ |
@@ -626,10 +605,34 @@ il3945_tx_skb(struct il_priv *il, | |||
626 | phys_addr = | 605 | phys_addr = |
627 | pci_map_single(il->pci_dev, skb->data + hdr_len, len, | 606 | pci_map_single(il->pci_dev, skb->data + hdr_len, len, |
628 | PCI_DMA_TODEVICE); | 607 | PCI_DMA_TODEVICE); |
608 | if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) | ||
609 | goto drop_unlock; | ||
610 | } | ||
611 | |||
612 | /* Add buffer containing Tx command and MAC(!) header to TFD's | ||
613 | * first entry */ | ||
614 | il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); | ||
615 | dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | ||
616 | dma_unmap_len_set(out_meta, len, len); | ||
617 | if (len) | ||
629 | il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, | 618 | il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, |
630 | U32_PAD(len)); | 619 | U32_PAD(len)); |
620 | |||
621 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||
622 | txq->need_update = 1; | ||
623 | } else { | ||
624 | wait_write_ptr = 1; | ||
625 | txq->need_update = 0; | ||
631 | } | 626 | } |
632 | 627 | ||
628 | il_update_stats(il, true, fc, skb->len); | ||
629 | |||
630 | D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); | ||
631 | D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | ||
632 | il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd)); | ||
633 | il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr, | ||
634 | ieee80211_hdrlen(fc)); | ||
635 | |||
633 | /* Tell device the write idx *just past* this latest filled TFD */ | 636 | /* Tell device the write idx *just past* this latest filled TFD */ |
634 | q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); | 637 | q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); |
635 | il_txq_update_write_ptr(il, txq); | 638 | il_txq_update_write_ptr(il, txq); |
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 9741ac10a334..7941eb3a0166 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c | |||
@@ -1793,8 +1793,7 @@ il4965_tx_skb(struct il_priv *il, | |||
1793 | memcpy(tx_cmd->hdr, hdr, hdr_len); | 1793 | memcpy(tx_cmd->hdr, hdr, hdr_len); |
1794 | 1794 | ||
1795 | /* Total # bytes to be transmitted */ | 1795 | /* Total # bytes to be transmitted */ |
1796 | len = (u16) skb->len; | 1796 | tx_cmd->len = cpu_to_le16((u16) skb->len); |
1797 | tx_cmd->len = cpu_to_le16(len); | ||
1798 | 1797 | ||
1799 | if (info->control.hw_key) | 1798 | if (info->control.hw_key) |
1800 | il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id); | 1799 | il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id); |
@@ -1804,7 +1803,6 @@ il4965_tx_skb(struct il_priv *il, | |||
1804 | 1803 | ||
1805 | il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc); | 1804 | il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc); |
1806 | 1805 | ||
1807 | il_update_stats(il, true, fc, len); | ||
1808 | /* | 1806 | /* |
1809 | * Use the first empty entry in this queue's command buffer array | 1807 | * Use the first empty entry in this queue's command buffer array |
1810 | * to contain the Tx command and MAC header concatenated together | 1808 | * to contain the Tx command and MAC header concatenated together |
@@ -1826,18 +1824,8 @@ il4965_tx_skb(struct il_priv *il, | |||
1826 | txcmd_phys = | 1824 | txcmd_phys = |
1827 | pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, | 1825 | pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, |
1828 | PCI_DMA_BIDIRECTIONAL); | 1826 | PCI_DMA_BIDIRECTIONAL); |
1829 | dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | 1827 | if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) |
1830 | dma_unmap_len_set(out_meta, len, firstlen); | 1828 | goto drop_unlock; |
1831 | /* Add buffer containing Tx command and MAC(!) header to TFD's | ||
1832 | * first entry */ | ||
1833 | il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0); | ||
1834 | |||
1835 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||
1836 | txq->need_update = 1; | ||
1837 | } else { | ||
1838 | wait_write_ptr = 1; | ||
1839 | txq->need_update = 0; | ||
1840 | } | ||
1841 | 1829 | ||
1842 | /* Set up TFD's 2nd entry to point directly to remainder of skb, | 1830 | /* Set up TFD's 2nd entry to point directly to remainder of skb, |
1843 | * if any (802.11 null frames have no payload). */ | 1831 | * if any (802.11 null frames have no payload). */ |
@@ -1846,8 +1834,24 @@ il4965_tx_skb(struct il_priv *il, | |||
1846 | phys_addr = | 1834 | phys_addr = |
1847 | pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, | 1835 | pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, |
1848 | PCI_DMA_TODEVICE); | 1836 | PCI_DMA_TODEVICE); |
1837 | if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) | ||
1838 | goto drop_unlock; | ||
1839 | } | ||
1840 | |||
1841 | /* Add buffer containing Tx command and MAC(!) header to TFD's | ||
1842 | * first entry */ | ||
1843 | il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0); | ||
1844 | dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | ||
1845 | dma_unmap_len_set(out_meta, len, firstlen); | ||
1846 | if (secondlen) | ||
1849 | il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, | 1847 | il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, |
1850 | 0, 0); | 1848 | 0, 0); |
1849 | |||
1850 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||
1851 | txq->need_update = 1; | ||
1852 | } else { | ||
1853 | wait_write_ptr = 1; | ||
1854 | txq->need_update = 0; | ||
1851 | } | 1855 | } |
1852 | 1856 | ||
1853 | scratch_phys = | 1857 | scratch_phys = |
@@ -1860,6 +1864,8 @@ il4965_tx_skb(struct il_priv *il, | |||
1860 | tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); | 1864 | tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); |
1861 | tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); | 1865 | tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); |
1862 | 1866 | ||
1867 | il_update_stats(il, true, fc, skb->len); | ||
1868 | |||
1863 | D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); | 1869 | D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); |
1864 | D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | 1870 | D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); |
1865 | il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd)); | 1871 | il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd)); |
@@ -5733,7 +5739,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) | |||
5733 | /* Tell mac80211 our characteristics */ | 5739 | /* Tell mac80211 our characteristics */ |
5734 | hw->flags = | 5740 | hw->flags = |
5735 | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | | 5741 | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | |
5736 | IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT | | 5742 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT | |
5737 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | | 5743 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | |
5738 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | 5744 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; |
5739 | if (il->cfg->sku & IL_SKU_N) | 5745 | if (il->cfg->sku & IL_SKU_N) |
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index f3b8e91aa3dc..e8324b5e5bfe 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c | |||
@@ -1183,8 +1183,7 @@ il4965_rs_switch_to_mimo2(struct il_priv *il, struct il_lq_sta *lq_sta, | |||
1183 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 1183 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) |
1184 | return -1; | 1184 | return -1; |
1185 | 1185 | ||
1186 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == | 1186 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
1187 | WLAN_HT_CAP_SM_PS_STATIC) | ||
1188 | return -1; | 1187 | return -1; |
1189 | 1188 | ||
1190 | /* Need both Tx chains/antennas to support MIMO */ | 1189 | /* Need both Tx chains/antennas to support MIMO */ |
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 1f598604a79c..e006ea831320 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
@@ -1830,32 +1830,30 @@ il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta) | |||
1830 | { | 1830 | { |
1831 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | 1831 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; |
1832 | __le32 sta_flags; | 1832 | __le32 sta_flags; |
1833 | u8 mimo_ps_mode; | ||
1834 | 1833 | ||
1835 | if (!sta || !sta_ht_inf->ht_supported) | 1834 | if (!sta || !sta_ht_inf->ht_supported) |
1836 | goto done; | 1835 | goto done; |
1837 | 1836 | ||
1838 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; | ||
1839 | D_ASSOC("spatial multiplexing power save mode: %s\n", | 1837 | D_ASSOC("spatial multiplexing power save mode: %s\n", |
1840 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" : | 1838 | (sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" : |
1841 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? "dynamic" : | 1839 | (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" : |
1842 | "disabled"); | 1840 | "disabled"); |
1843 | 1841 | ||
1844 | sta_flags = il->stations[idx].sta.station_flags; | 1842 | sta_flags = il->stations[idx].sta.station_flags; |
1845 | 1843 | ||
1846 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | 1844 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); |
1847 | 1845 | ||
1848 | switch (mimo_ps_mode) { | 1846 | switch (sta->smps_mode) { |
1849 | case WLAN_HT_CAP_SM_PS_STATIC: | 1847 | case IEEE80211_SMPS_STATIC: |
1850 | sta_flags |= STA_FLG_MIMO_DIS_MSK; | 1848 | sta_flags |= STA_FLG_MIMO_DIS_MSK; |
1851 | break; | 1849 | break; |
1852 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | 1850 | case IEEE80211_SMPS_DYNAMIC: |
1853 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 1851 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; |
1854 | break; | 1852 | break; |
1855 | case WLAN_HT_CAP_SM_PS_DISABLED: | 1853 | case IEEE80211_SMPS_OFF: |
1856 | break; | 1854 | break; |
1857 | default: | 1855 | default: |
1858 | IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode); | 1856 | IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode); |
1859 | break; | 1857 | break; |
1860 | } | 1858 | } |
1861 | 1859 | ||
@@ -3162,18 +3160,23 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) | |||
3162 | idx, il->cmd_queue); | 3160 | idx, il->cmd_queue); |
3163 | } | 3161 | } |
3164 | #endif | 3162 | #endif |
3165 | txq->need_update = 1; | ||
3166 | |||
3167 | if (il->ops->txq_update_byte_cnt_tbl) | ||
3168 | /* Set up entry in queue's byte count circular buffer */ | ||
3169 | il->ops->txq_update_byte_cnt_tbl(il, txq, 0); | ||
3170 | 3163 | ||
3171 | phys_addr = | 3164 | phys_addr = |
3172 | pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, | 3165 | pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, |
3173 | PCI_DMA_BIDIRECTIONAL); | 3166 | PCI_DMA_BIDIRECTIONAL); |
3167 | if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) { | ||
3168 | idx = -ENOMEM; | ||
3169 | goto out; | ||
3170 | } | ||
3174 | dma_unmap_addr_set(out_meta, mapping, phys_addr); | 3171 | dma_unmap_addr_set(out_meta, mapping, phys_addr); |
3175 | dma_unmap_len_set(out_meta, len, fix_size); | 3172 | dma_unmap_len_set(out_meta, len, fix_size); |
3176 | 3173 | ||
3174 | txq->need_update = 1; | ||
3175 | |||
3176 | if (il->ops->txq_update_byte_cnt_tbl) | ||
3177 | /* Set up entry in queue's byte count circular buffer */ | ||
3178 | il->ops->txq_update_byte_cnt_tbl(il, txq, 0); | ||
3179 | |||
3177 | il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1, | 3180 | il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1, |
3178 | U32_PAD(cmd->len)); | 3181 | U32_PAD(cmd->len)); |
3179 | 3182 | ||
@@ -3181,6 +3184,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) | |||
3181 | q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); | 3184 | q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); |
3182 | il_txq_update_write_ptr(il, txq); | 3185 | il_txq_update_write_ptr(il, txq); |
3183 | 3186 | ||
3187 | out: | ||
3184 | spin_unlock_irqrestore(&il->hcmd_lock, flags); | 3188 | spin_unlock_irqrestore(&il->hcmd_lock, flags); |
3185 | return idx; | 3189 | return idx; |
3186 | } | 3190 | } |
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index f41ae79e6bc0..41ec27cb6efe 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
@@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | |||
338 | 338 | ||
339 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 339 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
340 | struct iwl_rxon_context *ctx, | 340 | struct iwl_rxon_context *ctx, |
341 | struct ieee80211_sta_ht_cap *ht_cap); | 341 | struct ieee80211_sta *sta); |
342 | 342 | ||
343 | static inline int iwl_sta_id(struct ieee80211_sta *sta) | 343 | static inline int iwl_sta_id(struct ieee80211_sta *sta) |
344 | { | 344 | { |
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 8bce4b0148e0..02c9ebb3b340 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
@@ -3897,6 +3897,24 @@ struct iwlagn_wowlan_kek_kck_material_cmd { | |||
3897 | __le64 replay_ctr; | 3897 | __le64 replay_ctr; |
3898 | } __packed; | 3898 | } __packed; |
3899 | 3899 | ||
3900 | #define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 | ||
3901 | |||
3902 | /* | ||
3903 | * REPLY_WOWLAN_GET_STATUS = 0xe5 | ||
3904 | */ | ||
3905 | struct iwlagn_wowlan_status { | ||
3906 | __le64 replay_ctr; | ||
3907 | __le32 rekey_status; | ||
3908 | __le32 wakeup_reason; | ||
3909 | u8 pattern_number; | ||
3910 | u8 reserved1; | ||
3911 | __le16 qos_seq_ctr[8]; | ||
3912 | __le16 non_qos_seq_ctr; | ||
3913 | __le16 reserved2; | ||
3914 | union iwlagn_all_tsc_rsc tsc_rsc; | ||
3915 | __le16 reserved3; | ||
3916 | } __packed; | ||
3917 | |||
3900 | /* | 3918 | /* |
3901 | * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) | 3919 | * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) |
3902 | */ | 3920 | */ |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index c2f03ecd4bf8..323e4a33fcac 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -145,14 +145,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, | |||
145 | /* Tell mac80211 our characteristics */ | 145 | /* Tell mac80211 our characteristics */ |
146 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 146 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
147 | IEEE80211_HW_AMPDU_AGGREGATION | | 147 | IEEE80211_HW_AMPDU_AGGREGATION | |
148 | IEEE80211_HW_NEED_DTIM_PERIOD | | 148 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | |
149 | IEEE80211_HW_SPECTRUM_MGMT | | 149 | IEEE80211_HW_SPECTRUM_MGMT | |
150 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 150 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
151 | IEEE80211_HW_QUEUE_CONTROL | | 151 | IEEE80211_HW_QUEUE_CONTROL | |
152 | IEEE80211_HW_SUPPORTS_PS | | 152 | IEEE80211_HW_SUPPORTS_PS | |
153 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 153 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | |
154 | IEEE80211_HW_WANT_MONITOR_VIF | | 154 | IEEE80211_HW_WANT_MONITOR_VIF; |
155 | IEEE80211_HW_SCAN_WHILE_IDLE; | ||
156 | 155 | ||
157 | hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; | 156 | hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; |
158 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT; | 157 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT; |
@@ -442,52 +441,154 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, | |||
442 | return ret; | 441 | return ret; |
443 | } | 442 | } |
444 | 443 | ||
444 | struct iwl_resume_data { | ||
445 | struct iwl_priv *priv; | ||
446 | struct iwlagn_wowlan_status *cmd; | ||
447 | bool valid; | ||
448 | }; | ||
449 | |||
450 | static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait, | ||
451 | struct iwl_rx_packet *pkt, void *data) | ||
452 | { | ||
453 | struct iwl_resume_data *resume_data = data; | ||
454 | struct iwl_priv *priv = resume_data->priv; | ||
455 | u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
456 | |||
457 | if (len - 4 != sizeof(*resume_data->cmd)) { | ||
458 | IWL_ERR(priv, "rx wrong size data\n"); | ||
459 | return true; | ||
460 | } | ||
461 | memcpy(resume_data->cmd, pkt->data, sizeof(*resume_data->cmd)); | ||
462 | resume_data->valid = true; | ||
463 | |||
464 | return true; | ||
465 | } | ||
466 | |||
445 | static int iwlagn_mac_resume(struct ieee80211_hw *hw) | 467 | static int iwlagn_mac_resume(struct ieee80211_hw *hw) |
446 | { | 468 | { |
447 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 469 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
448 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | 470 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; |
449 | struct ieee80211_vif *vif; | 471 | struct ieee80211_vif *vif; |
450 | unsigned long flags; | 472 | u32 base; |
451 | u32 base, status = 0xffffffff; | 473 | int ret; |
452 | int ret = -EIO; | 474 | enum iwl_d3_status d3_status; |
475 | struct error_table_start { | ||
476 | /* cf. struct iwl_error_event_table */ | ||
477 | u32 valid; | ||
478 | u32 error_id; | ||
479 | } err_info; | ||
480 | struct iwl_notification_wait status_wait; | ||
481 | static const u8 status_cmd[] = { | ||
482 | REPLY_WOWLAN_GET_STATUS, | ||
483 | }; | ||
484 | struct iwlagn_wowlan_status status_data = {}; | ||
485 | struct iwl_resume_data resume_data = { | ||
486 | .priv = priv, | ||
487 | .cmd = &status_data, | ||
488 | .valid = false, | ||
489 | }; | ||
490 | struct cfg80211_wowlan_wakeup wakeup = { | ||
491 | .pattern_idx = -1, | ||
492 | }; | ||
493 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
494 | const struct fw_img *img; | ||
495 | #endif | ||
453 | 496 | ||
454 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 497 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
455 | mutex_lock(&priv->mutex); | 498 | mutex_lock(&priv->mutex); |
456 | 499 | ||
457 | iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, | 500 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ |
458 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | 501 | vif = ctx->vif; |
502 | |||
503 | ret = iwl_trans_d3_resume(priv->trans, &d3_status); | ||
504 | if (ret) | ||
505 | goto out_unlock; | ||
506 | |||
507 | if (d3_status != IWL_D3_STATUS_ALIVE) { | ||
508 | IWL_INFO(priv, "Device was reset during suspend\n"); | ||
509 | goto out_unlock; | ||
510 | } | ||
459 | 511 | ||
460 | base = priv->device_pointers.error_event_table; | 512 | base = priv->device_pointers.error_event_table; |
461 | if (iwlagn_hw_valid_rtc_data_addr(base)) { | 513 | if (!iwlagn_hw_valid_rtc_data_addr(base)) { |
462 | if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) { | 514 | IWL_WARN(priv, "Invalid error table during resume!\n"); |
463 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); | 515 | goto out_unlock; |
464 | status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); | 516 | } |
465 | iwl_trans_release_nic_access(priv->trans, &flags); | 517 | |
466 | ret = 0; | 518 | iwl_trans_read_mem_bytes(priv->trans, base, |
519 | &err_info, sizeof(err_info)); | ||
520 | |||
521 | if (err_info.valid) { | ||
522 | IWL_INFO(priv, "error table is valid (%d, 0x%x)\n", | ||
523 | err_info.valid, err_info.error_id); | ||
524 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||
525 | wakeup.rfkill_release = true; | ||
526 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||
527 | GFP_KERNEL); | ||
467 | } | 528 | } |
529 | goto out_unlock; | ||
530 | } | ||
468 | 531 | ||
469 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 532 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
470 | if (ret == 0) { | 533 | img = &priv->fw->img[IWL_UCODE_WOWLAN]; |
471 | const struct fw_img *img; | 534 | if (!priv->wowlan_sram) |
472 | 535 | priv->wowlan_sram = | |
473 | img = &(priv->fw->img[IWL_UCODE_WOWLAN]); | 536 | kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, |
474 | if (!priv->wowlan_sram) { | 537 | GFP_KERNEL); |
475 | priv->wowlan_sram = | 538 | |
476 | kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, | 539 | if (priv->wowlan_sram) |
477 | GFP_KERNEL); | 540 | iwl_trans_read_mem(priv->trans, 0x800000, |
478 | } | 541 | priv->wowlan_sram, |
542 | img->sec[IWL_UCODE_SECTION_DATA].len / 4); | ||
543 | #endif | ||
479 | 544 | ||
480 | if (priv->wowlan_sram) | 545 | /* |
481 | iwl_trans_read_mem( | 546 | * This is very strange. The GET_STATUS command is sent but the device |
482 | priv->trans, 0x800000, | 547 | * doesn't reply properly, it seems it doesn't close the RBD so one is |
483 | priv->wowlan_sram, | 548 | * always left open ... As a result, we need to send another command |
484 | img->sec[IWL_UCODE_SECTION_DATA].len / 4); | 549 | * and have to reset the driver afterwards. As we need to switch to |
550 | * runtime firmware again that'll happen. | ||
551 | */ | ||
552 | |||
553 | iwl_init_notification_wait(&priv->notif_wait, &status_wait, status_cmd, | ||
554 | ARRAY_SIZE(status_cmd), iwl_resume_status_fn, | ||
555 | &resume_data); | ||
556 | |||
557 | iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL); | ||
558 | iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL); | ||
559 | /* an RBD is left open in the firmware now! */ | ||
560 | |||
561 | ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5); | ||
562 | if (ret) | ||
563 | goto out_unlock; | ||
564 | |||
565 | if (resume_data.valid && priv->contexts[IWL_RXON_CTX_BSS].vif) { | ||
566 | u32 reasons = le32_to_cpu(status_data.wakeup_reason); | ||
567 | struct cfg80211_wowlan_wakeup *wakeup_report; | ||
568 | |||
569 | IWL_INFO(priv, "WoWLAN wakeup reason(s): 0x%.8x\n", reasons); | ||
570 | |||
571 | if (reasons) { | ||
572 | if (reasons & IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET) | ||
573 | wakeup.magic_pkt = true; | ||
574 | if (reasons & IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH) | ||
575 | wakeup.pattern_idx = status_data.pattern_number; | ||
576 | if (reasons & (IWLAGN_WOWLAN_WAKEUP_BEACON_MISS | | ||
577 | IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE)) | ||
578 | wakeup.disconnect = true; | ||
579 | if (reasons & IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL) | ||
580 | wakeup.gtk_rekey_failure = true; | ||
581 | if (reasons & IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ) | ||
582 | wakeup.eap_identity_req = true; | ||
583 | if (reasons & IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE) | ||
584 | wakeup.four_way_handshake = true; | ||
585 | wakeup_report = &wakeup; | ||
586 | } else { | ||
587 | wakeup_report = NULL; | ||
485 | } | 588 | } |
486 | #endif | ||
487 | } | ||
488 | 589 | ||
489 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ | 590 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); |
490 | vif = ctx->vif; | 591 | } |
491 | 592 | ||
492 | priv->wowlan = false; | 593 | priv->wowlan = false; |
493 | 594 | ||
@@ -497,6 +598,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
497 | iwl_connection_init_rx_config(priv, ctx); | 598 | iwl_connection_init_rx_config(priv, ctx); |
498 | iwlagn_set_rxon_chain(priv, ctx); | 599 | iwlagn_set_rxon_chain(priv, ctx); |
499 | 600 | ||
601 | out_unlock: | ||
500 | mutex_unlock(&priv->mutex); | 602 | mutex_unlock(&priv->mutex); |
501 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 603 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
502 | 604 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index a131227c49e9..abe304267261 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
@@ -1289,8 +1289,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
1289 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 1289 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) |
1290 | return -1; | 1290 | return -1; |
1291 | 1291 | ||
1292 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1292 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
1293 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
1294 | return -1; | 1293 | return -1; |
1295 | 1294 | ||
1296 | /* Need both Tx chains/antennas to support MIMO */ | 1295 | /* Need both Tx chains/antennas to support MIMO */ |
@@ -1305,7 +1304,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
1305 | tbl->max_search = IWL_MAX_SEARCH; | 1304 | tbl->max_search = IWL_MAX_SEARCH; |
1306 | rate_mask = lq_sta->active_mimo2_rate; | 1305 | rate_mask = lq_sta->active_mimo2_rate; |
1307 | 1306 | ||
1308 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1307 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
1309 | tbl->is_ht40 = 1; | 1308 | tbl->is_ht40 = 1; |
1310 | else | 1309 | else |
1311 | tbl->is_ht40 = 0; | 1310 | tbl->is_ht40 = 0; |
@@ -1345,8 +1344,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | |||
1345 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 1344 | if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) |
1346 | return -1; | 1345 | return -1; |
1347 | 1346 | ||
1348 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1347 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
1349 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
1350 | return -1; | 1348 | return -1; |
1351 | 1349 | ||
1352 | /* Need both Tx chains/antennas to support MIMO */ | 1350 | /* Need both Tx chains/antennas to support MIMO */ |
@@ -1361,7 +1359,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | |||
1361 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1359 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
1362 | rate_mask = lq_sta->active_mimo3_rate; | 1360 | rate_mask = lq_sta->active_mimo3_rate; |
1363 | 1361 | ||
1364 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1362 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
1365 | tbl->is_ht40 = 1; | 1363 | tbl->is_ht40 = 1; |
1366 | else | 1364 | else |
1367 | tbl->is_ht40 = 0; | 1365 | tbl->is_ht40 = 0; |
@@ -1410,7 +1408,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, | |||
1410 | tbl->max_search = IWL_MAX_SEARCH; | 1408 | tbl->max_search = IWL_MAX_SEARCH; |
1411 | rate_mask = lq_sta->active_siso_rate; | 1409 | rate_mask = lq_sta->active_siso_rate; |
1412 | 1410 | ||
1413 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1411 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
1414 | tbl->is_ht40 = 1; | 1412 | tbl->is_ht40 = 1; |
1415 | else | 1413 | else |
1416 | tbl->is_ht40 = 0; | 1414 | tbl->is_ht40 = 0; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index e8d5b90abf5c..a4eed2055fdb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c | |||
@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
790 | 790 | ||
791 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 791 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
792 | 792 | ||
793 | ieee80211_rx(priv->hw, skb); | 793 | ieee80211_rx_ni(priv->hw, skb); |
794 | } | 794 | } |
795 | 795 | ||
796 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | 796 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 9fabd26997ca..23be948cf162 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c | |||
@@ -1545,10 +1545,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | |||
1545 | bss_conf->bssid); | 1545 | bss_conf->bssid); |
1546 | } | 1546 | } |
1547 | 1547 | ||
1548 | if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC && | 1548 | if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) { |
1549 | priv->beacon_ctx) { | ||
1550 | if (iwlagn_update_beacon(priv, vif)) | 1549 | if (iwlagn_update_beacon(priv, vif)) |
1551 | IWL_ERR(priv, "Error sending IBSS beacon\n"); | 1550 | IWL_ERR(priv, "Error updating beacon\n"); |
1552 | } | 1551 | } |
1553 | 1552 | ||
1554 | mutex_unlock(&priv->mutex); | 1553 | mutex_unlock(&priv->mutex); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index ab768045696b..94ef33838bc6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -77,7 +77,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | 77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", |
78 | sta_id); | 78 | sta_id); |
79 | 79 | ||
80 | spin_lock(&priv->sta_lock); | 80 | spin_lock_bh(&priv->sta_lock); |
81 | 81 | ||
82 | switch (add_sta_resp->status) { | 82 | switch (add_sta_resp->status) { |
83 | case ADD_STA_SUCCESS_MSK: | 83 | case ADD_STA_SUCCESS_MSK: |
@@ -119,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
119 | priv->stations[sta_id].sta.mode == | 119 | priv->stations[sta_id].sta.mode == |
120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", |
121 | addsta->sta.addr); | 121 | addsta->sta.addr); |
122 | spin_unlock(&priv->sta_lock); | 122 | spin_unlock_bh(&priv->sta_lock); |
123 | 123 | ||
124 | return ret; | 124 | return ret; |
125 | } | 125 | } |
@@ -173,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
173 | 173 | ||
174 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 174 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
175 | struct iwl_rxon_context *ctx, | 175 | struct iwl_rxon_context *ctx, |
176 | struct ieee80211_sta_ht_cap *ht_cap) | 176 | struct ieee80211_sta *sta) |
177 | { | 177 | { |
178 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | 178 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) |
179 | return false; | 179 | return false; |
@@ -183,20 +183,11 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | |||
183 | return false; | 183 | return false; |
184 | #endif | 184 | #endif |
185 | 185 | ||
186 | /* | 186 | /* special case for RXON */ |
187 | * Remainder of this function checks ht_cap, but if it's | 187 | if (!sta) |
188 | * NULL then we can do HT40 (special case for RXON) | ||
189 | */ | ||
190 | if (!ht_cap) | ||
191 | return true; | 188 | return true; |
192 | 189 | ||
193 | if (!ht_cap->ht_supported) | 190 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
194 | return false; | ||
195 | |||
196 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
197 | return false; | ||
198 | |||
199 | return true; | ||
200 | } | 191 | } |
201 | 192 | ||
202 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | 193 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, |
@@ -205,7 +196,6 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
205 | __le32 *flags, __le32 *mask) | 196 | __le32 *flags, __le32 *mask) |
206 | { | 197 | { |
207 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | 198 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; |
208 | u8 mimo_ps_mode; | ||
209 | 199 | ||
210 | *mask = STA_FLG_RTS_MIMO_PROT_MSK | | 200 | *mask = STA_FLG_RTS_MIMO_PROT_MSK | |
211 | STA_FLG_MIMO_DIS_MSK | | 201 | STA_FLG_MIMO_DIS_MSK | |
@@ -217,26 +207,24 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
217 | if (!sta || !sta_ht_inf->ht_supported) | 207 | if (!sta || !sta_ht_inf->ht_supported) |
218 | return; | 208 | return; |
219 | 209 | ||
220 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; | ||
221 | |||
222 | IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", | 210 | IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", |
223 | sta->addr, | 211 | sta->addr, |
224 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? | 212 | (sta->smps_mode == IEEE80211_SMPS_STATIC) ? |
225 | "static" : | 213 | "static" : |
226 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? | 214 | (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? |
227 | "dynamic" : "disabled"); | 215 | "dynamic" : "disabled"); |
228 | 216 | ||
229 | switch (mimo_ps_mode) { | 217 | switch (sta->smps_mode) { |
230 | case WLAN_HT_CAP_SM_PS_STATIC: | 218 | case IEEE80211_SMPS_STATIC: |
231 | *flags |= STA_FLG_MIMO_DIS_MSK; | 219 | *flags |= STA_FLG_MIMO_DIS_MSK; |
232 | break; | 220 | break; |
233 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | 221 | case IEEE80211_SMPS_DYNAMIC: |
234 | *flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 222 | *flags |= STA_FLG_RTS_MIMO_PROT_MSK; |
235 | break; | 223 | break; |
236 | case WLAN_HT_CAP_SM_PS_DISABLED: | 224 | case IEEE80211_SMPS_OFF: |
237 | break; | 225 | break; |
238 | default: | 226 | default: |
239 | IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode); | 227 | IWL_WARN(priv, "Invalid MIMO PS mode %d\n", sta->smps_mode); |
240 | break; | 228 | break; |
241 | } | 229 | } |
242 | 230 | ||
@@ -246,7 +234,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
246 | *flags |= cpu_to_le32( | 234 | *flags |= cpu_to_le32( |
247 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | 235 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); |
248 | 236 | ||
249 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 237 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
250 | *flags |= STA_FLG_HT40_EN_MSK; | 238 | *flags |= STA_FLG_HT40_EN_MSK; |
251 | } | 239 | } |
252 | 240 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index f4a013675947..d1dccb361391 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -1117,7 +1117,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1117 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | 1117 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> |
1118 | IWLAGN_TX_RES_RA_POS; | 1118 | IWLAGN_TX_RES_RA_POS; |
1119 | 1119 | ||
1120 | spin_lock(&priv->sta_lock); | 1120 | spin_lock_bh(&priv->sta_lock); |
1121 | 1121 | ||
1122 | if (is_agg) | 1122 | if (is_agg) |
1123 | iwl_rx_reply_tx_agg(priv, tx_resp); | 1123 | iwl_rx_reply_tx_agg(priv, tx_resp); |
@@ -1207,7 +1207,15 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1207 | freed++; | 1207 | freed++; |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | WARN_ON(!is_agg && freed != 1); | 1210 | if (tid != IWL_TID_NON_QOS) { |
1211 | priv->tid_data[sta_id][tid].next_reclaimed = | ||
1212 | next_reclaimed; | ||
1213 | IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||
1214 | next_reclaimed); | ||
1215 | } | ||
1216 | |||
1217 | if (!is_agg && freed != 1) | ||
1218 | IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed); | ||
1211 | 1219 | ||
1212 | /* | 1220 | /* |
1213 | * An offchannel frame can be send only on the AUX queue, where | 1221 | * An offchannel frame can be send only on the AUX queue, where |
@@ -1228,11 +1236,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1228 | le16_to_cpu(tx_resp->seq_ctl)); | 1236 | le16_to_cpu(tx_resp->seq_ctl)); |
1229 | 1237 | ||
1230 | iwl_check_abort_status(priv, tx_resp->frame_count, status); | 1238 | iwl_check_abort_status(priv, tx_resp->frame_count, status); |
1231 | spin_unlock(&priv->sta_lock); | 1239 | spin_unlock_bh(&priv->sta_lock); |
1232 | 1240 | ||
1233 | while (!skb_queue_empty(&skbs)) { | 1241 | while (!skb_queue_empty(&skbs)) { |
1234 | skb = __skb_dequeue(&skbs); | 1242 | skb = __skb_dequeue(&skbs); |
1235 | ieee80211_tx_status(priv->hw, skb); | 1243 | ieee80211_tx_status_ni(priv->hw, skb); |
1236 | } | 1244 | } |
1237 | 1245 | ||
1238 | if (is_offchannel_skb) | 1246 | if (is_offchannel_skb) |
@@ -1279,12 +1287,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1279 | tid = ba_resp->tid; | 1287 | tid = ba_resp->tid; |
1280 | agg = &priv->tid_data[sta_id][tid].agg; | 1288 | agg = &priv->tid_data[sta_id][tid].agg; |
1281 | 1289 | ||
1282 | spin_lock(&priv->sta_lock); | 1290 | spin_lock_bh(&priv->sta_lock); |
1283 | 1291 | ||
1284 | if (unlikely(!agg->wait_for_ba)) { | 1292 | if (unlikely(!agg->wait_for_ba)) { |
1285 | if (unlikely(ba_resp->bitmap)) | 1293 | if (unlikely(ba_resp->bitmap)) |
1286 | IWL_ERR(priv, "Received BA when not expected\n"); | 1294 | IWL_ERR(priv, "Received BA when not expected\n"); |
1287 | spin_unlock(&priv->sta_lock); | 1295 | spin_unlock_bh(&priv->sta_lock); |
1288 | return 0; | 1296 | return 0; |
1289 | } | 1297 | } |
1290 | 1298 | ||
@@ -1298,7 +1306,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1298 | IWL_DEBUG_TX_QUEUES(priv, | 1306 | IWL_DEBUG_TX_QUEUES(priv, |
1299 | "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", | 1307 | "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", |
1300 | scd_flow, sta_id, tid, agg->txq_id); | 1308 | scd_flow, sta_id, tid, agg->txq_id); |
1301 | spin_unlock(&priv->sta_lock); | 1309 | spin_unlock_bh(&priv->sta_lock); |
1302 | return 0; | 1310 | return 0; |
1303 | } | 1311 | } |
1304 | 1312 | ||
@@ -1367,11 +1375,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1367 | } | 1375 | } |
1368 | } | 1376 | } |
1369 | 1377 | ||
1370 | spin_unlock(&priv->sta_lock); | 1378 | spin_unlock_bh(&priv->sta_lock); |
1371 | 1379 | ||
1372 | while (!skb_queue_empty(&reclaimed_skbs)) { | 1380 | while (!skb_queue_empty(&reclaimed_skbs)) { |
1373 | skb = __skb_dequeue(&reclaimed_skbs); | 1381 | skb = __skb_dequeue(&reclaimed_skbs); |
1374 | ieee80211_tx_status(priv->hw, skb); | 1382 | ieee80211_tx_status_ni(priv->hw, skb); |
1375 | } | 1383 | } |
1376 | 1384 | ||
1377 | return 0; | 1385 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index dc792584f401..4a680019e117 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -113,13 +113,13 @@ struct iwl_cfg; | |||
113 | * May sleep | 113 | * May sleep |
114 | * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the | 114 | * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the |
115 | * HCMD the this Rx responds to. | 115 | * HCMD the this Rx responds to. |
116 | * Must be atomic and called with BH disabled. | 116 | * This callback may sleep, it is called from a threaded IRQ handler. |
117 | * @queue_full: notifies that a HW queue is full. | 117 | * @queue_full: notifies that a HW queue is full. |
118 | * Must be atomic and called with BH disabled. | 118 | * Must be atomic and called with BH disabled. |
119 | * @queue_not_full: notifies that a HW queue is not full any more. | 119 | * @queue_not_full: notifies that a HW queue is not full any more. |
120 | * Must be atomic and called with BH disabled. | 120 | * Must be atomic and called with BH disabled. |
121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that | 121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that |
122 | * the radio is killed. Must be atomic. | 122 | * the radio is killed. May sleep. |
123 | * @free_skb: allows the transport layer to free skbs that haven't been | 123 | * @free_skb: allows the transport layer to free skbs that haven't been |
124 | * reclaimed by the op_mode. This can happen when the driver is freed and | 124 | * reclaimed by the op_mode. This can happen when the driver is freed and |
125 | * there are Tx packets pending in the transport layer. | 125 | * there are Tx packets pending in the transport layer. |
@@ -130,8 +130,7 @@ struct iwl_cfg; | |||
130 | * called with BH disabled. | 130 | * called with BH disabled. |
131 | * @nic_config: configure NIC, called before firmware is started. | 131 | * @nic_config: configure NIC, called before firmware is started. |
132 | * May sleep | 132 | * May sleep |
133 | * @wimax_active: invoked when WiMax becomes active. Must be atomic and called | 133 | * @wimax_active: invoked when WiMax becomes active. May sleep |
134 | * with BH disabled. | ||
135 | */ | 134 | */ |
136 | struct iwl_op_mode_ops { | 135 | struct iwl_op_mode_ops { |
137 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 136 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, |
@@ -178,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, | |||
178 | struct iwl_rx_cmd_buffer *rxb, | 177 | struct iwl_rx_cmd_buffer *rxb, |
179 | struct iwl_device_cmd *cmd) | 178 | struct iwl_device_cmd *cmd) |
180 | { | 179 | { |
180 | might_sleep(); | ||
181 | return op_mode->ops->rx(op_mode, rxb, cmd); | 181 | return op_mode->ops->rx(op_mode, rxb, cmd); |
182 | } | 182 | } |
183 | 183 | ||
@@ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, | |||
196 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, | 196 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, |
197 | bool state) | 197 | bool state) |
198 | { | 198 | { |
199 | might_sleep(); | ||
199 | op_mode->ops->hw_rf_kill(op_mode, state); | 200 | op_mode->ops->hw_rf_kill(op_mode, state); |
200 | } | 201 | } |
201 | 202 | ||
@@ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) | |||
223 | 224 | ||
224 | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) | 225 | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) |
225 | { | 226 | { |
227 | might_sleep(); | ||
226 | op_mode->ops->wimax_active(op_mode); | 228 | op_mode->ops->wimax_active(op_mode); |
227 | } | 229 | } |
228 | 230 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0a3d4df5f434..8c7bec6b9a0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -65,6 +65,7 @@ | |||
65 | 65 | ||
66 | #include <linux/ieee80211.h> | 66 | #include <linux/ieee80211.h> |
67 | #include <linux/mm.h> /* for page_address */ | 67 | #include <linux/mm.h> /* for page_address */ |
68 | #include <linux/lockdep.h> | ||
68 | 69 | ||
69 | #include "iwl-debug.h" | 70 | #include "iwl-debug.h" |
70 | #include "iwl-config.h" | 71 | #include "iwl-config.h" |
@@ -526,6 +527,10 @@ struct iwl_trans { | |||
526 | 527 | ||
527 | struct dentry *dbgfs_dir; | 528 | struct dentry *dbgfs_dir; |
528 | 529 | ||
530 | #ifdef CONFIG_LOCKDEP | ||
531 | struct lockdep_map sync_cmd_lockdep_map; | ||
532 | #endif | ||
533 | |||
529 | /* pointer to trans specific struct */ | 534 | /* pointer to trans specific struct */ |
530 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 535 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
531 | char trans_specific[0] __aligned(sizeof(void *)); | 536 | char trans_specific[0] __aligned(sizeof(void *)); |
@@ -602,12 +607,22 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | |||
602 | } | 607 | } |
603 | 608 | ||
604 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 609 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
605 | struct iwl_host_cmd *cmd) | 610 | struct iwl_host_cmd *cmd) |
606 | { | 611 | { |
612 | int ret; | ||
613 | |||
607 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 614 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
608 | "%s bad state = %d", __func__, trans->state); | 615 | "%s bad state = %d", __func__, trans->state); |
609 | 616 | ||
610 | return trans->ops->send_cmd(trans, cmd); | 617 | if (!(cmd->flags & CMD_ASYNC)) |
618 | lock_map_acquire_read(&trans->sync_cmd_lockdep_map); | ||
619 | |||
620 | ret = trans->ops->send_cmd(trans, cmd); | ||
621 | |||
622 | if (!(cmd->flags & CMD_ASYNC)) | ||
623 | lock_map_release(&trans->sync_cmd_lockdep_map); | ||
624 | |||
625 | return ret; | ||
611 | } | 626 | } |
612 | 627 | ||
613 | static inline struct iwl_device_cmd * | 628 | static inline struct iwl_device_cmd * |
@@ -791,4 +806,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) | |||
791 | int __must_check iwl_pci_register_driver(void); | 806 | int __must_check iwl_pci_register_driver(void); |
792 | void iwl_pci_unregister_driver(void); | 807 | void iwl_pci_unregister_driver(void); |
793 | 808 | ||
809 | static inline void trans_lockdep_init(struct iwl_trans *trans) | ||
810 | { | ||
811 | #ifdef CONFIG_LOCKDEP | ||
812 | static struct lock_class_key __key; | ||
813 | |||
814 | lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map", | ||
815 | &__key, 0); | ||
816 | #endif | ||
817 | } | ||
818 | |||
794 | #endif /* __iwl_trans_h__ */ | 819 | #endif /* __iwl_trans_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 9a95c374990d..c64d864799cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -97,14 +97,14 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
97 | struct inet6_ifaddr *ifa; | 97 | struct inet6_ifaddr *ifa; |
98 | int idx = 0; | 98 | int idx = 0; |
99 | 99 | ||
100 | read_lock(&idev->lock); | 100 | read_lock_bh(&idev->lock); |
101 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 101 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
102 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; | 102 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; |
103 | idx++; | 103 | idx++; |
104 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | 104 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) |
105 | break; | 105 | break; |
106 | } | 106 | } |
107 | read_unlock(&idev->lock); | 107 | read_unlock_bh(&idev->lock); |
108 | 108 | ||
109 | mvmvif->num_target_ipv6_addrs = idx; | 109 | mvmvif->num_target_ipv6_addrs = idx; |
110 | } | 110 | } |
@@ -490,7 +490,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
490 | return -EIO; | 490 | return -EIO; |
491 | } | 491 | } |
492 | 492 | ||
493 | ret = iwl_mvm_sta_add_to_fw(mvm, ap_sta); | 493 | ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false); |
494 | if (ret) | 494 | if (ret) |
495 | return ret; | 495 | return ret; |
496 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); | 496 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); |
@@ -763,6 +763,146 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
763 | return ret; | 763 | return ret; |
764 | } | 764 | } |
765 | 765 | ||
766 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | ||
767 | struct ieee80211_vif *vif) | ||
768 | { | ||
769 | u32 base = mvm->error_event_table; | ||
770 | struct error_table_start { | ||
771 | /* cf. struct iwl_error_event_table */ | ||
772 | u32 valid; | ||
773 | u32 error_id; | ||
774 | } err_info; | ||
775 | struct cfg80211_wowlan_wakeup wakeup = { | ||
776 | .pattern_idx = -1, | ||
777 | }; | ||
778 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | ||
779 | struct iwl_host_cmd cmd = { | ||
780 | .id = WOWLAN_GET_STATUSES, | ||
781 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
782 | }; | ||
783 | struct iwl_wowlan_status *status; | ||
784 | u32 reasons; | ||
785 | int ret, len; | ||
786 | bool pkt8023 = false; | ||
787 | struct sk_buff *pkt = NULL; | ||
788 | |||
789 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
790 | &err_info, sizeof(err_info)); | ||
791 | |||
792 | if (err_info.valid) { | ||
793 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
794 | err_info.valid); | ||
795 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||
796 | wakeup.rfkill_release = true; | ||
797 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||
798 | GFP_KERNEL); | ||
799 | } | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | /* only for tracing for now */ | ||
804 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
805 | if (ret) | ||
806 | IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); | ||
807 | |||
808 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
809 | if (ret) { | ||
810 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
811 | return; | ||
812 | } | ||
813 | |||
814 | /* RF-kill already asserted again... */ | ||
815 | if (!cmd.resp_pkt) | ||
816 | return; | ||
817 | |||
818 | len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
819 | if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { | ||
820 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
821 | goto out; | ||
822 | } | ||
823 | |||
824 | status = (void *)cmd.resp_pkt->data; | ||
825 | |||
826 | if (len - sizeof(struct iwl_cmd_header) != | ||
827 | sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { | ||
828 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
829 | goto out; | ||
830 | } | ||
831 | |||
832 | reasons = le32_to_cpu(status->wakeup_reasons); | ||
833 | |||
834 | if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { | ||
835 | wakeup_report = NULL; | ||
836 | goto report; | ||
837 | } | ||
838 | |||
839 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { | ||
840 | wakeup.magic_pkt = true; | ||
841 | pkt8023 = true; | ||
842 | } | ||
843 | |||
844 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { | ||
845 | wakeup.pattern_idx = | ||
846 | le16_to_cpu(status->pattern_number); | ||
847 | pkt8023 = true; | ||
848 | } | ||
849 | |||
850 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | ||
851 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | ||
852 | wakeup.disconnect = true; | ||
853 | |||
854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { | ||
855 | wakeup.gtk_rekey_failure = true; | ||
856 | pkt8023 = true; | ||
857 | } | ||
858 | |||
859 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { | ||
860 | wakeup.rfkill_release = true; | ||
861 | pkt8023 = true; | ||
862 | } | ||
863 | |||
864 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { | ||
865 | wakeup.eap_identity_req = true; | ||
866 | pkt8023 = true; | ||
867 | } | ||
868 | |||
869 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { | ||
870 | wakeup.four_way_handshake = true; | ||
871 | pkt8023 = true; | ||
872 | } | ||
873 | |||
874 | if (status->wake_packet_bufsize) { | ||
875 | u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); | ||
876 | u32 pktlen = le32_to_cpu(status->wake_packet_length); | ||
877 | |||
878 | if (pkt8023) { | ||
879 | pkt = alloc_skb(pktsize, GFP_KERNEL); | ||
880 | if (!pkt) | ||
881 | goto report; | ||
882 | memcpy(skb_put(pkt, pktsize), status->wake_packet, | ||
883 | pktsize); | ||
884 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) | ||
885 | goto report; | ||
886 | wakeup.packet = pkt->data; | ||
887 | wakeup.packet_present_len = pkt->len; | ||
888 | wakeup.packet_len = pkt->len - (pktlen - pktsize); | ||
889 | wakeup.packet_80211 = false; | ||
890 | } else { | ||
891 | wakeup.packet = status->wake_packet; | ||
892 | wakeup.packet_present_len = pktsize; | ||
893 | wakeup.packet_len = pktlen; | ||
894 | wakeup.packet_80211 = true; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | report: | ||
899 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | ||
900 | kfree_skb(pkt); | ||
901 | |||
902 | out: | ||
903 | iwl_free_resp(&cmd); | ||
904 | } | ||
905 | |||
766 | int iwl_mvm_resume(struct ieee80211_hw *hw) | 906 | int iwl_mvm_resume(struct ieee80211_hw *hw) |
767 | { | 907 | { |
768 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 908 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
@@ -770,14 +910,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
770 | .mvm = mvm, | 910 | .mvm = mvm, |
771 | }; | 911 | }; |
772 | struct ieee80211_vif *vif = NULL; | 912 | struct ieee80211_vif *vif = NULL; |
773 | u32 base; | ||
774 | int ret; | 913 | int ret; |
775 | enum iwl_d3_status d3_status; | 914 | enum iwl_d3_status d3_status; |
776 | struct error_table_start { | ||
777 | /* cf. struct iwl_error_event_table */ | ||
778 | u32 valid; | ||
779 | u32 error_id; | ||
780 | } err_info; | ||
781 | 915 | ||
782 | mutex_lock(&mvm->mutex); | 916 | mutex_lock(&mvm->mutex); |
783 | 917 | ||
@@ -800,27 +934,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
800 | goto out_unlock; | 934 | goto out_unlock; |
801 | } | 935 | } |
802 | 936 | ||
803 | base = mvm->error_event_table; | 937 | iwl_mvm_query_wakeup_reasons(mvm, vif); |
804 | |||
805 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
806 | &err_info, sizeof(err_info)); | ||
807 | |||
808 | if (err_info.valid) { | ||
809 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
810 | err_info.valid); | ||
811 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) | ||
812 | IWL_ERR(mvm, "this was due to RF-kill\n"); | ||
813 | goto out_unlock; | ||
814 | } | ||
815 | |||
816 | /* TODO: get status and whatever else ... */ | ||
817 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL); | ||
818 | if (ret) | ||
819 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
820 | |||
821 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
822 | if (ret) | ||
823 | IWL_ERR(mvm, "failed to query offloads (%d)\n", ret); | ||
824 | 938 | ||
825 | out_unlock: | 939 | out_unlock: |
826 | mutex_unlock(&mvm->mutex); | 940 | mutex_unlock(&mvm->mutex); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 9fd49db32a32..23eebda848b0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -633,6 +633,9 @@ struct iwl_binding_cmd { | |||
633 | __le32 phy; | 633 | __le32 phy; |
634 | } __packed; /* BINDING_CMD_API_S_VER_1 */ | 634 | } __packed; /* BINDING_CMD_API_S_VER_1 */ |
635 | 635 | ||
636 | /* The maximal number of fragments in the FW's schedule session */ | ||
637 | #define IWL_MVM_MAX_QUOTA 128 | ||
638 | |||
636 | /** | 639 | /** |
637 | * struct iwl_time_quota_data - configuration of time quota per binding | 640 | * struct iwl_time_quota_data - configuration of time quota per binding |
638 | * @id_and_color: ID and color of the relevant Binding | 641 | * @id_and_color: ID and color of the relevant Binding |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 90473c2ba1c7..d3d959db03a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -621,10 +621,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | |||
621 | (flags & CT_KILL_CARD_DISABLED) ? | 621 | (flags & CT_KILL_CARD_DISABLED) ? |
622 | "Reached" : "Not reached"); | 622 | "Reached" : "Not reached"); |
623 | 623 | ||
624 | if (flags & CARD_DISABLED_MSK) | ||
625 | iwl_write32(mvm->trans, CSR_UCODE_DRV_GP1_SET, | ||
626 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
627 | |||
628 | return 0; | 624 | return 0; |
629 | } | 625 | } |
630 | 626 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index c08a17a3cab9..0854dc338881 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -584,7 +584,11 @@ static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, | |||
584 | struct ieee80211_vif *vif, | 584 | struct ieee80211_vif *vif, |
585 | struct iwl_mac_data_sta *ctxt_sta) | 585 | struct iwl_mac_data_sta *ctxt_sta) |
586 | { | 586 | { |
587 | ctxt_sta->is_assoc = cpu_to_le32(vif->bss_conf.assoc ? 1 : 0); | 587 | /* We need the dtim_period to set the MAC as associated */ |
588 | if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) | ||
589 | ctxt_sta->is_assoc = cpu_to_le32(1); | ||
590 | else | ||
591 | ctxt_sta->is_assoc = cpu_to_le32(0); | ||
588 | 592 | ||
589 | ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); | 593 | ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); |
590 | ctxt_sta->bi_reciprocal = | 594 | ctxt_sta->bi_reciprocal = |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index a6b05a02cfd4..e27eb9724112 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -113,8 +113,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
113 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 113 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
114 | IEEE80211_HW_QUEUE_CONTROL | | 114 | IEEE80211_HW_QUEUE_CONTROL | |
115 | IEEE80211_HW_WANT_MONITOR_VIF | | 115 | IEEE80211_HW_WANT_MONITOR_VIF | |
116 | IEEE80211_HW_SCAN_WHILE_IDLE | | 116 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | |
117 | IEEE80211_HW_NEED_DTIM_PERIOD | | ||
118 | IEEE80211_HW_SUPPORTS_PS | | 117 | IEEE80211_HW_SUPPORTS_PS | |
119 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 118 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | |
120 | IEEE80211_HW_AMPDU_AGGREGATION; | 119 | IEEE80211_HW_AMPDU_AGGREGATION; |
@@ -475,7 +474,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
475 | if (mvm->vif_count > 1) { | 474 | if (mvm->vif_count > 1) { |
476 | IWL_DEBUG_MAC80211(mvm, | 475 | IWL_DEBUG_MAC80211(mvm, |
477 | "Disable power on existing interfaces\n"); | 476 | "Disable power on existing interfaces\n"); |
478 | ieee80211_iterate_active_interfaces( | 477 | ieee80211_iterate_active_interfaces_atomic( |
479 | mvm->hw, | 478 | mvm->hw, |
480 | IEEE80211_IFACE_ITER_NORMAL, | 479 | IEEE80211_IFACE_ITER_NORMAL, |
481 | iwl_mvm_pm_disable_iterator, mvm); | 480 | iwl_mvm_pm_disable_iterator, mvm); |
@@ -671,8 +670,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
671 | IWL_ERR(mvm, "failed to update quotas\n"); | 670 | IWL_ERR(mvm, "failed to update quotas\n"); |
672 | return; | 671 | return; |
673 | } | 672 | } |
674 | iwl_mvm_remove_time_event(mvm, mvmvif, | ||
675 | &mvmvif->time_event_data); | ||
676 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 673 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
677 | /* remove AP station now that the MAC is unassoc */ | 674 | /* remove AP station now that the MAC is unassoc */ |
678 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 675 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
@@ -684,6 +681,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
684 | if (ret) | 681 | if (ret) |
685 | IWL_ERR(mvm, "failed to update quotas\n"); | 682 | IWL_ERR(mvm, "failed to update quotas\n"); |
686 | } | 683 | } |
684 | } else if (changes & BSS_CHANGED_DTIM_PERIOD) { | ||
685 | /* | ||
686 | * We received a beacon _after_ association so | ||
687 | * remove the session protection. | ||
688 | */ | ||
689 | iwl_mvm_remove_time_event(mvm, mvmvif, | ||
690 | &mvmvif->time_event_data); | ||
687 | } else if (changes & BSS_CHANGED_PS) { | 691 | } else if (changes & BSS_CHANGED_PS) { |
688 | /* | 692 | /* |
689 | * TODO: remove this temporary code. | 693 | * TODO: remove this temporary code. |
@@ -922,8 +926,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
922 | ret = 0; | 926 | ret = 0; |
923 | } else if (old_state == IEEE80211_STA_AUTH && | 927 | } else if (old_state == IEEE80211_STA_AUTH && |
924 | new_state == IEEE80211_STA_ASSOC) { | 928 | new_state == IEEE80211_STA_ASSOC) { |
925 | iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); | 929 | ret = iwl_mvm_update_sta(mvm, vif, sta); |
926 | ret = 0; | 930 | if (ret == 0) |
931 | iwl_mvm_rs_rate_init(mvm, sta, | ||
932 | mvmvif->phy_ctxt->channel->band); | ||
927 | } else if (old_state == IEEE80211_STA_ASSOC && | 933 | } else if (old_state == IEEE80211_STA_ASSOC && |
928 | new_state == IEEE80211_STA_AUTHORIZED) { | 934 | new_state == IEEE80211_STA_AUTHORIZED) { |
929 | ret = 0; | 935 | ret = 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 983dca3f888a..aa59adf87db3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -536,25 +536,28 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, | |||
536 | 536 | ||
537 | for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { | 537 | for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { |
538 | const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; | 538 | const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; |
539 | if (rx_h->cmd_id == pkt->hdr.cmd) { | 539 | struct iwl_async_handler_entry *entry; |
540 | struct iwl_async_handler_entry *entry; | 540 | |
541 | if (!rx_h->async) | 541 | if (rx_h->cmd_id != pkt->hdr.cmd) |
542 | return rx_h->fn(mvm, rxb, cmd); | 542 | continue; |
543 | 543 | ||
544 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 544 | if (!rx_h->async) |
545 | /* we can't do much... */ | 545 | return rx_h->fn(mvm, rxb, cmd); |
546 | if (!entry) | 546 | |
547 | return 0; | 547 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
548 | 548 | /* we can't do much... */ | |
549 | entry->rxb._page = rxb_steal_page(rxb); | 549 | if (!entry) |
550 | entry->rxb._offset = rxb->_offset; | 550 | return 0; |
551 | entry->rxb._rx_page_order = rxb->_rx_page_order; | 551 | |
552 | entry->fn = rx_h->fn; | 552 | entry->rxb._page = rxb_steal_page(rxb); |
553 | spin_lock(&mvm->async_handlers_lock); | 553 | entry->rxb._offset = rxb->_offset; |
554 | list_add_tail(&entry->list, &mvm->async_handlers_list); | 554 | entry->rxb._rx_page_order = rxb->_rx_page_order; |
555 | spin_unlock(&mvm->async_handlers_lock); | 555 | entry->fn = rx_h->fn; |
556 | schedule_work(&mvm->async_handlers_wk); | 556 | spin_lock(&mvm->async_handlers_lock); |
557 | } | 557 | list_add_tail(&entry->list, &mvm->async_handlers_list); |
558 | spin_unlock(&mvm->async_handlers_lock); | ||
559 | schedule_work(&mvm->async_handlers_wk); | ||
560 | break; | ||
558 | } | 561 | } |
559 | 562 | ||
560 | return 0; | 563 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 63628739cf4a..5a92a4978795 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -194,7 +194,7 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | 194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, |
195 | le16_to_cpu(cmd.flags)); | 195 | le16_to_cpu(cmd.flags)); |
196 | 196 | ||
197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, |
198 | sizeof(cmd), &cmd); | 198 | sizeof(cmd), &cmd); |
199 | } | 199 | } |
200 | 200 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 2d4611a563c5..925628468146 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -131,7 +131,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
131 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | 131 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
132 | { | 132 | { |
133 | struct iwl_time_quota_cmd cmd; | 133 | struct iwl_time_quota_cmd cmd; |
134 | int i, idx, ret; | 134 | int i, idx, ret, num_active_bindings, quota, quota_rem; |
135 | struct iwl_mvm_quota_iterator_data data = { | 135 | struct iwl_mvm_quota_iterator_data data = { |
136 | .n_interfaces = {}, | 136 | .n_interfaces = {}, |
137 | .colors = { -1, -1, -1, -1 }, | 137 | .colors = { -1, -1, -1, -1 }, |
@@ -156,20 +156,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
156 | iwl_mvm_quota_iterator(&data, newvif->addr, newvif); | 156 | iwl_mvm_quota_iterator(&data, newvif->addr, newvif); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* | ||
160 | * The FW's scheduling session consists of | ||
161 | * IWL_MVM_MAX_QUOTA fragments. Divide these fragments | ||
162 | * equally between all the bindings that require quota | ||
163 | */ | ||
164 | num_active_bindings = 0; | ||
165 | for (i = 0; i < MAX_BINDINGS; i++) { | ||
166 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | ||
167 | if (data.n_interfaces[i] > 0) | ||
168 | num_active_bindings++; | ||
169 | } | ||
170 | |||
171 | if (!num_active_bindings) | ||
172 | goto send_cmd; | ||
173 | |||
174 | quota = IWL_MVM_MAX_QUOTA / num_active_bindings; | ||
175 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; | ||
176 | |||
159 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 177 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
160 | if (data.n_interfaces[i] <= 0) | 178 | if (data.n_interfaces[i] <= 0) |
161 | continue; | 179 | continue; |
162 | 180 | ||
163 | cmd.quotas[idx].id_and_color = | 181 | cmd.quotas[idx].id_and_color = |
164 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | 182 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); |
165 | cmd.quotas[idx].quota = cpu_to_le32(100); | 183 | cmd.quotas[idx].quota = cpu_to_le32(quota); |
166 | cmd.quotas[idx].max_duration = cpu_to_le32(1000); | 184 | cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); |
167 | idx++; | 185 | idx++; |
168 | } | 186 | } |
169 | 187 | ||
170 | for (i = idx; i < MAX_BINDINGS; i++) | 188 | /* Give the remainder of the session to the first binding */ |
171 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | 189 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); |
172 | 190 | ||
191 | send_cmd: | ||
173 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | 192 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, |
174 | sizeof(cmd), &cmd); | 193 | sizeof(cmd), &cmd); |
175 | if (ret) | 194 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 60a4291ca221..56b636d9ab30 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -1209,23 +1209,9 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1209 | return new_rate; | 1209 | return new_rate; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm, | 1212 | static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta) |
1213 | struct ieee80211_sta_ht_cap *ht_cap) | ||
1214 | { | 1213 | { |
1215 | /* | 1214 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
1216 | * Remainder of this function checks ht_cap, but if it's | ||
1217 | * NULL then we can do HT40 (special case for RXON) | ||
1218 | */ | ||
1219 | if (!ht_cap) | ||
1220 | return true; | ||
1221 | |||
1222 | if (!ht_cap->ht_supported) | ||
1223 | return false; | ||
1224 | |||
1225 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
1226 | return false; | ||
1227 | |||
1228 | return true; | ||
1229 | } | 1215 | } |
1230 | 1216 | ||
1231 | /* | 1217 | /* |
@@ -1243,8 +1229,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1243 | if (!sta->ht_cap.ht_supported) | 1229 | if (!sta->ht_cap.ht_supported) |
1244 | return -1; | 1230 | return -1; |
1245 | 1231 | ||
1246 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1232 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
1247 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
1248 | return -1; | 1233 | return -1; |
1249 | 1234 | ||
1250 | /* Need both Tx chains/antennas to support MIMO */ | 1235 | /* Need both Tx chains/antennas to support MIMO */ |
@@ -1258,7 +1243,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1258 | tbl->max_search = IWL_MAX_SEARCH; | 1243 | tbl->max_search = IWL_MAX_SEARCH; |
1259 | rate_mask = lq_sta->active_mimo2_rate; | 1244 | rate_mask = lq_sta->active_mimo2_rate; |
1260 | 1245 | ||
1261 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1246 | if (iwl_is_ht40_tx_allowed(sta)) |
1262 | tbl->is_ht40 = 1; | 1247 | tbl->is_ht40 = 1; |
1263 | else | 1248 | else |
1264 | tbl->is_ht40 = 0; | 1249 | tbl->is_ht40 = 0; |
@@ -1296,8 +1281,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | |||
1296 | if (!sta->ht_cap.ht_supported) | 1281 | if (!sta->ht_cap.ht_supported) |
1297 | return -1; | 1282 | return -1; |
1298 | 1283 | ||
1299 | if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 1284 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
1300 | == WLAN_HT_CAP_SM_PS_STATIC) | ||
1301 | return -1; | 1285 | return -1; |
1302 | 1286 | ||
1303 | /* Need both Tx chains/antennas to support MIMO */ | 1287 | /* Need both Tx chains/antennas to support MIMO */ |
@@ -1311,7 +1295,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | |||
1311 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1295 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
1312 | rate_mask = lq_sta->active_mimo3_rate; | 1296 | rate_mask = lq_sta->active_mimo3_rate; |
1313 | 1297 | ||
1314 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1298 | if (iwl_is_ht40_tx_allowed(sta)) |
1315 | tbl->is_ht40 = 1; | 1299 | tbl->is_ht40 = 1; |
1316 | else | 1300 | else |
1317 | tbl->is_ht40 = 0; | 1301 | tbl->is_ht40 = 0; |
@@ -1356,7 +1340,7 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | |||
1356 | tbl->max_search = IWL_MAX_SEARCH; | 1340 | tbl->max_search = IWL_MAX_SEARCH; |
1357 | rate_mask = lq_sta->active_siso_rate; | 1341 | rate_mask = lq_sta->active_siso_rate; |
1358 | 1342 | ||
1359 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1343 | if (iwl_is_ht40_tx_allowed(sta)) |
1360 | tbl->is_ht40 = 1; | 1344 | tbl->is_ht40 = 1; |
1361 | else | 1345 | else |
1362 | tbl->is_ht40 = 0; | 1346 | tbl->is_ht40 = 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 52da375e5740..3f3ce91ad5c2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -121,7 +121,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
121 | 121 | ||
122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
123 | 123 | ||
124 | ieee80211_rx(mvm->hw, skb); | 124 | ieee80211_rx_ni(mvm->hw, skb); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* | 127 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 69603c3b2b39..a1eb692d7fad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -81,8 +81,9 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | |||
81 | return IWL_MVM_STATION_COUNT; | 81 | return IWL_MVM_STATION_COUNT; |
82 | } | 82 | } |
83 | 83 | ||
84 | /* add a NEW station to fw */ | 84 | /* send station add/update command to firmware */ |
85 | int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | 85 | int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
86 | bool update) | ||
86 | { | 87 | { |
87 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 88 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
88 | struct iwl_mvm_add_sta_cmd add_sta_cmd; | 89 | struct iwl_mvm_add_sta_cmd add_sta_cmd; |
@@ -94,8 +95,11 @@ int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | |||
94 | 95 | ||
95 | add_sta_cmd.sta_id = mvm_sta->sta_id; | 96 | add_sta_cmd.sta_id = mvm_sta->sta_id; |
96 | add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | 97 | add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); |
97 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | 98 | if (!update) { |
98 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | 99 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); |
100 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | ||
101 | } | ||
102 | add_sta_cmd.add_modify = update ? 1 : 0; | ||
99 | 103 | ||
100 | /* STA_FLG_FAT_EN_MSK ? */ | 104 | /* STA_FLG_FAT_EN_MSK ? */ |
101 | /* STA_FLG_MIMO_EN_MSK ? */ | 105 | /* STA_FLG_MIMO_EN_MSK ? */ |
@@ -181,7 +185,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
181 | /* for HW restart - need to reset the seq_number etc... */ | 185 | /* for HW restart - need to reset the seq_number etc... */ |
182 | memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); | 186 | memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); |
183 | 187 | ||
184 | ret = iwl_mvm_sta_add_to_fw(mvm, sta); | 188 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); |
185 | if (ret) | 189 | if (ret) |
186 | return ret; | 190 | return ret; |
187 | 191 | ||
@@ -195,6 +199,13 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
195 | return 0; | 199 | return 0; |
196 | } | 200 | } |
197 | 201 | ||
202 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | ||
203 | struct ieee80211_vif *vif, | ||
204 | struct ieee80211_sta *sta) | ||
205 | { | ||
206 | return iwl_mvm_sta_send_to_fw(mvm, sta, true); | ||
207 | } | ||
208 | |||
198 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 209 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
199 | bool drain) | 210 | bool drain) |
200 | { | 211 | { |
@@ -1116,7 +1127,8 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1116 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | 1127 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) |
1117 | return -EINVAL; | 1128 | return -EINVAL; |
1118 | 1129 | ||
1119 | key_flags = cpu_to_le16(keyconf->keyidx & STA_KEY_FLG_KEYID_MSK); | 1130 | key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & |
1131 | STA_KEY_FLG_KEYID_MSK); | ||
1120 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | 1132 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); |
1121 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | 1133 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); |
1122 | 1134 | ||
@@ -1154,14 +1166,26 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1154 | struct ieee80211_sta *sta, u32 iv32, | 1166 | struct ieee80211_sta *sta, u32 iv32, |
1155 | u16 *phase1key) | 1167 | u16 *phase1key) |
1156 | { | 1168 | { |
1157 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 1169 | struct iwl_mvm_sta *mvm_sta; |
1158 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1170 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); |
1159 | 1171 | ||
1160 | if (sta_id == IWL_INVALID_STATION) | 1172 | if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) |
1161 | return; | 1173 | return; |
1162 | 1174 | ||
1175 | rcu_read_lock(); | ||
1176 | |||
1177 | if (!sta) { | ||
1178 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
1179 | if (WARN_ON(IS_ERR_OR_NULL(sta))) { | ||
1180 | rcu_read_unlock(); | ||
1181 | return; | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | mvm_sta = (void *)sta->drv_priv; | ||
1163 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | 1186 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, |
1164 | iv32, phase1key, CMD_ASYNC); | 1187 | iv32, phase1key, CMD_ASYNC); |
1188 | rcu_read_unlock(); | ||
1165 | } | 1189 | } |
1166 | 1190 | ||
1167 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) | 1191 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 1bf301097984..bdd7c5ed8222 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -309,10 +309,14 @@ struct iwl_mvm_int_sta { | |||
309 | u32 tfd_queue_msk; | 309 | u32 tfd_queue_msk; |
310 | }; | 310 | }; |
311 | 311 | ||
312 | int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta); | 312 | int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
313 | bool update); | ||
313 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | 314 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, |
314 | struct ieee80211_vif *vif, | 315 | struct ieee80211_vif *vif, |
315 | struct ieee80211_sta *sta); | 316 | struct ieee80211_sta *sta); |
317 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | ||
318 | struct ieee80211_vif *vif, | ||
319 | struct ieee80211_sta *sta); | ||
316 | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | 320 | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, |
317 | struct ieee80211_vif *vif, | 321 | struct ieee80211_vif *vif, |
318 | struct ieee80211_sta *sta); | 322 | struct ieee80211_sta *sta); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index b9f076f4f17c..c09b71f23759 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -76,6 +76,15 @@ | |||
76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) | 76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) |
77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
78 | 78 | ||
79 | /* For ROC use a TE type which has priority high enough to be scheduled when | ||
80 | * there is a concurrent BSS or GO/AP. Currently, use a TE type that has | ||
81 | * priority similar to the TE priority used for action scans by the FW. | ||
82 | * TODO: This needs to be changed, based on the reason for the ROC, i.e., use | ||
83 | * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use | ||
84 | * TE_P2P_DEVICE_ACTION_SCAN | ||
85 | */ | ||
86 | #define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN | ||
87 | |||
79 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | 88 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, |
80 | struct iwl_mvm_time_event_data *te_data) | 89 | struct iwl_mvm_time_event_data *te_data) |
81 | { | 90 | { |
@@ -175,9 +184,11 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
175 | */ | 184 | */ |
176 | if (te_data->vif->type == NL80211_IFTYPE_STATION && | 185 | if (te_data->vif->type == NL80211_IFTYPE_STATION && |
177 | (!te_data->vif->bss_conf.assoc || | 186 | (!te_data->vif->bss_conf.assoc || |
178 | !te_data->vif->bss_conf.dtim_period)) | 187 | !te_data->vif->bss_conf.dtim_period)) { |
179 | IWL_ERR(mvm, | 188 | IWL_ERR(mvm, |
180 | "No assocation and the time event is over already...\n"); | 189 | "No assocation and the time event is over already...\n"); |
190 | ieee80211_connection_loss(te_data->vif); | ||
191 | } | ||
181 | 192 | ||
182 | iwl_mvm_te_clear_data(mvm, te_data); | 193 | iwl_mvm_te_clear_data(mvm, te_data); |
183 | } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { | 194 | } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { |
@@ -219,57 +230,86 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | |||
219 | return 0; | 230 | return 0; |
220 | } | 231 | } |
221 | 232 | ||
222 | static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, | 233 | static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, |
223 | struct iwl_rx_packet *pkt, void *data) | 234 | struct iwl_rx_packet *pkt, void *data) |
224 | { | 235 | { |
225 | struct iwl_mvm *mvm = | 236 | struct iwl_mvm *mvm = |
226 | container_of(notif_wait, struct iwl_mvm, notif_wait); | 237 | container_of(notif_wait, struct iwl_mvm, notif_wait); |
227 | struct iwl_mvm_time_event_data *te_data = data; | 238 | struct iwl_mvm_time_event_data *te_data = data; |
228 | struct ieee80211_vif *vif = te_data->vif; | ||
229 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
230 | struct iwl_time_event_notif *notif; | ||
231 | struct iwl_time_event_resp *resp; | 239 | struct iwl_time_event_resp *resp; |
240 | int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
232 | 241 | ||
233 | u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | 242 | if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD)) |
243 | return true; | ||
234 | 244 | ||
235 | /* until we do something else */ | 245 | if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) { |
236 | WARN_ON(te_data->id != TE_BSS_STA_AGGRESSIVE_ASSOC); | 246 | IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n"); |
247 | return true; | ||
248 | } | ||
237 | 249 | ||
238 | switch (pkt->hdr.cmd) { | 250 | resp = (void *)pkt->data; |
239 | case TIME_EVENT_CMD: | 251 | te_data->uid = le32_to_cpu(resp->unique_id); |
240 | resp = (void *)pkt->data; | 252 | IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", |
241 | /* TODO: I can't check that since the fw is buggy - it doesn't | 253 | te_data->uid); |
242 | * put the right values when we remove a TE. We can be here | 254 | return true; |
243 | * when we remove a TE because the remove TE command is sent in | 255 | } |
244 | * ASYNC... | ||
245 | * WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); | ||
246 | */ | ||
247 | te_data->uid = le32_to_cpu(resp->unique_id); | ||
248 | IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); | ||
249 | return false; | ||
250 | |||
251 | case TIME_EVENT_NOTIFICATION: | ||
252 | notif = (void *)pkt->data; | ||
253 | WARN_ON(le32_to_cpu(notif->status) != 1); | ||
254 | WARN_ON(mac_id_n_color != le32_to_cpu(notif->id_and_color)); | ||
255 | /* check if this is our Time Event that is starting */ | ||
256 | if (le32_to_cpu(notif->unique_id) != te_data->uid) | ||
257 | return false; | ||
258 | IWL_DEBUG_TE(mvm, "Event %d is starting - time is %d\n", | ||
259 | te_data->uid, le32_to_cpu(notif->timestamp)); | ||
260 | |||
261 | WARN_ONCE(!le32_to_cpu(notif->status), | ||
262 | "Failed to schedule protected session TE\n"); | ||
263 | 256 | ||
264 | te_data->running = true; | 257 | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, |
265 | te_data->end_jiffies = jiffies + | 258 | struct ieee80211_vif *vif, |
266 | TU_TO_JIFFIES(te_data->duration); | 259 | struct iwl_mvm_time_event_data *te_data, |
267 | return true; | 260 | struct iwl_time_event_cmd *te_cmd) |
261 | { | ||
262 | static const u8 time_event_response[] = { TIME_EVENT_CMD }; | ||
263 | struct iwl_notification_wait wait_time_event; | ||
264 | int ret; | ||
265 | |||
266 | lockdep_assert_held(&mvm->mutex); | ||
267 | |||
268 | spin_lock_bh(&mvm->time_event_lock); | ||
269 | if (WARN_ON(te_data->id != TE_MAX)) { | ||
270 | spin_unlock_bh(&mvm->time_event_lock); | ||
271 | return -EIO; | ||
272 | } | ||
273 | te_data->vif = vif; | ||
274 | te_data->duration = le32_to_cpu(te_cmd->duration); | ||
275 | te_data->id = le32_to_cpu(te_cmd->id); | ||
276 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
277 | spin_unlock_bh(&mvm->time_event_lock); | ||
278 | |||
279 | /* | ||
280 | * Use a notification wait, which really just processes the | ||
281 | * command response and doesn't wait for anything, in order | ||
282 | * to be able to process the response and get the UID inside | ||
283 | * the RX path. Using CMD_WANT_SKB doesn't work because it | ||
284 | * stores the buffer and then wakes up this thread, by which | ||
285 | * time another notification (that the time event started) | ||
286 | * might already be processed unsuccessfully. | ||
287 | */ | ||
288 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
289 | time_event_response, | ||
290 | ARRAY_SIZE(time_event_response), | ||
291 | iwl_mvm_time_event_response, te_data); | ||
268 | 292 | ||
269 | default: | 293 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, |
270 | WARN_ON(1); | 294 | sizeof(*te_cmd), te_cmd); |
271 | return false; | 295 | if (ret) { |
272 | }; | 296 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); |
297 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
298 | goto out_clear_te; | ||
299 | } | ||
300 | |||
301 | /* No need to wait for anything, so just pass 1 (0 isn't valid) */ | ||
302 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); | ||
303 | /* should never fail */ | ||
304 | WARN_ON_ONCE(ret); | ||
305 | |||
306 | if (ret) { | ||
307 | out_clear_te: | ||
308 | spin_lock_bh(&mvm->time_event_lock); | ||
309 | iwl_mvm_te_clear_data(mvm, te_data); | ||
310 | spin_unlock_bh(&mvm->time_event_lock); | ||
311 | } | ||
312 | return ret; | ||
273 | } | 313 | } |
274 | 314 | ||
275 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 315 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, |
@@ -278,11 +318,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
278 | { | 318 | { |
279 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 319 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
280 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 320 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
281 | static const u8 time_event_notif[] = { TIME_EVENT_CMD, | ||
282 | TIME_EVENT_NOTIFICATION }; | ||
283 | struct iwl_notification_wait wait_time_event; | ||
284 | struct iwl_time_event_cmd time_cmd = {}; | 321 | struct iwl_time_event_cmd time_cmd = {}; |
285 | int ret; | ||
286 | 322 | ||
287 | lockdep_assert_held(&mvm->mutex); | 323 | lockdep_assert_held(&mvm->mutex); |
288 | 324 | ||
@@ -309,12 +345,6 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
309 | iwl_mvm_stop_session_protection(mvm, vif); | 345 | iwl_mvm_stop_session_protection(mvm, vif); |
310 | } | 346 | } |
311 | 347 | ||
312 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
313 | time_event_notif, | ||
314 | ARRAY_SIZE(time_event_notif), | ||
315 | iwl_mvm_time_event_notif, | ||
316 | &mvmvif->time_event_data); | ||
317 | |||
318 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 348 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); |
319 | time_cmd.id_and_color = | 349 | time_cmd.id_and_color = |
320 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 350 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
@@ -322,6 +352,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
322 | 352 | ||
323 | time_cmd.apply_time = | 353 | time_cmd.apply_time = |
324 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | 354 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); |
355 | |||
325 | time_cmd.dep_policy = TE_INDEPENDENT; | 356 | time_cmd.dep_policy = TE_INDEPENDENT; |
326 | time_cmd.is_present = cpu_to_le32(1); | 357 | time_cmd.is_present = cpu_to_le32(1); |
327 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | 358 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); |
@@ -333,33 +364,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
333 | time_cmd.repeat = cpu_to_le32(1); | 364 | time_cmd.repeat = cpu_to_le32(1); |
334 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 365 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); |
335 | 366 | ||
336 | te_data->vif = vif; | 367 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
337 | te_data->duration = duration; | ||
338 | |||
339 | spin_lock_bh(&mvm->time_event_lock); | ||
340 | te_data->id = le32_to_cpu(time_cmd.id); | ||
341 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
342 | spin_unlock_bh(&mvm->time_event_lock); | ||
343 | |||
344 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
345 | sizeof(time_cmd), &time_cmd); | ||
346 | if (ret) { | ||
347 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||
348 | goto out_remove_notif; | ||
349 | } | ||
350 | |||
351 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); | ||
352 | if (ret) { | ||
353 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
354 | spin_lock_bh(&mvm->time_event_lock); | ||
355 | iwl_mvm_te_clear_data(mvm, te_data); | ||
356 | spin_unlock_bh(&mvm->time_event_lock); | ||
357 | } | ||
358 | |||
359 | return; | ||
360 | |||
361 | out_remove_notif: | ||
362 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
363 | } | 368 | } |
364 | 369 | ||
365 | /* | 370 | /* |
@@ -424,43 +429,12 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, | |||
424 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | 429 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); |
425 | } | 430 | } |
426 | 431 | ||
427 | static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait, | ||
428 | struct iwl_rx_packet *pkt, void *data) | ||
429 | { | ||
430 | struct iwl_mvm *mvm = | ||
431 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
432 | struct iwl_mvm_time_event_data *te_data = data; | ||
433 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | ||
434 | struct iwl_time_event_resp *resp; | ||
435 | |||
436 | u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | ||
437 | |||
438 | /* until we do something else */ | ||
439 | WARN_ON(te_data->id != TE_P2P_DEVICE_DISCOVERABLE); | ||
440 | |||
441 | switch (pkt->hdr.cmd) { | ||
442 | case TIME_EVENT_CMD: | ||
443 | resp = (void *)pkt->data; | ||
444 | WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); | ||
445 | te_data->uid = le32_to_cpu(resp->unique_id); | ||
446 | IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); | ||
447 | return true; | ||
448 | |||
449 | default: | ||
450 | WARN_ON(1); | ||
451 | return false; | ||
452 | }; | ||
453 | } | ||
454 | |||
455 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 432 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
456 | int duration) | 433 | int duration) |
457 | { | 434 | { |
458 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 435 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
459 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 436 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
460 | static const u8 roc_te_notif[] = { TIME_EVENT_CMD }; | ||
461 | struct iwl_notification_wait wait_time_event; | ||
462 | struct iwl_time_event_cmd time_cmd = {}; | 437 | struct iwl_time_event_cmd time_cmd = {}; |
463 | int ret; | ||
464 | 438 | ||
465 | lockdep_assert_held(&mvm->mutex); | 439 | lockdep_assert_held(&mvm->mutex); |
466 | if (te_data->running) { | 440 | if (te_data->running) { |
@@ -474,16 +448,10 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
474 | */ | 448 | */ |
475 | flush_work(&mvm->roc_done_wk); | 449 | flush_work(&mvm->roc_done_wk); |
476 | 450 | ||
477 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
478 | roc_te_notif, | ||
479 | ARRAY_SIZE(roc_te_notif), | ||
480 | iwl_mvm_roc_te_notif, | ||
481 | &mvmvif->time_event_data); | ||
482 | |||
483 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 451 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); |
484 | time_cmd.id_and_color = | 452 | time_cmd.id_and_color = |
485 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 453 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
486 | time_cmd.id = cpu_to_le32(TE_P2P_DEVICE_DISCOVERABLE); | 454 | time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE); |
487 | 455 | ||
488 | time_cmd.apply_time = cpu_to_le32(0); | 456 | time_cmd.apply_time = cpu_to_le32(0); |
489 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | 457 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); |
@@ -492,7 +460,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
492 | time_cmd.interval = cpu_to_le32(1); | 460 | time_cmd.interval = cpu_to_le32(1); |
493 | 461 | ||
494 | /* | 462 | /* |
495 | * TE_P2P_DEVICE_DISCOVERABLE can have lower priority than other events | 463 | * IWL_MVM_ROC_TE_TYPE can have lower priority than other events |
496 | * that are being scheduled by the driver/fw, and thus it might not be | 464 | * that are being scheduled by the driver/fw, and thus it might not be |
497 | * scheduled. To improve the chances of it being scheduled, allow it to | 465 | * scheduled. To improve the chances of it being scheduled, allow it to |
498 | * be fragmented. | 466 | * be fragmented. |
@@ -505,33 +473,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
505 | time_cmd.repeat = cpu_to_le32(1); | 473 | time_cmd.repeat = cpu_to_le32(1); |
506 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 474 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); |
507 | 475 | ||
508 | /* Push the te data to the tracked te list */ | 476 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
509 | te_data->vif = vif; | ||
510 | te_data->duration = MSEC_TO_TU(duration); | ||
511 | |||
512 | spin_lock_bh(&mvm->time_event_lock); | ||
513 | te_data->id = le32_to_cpu(time_cmd.id); | ||
514 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
515 | spin_unlock_bh(&mvm->time_event_lock); | ||
516 | |||
517 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
518 | sizeof(time_cmd), &time_cmd); | ||
519 | if (ret) { | ||
520 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||
521 | goto out_remove_notif; | ||
522 | } | ||
523 | |||
524 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); | ||
525 | if (ret) { | ||
526 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
527 | iwl_mvm_te_clear_data(mvm, te_data); | ||
528 | } | ||
529 | |||
530 | return ret; | ||
531 | |||
532 | out_remove_notif: | ||
533 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
534 | return ret; | ||
535 | } | 477 | } |
536 | 478 | ||
537 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | 479 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index cada8efe0cca..6b67ce3f679c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -620,7 +620,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); | 620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); |
621 | } | 621 | } |
622 | 622 | ||
623 | ieee80211_tx_status(mvm->hw, skb); | 623 | ieee80211_tx_status_ni(mvm->hw, skb); |
624 | } | 624 | } |
625 | 625 | ||
626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | 626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { |
@@ -663,12 +663,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
663 | struct iwl_mvm_tid_data *tid_data = | 663 | struct iwl_mvm_tid_data *tid_data = |
664 | &mvmsta->tid_data[tid]; | 664 | &mvmsta->tid_data[tid]; |
665 | 665 | ||
666 | spin_lock(&mvmsta->lock); | 666 | spin_lock_bh(&mvmsta->lock); |
667 | tid_data->next_reclaimed = next_reclaimed; | 667 | tid_data->next_reclaimed = next_reclaimed; |
668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", | 668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", |
669 | next_reclaimed); | 669 | next_reclaimed); |
670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | 670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); |
671 | spin_unlock(&mvmsta->lock); | 671 | spin_unlock_bh(&mvmsta->lock); |
672 | } | 672 | } |
673 | 673 | ||
674 | #ifdef CONFIG_PM_SLEEP | 674 | #ifdef CONFIG_PM_SLEEP |
@@ -832,7 +832,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
832 | return 0; | 832 | return 0; |
833 | } | 833 | } |
834 | 834 | ||
835 | spin_lock(&mvmsta->lock); | 835 | spin_lock_bh(&mvmsta->lock); |
836 | 836 | ||
837 | __skb_queue_head_init(&reclaimed_skbs); | 837 | __skb_queue_head_init(&reclaimed_skbs); |
838 | 838 | ||
@@ -886,13 +886,13 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
886 | } | 886 | } |
887 | } | 887 | } |
888 | 888 | ||
889 | spin_unlock(&mvmsta->lock); | 889 | spin_unlock_bh(&mvmsta->lock); |
890 | 890 | ||
891 | rcu_read_unlock(); | 891 | rcu_read_unlock(); |
892 | 892 | ||
893 | while (!skb_queue_empty(&reclaimed_skbs)) { | 893 | while (!skb_queue_empty(&reclaimed_skbs)) { |
894 | skb = __skb_dequeue(&reclaimed_skbs); | 894 | skb = __skb_dequeue(&reclaimed_skbs); |
895 | ieee80211_tx_status(mvm->hw, skb); | 895 | ieee80211_tx_status_ni(mvm->hw, skb); |
896 | } | 896 | } |
897 | 897 | ||
898 | return 0; | 898 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 5f6bb4e09d42..aa2a39a637dd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -249,7 +249,6 @@ struct iwl_trans_pcie { | |||
249 | int ict_index; | 249 | int ict_index; |
250 | u32 inta; | 250 | u32 inta; |
251 | bool use_ict; | 251 | bool use_ict; |
252 | struct tasklet_struct irq_tasklet; | ||
253 | struct isr_statistics isr_stats; | 252 | struct isr_statistics isr_stats; |
254 | 253 | ||
255 | spinlock_t irq_lock; | 254 | spinlock_t irq_lock; |
@@ -330,7 +329,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); | |||
330 | * RX | 329 | * RX |
331 | ******************************************************/ | 330 | ******************************************************/ |
332 | int iwl_pcie_rx_init(struct iwl_trans *trans); | 331 | int iwl_pcie_rx_init(struct iwl_trans *trans); |
333 | void iwl_pcie_tasklet(struct iwl_trans *trans); | 332 | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); |
334 | int iwl_pcie_rx_stop(struct iwl_trans *trans); | 333 | int iwl_pcie_rx_stop(struct iwl_trans *trans); |
335 | void iwl_pcie_rx_free(struct iwl_trans *trans); | 334 | void iwl_pcie_rx_free(struct iwl_trans *trans); |
336 | 335 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a9ca1d35fa93..b0ae06d2456f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -81,10 +81,10 @@ | |||
81 | * 'processed' and 'read' driver indexes as well) | 81 | * 'processed' and 'read' driver indexes as well) |
82 | * + A received packet is processed and handed to the kernel network stack, | 82 | * + A received packet is processed and handed to the kernel network stack, |
83 | * detached from the iwl->rxq. The driver 'processed' index is updated. | 83 | * detached from the iwl->rxq. The driver 'processed' index is updated. |
84 | * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free | 84 | * + The Host/Firmware iwl->rxq is replenished at irq thread time from the |
85 | * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ | 85 | * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, |
86 | * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there | 86 | * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. |
87 | * were enough free buffers and RX_STALLED is set it is cleared. | 87 | * If there were enough free buffers and RX_STALLED is set it is cleared. |
88 | * | 88 | * |
89 | * | 89 | * |
90 | * Driver sequence: | 90 | * Driver sequence: |
@@ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) | |||
214 | /* | 214 | /* |
215 | * If the device isn't enabled - not need to try to add buffers... | 215 | * If the device isn't enabled - not need to try to add buffers... |
216 | * This can happen when we stop the device and still have an interrupt | 216 | * This can happen when we stop the device and still have an interrupt |
217 | * pending. We stop the APM before we sync the interrupts / tasklets | 217 | * pending. We stop the APM before we sync the interrupts because we |
218 | * because we have to (see comment there). On the other hand, since | 218 | * have to (see comment there). On the other hand, since the APM is |
219 | * the APM is stopped, we cannot access the HW (in particular not prph). | 219 | * stopped, we cannot access the HW (in particular not prph). |
220 | * So don't try to restock if the APM has been already stopped. | 220 | * So don't try to restock if the APM has been already stopped. |
221 | */ | 221 | */ |
222 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) | 222 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) |
@@ -796,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) | |||
796 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); | 796 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); |
797 | wake_up(&trans_pcie->wait_command_queue); | 797 | wake_up(&trans_pcie->wait_command_queue); |
798 | 798 | ||
799 | local_bh_disable(); | ||
799 | iwl_op_mode_nic_error(trans->op_mode); | 800 | iwl_op_mode_nic_error(trans->op_mode); |
801 | local_bh_enable(); | ||
800 | } | 802 | } |
801 | 803 | ||
802 | void iwl_pcie_tasklet(struct iwl_trans *trans) | 804 | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) |
803 | { | 805 | { |
806 | struct iwl_trans *trans = dev_id; | ||
804 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 807 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
805 | struct isr_statistics *isr_stats = &trans_pcie->isr_stats; | 808 | struct isr_statistics *isr_stats = &trans_pcie->isr_stats; |
806 | u32 inta = 0; | 809 | u32 inta = 0; |
@@ -811,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
811 | u32 inta_mask; | 814 | u32 inta_mask; |
812 | #endif | 815 | #endif |
813 | 816 | ||
817 | lock_map_acquire(&trans->sync_cmd_lockdep_map); | ||
818 | |||
814 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); | 819 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); |
815 | 820 | ||
816 | /* Ack/clear/reset pending uCode interrupts. | 821 | /* Ack/clear/reset pending uCode interrupts. |
@@ -855,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
855 | 860 | ||
856 | handled |= CSR_INT_BIT_HW_ERR; | 861 | handled |= CSR_INT_BIT_HW_ERR; |
857 | 862 | ||
858 | return; | 863 | goto out; |
859 | } | 864 | } |
860 | 865 | ||
861 | #ifdef CONFIG_IWLWIFI_DEBUG | 866 | #ifdef CONFIG_IWLWIFI_DEBUG |
@@ -1005,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
1005 | /* Re-enable RF_KILL if it occurred */ | 1010 | /* Re-enable RF_KILL if it occurred */ |
1006 | else if (handled & CSR_INT_BIT_RF_KILL) | 1011 | else if (handled & CSR_INT_BIT_RF_KILL) |
1007 | iwl_enable_rfkill_int(trans); | 1012 | iwl_enable_rfkill_int(trans); |
1013 | |||
1014 | out: | ||
1015 | lock_map_release(&trans->sync_cmd_lockdep_map); | ||
1016 | return IRQ_HANDLED; | ||
1008 | } | 1017 | } |
1009 | 1018 | ||
1010 | /****************************************************************************** | 1019 | /****************************************************************************** |
@@ -1127,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1127 | 1136 | ||
1128 | /* Disable (but don't clear!) interrupts here to avoid | 1137 | /* Disable (but don't clear!) interrupts here to avoid |
1129 | * back-to-back ISRs and sporadic interrupts from our NIC. | 1138 | * back-to-back ISRs and sporadic interrupts from our NIC. |
1130 | * If we have something to service, the tasklet will re-enable ints. | 1139 | * If we have something to service, the irq thread will re-enable ints. |
1131 | * If we *don't* have something, we'll re-enable before leaving here. */ | 1140 | * If we *don't* have something, we'll re-enable before leaving here. */ |
1132 | inta_mask = iwl_read32(trans, CSR_INT_MASK); | 1141 | inta_mask = iwl_read32(trans, CSR_INT_MASK); |
1133 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); | 1142 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); |
@@ -1167,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1167 | #endif | 1176 | #endif |
1168 | 1177 | ||
1169 | trans_pcie->inta |= inta; | 1178 | trans_pcie->inta |= inta; |
1170 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 1179 | /* the thread will service interrupts and re-enable them */ |
1171 | if (likely(inta)) | 1180 | if (likely(inta)) |
1172 | tasklet_schedule(&trans_pcie->irq_tasklet); | 1181 | return IRQ_WAKE_THREAD; |
1173 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1182 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && |
1174 | !trans_pcie->inta) | 1183 | !trans_pcie->inta) |
1175 | iwl_enable_interrupts(trans); | 1184 | iwl_enable_interrupts(trans); |
@@ -1277,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) | |||
1277 | trans_pcie->inta |= inta; | 1286 | trans_pcie->inta |= inta; |
1278 | 1287 | ||
1279 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 1288 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ |
1280 | if (likely(inta)) | 1289 | if (likely(inta)) { |
1281 | tasklet_schedule(&trans_pcie->irq_tasklet); | 1290 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
1282 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1291 | return IRQ_WAKE_THREAD; |
1292 | } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||
1283 | !trans_pcie->inta) { | 1293 | !trans_pcie->inta) { |
1284 | /* Allow interrupt if was disabled by this handler and | 1294 | /* Allow interrupt if was disabled by this handler and |
1285 | * no tasklet was schedules, We should not enable interrupt, | 1295 | * no tasklet was schedules, We should not enable interrupt, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 56d4f72500bc..17bedc50e753 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -760,7 +760,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) | |||
760 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 760 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
761 | 761 | ||
762 | synchronize_irq(trans_pcie->pci_dev->irq); | 762 | synchronize_irq(trans_pcie->pci_dev->irq); |
763 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
764 | 763 | ||
765 | iwl_pcie_tx_free(trans); | 764 | iwl_pcie_tx_free(trans); |
766 | iwl_pcie_rx_free(trans); | 765 | iwl_pcie_rx_free(trans); |
@@ -1480,6 +1479,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1480 | 1479 | ||
1481 | trans->ops = &trans_ops_pcie; | 1480 | trans->ops = &trans_ops_pcie; |
1482 | trans->cfg = cfg; | 1481 | trans->cfg = cfg; |
1482 | trans_lockdep_init(trans); | ||
1483 | trans_pcie->trans = trans; | 1483 | trans_pcie->trans = trans; |
1484 | spin_lock_init(&trans_pcie->irq_lock); | 1484 | spin_lock_init(&trans_pcie->irq_lock); |
1485 | spin_lock_init(&trans_pcie->reg_lock); | 1485 | spin_lock_init(&trans_pcie->reg_lock); |
@@ -1567,15 +1567,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1567 | 1567 | ||
1568 | trans_pcie->inta_mask = CSR_INI_SET_MASK; | 1568 | trans_pcie->inta_mask = CSR_INI_SET_MASK; |
1569 | 1569 | ||
1570 | tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) | ||
1571 | iwl_pcie_tasklet, (unsigned long)trans); | ||
1572 | |||
1573 | if (iwl_pcie_alloc_ict(trans)) | 1570 | if (iwl_pcie_alloc_ict(trans)) |
1574 | goto out_free_cmd_pool; | 1571 | goto out_free_cmd_pool; |
1575 | 1572 | ||
1576 | err = request_irq(pdev->irq, iwl_pcie_isr_ict, | 1573 | if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, |
1577 | IRQF_SHARED, DRV_NAME, trans); | 1574 | iwl_pcie_irq_handler, |
1578 | if (err) { | 1575 | IRQF_SHARED, DRV_NAME, trans)) { |
1579 | IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); | 1576 | IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); |
1580 | goto out_free_ict; | 1577 | goto out_free_ict; |
1581 | } | 1578 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 041127ad372a..8e9e3212fe78 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -926,7 +926,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
926 | if (WARN_ON(txq_id == trans_pcie->cmd_queue)) | 926 | if (WARN_ON(txq_id == trans_pcie->cmd_queue)) |
927 | return; | 927 | return; |
928 | 928 | ||
929 | spin_lock(&txq->lock); | 929 | spin_lock_bh(&txq->lock); |
930 | 930 | ||
931 | if (txq->q.read_ptr == tfd_num) | 931 | if (txq->q.read_ptr == tfd_num) |
932 | goto out; | 932 | goto out; |
@@ -970,7 +970,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
970 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) | 970 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) |
971 | iwl_wake_queue(trans, txq); | 971 | iwl_wake_queue(trans, txq); |
972 | out: | 972 | out: |
973 | spin_unlock(&txq->lock); | 973 | spin_unlock_bh(&txq->lock); |
974 | } | 974 | } |
975 | 975 | ||
976 | /* | 976 | /* |
@@ -1371,7 +1371,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1371 | return; | 1371 | return; |
1372 | } | 1372 | } |
1373 | 1373 | ||
1374 | spin_lock(&txq->lock); | 1374 | spin_lock_bh(&txq->lock); |
1375 | 1375 | ||
1376 | cmd_index = get_cmd_index(&txq->q, index); | 1376 | cmd_index = get_cmd_index(&txq->q, index); |
1377 | cmd = txq->entries[cmd_index].cmd; | 1377 | cmd = txq->entries[cmd_index].cmd; |
@@ -1405,7 +1405,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1405 | 1405 | ||
1406 | meta->flags = 0; | 1406 | meta->flags = 0; |
1407 | 1407 | ||
1408 | spin_unlock(&txq->lock); | 1408 | spin_unlock_bh(&txq->lock); |
1409 | } | 1409 | } |
1410 | 1410 | ||
1411 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | 1411 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) |
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index a7dcb2e5eccc..116f4aba08d6 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c | |||
@@ -657,7 +657,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, | |||
657 | capa, intvl, ie, ielen, | 657 | capa, intvl, ie, ielen, |
658 | LBS_SCAN_RSSI_TO_MBM(rssi), | 658 | LBS_SCAN_RSSI_TO_MBM(rssi), |
659 | GFP_KERNEL); | 659 | GFP_KERNEL); |
660 | cfg80211_put_bss(bss); | 660 | cfg80211_put_bss(wiphy, bss); |
661 | } | 661 | } |
662 | } else | 662 | } else |
663 | lbs_deb_scan("scan response: missing BSS channel IE\n"); | 663 | lbs_deb_scan("scan response: missing BSS channel IE\n"); |
@@ -1444,7 +1444,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, | |||
1444 | 1444 | ||
1445 | done: | 1445 | done: |
1446 | if (bss) | 1446 | if (bss) |
1447 | cfg80211_put_bss(bss); | 1447 | cfg80211_put_bss(wiphy, bss); |
1448 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | 1448 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); |
1449 | return ret; | 1449 | return ret; |
1450 | } | 1450 | } |
@@ -1766,7 +1766,7 @@ static void lbs_join_post(struct lbs_private *priv, | |||
1766 | params->beacon_interval, | 1766 | params->beacon_interval, |
1767 | fake_ie, fake - fake_ie, | 1767 | fake_ie, fake - fake_ie, |
1768 | 0, GFP_KERNEL); | 1768 | 0, GFP_KERNEL); |
1769 | cfg80211_put_bss(bss); | 1769 | cfg80211_put_bss(priv->wdev->wiphy, bss); |
1770 | 1770 | ||
1771 | memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); | 1771 | memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); |
1772 | priv->wdev->ssid_len = params->ssid_len; | 1772 | priv->wdev->ssid_len = params->ssid_len; |
@@ -2011,7 +2011,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, | |||
2011 | 2011 | ||
2012 | if (bss) { | 2012 | if (bss) { |
2013 | ret = lbs_ibss_join_existing(priv, params, bss); | 2013 | ret = lbs_ibss_join_existing(priv, params, bss); |
2014 | cfg80211_put_bss(bss); | 2014 | cfg80211_put_bss(wiphy, bss); |
2015 | } else | 2015 | } else |
2016 | ret = lbs_ibss_start_new(priv, params); | 2016 | ret = lbs_ibss_start_new(priv, params); |
2017 | 2017 | ||
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b73e497fe770..cffdf4fbf161 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -2247,6 +2247,7 @@ static int __init init_mac80211_hwsim(void) | |||
2247 | /* ask mac80211 to reserve space for magic */ | 2247 | /* ask mac80211 to reserve space for magic */ |
2248 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 2248 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); |
2249 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); | 2249 | hw->sta_data_size = sizeof(struct hwsim_sta_priv); |
2250 | hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); | ||
2250 | 2251 | ||
2251 | memcpy(data->channels_2ghz, hwsim_channels_2ghz, | 2252 | memcpy(data->channels_2ghz, hwsim_channels_2ghz, |
2252 | sizeof(hwsim_channels_2ghz)); | 2253 | sizeof(hwsim_channels_2ghz)); |
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index b2e27723f801..4f614aad9ded 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig | |||
@@ -20,12 +20,12 @@ config MWIFIEX_SDIO | |||
20 | mwifiex_sdio. | 20 | mwifiex_sdio. |
21 | 21 | ||
22 | config MWIFIEX_PCIE | 22 | config MWIFIEX_PCIE |
23 | tristate "Marvell WiFi-Ex Driver for PCIE 8766" | 23 | tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897" |
24 | depends on MWIFIEX && PCI | 24 | depends on MWIFIEX && PCI |
25 | select FW_LOADER | 25 | select FW_LOADER |
26 | ---help--- | 26 | ---help--- |
27 | This adds support for wireless adapters based on Marvell | 27 | This adds support for wireless adapters based on Marvell |
28 | 8766 chipset with PCIe interface. | 28 | 8766/8897 chipsets with PCIe interface. |
29 | 29 | ||
30 | If you choose to build it as a module, it will be called | 30 | If you choose to build it as a module, it will be called |
31 | mwifiex_pcie. | 31 | mwifiex_pcie. |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 8ba48192cd2f..dc5357c0098f 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -1430,7 +1430,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | |||
1430 | bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, | 1430 | bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, |
1431 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, | 1431 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, |
1432 | 0, ie_buf, ie_len, 0, GFP_KERNEL); | 1432 | 0, ie_buf, ie_len, 0, GFP_KERNEL); |
1433 | cfg80211_put_bss(bss); | 1433 | cfg80211_put_bss(priv->wdev->wiphy, bss); |
1434 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); | 1434 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); |
1435 | 1435 | ||
1436 | return 0; | 1436 | return 0; |
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index df88e65595c8..492655c048d1 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c | |||
@@ -62,6 +62,10 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) | |||
62 | { | 62 | { |
63 | u32 *cookie_addr; | 63 | u32 *cookie_addr; |
64 | struct pcie_service_card *card = adapter->card; | 64 | struct pcie_service_card *card = adapter->card; |
65 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
66 | |||
67 | if (!reg->sleep_cookie) | ||
68 | return true; | ||
65 | 69 | ||
66 | if (card->sleep_cookie_vbase) { | 70 | if (card->sleep_cookie_vbase) { |
67 | cookie_addr = (u32 *)card->sleep_cookie_vbase; | 71 | cookie_addr = (u32 *)card->sleep_cookie_vbase; |
@@ -94,6 +98,13 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, | |||
94 | 98 | ||
95 | card->dev = pdev; | 99 | card->dev = pdev; |
96 | 100 | ||
101 | if (ent->driver_data) { | ||
102 | struct mwifiex_pcie_device *data = (void *)ent->driver_data; | ||
103 | card->pcie.firmware = data->firmware; | ||
104 | card->pcie.reg = data->reg; | ||
105 | card->pcie.blksz_fw_dl = data->blksz_fw_dl; | ||
106 | } | ||
107 | |||
97 | if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, | 108 | if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, |
98 | MWIFIEX_PCIE)) { | 109 | MWIFIEX_PCIE)) { |
99 | pr_err("%s failed\n", __func__); | 110 | pr_err("%s failed\n", __func__); |
@@ -230,13 +241,16 @@ static int mwifiex_pcie_resume(struct pci_dev *pdev) | |||
230 | return 0; | 241 | return 0; |
231 | } | 242 | } |
232 | 243 | ||
233 | #define PCIE_VENDOR_ID_MARVELL (0x11ab) | ||
234 | #define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) | ||
235 | |||
236 | static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { | 244 | static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { |
237 | { | 245 | { |
238 | PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, | 246 | PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, |
239 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 247 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
248 | .driver_data = (unsigned long) &mwifiex_pcie8766, | ||
249 | }, | ||
250 | { | ||
251 | PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897, | ||
252 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
253 | .driver_data = (unsigned long) &mwifiex_pcie8897, | ||
240 | }, | 254 | }, |
241 | {}, | 255 | {}, |
242 | }; | 256 | }; |
@@ -289,8 +303,10 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data) | |||
289 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) | 303 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) |
290 | { | 304 | { |
291 | int i = 0; | 305 | int i = 0; |
306 | struct pcie_service_card *card = adapter->card; | ||
307 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
292 | 308 | ||
293 | while (mwifiex_pcie_ok_to_access_hw(adapter)) { | 309 | while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) { |
294 | i++; | 310 | i++; |
295 | usleep_range(10, 20); | 311 | usleep_range(10, 20); |
296 | /* 50ms max wait */ | 312 | /* 50ms max wait */ |
@@ -364,25 +380,268 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter) | |||
364 | } | 380 | } |
365 | 381 | ||
366 | /* | 382 | /* |
367 | * This function creates buffer descriptor ring for TX | 383 | * This function initializes TX buffer ring descriptors |
368 | */ | 384 | */ |
369 | static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) | 385 | static int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter) |
386 | { | ||
387 | struct pcie_service_card *card = adapter->card; | ||
388 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
389 | struct mwifiex_pcie_buf_desc *desc; | ||
390 | struct mwifiex_pfu_buf_desc *desc2; | ||
391 | int i; | ||
392 | |||
393 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | ||
394 | card->tx_buf_list[i] = NULL; | ||
395 | if (reg->pfu_enabled) { | ||
396 | card->txbd_ring[i] = (void *)card->txbd_ring_vbase + | ||
397 | (sizeof(*desc2) * i); | ||
398 | desc2 = card->txbd_ring[i]; | ||
399 | memset(desc2, 0, sizeof(*desc2)); | ||
400 | } else { | ||
401 | card->txbd_ring[i] = (void *)card->txbd_ring_vbase + | ||
402 | (sizeof(*desc) * i); | ||
403 | desc = card->txbd_ring[i]; | ||
404 | memset(desc, 0, sizeof(*desc)); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /* This function initializes RX buffer ring descriptors. Each SKB is allocated | ||
412 | * here and after mapping PCI memory, its physical address is assigned to | ||
413 | * PCIE Rx buffer descriptor's physical address. | ||
414 | */ | ||
415 | static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) | ||
416 | { | ||
417 | struct pcie_service_card *card = adapter->card; | ||
418 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
419 | struct sk_buff *skb; | ||
420 | struct mwifiex_pcie_buf_desc *desc; | ||
421 | struct mwifiex_pfu_buf_desc *desc2; | ||
422 | dma_addr_t buf_pa; | ||
423 | int i; | ||
424 | |||
425 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | ||
426 | /* Allocate skb here so that firmware can DMA data from it */ | ||
427 | skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); | ||
428 | if (!skb) { | ||
429 | dev_err(adapter->dev, | ||
430 | "Unable to allocate skb for RX ring.\n"); | ||
431 | kfree(card->rxbd_ring_vbase); | ||
432 | return -ENOMEM; | ||
433 | } | ||
434 | |||
435 | if (mwifiex_map_pci_memory(adapter, skb, | ||
436 | MWIFIEX_RX_DATA_BUF_SIZE, | ||
437 | PCI_DMA_FROMDEVICE)) | ||
438 | return -1; | ||
439 | |||
440 | MWIFIEX_SKB_PACB(skb, &buf_pa); | ||
441 | |||
442 | dev_dbg(adapter->dev, | ||
443 | "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n", | ||
444 | skb, skb->len, skb->data, (u32)buf_pa, | ||
445 | (u32)((u64)buf_pa >> 32)); | ||
446 | |||
447 | card->rx_buf_list[i] = skb; | ||
448 | if (reg->pfu_enabled) { | ||
449 | card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase + | ||
450 | (sizeof(*desc2) * i); | ||
451 | desc2 = card->rxbd_ring[i]; | ||
452 | desc2->paddr = buf_pa; | ||
453 | desc2->len = (u16)skb->len; | ||
454 | desc2->frag_len = (u16)skb->len; | ||
455 | desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop; | ||
456 | desc2->offset = 0; | ||
457 | } else { | ||
458 | card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase + | ||
459 | (sizeof(*desc) * i)); | ||
460 | desc = card->rxbd_ring[i]; | ||
461 | desc->paddr = buf_pa; | ||
462 | desc->len = (u16)skb->len; | ||
463 | desc->flags = 0; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | /* This function initializes event buffer ring descriptors. Each SKB is | ||
471 | * allocated here and after mapping PCI memory, its physical address is assigned | ||
472 | * to PCIE Rx buffer descriptor's physical address | ||
473 | */ | ||
474 | static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) | ||
370 | { | 475 | { |
371 | struct pcie_service_card *card = adapter->card; | 476 | struct pcie_service_card *card = adapter->card; |
477 | struct mwifiex_evt_buf_desc *desc; | ||
478 | struct sk_buff *skb; | ||
479 | dma_addr_t buf_pa; | ||
372 | int i; | 480 | int i; |
373 | 481 | ||
482 | for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { | ||
483 | /* Allocate skb here so that firmware can DMA data from it */ | ||
484 | skb = dev_alloc_skb(MAX_EVENT_SIZE); | ||
485 | if (!skb) { | ||
486 | dev_err(adapter->dev, | ||
487 | "Unable to allocate skb for EVENT buf.\n"); | ||
488 | kfree(card->evtbd_ring_vbase); | ||
489 | return -ENOMEM; | ||
490 | } | ||
491 | skb_put(skb, MAX_EVENT_SIZE); | ||
492 | |||
493 | if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, | ||
494 | PCI_DMA_FROMDEVICE)) | ||
495 | return -1; | ||
496 | |||
497 | MWIFIEX_SKB_PACB(skb, &buf_pa); | ||
498 | |||
499 | dev_dbg(adapter->dev, | ||
500 | "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n", | ||
501 | skb, skb->len, skb->data, (u32)buf_pa, | ||
502 | (u32)((u64)buf_pa >> 32)); | ||
503 | |||
504 | card->evt_buf_list[i] = skb; | ||
505 | card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase + | ||
506 | (sizeof(*desc) * i)); | ||
507 | desc = card->evtbd_ring[i]; | ||
508 | desc->paddr = buf_pa; | ||
509 | desc->len = (u16)skb->len; | ||
510 | desc->flags = 0; | ||
511 | } | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* This function cleans up TX buffer rings. If any of the buffer list has valid | ||
517 | * SKB address, associated SKB is freed. | ||
518 | */ | ||
519 | static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter) | ||
520 | { | ||
521 | struct pcie_service_card *card = adapter->card; | ||
522 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
523 | struct sk_buff *skb; | ||
524 | struct mwifiex_pcie_buf_desc *desc; | ||
525 | struct mwifiex_pfu_buf_desc *desc2; | ||
526 | int i; | ||
527 | |||
528 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | ||
529 | if (reg->pfu_enabled) { | ||
530 | desc2 = card->txbd_ring[i]; | ||
531 | if (card->tx_buf_list[i]) { | ||
532 | skb = card->tx_buf_list[i]; | ||
533 | pci_unmap_single(card->dev, desc2->paddr, | ||
534 | skb->len, PCI_DMA_TODEVICE); | ||
535 | dev_kfree_skb_any(skb); | ||
536 | } | ||
537 | memset(desc2, 0, sizeof(*desc2)); | ||
538 | } else { | ||
539 | desc = card->txbd_ring[i]; | ||
540 | if (card->tx_buf_list[i]) { | ||
541 | skb = card->tx_buf_list[i]; | ||
542 | pci_unmap_single(card->dev, desc->paddr, | ||
543 | skb->len, PCI_DMA_TODEVICE); | ||
544 | dev_kfree_skb_any(skb); | ||
545 | } | ||
546 | memset(desc, 0, sizeof(*desc)); | ||
547 | } | ||
548 | card->tx_buf_list[i] = NULL; | ||
549 | } | ||
550 | |||
551 | return; | ||
552 | } | ||
553 | |||
554 | /* This function cleans up RX buffer rings. If any of the buffer list has valid | ||
555 | * SKB address, associated SKB is freed. | ||
556 | */ | ||
557 | static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter) | ||
558 | { | ||
559 | struct pcie_service_card *card = adapter->card; | ||
560 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
561 | struct mwifiex_pcie_buf_desc *desc; | ||
562 | struct mwifiex_pfu_buf_desc *desc2; | ||
563 | struct sk_buff *skb; | ||
564 | int i; | ||
565 | |||
566 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | ||
567 | if (reg->pfu_enabled) { | ||
568 | desc2 = card->rxbd_ring[i]; | ||
569 | if (card->rx_buf_list[i]) { | ||
570 | skb = card->rx_buf_list[i]; | ||
571 | pci_unmap_single(card->dev, desc2->paddr, | ||
572 | skb->len, PCI_DMA_TODEVICE); | ||
573 | dev_kfree_skb_any(skb); | ||
574 | } | ||
575 | memset(desc2, 0, sizeof(*desc2)); | ||
576 | } else { | ||
577 | desc = card->rxbd_ring[i]; | ||
578 | if (card->rx_buf_list[i]) { | ||
579 | skb = card->rx_buf_list[i]; | ||
580 | pci_unmap_single(card->dev, desc->paddr, | ||
581 | skb->len, PCI_DMA_TODEVICE); | ||
582 | dev_kfree_skb_any(skb); | ||
583 | } | ||
584 | memset(desc, 0, sizeof(*desc)); | ||
585 | } | ||
586 | card->rx_buf_list[i] = NULL; | ||
587 | } | ||
588 | |||
589 | return; | ||
590 | } | ||
591 | |||
592 | /* This function cleans up event buffer rings. If any of the buffer list has | ||
593 | * valid SKB address, associated SKB is freed. | ||
594 | */ | ||
595 | static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter) | ||
596 | { | ||
597 | struct pcie_service_card *card = adapter->card; | ||
598 | struct mwifiex_evt_buf_desc *desc; | ||
599 | struct sk_buff *skb; | ||
600 | int i; | ||
601 | |||
602 | for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { | ||
603 | desc = card->evtbd_ring[i]; | ||
604 | if (card->evt_buf_list[i]) { | ||
605 | skb = card->evt_buf_list[i]; | ||
606 | pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE, | ||
607 | PCI_DMA_FROMDEVICE); | ||
608 | dev_kfree_skb_any(skb); | ||
609 | } | ||
610 | card->evt_buf_list[i] = NULL; | ||
611 | memset(desc, 0, sizeof(*desc)); | ||
612 | } | ||
613 | |||
614 | return; | ||
615 | } | ||
616 | |||
617 | /* This function creates buffer descriptor ring for TX | ||
618 | */ | ||
619 | static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) | ||
620 | { | ||
621 | struct pcie_service_card *card = adapter->card; | ||
622 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
623 | |||
374 | /* | 624 | /* |
375 | * driver maintaines the write pointer and firmware maintaines the read | 625 | * driver maintaines the write pointer and firmware maintaines the read |
376 | * pointer. The write pointer starts at 0 (zero) while the read pointer | 626 | * pointer. The write pointer starts at 0 (zero) while the read pointer |
377 | * starts at zero with rollover bit set | 627 | * starts at zero with rollover bit set |
378 | */ | 628 | */ |
379 | card->txbd_wrptr = 0; | 629 | card->txbd_wrptr = 0; |
380 | card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; | 630 | |
631 | if (reg->pfu_enabled) | ||
632 | card->txbd_rdptr = 0; | ||
633 | else | ||
634 | card->txbd_rdptr |= reg->tx_rollover_ind; | ||
381 | 635 | ||
382 | /* allocate shared memory for the BD ring and divide the same in to | 636 | /* allocate shared memory for the BD ring and divide the same in to |
383 | several descriptors */ | 637 | several descriptors */ |
384 | card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * | 638 | if (reg->pfu_enabled) |
385 | MWIFIEX_MAX_TXRX_BD; | 639 | card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) * |
640 | MWIFIEX_MAX_TXRX_BD; | ||
641 | else | ||
642 | card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * | ||
643 | MWIFIEX_MAX_TXRX_BD; | ||
644 | |||
386 | dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", | 645 | dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", |
387 | card->txbd_ring_size); | 646 | card->txbd_ring_size); |
388 | card->txbd_ring_vbase = pci_alloc_consistent(card->dev, | 647 | card->txbd_ring_vbase = pci_alloc_consistent(card->dev, |
@@ -399,40 +658,15 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) | |||
399 | card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase, | 658 | card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase, |
400 | (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size); | 659 | (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size); |
401 | 660 | ||
402 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | 661 | return mwifiex_init_txq_ring(adapter); |
403 | card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *) | ||
404 | (card->txbd_ring_vbase + | ||
405 | (sizeof(struct mwifiex_pcie_buf_desc) | ||
406 | * i)); | ||
407 | |||
408 | card->tx_buf_list[i] = NULL; | ||
409 | card->txbd_ring[i]->paddr = 0; | ||
410 | card->txbd_ring[i]->len = 0; | ||
411 | card->txbd_ring[i]->flags = 0; | ||
412 | } | ||
413 | |||
414 | return 0; | ||
415 | } | 662 | } |
416 | 663 | ||
417 | static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) | 664 | static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) |
418 | { | 665 | { |
419 | struct pcie_service_card *card = adapter->card; | 666 | struct pcie_service_card *card = adapter->card; |
420 | struct sk_buff *skb; | 667 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
421 | int i; | ||
422 | 668 | ||
423 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | 669 | mwifiex_cleanup_txq_ring(adapter); |
424 | if (card->tx_buf_list[i]) { | ||
425 | skb = card->tx_buf_list[i]; | ||
426 | pci_unmap_single(card->dev, card->txbd_ring[i]->paddr, | ||
427 | skb->len, PCI_DMA_TODEVICE); | ||
428 | dev_kfree_skb_any(skb); | ||
429 | } | ||
430 | card->tx_buf_list[i] = NULL; | ||
431 | card->txbd_ring[i]->paddr = 0; | ||
432 | card->txbd_ring[i]->len = 0; | ||
433 | card->txbd_ring[i]->flags = 0; | ||
434 | card->txbd_ring[i] = NULL; | ||
435 | } | ||
436 | 670 | ||
437 | if (card->txbd_ring_vbase) | 671 | if (card->txbd_ring_vbase) |
438 | pci_free_consistent(card->dev, card->txbd_ring_size, | 672 | pci_free_consistent(card->dev, card->txbd_ring_size, |
@@ -440,7 +674,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) | |||
440 | card->txbd_ring_pbase); | 674 | card->txbd_ring_pbase); |
441 | card->txbd_ring_size = 0; | 675 | card->txbd_ring_size = 0; |
442 | card->txbd_wrptr = 0; | 676 | card->txbd_wrptr = 0; |
443 | card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; | 677 | card->txbd_rdptr = 0 | reg->tx_rollover_ind; |
444 | card->txbd_ring_vbase = NULL; | 678 | card->txbd_ring_vbase = NULL; |
445 | card->txbd_ring_pbase = 0; | 679 | card->txbd_ring_pbase = 0; |
446 | 680 | ||
@@ -453,9 +687,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) | |||
453 | static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) | 687 | static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) |
454 | { | 688 | { |
455 | struct pcie_service_card *card = adapter->card; | 689 | struct pcie_service_card *card = adapter->card; |
456 | struct sk_buff *skb; | 690 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
457 | int i; | ||
458 | dma_addr_t buf_pa; | ||
459 | 691 | ||
460 | /* | 692 | /* |
461 | * driver maintaines the read pointer and firmware maintaines the write | 693 | * driver maintaines the read pointer and firmware maintaines the write |
@@ -463,10 +695,15 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) | |||
463 | * starts at zero with rollover bit set | 695 | * starts at zero with rollover bit set |
464 | */ | 696 | */ |
465 | card->rxbd_wrptr = 0; | 697 | card->rxbd_wrptr = 0; |
466 | card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; | 698 | card->rxbd_rdptr = reg->rx_rollover_ind; |
699 | |||
700 | if (reg->pfu_enabled) | ||
701 | card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) * | ||
702 | MWIFIEX_MAX_TXRX_BD; | ||
703 | else | ||
704 | card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * | ||
705 | MWIFIEX_MAX_TXRX_BD; | ||
467 | 706 | ||
468 | card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * | ||
469 | MWIFIEX_MAX_TXRX_BD; | ||
470 | dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", | 707 | dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", |
471 | card->rxbd_ring_size); | 708 | card->rxbd_ring_size); |
472 | card->rxbd_ring_vbase = pci_alloc_consistent(card->dev, | 709 | card->rxbd_ring_vbase = pci_alloc_consistent(card->dev, |
@@ -485,39 +722,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) | |||
485 | (u32)((u64)card->rxbd_ring_pbase >> 32), | 722 | (u32)((u64)card->rxbd_ring_pbase >> 32), |
486 | card->rxbd_ring_size); | 723 | card->rxbd_ring_size); |
487 | 724 | ||
488 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | 725 | return mwifiex_init_rxq_ring(adapter); |
489 | card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *) | ||
490 | (card->rxbd_ring_vbase + | ||
491 | (sizeof(struct mwifiex_pcie_buf_desc) | ||
492 | * i)); | ||
493 | |||
494 | /* Allocate skb here so that firmware can DMA data from it */ | ||
495 | skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); | ||
496 | if (!skb) { | ||
497 | dev_err(adapter->dev, | ||
498 | "Unable to allocate skb for RX ring.\n"); | ||
499 | kfree(card->rxbd_ring_vbase); | ||
500 | return -ENOMEM; | ||
501 | } | ||
502 | if (mwifiex_map_pci_memory(adapter, skb, | ||
503 | MWIFIEX_RX_DATA_BUF_SIZE, | ||
504 | PCI_DMA_FROMDEVICE)) | ||
505 | return -1; | ||
506 | |||
507 | MWIFIEX_SKB_PACB(skb, &buf_pa); | ||
508 | |||
509 | dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, " | ||
510 | "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", | ||
511 | skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), | ||
512 | skb->len); | ||
513 | |||
514 | card->rx_buf_list[i] = skb; | ||
515 | card->rxbd_ring[i]->paddr = buf_pa; | ||
516 | card->rxbd_ring[i]->len = (u16)skb->len; | ||
517 | card->rxbd_ring[i]->flags = 0; | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | 726 | } |
522 | 727 | ||
523 | /* | 728 | /* |
@@ -526,23 +731,9 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) | |||
526 | static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) | 731 | static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) |
527 | { | 732 | { |
528 | struct pcie_service_card *card = adapter->card; | 733 | struct pcie_service_card *card = adapter->card; |
529 | struct sk_buff *skb; | 734 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
530 | int i; | ||
531 | 735 | ||
532 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { | 736 | mwifiex_cleanup_rxq_ring(adapter); |
533 | if (card->rx_buf_list[i]) { | ||
534 | skb = card->rx_buf_list[i]; | ||
535 | pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr , | ||
536 | MWIFIEX_RX_DATA_BUF_SIZE, | ||
537 | PCI_DMA_FROMDEVICE); | ||
538 | dev_kfree_skb_any(skb); | ||
539 | } | ||
540 | card->rx_buf_list[i] = NULL; | ||
541 | card->rxbd_ring[i]->paddr = 0; | ||
542 | card->rxbd_ring[i]->len = 0; | ||
543 | card->rxbd_ring[i]->flags = 0; | ||
544 | card->rxbd_ring[i] = NULL; | ||
545 | } | ||
546 | 737 | ||
547 | if (card->rxbd_ring_vbase) | 738 | if (card->rxbd_ring_vbase) |
548 | pci_free_consistent(card->dev, card->rxbd_ring_size, | 739 | pci_free_consistent(card->dev, card->rxbd_ring_size, |
@@ -550,7 +741,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) | |||
550 | card->rxbd_ring_pbase); | 741 | card->rxbd_ring_pbase); |
551 | card->rxbd_ring_size = 0; | 742 | card->rxbd_ring_size = 0; |
552 | card->rxbd_wrptr = 0; | 743 | card->rxbd_wrptr = 0; |
553 | card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; | 744 | card->rxbd_rdptr = 0 | reg->rx_rollover_ind; |
554 | card->rxbd_ring_vbase = NULL; | 745 | card->rxbd_ring_vbase = NULL; |
555 | card->rxbd_ring_pbase = 0; | 746 | card->rxbd_ring_pbase = 0; |
556 | 747 | ||
@@ -563,9 +754,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) | |||
563 | static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) | 754 | static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) |
564 | { | 755 | { |
565 | struct pcie_service_card *card = adapter->card; | 756 | struct pcie_service_card *card = adapter->card; |
566 | struct sk_buff *skb; | 757 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
567 | int i; | ||
568 | dma_addr_t buf_pa; | ||
569 | 758 | ||
570 | /* | 759 | /* |
571 | * driver maintaines the read pointer and firmware maintaines the write | 760 | * driver maintaines the read pointer and firmware maintaines the write |
@@ -573,10 +762,11 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) | |||
573 | * starts at zero with rollover bit set | 762 | * starts at zero with rollover bit set |
574 | */ | 763 | */ |
575 | card->evtbd_wrptr = 0; | 764 | card->evtbd_wrptr = 0; |
576 | card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; | 765 | card->evtbd_rdptr = reg->evt_rollover_ind; |
766 | |||
767 | card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) * | ||
768 | MWIFIEX_MAX_EVT_BD; | ||
577 | 769 | ||
578 | card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * | ||
579 | MWIFIEX_MAX_EVT_BD; | ||
580 | dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", | 770 | dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", |
581 | card->evtbd_ring_size); | 771 | card->evtbd_ring_size); |
582 | card->evtbd_ring_vbase = pci_alloc_consistent(card->dev, | 772 | card->evtbd_ring_vbase = pci_alloc_consistent(card->dev, |
@@ -595,39 +785,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) | |||
595 | (u32)((u64)card->evtbd_ring_pbase >> 32), | 785 | (u32)((u64)card->evtbd_ring_pbase >> 32), |
596 | card->evtbd_ring_size); | 786 | card->evtbd_ring_size); |
597 | 787 | ||
598 | for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { | 788 | return mwifiex_pcie_init_evt_ring(adapter); |
599 | card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *) | ||
600 | (card->evtbd_ring_vbase + | ||
601 | (sizeof(struct mwifiex_pcie_buf_desc) | ||
602 | * i)); | ||
603 | |||
604 | /* Allocate skb here so that firmware can DMA data from it */ | ||
605 | skb = dev_alloc_skb(MAX_EVENT_SIZE); | ||
606 | if (!skb) { | ||
607 | dev_err(adapter->dev, | ||
608 | "Unable to allocate skb for EVENT buf.\n"); | ||
609 | kfree(card->evtbd_ring_vbase); | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | skb_put(skb, MAX_EVENT_SIZE); | ||
613 | |||
614 | if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, | ||
615 | PCI_DMA_FROMDEVICE)) | ||
616 | return -1; | ||
617 | |||
618 | MWIFIEX_SKB_PACB(skb, &buf_pa); | ||
619 | dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, " | ||
620 | "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", | ||
621 | skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), | ||
622 | skb->len); | ||
623 | |||
624 | card->evt_buf_list[i] = skb; | ||
625 | card->evtbd_ring[i]->paddr = buf_pa; | ||
626 | card->evtbd_ring[i]->len = (u16)skb->len; | ||
627 | card->evtbd_ring[i]->flags = 0; | ||
628 | } | ||
629 | |||
630 | return 0; | ||
631 | } | 789 | } |
632 | 790 | ||
633 | /* | 791 | /* |
@@ -636,29 +794,16 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) | |||
636 | static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) | 794 | static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) |
637 | { | 795 | { |
638 | struct pcie_service_card *card = adapter->card; | 796 | struct pcie_service_card *card = adapter->card; |
639 | struct sk_buff *skb; | 797 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
640 | int i; | ||
641 | 798 | ||
642 | for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { | 799 | mwifiex_cleanup_evt_ring(adapter); |
643 | if (card->evt_buf_list[i]) { | ||
644 | skb = card->evt_buf_list[i]; | ||
645 | pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr, | ||
646 | MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE); | ||
647 | dev_kfree_skb_any(skb); | ||
648 | } | ||
649 | card->evt_buf_list[i] = NULL; | ||
650 | card->evtbd_ring[i]->paddr = 0; | ||
651 | card->evtbd_ring[i]->len = 0; | ||
652 | card->evtbd_ring[i]->flags = 0; | ||
653 | card->evtbd_ring[i] = NULL; | ||
654 | } | ||
655 | 800 | ||
656 | if (card->evtbd_ring_vbase) | 801 | if (card->evtbd_ring_vbase) |
657 | pci_free_consistent(card->dev, card->evtbd_ring_size, | 802 | pci_free_consistent(card->dev, card->evtbd_ring_size, |
658 | card->evtbd_ring_vbase, | 803 | card->evtbd_ring_vbase, |
659 | card->evtbd_ring_pbase); | 804 | card->evtbd_ring_pbase); |
660 | card->evtbd_wrptr = 0; | 805 | card->evtbd_wrptr = 0; |
661 | card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; | 806 | card->evtbd_rdptr = 0 | reg->evt_rollover_ind; |
662 | card->evtbd_ring_size = 0; | 807 | card->evtbd_ring_size = 0; |
663 | card->evtbd_ring_vbase = NULL; | 808 | card->evtbd_ring_vbase = NULL; |
664 | card->evtbd_ring_pbase = 0; | 809 | card->evtbd_ring_pbase = 0; |
@@ -771,12 +916,13 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter) | |||
771 | static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) | 916 | static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) |
772 | { | 917 | { |
773 | struct pcie_service_card *card = adapter->card; | 918 | struct pcie_service_card *card = adapter->card; |
919 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
774 | u32 rdptr; | 920 | u32 rdptr; |
775 | 921 | ||
776 | /* Read the TX ring read pointer set by firmware */ | 922 | /* Read the TX ring read pointer set by firmware */ |
777 | if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { | 923 | if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) { |
778 | dev_err(adapter->dev, | 924 | dev_err(adapter->dev, |
779 | "Flush TXBD: failed to read REG_TXBD_RDPTR\n"); | 925 | "Flush TXBD: failed to read reg->tx_rdptr\n"); |
780 | return -1; | 926 | return -1; |
781 | } | 927 | } |
782 | 928 | ||
@@ -800,31 +946,35 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) | |||
800 | */ | 946 | */ |
801 | static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) | 947 | static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) |
802 | { | 948 | { |
803 | const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD; | ||
804 | struct sk_buff *skb; | 949 | struct sk_buff *skb; |
805 | dma_addr_t buf_pa; | 950 | dma_addr_t buf_pa; |
806 | u32 wrdoneidx, rdptr, unmap_count = 0; | 951 | u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0; |
952 | struct mwifiex_pcie_buf_desc *desc; | ||
953 | struct mwifiex_pfu_buf_desc *desc2; | ||
807 | struct pcie_service_card *card = adapter->card; | 954 | struct pcie_service_card *card = adapter->card; |
955 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
808 | 956 | ||
809 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) | 957 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) |
810 | mwifiex_pm_wakeup_card(adapter); | 958 | mwifiex_pm_wakeup_card(adapter); |
811 | 959 | ||
812 | /* Read the TX ring read pointer set by firmware */ | 960 | /* Read the TX ring read pointer set by firmware */ |
813 | if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { | 961 | if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) { |
814 | dev_err(adapter->dev, | 962 | dev_err(adapter->dev, |
815 | "SEND COMP: failed to read REG_TXBD_RDPTR\n"); | 963 | "SEND COMP: failed to read reg->tx_rdptr\n"); |
816 | return -1; | 964 | return -1; |
817 | } | 965 | } |
818 | 966 | ||
819 | dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n", | 967 | dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n", |
820 | card->txbd_rdptr, rdptr); | 968 | card->txbd_rdptr, rdptr); |
821 | 969 | ||
970 | num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr; | ||
822 | /* free from previous txbd_rdptr to current txbd_rdptr */ | 971 | /* free from previous txbd_rdptr to current txbd_rdptr */ |
823 | while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) != | 972 | while (((card->txbd_rdptr & reg->tx_mask) != |
824 | (rdptr & MWIFIEX_TXBD_MASK)) || | 973 | (rdptr & reg->tx_mask)) || |
825 | ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | 974 | ((card->txbd_rdptr & reg->tx_rollover_ind) != |
826 | (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { | 975 | (rdptr & reg->tx_rollover_ind))) { |
827 | wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK; | 976 | wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >> |
977 | reg->tx_start_ptr; | ||
828 | 978 | ||
829 | skb = card->tx_buf_list[wrdoneidx]; | 979 | skb = card->tx_buf_list[wrdoneidx]; |
830 | if (skb) { | 980 | if (skb) { |
@@ -845,25 +995,38 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) | |||
845 | } | 995 | } |
846 | 996 | ||
847 | card->tx_buf_list[wrdoneidx] = NULL; | 997 | card->tx_buf_list[wrdoneidx] = NULL; |
848 | card->txbd_ring[wrdoneidx]->paddr = 0; | ||
849 | card->txbd_ring[wrdoneidx]->len = 0; | ||
850 | card->txbd_ring[wrdoneidx]->flags = 0; | ||
851 | card->txbd_rdptr++; | ||
852 | 998 | ||
853 | if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs) | 999 | if (reg->pfu_enabled) { |
1000 | desc2 = (void *)card->txbd_ring[wrdoneidx]; | ||
1001 | memset(desc2, 0, sizeof(*desc2)); | ||
1002 | } else { | ||
1003 | desc = card->txbd_ring[wrdoneidx]; | ||
1004 | memset(desc, 0, sizeof(*desc)); | ||
1005 | } | ||
1006 | switch (card->dev->device) { | ||
1007 | case PCIE_DEVICE_ID_MARVELL_88W8766P: | ||
1008 | card->txbd_rdptr++; | ||
1009 | break; | ||
1010 | case PCIE_DEVICE_ID_MARVELL_88W8897: | ||
1011 | card->txbd_rdptr += reg->ring_tx_start_ptr; | ||
1012 | break; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs) | ||
854 | card->txbd_rdptr = ((card->txbd_rdptr & | 1017 | card->txbd_rdptr = ((card->txbd_rdptr & |
855 | MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ | 1018 | reg->tx_rollover_ind) ^ |
856 | MWIFIEX_BD_FLAG_ROLLOVER_IND); | 1019 | reg->tx_rollover_ind); |
857 | } | 1020 | } |
858 | 1021 | ||
859 | if (unmap_count) | 1022 | if (unmap_count) |
860 | adapter->data_sent = false; | 1023 | adapter->data_sent = false; |
861 | 1024 | ||
862 | if (card->txbd_flush) { | 1025 | if (card->txbd_flush) { |
863 | if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == | 1026 | if (((card->txbd_wrptr & reg->tx_mask) == |
864 | (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) && | 1027 | (card->txbd_rdptr & reg->tx_mask)) && |
865 | ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | 1028 | ((card->txbd_wrptr & reg->tx_rollover_ind) != |
866 | (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | 1029 | (card->txbd_rdptr & reg->tx_rollover_ind))) |
867 | card->txbd_flush = 0; | 1030 | card->txbd_flush = 0; |
868 | else | 1031 | else |
869 | mwifiex_clean_pcie_ring_buf(adapter); | 1032 | mwifiex_clean_pcie_ring_buf(adapter); |
@@ -883,9 +1046,12 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, | |||
883 | struct mwifiex_tx_param *tx_param) | 1046 | struct mwifiex_tx_param *tx_param) |
884 | { | 1047 | { |
885 | struct pcie_service_card *card = adapter->card; | 1048 | struct pcie_service_card *card = adapter->card; |
886 | u32 wrindx; | 1049 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
1050 | u32 wrindx, num_tx_buffs, rx_val; | ||
887 | int ret; | 1051 | int ret; |
888 | dma_addr_t buf_pa; | 1052 | dma_addr_t buf_pa; |
1053 | struct mwifiex_pcie_buf_desc *desc; | ||
1054 | struct mwifiex_pfu_buf_desc *desc2; | ||
889 | __le16 *tmp; | 1055 | __le16 *tmp; |
890 | 1056 | ||
891 | if (!(skb->data && skb->len)) { | 1057 | if (!(skb->data && skb->len)) { |
@@ -897,6 +1063,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, | |||
897 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) | 1063 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) |
898 | mwifiex_pm_wakeup_card(adapter); | 1064 | mwifiex_pm_wakeup_card(adapter); |
899 | 1065 | ||
1066 | num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr; | ||
900 | dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", | 1067 | dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", |
901 | card->txbd_rdptr, card->txbd_wrptr); | 1068 | card->txbd_rdptr, card->txbd_wrptr); |
902 | if (mwifiex_pcie_txbd_not_full(card)) { | 1069 | if (mwifiex_pcie_txbd_not_full(card)) { |
@@ -913,25 +1080,46 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, | |||
913 | PCI_DMA_TODEVICE)) | 1080 | PCI_DMA_TODEVICE)) |
914 | return -1; | 1081 | return -1; |
915 | 1082 | ||
916 | wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; | 1083 | wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr; |
917 | MWIFIEX_SKB_PACB(skb, &buf_pa); | 1084 | MWIFIEX_SKB_PACB(skb, &buf_pa); |
918 | card->tx_buf_list[wrindx] = skb; | 1085 | card->tx_buf_list[wrindx] = skb; |
919 | card->txbd_ring[wrindx]->paddr = buf_pa; | ||
920 | card->txbd_ring[wrindx]->len = (u16)skb->len; | ||
921 | card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | | ||
922 | MWIFIEX_BD_FLAG_LAST_DESC; | ||
923 | 1086 | ||
924 | if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) == | 1087 | if (reg->pfu_enabled) { |
925 | MWIFIEX_MAX_TXRX_BD) | 1088 | desc2 = (void *)card->txbd_ring[wrindx]; |
1089 | desc2->paddr = buf_pa; | ||
1090 | desc2->len = (u16)skb->len; | ||
1091 | desc2->frag_len = (u16)skb->len; | ||
1092 | desc2->offset = 0; | ||
1093 | desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC | | ||
1094 | MWIFIEX_BD_FLAG_LAST_DESC; | ||
1095 | } else { | ||
1096 | desc = card->txbd_ring[wrindx]; | ||
1097 | desc->paddr = buf_pa; | ||
1098 | desc->len = (u16)skb->len; | ||
1099 | desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC | | ||
1100 | MWIFIEX_BD_FLAG_LAST_DESC; | ||
1101 | } | ||
1102 | |||
1103 | switch (card->dev->device) { | ||
1104 | case PCIE_DEVICE_ID_MARVELL_88W8766P: | ||
1105 | card->txbd_wrptr++; | ||
1106 | break; | ||
1107 | case PCIE_DEVICE_ID_MARVELL_88W8897: | ||
1108 | card->txbd_wrptr += reg->ring_tx_start_ptr; | ||
1109 | break; | ||
1110 | } | ||
1111 | |||
1112 | if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs) | ||
926 | card->txbd_wrptr = ((card->txbd_wrptr & | 1113 | card->txbd_wrptr = ((card->txbd_wrptr & |
927 | MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ | 1114 | reg->tx_rollover_ind) ^ |
928 | MWIFIEX_BD_FLAG_ROLLOVER_IND); | 1115 | reg->tx_rollover_ind); |
929 | 1116 | ||
930 | /* Write the TX ring write pointer in to REG_TXBD_WRPTR */ | 1117 | rx_val = card->rxbd_rdptr & reg->rx_wrap_mask; |
931 | if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR, | 1118 | /* Write the TX ring write pointer in to reg->tx_wrptr */ |
932 | card->txbd_wrptr)) { | 1119 | if (mwifiex_write_reg(adapter, reg->tx_wrptr, |
1120 | card->txbd_wrptr | rx_val)) { | ||
933 | dev_err(adapter->dev, | 1121 | dev_err(adapter->dev, |
934 | "SEND DATA: failed to write REG_TXBD_WRPTR\n"); | 1122 | "SEND DATA: failed to write reg->tx_wrptr\n"); |
935 | ret = -1; | 1123 | ret = -1; |
936 | goto done_unmap; | 1124 | goto done_unmap; |
937 | } | 1125 | } |
@@ -971,9 +1159,11 @@ done_unmap: | |||
971 | MWIFIEX_SKB_PACB(skb, &buf_pa); | 1159 | MWIFIEX_SKB_PACB(skb, &buf_pa); |
972 | pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE); | 1160 | pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE); |
973 | card->tx_buf_list[wrindx] = NULL; | 1161 | card->tx_buf_list[wrindx] = NULL; |
974 | card->txbd_ring[wrindx]->paddr = 0; | 1162 | if (reg->pfu_enabled) |
975 | card->txbd_ring[wrindx]->len = 0; | 1163 | memset(desc2, 0, sizeof(*desc2)); |
976 | card->txbd_ring[wrindx]->flags = 0; | 1164 | else |
1165 | memset(desc, 0, sizeof(*desc)); | ||
1166 | |||
977 | return ret; | 1167 | return ret; |
978 | } | 1168 | } |
979 | 1169 | ||
@@ -984,32 +1174,35 @@ done_unmap: | |||
984 | static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) | 1174 | static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) |
985 | { | 1175 | { |
986 | struct pcie_service_card *card = adapter->card; | 1176 | struct pcie_service_card *card = adapter->card; |
987 | u32 wrptr, rd_index; | 1177 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
1178 | u32 wrptr, rd_index, tx_val; | ||
988 | dma_addr_t buf_pa; | 1179 | dma_addr_t buf_pa; |
989 | int ret = 0; | 1180 | int ret = 0; |
990 | struct sk_buff *skb_tmp = NULL; | 1181 | struct sk_buff *skb_tmp = NULL; |
1182 | struct mwifiex_pcie_buf_desc *desc; | ||
1183 | struct mwifiex_pfu_buf_desc *desc2; | ||
991 | 1184 | ||
992 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) | 1185 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) |
993 | mwifiex_pm_wakeup_card(adapter); | 1186 | mwifiex_pm_wakeup_card(adapter); |
994 | 1187 | ||
995 | /* Read the RX ring Write pointer set by firmware */ | 1188 | /* Read the RX ring Write pointer set by firmware */ |
996 | if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { | 1189 | if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) { |
997 | dev_err(adapter->dev, | 1190 | dev_err(adapter->dev, |
998 | "RECV DATA: failed to read REG_TXBD_RDPTR\n"); | 1191 | "RECV DATA: failed to read reg->rx_wrptr\n"); |
999 | ret = -1; | 1192 | ret = -1; |
1000 | goto done; | 1193 | goto done; |
1001 | } | 1194 | } |
1002 | card->rxbd_wrptr = wrptr; | 1195 | card->rxbd_wrptr = wrptr; |
1003 | 1196 | ||
1004 | while (((wrptr & MWIFIEX_RXBD_MASK) != | 1197 | while (((wrptr & reg->rx_mask) != |
1005 | (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || | 1198 | (card->rxbd_rdptr & reg->rx_mask)) || |
1006 | ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == | 1199 | ((wrptr & reg->rx_rollover_ind) == |
1007 | (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { | 1200 | (card->rxbd_rdptr & reg->rx_rollover_ind))) { |
1008 | struct sk_buff *skb_data; | 1201 | struct sk_buff *skb_data; |
1009 | u16 rx_len; | 1202 | u16 rx_len; |
1010 | __le16 pkt_len; | 1203 | __le16 pkt_len; |
1011 | 1204 | ||
1012 | rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; | 1205 | rd_index = card->rxbd_rdptr & reg->rx_mask; |
1013 | skb_data = card->rx_buf_list[rd_index]; | 1206 | skb_data = card->rx_buf_list[rd_index]; |
1014 | 1207 | ||
1015 | MWIFIEX_SKB_PACB(skb_data, &buf_pa); | 1208 | MWIFIEX_SKB_PACB(skb_data, &buf_pa); |
@@ -1047,32 +1240,44 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) | |||
1047 | "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n", | 1240 | "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n", |
1048 | skb_tmp, rd_index); | 1241 | skb_tmp, rd_index); |
1049 | card->rx_buf_list[rd_index] = skb_tmp; | 1242 | card->rx_buf_list[rd_index] = skb_tmp; |
1050 | card->rxbd_ring[rd_index]->paddr = buf_pa; | ||
1051 | card->rxbd_ring[rd_index]->len = skb_tmp->len; | ||
1052 | card->rxbd_ring[rd_index]->flags = 0; | ||
1053 | 1243 | ||
1054 | if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == | 1244 | if (reg->pfu_enabled) { |
1245 | desc2 = (void *)card->rxbd_ring[rd_index]; | ||
1246 | desc2->paddr = buf_pa; | ||
1247 | desc2->len = skb_tmp->len; | ||
1248 | desc2->frag_len = skb_tmp->len; | ||
1249 | desc2->offset = 0; | ||
1250 | desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop; | ||
1251 | } else { | ||
1252 | desc = card->rxbd_ring[rd_index]; | ||
1253 | desc->paddr = buf_pa; | ||
1254 | desc->len = skb_tmp->len; | ||
1255 | desc->flags = 0; | ||
1256 | } | ||
1257 | |||
1258 | if ((++card->rxbd_rdptr & reg->rx_mask) == | ||
1055 | MWIFIEX_MAX_TXRX_BD) { | 1259 | MWIFIEX_MAX_TXRX_BD) { |
1056 | card->rxbd_rdptr = ((card->rxbd_rdptr & | 1260 | card->rxbd_rdptr = ((card->rxbd_rdptr & |
1057 | MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ | 1261 | reg->rx_rollover_ind) ^ |
1058 | MWIFIEX_BD_FLAG_ROLLOVER_IND); | 1262 | reg->rx_rollover_ind); |
1059 | } | 1263 | } |
1060 | dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n", | 1264 | dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n", |
1061 | card->rxbd_rdptr, wrptr); | 1265 | card->rxbd_rdptr, wrptr); |
1062 | 1266 | ||
1063 | /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ | 1267 | tx_val = card->txbd_wrptr & reg->tx_wrap_mask; |
1064 | if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, | 1268 | /* Write the RX ring read pointer in to reg->rx_rdptr */ |
1065 | card->rxbd_rdptr)) { | 1269 | if (mwifiex_write_reg(adapter, reg->rx_rdptr, |
1270 | card->rxbd_rdptr | tx_val)) { | ||
1066 | dev_err(adapter->dev, | 1271 | dev_err(adapter->dev, |
1067 | "RECV DATA: failed to write REG_RXBD_RDPTR\n"); | 1272 | "RECV DATA: failed to write reg->rx_rdptr\n"); |
1068 | ret = -1; | 1273 | ret = -1; |
1069 | goto done; | 1274 | goto done; |
1070 | } | 1275 | } |
1071 | 1276 | ||
1072 | /* Read the RX ring Write pointer set by firmware */ | 1277 | /* Read the RX ring Write pointer set by firmware */ |
1073 | if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { | 1278 | if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) { |
1074 | dev_err(adapter->dev, | 1279 | dev_err(adapter->dev, |
1075 | "RECV DATA: failed to read REG_TXBD_RDPTR\n"); | 1280 | "RECV DATA: failed to read reg->rx_wrptr\n"); |
1076 | ret = -1; | 1281 | ret = -1; |
1077 | goto done; | 1282 | goto done; |
1078 | } | 1283 | } |
@@ -1093,6 +1298,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1093 | { | 1298 | { |
1094 | dma_addr_t buf_pa; | 1299 | dma_addr_t buf_pa; |
1095 | struct pcie_service_card *card = adapter->card; | 1300 | struct pcie_service_card *card = adapter->card; |
1301 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1096 | 1302 | ||
1097 | if (!(skb->data && skb->len)) { | 1303 | if (!(skb->data && skb->len)) { |
1098 | dev_err(adapter->dev, | 1304 | dev_err(adapter->dev, |
@@ -1106,9 +1312,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1106 | 1312 | ||
1107 | MWIFIEX_SKB_PACB(skb, &buf_pa); | 1313 | MWIFIEX_SKB_PACB(skb, &buf_pa); |
1108 | 1314 | ||
1109 | /* Write the lower 32bits of the physical address to scratch | 1315 | /* Write the lower 32bits of the physical address to low command |
1110 | * register 0 */ | 1316 | * address scratch register |
1111 | if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) { | 1317 | */ |
1318 | if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) { | ||
1112 | dev_err(adapter->dev, | 1319 | dev_err(adapter->dev, |
1113 | "%s: failed to write download command to boot code.\n", | 1320 | "%s: failed to write download command to boot code.\n", |
1114 | __func__); | 1321 | __func__); |
@@ -1117,9 +1324,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1117 | return -1; | 1324 | return -1; |
1118 | } | 1325 | } |
1119 | 1326 | ||
1120 | /* Write the upper 32bits of the physical address to scratch | 1327 | /* Write the upper 32bits of the physical address to high command |
1121 | * register 1 */ | 1328 | * address scratch register |
1122 | if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG, | 1329 | */ |
1330 | if (mwifiex_write_reg(adapter, reg->cmd_addr_hi, | ||
1123 | (u32)((u64)buf_pa >> 32))) { | 1331 | (u32)((u64)buf_pa >> 32))) { |
1124 | dev_err(adapter->dev, | 1332 | dev_err(adapter->dev, |
1125 | "%s: failed to write download command to boot code.\n", | 1333 | "%s: failed to write download command to boot code.\n", |
@@ -1129,10 +1337,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1129 | return -1; | 1337 | return -1; |
1130 | } | 1338 | } |
1131 | 1339 | ||
1132 | /* Write the command length to scratch register 2 */ | 1340 | /* Write the command length to cmd_size scratch register */ |
1133 | if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) { | 1341 | if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) { |
1134 | dev_err(adapter->dev, | 1342 | dev_err(adapter->dev, |
1135 | "%s: failed to write command len to scratch reg 2\n", | 1343 | "%s: failed to write command len to cmd_size scratch reg\n", |
1136 | __func__); | 1344 | __func__); |
1137 | pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | 1345 | pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, |
1138 | PCI_DMA_TODEVICE); | 1346 | PCI_DMA_TODEVICE); |
@@ -1158,11 +1366,14 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1158 | static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) | 1366 | static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) |
1159 | { | 1367 | { |
1160 | struct pcie_service_card *card = adapter->card; | 1368 | struct pcie_service_card *card = adapter->card; |
1369 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1370 | int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; | ||
1161 | 1371 | ||
1162 | /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ | 1372 | /* Write the RX ring read pointer in to reg->rx_rdptr */ |
1163 | if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) { | 1373 | if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | |
1374 | tx_wrap)) { | ||
1164 | dev_err(adapter->dev, | 1375 | dev_err(adapter->dev, |
1165 | "RECV DATA: failed to write REG_RXBD_RDPTR\n"); | 1376 | "RECV DATA: failed to write reg->rx_rdptr\n"); |
1166 | return -1; | 1377 | return -1; |
1167 | } | 1378 | } |
1168 | return 0; | 1379 | return 0; |
@@ -1174,6 +1385,7 @@ static int | |||
1174 | mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | 1385 | mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) |
1175 | { | 1386 | { |
1176 | struct pcie_service_card *card = adapter->card; | 1387 | struct pcie_service_card *card = adapter->card; |
1388 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1177 | int ret = 0; | 1389 | int ret = 0; |
1178 | dma_addr_t cmd_buf_pa, cmdrsp_buf_pa; | 1390 | dma_addr_t cmd_buf_pa, cmdrsp_buf_pa; |
1179 | u8 *payload = (u8 *)skb->data; | 1391 | u8 *payload = (u8 *)skb->data; |
@@ -1206,7 +1418,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1206 | 1418 | ||
1207 | /* To send a command, the driver will: | 1419 | /* To send a command, the driver will: |
1208 | 1. Write the 64bit physical address of the data buffer to | 1420 | 1. Write the 64bit physical address of the data buffer to |
1209 | SCRATCH1 + SCRATCH0 | 1421 | cmd response address low + cmd response address high |
1210 | 2. Ring the door bell (i.e. set the door bell interrupt) | 1422 | 2. Ring the door bell (i.e. set the door bell interrupt) |
1211 | 1423 | ||
1212 | In response to door bell interrupt, the firmware will perform | 1424 | In response to door bell interrupt, the firmware will perform |
@@ -1218,7 +1430,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1218 | MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa); | 1430 | MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa); |
1219 | /* Write the lower 32bits of the cmdrsp buffer physical | 1431 | /* Write the lower 32bits of the cmdrsp buffer physical |
1220 | address */ | 1432 | address */ |
1221 | if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, | 1433 | if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, |
1222 | (u32)cmdrsp_buf_pa)) { | 1434 | (u32)cmdrsp_buf_pa)) { |
1223 | dev_err(adapter->dev, | 1435 | dev_err(adapter->dev, |
1224 | "Failed to write download cmd to boot code.\n"); | 1436 | "Failed to write download cmd to boot code.\n"); |
@@ -1227,7 +1439,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1227 | } | 1439 | } |
1228 | /* Write the upper 32bits of the cmdrsp buffer physical | 1440 | /* Write the upper 32bits of the cmdrsp buffer physical |
1229 | address */ | 1441 | address */ |
1230 | if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, | 1442 | if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, |
1231 | (u32)((u64)cmdrsp_buf_pa >> 32))) { | 1443 | (u32)((u64)cmdrsp_buf_pa >> 32))) { |
1232 | dev_err(adapter->dev, | 1444 | dev_err(adapter->dev, |
1233 | "Failed to write download cmd to boot code.\n"); | 1445 | "Failed to write download cmd to boot code.\n"); |
@@ -1237,15 +1449,16 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1237 | } | 1449 | } |
1238 | 1450 | ||
1239 | MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa); | 1451 | MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa); |
1240 | /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */ | 1452 | /* Write the lower 32bits of the physical address to reg->cmd_addr_lo */ |
1241 | if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) { | 1453 | if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, |
1454 | (u32)cmd_buf_pa)) { | ||
1242 | dev_err(adapter->dev, | 1455 | dev_err(adapter->dev, |
1243 | "Failed to write download cmd to boot code.\n"); | 1456 | "Failed to write download cmd to boot code.\n"); |
1244 | ret = -1; | 1457 | ret = -1; |
1245 | goto done; | 1458 | goto done; |
1246 | } | 1459 | } |
1247 | /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */ | 1460 | /* Write the upper 32bits of the physical address to reg->cmd_addr_hi */ |
1248 | if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI, | 1461 | if (mwifiex_write_reg(adapter, reg->cmd_addr_hi, |
1249 | (u32)((u64)cmd_buf_pa >> 32))) { | 1462 | (u32)((u64)cmd_buf_pa >> 32))) { |
1250 | dev_err(adapter->dev, | 1463 | dev_err(adapter->dev, |
1251 | "Failed to write download cmd to boot code.\n"); | 1464 | "Failed to write download cmd to boot code.\n"); |
@@ -1253,10 +1466,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
1253 | goto done; | 1466 | goto done; |
1254 | } | 1467 | } |
1255 | 1468 | ||
1256 | /* Write the command length to REG_CMD_SIZE */ | 1469 | /* Write the command length to reg->cmd_size */ |
1257 | if (mwifiex_write_reg(adapter, REG_CMD_SIZE, card->cmd_buf->len)) { | 1470 | if (mwifiex_write_reg(adapter, reg->cmd_size, |
1471 | card->cmd_buf->len)) { | ||
1258 | dev_err(adapter->dev, | 1472 | dev_err(adapter->dev, |
1259 | "Failed to write cmd len to REG_CMD_SIZE\n"); | 1473 | "Failed to write cmd len to reg->cmd_size\n"); |
1260 | ret = -1; | 1474 | ret = -1; |
1261 | goto done; | 1475 | goto done; |
1262 | } | 1476 | } |
@@ -1283,6 +1497,7 @@ done: | |||
1283 | static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) | 1497 | static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) |
1284 | { | 1498 | { |
1285 | struct pcie_service_card *card = adapter->card; | 1499 | struct pcie_service_card *card = adapter->card; |
1500 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1286 | struct sk_buff *skb = card->cmdrsp_buf; | 1501 | struct sk_buff *skb = card->cmdrsp_buf; |
1287 | int count = 0; | 1502 | int count = 0; |
1288 | u16 rx_len; | 1503 | u16 rx_len; |
@@ -1304,8 +1519,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) | |||
1304 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) { | 1519 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) { |
1305 | mwifiex_process_sleep_confirm_resp(adapter, skb->data, | 1520 | mwifiex_process_sleep_confirm_resp(adapter, skb->data, |
1306 | skb->len); | 1521 | skb->len); |
1307 | while (mwifiex_pcie_ok_to_access_hw(adapter) && | 1522 | while (reg->sleep_cookie && (count++ < 10) && |
1308 | (count++ < 10)) | 1523 | mwifiex_pcie_ok_to_access_hw(adapter)) |
1309 | usleep_range(50, 60); | 1524 | usleep_range(50, 60); |
1310 | } else { | 1525 | } else { |
1311 | dev_err(adapter->dev, | 1526 | dev_err(adapter->dev, |
@@ -1328,14 +1543,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) | |||
1328 | /* Clear the cmd-rsp buffer address in scratch registers. This | 1543 | /* Clear the cmd-rsp buffer address in scratch registers. This |
1329 | will prevent firmware from writing to the same response | 1544 | will prevent firmware from writing to the same response |
1330 | buffer again. */ | 1545 | buffer again. */ |
1331 | if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) { | 1546 | if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) { |
1332 | dev_err(adapter->dev, | 1547 | dev_err(adapter->dev, |
1333 | "cmd_done: failed to clear cmd_rsp_addr_lo\n"); | 1548 | "cmd_done: failed to clear cmd_rsp_addr_lo\n"); |
1334 | return -1; | 1549 | return -1; |
1335 | } | 1550 | } |
1336 | /* Write the upper 32bits of the cmdrsp buffer physical | 1551 | /* Write the upper 32bits of the cmdrsp buffer physical |
1337 | address */ | 1552 | address */ |
1338 | if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) { | 1553 | if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) { |
1339 | dev_err(adapter->dev, | 1554 | dev_err(adapter->dev, |
1340 | "cmd_done: failed to clear cmd_rsp_addr_hi\n"); | 1555 | "cmd_done: failed to clear cmd_rsp_addr_hi\n"); |
1341 | return -1; | 1556 | return -1; |
@@ -1380,9 +1595,11 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, | |||
1380 | static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) | 1595 | static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) |
1381 | { | 1596 | { |
1382 | struct pcie_service_card *card = adapter->card; | 1597 | struct pcie_service_card *card = adapter->card; |
1598 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1383 | u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; | 1599 | u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; |
1384 | u32 wrptr, event; | 1600 | u32 wrptr, event; |
1385 | dma_addr_t buf_pa; | 1601 | dma_addr_t buf_pa; |
1602 | struct mwifiex_evt_buf_desc *desc; | ||
1386 | 1603 | ||
1387 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) | 1604 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) |
1388 | mwifiex_pm_wakeup_card(adapter); | 1605 | mwifiex_pm_wakeup_card(adapter); |
@@ -1399,9 +1616,9 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) | |||
1399 | } | 1616 | } |
1400 | 1617 | ||
1401 | /* Read the event ring write pointer set by firmware */ | 1618 | /* Read the event ring write pointer set by firmware */ |
1402 | if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { | 1619 | if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) { |
1403 | dev_err(adapter->dev, | 1620 | dev_err(adapter->dev, |
1404 | "EventReady: failed to read REG_EVTBD_WRPTR\n"); | 1621 | "EventReady: failed to read reg->evt_wrptr\n"); |
1405 | return -1; | 1622 | return -1; |
1406 | } | 1623 | } |
1407 | 1624 | ||
@@ -1409,8 +1626,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) | |||
1409 | card->evtbd_rdptr, wrptr); | 1626 | card->evtbd_rdptr, wrptr); |
1410 | if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr | 1627 | if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr |
1411 | & MWIFIEX_EVTBD_MASK)) || | 1628 | & MWIFIEX_EVTBD_MASK)) || |
1412 | ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == | 1629 | ((wrptr & reg->evt_rollover_ind) == |
1413 | (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { | 1630 | (card->evtbd_rdptr & reg->evt_rollover_ind))) { |
1414 | struct sk_buff *skb_cmd; | 1631 | struct sk_buff *skb_cmd; |
1415 | __le16 data_len = 0; | 1632 | __le16 data_len = 0; |
1416 | u16 evt_len; | 1633 | u16 evt_len; |
@@ -1424,9 +1641,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) | |||
1424 | /* Take the pointer and set it to event pointer in adapter | 1641 | /* Take the pointer and set it to event pointer in adapter |
1425 | and will return back after event handling callback */ | 1642 | and will return back after event handling callback */ |
1426 | card->evt_buf_list[rdptr] = NULL; | 1643 | card->evt_buf_list[rdptr] = NULL; |
1427 | card->evtbd_ring[rdptr]->paddr = 0; | 1644 | desc = card->evtbd_ring[rdptr]; |
1428 | card->evtbd_ring[rdptr]->len = 0; | 1645 | memset(desc, 0, sizeof(*desc)); |
1429 | card->evtbd_ring[rdptr]->flags = 0; | ||
1430 | 1646 | ||
1431 | event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN]; | 1647 | event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN]; |
1432 | adapter->event_cause = event; | 1648 | adapter->event_cause = event; |
@@ -1462,10 +1678,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, | |||
1462 | struct sk_buff *skb) | 1678 | struct sk_buff *skb) |
1463 | { | 1679 | { |
1464 | struct pcie_service_card *card = adapter->card; | 1680 | struct pcie_service_card *card = adapter->card; |
1681 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1465 | int ret = 0; | 1682 | int ret = 0; |
1466 | u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; | 1683 | u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; |
1467 | u32 wrptr; | 1684 | u32 wrptr; |
1468 | dma_addr_t buf_pa; | 1685 | dma_addr_t buf_pa; |
1686 | struct mwifiex_evt_buf_desc *desc; | ||
1469 | 1687 | ||
1470 | if (!skb) | 1688 | if (!skb) |
1471 | return 0; | 1689 | return 0; |
@@ -1477,9 +1695,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, | |||
1477 | } | 1695 | } |
1478 | 1696 | ||
1479 | /* Read the event ring write pointer set by firmware */ | 1697 | /* Read the event ring write pointer set by firmware */ |
1480 | if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { | 1698 | if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) { |
1481 | dev_err(adapter->dev, | 1699 | dev_err(adapter->dev, |
1482 | "event_complete: failed to read REG_EVTBD_WRPTR\n"); | 1700 | "event_complete: failed to read reg->evt_wrptr\n"); |
1483 | return -1; | 1701 | return -1; |
1484 | } | 1702 | } |
1485 | 1703 | ||
@@ -1492,9 +1710,10 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, | |||
1492 | MWIFIEX_SKB_PACB(skb, &buf_pa); | 1710 | MWIFIEX_SKB_PACB(skb, &buf_pa); |
1493 | card->evt_buf_list[rdptr] = skb; | 1711 | card->evt_buf_list[rdptr] = skb; |
1494 | MWIFIEX_SKB_PACB(skb, &buf_pa); | 1712 | MWIFIEX_SKB_PACB(skb, &buf_pa); |
1495 | card->evtbd_ring[rdptr]->paddr = buf_pa; | 1713 | desc = card->evtbd_ring[rdptr]; |
1496 | card->evtbd_ring[rdptr]->len = (u16)skb->len; | 1714 | desc->paddr = buf_pa; |
1497 | card->evtbd_ring[rdptr]->flags = 0; | 1715 | desc->len = (u16)skb->len; |
1716 | desc->flags = 0; | ||
1498 | skb = NULL; | 1717 | skb = NULL; |
1499 | } else { | 1718 | } else { |
1500 | dev_dbg(adapter->dev, | 1719 | dev_dbg(adapter->dev, |
@@ -1504,17 +1723,18 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, | |||
1504 | 1723 | ||
1505 | if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) { | 1724 | if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) { |
1506 | card->evtbd_rdptr = ((card->evtbd_rdptr & | 1725 | card->evtbd_rdptr = ((card->evtbd_rdptr & |
1507 | MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ | 1726 | reg->evt_rollover_ind) ^ |
1508 | MWIFIEX_BD_FLAG_ROLLOVER_IND); | 1727 | reg->evt_rollover_ind); |
1509 | } | 1728 | } |
1510 | 1729 | ||
1511 | dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>", | 1730 | dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>", |
1512 | card->evtbd_rdptr, wrptr); | 1731 | card->evtbd_rdptr, wrptr); |
1513 | 1732 | ||
1514 | /* Write the event ring read pointer in to REG_EVTBD_RDPTR */ | 1733 | /* Write the event ring read pointer in to reg->evt_rdptr */ |
1515 | if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) { | 1734 | if (mwifiex_write_reg(adapter, reg->evt_rdptr, |
1735 | card->evtbd_rdptr)) { | ||
1516 | dev_err(adapter->dev, | 1736 | dev_err(adapter->dev, |
1517 | "event_complete: failed to read REG_EVTBD_RDPTR\n"); | 1737 | "event_complete: failed to read reg->evt_rdptr\n"); |
1518 | return -1; | 1738 | return -1; |
1519 | } | 1739 | } |
1520 | 1740 | ||
@@ -1543,6 +1763,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | |||
1543 | u32 block_retry_cnt = 0; | 1763 | u32 block_retry_cnt = 0; |
1544 | dma_addr_t buf_pa; | 1764 | dma_addr_t buf_pa; |
1545 | struct pcie_service_card *card = adapter->card; | 1765 | struct pcie_service_card *card = adapter->card; |
1766 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1546 | 1767 | ||
1547 | if (!firmware || !firmware_len) { | 1768 | if (!firmware || !firmware_len) { |
1548 | dev_err(adapter->dev, | 1769 | dev_err(adapter->dev, |
@@ -1574,7 +1795,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | |||
1574 | break; | 1795 | break; |
1575 | 1796 | ||
1576 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | 1797 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { |
1577 | ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG, | 1798 | ret = mwifiex_read_reg(adapter, reg->cmd_size, |
1578 | &len); | 1799 | &len); |
1579 | if (ret) { | 1800 | if (ret) { |
1580 | dev_warn(adapter->dev, | 1801 | dev_warn(adapter->dev, |
@@ -1620,16 +1841,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | |||
1620 | 1841 | ||
1621 | dev_dbg(adapter->dev, "."); | 1842 | dev_dbg(adapter->dev, "."); |
1622 | 1843 | ||
1623 | tx_blocks = (txlen + | 1844 | tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) / |
1624 | MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) / | 1845 | card->pcie.blksz_fw_dl; |
1625 | MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD; | ||
1626 | 1846 | ||
1627 | /* Copy payload to buffer */ | 1847 | /* Copy payload to buffer */ |
1628 | memmove(skb->data, &firmware[offset], txlen); | 1848 | memmove(skb->data, &firmware[offset], txlen); |
1629 | } | 1849 | } |
1630 | 1850 | ||
1631 | skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); | 1851 | skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); |
1632 | skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD); | 1852 | skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl); |
1633 | 1853 | ||
1634 | /* Send the boot command to device */ | 1854 | /* Send the boot command to device */ |
1635 | if (mwifiex_pcie_send_boot_cmd(adapter, skb)) { | 1855 | if (mwifiex_pcie_send_boot_cmd(adapter, skb)) { |
@@ -1682,6 +1902,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) | |||
1682 | { | 1902 | { |
1683 | int ret = 0; | 1903 | int ret = 0; |
1684 | u32 firmware_stat, winner_status; | 1904 | u32 firmware_stat, winner_status; |
1905 | struct pcie_service_card *card = adapter->card; | ||
1906 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1685 | u32 tries; | 1907 | u32 tries; |
1686 | 1908 | ||
1687 | /* Mask spurios interrupts */ | 1909 | /* Mask spurios interrupts */ |
@@ -1692,7 +1914,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) | |||
1692 | } | 1914 | } |
1693 | 1915 | ||
1694 | dev_dbg(adapter->dev, "Setting driver ready signature\n"); | 1916 | dev_dbg(adapter->dev, "Setting driver ready signature\n"); |
1695 | if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) { | 1917 | if (mwifiex_write_reg(adapter, reg->drv_rdy, |
1918 | FIRMWARE_READY_PCIE)) { | ||
1696 | dev_err(adapter->dev, | 1919 | dev_err(adapter->dev, |
1697 | "Failed to write driver ready signature\n"); | 1920 | "Failed to write driver ready signature\n"); |
1698 | return -1; | 1921 | return -1; |
@@ -1700,7 +1923,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) | |||
1700 | 1923 | ||
1701 | /* Wait for firmware initialization event */ | 1924 | /* Wait for firmware initialization event */ |
1702 | for (tries = 0; tries < poll_num; tries++) { | 1925 | for (tries = 0; tries < poll_num; tries++) { |
1703 | if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, | 1926 | if (mwifiex_read_reg(adapter, reg->fw_status, |
1704 | &firmware_stat)) | 1927 | &firmware_stat)) |
1705 | ret = -1; | 1928 | ret = -1; |
1706 | else | 1929 | else |
@@ -1717,7 +1940,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) | |||
1717 | } | 1940 | } |
1718 | 1941 | ||
1719 | if (ret) { | 1942 | if (ret) { |
1720 | if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, | 1943 | if (mwifiex_read_reg(adapter, reg->fw_status, |
1721 | &winner_status)) | 1944 | &winner_status)) |
1722 | ret = -1; | 1945 | ret = -1; |
1723 | else if (!winner_status) { | 1946 | else if (!winner_status) { |
@@ -1955,6 +2178,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) | |||
1955 | struct pcie_service_card *card = adapter->card; | 2178 | struct pcie_service_card *card = adapter->card; |
1956 | int ret; | 2179 | int ret; |
1957 | struct pci_dev *pdev = card->dev; | 2180 | struct pci_dev *pdev = card->dev; |
2181 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
1958 | 2182 | ||
1959 | pci_set_drvdata(pdev, card); | 2183 | pci_set_drvdata(pdev, card); |
1960 | 2184 | ||
@@ -2017,10 +2241,13 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) | |||
2017 | ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); | 2241 | ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); |
2018 | if (ret) | 2242 | if (ret) |
2019 | goto err_alloc_cmdbuf; | 2243 | goto err_alloc_cmdbuf; |
2020 | ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); | 2244 | if (reg->sleep_cookie) { |
2021 | if (ret) | 2245 | ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); |
2022 | goto err_alloc_cookie; | 2246 | if (ret) |
2023 | 2247 | goto err_alloc_cookie; | |
2248 | } else { | ||
2249 | card->sleep_cookie_vbase = NULL; | ||
2250 | } | ||
2024 | return ret; | 2251 | return ret; |
2025 | 2252 | ||
2026 | err_alloc_cookie: | 2253 | err_alloc_cookie: |
@@ -2061,10 +2288,11 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) | |||
2061 | { | 2288 | { |
2062 | struct pcie_service_card *card = adapter->card; | 2289 | struct pcie_service_card *card = adapter->card; |
2063 | struct pci_dev *pdev = card->dev; | 2290 | struct pci_dev *pdev = card->dev; |
2291 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||
2064 | 2292 | ||
2065 | if (user_rmmod) { | 2293 | if (user_rmmod) { |
2066 | dev_dbg(adapter->dev, "Clearing driver ready signature\n"); | 2294 | dev_dbg(adapter->dev, "Clearing driver ready signature\n"); |
2067 | if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000)) | 2295 | if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000)) |
2068 | dev_err(adapter->dev, | 2296 | dev_err(adapter->dev, |
2069 | "Failed to write driver not-ready signature\n"); | 2297 | "Failed to write driver not-ready signature\n"); |
2070 | } | 2298 | } |
@@ -2102,7 +2330,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | |||
2102 | } | 2330 | } |
2103 | 2331 | ||
2104 | adapter->dev = &pdev->dev; | 2332 | adapter->dev = &pdev->dev; |
2105 | strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME); | 2333 | strcpy(adapter->fw_name, card->pcie.firmware); |
2106 | 2334 | ||
2107 | return 0; | 2335 | return 0; |
2108 | } | 2336 | } |
@@ -2116,12 +2344,16 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | |||
2116 | static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) | 2344 | static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) |
2117 | { | 2345 | { |
2118 | struct pcie_service_card *card = adapter->card; | 2346 | struct pcie_service_card *card = adapter->card; |
2347 | const struct mwifiex_pcie_card_reg *reg; | ||
2119 | 2348 | ||
2120 | if (card) { | 2349 | if (card) { |
2121 | dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__); | 2350 | dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__); |
2122 | free_irq(card->dev->irq, card->dev); | 2351 | free_irq(card->dev->irq, card->dev); |
2123 | 2352 | ||
2124 | mwifiex_pcie_delete_sleep_cookie_buf(adapter); | 2353 | reg = card->pcie.reg; |
2354 | if (reg->sleep_cookie) | ||
2355 | mwifiex_pcie_delete_sleep_cookie_buf(adapter); | ||
2356 | |||
2125 | mwifiex_pcie_delete_cmdrsp_buf(adapter); | 2357 | mwifiex_pcie_delete_cmdrsp_buf(adapter); |
2126 | mwifiex_pcie_delete_evtbd_ring(adapter); | 2358 | mwifiex_pcie_delete_evtbd_ring(adapter); |
2127 | mwifiex_pcie_delete_rxbd_ring(adapter); | 2359 | mwifiex_pcie_delete_rxbd_ring(adapter); |
@@ -2162,7 +2394,7 @@ static int mwifiex_pcie_init_module(void) | |||
2162 | { | 2394 | { |
2163 | int ret; | 2395 | int ret; |
2164 | 2396 | ||
2165 | pr_debug("Marvell 8766 PCIe Driver\n"); | 2397 | pr_debug("Marvell PCIe Driver\n"); |
2166 | 2398 | ||
2167 | sema_init(&add_remove_card_sem, 1); | 2399 | sema_init(&add_remove_card_sem, 1); |
2168 | 2400 | ||
@@ -2205,4 +2437,5 @@ MODULE_AUTHOR("Marvell International Ltd."); | |||
2205 | MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION); | 2437 | MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION); |
2206 | MODULE_VERSION(PCIE_VERSION); | 2438 | MODULE_VERSION(PCIE_VERSION); |
2207 | MODULE_LICENSE("GPL v2"); | 2439 | MODULE_LICENSE("GPL v2"); |
2208 | MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin"); | 2440 | MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME); |
2441 | MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME); | ||
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 37eeb2ca6b29..d322ab8604ea 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h | |||
@@ -29,6 +29,11 @@ | |||
29 | #include "main.h" | 29 | #include "main.h" |
30 | 30 | ||
31 | #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" | 31 | #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" |
32 | #define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" | ||
33 | |||
34 | #define PCIE_VENDOR_ID_MARVELL (0x11ab) | ||
35 | #define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) | ||
36 | #define PCIE_DEVICE_ID_MARVELL_88W8897 (0x2b38) | ||
32 | 37 | ||
33 | /* Constants for Buffer Descriptor (BD) rings */ | 38 | /* Constants for Buffer Descriptor (BD) rings */ |
34 | #define MWIFIEX_MAX_TXRX_BD 0x20 | 39 | #define MWIFIEX_MAX_TXRX_BD 0x20 |
@@ -57,6 +62,8 @@ | |||
57 | #define PCIE_SCRATCH_10_REG 0xCE8 | 62 | #define PCIE_SCRATCH_10_REG 0xCE8 |
58 | #define PCIE_SCRATCH_11_REG 0xCEC | 63 | #define PCIE_SCRATCH_11_REG 0xCEC |
59 | #define PCIE_SCRATCH_12_REG 0xCF0 | 64 | #define PCIE_SCRATCH_12_REG 0xCF0 |
65 | #define PCIE_RD_DATA_PTR_Q0_Q1 0xC08C | ||
66 | #define PCIE_WR_DATA_PTR_Q0_Q1 0xC05C | ||
60 | 67 | ||
61 | #define CPU_INTR_DNLD_RDY BIT(0) | 68 | #define CPU_INTR_DNLD_RDY BIT(0) |
62 | #define CPU_INTR_DOOR_BELL BIT(1) | 69 | #define CPU_INTR_DOOR_BELL BIT(1) |
@@ -75,27 +82,14 @@ | |||
75 | #define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7) | 82 | #define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7) |
76 | #define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0) | 83 | #define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0) |
77 | #define MWIFIEX_BD_FLAG_LAST_DESC BIT(1) | 84 | #define MWIFIEX_BD_FLAG_LAST_DESC BIT(1) |
78 | #define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG | 85 | #define MWIFIEX_BD_FLAG_SOP BIT(0) |
79 | #define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG | 86 | #define MWIFIEX_BD_FLAG_EOP BIT(1) |
80 | #define REG_CMD_SIZE PCIE_SCRATCH_2_REG | 87 | #define MWIFIEX_BD_FLAG_XS_SOP BIT(2) |
81 | 88 | #define MWIFIEX_BD_FLAG_XS_EOP BIT(3) | |
82 | #define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG | 89 | #define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND BIT(7) |
83 | #define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG | 90 | #define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND BIT(10) |
84 | 91 | #define MWIFIEX_BD_FLAG_TX_START_PTR BIT(16) | |
85 | /* TX buffer description read pointer */ | 92 | #define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND BIT(26) |
86 | #define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG | ||
87 | /* TX buffer description write pointer */ | ||
88 | #define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG | ||
89 | /* RX buffer description read pointer */ | ||
90 | #define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG | ||
91 | /* RX buffer description write pointer */ | ||
92 | #define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG | ||
93 | /* Event buffer description read pointer */ | ||
94 | #define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG | ||
95 | /* Event buffer description write pointer */ | ||
96 | #define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG | ||
97 | /* Driver ready signature write pointer */ | ||
98 | #define REG_DRV_READY PCIE_SCRATCH_12_REG | ||
99 | 93 | ||
100 | /* Max retry number of command write */ | 94 | /* Max retry number of command write */ |
101 | #define MAX_WRITE_IOMEM_RETRY 2 | 95 | #define MAX_WRITE_IOMEM_RETRY 2 |
@@ -104,15 +98,142 @@ | |||
104 | /* FW awake cookie after FW ready */ | 98 | /* FW awake cookie after FW ready */ |
105 | #define FW_AWAKE_COOKIE (0xAA55AA55) | 99 | #define FW_AWAKE_COOKIE (0xAA55AA55) |
106 | 100 | ||
101 | struct mwifiex_pcie_card_reg { | ||
102 | u16 cmd_addr_lo; | ||
103 | u16 cmd_addr_hi; | ||
104 | u16 fw_status; | ||
105 | u16 cmd_size; | ||
106 | u16 cmdrsp_addr_lo; | ||
107 | u16 cmdrsp_addr_hi; | ||
108 | u16 tx_rdptr; | ||
109 | u16 tx_wrptr; | ||
110 | u16 rx_rdptr; | ||
111 | u16 rx_wrptr; | ||
112 | u16 evt_rdptr; | ||
113 | u16 evt_wrptr; | ||
114 | u16 drv_rdy; | ||
115 | u16 tx_start_ptr; | ||
116 | u32 tx_mask; | ||
117 | u32 tx_wrap_mask; | ||
118 | u32 rx_mask; | ||
119 | u32 rx_wrap_mask; | ||
120 | u32 tx_rollover_ind; | ||
121 | u32 rx_rollover_ind; | ||
122 | u32 evt_rollover_ind; | ||
123 | u8 ring_flag_sop; | ||
124 | u8 ring_flag_eop; | ||
125 | u8 ring_flag_xs_sop; | ||
126 | u8 ring_flag_xs_eop; | ||
127 | u32 ring_tx_start_ptr; | ||
128 | u8 pfu_enabled; | ||
129 | u8 sleep_cookie; | ||
130 | }; | ||
131 | |||
132 | static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { | ||
133 | .cmd_addr_lo = PCIE_SCRATCH_0_REG, | ||
134 | .cmd_addr_hi = PCIE_SCRATCH_1_REG, | ||
135 | .cmd_size = PCIE_SCRATCH_2_REG, | ||
136 | .fw_status = PCIE_SCRATCH_3_REG, | ||
137 | .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, | ||
138 | .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, | ||
139 | .tx_rdptr = PCIE_SCRATCH_6_REG, | ||
140 | .tx_wrptr = PCIE_SCRATCH_7_REG, | ||
141 | .rx_rdptr = PCIE_SCRATCH_8_REG, | ||
142 | .rx_wrptr = PCIE_SCRATCH_9_REG, | ||
143 | .evt_rdptr = PCIE_SCRATCH_10_REG, | ||
144 | .evt_wrptr = PCIE_SCRATCH_11_REG, | ||
145 | .drv_rdy = PCIE_SCRATCH_12_REG, | ||
146 | .tx_start_ptr = 0, | ||
147 | .tx_mask = MWIFIEX_TXBD_MASK, | ||
148 | .tx_wrap_mask = 0, | ||
149 | .rx_mask = MWIFIEX_RXBD_MASK, | ||
150 | .rx_wrap_mask = 0, | ||
151 | .tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, | ||
152 | .rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, | ||
153 | .evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, | ||
154 | .ring_flag_sop = 0, | ||
155 | .ring_flag_eop = 0, | ||
156 | .ring_flag_xs_sop = 0, | ||
157 | .ring_flag_xs_eop = 0, | ||
158 | .ring_tx_start_ptr = 0, | ||
159 | .pfu_enabled = 0, | ||
160 | .sleep_cookie = 1, | ||
161 | }; | ||
162 | |||
163 | static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { | ||
164 | .cmd_addr_lo = PCIE_SCRATCH_0_REG, | ||
165 | .cmd_addr_hi = PCIE_SCRATCH_1_REG, | ||
166 | .cmd_size = PCIE_SCRATCH_2_REG, | ||
167 | .fw_status = PCIE_SCRATCH_3_REG, | ||
168 | .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, | ||
169 | .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, | ||
170 | .tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1, | ||
171 | .tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1, | ||
172 | .rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1, | ||
173 | .rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1, | ||
174 | .evt_rdptr = PCIE_SCRATCH_10_REG, | ||
175 | .evt_wrptr = PCIE_SCRATCH_11_REG, | ||
176 | .drv_rdy = PCIE_SCRATCH_12_REG, | ||
177 | .tx_start_ptr = 16, | ||
178 | .tx_mask = 0x03FF0000, | ||
179 | .tx_wrap_mask = 0x07FF0000, | ||
180 | .rx_mask = 0x000003FF, | ||
181 | .rx_wrap_mask = 0x000007FF, | ||
182 | .tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND, | ||
183 | .rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND, | ||
184 | .evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, | ||
185 | .ring_flag_sop = MWIFIEX_BD_FLAG_SOP, | ||
186 | .ring_flag_eop = MWIFIEX_BD_FLAG_EOP, | ||
187 | .ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP, | ||
188 | .ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP, | ||
189 | .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, | ||
190 | .pfu_enabled = 1, | ||
191 | .sleep_cookie = 0, | ||
192 | }; | ||
193 | |||
194 | struct mwifiex_pcie_device { | ||
195 | const char *firmware; | ||
196 | const struct mwifiex_pcie_card_reg *reg; | ||
197 | u16 blksz_fw_dl; | ||
198 | }; | ||
199 | |||
200 | static const struct mwifiex_pcie_device mwifiex_pcie8766 = { | ||
201 | .firmware = PCIE8766_DEFAULT_FW_NAME, | ||
202 | .reg = &mwifiex_reg_8766, | ||
203 | .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, | ||
204 | }; | ||
205 | |||
206 | static const struct mwifiex_pcie_device mwifiex_pcie8897 = { | ||
207 | .firmware = PCIE8897_DEFAULT_FW_NAME, | ||
208 | .reg = &mwifiex_reg_8897, | ||
209 | .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, | ||
210 | }; | ||
211 | |||
212 | struct mwifiex_evt_buf_desc { | ||
213 | u64 paddr; | ||
214 | u16 len; | ||
215 | u16 flags; | ||
216 | } __packed; | ||
217 | |||
107 | struct mwifiex_pcie_buf_desc { | 218 | struct mwifiex_pcie_buf_desc { |
108 | u64 paddr; | 219 | u64 paddr; |
109 | u16 len; | 220 | u16 len; |
110 | u16 flags; | 221 | u16 flags; |
111 | } __packed; | 222 | } __packed; |
112 | 223 | ||
224 | struct mwifiex_pfu_buf_desc { | ||
225 | u16 flags; | ||
226 | u16 offset; | ||
227 | u16 frag_len; | ||
228 | u16 len; | ||
229 | u64 paddr; | ||
230 | u32 reserved; | ||
231 | } __packed; | ||
232 | |||
113 | struct pcie_service_card { | 233 | struct pcie_service_card { |
114 | struct pci_dev *dev; | 234 | struct pci_dev *dev; |
115 | struct mwifiex_adapter *adapter; | 235 | struct mwifiex_adapter *adapter; |
236 | struct mwifiex_pcie_device pcie; | ||
116 | 237 | ||
117 | u8 txbd_flush; | 238 | u8 txbd_flush; |
118 | u32 txbd_wrptr; | 239 | u32 txbd_wrptr; |
@@ -120,7 +241,7 @@ struct pcie_service_card { | |||
120 | u32 txbd_ring_size; | 241 | u32 txbd_ring_size; |
121 | u8 *txbd_ring_vbase; | 242 | u8 *txbd_ring_vbase; |
122 | dma_addr_t txbd_ring_pbase; | 243 | dma_addr_t txbd_ring_pbase; |
123 | struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; | 244 | void *txbd_ring[MWIFIEX_MAX_TXRX_BD]; |
124 | struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; | 245 | struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; |
125 | 246 | ||
126 | u32 rxbd_wrptr; | 247 | u32 rxbd_wrptr; |
@@ -128,7 +249,7 @@ struct pcie_service_card { | |||
128 | u32 rxbd_ring_size; | 249 | u32 rxbd_ring_size; |
129 | u8 *rxbd_ring_vbase; | 250 | u8 *rxbd_ring_vbase; |
130 | dma_addr_t rxbd_ring_pbase; | 251 | dma_addr_t rxbd_ring_pbase; |
131 | struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; | 252 | void *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; |
132 | struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; | 253 | struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; |
133 | 254 | ||
134 | u32 evtbd_wrptr; | 255 | u32 evtbd_wrptr; |
@@ -136,7 +257,7 @@ struct pcie_service_card { | |||
136 | u32 evtbd_ring_size; | 257 | u32 evtbd_ring_size; |
137 | u8 *evtbd_ring_vbase; | 258 | u8 *evtbd_ring_vbase; |
138 | dma_addr_t evtbd_ring_pbase; | 259 | dma_addr_t evtbd_ring_pbase; |
139 | struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; | 260 | void *evtbd_ring[MWIFIEX_MAX_EVT_BD]; |
140 | struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; | 261 | struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; |
141 | 262 | ||
142 | struct sk_buff *cmd_buf; | 263 | struct sk_buff *cmd_buf; |
@@ -150,11 +271,24 @@ struct pcie_service_card { | |||
150 | static inline int | 271 | static inline int |
151 | mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) | 272 | mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) |
152 | { | 273 | { |
153 | if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == | 274 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
154 | (rdptr & MWIFIEX_TXBD_MASK)) && | 275 | |
155 | ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | 276 | switch (card->dev->device) { |
156 | (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | 277 | case PCIE_DEVICE_ID_MARVELL_88W8766P: |
157 | return 1; | 278 | if (((card->txbd_wrptr & reg->tx_mask) == |
279 | (rdptr & reg->tx_mask)) && | ||
280 | ((card->txbd_wrptr & reg->tx_rollover_ind) != | ||
281 | (rdptr & reg->tx_rollover_ind))) | ||
282 | return 1; | ||
283 | break; | ||
284 | case PCIE_DEVICE_ID_MARVELL_88W8897: | ||
285 | if (((card->txbd_wrptr & reg->tx_mask) == | ||
286 | (rdptr & reg->tx_mask)) && | ||
287 | ((card->txbd_wrptr & reg->tx_rollover_ind) == | ||
288 | (rdptr & reg->tx_rollover_ind))) | ||
289 | return 1; | ||
290 | break; | ||
291 | } | ||
158 | 292 | ||
159 | return 0; | 293 | return 0; |
160 | } | 294 | } |
@@ -162,11 +296,24 @@ mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) | |||
162 | static inline int | 296 | static inline int |
163 | mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) | 297 | mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) |
164 | { | 298 | { |
165 | if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != | 299 | const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; |
166 | (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) || | 300 | |
167 | ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | 301 | switch (card->dev->device) { |
168 | (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | 302 | case PCIE_DEVICE_ID_MARVELL_88W8766P: |
169 | return 1; | 303 | if (((card->txbd_wrptr & reg->tx_mask) != |
304 | (card->txbd_rdptr & reg->tx_mask)) || | ||
305 | ((card->txbd_wrptr & reg->tx_rollover_ind) != | ||
306 | (card->txbd_rdptr & reg->tx_rollover_ind))) | ||
307 | return 1; | ||
308 | break; | ||
309 | case PCIE_DEVICE_ID_MARVELL_88W8897: | ||
310 | if (((card->txbd_wrptr & reg->tx_mask) != | ||
311 | (card->txbd_rdptr & reg->tx_mask)) || | ||
312 | ((card->txbd_wrptr & reg->tx_rollover_ind) == | ||
313 | (card->txbd_rdptr & reg->tx_rollover_ind))) | ||
314 | return 1; | ||
315 | break; | ||
316 | } | ||
170 | 317 | ||
171 | return 0; | 318 | return 0; |
172 | } | 319 | } |
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index d41f0e647280..e0cce1b52d55 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -1741,7 +1741,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
1741 | .mac_address, ETH_ALEN)) | 1741 | .mac_address, ETH_ALEN)) |
1742 | mwifiex_update_curr_bss_params(priv, | 1742 | mwifiex_update_curr_bss_params(priv, |
1743 | bss); | 1743 | bss); |
1744 | cfg80211_put_bss(bss); | 1744 | cfg80211_put_bss(priv->wdev->wiphy, bss); |
1745 | } | 1745 | } |
1746 | } else { | 1746 | } else { |
1747 | dev_dbg(adapter->dev, "missing BSS channel IE\n"); | 1747 | dev_dbg(adapter->dev, "missing BSS channel IE\n"); |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index b8fa76a2b953..7eef74564a92 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -162,13 +162,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | |||
162 | 162 | ||
163 | rcu_read_lock(); | 163 | rcu_read_lock(); |
164 | ies = rcu_dereference(bss->ies); | 164 | ies = rcu_dereference(bss->ies); |
165 | if (WARN_ON(!ies)) { | ||
166 | /* should never happen */ | ||
167 | rcu_read_unlock(); | ||
168 | return -EINVAL; | ||
169 | } | ||
170 | beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); | 165 | beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); |
171 | beacon_ie_len = ies->len; | 166 | beacon_ie_len = ies->len; |
167 | bss_desc->timestamp = ies->tsf; | ||
172 | rcu_read_unlock(); | 168 | rcu_read_unlock(); |
173 | 169 | ||
174 | if (!beacon_ie) { | 170 | if (!beacon_ie) { |
@@ -184,7 +180,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | |||
184 | bss_desc->cap_info_bitmap = bss->capability; | 180 | bss_desc->cap_info_bitmap = bss->capability; |
185 | bss_desc->bss_band = bss_priv->band; | 181 | bss_desc->bss_band = bss_priv->band; |
186 | bss_desc->fw_tsf = bss_priv->fw_tsf; | 182 | bss_desc->fw_tsf = bss_priv->fw_tsf; |
187 | bss_desc->timestamp = bss->tsf; | ||
188 | if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { | 183 | if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { |
189 | dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); | 184 | dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); |
190 | bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | 185 | bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; |
@@ -322,7 +317,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, | |||
322 | } | 317 | } |
323 | 318 | ||
324 | if (bss) | 319 | if (bss) |
325 | cfg80211_put_bss(bss); | 320 | cfg80211_put_bss(priv->adapter->wiphy, bss); |
326 | } else { | 321 | } else { |
327 | /* Adhoc mode */ | 322 | /* Adhoc mode */ |
328 | /* If the requested SSID matches current SSID, return */ | 323 | /* If the requested SSID matches current SSID, return */ |
@@ -352,7 +347,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, | |||
352 | " list. Joining...\n"); | 347 | " list. Joining...\n"); |
353 | ret = mwifiex_adhoc_join(priv, bss_desc); | 348 | ret = mwifiex_adhoc_join(priv, bss_desc); |
354 | if (bss) | 349 | if (bss) |
355 | cfg80211_put_bss(bss); | 350 | cfg80211_put_bss(priv->adapter->wiphy, bss); |
356 | } else { | 351 | } else { |
357 | dev_dbg(adapter->dev, "info: Network not found in " | 352 | dev_dbg(adapter->dev, "info: Network not found in " |
358 | "the list, creating adhoc with ssid = %s\n", | 353 | "the list, creating adhoc with ssid = %s\n", |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c86e4573798f..091d9a64080a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -5471,6 +5471,8 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | |||
5471 | { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, | 5471 | { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, |
5472 | { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, | 5472 | { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, |
5473 | { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, | 5473 | { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, |
5474 | { PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, }, | ||
5475 | { PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, }, | ||
5474 | { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, | 5476 | { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, |
5475 | { }, | 5477 | { }, |
5476 | }; | 5478 | }; |
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 96e39edfec77..e8c5714bfd11 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c | |||
@@ -125,7 +125,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv, | |||
125 | cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, | 125 | cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, |
126 | capability, beacon_interval, ie_buf, ie_len, | 126 | capability, beacon_interval, ie_buf, ie_len, |
127 | signal, GFP_KERNEL); | 127 | signal, GFP_KERNEL); |
128 | cfg80211_put_bss(cbss); | 128 | cfg80211_put_bss(wiphy, cbss); |
129 | } | 129 | } |
130 | 130 | ||
131 | void orinoco_add_extscan_result(struct orinoco_private *priv, | 131 | void orinoco_add_extscan_result(struct orinoco_private *priv, |
@@ -158,7 +158,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv, | |||
158 | cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, | 158 | cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, |
159 | capability, beacon_interval, ie, ie_len, | 159 | capability, beacon_interval, ie, ie_len, |
160 | signal, GFP_KERNEL); | 160 | signal, GFP_KERNEL); |
161 | cfg80211_put_bss(cbss); | 161 | cfg80211_put_bss(wiphy, cbss); |
162 | } | 162 | } |
163 | 163 | ||
164 | void orinoco_add_hostscan_results(struct orinoco_private *priv, | 164 | void orinoco_add_hostscan_results(struct orinoco_private *priv, |
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 62ac60737531..b9deef66cf4b 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c | |||
@@ -84,8 +84,8 @@ static struct usb_device_id p54u_table[] = { | |||
84 | {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ | 84 | {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ |
85 | {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ | 85 | {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ |
86 | {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ | 86 | {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ |
87 | {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */ | ||
88 | {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ | 87 | {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ |
88 | {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */ | ||
89 | {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ | 89 | {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ |
90 | {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ | 90 | {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ |
91 | {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ | 91 | {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9bb3f22b3669..525fd7521dff 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -2026,7 +2026,7 @@ static bool rndis_bss_info_update(struct usbnet *usbdev, | |||
2026 | bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, | 2026 | bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, |
2027 | timestamp, capability, beacon_interval, ie, ie_len, signal, | 2027 | timestamp, capability, beacon_interval, ie, ie_len, signal, |
2028 | GFP_KERNEL); | 2028 | GFP_KERNEL); |
2029 | cfg80211_put_bss(bss); | 2029 | cfg80211_put_bss(priv->wdev.wiphy, bss); |
2030 | 2030 | ||
2031 | return (bss != NULL); | 2031 | return (bss != NULL); |
2032 | } | 2032 | } |
@@ -2715,7 +2715,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, | |||
2715 | bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, | 2715 | bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, |
2716 | timestamp, capability, beacon_period, ie_buf, ie_len, | 2716 | timestamp, capability, beacon_period, ie_buf, ie_len, |
2717 | signal, GFP_KERNEL); | 2717 | signal, GFP_KERNEL); |
2718 | cfg80211_put_bss(bss); | 2718 | cfg80211_put_bss(priv->wdev.wiphy, bss); |
2719 | } | 2719 | } |
2720 | 2720 | ||
2721 | /* | 2721 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index a2d2bc2c7b3d..221beaaa83f1 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1185,8 +1185,14 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, | |||
1185 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 1185 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); |
1186 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 1186 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
1187 | 1187 | ||
1188 | rt2x00queue_map_txskb(entry); | 1188 | if (rt2x00queue_map_txskb(entry)) { |
1189 | 1189 | ERROR(rt2x00dev, "Fail to map beacon, aborting\n"); | |
1190 | goto out; | ||
1191 | } | ||
1192 | /* | ||
1193 | * Enable beaconing again. | ||
1194 | */ | ||
1195 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); | ||
1190 | /* | 1196 | /* |
1191 | * Write the TX descriptor for the beacon. | 1197 | * Write the TX descriptor for the beacon. |
1192 | */ | 1198 | */ |
@@ -1196,7 +1202,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, | |||
1196 | * Dump beacon to userspace through debugfs. | 1202 | * Dump beacon to userspace through debugfs. |
1197 | */ | 1203 | */ |
1198 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); | 1204 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); |
1199 | 1205 | out: | |
1200 | /* | 1206 | /* |
1201 | * Enable beaconing again. | 1207 | * Enable beaconing again. |
1202 | */ | 1208 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 9bea10f53f0a..39edc59e8d03 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1338,7 +1338,10 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, | |||
1338 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 1338 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); |
1339 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 1339 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
1340 | 1340 | ||
1341 | rt2x00queue_map_txskb(entry); | 1341 | if (rt2x00queue_map_txskb(entry)) { |
1342 | ERROR(rt2x00dev, "Fail to map beacon, aborting\n"); | ||
1343 | goto out; | ||
1344 | } | ||
1342 | 1345 | ||
1343 | /* | 1346 | /* |
1344 | * Write the TX descriptor for the beacon. | 1347 | * Write the TX descriptor for the beacon. |
@@ -1349,7 +1352,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, | |||
1349 | * Dump beacon to userspace through debugfs. | 1352 | * Dump beacon to userspace through debugfs. |
1350 | */ | 1353 | */ |
1351 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); | 1354 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); |
1352 | 1355 | out: | |
1353 | /* | 1356 | /* |
1354 | * Enable beaconing again. | 1357 | * Enable beaconing again. |
1355 | */ | 1358 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 42b5b659af16..098613ed93fb 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -1099,9 +1099,11 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1099 | { USB_DEVICE(0x15a9, 0x0006) }, | 1099 | { USB_DEVICE(0x15a9, 0x0006) }, |
1100 | /* Sweex */ | 1100 | /* Sweex */ |
1101 | { USB_DEVICE(0x177f, 0x0153) }, | 1101 | { USB_DEVICE(0x177f, 0x0153) }, |
1102 | { USB_DEVICE(0x177f, 0x0164) }, | ||
1102 | { USB_DEVICE(0x177f, 0x0302) }, | 1103 | { USB_DEVICE(0x177f, 0x0302) }, |
1103 | { USB_DEVICE(0x177f, 0x0313) }, | 1104 | { USB_DEVICE(0x177f, 0x0313) }, |
1104 | { USB_DEVICE(0x177f, 0x0323) }, | 1105 | { USB_DEVICE(0x177f, 0x0323) }, |
1106 | { USB_DEVICE(0x177f, 0x0324) }, | ||
1105 | /* U-Media */ | 1107 | /* U-Media */ |
1106 | { USB_DEVICE(0x157e, 0x300e) }, | 1108 | { USB_DEVICE(0x157e, 0x300e) }, |
1107 | { USB_DEVICE(0x157e, 0x3013) }, | 1109 | { USB_DEVICE(0x157e, 0x3013) }, |
@@ -1133,6 +1135,9 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1133 | { USB_DEVICE(0x148f, 0x8070) }, | 1135 | { USB_DEVICE(0x148f, 0x8070) }, |
1134 | /* Sitecom */ | 1136 | /* Sitecom */ |
1135 | { USB_DEVICE(0x0df6, 0x0050) }, | 1137 | { USB_DEVICE(0x0df6, 0x0050) }, |
1138 | /* Sweex */ | ||
1139 | { USB_DEVICE(0x177f, 0x0163) }, | ||
1140 | { USB_DEVICE(0x177f, 0x0165) }, | ||
1136 | #endif | 1141 | #endif |
1137 | #ifdef CONFIG_RT2800USB_RT35XX | 1142 | #ifdef CONFIG_RT2800USB_RT35XX |
1138 | /* Allwin */ | 1143 | /* Allwin */ |
@@ -1214,10 +1219,15 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1214 | { USB_DEVICE(0x0b05, 0x1760) }, | 1219 | { USB_DEVICE(0x0b05, 0x1760) }, |
1215 | { USB_DEVICE(0x0b05, 0x1761) }, | 1220 | { USB_DEVICE(0x0b05, 0x1761) }, |
1216 | { USB_DEVICE(0x0b05, 0x1790) }, | 1221 | { USB_DEVICE(0x0b05, 0x1790) }, |
1222 | { USB_DEVICE(0x0b05, 0x17a7) }, | ||
1217 | /* AzureWave */ | 1223 | /* AzureWave */ |
1218 | { USB_DEVICE(0x13d3, 0x3262) }, | 1224 | { USB_DEVICE(0x13d3, 0x3262) }, |
1219 | { USB_DEVICE(0x13d3, 0x3284) }, | 1225 | { USB_DEVICE(0x13d3, 0x3284) }, |
1220 | { USB_DEVICE(0x13d3, 0x3322) }, | 1226 | { USB_DEVICE(0x13d3, 0x3322) }, |
1227 | { USB_DEVICE(0x13d3, 0x3340) }, | ||
1228 | { USB_DEVICE(0x13d3, 0x3399) }, | ||
1229 | { USB_DEVICE(0x13d3, 0x3400) }, | ||
1230 | { USB_DEVICE(0x13d3, 0x3401) }, | ||
1221 | /* Belkin */ | 1231 | /* Belkin */ |
1222 | { USB_DEVICE(0x050d, 0x1003) }, | 1232 | { USB_DEVICE(0x050d, 0x1003) }, |
1223 | /* Buffalo */ | 1233 | /* Buffalo */ |
@@ -1232,10 +1242,15 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1232 | { USB_DEVICE(0x07d1, 0x3c0b) }, | 1242 | { USB_DEVICE(0x07d1, 0x3c0b) }, |
1233 | /* Encore */ | 1243 | /* Encore */ |
1234 | { USB_DEVICE(0x203d, 0x14a1) }, | 1244 | { USB_DEVICE(0x203d, 0x14a1) }, |
1245 | /* EnGenius */ | ||
1246 | { USB_DEVICE(0x1740, 0x0600) }, | ||
1247 | { USB_DEVICE(0x1740, 0x0602) }, | ||
1235 | /* Gemtek */ | 1248 | /* Gemtek */ |
1236 | { USB_DEVICE(0x15a9, 0x0010) }, | 1249 | { USB_DEVICE(0x15a9, 0x0010) }, |
1237 | /* Gigabyte */ | 1250 | /* Gigabyte */ |
1238 | { USB_DEVICE(0x1044, 0x800c) }, | 1251 | { USB_DEVICE(0x1044, 0x800c) }, |
1252 | /* Hercules */ | ||
1253 | { USB_DEVICE(0x06f8, 0xe036) }, | ||
1239 | /* Huawei */ | 1254 | /* Huawei */ |
1240 | { USB_DEVICE(0x148f, 0xf101) }, | 1255 | { USB_DEVICE(0x148f, 0xf101) }, |
1241 | /* I-O DATA */ | 1256 | /* I-O DATA */ |
@@ -1262,11 +1277,17 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
1262 | { USB_DEVICE(0x0df6, 0x004a) }, | 1277 | { USB_DEVICE(0x0df6, 0x004a) }, |
1263 | { USB_DEVICE(0x0df6, 0x004d) }, | 1278 | { USB_DEVICE(0x0df6, 0x004d) }, |
1264 | { USB_DEVICE(0x0df6, 0x0053) }, | 1279 | { USB_DEVICE(0x0df6, 0x0053) }, |
1280 | { USB_DEVICE(0x0df6, 0x0069) }, | ||
1281 | { USB_DEVICE(0x0df6, 0x006f) }, | ||
1265 | /* SMC */ | 1282 | /* SMC */ |
1266 | { USB_DEVICE(0x083a, 0xa512) }, | 1283 | { USB_DEVICE(0x083a, 0xa512) }, |
1267 | { USB_DEVICE(0x083a, 0xc522) }, | 1284 | { USB_DEVICE(0x083a, 0xc522) }, |
1268 | { USB_DEVICE(0x083a, 0xd522) }, | 1285 | { USB_DEVICE(0x083a, 0xd522) }, |
1269 | { USB_DEVICE(0x083a, 0xf511) }, | 1286 | { USB_DEVICE(0x083a, 0xf511) }, |
1287 | /* Sweex */ | ||
1288 | { USB_DEVICE(0x177f, 0x0254) }, | ||
1289 | /* TP-LINK */ | ||
1290 | { USB_DEVICE(0xf201, 0x5370) }, | ||
1270 | #endif | 1291 | #endif |
1271 | { 0, } | 1292 | { 0, } |
1272 | }; | 1293 | }; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9a3f31a543ce..086abb403a4f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1169,8 +1169,10 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev) | |||
1169 | /** | 1169 | /** |
1170 | * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. | 1170 | * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. |
1171 | * @entry: Pointer to &struct queue_entry | 1171 | * @entry: Pointer to &struct queue_entry |
1172 | * | ||
1173 | * Returns -ENOMEM if mapping fail, 0 otherwise. | ||
1172 | */ | 1174 | */ |
1173 | void rt2x00queue_map_txskb(struct queue_entry *entry); | 1175 | int rt2x00queue_map_txskb(struct queue_entry *entry); |
1174 | 1176 | ||
1175 | /** | 1177 | /** |
1176 | * rt2x00queue_unmap_skb - Unmap a skb from DMA. | 1178 | * rt2x00queue_unmap_skb - Unmap a skb from DMA. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index f35d85a71bbc..4d91795dc6a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -87,24 +87,35 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) | |||
87 | skbdesc->entry = entry; | 87 | skbdesc->entry = entry; |
88 | 88 | ||
89 | if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { | 89 | if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { |
90 | skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, | 90 | dma_addr_t skb_dma; |
91 | skb->data, | 91 | |
92 | skb->len, | 92 | skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, |
93 | DMA_FROM_DEVICE); | 93 | DMA_FROM_DEVICE); |
94 | if (unlikely(dma_mapping_error(rt2x00dev->dev, skb_dma))) { | ||
95 | dev_kfree_skb_any(skb); | ||
96 | return NULL; | ||
97 | } | ||
98 | |||
99 | skbdesc->skb_dma = skb_dma; | ||
94 | skbdesc->flags |= SKBDESC_DMA_MAPPED_RX; | 100 | skbdesc->flags |= SKBDESC_DMA_MAPPED_RX; |
95 | } | 101 | } |
96 | 102 | ||
97 | return skb; | 103 | return skb; |
98 | } | 104 | } |
99 | 105 | ||
100 | void rt2x00queue_map_txskb(struct queue_entry *entry) | 106 | int rt2x00queue_map_txskb(struct queue_entry *entry) |
101 | { | 107 | { |
102 | struct device *dev = entry->queue->rt2x00dev->dev; | 108 | struct device *dev = entry->queue->rt2x00dev->dev; |
103 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | 109 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); |
104 | 110 | ||
105 | skbdesc->skb_dma = | 111 | skbdesc->skb_dma = |
106 | dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE); | 112 | dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE); |
113 | |||
114 | if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma))) | ||
115 | return -ENOMEM; | ||
116 | |||
107 | skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; | 117 | skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; |
118 | return 0; | ||
108 | } | 119 | } |
109 | EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); | 120 | EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); |
110 | 121 | ||
@@ -343,10 +354,7 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | |||
343 | * when using more then one tx stream (>MCS7). | 354 | * when using more then one tx stream (>MCS7). |
344 | */ | 355 | */ |
345 | if (sta && txdesc->u.ht.mcs > 7 && | 356 | if (sta && txdesc->u.ht.mcs > 7 && |
346 | ((sta->ht_cap.cap & | 357 | sta->smps_mode == IEEE80211_SMPS_DYNAMIC) |
347 | IEEE80211_HT_CAP_SM_PS) >> | ||
348 | IEEE80211_HT_CAP_SM_PS_SHIFT) == | ||
349 | WLAN_HT_CAP_SM_PS_DYNAMIC) | ||
350 | __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); | 358 | __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); |
351 | } else { | 359 | } else { |
352 | txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); | 360 | txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); |
@@ -545,8 +553,9 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, | |||
545 | /* | 553 | /* |
546 | * Map the skb to DMA. | 554 | * Map the skb to DMA. |
547 | */ | 555 | */ |
548 | if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) | 556 | if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) && |
549 | rt2x00queue_map_txskb(entry); | 557 | rt2x00queue_map_txskb(entry)) |
558 | return -ENOMEM; | ||
550 | 559 | ||
551 | return 0; | 560 | return 0; |
552 | } | 561 | } |
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index b80bc4612581..b6aa0c40658f 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig | |||
@@ -1,8 +1,26 @@ | |||
1 | config RTLWIFI | ||
2 | tristate "Realtek wireless card support" | ||
3 | depends on MAC80211 | ||
4 | select FW_LOADER | ||
5 | ---help--- | ||
6 | This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE | ||
7 | drivers. This module does nothing by itself - the various front-end | ||
8 | drivers need to be enabled to support any desired devices. | ||
9 | |||
10 | If you choose to build as a module, it'll be called rtlwifi. | ||
11 | |||
12 | config RTLWIFI_DEBUG | ||
13 | bool "Debugging output for rtlwifi driver family" | ||
14 | depends on RTLWIFI | ||
15 | default y | ||
16 | ---help--- | ||
17 | To use the module option that sets the dynamic-debugging level for, | ||
18 | the front-end driver, this parameter must be "Y". For memory-limited | ||
19 | systems, choose "N". If in doubt, choose "Y". | ||
20 | |||
1 | config RTL8192CE | 21 | config RTL8192CE |
2 | tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" | 22 | tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" |
3 | depends on MAC80211 && PCI | 23 | depends on RTLWIFI && PCI |
4 | select FW_LOADER | ||
5 | select RTLWIFI | ||
6 | select RTL8192C_COMMON | 24 | select RTL8192C_COMMON |
7 | ---help--- | 25 | ---help--- |
8 | This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe | 26 | This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe |
@@ -12,9 +30,7 @@ config RTL8192CE | |||
12 | 30 | ||
13 | config RTL8192SE | 31 | config RTL8192SE |
14 | tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" | 32 | tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" |
15 | depends on MAC80211 && PCI | 33 | depends on RTLWIFI && PCI |
16 | select FW_LOADER | ||
17 | select RTLWIFI | ||
18 | ---help--- | 34 | ---help--- |
19 | This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe | 35 | This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe |
20 | wireless network adapters. | 36 | wireless network adapters. |
@@ -23,9 +39,7 @@ config RTL8192SE | |||
23 | 39 | ||
24 | config RTL8192DE | 40 | config RTL8192DE |
25 | tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" | 41 | tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" |
26 | depends on MAC80211 && PCI | 42 | depends on RTLWIFI && PCI |
27 | select FW_LOADER | ||
28 | select RTLWIFI | ||
29 | ---help--- | 43 | ---help--- |
30 | This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe | 44 | This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe |
31 | wireless network adapters. | 45 | wireless network adapters. |
@@ -34,9 +48,7 @@ config RTL8192DE | |||
34 | 48 | ||
35 | config RTL8723AE | 49 | config RTL8723AE |
36 | tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" | 50 | tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" |
37 | depends on MAC80211 && PCI && EXPERIMENTAL | 51 | depends on RTLWIFI && PCI |
38 | select FW_LOADER | ||
39 | select RTLWIFI | ||
40 | ---help--- | 52 | ---help--- |
41 | This is the driver for Realtek RTL8723AE 802.11n PCIe | 53 | This is the driver for Realtek RTL8723AE 802.11n PCIe |
42 | wireless network adapters. | 54 | wireless network adapters. |
@@ -45,9 +57,7 @@ config RTL8723AE | |||
45 | 57 | ||
46 | config RTL8192CU | 58 | config RTL8192CU |
47 | tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" | 59 | tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" |
48 | depends on MAC80211 && USB | 60 | depends on RTLWIFI && USB |
49 | select FW_LOADER | ||
50 | select RTLWIFI | ||
51 | select RTL8192C_COMMON | 61 | select RTL8192C_COMMON |
52 | ---help--- | 62 | ---help--- |
53 | This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB | 63 | This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB |
@@ -55,16 +65,6 @@ config RTL8192CU | |||
55 | 65 | ||
56 | If you choose to build it as a module, it will be called rtl8192cu | 66 | If you choose to build it as a module, it will be called rtl8192cu |
57 | 67 | ||
58 | config RTLWIFI | ||
59 | tristate | ||
60 | depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE | ||
61 | default m | ||
62 | |||
63 | config RTLWIFI_DEBUG | ||
64 | bool "Additional debugging output" | ||
65 | depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE | ||
66 | default y | ||
67 | |||
68 | config RTL8192C_COMMON | 68 | config RTL8192C_COMMON |
69 | tristate | 69 | tristate |
70 | depends on RTL8192CE || RTL8192CU | 70 | depends on RTL8192CE || RTL8192CU |
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 0f8b05185eda..99c5cea3fe21 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c | |||
@@ -523,8 +523,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw, | |||
523 | if (mac->opmode == NL80211_IFTYPE_STATION) | 523 | if (mac->opmode == NL80211_IFTYPE_STATION) |
524 | bw_40 = mac->bw_40; | 524 | bw_40 = mac->bw_40; |
525 | else if (mac->opmode == NL80211_IFTYPE_AP || | 525 | else if (mac->opmode == NL80211_IFTYPE_AP || |
526 | mac->opmode == NL80211_IFTYPE_ADHOC) | 526 | mac->opmode == NL80211_IFTYPE_ADHOC) |
527 | bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 527 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
528 | 528 | ||
529 | if (bw_40 && sgi_40) | 529 | if (bw_40 && sgi_40) |
530 | tcb_desc->use_shortgi = true; | 530 | tcb_desc->use_shortgi = true; |
@@ -634,8 +634,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, | |||
634 | return; | 634 | return; |
635 | if (mac->opmode == NL80211_IFTYPE_AP || | 635 | if (mac->opmode == NL80211_IFTYPE_AP || |
636 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 636 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
637 | if (!(sta->ht_cap.ht_supported) || | 637 | if (sta->bandwidth == IEEE80211_STA_RX_BW_20) |
638 | !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
639 | return; | 638 | return; |
640 | } else if (mac->opmode == NL80211_IFTYPE_STATION) { | 639 | } else if (mac->opmode == NL80211_IFTYPE_STATION) { |
641 | if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) | 640 | if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) |
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 204f46c4510d..f9f059dadb73 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c | |||
@@ -116,9 +116,8 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, | |||
116 | if (txrc->short_preamble) | 116 | if (txrc->short_preamble) |
117 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | 117 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; |
118 | if (mac->opmode == NL80211_IFTYPE_AP || | 118 | if (mac->opmode == NL80211_IFTYPE_AP || |
119 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 119 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
120 | if (sta && (sta->ht_cap.cap & | 120 | if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40)) |
121 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
122 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 121 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
123 | } else { | 122 | } else { |
124 | if (mac->bw_40) | 123 | if (mac->bw_40) |
@@ -217,6 +216,12 @@ static void rtl_tx_status(void *ppriv, | |||
217 | } | 216 | } |
218 | } | 217 | } |
219 | 218 | ||
219 | static void rtl_rate_init(void *ppriv, | ||
220 | struct ieee80211_supported_band *sband, | ||
221 | struct ieee80211_sta *sta, void *priv_sta) | ||
222 | { | ||
223 | } | ||
224 | |||
220 | static void *rtl_rate_alloc(struct ieee80211_hw *hw, | 225 | static void *rtl_rate_alloc(struct ieee80211_hw *hw, |
221 | struct dentry *debugfsdir) | 226 | struct dentry *debugfsdir) |
222 | { | 227 | { |
@@ -261,6 +266,7 @@ static struct rate_control_ops rtl_rate_ops = { | |||
261 | .free = rtl_rate_free, | 266 | .free = rtl_rate_free, |
262 | .alloc_sta = rtl_rate_alloc_sta, | 267 | .alloc_sta = rtl_rate_alloc_sta, |
263 | .free_sta = rtl_rate_free_sta, | 268 | .free_sta = rtl_rate_free_sta, |
269 | .rate_init = rtl_rate_init, | ||
264 | .tx_status = rtl_tx_status, | 270 | .tx_status = rtl_tx_status, |
265 | .get_rate = rtl_get_rate, | 271 | .get_rate = rtl_get_rate, |
266 | }; | 272 | }; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index d1f34f6ffbdf..1b65db7fd651 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | |||
@@ -1846,9 +1846,9 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
1846 | struct rtl_sta_info *sta_entry = NULL; | 1846 | struct rtl_sta_info *sta_entry = NULL; |
1847 | u32 ratr_bitmap; | 1847 | u32 ratr_bitmap; |
1848 | u8 ratr_index; | 1848 | u8 ratr_index; |
1849 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1849 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
1850 | ? 1 : 0; | 1850 | u8 curshortgi_40mhz = curtxbw_40mhz && |
1851 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1851 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
1852 | 1 : 0; | 1852 | 1 : 0; |
1853 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1853 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
1854 | 1 : 0; | 1854 | 1 : 0; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index c31795e379f7..b9b1a6e0b16e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | |||
@@ -488,7 +488,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, | |||
488 | u8 *praddr; | 488 | u8 *praddr; |
489 | __le16 fc; | 489 | __le16 fc; |
490 | u16 type, c_fc; | 490 | u16 type, c_fc; |
491 | bool packet_matchbssid, packet_toself, packet_beacon; | 491 | bool packet_matchbssid, packet_toself, packet_beacon = false; |
492 | 492 | ||
493 | tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; | 493 | tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; |
494 | 494 | ||
@@ -626,8 +626,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | |||
626 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 626 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
627 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 627 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
628 | if (sta) | 628 | if (sta) |
629 | bw_40 = sta->ht_cap.cap & | 629 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
630 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
631 | } | 630 | } |
632 | 631 | ||
633 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 632 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 32ff959a0251..85b6bdb163c0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | |||
@@ -1084,7 +1084,7 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, | |||
1084 | u8 *praddr; | 1084 | u8 *praddr; |
1085 | __le16 fc; | 1085 | __le16 fc; |
1086 | u16 type, cpu_fc; | 1086 | u16 type, cpu_fc; |
1087 | bool packet_matchbssid, packet_toself, packet_beacon; | 1087 | bool packet_matchbssid, packet_toself, packet_beacon = false; |
1088 | 1088 | ||
1089 | tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; | 1089 | tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; |
1090 | hdr = (struct ieee80211_hdr *)tmp_buf; | 1090 | hdr = (struct ieee80211_hdr *)tmp_buf; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index d9e659f92767..a73a17bc56dd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | |||
@@ -285,6 +285,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { | |||
285 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, | 285 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, |
286 | /* RTL8188CUS-VL */ | 286 | /* RTL8188CUS-VL */ |
287 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, | 287 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, |
288 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)}, | ||
288 | /* 8188 Combo for BC4 */ | 289 | /* 8188 Combo for BC4 */ |
289 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, | 290 | {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, |
290 | 291 | ||
@@ -363,9 +364,15 @@ static struct usb_device_id rtl8192c_usb_ids[] = { | |||
363 | 364 | ||
364 | MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids); | 365 | MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids); |
365 | 366 | ||
367 | static int rtl8192cu_probe(struct usb_interface *intf, | ||
368 | const struct usb_device_id *id) | ||
369 | { | ||
370 | return rtl_usb_probe(intf, id, &rtl92cu_hal_cfg); | ||
371 | } | ||
372 | |||
366 | static struct usb_driver rtl8192cu_driver = { | 373 | static struct usb_driver rtl8192cu_driver = { |
367 | .name = "rtl8192cu", | 374 | .name = "rtl8192cu", |
368 | .probe = rtl_usb_probe, | 375 | .probe = rtl8192cu_probe, |
369 | .disconnect = rtl_usb_disconnect, | 376 | .disconnect = rtl_usb_disconnect, |
370 | .id_table = rtl8192c_usb_ids, | 377 | .id_table = rtl8192c_usb_ids, |
371 | 378 | ||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index f4051f4f0390..aa5b42521bb4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c | |||
@@ -1970,8 +1970,7 @@ static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
1970 | struct rtl_sta_info *sta_entry = NULL; | 1970 | struct rtl_sta_info *sta_entry = NULL; |
1971 | u32 ratr_bitmap; | 1971 | u32 ratr_bitmap; |
1972 | u8 ratr_index; | 1972 | u8 ratr_index; |
1973 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1973 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
1974 | ? 1 : 0; | ||
1975 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1974 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
1976 | 1 : 0; | 1975 | 1 : 0; |
1977 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1976 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index cdb570ffb4b5..941080e03c06 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c | |||
@@ -574,8 +574,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | |||
574 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 574 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
575 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 575 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
576 | if (sta) | 576 | if (sta) |
577 | bw_40 = sta->ht_cap.cap & | 577 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
578 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
579 | } | 578 | } |
580 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 579 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
581 | rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); | 580 | rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 28526a7361f5..084e7773bce2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c | |||
@@ -2085,8 +2085,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
2085 | struct rtl_sta_info *sta_entry = NULL; | 2085 | struct rtl_sta_info *sta_entry = NULL; |
2086 | u32 ratr_bitmap; | 2086 | u32 ratr_bitmap; |
2087 | u8 ratr_index = 0; | 2087 | u8 ratr_index = 0; |
2088 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 2088 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
2089 | ? 1 : 0; | ||
2090 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 2089 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
2091 | 1 : 0; | 2090 | 1 : 0; |
2092 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 2091 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index f8431a3c2c9d..7b0a2e75b8b8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c | |||
@@ -621,8 +621,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, | |||
621 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 621 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
622 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 622 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
623 | if (sta) | 623 | if (sta) |
624 | bw_40 = sta->ht_cap.cap & | 624 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
625 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
626 | } | 625 | } |
627 | 626 | ||
628 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 627 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 149804816ac4..9a0c71c2e15e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | |||
@@ -1866,8 +1866,7 @@ static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
1866 | struct rtl_sta_info *sta_entry = NULL; | 1866 | struct rtl_sta_info *sta_entry = NULL; |
1867 | u32 ratr_bitmap; | 1867 | u32 ratr_bitmap; |
1868 | u8 ratr_index; | 1868 | u8 ratr_index; |
1869 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1869 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
1870 | ? 1 : 0; | ||
1871 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1870 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
1872 | 1 : 0; | 1871 | 1 : 0; |
1873 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1872 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index b1fd2b328abf..ac081297db50 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | |||
@@ -395,8 +395,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, | |||
395 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 395 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
396 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 396 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
397 | if (sta) | 397 | if (sta) |
398 | bw_40 = sta->ht_cap.cap & | 398 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
399 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
400 | } | 399 | } |
401 | 400 | ||
402 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 401 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index d42bbe21ba6e..476eaef5e4a9 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -937,7 +937,8 @@ static struct rtl_intf_ops rtl_usb_ops = { | |||
937 | }; | 937 | }; |
938 | 938 | ||
939 | int rtl_usb_probe(struct usb_interface *intf, | 939 | int rtl_usb_probe(struct usb_interface *intf, |
940 | const struct usb_device_id *id) | 940 | const struct usb_device_id *id, |
941 | struct rtl_hal_cfg *rtl_hal_cfg) | ||
941 | { | 942 | { |
942 | int err; | 943 | int err; |
943 | struct ieee80211_hw *hw = NULL; | 944 | struct ieee80211_hw *hw = NULL; |
@@ -972,7 +973,7 @@ int rtl_usb_probe(struct usb_interface *intf, | |||
972 | usb_set_intfdata(intf, hw); | 973 | usb_set_intfdata(intf, hw); |
973 | /* init cfg & intf_ops */ | 974 | /* init cfg & intf_ops */ |
974 | rtlpriv->rtlhal.interface = INTF_USB; | 975 | rtlpriv->rtlhal.interface = INTF_USB; |
975 | rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info); | 976 | rtlpriv->cfg = rtl_hal_cfg; |
976 | rtlpriv->intf_ops = &rtl_usb_ops; | 977 | rtlpriv->intf_ops = &rtl_usb_ops; |
977 | rtl_dbgp_flag_init(hw); | 978 | rtl_dbgp_flag_init(hw); |
978 | /* Init IO handler */ | 979 | /* Init IO handler */ |
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index 5235136f6dd2..fb986f98d1df 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h | |||
@@ -157,7 +157,8 @@ struct rtl_usb_priv { | |||
157 | 157 | ||
158 | 158 | ||
159 | int rtl_usb_probe(struct usb_interface *intf, | 159 | int rtl_usb_probe(struct usb_interface *intf, |
160 | const struct usb_device_id *id); | 160 | const struct usb_device_id *id, |
161 | struct rtl_hal_cfg *rtl92cu_hal_cfg); | ||
161 | void rtl_usb_disconnect(struct usb_interface *intf); | 162 | void rtl_usb_disconnect(struct usb_interface *intf); |
162 | int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message); | 163 | int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message); |
163 | int rtl_usb_resume(struct usb_interface *pusb_intf); | 164 | int rtl_usb_resume(struct usb_interface *pusb_intf); |
diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig index be800119d0a3..cbe1e7fef61b 100644 --- a/drivers/net/wireless/ti/Kconfig +++ b/drivers/net/wireless/ti/Kconfig | |||
@@ -12,4 +12,13 @@ source "drivers/net/wireless/ti/wl18xx/Kconfig" | |||
12 | 12 | ||
13 | # keep last for automatic dependencies | 13 | # keep last for automatic dependencies |
14 | source "drivers/net/wireless/ti/wlcore/Kconfig" | 14 | source "drivers/net/wireless/ti/wlcore/Kconfig" |
15 | |||
16 | config WILINK_PLATFORM_DATA | ||
17 | bool "TI WiLink platform data" | ||
18 | depends on WLCORE_SDIO || WL1251_SDIO | ||
19 | default y | ||
20 | ---help--- | ||
21 | Small platform data bit needed to pass data to the sdio modules. | ||
22 | |||
23 | |||
15 | endif # WL_TI | 24 | endif # WL_TI |
diff --git a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile index 4d6823983c04..af14231aeede 100644 --- a/drivers/net/wireless/ti/Makefile +++ b/drivers/net/wireless/ti/Makefile | |||
@@ -1,5 +1,7 @@ | |||
1 | obj-$(CONFIG_WLCORE) += wlcore/ | 1 | obj-$(CONFIG_WLCORE) += wlcore/ |
2 | obj-$(CONFIG_WL12XX) += wl12xx/ | 2 | obj-$(CONFIG_WL12XX) += wl12xx/ |
3 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/ | ||
4 | obj-$(CONFIG_WL1251) += wl1251/ | 3 | obj-$(CONFIG_WL1251) += wl1251/ |
5 | obj-$(CONFIG_WL18XX) += wl18xx/ | 4 | obj-$(CONFIG_WL18XX) += wl18xx/ |
5 | |||
6 | # small builtin driver bit | ||
7 | obj-$(CONFIG_WILINK_PLATFORM_DATA) += wilink_platform_data.o | ||
diff --git a/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c index 998e95895f9d..998e95895f9d 100644 --- a/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c +++ b/drivers/net/wireless/ti/wilink_platform_data.c | |||
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c index 5ec50a476a69..74ae8e1c2e33 100644 --- a/drivers/net/wireless/ti/wl1251/event.c +++ b/drivers/net/wireless/ti/wl1251/event.c | |||
@@ -29,6 +29,8 @@ | |||
29 | static int wl1251_event_scan_complete(struct wl1251 *wl, | 29 | static int wl1251_event_scan_complete(struct wl1251 *wl, |
30 | struct event_mailbox *mbox) | 30 | struct event_mailbox *mbox) |
31 | { | 31 | { |
32 | int ret = 0; | ||
33 | |||
32 | wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", | 34 | wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", |
33 | mbox->scheduled_scan_status, | 35 | mbox->scheduled_scan_status, |
34 | mbox->scheduled_scan_channels); | 36 | mbox->scheduled_scan_channels); |
@@ -37,9 +39,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, | |||
37 | ieee80211_scan_completed(wl->hw, false); | 39 | ieee80211_scan_completed(wl->hw, false); |
38 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); | 40 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); |
39 | wl->scanning = false; | 41 | wl->scanning = false; |
42 | if (wl->hw->conf.flags & IEEE80211_CONF_IDLE) | ||
43 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); | ||
40 | } | 44 | } |
41 | 45 | ||
42 | return 0; | 46 | return ret; |
43 | } | 47 | } |
44 | 48 | ||
45 | static void wl1251_event_mbox_dump(struct event_mailbox *mbox) | 49 | static void wl1251_event_mbox_dump(struct event_mailbox *mbox) |
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index f47e8b0482ad..bbbf68cf50a7 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c | |||
@@ -623,7 +623,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | |||
623 | } | 623 | } |
624 | } | 624 | } |
625 | 625 | ||
626 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | 626 | if (changed & IEEE80211_CONF_CHANGE_IDLE && !wl->scanning) { |
627 | if (conf->flags & IEEE80211_CONF_IDLE) { | 627 | if (conf->flags & IEEE80211_CONF_IDLE) { |
628 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); | 628 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); |
629 | if (ret < 0) | 629 | if (ret < 0) |
@@ -895,11 +895,21 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | |||
895 | if (ret < 0) | 895 | if (ret < 0) |
896 | goto out; | 896 | goto out; |
897 | 897 | ||
898 | if (hw->conf.flags & IEEE80211_CONF_IDLE) { | ||
899 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
900 | if (ret < 0) | ||
901 | goto out_sleep; | ||
902 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
903 | wl->beacon_int, wl->dtim_period); | ||
904 | if (ret < 0) | ||
905 | goto out_sleep; | ||
906 | } | ||
907 | |||
898 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, | 908 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, |
899 | req->ie_len); | 909 | req->ie_len); |
900 | if (!skb) { | 910 | if (!skb) { |
901 | ret = -ENOMEM; | 911 | ret = -ENOMEM; |
902 | goto out; | 912 | goto out_idle; |
903 | } | 913 | } |
904 | if (req->ie_len) | 914 | if (req->ie_len) |
905 | memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); | 915 | memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); |
@@ -908,11 +918,11 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | |||
908 | skb->len); | 918 | skb->len); |
909 | dev_kfree_skb(skb); | 919 | dev_kfree_skb(skb); |
910 | if (ret < 0) | 920 | if (ret < 0) |
911 | goto out_sleep; | 921 | goto out_idle; |
912 | 922 | ||
913 | ret = wl1251_cmd_trigger_scan_to(wl, 0); | 923 | ret = wl1251_cmd_trigger_scan_to(wl, 0); |
914 | if (ret < 0) | 924 | if (ret < 0) |
915 | goto out_sleep; | 925 | goto out_idle; |
916 | 926 | ||
917 | wl->scanning = true; | 927 | wl->scanning = true; |
918 | 928 | ||
@@ -920,9 +930,13 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | |||
920 | req->n_channels, WL1251_SCAN_NUM_PROBES); | 930 | req->n_channels, WL1251_SCAN_NUM_PROBES); |
921 | if (ret < 0) { | 931 | if (ret < 0) { |
922 | wl->scanning = false; | 932 | wl->scanning = false; |
923 | goto out_sleep; | 933 | goto out_idle; |
924 | } | 934 | } |
935 | goto out_sleep; | ||
925 | 936 | ||
937 | out_idle: | ||
938 | if (hw->conf.flags & IEEE80211_CONF_IDLE) | ||
939 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); | ||
926 | out_sleep: | 940 | out_sleep: |
927 | wl1251_ps_elp_sleep(wl); | 941 | wl1251_ps_elp_sleep(wl); |
928 | 942 | ||
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 3254bfc81a2a..09694e39bb14 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c | |||
@@ -1703,7 +1703,8 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { | |||
1703 | static int wl12xx_setup(struct wl1271 *wl) | 1703 | static int wl12xx_setup(struct wl1271 *wl) |
1704 | { | 1704 | { |
1705 | struct wl12xx_priv *priv = wl->priv; | 1705 | struct wl12xx_priv *priv = wl->priv; |
1706 | struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data; | 1706 | struct wlcore_platdev_data *pdev_data = wl->pdev->dev.platform_data; |
1707 | struct wl12xx_platform_data *pdata = pdev_data->pdata; | ||
1707 | 1708 | ||
1708 | wl->rtable = wl12xx_rtable; | 1709 | wl->rtable = wl12xx_rtable; |
1709 | wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; | 1710 | wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; |
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h index b5f114857191..e34302e3b51d 100644 --- a/drivers/net/wireless/ti/wl18xx/conf.h +++ b/drivers/net/wireless/ti/wl18xx/conf.h | |||
@@ -23,7 +23,7 @@ | |||
23 | #define __WL18XX_CONF_H__ | 23 | #define __WL18XX_CONF_H__ |
24 | 24 | ||
25 | #define WL18XX_CONF_MAGIC 0x10e100ca | 25 | #define WL18XX_CONF_MAGIC 0x10e100ca |
26 | #define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0005) | 26 | #define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006) |
27 | #define WL18XX_CONF_MASK 0x0000ffff | 27 | #define WL18XX_CONF_MASK 0x0000ffff |
28 | #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ | 28 | #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ |
29 | sizeof(struct wl18xx_priv_conf)) | 29 | sizeof(struct wl18xx_priv_conf)) |
@@ -70,8 +70,9 @@ struct wl18xx_mac_and_phy_params { | |||
70 | u8 pwr_limit_reference_11_abg; | 70 | u8 pwr_limit_reference_11_abg; |
71 | u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P]; | 71 | u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P]; |
72 | u8 pwr_limit_reference_11p; | 72 | u8 pwr_limit_reference_11p; |
73 | u8 spare1[9]; | 73 | u8 spare1; |
74 | u8 spare2[9]; | 74 | u8 per_chan_bo_mode_11_abg[13]; |
75 | u8 per_chan_bo_mode_11_p[4]; | ||
75 | u8 primary_clock_setting_time; | 76 | u8 primary_clock_setting_time; |
76 | u8 clock_valid_on_wake_up; | 77 | u8 clock_valid_on_wake_up; |
77 | u8 secondary_clock_setting_time; | 78 | u8 secondary_clock_setting_time; |
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 0be1cfc17a86..da3ef1b10a9c 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -547,6 +547,11 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { | |||
547 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 547 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
548 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, | 548 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, |
549 | .pwr_limit_reference_11p = 0x64, | 549 | .pwr_limit_reference_11p = 0x64, |
550 | .per_chan_bo_mode_11_abg = { 0x00, 0x00, 0x00, 0x00, | ||
551 | 0x00, 0x00, 0x00, 0x00, | ||
552 | 0x00, 0x00, 0x00, 0x00, | ||
553 | 0x00 }, | ||
554 | .per_chan_bo_mode_11_p = { 0x00, 0x00, 0x00, 0x00 }, | ||
550 | .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff, | 555 | .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff, |
551 | 0xff, 0xff, 0xff }, | 556 | 0xff, 0xff, 0xff }, |
552 | .psat = 0, | 557 | .psat = 0, |
@@ -1369,7 +1374,7 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl, | |||
1369 | struct ieee80211_sta *sta, | 1374 | struct ieee80211_sta *sta, |
1370 | u32 changed) | 1375 | u32 changed) |
1371 | { | 1376 | { |
1372 | bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 1377 | bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
1373 | 1378 | ||
1374 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); | 1379 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); |
1375 | 1380 | ||
diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig index d7b907e67170..2b832825c3d4 100644 --- a/drivers/net/wireless/ti/wlcore/Kconfig +++ b/drivers/net/wireless/ti/wlcore/Kconfig | |||
@@ -33,8 +33,3 @@ config WLCORE_SDIO | |||
33 | 33 | ||
34 | If you choose to build a module, it'll be called wlcore_sdio. | 34 | If you choose to build a module, it'll be called wlcore_sdio. |
35 | Say N if unsure. | 35 | Say N if unsure. |
36 | |||
37 | config WL12XX_PLATFORM_DATA | ||
38 | bool | ||
39 | depends on WLCORE_SDIO != n || WL1251_SDIO != n | ||
40 | default y | ||
diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile index d9fba9e32130..b21398f6c3ec 100644 --- a/drivers/net/wireless/ti/wlcore/Makefile +++ b/drivers/net/wireless/ti/wlcore/Makefile | |||
@@ -9,7 +9,4 @@ obj-$(CONFIG_WLCORE) += wlcore.o | |||
9 | obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o | 9 | obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o |
10 | obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o | 10 | obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o |
11 | 11 | ||
12 | # small builtin driver bit | ||
13 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o | ||
14 | |||
15 | ccflags-y += -D__CHECK_ENDIAN__ | 12 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index b58ae5fc1487..77752b03f189 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c | |||
@@ -84,8 +84,8 @@ out: | |||
84 | static int wlcore_validate_fw_ver(struct wl1271 *wl) | 84 | static int wlcore_validate_fw_ver(struct wl1271 *wl) |
85 | { | 85 | { |
86 | unsigned int *fw_ver = wl->chip.fw_ver; | 86 | unsigned int *fw_ver = wl->chip.fw_ver; |
87 | unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_NORMAL) ? | 87 | unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_MULTI) ? |
88 | wl->min_sr_fw_ver : wl->min_mr_fw_ver; | 88 | wl->min_mr_fw_ver : wl->min_sr_fw_ver; |
89 | char min_fw_str[32] = ""; | 89 | char min_fw_str[32] = ""; |
90 | int i; | 90 | int i; |
91 | 91 | ||
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 1201aca9c89a..6331f9e1cb39 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -510,10 +510,12 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
510 | cmd->sta.hlid = wlvif->sta.hlid; | 510 | cmd->sta.hlid = wlvif->sta.hlid; |
511 | cmd->sta.session = wl->session_ids[wlvif->sta.hlid]; | 511 | cmd->sta.session = wl->session_ids[wlvif->sta.hlid]; |
512 | /* | 512 | /* |
513 | * We don't have the correct remote rates in this stage. the rates | 513 | * We don't have the correct remote rates in this stage. The |
514 | * will be reconfigured later, after authorization. | 514 | * rates will be reconfigured later, after association, if the |
515 | * firmware supports ACX_PEER_CAP. Otherwise, there's nothing | ||
516 | * we can do, so use all supported_rates here. | ||
515 | */ | 517 | */ |
516 | cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); | 518 | cmd->sta.remote_rates = cpu_to_le32(supported_rates); |
517 | 519 | ||
518 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " | 520 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " |
519 | "basic_rate_set: 0x%x, remote_rates: 0x%x", | 521 | "basic_rate_set: 0x%x, remote_rates: 0x%x", |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index e1dfdf94d0f7..2c2ff3e1f849 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -2162,7 +2162,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) | |||
2162 | return 0; | 2162 | return 0; |
2163 | } | 2163 | } |
2164 | 2164 | ||
2165 | static bool wl12xx_init_fw(struct wl1271 *wl) | 2165 | static int wl12xx_init_fw(struct wl1271 *wl) |
2166 | { | 2166 | { |
2167 | int retries = WL1271_BOOT_RETRIES; | 2167 | int retries = WL1271_BOOT_RETRIES; |
2168 | bool booted = false; | 2168 | bool booted = false; |
@@ -2228,7 +2228,7 @@ power_off: | |||
2228 | 2228 | ||
2229 | wl->state = WLCORE_STATE_ON; | 2229 | wl->state = WLCORE_STATE_ON; |
2230 | out: | 2230 | out: |
2231 | return booted; | 2231 | return ret; |
2232 | } | 2232 | } |
2233 | 2233 | ||
2234 | static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) | 2234 | static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) |
@@ -2371,7 +2371,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, | |||
2371 | struct vif_counter_data vif_count; | 2371 | struct vif_counter_data vif_count; |
2372 | int ret = 0; | 2372 | int ret = 0; |
2373 | u8 role_type; | 2373 | u8 role_type; |
2374 | bool booted = false; | ||
2375 | 2374 | ||
2376 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | | 2375 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | |
2377 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; | 2376 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; |
@@ -2432,11 +2431,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, | |||
2432 | */ | 2431 | */ |
2433 | memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN); | 2432 | memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN); |
2434 | 2433 | ||
2435 | booted = wl12xx_init_fw(wl); | 2434 | ret = wl12xx_init_fw(wl); |
2436 | if (!booted) { | 2435 | if (ret < 0) |
2437 | ret = -EINVAL; | ||
2438 | goto out; | 2436 | goto out; |
2439 | } | ||
2440 | } | 2437 | } |
2441 | 2438 | ||
2442 | ret = wl12xx_cmd_role_enable(wl, vif->addr, | 2439 | ret = wl12xx_cmd_role_enable(wl, vif->addr, |
@@ -5639,7 +5636,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
5639 | IEEE80211_HW_AP_LINK_PS | | 5636 | IEEE80211_HW_AP_LINK_PS | |
5640 | IEEE80211_HW_AMPDU_AGGREGATION | | 5637 | IEEE80211_HW_AMPDU_AGGREGATION | |
5641 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | | 5638 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | |
5642 | IEEE80211_HW_SCAN_WHILE_IDLE | | ||
5643 | IEEE80211_HW_QUEUE_CONTROL; | 5639 | IEEE80211_HW_QUEUE_CONTROL; |
5644 | 5640 | ||
5645 | wl->hw->wiphy->cipher_suites = cipher_suites; | 5641 | wl->hw->wiphy->cipher_suites = cipher_suites; |
@@ -5966,7 +5962,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) | |||
5966 | { | 5962 | { |
5967 | struct wl1271 *wl = context; | 5963 | struct wl1271 *wl = context; |
5968 | struct platform_device *pdev = wl->pdev; | 5964 | struct platform_device *pdev = wl->pdev; |
5969 | struct wl12xx_platform_data *pdata = pdev->dev.platform_data; | 5965 | struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data; |
5966 | struct wl12xx_platform_data *pdata = pdev_data->pdata; | ||
5970 | unsigned long irqflags; | 5967 | unsigned long irqflags; |
5971 | int ret; | 5968 | int ret; |
5972 | 5969 | ||
@@ -5995,8 +5992,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) | |||
5995 | 5992 | ||
5996 | wl->irq = platform_get_irq(pdev, 0); | 5993 | wl->irq = platform_get_irq(pdev, 0); |
5997 | wl->platform_quirks = pdata->platform_quirks; | 5994 | wl->platform_quirks = pdata->platform_quirks; |
5998 | wl->set_power = pdata->set_power; | 5995 | wl->if_ops = pdev_data->if_ops; |
5999 | wl->if_ops = pdata->ops; | ||
6000 | 5996 | ||
6001 | if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) | 5997 | if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) |
6002 | irqflags = IRQF_TRIGGER_RISING; | 5998 | irqflags = IRQF_TRIGGER_RISING; |
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 75622f6f3e6c..29ef2492951f 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c | |||
@@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = { | |||
217 | static int wl1271_probe(struct sdio_func *func, | 217 | static int wl1271_probe(struct sdio_func *func, |
218 | const struct sdio_device_id *id) | 218 | const struct sdio_device_id *id) |
219 | { | 219 | { |
220 | struct wl12xx_platform_data *wlan_data; | 220 | struct wlcore_platdev_data *pdev_data; |
221 | struct wl12xx_sdio_glue *glue; | 221 | struct wl12xx_sdio_glue *glue; |
222 | struct resource res[1]; | 222 | struct resource res[1]; |
223 | mmc_pm_flag_t mmcflags; | 223 | mmc_pm_flag_t mmcflags; |
@@ -228,10 +228,18 @@ static int wl1271_probe(struct sdio_func *func, | |||
228 | if (func->num != 0x02) | 228 | if (func->num != 0x02) |
229 | return -ENODEV; | 229 | return -ENODEV; |
230 | 230 | ||
231 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | 231 | pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); |
232 | if (!glue) | 232 | if (!pdev_data) |
233 | goto out; | 233 | goto out; |
234 | 234 | ||
235 | pdev_data->if_ops = &sdio_ops; | ||
236 | |||
237 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | ||
238 | if (!glue) { | ||
239 | dev_err(&func->dev, "can't allocate glue\n"); | ||
240 | goto out_free_pdev_data; | ||
241 | } | ||
242 | |||
235 | glue->dev = &func->dev; | 243 | glue->dev = &func->dev; |
236 | 244 | ||
237 | /* Grab access to FN0 for ELP reg. */ | 245 | /* Grab access to FN0 for ELP reg. */ |
@@ -240,9 +248,9 @@ static int wl1271_probe(struct sdio_func *func, | |||
240 | /* Use block mode for transferring over one block size of data */ | 248 | /* Use block mode for transferring over one block size of data */ |
241 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; | 249 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; |
242 | 250 | ||
243 | wlan_data = wl12xx_get_platform_data(); | 251 | pdev_data->pdata = wl12xx_get_platform_data(); |
244 | if (IS_ERR(wlan_data)) { | 252 | if (IS_ERR(pdev_data->pdata)) { |
245 | ret = PTR_ERR(wlan_data); | 253 | ret = PTR_ERR(pdev_data->pdata); |
246 | dev_err(glue->dev, "missing wlan platform data: %d\n", ret); | 254 | dev_err(glue->dev, "missing wlan platform data: %d\n", ret); |
247 | goto out_free_glue; | 255 | goto out_free_glue; |
248 | } | 256 | } |
@@ -252,9 +260,7 @@ static int wl1271_probe(struct sdio_func *func, | |||
252 | dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); | 260 | dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); |
253 | 261 | ||
254 | if (mmcflags & MMC_PM_KEEP_POWER) | 262 | if (mmcflags & MMC_PM_KEEP_POWER) |
255 | wlan_data->pwr_in_suspend = true; | 263 | pdev_data->pdata->pwr_in_suspend = true; |
256 | |||
257 | wlan_data->ops = &sdio_ops; | ||
258 | 264 | ||
259 | sdio_set_drvdata(func, glue); | 265 | sdio_set_drvdata(func, glue); |
260 | 266 | ||
@@ -272,7 +278,7 @@ static int wl1271_probe(struct sdio_func *func, | |||
272 | else | 278 | else |
273 | chip_family = "wl12xx"; | 279 | chip_family = "wl12xx"; |
274 | 280 | ||
275 | glue->core = platform_device_alloc(chip_family, -1); | 281 | glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO); |
276 | if (!glue->core) { | 282 | if (!glue->core) { |
277 | dev_err(glue->dev, "can't allocate platform_device"); | 283 | dev_err(glue->dev, "can't allocate platform_device"); |
278 | ret = -ENOMEM; | 284 | ret = -ENOMEM; |
@@ -283,7 +289,7 @@ static int wl1271_probe(struct sdio_func *func, | |||
283 | 289 | ||
284 | memset(res, 0x00, sizeof(res)); | 290 | memset(res, 0x00, sizeof(res)); |
285 | 291 | ||
286 | res[0].start = wlan_data->irq; | 292 | res[0].start = pdev_data->pdata->irq; |
287 | res[0].flags = IORESOURCE_IRQ; | 293 | res[0].flags = IORESOURCE_IRQ; |
288 | res[0].name = "irq"; | 294 | res[0].name = "irq"; |
289 | 295 | ||
@@ -293,8 +299,8 @@ static int wl1271_probe(struct sdio_func *func, | |||
293 | goto out_dev_put; | 299 | goto out_dev_put; |
294 | } | 300 | } |
295 | 301 | ||
296 | ret = platform_device_add_data(glue->core, wlan_data, | 302 | ret = platform_device_add_data(glue->core, pdev_data, |
297 | sizeof(*wlan_data)); | 303 | sizeof(*pdev_data)); |
298 | if (ret) { | 304 | if (ret) { |
299 | dev_err(glue->dev, "can't add platform data\n"); | 305 | dev_err(glue->dev, "can't add platform data\n"); |
300 | goto out_dev_put; | 306 | goto out_dev_put; |
@@ -313,6 +319,9 @@ out_dev_put: | |||
313 | out_free_glue: | 319 | out_free_glue: |
314 | kfree(glue); | 320 | kfree(glue); |
315 | 321 | ||
322 | out_free_pdev_data: | ||
323 | kfree(pdev_data); | ||
324 | |||
316 | out: | 325 | out: |
317 | return ret; | 326 | return ret; |
318 | } | 327 | } |
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 53790d1d0d27..e26447832683 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c | |||
@@ -87,8 +87,11 @@ static void wl12xx_spi_reset(struct device *child) | |||
87 | struct spi_message m; | 87 | struct spi_message m; |
88 | 88 | ||
89 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | 89 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); |
90 | if (!cmd) | 90 | if (!cmd) { |
91 | dev_err(child->parent, | ||
92 | "could not allocate cmd for spi reset\n"); | ||
91 | return; | 93 | return; |
94 | } | ||
92 | 95 | ||
93 | memset(&t, 0, sizeof(t)); | 96 | memset(&t, 0, sizeof(t)); |
94 | spi_message_init(&m); | 97 | spi_message_init(&m); |
@@ -112,8 +115,11 @@ static void wl12xx_spi_init(struct device *child) | |||
112 | struct spi_message m; | 115 | struct spi_message m; |
113 | 116 | ||
114 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | 117 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); |
115 | if (!cmd) | 118 | if (!cmd) { |
119 | dev_err(child->parent, | ||
120 | "could not allocate cmd for spi init\n"); | ||
116 | return; | 121 | return; |
122 | } | ||
117 | 123 | ||
118 | memset(crc, 0, sizeof(crc)); | 124 | memset(crc, 0, sizeof(crc)); |
119 | memset(&t, 0, sizeof(t)); | 125 | memset(&t, 0, sizeof(t)); |
@@ -321,21 +327,28 @@ static struct wl1271_if_operations spi_ops = { | |||
321 | static int wl1271_probe(struct spi_device *spi) | 327 | static int wl1271_probe(struct spi_device *spi) |
322 | { | 328 | { |
323 | struct wl12xx_spi_glue *glue; | 329 | struct wl12xx_spi_glue *glue; |
324 | struct wl12xx_platform_data *pdata; | 330 | struct wlcore_platdev_data *pdev_data; |
325 | struct resource res[1]; | 331 | struct resource res[1]; |
326 | int ret = -ENOMEM; | 332 | int ret = -ENOMEM; |
327 | 333 | ||
328 | pdata = spi->dev.platform_data; | 334 | pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); |
329 | if (!pdata) { | 335 | if (!pdev_data) |
336 | goto out; | ||
337 | |||
338 | pdev_data->pdata = spi->dev.platform_data; | ||
339 | if (!pdev_data->pdata) { | ||
330 | dev_err(&spi->dev, "no platform data\n"); | 340 | dev_err(&spi->dev, "no platform data\n"); |
331 | return -ENODEV; | 341 | ret = -ENODEV; |
342 | goto out_free_pdev_data; | ||
332 | } | 343 | } |
333 | 344 | ||
334 | pdata->ops = &spi_ops; | 345 | pdev_data->if_ops = &spi_ops; |
335 | 346 | ||
336 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | 347 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); |
337 | if (!glue) | 348 | if (!glue) { |
338 | goto out; | 349 | dev_err(&spi->dev, "can't allocate glue\n"); |
350 | goto out_free_pdev_data; | ||
351 | } | ||
339 | 352 | ||
340 | glue->dev = &spi->dev; | 353 | glue->dev = &spi->dev; |
341 | 354 | ||
@@ -351,7 +364,7 @@ static int wl1271_probe(struct spi_device *spi) | |||
351 | goto out_free_glue; | 364 | goto out_free_glue; |
352 | } | 365 | } |
353 | 366 | ||
354 | glue->core = platform_device_alloc("wl12xx", -1); | 367 | glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO); |
355 | if (!glue->core) { | 368 | if (!glue->core) { |
356 | dev_err(glue->dev, "can't allocate platform_device\n"); | 369 | dev_err(glue->dev, "can't allocate platform_device\n"); |
357 | ret = -ENOMEM; | 370 | ret = -ENOMEM; |
@@ -372,7 +385,8 @@ static int wl1271_probe(struct spi_device *spi) | |||
372 | goto out_dev_put; | 385 | goto out_dev_put; |
373 | } | 386 | } |
374 | 387 | ||
375 | ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata)); | 388 | ret = platform_device_add_data(glue->core, pdev_data, |
389 | sizeof(*pdev_data)); | ||
376 | if (ret) { | 390 | if (ret) { |
377 | dev_err(glue->dev, "can't add platform data\n"); | 391 | dev_err(glue->dev, "can't add platform data\n"); |
378 | goto out_dev_put; | 392 | goto out_dev_put; |
@@ -391,6 +405,10 @@ out_dev_put: | |||
391 | 405 | ||
392 | out_free_glue: | 406 | out_free_glue: |
393 | kfree(glue); | 407 | kfree(glue); |
408 | |||
409 | out_free_pdev_data: | ||
410 | kfree(pdev_data); | ||
411 | |||
394 | out: | 412 | out: |
395 | return ret; | 413 | return ret; |
396 | } | 414 | } |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index ebd8c6fad7cd..af9fecaefc30 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h | |||
@@ -183,7 +183,6 @@ struct wl1271 { | |||
183 | 183 | ||
184 | struct wl1271_if_operations *if_ops; | 184 | struct wl1271_if_operations *if_ops; |
185 | 185 | ||
186 | void (*set_power)(bool enable); | ||
187 | int irq; | 186 | int irq; |
188 | 187 | ||
189 | spinlock_t wl_lock; | 188 | spinlock_t wl_lock; |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 910f8e2e556a..508f5b0f8a70 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h | |||
@@ -206,6 +206,11 @@ struct wl1271_if_operations { | |||
206 | void (*set_block_size) (struct device *child, unsigned int blksz); | 206 | void (*set_block_size) (struct device *child, unsigned int blksz); |
207 | }; | 207 | }; |
208 | 208 | ||
209 | struct wlcore_platdev_data { | ||
210 | struct wl12xx_platform_data *pdata; | ||
211 | struct wl1271_if_operations *if_ops; | ||
212 | }; | ||
213 | |||
209 | #define MAX_NUM_KEYS 14 | 214 | #define MAX_NUM_KEYS 14 |
210 | #define MAX_KEY_SIZE 32 | 215 | #define MAX_KEY_SIZE 32 |
211 | 216 | ||
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 80c728b28828..e57034971ccc 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig | |||
@@ -27,5 +27,6 @@ config NFC_WILINK | |||
27 | into the kernel or say M to compile it as module. | 27 | into the kernel or say M to compile it as module. |
28 | 28 | ||
29 | source "drivers/nfc/pn544/Kconfig" | 29 | source "drivers/nfc/pn544/Kconfig" |
30 | source "drivers/nfc/microread/Kconfig" | ||
30 | 31 | ||
31 | endmenu | 32 | endmenu |
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 574bbc04d97a..a189ada0926a 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_NFC_PN544) += pn544/ | 5 | obj-$(CONFIG_NFC_PN544) += pn544/ |
6 | obj-$(CONFIG_NFC_MICROREAD) += microread/ | ||
6 | obj-$(CONFIG_NFC_PN533) += pn533.o | 7 | obj-$(CONFIG_NFC_PN533) += pn533.o |
7 | obj-$(CONFIG_NFC_WILINK) += nfcwilink.o | 8 | obj-$(CONFIG_NFC_WILINK) += nfcwilink.o |
8 | 9 | ||
diff --git a/drivers/nfc/microread/Kconfig b/drivers/nfc/microread/Kconfig new file mode 100644 index 000000000000..572305be6e37 --- /dev/null +++ b/drivers/nfc/microread/Kconfig | |||
@@ -0,0 +1,35 @@ | |||
1 | config NFC_MICROREAD | ||
2 | tristate "Inside Secure microread NFC driver" | ||
3 | depends on NFC_HCI | ||
4 | select CRC_CCITT | ||
5 | default n | ||
6 | ---help--- | ||
7 | This module contains the main code for Inside Secure microread | ||
8 | NFC chipsets. It implements the chipset HCI logic and hooks into | ||
9 | the NFC kernel APIs. Physical layers will register against it. | ||
10 | |||
11 | To compile this driver as a module, choose m here. The module will | ||
12 | be called microread. | ||
13 | Say N if unsure. | ||
14 | |||
15 | config NFC_MICROREAD_I2C | ||
16 | tristate "NFC Microread i2c support" | ||
17 | depends on NFC_MICROREAD && I2C && NFC_SHDLC | ||
18 | ---help--- | ||
19 | This module adds support for the i2c interface of adapters using | ||
20 | Inside microread chipsets. Select this if your platform is using | ||
21 | the i2c bus. | ||
22 | |||
23 | If you choose to build a module, it'll be called microread_i2c. | ||
24 | Say N if unsure. | ||
25 | |||
26 | config NFC_MICROREAD_MEI | ||
27 | tristate "NFC Microread MEI support" | ||
28 | depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC | ||
29 | ---help--- | ||
30 | This module adds support for the mei interface of adapters using | ||
31 | Inside microread chipsets. Select this if your microread chipset | ||
32 | is handled by Intel's Management Engine Interface on your platform. | ||
33 | |||
34 | If you choose to build a module, it'll be called microread_mei. | ||
35 | Say N if unsure. | ||
diff --git a/drivers/nfc/microread/Makefile b/drivers/nfc/microread/Makefile new file mode 100644 index 000000000000..755c24cba253 --- /dev/null +++ b/drivers/nfc/microread/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for Microread HCI based NFC driver | ||
3 | # | ||
4 | |||
5 | microread_i2c-objs = i2c.o | ||
6 | microread_mei-objs = mei.o | ||
7 | |||
8 | obj-$(CONFIG_NFC_MICROREAD) += microread.o | ||
9 | obj-$(CONFIG_NFC_MICROREAD_I2C) += microread_i2c.o | ||
10 | obj-$(CONFIG_NFC_MICROREAD_MEI) += microread_mei.o | ||
diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c new file mode 100644 index 000000000000..101089495bf8 --- /dev/null +++ b/drivers/nfc/microread/i2c.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * HCI based Driver for Inside Secure microread NFC Chip - i2c layer | ||
3 | * | ||
4 | * Copyright (C) 2013 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/gpio.h> | ||
27 | |||
28 | #include <linux/nfc.h> | ||
29 | #include <net/nfc/hci.h> | ||
30 | #include <net/nfc/llc.h> | ||
31 | |||
32 | #include "microread.h" | ||
33 | |||
34 | #define MICROREAD_I2C_DRIVER_NAME "microread" | ||
35 | |||
36 | #define MICROREAD_I2C_FRAME_HEADROOM 1 | ||
37 | #define MICROREAD_I2C_FRAME_TAILROOM 1 | ||
38 | |||
39 | /* framing in HCI mode */ | ||
40 | #define MICROREAD_I2C_LLC_LEN 1 | ||
41 | #define MICROREAD_I2C_LLC_CRC 1 | ||
42 | #define MICROREAD_I2C_LLC_LEN_CRC (MICROREAD_I2C_LLC_LEN + \ | ||
43 | MICROREAD_I2C_LLC_CRC) | ||
44 | #define MICROREAD_I2C_LLC_MIN_SIZE (1 + MICROREAD_I2C_LLC_LEN_CRC) | ||
45 | #define MICROREAD_I2C_LLC_MAX_PAYLOAD 29 | ||
46 | #define MICROREAD_I2C_LLC_MAX_SIZE (MICROREAD_I2C_LLC_LEN_CRC + 1 + \ | ||
47 | MICROREAD_I2C_LLC_MAX_PAYLOAD) | ||
48 | |||
49 | struct microread_i2c_phy { | ||
50 | struct i2c_client *i2c_dev; | ||
51 | struct nfc_hci_dev *hdev; | ||
52 | |||
53 | int irq; | ||
54 | |||
55 | int hard_fault; /* | ||
56 | * < 0 if hardware error occured (e.g. i2c err) | ||
57 | * and prevents normal operation. | ||
58 | */ | ||
59 | }; | ||
60 | |||
61 | #define I2C_DUMP_SKB(info, skb) \ | ||
62 | do { \ | ||
63 | pr_debug("%s:\n", info); \ | ||
64 | print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \ | ||
65 | 16, 1, (skb)->data, (skb)->len, 0); \ | ||
66 | } while (0) | ||
67 | |||
68 | static void microread_i2c_add_len_crc(struct sk_buff *skb) | ||
69 | { | ||
70 | int i; | ||
71 | u8 crc = 0; | ||
72 | int len; | ||
73 | |||
74 | len = skb->len; | ||
75 | *skb_push(skb, 1) = len; | ||
76 | |||
77 | for (i = 0; i < skb->len; i++) | ||
78 | crc = crc ^ skb->data[i]; | ||
79 | |||
80 | *skb_put(skb, 1) = crc; | ||
81 | } | ||
82 | |||
83 | static void microread_i2c_remove_len_crc(struct sk_buff *skb) | ||
84 | { | ||
85 | skb_pull(skb, MICROREAD_I2C_FRAME_HEADROOM); | ||
86 | skb_trim(skb, MICROREAD_I2C_FRAME_TAILROOM); | ||
87 | } | ||
88 | |||
89 | static int check_crc(struct sk_buff *skb) | ||
90 | { | ||
91 | int i; | ||
92 | u8 crc = 0; | ||
93 | |||
94 | for (i = 0; i < skb->len - 1; i++) | ||
95 | crc = crc ^ skb->data[i]; | ||
96 | |||
97 | if (crc != skb->data[skb->len-1]) { | ||
98 | pr_err(MICROREAD_I2C_DRIVER_NAME | ||
99 | ": CRC error 0x%x != 0x%x\n", | ||
100 | crc, skb->data[skb->len-1]); | ||
101 | |||
102 | pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); | ||
103 | |||
104 | return -EPERM; | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int microread_i2c_enable(void *phy_id) | ||
111 | { | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void microread_i2c_disable(void *phy_id) | ||
116 | { | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | static int microread_i2c_write(void *phy_id, struct sk_buff *skb) | ||
121 | { | ||
122 | int r; | ||
123 | struct microread_i2c_phy *phy = phy_id; | ||
124 | struct i2c_client *client = phy->i2c_dev; | ||
125 | |||
126 | if (phy->hard_fault != 0) | ||
127 | return phy->hard_fault; | ||
128 | |||
129 | usleep_range(3000, 6000); | ||
130 | |||
131 | microread_i2c_add_len_crc(skb); | ||
132 | |||
133 | I2C_DUMP_SKB("i2c frame written", skb); | ||
134 | |||
135 | r = i2c_master_send(client, skb->data, skb->len); | ||
136 | |||
137 | if (r == -EREMOTEIO) { /* Retry, chip was in standby */ | ||
138 | usleep_range(6000, 10000); | ||
139 | r = i2c_master_send(client, skb->data, skb->len); | ||
140 | } | ||
141 | |||
142 | if (r >= 0) { | ||
143 | if (r != skb->len) | ||
144 | r = -EREMOTEIO; | ||
145 | else | ||
146 | r = 0; | ||
147 | } | ||
148 | |||
149 | microread_i2c_remove_len_crc(skb); | ||
150 | |||
151 | return r; | ||
152 | } | ||
153 | |||
154 | |||
155 | static int microread_i2c_read(struct microread_i2c_phy *phy, | ||
156 | struct sk_buff **skb) | ||
157 | { | ||
158 | int r; | ||
159 | u8 len; | ||
160 | u8 tmp[MICROREAD_I2C_LLC_MAX_SIZE - 1]; | ||
161 | struct i2c_client *client = phy->i2c_dev; | ||
162 | |||
163 | pr_debug("%s\n", __func__); | ||
164 | |||
165 | r = i2c_master_recv(client, &len, 1); | ||
166 | if (r != 1) { | ||
167 | dev_err(&client->dev, "cannot read len byte\n"); | ||
168 | return -EREMOTEIO; | ||
169 | } | ||
170 | |||
171 | if ((len < MICROREAD_I2C_LLC_MIN_SIZE) || | ||
172 | (len > MICROREAD_I2C_LLC_MAX_SIZE)) { | ||
173 | dev_err(&client->dev, "invalid len byte\n"); | ||
174 | pr_err("invalid len byte\n"); | ||
175 | r = -EBADMSG; | ||
176 | goto flush; | ||
177 | } | ||
178 | |||
179 | *skb = alloc_skb(1 + len, GFP_KERNEL); | ||
180 | if (*skb == NULL) { | ||
181 | r = -ENOMEM; | ||
182 | goto flush; | ||
183 | } | ||
184 | |||
185 | *skb_put(*skb, 1) = len; | ||
186 | |||
187 | r = i2c_master_recv(client, skb_put(*skb, len), len); | ||
188 | if (r != len) { | ||
189 | kfree_skb(*skb); | ||
190 | return -EREMOTEIO; | ||
191 | } | ||
192 | |||
193 | I2C_DUMP_SKB("cc frame read", *skb); | ||
194 | |||
195 | r = check_crc(*skb); | ||
196 | if (r != 0) { | ||
197 | kfree_skb(*skb); | ||
198 | r = -EBADMSG; | ||
199 | goto flush; | ||
200 | } | ||
201 | |||
202 | skb_pull(*skb, 1); | ||
203 | skb_trim(*skb, (*skb)->len - MICROREAD_I2C_FRAME_TAILROOM); | ||
204 | |||
205 | usleep_range(3000, 6000); | ||
206 | |||
207 | return 0; | ||
208 | |||
209 | flush: | ||
210 | if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) | ||
211 | r = -EREMOTEIO; | ||
212 | |||
213 | usleep_range(3000, 6000); | ||
214 | |||
215 | return r; | ||
216 | } | ||
217 | |||
218 | static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id) | ||
219 | { | ||
220 | struct microread_i2c_phy *phy = phy_id; | ||
221 | struct i2c_client *client; | ||
222 | struct sk_buff *skb = NULL; | ||
223 | int r; | ||
224 | |||
225 | if (!phy || irq != phy->i2c_dev->irq) { | ||
226 | WARN_ON_ONCE(1); | ||
227 | return IRQ_NONE; | ||
228 | } | ||
229 | |||
230 | client = phy->i2c_dev; | ||
231 | dev_dbg(&client->dev, "IRQ\n"); | ||
232 | |||
233 | if (phy->hard_fault != 0) | ||
234 | return IRQ_HANDLED; | ||
235 | |||
236 | r = microread_i2c_read(phy, &skb); | ||
237 | if (r == -EREMOTEIO) { | ||
238 | phy->hard_fault = r; | ||
239 | |||
240 | nfc_hci_recv_frame(phy->hdev, NULL); | ||
241 | |||
242 | return IRQ_HANDLED; | ||
243 | } else if ((r == -ENOMEM) || (r == -EBADMSG)) { | ||
244 | return IRQ_HANDLED; | ||
245 | } | ||
246 | |||
247 | nfc_hci_recv_frame(phy->hdev, skb); | ||
248 | |||
249 | return IRQ_HANDLED; | ||
250 | } | ||
251 | |||
252 | static struct nfc_phy_ops i2c_phy_ops = { | ||
253 | .write = microread_i2c_write, | ||
254 | .enable = microread_i2c_enable, | ||
255 | .disable = microread_i2c_disable, | ||
256 | }; | ||
257 | |||
258 | static int microread_i2c_probe(struct i2c_client *client, | ||
259 | const struct i2c_device_id *id) | ||
260 | { | ||
261 | struct microread_i2c_phy *phy; | ||
262 | struct microread_nfc_platform_data *pdata = | ||
263 | dev_get_platdata(&client->dev); | ||
264 | int r; | ||
265 | |||
266 | dev_dbg(&client->dev, "client %p", client); | ||
267 | |||
268 | if (!pdata) { | ||
269 | dev_err(&client->dev, "client %p: missing platform data", | ||
270 | client); | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | |||
274 | phy = devm_kzalloc(&client->dev, sizeof(struct microread_i2c_phy), | ||
275 | GFP_KERNEL); | ||
276 | if (!phy) { | ||
277 | dev_err(&client->dev, "Can't allocate microread phy"); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | |||
281 | i2c_set_clientdata(client, phy); | ||
282 | phy->i2c_dev = client; | ||
283 | |||
284 | r = request_threaded_irq(client->irq, NULL, microread_i2c_irq_thread_fn, | ||
285 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
286 | MICROREAD_I2C_DRIVER_NAME, phy); | ||
287 | if (r) { | ||
288 | dev_err(&client->dev, "Unable to register IRQ handler"); | ||
289 | return r; | ||
290 | } | ||
291 | |||
292 | r = microread_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, | ||
293 | MICROREAD_I2C_FRAME_HEADROOM, | ||
294 | MICROREAD_I2C_FRAME_TAILROOM, | ||
295 | MICROREAD_I2C_LLC_MAX_PAYLOAD, &phy->hdev); | ||
296 | if (r < 0) | ||
297 | goto err_irq; | ||
298 | |||
299 | dev_info(&client->dev, "Probed"); | ||
300 | |||
301 | return 0; | ||
302 | |||
303 | err_irq: | ||
304 | free_irq(client->irq, phy); | ||
305 | |||
306 | return r; | ||
307 | } | ||
308 | |||
309 | static int microread_i2c_remove(struct i2c_client *client) | ||
310 | { | ||
311 | struct microread_i2c_phy *phy = i2c_get_clientdata(client); | ||
312 | |||
313 | dev_dbg(&client->dev, "%s\n", __func__); | ||
314 | |||
315 | microread_remove(phy->hdev); | ||
316 | |||
317 | free_irq(client->irq, phy); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static struct i2c_device_id microread_i2c_id[] = { | ||
323 | { MICROREAD_I2C_DRIVER_NAME, 0}, | ||
324 | { } | ||
325 | }; | ||
326 | MODULE_DEVICE_TABLE(i2c, microread_i2c_id); | ||
327 | |||
328 | static struct i2c_driver microread_i2c_driver = { | ||
329 | .driver = { | ||
330 | .name = MICROREAD_I2C_DRIVER_NAME, | ||
331 | }, | ||
332 | .probe = microread_i2c_probe, | ||
333 | .remove = microread_i2c_remove, | ||
334 | .id_table = microread_i2c_id, | ||
335 | }; | ||
336 | |||
337 | module_i2c_driver(microread_i2c_driver); | ||
338 | |||
339 | MODULE_LICENSE("GPL"); | ||
340 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c new file mode 100644 index 000000000000..eef38cfd812e --- /dev/null +++ b/drivers/nfc/microread/mei.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * HCI based Driver for Inside Secure microread NFC Chip | ||
3 | * | ||
4 | * Copyright (C) 2013 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/mei_bus.h> | ||
26 | |||
27 | #include <linux/nfc.h> | ||
28 | #include <net/nfc/hci.h> | ||
29 | #include <net/nfc/llc.h> | ||
30 | |||
31 | #include "microread.h" | ||
32 | |||
33 | #define MICROREAD_DRIVER_NAME "microread" | ||
34 | |||
35 | #define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \ | ||
36 | 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c) | ||
37 | |||
38 | struct mei_nfc_hdr { | ||
39 | u8 cmd; | ||
40 | u8 status; | ||
41 | u16 req_id; | ||
42 | u32 reserved; | ||
43 | u16 data_size; | ||
44 | } __attribute__((packed)); | ||
45 | |||
46 | #define MEI_NFC_HEADER_SIZE 10 | ||
47 | #define MEI_NFC_MAX_HCI_PAYLOAD 300 | ||
48 | #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) | ||
49 | |||
50 | struct microread_mei_phy { | ||
51 | struct mei_device *mei_device; | ||
52 | struct nfc_hci_dev *hdev; | ||
53 | |||
54 | int powered; | ||
55 | |||
56 | int hard_fault; /* | ||
57 | * < 0 if hardware error occured (e.g. i2c err) | ||
58 | * and prevents normal operation. | ||
59 | */ | ||
60 | }; | ||
61 | |||
62 | #define MEI_DUMP_SKB_IN(info, skb) \ | ||
63 | do { \ | ||
64 | pr_debug("%s:\n", info); \ | ||
65 | print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \ | ||
66 | 16, 1, (skb)->data, (skb)->len, 0); \ | ||
67 | } while (0) | ||
68 | |||
69 | #define MEI_DUMP_SKB_OUT(info, skb) \ | ||
70 | do { \ | ||
71 | pr_debug("%s:\n", info); \ | ||
72 | print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \ | ||
73 | 16, 1, (skb)->data, (skb)->len, 0); \ | ||
74 | } while (0) | ||
75 | |||
76 | static int microread_mei_enable(void *phy_id) | ||
77 | { | ||
78 | struct microread_mei_phy *phy = phy_id; | ||
79 | |||
80 | pr_info(DRIVER_DESC ": %s\n", __func__); | ||
81 | |||
82 | phy->powered = 1; | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static void microread_mei_disable(void *phy_id) | ||
88 | { | ||
89 | struct microread_mei_phy *phy = phy_id; | ||
90 | |||
91 | pr_info(DRIVER_DESC ": %s\n", __func__); | ||
92 | |||
93 | phy->powered = 0; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Writing a frame must not return the number of written bytes. | ||
98 | * It must return either zero for success, or <0 for error. | ||
99 | * In addition, it must not alter the skb | ||
100 | */ | ||
101 | static int microread_mei_write(void *phy_id, struct sk_buff *skb) | ||
102 | { | ||
103 | struct microread_mei_phy *phy = phy_id; | ||
104 | int r; | ||
105 | |||
106 | MEI_DUMP_SKB_OUT("mei frame sent", skb); | ||
107 | |||
108 | r = mei_send(phy->device, skb->data, skb->len); | ||
109 | if (r > 0) | ||
110 | r = 0; | ||
111 | |||
112 | return r; | ||
113 | } | ||
114 | |||
115 | static void microread_event_cb(struct mei_device *device, u32 events, | ||
116 | void *context) | ||
117 | { | ||
118 | struct microread_mei_phy *phy = context; | ||
119 | |||
120 | if (phy->hard_fault != 0) | ||
121 | return; | ||
122 | |||
123 | if (events & BIT(MEI_EVENT_RX)) { | ||
124 | struct sk_buff *skb; | ||
125 | int reply_size; | ||
126 | |||
127 | skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); | ||
128 | if (!skb) | ||
129 | return; | ||
130 | |||
131 | reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ); | ||
132 | if (reply_size < MEI_NFC_HEADER_SIZE) { | ||
133 | kfree(skb); | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | skb_put(skb, reply_size); | ||
138 | skb_pull(skb, MEI_NFC_HEADER_SIZE); | ||
139 | |||
140 | MEI_DUMP_SKB_IN("mei frame read", skb); | ||
141 | |||
142 | nfc_hci_recv_frame(phy->hdev, skb); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static struct nfc_phy_ops mei_phy_ops = { | ||
147 | .write = microread_mei_write, | ||
148 | .enable = microread_mei_enable, | ||
149 | .disable = microread_mei_disable, | ||
150 | }; | ||
151 | |||
152 | static int microread_mei_probe(struct mei_device *device, | ||
153 | const struct mei_id *id) | ||
154 | { | ||
155 | struct microread_mei_phy *phy; | ||
156 | int r; | ||
157 | |||
158 | pr_info("Probing NFC microread\n"); | ||
159 | |||
160 | phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL); | ||
161 | if (!phy) { | ||
162 | pr_err("Cannot allocate memory for microread mei phy.\n"); | ||
163 | return -ENOMEM; | ||
164 | } | ||
165 | |||
166 | phy->device = device; | ||
167 | mei_set_clientdata(device, phy); | ||
168 | |||
169 | r = mei_register_event_cb(device, microread_event_cb, phy); | ||
170 | if (r) { | ||
171 | pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); | ||
172 | goto err_out; | ||
173 | } | ||
174 | |||
175 | r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME, | ||
176 | MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, | ||
177 | &phy->hdev); | ||
178 | if (r < 0) | ||
179 | goto err_out; | ||
180 | |||
181 | return 0; | ||
182 | |||
183 | err_out: | ||
184 | kfree(phy); | ||
185 | |||
186 | return r; | ||
187 | } | ||
188 | |||
189 | static int microread_mei_remove(struct mei_device *device) | ||
190 | { | ||
191 | struct microread_mei_phy *phy = mei_get_clientdata(device); | ||
192 | |||
193 | pr_info("Removing microread\n"); | ||
194 | |||
195 | microread_remove(phy->hdev); | ||
196 | |||
197 | if (phy->powered) | ||
198 | microread_mei_disable(phy); | ||
199 | |||
200 | kfree(phy); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static struct mei_id microread_mei_tbl[] = { | ||
206 | { MICROREAD_DRIVER_NAME, MICROREAD_UUID }, | ||
207 | |||
208 | /* required last entry */ | ||
209 | { } | ||
210 | }; | ||
211 | |||
212 | MODULE_DEVICE_TABLE(mei, microread_mei_tbl); | ||
213 | |||
214 | static struct mei_driver microread_driver = { | ||
215 | .id_table = microread_mei_tbl, | ||
216 | .name = MICROREAD_DRIVER_NAME, | ||
217 | |||
218 | .probe = microread_mei_probe, | ||
219 | .remove = microread_mei_remove, | ||
220 | }; | ||
221 | |||
222 | static int microread_mei_init(void) | ||
223 | { | ||
224 | int r; | ||
225 | |||
226 | pr_debug(DRIVER_DESC ": %s\n", __func__); | ||
227 | |||
228 | r = mei_driver_register(µread_driver); | ||
229 | if (r) { | ||
230 | pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n"); | ||
231 | return r; | ||
232 | } | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void microread_mei_exit(void) | ||
238 | { | ||
239 | mei_driver_unregister(µread_driver); | ||
240 | } | ||
241 | |||
242 | module_init(microread_mei_init); | ||
243 | module_exit(microread_mei_exit); | ||
244 | |||
245 | MODULE_LICENSE("GPL"); | ||
246 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c new file mode 100644 index 000000000000..3420d833db17 --- /dev/null +++ b/drivers/nfc/microread/microread.c | |||
@@ -0,0 +1,728 @@ | |||
1 | /* | ||
2 | * HCI based Driver for Inside Secure microread NFC Chip | ||
3 | * | ||
4 | * Copyright (C) 2013 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/crc-ccitt.h> | ||
25 | |||
26 | #include <linux/nfc.h> | ||
27 | #include <net/nfc/nfc.h> | ||
28 | #include <net/nfc/hci.h> | ||
29 | #include <net/nfc/llc.h> | ||
30 | |||
31 | #include "microread.h" | ||
32 | |||
33 | /* Proprietary gates, events, commands and registers */ | ||
34 | /* Admin */ | ||
35 | #define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE | ||
36 | #define MICROREAD_GATE_ID_MGT 0x01 | ||
37 | #define MICROREAD_GATE_ID_OS 0x02 | ||
38 | #define MICROREAD_GATE_ID_TESTRF 0x03 | ||
39 | #define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE | ||
40 | #define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE | ||
41 | #define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE | ||
42 | |||
43 | /* Reader */ | ||
44 | #define MICROREAD_GATE_ID_MREAD_GEN 0x10 | ||
45 | #define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE | ||
46 | #define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12 | ||
47 | #define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE | ||
48 | #define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14 | ||
49 | #define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15 | ||
50 | #define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16 | ||
51 | #define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17 | ||
52 | #define MICROREAD_GATE_ID_MREAD_BPRIME 0x18 | ||
53 | #define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19 | ||
54 | |||
55 | /* Card */ | ||
56 | #define MICROREAD_GATE_ID_MCARD_GEN 0x20 | ||
57 | #define MICROREAD_GATE_ID_MCARD_ISO_B 0x21 | ||
58 | #define MICROREAD_GATE_ID_MCARD_BPRIME 0x22 | ||
59 | #define MICROREAD_GATE_ID_MCARD_ISO_A 0x23 | ||
60 | #define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24 | ||
61 | #define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25 | ||
62 | #define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26 | ||
63 | #define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27 | ||
64 | #define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28 | ||
65 | #define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F | ||
66 | |||
67 | /* P2P */ | ||
68 | #define MICROREAD_GATE_ID_P2P_GEN 0x30 | ||
69 | #define MICROREAD_GATE_ID_P2P_TARGET 0x31 | ||
70 | #define MICROREAD_PAR_P2P_TARGET_MODE 0x01 | ||
71 | #define MICROREAD_PAR_P2P_TARGET_GT 0x04 | ||
72 | #define MICROREAD_GATE_ID_P2P_INITIATOR 0x32 | ||
73 | #define MICROREAD_PAR_P2P_INITIATOR_GI 0x01 | ||
74 | #define MICROREAD_PAR_P2P_INITIATOR_GT 0x03 | ||
75 | |||
76 | /* Those pipes are created/opened by default in the chip */ | ||
77 | #define MICROREAD_PIPE_ID_LMS 0x00 | ||
78 | #define MICROREAD_PIPE_ID_ADMIN 0x01 | ||
79 | #define MICROREAD_PIPE_ID_MGT 0x02 | ||
80 | #define MICROREAD_PIPE_ID_OS 0x03 | ||
81 | #define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04 | ||
82 | #define MICROREAD_PIPE_ID_HDS_IDT 0x05 | ||
83 | #define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08 | ||
84 | #define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09 | ||
85 | #define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A | ||
86 | #define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B | ||
87 | #define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C | ||
88 | #define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D | ||
89 | #define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E | ||
90 | #define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F | ||
91 | #define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10 | ||
92 | #define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11 | ||
93 | #define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12 | ||
94 | #define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13 | ||
95 | #define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14 | ||
96 | #define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15 | ||
97 | #define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16 | ||
98 | #define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17 | ||
99 | #define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18 | ||
100 | #define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B | ||
101 | #define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C | ||
102 | #define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D | ||
103 | #define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E | ||
104 | #define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F | ||
105 | #define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20 | ||
106 | |||
107 | /* Events */ | ||
108 | #define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED | ||
109 | #define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D | ||
110 | #define MICROREAD_EMCF_A_ATQA 0 | ||
111 | #define MICROREAD_EMCF_A_SAK 2 | ||
112 | #define MICROREAD_EMCF_A_LEN 3 | ||
113 | #define MICROREAD_EMCF_A_UID 4 | ||
114 | #define MICROREAD_EMCF_A3_ATQA 0 | ||
115 | #define MICROREAD_EMCF_A3_SAK 2 | ||
116 | #define MICROREAD_EMCF_A3_LEN 3 | ||
117 | #define MICROREAD_EMCF_A3_UID 4 | ||
118 | #define MICROREAD_EMCF_B_UID 0 | ||
119 | #define MICROREAD_EMCF_T1_ATQA 0 | ||
120 | #define MICROREAD_EMCF_T1_UID 4 | ||
121 | #define MICROREAD_EMCF_T3_UID 0 | ||
122 | #define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED | ||
123 | #define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E | ||
124 | #define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION | ||
125 | #define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F | ||
126 | #define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED | ||
127 | #define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20 | ||
128 | #define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21 | ||
129 | #define MICROREAD_EVT_MCARD_FIELD_ON 0x11 | ||
130 | #define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13 | ||
131 | #define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12 | ||
132 | #define MICROREAD_EVT_MCARD_FIELD_OFF 0x14 | ||
133 | |||
134 | /* Commands */ | ||
135 | #define MICROREAD_CMD_MREAD_EXCHANGE 0x10 | ||
136 | #define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F | ||
137 | |||
138 | /* Hosts IDs */ | ||
139 | #define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID | ||
140 | #define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID | ||
141 | #define MICROREAD_ELT_ID_SE1 0x03 | ||
142 | #define MICROREAD_ELT_ID_SE2 0x04 | ||
143 | #define MICROREAD_ELT_ID_SE3 0x05 | ||
144 | |||
145 | static struct nfc_hci_gate microread_gates[] = { | ||
146 | {MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN}, | ||
147 | {MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK}, | ||
148 | {MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT}, | ||
149 | {MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS}, | ||
150 | {MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B}, | ||
151 | {MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A}, | ||
152 | {MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3}, | ||
153 | {MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT}, | ||
154 | {MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS}, | ||
155 | {MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1}, | ||
156 | {MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3}, | ||
157 | {MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET}, | ||
158 | {MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR} | ||
159 | }; | ||
160 | |||
161 | /* Largest headroom needed for outgoing custom commands */ | ||
162 | #define MICROREAD_CMDS_HEADROOM 2 | ||
163 | #define MICROREAD_CMD_TAILROOM 2 | ||
164 | |||
165 | struct microread_info { | ||
166 | struct nfc_phy_ops *phy_ops; | ||
167 | void *phy_id; | ||
168 | |||
169 | struct nfc_hci_dev *hdev; | ||
170 | |||
171 | int async_cb_type; | ||
172 | data_exchange_cb_t async_cb; | ||
173 | void *async_cb_context; | ||
174 | }; | ||
175 | |||
176 | static int microread_open(struct nfc_hci_dev *hdev) | ||
177 | { | ||
178 | struct microread_info *info = nfc_hci_get_clientdata(hdev); | ||
179 | |||
180 | return info->phy_ops->enable(info->phy_id); | ||
181 | } | ||
182 | |||
183 | static void microread_close(struct nfc_hci_dev *hdev) | ||
184 | { | ||
185 | struct microread_info *info = nfc_hci_get_clientdata(hdev); | ||
186 | |||
187 | info->phy_ops->disable(info->phy_id); | ||
188 | } | ||
189 | |||
190 | static int microread_hci_ready(struct nfc_hci_dev *hdev) | ||
191 | { | ||
192 | int r; | ||
193 | u8 param[4]; | ||
194 | |||
195 | param[0] = 0x03; | ||
196 | r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, | ||
197 | MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL); | ||
198 | if (r) | ||
199 | return r; | ||
200 | |||
201 | r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3, | ||
202 | MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL); | ||
203 | if (r) | ||
204 | return r; | ||
205 | |||
206 | param[0] = 0x00; | ||
207 | param[1] = 0x03; | ||
208 | param[2] = 0x00; | ||
209 | r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B, | ||
210 | MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL); | ||
211 | if (r) | ||
212 | return r; | ||
213 | |||
214 | r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1, | ||
215 | MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL); | ||
216 | if (r) | ||
217 | return r; | ||
218 | |||
219 | param[0] = 0xFF; | ||
220 | param[1] = 0xFF; | ||
221 | param[2] = 0x00; | ||
222 | param[3] = 0x00; | ||
223 | r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3, | ||
224 | MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL); | ||
225 | |||
226 | return r; | ||
227 | } | ||
228 | |||
229 | static int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
230 | { | ||
231 | struct microread_info *info = nfc_hci_get_clientdata(hdev); | ||
232 | |||
233 | return info->phy_ops->write(info->phy_id, skb); | ||
234 | } | ||
235 | |||
236 | static int microread_start_poll(struct nfc_hci_dev *hdev, | ||
237 | u32 im_protocols, u32 tm_protocols) | ||
238 | { | ||
239 | int r; | ||
240 | |||
241 | u8 param[2]; | ||
242 | u8 mode; | ||
243 | |||
244 | param[0] = 0x00; | ||
245 | param[1] = 0x00; | ||
246 | |||
247 | if (im_protocols & NFC_PROTO_ISO14443_MASK) | ||
248 | param[0] |= (1 << 2); | ||
249 | |||
250 | if (im_protocols & NFC_PROTO_ISO14443_B_MASK) | ||
251 | param[0] |= 1; | ||
252 | |||
253 | if (im_protocols & NFC_PROTO_MIFARE_MASK) | ||
254 | param[1] |= 1; | ||
255 | |||
256 | if (im_protocols & NFC_PROTO_JEWEL_MASK) | ||
257 | param[0] |= (1 << 1); | ||
258 | |||
259 | if (im_protocols & NFC_PROTO_FELICA_MASK) | ||
260 | param[0] |= (1 << 5); | ||
261 | |||
262 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) | ||
263 | param[1] |= (1 << 1); | ||
264 | |||
265 | if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { | ||
266 | hdev->gb = nfc_get_local_general_bytes(hdev->ndev, | ||
267 | &hdev->gb_len); | ||
268 | if (hdev->gb == NULL || hdev->gb_len == 0) { | ||
269 | im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; | ||
270 | tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, | ||
275 | MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0); | ||
276 | if (r) | ||
277 | return r; | ||
278 | |||
279 | mode = 0xff; | ||
280 | r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, | ||
281 | MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); | ||
282 | if (r) | ||
283 | return r; | ||
284 | |||
285 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { | ||
286 | r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR, | ||
287 | MICROREAD_PAR_P2P_INITIATOR_GI, | ||
288 | hdev->gb, hdev->gb_len); | ||
289 | if (r) | ||
290 | return r; | ||
291 | } | ||
292 | |||
293 | if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { | ||
294 | r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, | ||
295 | MICROREAD_PAR_P2P_TARGET_GT, | ||
296 | hdev->gb, hdev->gb_len); | ||
297 | if (r) | ||
298 | return r; | ||
299 | |||
300 | mode = 0x02; | ||
301 | r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, | ||
302 | MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); | ||
303 | if (r) | ||
304 | return r; | ||
305 | } | ||
306 | |||
307 | return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, | ||
308 | MICROREAD_EVT_MREAD_DISCOVERY_START_SOME, | ||
309 | param, 2); | ||
310 | } | ||
311 | |||
312 | static int microread_dep_link_up(struct nfc_hci_dev *hdev, | ||
313 | struct nfc_target *target, u8 comm_mode, | ||
314 | u8 *gb, size_t gb_len) | ||
315 | { | ||
316 | struct sk_buff *rgb_skb = NULL; | ||
317 | int r; | ||
318 | |||
319 | r = nfc_hci_get_param(hdev, target->hci_reader_gate, | ||
320 | MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb); | ||
321 | if (r < 0) | ||
322 | return r; | ||
323 | |||
324 | if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) { | ||
325 | r = -EPROTO; | ||
326 | goto exit; | ||
327 | } | ||
328 | |||
329 | r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data, | ||
330 | rgb_skb->len); | ||
331 | if (r == 0) | ||
332 | r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode, | ||
333 | NFC_RF_INITIATOR); | ||
334 | exit: | ||
335 | kfree_skb(rgb_skb); | ||
336 | |||
337 | return r; | ||
338 | } | ||
339 | |||
340 | static int microread_dep_link_down(struct nfc_hci_dev *hdev) | ||
341 | { | ||
342 | return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR, | ||
343 | MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0); | ||
344 | } | ||
345 | |||
346 | static int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, | ||
347 | struct nfc_target *target) | ||
348 | { | ||
349 | switch (gate) { | ||
350 | case MICROREAD_GATE_ID_P2P_INITIATOR: | ||
351 | target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; | ||
352 | break; | ||
353 | default: | ||
354 | return -EPROTO; | ||
355 | } | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int microread_complete_target_discovered(struct nfc_hci_dev *hdev, | ||
361 | u8 gate, | ||
362 | struct nfc_target *target) | ||
363 | { | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | #define MICROREAD_CB_TYPE_READER_ALL 1 | ||
368 | |||
369 | static void microread_im_transceive_cb(void *context, struct sk_buff *skb, | ||
370 | int err) | ||
371 | { | ||
372 | struct microread_info *info = context; | ||
373 | |||
374 | switch (info->async_cb_type) { | ||
375 | case MICROREAD_CB_TYPE_READER_ALL: | ||
376 | if (err == 0) { | ||
377 | if (skb->len == 0) { | ||
378 | err = -EPROTO; | ||
379 | kfree_skb(skb); | ||
380 | info->async_cb(info->async_cb_context, NULL, | ||
381 | -EPROTO); | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | if (skb->data[skb->len - 1] != 0) { | ||
386 | err = nfc_hci_result_to_errno( | ||
387 | skb->data[skb->len - 1]); | ||
388 | kfree_skb(skb); | ||
389 | info->async_cb(info->async_cb_context, NULL, | ||
390 | err); | ||
391 | return; | ||
392 | } | ||
393 | |||
394 | skb_trim(skb, skb->len - 1); /* RF Error ind. */ | ||
395 | } | ||
396 | info->async_cb(info->async_cb_context, skb, err); | ||
397 | break; | ||
398 | default: | ||
399 | if (err == 0) | ||
400 | kfree_skb(skb); | ||
401 | break; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * Returns: | ||
407 | * <= 0: driver handled the data exchange | ||
408 | * 1: driver doesn't especially handle, please do standard processing | ||
409 | */ | ||
410 | static int microread_im_transceive(struct nfc_hci_dev *hdev, | ||
411 | struct nfc_target *target, | ||
412 | struct sk_buff *skb, data_exchange_cb_t cb, | ||
413 | void *cb_context) | ||
414 | { | ||
415 | struct microread_info *info = nfc_hci_get_clientdata(hdev); | ||
416 | u8 control_bits; | ||
417 | u16 crc; | ||
418 | |||
419 | pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate); | ||
420 | |||
421 | if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) { | ||
422 | *skb_push(skb, 1) = 0; | ||
423 | |||
424 | return nfc_hci_send_event(hdev, target->hci_reader_gate, | ||
425 | MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF, | ||
426 | skb->data, skb->len); | ||
427 | } | ||
428 | |||
429 | switch (target->hci_reader_gate) { | ||
430 | case MICROREAD_GATE_ID_MREAD_ISO_A: | ||
431 | control_bits = 0xCB; | ||
432 | break; | ||
433 | case MICROREAD_GATE_ID_MREAD_ISO_A_3: | ||
434 | control_bits = 0xCB; | ||
435 | break; | ||
436 | case MICROREAD_GATE_ID_MREAD_ISO_B: | ||
437 | control_bits = 0xCB; | ||
438 | break; | ||
439 | case MICROREAD_GATE_ID_MREAD_NFC_T1: | ||
440 | control_bits = 0x1B; | ||
441 | |||
442 | crc = crc_ccitt(0xffff, skb->data, skb->len); | ||
443 | crc = ~crc; | ||
444 | *skb_put(skb, 1) = crc & 0xff; | ||
445 | *skb_put(skb, 1) = crc >> 8; | ||
446 | break; | ||
447 | case MICROREAD_GATE_ID_MREAD_NFC_T3: | ||
448 | control_bits = 0xDB; | ||
449 | break; | ||
450 | default: | ||
451 | pr_info("Abort im_transceive to invalid gate 0x%x\n", | ||
452 | target->hci_reader_gate); | ||
453 | return 1; | ||
454 | } | ||
455 | |||
456 | *skb_push(skb, 1) = control_bits; | ||
457 | |||
458 | info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL; | ||
459 | info->async_cb = cb; | ||
460 | info->async_cb_context = cb_context; | ||
461 | |||
462 | return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, | ||
463 | MICROREAD_CMD_MREAD_EXCHANGE, | ||
464 | skb->data, skb->len, | ||
465 | microread_im_transceive_cb, info); | ||
466 | } | ||
467 | |||
468 | static int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
469 | { | ||
470 | int r; | ||
471 | |||
472 | r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET, | ||
473 | MICROREAD_EVT_MCARD_EXCHANGE, | ||
474 | skb->data, skb->len); | ||
475 | |||
476 | kfree_skb(skb); | ||
477 | |||
478 | return r; | ||
479 | } | ||
480 | |||
481 | static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate, | ||
482 | struct sk_buff *skb) | ||
483 | { | ||
484 | struct nfc_target *targets; | ||
485 | int r = 0; | ||
486 | |||
487 | pr_info("target discovered to gate 0x%x\n", gate); | ||
488 | |||
489 | targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL); | ||
490 | if (targets == NULL) { | ||
491 | r = -ENOMEM; | ||
492 | goto exit; | ||
493 | } | ||
494 | |||
495 | targets->hci_reader_gate = gate; | ||
496 | |||
497 | switch (gate) { | ||
498 | case MICROREAD_GATE_ID_MREAD_ISO_A: | ||
499 | targets->supported_protocols = | ||
500 | nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]); | ||
501 | targets->sens_res = | ||
502 | be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]); | ||
503 | targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK]; | ||
504 | memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID], | ||
505 | skb->data[MICROREAD_EMCF_A_LEN]); | ||
506 | targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN]; | ||
507 | break; | ||
508 | case MICROREAD_GATE_ID_MREAD_ISO_A_3: | ||
509 | targets->supported_protocols = | ||
510 | nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]); | ||
511 | targets->sens_res = | ||
512 | be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]); | ||
513 | targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK]; | ||
514 | memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID], | ||
515 | skb->data[MICROREAD_EMCF_A3_LEN]); | ||
516 | targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN]; | ||
517 | break; | ||
518 | case MICROREAD_GATE_ID_MREAD_ISO_B: | ||
519 | targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; | ||
520 | memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4); | ||
521 | targets->nfcid1_len = 4; | ||
522 | break; | ||
523 | case MICROREAD_GATE_ID_MREAD_NFC_T1: | ||
524 | targets->supported_protocols = NFC_PROTO_JEWEL_MASK; | ||
525 | targets->sens_res = | ||
526 | le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]); | ||
527 | memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4); | ||
528 | targets->nfcid1_len = 4; | ||
529 | break; | ||
530 | case MICROREAD_GATE_ID_MREAD_NFC_T3: | ||
531 | targets->supported_protocols = NFC_PROTO_FELICA_MASK; | ||
532 | memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8); | ||
533 | targets->nfcid1_len = 8; | ||
534 | break; | ||
535 | default: | ||
536 | pr_info("discard target discovered to gate 0x%x\n", gate); | ||
537 | goto exit_free; | ||
538 | } | ||
539 | |||
540 | r = nfc_targets_found(hdev->ndev, targets, 1); | ||
541 | |||
542 | exit_free: | ||
543 | kfree(targets); | ||
544 | |||
545 | exit: | ||
546 | kfree_skb(skb); | ||
547 | |||
548 | if (r) | ||
549 | pr_err("Failed to handle discovered target err=%d", r); | ||
550 | } | ||
551 | |||
552 | static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate, | ||
553 | u8 event, struct sk_buff *skb) | ||
554 | { | ||
555 | int r; | ||
556 | u8 mode; | ||
557 | |||
558 | pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate); | ||
559 | |||
560 | switch (event) { | ||
561 | case MICROREAD_EVT_MREAD_CARD_FOUND: | ||
562 | microread_target_discovered(hdev, gate, skb); | ||
563 | return 0; | ||
564 | |||
565 | case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF: | ||
566 | if (skb->len < 1) { | ||
567 | kfree_skb(skb); | ||
568 | return -EPROTO; | ||
569 | } | ||
570 | |||
571 | if (skb->data[skb->len - 1]) { | ||
572 | kfree_skb(skb); | ||
573 | return -EIO; | ||
574 | } | ||
575 | |||
576 | skb_trim(skb, skb->len - 1); | ||
577 | |||
578 | r = nfc_tm_data_received(hdev->ndev, skb); | ||
579 | break; | ||
580 | |||
581 | case MICROREAD_EVT_MCARD_FIELD_ON: | ||
582 | case MICROREAD_EVT_MCARD_FIELD_OFF: | ||
583 | kfree_skb(skb); | ||
584 | return 0; | ||
585 | |||
586 | case MICROREAD_EVT_P2P_TARGET_ACTIVATED: | ||
587 | r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, | ||
588 | NFC_COMM_PASSIVE, skb->data, | ||
589 | skb->len); | ||
590 | |||
591 | kfree_skb(skb); | ||
592 | break; | ||
593 | |||
594 | case MICROREAD_EVT_MCARD_EXCHANGE: | ||
595 | if (skb->len < 1) { | ||
596 | kfree_skb(skb); | ||
597 | return -EPROTO; | ||
598 | } | ||
599 | |||
600 | if (skb->data[skb->len-1]) { | ||
601 | kfree_skb(skb); | ||
602 | return -EIO; | ||
603 | } | ||
604 | |||
605 | skb_trim(skb, skb->len - 1); | ||
606 | |||
607 | r = nfc_tm_data_received(hdev->ndev, skb); | ||
608 | break; | ||
609 | |||
610 | case MICROREAD_EVT_P2P_TARGET_DEACTIVATED: | ||
611 | kfree_skb(skb); | ||
612 | |||
613 | mode = 0xff; | ||
614 | r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, | ||
615 | MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); | ||
616 | if (r) | ||
617 | break; | ||
618 | |||
619 | r = nfc_hci_send_event(hdev, gate, | ||
620 | MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, | ||
621 | 0); | ||
622 | break; | ||
623 | |||
624 | default: | ||
625 | return 1; | ||
626 | } | ||
627 | |||
628 | return r; | ||
629 | } | ||
630 | |||
631 | static struct nfc_hci_ops microread_hci_ops = { | ||
632 | .open = microread_open, | ||
633 | .close = microread_close, | ||
634 | .hci_ready = microread_hci_ready, | ||
635 | .xmit = microread_xmit, | ||
636 | .start_poll = microread_start_poll, | ||
637 | .dep_link_up = microread_dep_link_up, | ||
638 | .dep_link_down = microread_dep_link_down, | ||
639 | .target_from_gate = microread_target_from_gate, | ||
640 | .complete_target_discovered = microread_complete_target_discovered, | ||
641 | .im_transceive = microread_im_transceive, | ||
642 | .tm_send = microread_tm_send, | ||
643 | .check_presence = NULL, | ||
644 | .event_received = microread_event_received, | ||
645 | }; | ||
646 | |||
647 | int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, | ||
648 | int phy_headroom, int phy_tailroom, int phy_payload, | ||
649 | struct nfc_hci_dev **hdev) | ||
650 | { | ||
651 | struct microread_info *info; | ||
652 | unsigned long quirks = 0; | ||
653 | u32 protocols, se; | ||
654 | struct nfc_hci_init_data init_data; | ||
655 | int r; | ||
656 | |||
657 | info = kzalloc(sizeof(struct microread_info), GFP_KERNEL); | ||
658 | if (!info) { | ||
659 | pr_err("Cannot allocate memory for microread_info.\n"); | ||
660 | r = -ENOMEM; | ||
661 | goto err_info_alloc; | ||
662 | } | ||
663 | |||
664 | info->phy_ops = phy_ops; | ||
665 | info->phy_id = phy_id; | ||
666 | |||
667 | init_data.gate_count = ARRAY_SIZE(microread_gates); | ||
668 | memcpy(init_data.gates, microread_gates, sizeof(microread_gates)); | ||
669 | |||
670 | strcpy(init_data.session_id, "MICROREA"); | ||
671 | |||
672 | set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks); | ||
673 | |||
674 | protocols = NFC_PROTO_JEWEL_MASK | | ||
675 | NFC_PROTO_MIFARE_MASK | | ||
676 | NFC_PROTO_FELICA_MASK | | ||
677 | NFC_PROTO_ISO14443_MASK | | ||
678 | NFC_PROTO_ISO14443_B_MASK | | ||
679 | NFC_PROTO_NFC_DEP_MASK; | ||
680 | |||
681 | se = NFC_SE_UICC | NFC_SE_EMBEDDED; | ||
682 | |||
683 | info->hdev = nfc_hci_allocate_device(µread_hci_ops, &init_data, | ||
684 | quirks, protocols, se, llc_name, | ||
685 | phy_headroom + | ||
686 | MICROREAD_CMDS_HEADROOM, | ||
687 | phy_tailroom + | ||
688 | MICROREAD_CMD_TAILROOM, | ||
689 | phy_payload); | ||
690 | if (!info->hdev) { | ||
691 | pr_err("Cannot allocate nfc hdev.\n"); | ||
692 | r = -ENOMEM; | ||
693 | goto err_alloc_hdev; | ||
694 | } | ||
695 | |||
696 | nfc_hci_set_clientdata(info->hdev, info); | ||
697 | |||
698 | r = nfc_hci_register_device(info->hdev); | ||
699 | if (r) | ||
700 | goto err_regdev; | ||
701 | |||
702 | *hdev = info->hdev; | ||
703 | |||
704 | return 0; | ||
705 | |||
706 | err_regdev: | ||
707 | nfc_hci_free_device(info->hdev); | ||
708 | |||
709 | err_alloc_hdev: | ||
710 | kfree(info); | ||
711 | |||
712 | err_info_alloc: | ||
713 | return r; | ||
714 | } | ||
715 | EXPORT_SYMBOL(microread_probe); | ||
716 | |||
717 | void microread_remove(struct nfc_hci_dev *hdev) | ||
718 | { | ||
719 | struct microread_info *info = nfc_hci_get_clientdata(hdev); | ||
720 | |||
721 | nfc_hci_unregister_device(hdev); | ||
722 | nfc_hci_free_device(hdev); | ||
723 | kfree(info); | ||
724 | } | ||
725 | EXPORT_SYMBOL(microread_remove); | ||
726 | |||
727 | MODULE_LICENSE("GPL"); | ||
728 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
diff --git a/drivers/nfc/microread/microread.h b/drivers/nfc/microread/microread.h new file mode 100644 index 000000000000..64b447a1c5bf --- /dev/null +++ b/drivers/nfc/microread/microread.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 - 2012 Intel Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef __LOCAL_MICROREAD_H_ | ||
21 | #define __LOCAL_MICROREAD_H_ | ||
22 | |||
23 | #include <net/nfc/hci.h> | ||
24 | |||
25 | #define DRIVER_DESC "NFC driver for microread" | ||
26 | |||
27 | int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, | ||
28 | int phy_headroom, int phy_tailroom, int phy_payload, | ||
29 | struct nfc_hci_dev **hdev); | ||
30 | |||
31 | void microread_remove(struct nfc_hci_dev *hdev); | ||
32 | |||
33 | #endif /* __LOCAL_MICROREAD_H_ */ | ||
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index f696318cfb51..f0f6763d67ae 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -219,7 +219,7 @@ struct pn533_poll_modulations { | |||
219 | u8 len; | 219 | u8 len; |
220 | }; | 220 | }; |
221 | 221 | ||
222 | const struct pn533_poll_modulations poll_mod[] = { | 222 | static const struct pn533_poll_modulations poll_mod[] = { |
223 | [PN533_POLL_MOD_106KBPS_A] = { | 223 | [PN533_POLL_MOD_106KBPS_A] = { |
224 | .data = { | 224 | .data = { |
225 | .maxtg = 1, | 225 | .maxtg = 1, |
@@ -485,7 +485,7 @@ static u8 pn533_get_cmd_code(void *frame) | |||
485 | return PN533_FRAME_CMD(f); | 485 | return PN533_FRAME_CMD(f); |
486 | } | 486 | } |
487 | 487 | ||
488 | struct pn533_frame_ops pn533_std_frame_ops = { | 488 | static struct pn533_frame_ops pn533_std_frame_ops = { |
489 | .tx_frame_init = pn533_tx_frame_init, | 489 | .tx_frame_init = pn533_tx_frame_init, |
490 | .tx_frame_finish = pn533_tx_frame_finish, | 490 | .tx_frame_finish = pn533_tx_frame_finish, |
491 | .tx_update_payload_len = pn533_tx_update_payload_len, | 491 | .tx_update_payload_len = pn533_tx_update_payload_len, |
@@ -532,7 +532,6 @@ static void pn533_recv_response(struct urb *urb) | |||
532 | urb->status); | 532 | urb->status); |
533 | dev->wq_in_error = urb->status; | 533 | dev->wq_in_error = urb->status; |
534 | goto sched_wq; | 534 | goto sched_wq; |
535 | break; | ||
536 | case -ESHUTDOWN: | 535 | case -ESHUTDOWN: |
537 | default: | 536 | default: |
538 | nfc_dev_err(&dev->interface->dev, | 537 | nfc_dev_err(&dev->interface->dev, |
@@ -589,7 +588,6 @@ static void pn533_recv_ack(struct urb *urb) | |||
589 | urb->status); | 588 | urb->status); |
590 | dev->wq_in_error = urb->status; | 589 | dev->wq_in_error = urb->status; |
591 | goto sched_wq; | 590 | goto sched_wq; |
592 | break; | ||
593 | case -ESHUTDOWN: | 591 | case -ESHUTDOWN: |
594 | default: | 592 | default: |
595 | nfc_dev_err(&dev->interface->dev, | 593 | nfc_dev_err(&dev->interface->dev, |
@@ -1380,7 +1378,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) | |||
1380 | return NULL; | 1378 | return NULL; |
1381 | 1379 | ||
1382 | /* DEP support only */ | 1380 | /* DEP support only */ |
1383 | *skb_put(skb, 1) |= PN533_INIT_TARGET_DEP; | 1381 | *skb_put(skb, 1) = PN533_INIT_TARGET_DEP; |
1384 | 1382 | ||
1385 | /* MIFARE params */ | 1383 | /* MIFARE params */ |
1386 | memcpy(skb_put(skb, 6), mifare_params, 6); | 1384 | memcpy(skb_put(skb, 6), mifare_params, 6); |
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 1d31eab19d16..f1bce18ea828 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c | |||
@@ -424,7 +424,7 @@ int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) | |||
424 | goto exit; | 424 | goto exit; |
425 | } | 425 | } |
426 | 426 | ||
427 | cfg80211_put_bss(bss); | 427 | cfg80211_put_bss(wiphy, bss); |
428 | } | 428 | } |
429 | 429 | ||
430 | if (result) | 430 | if (result) |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 11c8bc87fdcb..7e24fe0cfbcd 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -151,6 +151,11 @@ | |||
151 | /* Mesh Control 802.11s */ | 151 | /* Mesh Control 802.11s */ |
152 | #define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100 | 152 | #define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100 |
153 | 153 | ||
154 | /* Mesh Power Save Level */ | ||
155 | #define IEEE80211_QOS_CTL_MESH_PS_LEVEL 0x0200 | ||
156 | /* Mesh Receiver Service Period Initiated */ | ||
157 | #define IEEE80211_QOS_CTL_RSPI 0x0400 | ||
158 | |||
154 | /* U-APSD queue for WMM IEs sent by AP */ | 159 | /* U-APSD queue for WMM IEs sent by AP */ |
155 | #define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) | 160 | #define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) |
156 | #define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK 0x0f | 161 | #define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK 0x0f |
@@ -675,11 +680,14 @@ struct ieee80211_meshconf_ie { | |||
675 | * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs | 680 | * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs |
676 | * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure | 681 | * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure |
677 | * is ongoing | 682 | * is ongoing |
683 | * @IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL: STA is in deep sleep mode or has | ||
684 | * neighbors in deep sleep mode | ||
678 | */ | 685 | */ |
679 | enum mesh_config_capab_flags { | 686 | enum mesh_config_capab_flags { |
680 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01, | 687 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01, |
681 | IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08, | 688 | IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08, |
682 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20, | 689 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20, |
690 | IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL = 0x40, | ||
683 | }; | 691 | }; |
684 | 692 | ||
685 | /** | 693 | /** |
@@ -706,6 +714,30 @@ enum ieee80211_ht_chanwidth_values { | |||
706 | IEEE80211_HT_CHANWIDTH_ANY = 1, | 714 | IEEE80211_HT_CHANWIDTH_ANY = 1, |
707 | }; | 715 | }; |
708 | 716 | ||
717 | /** | ||
718 | * enum ieee80211_opmode_bits - VHT operating mode field bits | ||
719 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK: channel width mask | ||
720 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 20 MHz channel width | ||
721 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width | ||
722 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width | ||
723 | * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width | ||
724 | * @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask | ||
725 | * (the NSS value is the value of this field + 1) | ||
726 | * @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift | ||
727 | * @IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF: indicates streams in SU-MIMO PPDU | ||
728 | * using a beamforming steering matrix | ||
729 | */ | ||
730 | enum ieee80211_vht_opmode_bits { | ||
731 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 3, | ||
732 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ = 0, | ||
733 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1, | ||
734 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2, | ||
735 | IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3, | ||
736 | IEEE80211_OPMODE_NOTIF_RX_NSS_MASK = 0x70, | ||
737 | IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4, | ||
738 | IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80, | ||
739 | }; | ||
740 | |||
709 | #define WLAN_SA_QUERY_TR_ID_LEN 2 | 741 | #define WLAN_SA_QUERY_TR_ID_LEN 2 |
710 | 742 | ||
711 | struct ieee80211_mgmt { | 743 | struct ieee80211_mgmt { |
@@ -836,6 +868,10 @@ struct ieee80211_mgmt { | |||
836 | __le16 capability; | 868 | __le16 capability; |
837 | u8 variable[0]; | 869 | u8 variable[0]; |
838 | } __packed tdls_discover_resp; | 870 | } __packed tdls_discover_resp; |
871 | struct { | ||
872 | u8 action_code; | ||
873 | u8 operating_mode; | ||
874 | } __packed vht_opmode_notif; | ||
839 | } u; | 875 | } u; |
840 | } __packed action; | 876 | } __packed action; |
841 | } u; | 877 | } u; |
@@ -1265,6 +1301,7 @@ struct ieee80211_vht_operation { | |||
1265 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 | 1301 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 |
1266 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 | 1302 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 |
1267 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 | 1303 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 |
1304 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C | ||
1268 | #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 | 1305 | #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 |
1269 | #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 | 1306 | #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 |
1270 | #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 | 1307 | #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 |
@@ -1590,6 +1627,7 @@ enum ieee80211_eid { | |||
1590 | 1627 | ||
1591 | WLAN_EID_VHT_CAPABILITY = 191, | 1628 | WLAN_EID_VHT_CAPABILITY = 191, |
1592 | WLAN_EID_VHT_OPERATION = 192, | 1629 | WLAN_EID_VHT_OPERATION = 192, |
1630 | WLAN_EID_OPMODE_NOTIF = 199, | ||
1593 | 1631 | ||
1594 | /* 802.11ad */ | 1632 | /* 802.11ad */ |
1595 | WLAN_EID_NON_TX_BSSID_CAP = 83, | 1633 | WLAN_EID_NON_TX_BSSID_CAP = 83, |
@@ -1644,6 +1682,7 @@ enum ieee80211_category { | |||
1644 | WLAN_CATEGORY_WMM = 17, | 1682 | WLAN_CATEGORY_WMM = 17, |
1645 | WLAN_CATEGORY_FST = 18, | 1683 | WLAN_CATEGORY_FST = 18, |
1646 | WLAN_CATEGORY_UNPROT_DMG = 20, | 1684 | WLAN_CATEGORY_UNPROT_DMG = 20, |
1685 | WLAN_CATEGORY_VHT = 21, | ||
1647 | WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, | 1686 | WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, |
1648 | WLAN_CATEGORY_VENDOR_SPECIFIC = 127, | 1687 | WLAN_CATEGORY_VENDOR_SPECIFIC = 127, |
1649 | }; | 1688 | }; |
@@ -1669,6 +1708,13 @@ enum ieee80211_ht_actioncode { | |||
1669 | WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, | 1708 | WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, |
1670 | }; | 1709 | }; |
1671 | 1710 | ||
1711 | /* VHT action codes */ | ||
1712 | enum ieee80211_vht_actioncode { | ||
1713 | WLAN_VHT_ACTION_COMPRESSED_BF = 0, | ||
1714 | WLAN_VHT_ACTION_GROUPID_MGMT = 1, | ||
1715 | WLAN_VHT_ACTION_OPMODE_NOTIF = 2, | ||
1716 | }; | ||
1717 | |||
1672 | /* Self Protected Action codes */ | 1718 | /* Self Protected Action codes */ |
1673 | enum ieee80211_self_protected_actioncode { | 1719 | enum ieee80211_self_protected_actioncode { |
1674 | WLAN_SP_RESERVED = 0, | 1720 | WLAN_SP_RESERVED = 0, |
@@ -1730,6 +1776,8 @@ enum ieee80211_tdls_actioncode { | |||
1730 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) | 1776 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) |
1731 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) | 1777 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) |
1732 | 1778 | ||
1779 | #define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6) | ||
1780 | |||
1733 | /* TDLS specific payload type in the LLC/SNAP header */ | 1781 | /* TDLS specific payload type in the LLC/SNAP header */ |
1734 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | 1782 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 |
1735 | 1783 | ||
@@ -2106,7 +2154,7 @@ static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) | |||
2106 | * @tim_len: length of the TIM IE | 2154 | * @tim_len: length of the TIM IE |
2107 | * @aid: the AID to look for | 2155 | * @aid: the AID to look for |
2108 | */ | 2156 | */ |
2109 | static inline bool ieee80211_check_tim(struct ieee80211_tim_ie *tim, | 2157 | static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, |
2110 | u8 tim_len, u16 aid) | 2158 | u8 tim_len, u16 aid) |
2111 | { | 2159 | { |
2112 | u8 mask; | 2160 | u8 mask; |
diff --git a/include/linux/platform_data/microread.h b/include/linux/platform_data/microread.h new file mode 100644 index 000000000000..cfda59b226ee --- /dev/null +++ b/include/linux/platform_data/microread.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Driver include for the PN544 NFC chip. | ||
3 | * | ||
4 | * Copyright (C) 2011 Tieto Poland | ||
5 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef _MICROREAD_H | ||
22 | #define _MICROREAD_H | ||
23 | |||
24 | #include <linux/i2c.h> | ||
25 | |||
26 | #define MICROREAD_DRIVER_NAME "microread" | ||
27 | |||
28 | /* board config platform data for microread */ | ||
29 | struct microread_nfc_platform_data { | ||
30 | unsigned int rst_gpio; | ||
31 | unsigned int irq_gpio; | ||
32 | unsigned int ioh_gpio; | ||
33 | }; | ||
34 | |||
35 | #endif /* _MICROREAD_H */ | ||
diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index 0d6373195d32..a54fe82e704b 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h | |||
@@ -24,6 +24,8 @@ | |||
24 | #ifndef _LINUX_WL12XX_H | 24 | #ifndef _LINUX_WL12XX_H |
25 | #define _LINUX_WL12XX_H | 25 | #define _LINUX_WL12XX_H |
26 | 26 | ||
27 | #include <linux/err.h> | ||
28 | |||
27 | /* Reference clock values */ | 29 | /* Reference clock values */ |
28 | enum { | 30 | enum { |
29 | WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ | 31 | WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ |
@@ -55,17 +57,17 @@ struct wl12xx_platform_data { | |||
55 | int board_tcxo_clock; | 57 | int board_tcxo_clock; |
56 | unsigned long platform_quirks; | 58 | unsigned long platform_quirks; |
57 | bool pwr_in_suspend; | 59 | bool pwr_in_suspend; |
58 | |||
59 | struct wl1271_if_operations *ops; | ||
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* Platform does not support level trigger interrupts */ | 62 | /* Platform does not support level trigger interrupts */ |
63 | #define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) | 63 | #define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) |
64 | 64 | ||
65 | #ifdef CONFIG_WL12XX_PLATFORM_DATA | 65 | #ifdef CONFIG_WILINK_PLATFORM_DATA |
66 | 66 | ||
67 | int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); | 67 | int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); |
68 | 68 | ||
69 | struct wl12xx_platform_data *wl12xx_get_platform_data(void); | ||
70 | |||
69 | #else | 71 | #else |
70 | 72 | ||
71 | static inline | 73 | static inline |
@@ -74,8 +76,12 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data) | |||
74 | return -ENOSYS; | 76 | return -ENOSYS; |
75 | } | 77 | } |
76 | 78 | ||
77 | #endif | 79 | static inline |
80 | struct wl12xx_platform_data *wl12xx_get_platform_data(void) | ||
81 | { | ||
82 | return ERR_PTR(-ENODATA); | ||
83 | } | ||
78 | 84 | ||
79 | struct wl12xx_platform_data *wl12xx_get_platform_data(void); | 85 | #endif |
80 | 86 | ||
81 | #endif | 87 | #endif |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f9df20028bbd..d581c6de5d64 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/nl80211.h> | 19 | #include <linux/nl80211.h> |
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <linux/ieee80211.h> | 21 | #include <linux/ieee80211.h> |
22 | #include <linux/net.h> | ||
22 | #include <net/regulatory.h> | 23 | #include <net/regulatory.h> |
23 | 24 | ||
24 | /** | 25 | /** |
@@ -99,6 +100,16 @@ enum ieee80211_band { | |||
99 | * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel | 100 | * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel |
100 | * is not permitted. | 101 | * is not permitted. |
101 | * @IEEE80211_CHAN_NO_OFDM: OFDM is not allowed on this channel. | 102 | * @IEEE80211_CHAN_NO_OFDM: OFDM is not allowed on this channel. |
103 | * @IEEE80211_CHAN_NO_80MHZ: If the driver supports 80 MHz on the band, | ||
104 | * this flag indicates that an 80 MHz channel cannot use this | ||
105 | * channel as the control or any of the secondary channels. | ||
106 | * This may be due to the driver or due to regulatory bandwidth | ||
107 | * restrictions. | ||
108 | * @IEEE80211_CHAN_NO_160MHZ: If the driver supports 160 MHz on the band, | ||
109 | * this flag indicates that an 160 MHz channel cannot use this | ||
110 | * channel as the control or any of the secondary channels. | ||
111 | * This may be due to the driver or due to regulatory bandwidth | ||
112 | * restrictions. | ||
102 | */ | 113 | */ |
103 | enum ieee80211_channel_flags { | 114 | enum ieee80211_channel_flags { |
104 | IEEE80211_CHAN_DISABLED = 1<<0, | 115 | IEEE80211_CHAN_DISABLED = 1<<0, |
@@ -108,11 +119,16 @@ enum ieee80211_channel_flags { | |||
108 | IEEE80211_CHAN_NO_HT40PLUS = 1<<4, | 119 | IEEE80211_CHAN_NO_HT40PLUS = 1<<4, |
109 | IEEE80211_CHAN_NO_HT40MINUS = 1<<5, | 120 | IEEE80211_CHAN_NO_HT40MINUS = 1<<5, |
110 | IEEE80211_CHAN_NO_OFDM = 1<<6, | 121 | IEEE80211_CHAN_NO_OFDM = 1<<6, |
122 | IEEE80211_CHAN_NO_80MHZ = 1<<7, | ||
123 | IEEE80211_CHAN_NO_160MHZ = 1<<8, | ||
111 | }; | 124 | }; |
112 | 125 | ||
113 | #define IEEE80211_CHAN_NO_HT40 \ | 126 | #define IEEE80211_CHAN_NO_HT40 \ |
114 | (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) | 127 | (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) |
115 | 128 | ||
129 | #define IEEE80211_DFS_MIN_CAC_TIME_MS 60000 | ||
130 | #define IEEE80211_DFS_MIN_NOP_TIME_MS (30 * 60 * 1000) | ||
131 | |||
116 | /** | 132 | /** |
117 | * struct ieee80211_channel - channel definition | 133 | * struct ieee80211_channel - channel definition |
118 | * | 134 | * |
@@ -133,6 +149,9 @@ enum ieee80211_channel_flags { | |||
133 | * to enable this, this is useful only on 5 GHz band. | 149 | * to enable this, this is useful only on 5 GHz band. |
134 | * @orig_mag: internal use | 150 | * @orig_mag: internal use |
135 | * @orig_mpwr: internal use | 151 | * @orig_mpwr: internal use |
152 | * @dfs_state: current state of this channel. Only relevant if radar is required | ||
153 | * on this channel. | ||
154 | * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. | ||
136 | */ | 155 | */ |
137 | struct ieee80211_channel { | 156 | struct ieee80211_channel { |
138 | enum ieee80211_band band; | 157 | enum ieee80211_band band; |
@@ -145,6 +164,8 @@ struct ieee80211_channel { | |||
145 | bool beacon_found; | 164 | bool beacon_found; |
146 | u32 orig_flags; | 165 | u32 orig_flags; |
147 | int orig_mag, orig_mpwr; | 166 | int orig_mag, orig_mpwr; |
167 | enum nl80211_dfs_state dfs_state; | ||
168 | unsigned long dfs_state_entered; | ||
148 | }; | 169 | }; |
149 | 170 | ||
150 | /** | 171 | /** |
@@ -535,7 +556,7 @@ struct mac_address { | |||
535 | * struct cfg80211_acl_data - Access control list data | 556 | * struct cfg80211_acl_data - Access control list data |
536 | * | 557 | * |
537 | * @acl_policy: ACL policy to be applied on the station's | 558 | * @acl_policy: ACL policy to be applied on the station's |
538 | entry specified by mac_addr | 559 | * entry specified by mac_addr |
539 | * @n_acl_entries: Number of MAC address entries passed | 560 | * @n_acl_entries: Number of MAC address entries passed |
540 | * @mac_addrs: List of MAC addresses of stations to be used for ACL | 561 | * @mac_addrs: List of MAC addresses of stations to be used for ACL |
541 | */ | 562 | */ |
@@ -568,6 +589,7 @@ struct cfg80211_acl_data { | |||
568 | * @p2p_opp_ps: P2P opportunistic PS | 589 | * @p2p_opp_ps: P2P opportunistic PS |
569 | * @acl: ACL configuration used by the drivers which has support for | 590 | * @acl: ACL configuration used by the drivers which has support for |
570 | * MAC address based access control | 591 | * MAC address based access control |
592 | * @radar_required: set if radar detection is required | ||
571 | */ | 593 | */ |
572 | struct cfg80211_ap_settings { | 594 | struct cfg80211_ap_settings { |
573 | struct cfg80211_chan_def chandef; | 595 | struct cfg80211_chan_def chandef; |
@@ -585,6 +607,7 @@ struct cfg80211_ap_settings { | |||
585 | u8 p2p_ctwindow; | 607 | u8 p2p_ctwindow; |
586 | bool p2p_opp_ps; | 608 | bool p2p_opp_ps; |
587 | const struct cfg80211_acl_data *acl; | 609 | const struct cfg80211_acl_data *acl; |
610 | bool radar_required; | ||
588 | }; | 611 | }; |
589 | 612 | ||
590 | /** | 613 | /** |
@@ -603,12 +626,14 @@ enum plink_actions { | |||
603 | /** | 626 | /** |
604 | * enum station_parameters_apply_mask - station parameter values to apply | 627 | * enum station_parameters_apply_mask - station parameter values to apply |
605 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) | 628 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) |
629 | * @STATION_PARAM_APPLY_CAPABILITY: apply new capability | ||
606 | * | 630 | * |
607 | * Not all station parameters have in-band "no change" signalling, | 631 | * Not all station parameters have in-band "no change" signalling, |
608 | * for those that don't these flags will are used. | 632 | * for those that don't these flags will are used. |
609 | */ | 633 | */ |
610 | enum station_parameters_apply_mask { | 634 | enum station_parameters_apply_mask { |
611 | STATION_PARAM_APPLY_UAPSD = BIT(0), | 635 | STATION_PARAM_APPLY_UAPSD = BIT(0), |
636 | STATION_PARAM_APPLY_CAPABILITY = BIT(1), | ||
612 | }; | 637 | }; |
613 | 638 | ||
614 | /** | 639 | /** |
@@ -639,6 +664,9 @@ enum station_parameters_apply_mask { | |||
639 | * see &enum station_parameters_apply_mask | 664 | * see &enum station_parameters_apply_mask |
640 | * @local_pm: local link-specific mesh power save mode (no change when set | 665 | * @local_pm: local link-specific mesh power save mode (no change when set |
641 | * to unknown) | 666 | * to unknown) |
667 | * @capability: station capability | ||
668 | * @ext_capab: extended capabilities of the station | ||
669 | * @ext_capab_len: number of extended capabilities | ||
642 | */ | 670 | */ |
643 | struct station_parameters { | 671 | struct station_parameters { |
644 | u8 *supported_rates; | 672 | u8 *supported_rates; |
@@ -655,6 +683,9 @@ struct station_parameters { | |||
655 | u8 uapsd_queues; | 683 | u8 uapsd_queues; |
656 | u8 max_sp; | 684 | u8 max_sp; |
657 | enum nl80211_mesh_power_mode local_pm; | 685 | enum nl80211_mesh_power_mode local_pm; |
686 | u16 capability; | ||
687 | u8 *ext_capab; | ||
688 | u8 ext_capab_len; | ||
658 | }; | 689 | }; |
659 | 690 | ||
660 | /** | 691 | /** |
@@ -666,14 +697,16 @@ struct station_parameters { | |||
666 | * @STATION_INFO_INACTIVE_TIME: @inactive_time filled | 697 | * @STATION_INFO_INACTIVE_TIME: @inactive_time filled |
667 | * @STATION_INFO_RX_BYTES: @rx_bytes filled | 698 | * @STATION_INFO_RX_BYTES: @rx_bytes filled |
668 | * @STATION_INFO_TX_BYTES: @tx_bytes filled | 699 | * @STATION_INFO_TX_BYTES: @tx_bytes filled |
700 | * @STATION_INFO_RX_BYTES64: @rx_bytes filled with 64-bit value | ||
701 | * @STATION_INFO_TX_BYTES64: @tx_bytes filled with 64-bit value | ||
669 | * @STATION_INFO_LLID: @llid filled | 702 | * @STATION_INFO_LLID: @llid filled |
670 | * @STATION_INFO_PLID: @plid filled | 703 | * @STATION_INFO_PLID: @plid filled |
671 | * @STATION_INFO_PLINK_STATE: @plink_state filled | 704 | * @STATION_INFO_PLINK_STATE: @plink_state filled |
672 | * @STATION_INFO_SIGNAL: @signal filled | 705 | * @STATION_INFO_SIGNAL: @signal filled |
673 | * @STATION_INFO_TX_BITRATE: @txrate fields are filled | 706 | * @STATION_INFO_TX_BITRATE: @txrate fields are filled |
674 | * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) | 707 | * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) |
675 | * @STATION_INFO_RX_PACKETS: @rx_packets filled | 708 | * @STATION_INFO_RX_PACKETS: @rx_packets filled with 32-bit value |
676 | * @STATION_INFO_TX_PACKETS: @tx_packets filled | 709 | * @STATION_INFO_TX_PACKETS: @tx_packets filled with 32-bit value |
677 | * @STATION_INFO_TX_RETRIES: @tx_retries filled | 710 | * @STATION_INFO_TX_RETRIES: @tx_retries filled |
678 | * @STATION_INFO_TX_FAILED: @tx_failed filled | 711 | * @STATION_INFO_TX_FAILED: @tx_failed filled |
679 | * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled | 712 | * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled |
@@ -714,6 +747,8 @@ enum station_info_flags { | |||
714 | STATION_INFO_LOCAL_PM = 1<<21, | 747 | STATION_INFO_LOCAL_PM = 1<<21, |
715 | STATION_INFO_PEER_PM = 1<<22, | 748 | STATION_INFO_PEER_PM = 1<<22, |
716 | STATION_INFO_NONPEER_PM = 1<<23, | 749 | STATION_INFO_NONPEER_PM = 1<<23, |
750 | STATION_INFO_RX_BYTES64 = 1<<24, | ||
751 | STATION_INFO_TX_BYTES64 = 1<<25, | ||
717 | }; | 752 | }; |
718 | 753 | ||
719 | /** | 754 | /** |
@@ -835,8 +870,8 @@ struct station_info { | |||
835 | u32 filled; | 870 | u32 filled; |
836 | u32 connected_time; | 871 | u32 connected_time; |
837 | u32 inactive_time; | 872 | u32 inactive_time; |
838 | u32 rx_bytes; | 873 | u64 rx_bytes; |
839 | u32 tx_bytes; | 874 | u64 tx_bytes; |
840 | u16 llid; | 875 | u16 llid; |
841 | u16 plid; | 876 | u16 plid; |
842 | u8 plink_state; | 877 | u8 plink_state; |
@@ -1222,6 +1257,7 @@ struct cfg80211_match_set { | |||
1222 | * @n_match_sets: number of match sets | 1257 | * @n_match_sets: number of match sets |
1223 | * @wiphy: the wiphy this was for | 1258 | * @wiphy: the wiphy this was for |
1224 | * @dev: the interface | 1259 | * @dev: the interface |
1260 | * @scan_start: start time of the scheduled scan | ||
1225 | * @channels: channels to scan | 1261 | * @channels: channels to scan |
1226 | * @rssi_thold: don't report scan results below this threshold (in s32 dBm) | 1262 | * @rssi_thold: don't report scan results below this threshold (in s32 dBm) |
1227 | */ | 1263 | */ |
@@ -1261,11 +1297,13 @@ enum cfg80211_signal_type { | |||
1261 | 1297 | ||
1262 | /** | 1298 | /** |
1263 | * struct cfg80211_bss_ie_data - BSS entry IE data | 1299 | * struct cfg80211_bss_ie_data - BSS entry IE data |
1300 | * @tsf: TSF contained in the frame that carried these IEs | ||
1264 | * @rcu_head: internal use, for freeing | 1301 | * @rcu_head: internal use, for freeing |
1265 | * @len: length of the IEs | 1302 | * @len: length of the IEs |
1266 | * @data: IE data | 1303 | * @data: IE data |
1267 | */ | 1304 | */ |
1268 | struct cfg80211_bss_ies { | 1305 | struct cfg80211_bss_ies { |
1306 | u64 tsf; | ||
1269 | struct rcu_head rcu_head; | 1307 | struct rcu_head rcu_head; |
1270 | int len; | 1308 | int len; |
1271 | u8 data[]; | 1309 | u8 data[]; |
@@ -1279,29 +1317,32 @@ struct cfg80211_bss_ies { | |||
1279 | * | 1317 | * |
1280 | * @channel: channel this BSS is on | 1318 | * @channel: channel this BSS is on |
1281 | * @bssid: BSSID of the BSS | 1319 | * @bssid: BSSID of the BSS |
1282 | * @tsf: timestamp of last received update | ||
1283 | * @beacon_interval: the beacon interval as from the frame | 1320 | * @beacon_interval: the beacon interval as from the frame |
1284 | * @capability: the capability field in host byte order | 1321 | * @capability: the capability field in host byte order |
1285 | * @ies: the information elements (Note that there | 1322 | * @ies: the information elements (Note that there is no guarantee that these |
1286 | * is no guarantee that these are well-formed!); this is a pointer to | 1323 | * are well-formed!); this is a pointer to either the beacon_ies or |
1287 | * either the beacon_ies or proberesp_ies depending on whether Probe | 1324 | * proberesp_ies depending on whether Probe Response frame has been |
1288 | * Response frame has been received | 1325 | * received. It is always non-%NULL. |
1289 | * @beacon_ies: the information elements from the last Beacon frame | 1326 | * @beacon_ies: the information elements from the last Beacon frame |
1327 | * (implementation note: if @hidden_beacon_bss is set this struct doesn't | ||
1328 | * own the beacon_ies, but they're just pointers to the ones from the | ||
1329 | * @hidden_beacon_bss struct) | ||
1290 | * @proberesp_ies: the information elements from the last Probe Response frame | 1330 | * @proberesp_ies: the information elements from the last Probe Response frame |
1331 | * @hidden_beacon_bss: in case this BSS struct represents a probe response from | ||
1332 | * a BSS that hides the SSID in its beacon, this points to the BSS struct | ||
1333 | * that holds the beacon data. @beacon_ies is still valid, of course, and | ||
1334 | * points to the same data as hidden_beacon_bss->beacon_ies in that case. | ||
1291 | * @signal: signal strength value (type depends on the wiphy's signal_type) | 1335 | * @signal: signal strength value (type depends on the wiphy's signal_type) |
1292 | * @free_priv: function pointer to free private data | ||
1293 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes | 1336 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes |
1294 | */ | 1337 | */ |
1295 | struct cfg80211_bss { | 1338 | struct cfg80211_bss { |
1296 | u64 tsf; | ||
1297 | |||
1298 | struct ieee80211_channel *channel; | 1339 | struct ieee80211_channel *channel; |
1299 | 1340 | ||
1300 | const struct cfg80211_bss_ies __rcu *ies; | 1341 | const struct cfg80211_bss_ies __rcu *ies; |
1301 | const struct cfg80211_bss_ies __rcu *beacon_ies; | 1342 | const struct cfg80211_bss_ies __rcu *beacon_ies; |
1302 | const struct cfg80211_bss_ies __rcu *proberesp_ies; | 1343 | const struct cfg80211_bss_ies __rcu *proberesp_ies; |
1303 | 1344 | ||
1304 | void (*free_priv)(struct cfg80211_bss *bss); | 1345 | struct cfg80211_bss *hidden_beacon_bss; |
1305 | 1346 | ||
1306 | s32 signal; | 1347 | s32 signal; |
1307 | 1348 | ||
@@ -1403,6 +1444,8 @@ struct cfg80211_assoc_request { | |||
1403 | * @ie: Extra IEs to add to Deauthentication frame or %NULL | 1444 | * @ie: Extra IEs to add to Deauthentication frame or %NULL |
1404 | * @ie_len: Length of ie buffer in octets | 1445 | * @ie_len: Length of ie buffer in octets |
1405 | * @reason_code: The reason code for the deauthentication | 1446 | * @reason_code: The reason code for the deauthentication |
1447 | * @local_state_change: if set, change local state only and | ||
1448 | * do not set a deauth frame | ||
1406 | */ | 1449 | */ |
1407 | struct cfg80211_deauth_request { | 1450 | struct cfg80211_deauth_request { |
1408 | const u8 *bssid; | 1451 | const u8 *bssid; |
@@ -1564,6 +1607,7 @@ struct cfg80211_pmksa { | |||
1564 | * one bit per byte, in same format as nl80211 | 1607 | * one bit per byte, in same format as nl80211 |
1565 | * @pattern: bytes to match where bitmask is 1 | 1608 | * @pattern: bytes to match where bitmask is 1 |
1566 | * @pattern_len: length of pattern (in bytes) | 1609 | * @pattern_len: length of pattern (in bytes) |
1610 | * @pkt_offset: packet offset (in bytes) | ||
1567 | * | 1611 | * |
1568 | * Internal note: @mask and @pattern are allocated in one chunk of | 1612 | * Internal note: @mask and @pattern are allocated in one chunk of |
1569 | * memory, free @mask only! | 1613 | * memory, free @mask only! |
@@ -1571,6 +1615,42 @@ struct cfg80211_pmksa { | |||
1571 | struct cfg80211_wowlan_trig_pkt_pattern { | 1615 | struct cfg80211_wowlan_trig_pkt_pattern { |
1572 | u8 *mask, *pattern; | 1616 | u8 *mask, *pattern; |
1573 | int pattern_len; | 1617 | int pattern_len; |
1618 | int pkt_offset; | ||
1619 | }; | ||
1620 | |||
1621 | /** | ||
1622 | * struct cfg80211_wowlan_tcp - TCP connection parameters | ||
1623 | * | ||
1624 | * @sock: (internal) socket for source port allocation | ||
1625 | * @src: source IP address | ||
1626 | * @dst: destination IP address | ||
1627 | * @dst_mac: destination MAC address | ||
1628 | * @src_port: source port | ||
1629 | * @dst_port: destination port | ||
1630 | * @payload_len: data payload length | ||
1631 | * @payload: data payload buffer | ||
1632 | * @payload_seq: payload sequence stamping configuration | ||
1633 | * @data_interval: interval at which to send data packets | ||
1634 | * @wake_len: wakeup payload match length | ||
1635 | * @wake_data: wakeup payload match data | ||
1636 | * @wake_mask: wakeup payload match mask | ||
1637 | * @tokens_size: length of the tokens buffer | ||
1638 | * @payload_tok: payload token usage configuration | ||
1639 | */ | ||
1640 | struct cfg80211_wowlan_tcp { | ||
1641 | struct socket *sock; | ||
1642 | __be32 src, dst; | ||
1643 | u16 src_port, dst_port; | ||
1644 | u8 dst_mac[ETH_ALEN]; | ||
1645 | int payload_len; | ||
1646 | const u8 *payload; | ||
1647 | struct nl80211_wowlan_tcp_data_seq payload_seq; | ||
1648 | u32 data_interval; | ||
1649 | u32 wake_len; | ||
1650 | const u8 *wake_data, *wake_mask; | ||
1651 | u32 tokens_size; | ||
1652 | /* must be last, variable member */ | ||
1653 | struct nl80211_wowlan_tcp_data_token payload_tok; | ||
1574 | }; | 1654 | }; |
1575 | 1655 | ||
1576 | /** | 1656 | /** |
@@ -1587,16 +1667,49 @@ struct cfg80211_wowlan_trig_pkt_pattern { | |||
1587 | * @eap_identity_req: wake up on EAP identity request packet | 1667 | * @eap_identity_req: wake up on EAP identity request packet |
1588 | * @four_way_handshake: wake up on 4-way handshake | 1668 | * @four_way_handshake: wake up on 4-way handshake |
1589 | * @rfkill_release: wake up when rfkill is released | 1669 | * @rfkill_release: wake up when rfkill is released |
1670 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. | ||
1671 | * NULL if not configured. | ||
1590 | */ | 1672 | */ |
1591 | struct cfg80211_wowlan { | 1673 | struct cfg80211_wowlan { |
1592 | bool any, disconnect, magic_pkt, gtk_rekey_failure, | 1674 | bool any, disconnect, magic_pkt, gtk_rekey_failure, |
1593 | eap_identity_req, four_way_handshake, | 1675 | eap_identity_req, four_way_handshake, |
1594 | rfkill_release; | 1676 | rfkill_release; |
1595 | struct cfg80211_wowlan_trig_pkt_pattern *patterns; | 1677 | struct cfg80211_wowlan_trig_pkt_pattern *patterns; |
1678 | struct cfg80211_wowlan_tcp *tcp; | ||
1596 | int n_patterns; | 1679 | int n_patterns; |
1597 | }; | 1680 | }; |
1598 | 1681 | ||
1599 | /** | 1682 | /** |
1683 | * struct cfg80211_wowlan_wakeup - wakeup report | ||
1684 | * @disconnect: woke up by getting disconnected | ||
1685 | * @magic_pkt: woke up by receiving magic packet | ||
1686 | * @gtk_rekey_failure: woke up by GTK rekey failure | ||
1687 | * @eap_identity_req: woke up by EAP identity request packet | ||
1688 | * @four_way_handshake: woke up by 4-way handshake | ||
1689 | * @rfkill_release: woke up by rfkill being released | ||
1690 | * @pattern_idx: pattern that caused wakeup, -1 if not due to pattern | ||
1691 | * @packet_present_len: copied wakeup packet data | ||
1692 | * @packet_len: original wakeup packet length | ||
1693 | * @packet: The packet causing the wakeup, if any. | ||
1694 | * @packet_80211: For pattern match, magic packet and other data | ||
1695 | * frame triggers an 802.3 frame should be reported, for | ||
1696 | * disconnect due to deauth 802.11 frame. This indicates which | ||
1697 | * it is. | ||
1698 | * @tcp_match: TCP wakeup packet received | ||
1699 | * @tcp_connlost: TCP connection lost or failed to establish | ||
1700 | * @tcp_nomoretokens: TCP data ran out of tokens | ||
1701 | */ | ||
1702 | struct cfg80211_wowlan_wakeup { | ||
1703 | bool disconnect, magic_pkt, gtk_rekey_failure, | ||
1704 | eap_identity_req, four_way_handshake, | ||
1705 | rfkill_release, packet_80211, | ||
1706 | tcp_match, tcp_connlost, tcp_nomoretokens; | ||
1707 | s32 pattern_idx; | ||
1708 | u32 packet_present_len, packet_len; | ||
1709 | const void *packet; | ||
1710 | }; | ||
1711 | |||
1712 | /** | ||
1600 | * struct cfg80211_gtk_rekey_data - rekey data | 1713 | * struct cfg80211_gtk_rekey_data - rekey data |
1601 | * @kek: key encryption key | 1714 | * @kek: key encryption key |
1602 | * @kck: key confirmation key | 1715 | * @kck: key confirmation key |
@@ -1826,6 +1939,8 @@ struct cfg80211_gtk_rekey_data { | |||
1826 | * this new list replaces the existing one. Driver has to clear its ACL | 1939 | * this new list replaces the existing one. Driver has to clear its ACL |
1827 | * when number of MAC addresses entries is passed as 0. Drivers which | 1940 | * when number of MAC addresses entries is passed as 0. Drivers which |
1828 | * advertise the support for MAC based ACL have to implement this callback. | 1941 | * advertise the support for MAC based ACL have to implement this callback. |
1942 | * | ||
1943 | * @start_radar_detection: Start radar detection in the driver. | ||
1829 | */ | 1944 | */ |
1830 | struct cfg80211_ops { | 1945 | struct cfg80211_ops { |
1831 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 1946 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -2049,6 +2164,10 @@ struct cfg80211_ops { | |||
2049 | 2164 | ||
2050 | int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev, | 2165 | int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev, |
2051 | const struct cfg80211_acl_data *params); | 2166 | const struct cfg80211_acl_data *params); |
2167 | |||
2168 | int (*start_radar_detection)(struct wiphy *wiphy, | ||
2169 | struct net_device *dev, | ||
2170 | struct cfg80211_chan_def *chandef); | ||
2052 | }; | 2171 | }; |
2053 | 2172 | ||
2054 | /* | 2173 | /* |
@@ -2245,6 +2364,14 @@ enum wiphy_wowlan_support_flags { | |||
2245 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), | 2364 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), |
2246 | }; | 2365 | }; |
2247 | 2366 | ||
2367 | struct wiphy_wowlan_tcp_support { | ||
2368 | const struct nl80211_wowlan_tcp_data_token_feature *tok; | ||
2369 | u32 data_payload_max; | ||
2370 | u32 data_interval_max; | ||
2371 | u32 wake_payload_max; | ||
2372 | bool seq; | ||
2373 | }; | ||
2374 | |||
2248 | /** | 2375 | /** |
2249 | * struct wiphy_wowlan_support - WoWLAN support data | 2376 | * struct wiphy_wowlan_support - WoWLAN support data |
2250 | * @flags: see &enum wiphy_wowlan_support_flags | 2377 | * @flags: see &enum wiphy_wowlan_support_flags |
@@ -2252,12 +2379,16 @@ enum wiphy_wowlan_support_flags { | |||
2252 | * (see nl80211.h for the pattern definition) | 2379 | * (see nl80211.h for the pattern definition) |
2253 | * @pattern_max_len: maximum length of each pattern | 2380 | * @pattern_max_len: maximum length of each pattern |
2254 | * @pattern_min_len: minimum length of each pattern | 2381 | * @pattern_min_len: minimum length of each pattern |
2382 | * @max_pkt_offset: maximum Rx packet offset | ||
2383 | * @tcp: TCP wakeup support information | ||
2255 | */ | 2384 | */ |
2256 | struct wiphy_wowlan_support { | 2385 | struct wiphy_wowlan_support { |
2257 | u32 flags; | 2386 | u32 flags; |
2258 | int n_patterns; | 2387 | int n_patterns; |
2259 | int pattern_max_len; | 2388 | int pattern_max_len; |
2260 | int pattern_min_len; | 2389 | int pattern_min_len; |
2390 | int max_pkt_offset; | ||
2391 | const struct wiphy_wowlan_tcp_support *tcp; | ||
2261 | }; | 2392 | }; |
2262 | 2393 | ||
2263 | /** | 2394 | /** |
@@ -2357,6 +2488,14 @@ struct wiphy_wowlan_support { | |||
2357 | * | 2488 | * |
2358 | * @max_acl_mac_addrs: Maximum number of MAC addresses that the device | 2489 | * @max_acl_mac_addrs: Maximum number of MAC addresses that the device |
2359 | * supports for ACL. | 2490 | * supports for ACL. |
2491 | * | ||
2492 | * @extended_capabilities: extended capabilities supported by the driver, | ||
2493 | * additional capabilities might be supported by userspace; these are | ||
2494 | * the 802.11 extended capabilities ("Extended Capabilities element") | ||
2495 | * and are in the same format as in the information element. See | ||
2496 | * 802.11-2012 8.4.2.29 for the defined fields. | ||
2497 | * @extended_capabilities_mask: mask of the valid values | ||
2498 | * @extended_capabilities_len: length of the extended capabilities | ||
2360 | */ | 2499 | */ |
2361 | struct wiphy { | 2500 | struct wiphy { |
2362 | /* assign these fields before you register the wiphy */ | 2501 | /* assign these fields before you register the wiphy */ |
@@ -2423,6 +2562,9 @@ struct wiphy { | |||
2423 | */ | 2562 | */ |
2424 | u32 probe_resp_offload; | 2563 | u32 probe_resp_offload; |
2425 | 2564 | ||
2565 | const u8 *extended_capabilities, *extended_capabilities_mask; | ||
2566 | u8 extended_capabilities_len; | ||
2567 | |||
2426 | /* If multiple wiphys are registered and you're handed e.g. | 2568 | /* If multiple wiphys are registered and you're handed e.g. |
2427 | * a regular netdev with assigned ieee80211_ptr, you won't | 2569 | * a regular netdev with assigned ieee80211_ptr, you won't |
2428 | * know whether it points to a wiphy your driver has registered | 2570 | * know whether it points to a wiphy your driver has registered |
@@ -2602,7 +2744,6 @@ struct cfg80211_cached_keys; | |||
2602 | * the user-set AP, monitor and WDS channel | 2744 | * the user-set AP, monitor and WDS channel |
2603 | * @preset_chan: (private) Used by the internal configuration code to | 2745 | * @preset_chan: (private) Used by the internal configuration code to |
2604 | * track the channel to be used for AP later | 2746 | * track the channel to be used for AP later |
2605 | * @preset_chantype: (private) the corresponding channel type | ||
2606 | * @bssid: (private) Used by the internal configuration code | 2747 | * @bssid: (private) Used by the internal configuration code |
2607 | * @ssid: (private) Used by the internal configuration code | 2748 | * @ssid: (private) Used by the internal configuration code |
2608 | * @ssid_len: (private) Used by the internal configuration code | 2749 | * @ssid_len: (private) Used by the internal configuration code |
@@ -2621,6 +2762,8 @@ struct cfg80211_cached_keys; | |||
2621 | * beacons, 0 when not valid | 2762 | * beacons, 0 when not valid |
2622 | * @address: The address for this device, valid only if @netdev is %NULL | 2763 | * @address: The address for this device, valid only if @netdev is %NULL |
2623 | * @p2p_started: true if this is a P2P Device that has been started | 2764 | * @p2p_started: true if this is a P2P Device that has been started |
2765 | * @cac_started: true if DFS channel availability check has been started | ||
2766 | * @cac_start_time: timestamp (jiffies) when the dfs state was entered. | ||
2624 | */ | 2767 | */ |
2625 | struct wireless_dev { | 2768 | struct wireless_dev { |
2626 | struct wiphy *wiphy; | 2769 | struct wiphy *wiphy; |
@@ -2672,6 +2815,9 @@ struct wireless_dev { | |||
2672 | 2815 | ||
2673 | u32 ap_unexpected_nlportid; | 2816 | u32 ap_unexpected_nlportid; |
2674 | 2817 | ||
2818 | bool cac_started; | ||
2819 | unsigned long cac_start_time; | ||
2820 | |||
2675 | #ifdef CONFIG_CFG80211_WEXT | 2821 | #ifdef CONFIG_CFG80211_WEXT |
2676 | /* wext data */ | 2822 | /* wext data */ |
2677 | struct { | 2823 | struct { |
@@ -3137,25 +3283,23 @@ cfg80211_get_ibss(struct wiphy *wiphy, | |||
3137 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); | 3283 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); |
3138 | } | 3284 | } |
3139 | 3285 | ||
3140 | struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, | ||
3141 | struct ieee80211_channel *channel, | ||
3142 | const u8 *meshid, size_t meshidlen, | ||
3143 | const u8 *meshcfg); | ||
3144 | /** | 3286 | /** |
3145 | * cfg80211_ref_bss - reference BSS struct | 3287 | * cfg80211_ref_bss - reference BSS struct |
3288 | * @wiphy: the wiphy this BSS struct belongs to | ||
3146 | * @bss: the BSS struct to reference | 3289 | * @bss: the BSS struct to reference |
3147 | * | 3290 | * |
3148 | * Increments the refcount of the given BSS struct. | 3291 | * Increments the refcount of the given BSS struct. |
3149 | */ | 3292 | */ |
3150 | void cfg80211_ref_bss(struct cfg80211_bss *bss); | 3293 | void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); |
3151 | 3294 | ||
3152 | /** | 3295 | /** |
3153 | * cfg80211_put_bss - unref BSS struct | 3296 | * cfg80211_put_bss - unref BSS struct |
3297 | * @wiphy: the wiphy this BSS struct belongs to | ||
3154 | * @bss: the BSS struct | 3298 | * @bss: the BSS struct |
3155 | * | 3299 | * |
3156 | * Decrements the refcount of the given BSS struct. | 3300 | * Decrements the refcount of the given BSS struct. |
3157 | */ | 3301 | */ |
3158 | void cfg80211_put_bss(struct cfg80211_bss *bss); | 3302 | void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); |
3159 | 3303 | ||
3160 | /** | 3304 | /** |
3161 | * cfg80211_unlink_bss - unlink BSS from internal data structures | 3305 | * cfg80211_unlink_bss - unlink BSS from internal data structures |
@@ -3663,6 +3807,31 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, | |||
3663 | gfp_t gfp); | 3807 | gfp_t gfp); |
3664 | 3808 | ||
3665 | /** | 3809 | /** |
3810 | * cfg80211_radar_event - radar detection event | ||
3811 | * @wiphy: the wiphy | ||
3812 | * @chandef: chandef for the current channel | ||
3813 | * @gfp: context flags | ||
3814 | * | ||
3815 | * This function is called when a radar is detected on the current chanenl. | ||
3816 | */ | ||
3817 | void cfg80211_radar_event(struct wiphy *wiphy, | ||
3818 | struct cfg80211_chan_def *chandef, gfp_t gfp); | ||
3819 | |||
3820 | /** | ||
3821 | * cfg80211_cac_event - Channel availability check (CAC) event | ||
3822 | * @netdev: network device | ||
3823 | * @event: type of event | ||
3824 | * @gfp: context flags | ||
3825 | * | ||
3826 | * This function is called when a Channel availability check (CAC) is finished | ||
3827 | * or aborted. This must be called to notify the completion of a CAC process, | ||
3828 | * also by full-MAC drivers. | ||
3829 | */ | ||
3830 | void cfg80211_cac_event(struct net_device *netdev, | ||
3831 | enum nl80211_radar_event event, gfp_t gfp); | ||
3832 | |||
3833 | |||
3834 | /** | ||
3666 | * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer | 3835 | * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer |
3667 | * @dev: network device | 3836 | * @dev: network device |
3668 | * @peer: peer's MAC address | 3837 | * @peer: peer's MAC address |
@@ -3852,6 +4021,21 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | |||
3852 | enum ieee80211_p2p_attr_id attr, | 4021 | enum ieee80211_p2p_attr_id attr, |
3853 | u8 *buf, unsigned int bufsize); | 4022 | u8 *buf, unsigned int bufsize); |
3854 | 4023 | ||
4024 | /** | ||
4025 | * cfg80211_report_wowlan_wakeup - report wakeup from WoWLAN | ||
4026 | * @wdev: the wireless device reporting the wakeup | ||
4027 | * @wakeup: the wakeup report | ||
4028 | * @gfp: allocation flags | ||
4029 | * | ||
4030 | * This function reports that the given device woke up. If it | ||
4031 | * caused the wakeup, report the reason(s), otherwise you may | ||
4032 | * pass %NULL as the @wakeup parameter to advertise that something | ||
4033 | * else caused the wakeup. | ||
4034 | */ | ||
4035 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | ||
4036 | struct cfg80211_wowlan_wakeup *wakeup, | ||
4037 | gfp_t gfp); | ||
4038 | |||
3855 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 4039 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
3856 | 4040 | ||
3857 | /* wiphy_printk helpers, similar to dev_printk */ | 4041 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5c98d654fc75..f7eba1300d82 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -147,10 +147,12 @@ struct ieee80211_low_level_stats { | |||
147 | * enum ieee80211_chanctx_change - change flag for channel context | 147 | * enum ieee80211_chanctx_change - change flag for channel context |
148 | * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed | 148 | * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed |
149 | * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed | 149 | * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed |
150 | * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed | ||
150 | */ | 151 | */ |
151 | enum ieee80211_chanctx_change { | 152 | enum ieee80211_chanctx_change { |
152 | IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), | 153 | IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), |
153 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), | 154 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), |
155 | IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2), | ||
154 | }; | 156 | }; |
155 | 157 | ||
156 | /** | 158 | /** |
@@ -165,6 +167,7 @@ enum ieee80211_chanctx_change { | |||
165 | * @rx_chains_dynamic: The number of RX chains that must be enabled | 167 | * @rx_chains_dynamic: The number of RX chains that must be enabled |
166 | * after RTS/CTS handshake to receive SMPS MIMO transmissions; | 168 | * after RTS/CTS handshake to receive SMPS MIMO transmissions; |
167 | * this will always be >= @rx_chains_static. | 169 | * this will always be >= @rx_chains_static. |
170 | * @radar_enabled: whether radar detection is enabled on this channel. | ||
168 | * @drv_priv: data area for driver use, will always be aligned to | 171 | * @drv_priv: data area for driver use, will always be aligned to |
169 | * sizeof(void *), size is determined in hw information. | 172 | * sizeof(void *), size is determined in hw information. |
170 | */ | 173 | */ |
@@ -173,6 +176,8 @@ struct ieee80211_chanctx_conf { | |||
173 | 176 | ||
174 | u8 rx_chains_static, rx_chains_dynamic; | 177 | u8 rx_chains_static, rx_chains_dynamic; |
175 | 178 | ||
179 | bool radar_enabled; | ||
180 | |||
176 | u8 drv_priv[0] __aligned(sizeof(void *)); | 181 | u8 drv_priv[0] __aligned(sizeof(void *)); |
177 | }; | 182 | }; |
178 | 183 | ||
@@ -208,6 +213,11 @@ struct ieee80211_chanctx_conf { | |||
208 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface | 213 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface |
209 | * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS) | 214 | * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS) |
210 | * changed (currently only in P2P client mode, GO mode will be later) | 215 | * changed (currently only in P2P client mode, GO mode will be later) |
216 | * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when | ||
217 | * it becomes valid, managed mode only) | ||
218 | * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed, | ||
219 | * note that this is only called when it changes after the channel | ||
220 | * context had been assigned. | ||
211 | */ | 221 | */ |
212 | enum ieee80211_bss_change { | 222 | enum ieee80211_bss_change { |
213 | BSS_CHANGED_ASSOC = 1<<0, | 223 | BSS_CHANGED_ASSOC = 1<<0, |
@@ -230,6 +240,8 @@ enum ieee80211_bss_change { | |||
230 | BSS_CHANGED_PS = 1<<17, | 240 | BSS_CHANGED_PS = 1<<17, |
231 | BSS_CHANGED_TXPOWER = 1<<18, | 241 | BSS_CHANGED_TXPOWER = 1<<18, |
232 | BSS_CHANGED_P2P_PS = 1<<19, | 242 | BSS_CHANGED_P2P_PS = 1<<19, |
243 | BSS_CHANGED_DTIM_PERIOD = 1<<20, | ||
244 | BSS_CHANGED_BANDWIDTH = 1<<21, | ||
233 | 245 | ||
234 | /* when adding here, make sure to change ieee80211_reconfig */ | 246 | /* when adding here, make sure to change ieee80211_reconfig */ |
235 | }; | 247 | }; |
@@ -271,13 +283,19 @@ enum ieee80211_rssi_event { | |||
271 | * if the hardware cannot handle this it must set the | 283 | * if the hardware cannot handle this it must set the |
272 | * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag | 284 | * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag |
273 | * @dtim_period: num of beacons before the next DTIM, for beaconing, | 285 | * @dtim_period: num of beacons before the next DTIM, for beaconing, |
274 | * valid in station mode only while @assoc is true and if also | 286 | * valid in station mode only if after the driver was notified |
275 | * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf | 287 | * with the %BSS_CHANGED_DTIM_PERIOD flag, will be non-zero then. |
276 | * @ps_dtim_period) | ||
277 | * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old | 288 | * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old |
278 | * as it may have been received during scanning long ago) | 289 | * as it may have been received during scanning long ago). If the |
290 | * HW flag %IEEE80211_HW_TIMING_BEACON_ONLY is set, then this can | ||
291 | * only come from a beacon, but might not become valid until after | ||
292 | * association when a beacon is received (which is notified with the | ||
293 | * %BSS_CHANGED_DTIM flag.) | ||
279 | * @sync_device_ts: the device timestamp corresponding to the sync_tsf, | 294 | * @sync_device_ts: the device timestamp corresponding to the sync_tsf, |
280 | * the driver/device can use this to calculate synchronisation | 295 | * the driver/device can use this to calculate synchronisation |
296 | * (see @sync_tsf) | ||
297 | * @sync_dtim_count: Only valid when %IEEE80211_HW_TIMING_BEACON_ONLY | ||
298 | * is requested, see @sync_tsf/@sync_device_ts. | ||
281 | * @beacon_int: beacon interval | 299 | * @beacon_int: beacon interval |
282 | * @assoc_capability: capabilities taken from assoc resp | 300 | * @assoc_capability: capabilities taken from assoc resp |
283 | * @basic_rates: bitmap of basic rates, each bit stands for an | 301 | * @basic_rates: bitmap of basic rates, each bit stands for an |
@@ -329,6 +347,7 @@ struct ieee80211_bss_conf { | |||
329 | u16 assoc_capability; | 347 | u16 assoc_capability; |
330 | u64 sync_tsf; | 348 | u64 sync_tsf; |
331 | u32 sync_device_ts; | 349 | u32 sync_device_ts; |
350 | u8 sync_dtim_count; | ||
332 | u32 basic_rates; | 351 | u32 basic_rates; |
333 | int mcast_rate[IEEE80211_NUM_BANDS]; | 352 | int mcast_rate[IEEE80211_NUM_BANDS]; |
334 | u16 ht_operation_mode; | 353 | u16 ht_operation_mode; |
@@ -389,6 +408,9 @@ struct ieee80211_bss_conf { | |||
389 | * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be | 408 | * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be |
390 | * set by rate control algorithms to indicate probe rate, will | 409 | * set by rate control algorithms to indicate probe rate, will |
391 | * be cleared for fragmented frames (except on the last fragment) | 410 | * be cleared for fragmented frames (except on the last fragment) |
411 | * @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate | ||
412 | * that a frame can be transmitted while the queues are stopped for | ||
413 | * off-channel operation. | ||
392 | * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, | 414 | * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, |
393 | * used to indicate that a pending frame requires TX processing before | 415 | * used to indicate that a pending frame requires TX processing before |
394 | * it can be sent out. | 416 | * it can be sent out. |
@@ -406,6 +428,9 @@ struct ieee80211_bss_conf { | |||
406 | * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted | 428 | * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted |
407 | * after TX status because the destination was asleep, it must not | 429 | * after TX status because the destination was asleep, it must not |
408 | * be modified again (no seqno assignment, crypto, etc.) | 430 | * be modified again (no seqno assignment, crypto, etc.) |
431 | * @IEEE80211_TX_INTFL_MLME_CONN_TX: This frame was transmitted by the MLME | ||
432 | * code for connection establishment, this indicates that its status | ||
433 | * should kick the MLME state machine. | ||
409 | * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 | 434 | * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 |
410 | * MLME command (internal to mac80211 to figure out whether to send TX | 435 | * MLME command (internal to mac80211 to figure out whether to send TX |
411 | * status to user space) | 436 | * status to user space) |
@@ -451,13 +476,14 @@ enum mac80211_tx_control_flags { | |||
451 | IEEE80211_TX_STAT_AMPDU = BIT(10), | 476 | IEEE80211_TX_STAT_AMPDU = BIT(10), |
452 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), | 477 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), |
453 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), | 478 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), |
479 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13), | ||
454 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), | 480 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), |
455 | IEEE80211_TX_INTFL_RETRIED = BIT(15), | 481 | IEEE80211_TX_INTFL_RETRIED = BIT(15), |
456 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), | 482 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), |
457 | IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17), | 483 | IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17), |
458 | IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), | 484 | IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), |
459 | IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), | 485 | IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), |
460 | /* hole at 20, use later */ | 486 | IEEE80211_TX_INTFL_MLME_CONN_TX = BIT(20), |
461 | IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), | 487 | IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), |
462 | IEEE80211_TX_CTL_LDPC = BIT(22), | 488 | IEEE80211_TX_CTL_LDPC = BIT(22), |
463 | IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), | 489 | IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), |
@@ -950,6 +976,7 @@ enum ieee80211_smps_mode { | |||
950 | * | 976 | * |
951 | * @channel: the channel to tune to | 977 | * @channel: the channel to tune to |
952 | * @channel_type: the channel (HT) type | 978 | * @channel_type: the channel (HT) type |
979 | * @radar_enabled: whether radar detection is enabled | ||
953 | * | 980 | * |
954 | * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame | 981 | * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame |
955 | * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, | 982 | * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, |
@@ -976,6 +1003,7 @@ struct ieee80211_conf { | |||
976 | 1003 | ||
977 | struct ieee80211_channel *channel; | 1004 | struct ieee80211_channel *channel; |
978 | enum nl80211_channel_type channel_type; | 1005 | enum nl80211_channel_type channel_type; |
1006 | bool radar_enabled; | ||
979 | enum ieee80211_smps_mode smps_mode; | 1007 | enum ieee80211_smps_mode smps_mode; |
980 | }; | 1008 | }; |
981 | 1009 | ||
@@ -1173,6 +1201,24 @@ enum ieee80211_sta_state { | |||
1173 | }; | 1201 | }; |
1174 | 1202 | ||
1175 | /** | 1203 | /** |
1204 | * enum ieee80211_sta_rx_bandwidth - station RX bandwidth | ||
1205 | * @IEEE80211_STA_RX_BW_20: station can only receive 20 MHz | ||
1206 | * @IEEE80211_STA_RX_BW_40: station can receive up to 40 MHz | ||
1207 | * @IEEE80211_STA_RX_BW_80: station can receive up to 80 MHz | ||
1208 | * @IEEE80211_STA_RX_BW_160: station can receive up to 160 MHz | ||
1209 | * (including 80+80 MHz) | ||
1210 | * | ||
1211 | * Implementation note: 20 must be zero to be initialized | ||
1212 | * correctly, the values must be sorted. | ||
1213 | */ | ||
1214 | enum ieee80211_sta_rx_bandwidth { | ||
1215 | IEEE80211_STA_RX_BW_20 = 0, | ||
1216 | IEEE80211_STA_RX_BW_40, | ||
1217 | IEEE80211_STA_RX_BW_80, | ||
1218 | IEEE80211_STA_RX_BW_160, | ||
1219 | }; | ||
1220 | |||
1221 | /** | ||
1176 | * struct ieee80211_sta - station table entry | 1222 | * struct ieee80211_sta - station table entry |
1177 | * | 1223 | * |
1178 | * A station table entry represents a station we are possibly | 1224 | * A station table entry represents a station we are possibly |
@@ -1194,6 +1240,12 @@ enum ieee80211_sta_state { | |||
1194 | * @uapsd_queues: bitmap of queues configured for uapsd. Only valid | 1240 | * @uapsd_queues: bitmap of queues configured for uapsd. Only valid |
1195 | * if wme is supported. | 1241 | * if wme is supported. |
1196 | * @max_sp: max Service Period. Only valid if wme is supported. | 1242 | * @max_sp: max Service Period. Only valid if wme is supported. |
1243 | * @bandwidth: current bandwidth the station can receive with | ||
1244 | * @rx_nss: in HT/VHT, the maximum number of spatial streams the | ||
1245 | * station can receive at the moment, changed by operating mode | ||
1246 | * notifications and capabilities. The value is only valid after | ||
1247 | * the station moves to associated state. | ||
1248 | * @smps_mode: current SMPS mode (off, static or dynamic) | ||
1197 | */ | 1249 | */ |
1198 | struct ieee80211_sta { | 1250 | struct ieee80211_sta { |
1199 | u32 supp_rates[IEEE80211_NUM_BANDS]; | 1251 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
@@ -1204,6 +1256,9 @@ struct ieee80211_sta { | |||
1204 | bool wme; | 1256 | bool wme; |
1205 | u8 uapsd_queues; | 1257 | u8 uapsd_queues; |
1206 | u8 max_sp; | 1258 | u8 max_sp; |
1259 | u8 rx_nss; | ||
1260 | enum ieee80211_sta_rx_bandwidth bandwidth; | ||
1261 | enum ieee80211_smps_mode smps_mode; | ||
1207 | 1262 | ||
1208 | /* must be last */ | 1263 | /* must be last */ |
1209 | u8 drv_priv[0] __aligned(sizeof(void *)); | 1264 | u8 drv_priv[0] __aligned(sizeof(void *)); |
@@ -1328,9 +1383,9 @@ struct ieee80211_tx_control { | |||
1328 | * When this flag is set, signaling beacon-loss will cause an immediate | 1383 | * When this flag is set, signaling beacon-loss will cause an immediate |
1329 | * change to disassociated state. | 1384 | * change to disassociated state. |
1330 | * | 1385 | * |
1331 | * @IEEE80211_HW_NEED_DTIM_PERIOD: | 1386 | * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC: |
1332 | * This device needs to know the DTIM period for the BSS before | 1387 | * This device needs to get data from beacon before association (i.e. |
1333 | * associating. | 1388 | * dtim_period). |
1334 | * | 1389 | * |
1335 | * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports | 1390 | * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports |
1336 | * per-station GTKs as used by IBSS RSN or during fast transition. If | 1391 | * per-station GTKs as used by IBSS RSN or during fast transition. If |
@@ -1350,10 +1405,6 @@ struct ieee80211_tx_control { | |||
1350 | * setup strictly in HW. mac80211 should not attempt to do this in | 1405 | * setup strictly in HW. mac80211 should not attempt to do this in |
1351 | * software. | 1406 | * software. |
1352 | * | 1407 | * |
1353 | * @IEEE80211_HW_SCAN_WHILE_IDLE: The device can do hw scan while | ||
1354 | * being idle (i.e. mac80211 doesn't have to go idle-off during the | ||
1355 | * the scan). | ||
1356 | * | ||
1357 | * @IEEE80211_HW_WANT_MONITOR_VIF: The driver would like to be informed of | 1408 | * @IEEE80211_HW_WANT_MONITOR_VIF: The driver would like to be informed of |
1358 | * a virtual monitor interface when monitor interfaces are the only | 1409 | * a virtual monitor interface when monitor interfaces are the only |
1359 | * active interfaces. | 1410 | * active interfaces. |
@@ -1367,9 +1418,8 @@ struct ieee80211_tx_control { | |||
1367 | * P2P Interface. This will be honoured even if more than one interface | 1418 | * P2P Interface. This will be honoured even if more than one interface |
1368 | * is supported. | 1419 | * is supported. |
1369 | * | 1420 | * |
1370 | * @IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL: On this hardware TX BA session | 1421 | * @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames |
1371 | * should be tear down once BAR frame will not be acked. | 1422 | * only, to allow getting TBTT of a DTIM beacon. |
1372 | * | ||
1373 | */ | 1423 | */ |
1374 | enum ieee80211_hw_flags { | 1424 | enum ieee80211_hw_flags { |
1375 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 1425 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
@@ -1379,7 +1429,7 @@ enum ieee80211_hw_flags { | |||
1379 | IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, | 1429 | IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, |
1380 | IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, | 1430 | IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, |
1381 | IEEE80211_HW_SIGNAL_DBM = 1<<6, | 1431 | IEEE80211_HW_SIGNAL_DBM = 1<<6, |
1382 | IEEE80211_HW_NEED_DTIM_PERIOD = 1<<7, | 1432 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC = 1<<7, |
1383 | IEEE80211_HW_SPECTRUM_MGMT = 1<<8, | 1433 | IEEE80211_HW_SPECTRUM_MGMT = 1<<8, |
1384 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<9, | 1434 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<9, |
1385 | IEEE80211_HW_SUPPORTS_PS = 1<<10, | 1435 | IEEE80211_HW_SUPPORTS_PS = 1<<10, |
@@ -1396,9 +1446,8 @@ enum ieee80211_hw_flags { | |||
1396 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, | 1446 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, |
1397 | IEEE80211_HW_AP_LINK_PS = 1<<22, | 1447 | IEEE80211_HW_AP_LINK_PS = 1<<22, |
1398 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, | 1448 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, |
1399 | IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24, | ||
1400 | IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25, | 1449 | IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25, |
1401 | IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL = 1<<26, | 1450 | IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, |
1402 | }; | 1451 | }; |
1403 | 1452 | ||
1404 | /** | 1453 | /** |
@@ -1683,15 +1732,6 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); | |||
1683 | * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS | 1732 | * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS |
1684 | * enabled whenever user has enabled powersave. | 1733 | * enabled whenever user has enabled powersave. |
1685 | * | 1734 | * |
1686 | * Some hardware need to toggle a single shared antenna between WLAN and | ||
1687 | * Bluetooth to facilitate co-existence. These types of hardware set | ||
1688 | * limitations on the use of host controlled dynamic powersave whenever there | ||
1689 | * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the | ||
1690 | * driver may request temporarily going into full power save, in order to | ||
1691 | * enable toggling the antenna between BT and WLAN. If the driver requests | ||
1692 | * disabling dynamic powersave, the @dynamic_ps_timeout value will be | ||
1693 | * temporarily set to zero until the driver re-enables dynamic powersave. | ||
1694 | * | ||
1695 | * Driver informs U-APSD client support by enabling | 1735 | * Driver informs U-APSD client support by enabling |
1696 | * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the | 1736 | * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the |
1697 | * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS | 1737 | * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS |
@@ -2077,16 +2117,21 @@ enum ieee80211_frame_release_type { | |||
2077 | * enum ieee80211_rate_control_changed - flags to indicate what changed | 2117 | * enum ieee80211_rate_control_changed - flags to indicate what changed |
2078 | * | 2118 | * |
2079 | * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit | 2119 | * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit |
2080 | * to this station changed. | 2120 | * to this station changed. The actual bandwidth is in the station |
2121 | * information -- for HT20/40 the IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
2122 | * flag changes, for HT and VHT the bandwidth field changes. | ||
2081 | * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. | 2123 | * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. |
2082 | * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer | 2124 | * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer |
2083 | * changed (in IBSS mode) due to discovering more information about | 2125 | * changed (in IBSS mode) due to discovering more information about |
2084 | * the peer. | 2126 | * the peer. |
2127 | * @IEEE80211_RC_NSS_CHANGED: N_SS (number of spatial streams) was changed | ||
2128 | * by the peer | ||
2085 | */ | 2129 | */ |
2086 | enum ieee80211_rate_control_changed { | 2130 | enum ieee80211_rate_control_changed { |
2087 | IEEE80211_RC_BW_CHANGED = BIT(0), | 2131 | IEEE80211_RC_BW_CHANGED = BIT(0), |
2088 | IEEE80211_RC_SMPS_CHANGED = BIT(1), | 2132 | IEEE80211_RC_SMPS_CHANGED = BIT(1), |
2089 | IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2), | 2133 | IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2), |
2134 | IEEE80211_RC_NSS_CHANGED = BIT(3), | ||
2090 | }; | 2135 | }; |
2091 | 2136 | ||
2092 | /** | 2137 | /** |
@@ -2167,6 +2212,18 @@ enum ieee80211_rate_control_changed { | |||
2167 | * MAC address of the device going away. | 2212 | * MAC address of the device going away. |
2168 | * Hence, this callback must be implemented. It can sleep. | 2213 | * Hence, this callback must be implemented. It can sleep. |
2169 | * | 2214 | * |
2215 | * @add_interface_debugfs: Drivers can use this callback to add debugfs files | ||
2216 | * when a vif is added to mac80211. This callback and | ||
2217 | * @remove_interface_debugfs should be within a CONFIG_MAC80211_DEBUGFS | ||
2218 | * conditional. @remove_interface_debugfs must be provided for cleanup. | ||
2219 | * This callback can sleep. | ||
2220 | * | ||
2221 | * @remove_interface_debugfs: Remove the debugfs files which were added using | ||
2222 | * @add_interface_debugfs. This callback must remove all debugfs entries | ||
2223 | * that were added because mac80211 only removes interface debugfs when the | ||
2224 | * interface is destroyed, not when it is removed from the driver. | ||
2225 | * This callback can sleep. | ||
2226 | * | ||
2170 | * @config: Handler for configuration requests. IEEE 802.11 code calls this | 2227 | * @config: Handler for configuration requests. IEEE 802.11 code calls this |
2171 | * function to change hardware configuration, e.g., channel. | 2228 | * function to change hardware configuration, e.g., channel. |
2172 | * This function should never fail but returns a negative error code | 2229 | * This function should never fail but returns a negative error code |
@@ -2580,6 +2637,12 @@ struct ieee80211_ops { | |||
2580 | struct ieee80211_vif *vif, | 2637 | struct ieee80211_vif *vif, |
2581 | struct ieee80211_sta *sta, | 2638 | struct ieee80211_sta *sta, |
2582 | struct dentry *dir); | 2639 | struct dentry *dir); |
2640 | void (*add_interface_debugfs)(struct ieee80211_hw *hw, | ||
2641 | struct ieee80211_vif *vif, | ||
2642 | struct dentry *dir); | ||
2643 | void (*remove_interface_debugfs)(struct ieee80211_hw *hw, | ||
2644 | struct ieee80211_vif *vif, | ||
2645 | struct dentry *dir); | ||
2583 | #endif | 2646 | #endif |
2584 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2647 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2585 | enum sta_notify_cmd, struct ieee80211_sta *sta); | 2648 | enum sta_notify_cmd, struct ieee80211_sta *sta); |
@@ -3877,6 +3940,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif); | |||
3877 | * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and | 3940 | * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and |
3878 | * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver | 3941 | * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver |
3879 | * needs to inform if the connection to the AP has been lost. | 3942 | * needs to inform if the connection to the AP has been lost. |
3943 | * The function may also be called if the connection needs to be terminated | ||
3944 | * for some other reason, even if %IEEE80211_HW_CONNECTION_MONITOR isn't set. | ||
3880 | * | 3945 | * |
3881 | * This function will cause immediate change to disassociated state, | 3946 | * This function will cause immediate change to disassociated state, |
3882 | * without connection recovery attempts. | 3947 | * without connection recovery attempts. |
@@ -3907,36 +3972,6 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif); | |||
3907 | void ieee80211_resume_disconnect(struct ieee80211_vif *vif); | 3972 | void ieee80211_resume_disconnect(struct ieee80211_vif *vif); |
3908 | 3973 | ||
3909 | /** | 3974 | /** |
3910 | * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm | ||
3911 | * | ||
3912 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
3913 | * | ||
3914 | * Some hardware require full power save to manage simultaneous BT traffic | ||
3915 | * on the WLAN frequency. Full PSM is required periodically, whenever there are | ||
3916 | * burst of BT traffic. The hardware gets information of BT traffic via | ||
3917 | * hardware co-existence lines, and consequentially requests mac80211 to | ||
3918 | * (temporarily) enter full psm. | ||
3919 | * This function will only temporarily disable dynamic PS, not enable PSM if | ||
3920 | * it was not already enabled. | ||
3921 | * The driver must make sure to re-enable dynamic PS using | ||
3922 | * ieee80211_enable_dyn_ps() if the driver has disabled it. | ||
3923 | * | ||
3924 | */ | ||
3925 | void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif); | ||
3926 | |||
3927 | /** | ||
3928 | * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled | ||
3929 | * | ||
3930 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
3931 | * | ||
3932 | * This function restores dynamic PS after being temporarily disabled via | ||
3933 | * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must | ||
3934 | * be coupled with an eventual call to this function. | ||
3935 | * | ||
3936 | */ | ||
3937 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif); | ||
3938 | |||
3939 | /** | ||
3940 | * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring | 3975 | * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring |
3941 | * rssi threshold triggered | 3976 | * rssi threshold triggered |
3942 | * | 3977 | * |
@@ -3953,6 +3988,13 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | |||
3953 | gfp_t gfp); | 3988 | gfp_t gfp); |
3954 | 3989 | ||
3955 | /** | 3990 | /** |
3991 | * ieee80211_radar_detected - inform that a radar was detected | ||
3992 | * | ||
3993 | * @hw: pointer as obtained from ieee80211_alloc_hw() | ||
3994 | */ | ||
3995 | void ieee80211_radar_detected(struct ieee80211_hw *hw); | ||
3996 | |||
3997 | /** | ||
3956 | * ieee80211_chswitch_done - Complete channel switch process | 3998 | * ieee80211_chswitch_done - Complete channel switch process |
3957 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 3999 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
3958 | * @success: make the channel switch successful or not | 4000 | * @success: make the channel switch successful or not |
@@ -4211,4 +4253,16 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); | |||
4211 | */ | 4253 | */ |
4212 | int ieee80211_ave_rssi(struct ieee80211_vif *vif); | 4254 | int ieee80211_ave_rssi(struct ieee80211_vif *vif); |
4213 | 4255 | ||
4256 | /** | ||
4257 | * ieee80211_report_wowlan_wakeup - report WoWLAN wakeup | ||
4258 | * @vif: virtual interface | ||
4259 | * @wakeup: wakeup reason(s) | ||
4260 | * @gfp: allocation flags | ||
4261 | * | ||
4262 | * See cfg80211_report_wowlan_wakeup(). | ||
4263 | */ | ||
4264 | void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif, | ||
4265 | struct cfg80211_wowlan_wakeup *wakeup, | ||
4266 | gfp_t gfp); | ||
4267 | |||
4214 | #endif /* MAC80211_H */ | 4268 | #endif /* MAC80211_H */ |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5b7dbc1ea966..c46bb016f4e4 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -513,6 +513,12 @@ | |||
513 | * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For | 513 | * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For |
514 | * more background information, see | 514 | * more background information, see |
515 | * http://wireless.kernel.org/en/users/Documentation/WoWLAN. | 515 | * http://wireless.kernel.org/en/users/Documentation/WoWLAN. |
516 | * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification | ||
517 | * from the driver reporting the wakeup reason. In this case, the | ||
518 | * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason | ||
519 | * for the wakeup, if it was caused by wireless. If it is not present | ||
520 | * in the wakeup notification, the wireless device didn't cause the | ||
521 | * wakeup but reports that it was woken up. | ||
516 | * | 522 | * |
517 | * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver | 523 | * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver |
518 | * the necessary information for supporting GTK rekey offload. This | 524 | * the necessary information for supporting GTK rekey offload. This |
@@ -597,6 +603,14 @@ | |||
597 | * command is used in AP/P2P GO mode. Driver has to make sure to clear its | 603 | * command is used in AP/P2P GO mode. Driver has to make sure to clear its |
598 | * ACL list during %NL80211_CMD_STOP_AP. | 604 | * ACL list during %NL80211_CMD_STOP_AP. |
599 | * | 605 | * |
606 | * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once | ||
607 | * a radar is detected or the channel availability scan (CAC) has finished | ||
608 | * or was aborted, or a radar was detected, usermode will be notified with | ||
609 | * this event. This command is also used to notify userspace about radars | ||
610 | * while operating on this channel. | ||
611 | * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the | ||
612 | * event. | ||
613 | * | ||
600 | * @NL80211_CMD_MAX: highest used command number | 614 | * @NL80211_CMD_MAX: highest used command number |
601 | * @__NL80211_CMD_AFTER_LAST: internal use | 615 | * @__NL80211_CMD_AFTER_LAST: internal use |
602 | */ | 616 | */ |
@@ -749,6 +763,8 @@ enum nl80211_commands { | |||
749 | 763 | ||
750 | NL80211_CMD_SET_MAC_ACL, | 764 | NL80211_CMD_SET_MAC_ACL, |
751 | 765 | ||
766 | NL80211_CMD_RADAR_DETECT, | ||
767 | |||
752 | /* add new commands above here */ | 768 | /* add new commands above here */ |
753 | 769 | ||
754 | /* used to define NL80211_CMD_MAX below */ | 770 | /* used to define NL80211_CMD_MAX below */ |
@@ -1336,6 +1352,22 @@ enum nl80211_commands { | |||
1336 | * number of MAC addresses that a device can support for MAC | 1352 | * number of MAC addresses that a device can support for MAC |
1337 | * ACL. | 1353 | * ACL. |
1338 | * | 1354 | * |
1355 | * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace, | ||
1356 | * contains a value of enum nl80211_radar_event (u32). | ||
1357 | * | ||
1358 | * @NL80211_ATTR_EXT_CAPA: 802.11 extended capabilities that the kernel driver | ||
1359 | * has and handles. The format is the same as the IE contents. See | ||
1360 | * 802.11-2012 8.4.2.29 for more information. | ||
1361 | * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver | ||
1362 | * has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields. | ||
1363 | * | ||
1364 | * @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to | ||
1365 | * the driver, e.g., to enable TDLS power save (PU-APSD). | ||
1366 | * | ||
1367 | * @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are | ||
1368 | * advertised to the driver, e.g., to enable TDLS off channel operations | ||
1369 | * and PU-APSD. | ||
1370 | * | ||
1339 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1371 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1340 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1372 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1341 | */ | 1373 | */ |
@@ -1614,6 +1646,14 @@ enum nl80211_attrs { | |||
1614 | 1646 | ||
1615 | NL80211_ATTR_MAC_ACL_MAX, | 1647 | NL80211_ATTR_MAC_ACL_MAX, |
1616 | 1648 | ||
1649 | NL80211_ATTR_RADAR_EVENT, | ||
1650 | |||
1651 | NL80211_ATTR_EXT_CAPA, | ||
1652 | NL80211_ATTR_EXT_CAPA_MASK, | ||
1653 | |||
1654 | NL80211_ATTR_STA_CAPABILITY, | ||
1655 | NL80211_ATTR_STA_EXT_CAPABILITY, | ||
1656 | |||
1617 | /* add attributes here, update the policy in nl80211.c */ | 1657 | /* add attributes here, update the policy in nl80211.c */ |
1618 | 1658 | ||
1619 | __NL80211_ATTR_AFTER_LAST, | 1659 | __NL80211_ATTR_AFTER_LAST, |
@@ -1851,6 +1891,8 @@ enum nl80211_sta_bss_param { | |||
1851 | * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) | 1891 | * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) |
1852 | * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) | 1892 | * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) |
1853 | * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) | 1893 | * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) |
1894 | * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station) | ||
1895 | * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station) | ||
1854 | * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) | 1896 | * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) |
1855 | * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute | 1897 | * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute |
1856 | * containing info as possible, see &enum nl80211_rate_info | 1898 | * containing info as possible, see &enum nl80211_rate_info |
@@ -1903,6 +1945,8 @@ enum nl80211_sta_info { | |||
1903 | NL80211_STA_INFO_LOCAL_PM, | 1945 | NL80211_STA_INFO_LOCAL_PM, |
1904 | NL80211_STA_INFO_PEER_PM, | 1946 | NL80211_STA_INFO_PEER_PM, |
1905 | NL80211_STA_INFO_NONPEER_PM, | 1947 | NL80211_STA_INFO_NONPEER_PM, |
1948 | NL80211_STA_INFO_RX_BYTES64, | ||
1949 | NL80211_STA_INFO_TX_BYTES64, | ||
1906 | 1950 | ||
1907 | /* keep last */ | 1951 | /* keep last */ |
1908 | __NL80211_STA_INFO_AFTER_LAST, | 1952 | __NL80211_STA_INFO_AFTER_LAST, |
@@ -2012,6 +2056,20 @@ enum nl80211_band_attr { | |||
2012 | * on this channel in current regulatory domain. | 2056 | * on this channel in current regulatory domain. |
2013 | * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm | 2057 | * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm |
2014 | * (100 * dBm). | 2058 | * (100 * dBm). |
2059 | * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS | ||
2060 | * (enum nl80211_dfs_state) | ||
2061 | * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long | ||
2062 | * this channel is in this DFS state. | ||
2063 | * @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this | ||
2064 | * channel as the control channel | ||
2065 | * @NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: HT40+ isn't possible with this | ||
2066 | * channel as the control channel | ||
2067 | * @NL80211_FREQUENCY_ATTR_NO_80MHZ: any 80 MHz channel using this channel | ||
2068 | * as the primary or any of the secondary channels isn't possible, | ||
2069 | * this includes 80+80 channels | ||
2070 | * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel | ||
2071 | * using this channel as the primary or any of the secondary channels | ||
2072 | * isn't possible | ||
2015 | * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number | 2073 | * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number |
2016 | * currently defined | 2074 | * currently defined |
2017 | * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use | 2075 | * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use |
@@ -2024,6 +2082,12 @@ enum nl80211_frequency_attr { | |||
2024 | NL80211_FREQUENCY_ATTR_NO_IBSS, | 2082 | NL80211_FREQUENCY_ATTR_NO_IBSS, |
2025 | NL80211_FREQUENCY_ATTR_RADAR, | 2083 | NL80211_FREQUENCY_ATTR_RADAR, |
2026 | NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 2084 | NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
2085 | NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
2086 | NL80211_FREQUENCY_ATTR_DFS_TIME, | ||
2087 | NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, | ||
2088 | NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, | ||
2089 | NL80211_FREQUENCY_ATTR_NO_80MHZ, | ||
2090 | NL80211_FREQUENCY_ATTR_NO_160MHZ, | ||
2027 | 2091 | ||
2028 | /* keep last */ | 2092 | /* keep last */ |
2029 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, | 2093 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, |
@@ -2896,10 +2960,12 @@ enum nl80211_tx_power_setting { | |||
2896 | * corresponds to the lowest-order bit in the second byte of the mask. | 2960 | * corresponds to the lowest-order bit in the second byte of the mask. |
2897 | * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where | 2961 | * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where |
2898 | * xx indicates "don't care") would be represented by a pattern of | 2962 | * xx indicates "don't care") would be represented by a pattern of |
2899 | * twelve zero bytes, and a mask of "0xed,0x07". | 2963 | * twelve zero bytes, and a mask of "0xed,0x01". |
2900 | * Note that the pattern matching is done as though frames were not | 2964 | * Note that the pattern matching is done as though frames were not |
2901 | * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked | 2965 | * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked |
2902 | * first (including SNAP header unpacking) and then matched. | 2966 | * first (including SNAP header unpacking) and then matched. |
2967 | * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after | ||
2968 | * these fixed number of bytes of received packet | ||
2903 | * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes | 2969 | * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes |
2904 | * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number | 2970 | * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number |
2905 | */ | 2971 | */ |
@@ -2907,6 +2973,7 @@ enum nl80211_wowlan_packet_pattern_attr { | |||
2907 | __NL80211_WOWLAN_PKTPAT_INVALID, | 2973 | __NL80211_WOWLAN_PKTPAT_INVALID, |
2908 | NL80211_WOWLAN_PKTPAT_MASK, | 2974 | NL80211_WOWLAN_PKTPAT_MASK, |
2909 | NL80211_WOWLAN_PKTPAT_PATTERN, | 2975 | NL80211_WOWLAN_PKTPAT_PATTERN, |
2976 | NL80211_WOWLAN_PKTPAT_OFFSET, | ||
2910 | 2977 | ||
2911 | NUM_NL80211_WOWLAN_PKTPAT, | 2978 | NUM_NL80211_WOWLAN_PKTPAT, |
2912 | MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, | 2979 | MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, |
@@ -2917,6 +2984,7 @@ enum nl80211_wowlan_packet_pattern_attr { | |||
2917 | * @max_patterns: maximum number of patterns supported | 2984 | * @max_patterns: maximum number of patterns supported |
2918 | * @min_pattern_len: minimum length of each pattern | 2985 | * @min_pattern_len: minimum length of each pattern |
2919 | * @max_pattern_len: maximum length of each pattern | 2986 | * @max_pattern_len: maximum length of each pattern |
2987 | * @max_pkt_offset: maximum Rx packet offset | ||
2920 | * | 2988 | * |
2921 | * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when | 2989 | * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when |
2922 | * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the | 2990 | * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the |
@@ -2926,6 +2994,7 @@ struct nl80211_wowlan_pattern_support { | |||
2926 | __u32 max_patterns; | 2994 | __u32 max_patterns; |
2927 | __u32 min_pattern_len; | 2995 | __u32 min_pattern_len; |
2928 | __u32 max_pattern_len; | 2996 | __u32 max_pattern_len; |
2997 | __u32 max_pkt_offset; | ||
2929 | } __attribute__((packed)); | 2998 | } __attribute__((packed)); |
2930 | 2999 | ||
2931 | /** | 3000 | /** |
@@ -2941,12 +3010,17 @@ struct nl80211_wowlan_pattern_support { | |||
2941 | * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns | 3010 | * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns |
2942 | * which are passed in an array of nested attributes, each nested attribute | 3011 | * which are passed in an array of nested attributes, each nested attribute |
2943 | * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. | 3012 | * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. |
2944 | * Each pattern defines a wakeup packet. The matching is done on the MSDU, | 3013 | * Each pattern defines a wakeup packet. Packet offset is associated with |
2945 | * i.e. as though the packet was an 802.3 packet, so the pattern matching | 3014 | * each pattern which is used while matching the pattern. The matching is |
2946 | * is done after the packet is converted to the MSDU. | 3015 | * done on the MSDU, i.e. as though the packet was an 802.3 packet, so the |
3016 | * pattern matching is done after the packet is converted to the MSDU. | ||
2947 | * | 3017 | * |
2948 | * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute | 3018 | * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute |
2949 | * carrying a &struct nl80211_wowlan_pattern_support. | 3019 | * carrying a &struct nl80211_wowlan_pattern_support. |
3020 | * | ||
3021 | * When reporting wakeup. it is a u32 attribute containing the 0-based | ||
3022 | * index of the pattern that caused the wakeup, in the patterns passed | ||
3023 | * to the kernel when configuring. | ||
2950 | * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be | 3024 | * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be |
2951 | * used when setting, used only to indicate that GTK rekeying is supported | 3025 | * used when setting, used only to indicate that GTK rekeying is supported |
2952 | * by the device (flag) | 3026 | * by the device (flag) |
@@ -2957,8 +3031,36 @@ struct nl80211_wowlan_pattern_support { | |||
2957 | * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) | 3031 | * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) |
2958 | * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released | 3032 | * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released |
2959 | * (on devices that have rfkill in the device) (flag) | 3033 | * (on devices that have rfkill in the device) (flag) |
3034 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains | ||
3035 | * the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame | ||
3036 | * may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN | ||
3037 | * attribute contains the original length. | ||
3038 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11 | ||
3039 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211 | ||
3040 | * attribute if the packet was truncated somewhere. | ||
3041 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the | ||
3042 | * 802.11 packet that caused the wakeup, e.g. a magic packet. The frame may | ||
3043 | * be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute | ||
3044 | * contains the original length. | ||
3045 | * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3 | ||
3046 | * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 | ||
3047 | * attribute if the packet was truncated somewhere. | ||
3048 | * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section | ||
3049 | * "TCP connection wakeup" for more details. This is a nested attribute | ||
3050 | * containing the exact information for establishing and keeping alive | ||
3051 | * the TCP connection. | ||
3052 | * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the | ||
3053 | * wakeup packet was received on the TCP connection | ||
3054 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the | ||
3055 | * TCP connection was lost or failed to be established | ||
3056 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, | ||
3057 | * the TCP connection ran out of tokens to use for data to send to the | ||
3058 | * service | ||
2960 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers | 3059 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers |
2961 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number | 3060 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number |
3061 | * | ||
3062 | * These nested attributes are used to configure the wakeup triggers and | ||
3063 | * to report the wakeup reason(s). | ||
2962 | */ | 3064 | */ |
2963 | enum nl80211_wowlan_triggers { | 3065 | enum nl80211_wowlan_triggers { |
2964 | __NL80211_WOWLAN_TRIG_INVALID, | 3066 | __NL80211_WOWLAN_TRIG_INVALID, |
@@ -2971,6 +3073,14 @@ enum nl80211_wowlan_triggers { | |||
2971 | NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, | 3073 | NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, |
2972 | NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, | 3074 | NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, |
2973 | NL80211_WOWLAN_TRIG_RFKILL_RELEASE, | 3075 | NL80211_WOWLAN_TRIG_RFKILL_RELEASE, |
3076 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211, | ||
3077 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN, | ||
3078 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023, | ||
3079 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN, | ||
3080 | NL80211_WOWLAN_TRIG_TCP_CONNECTION, | ||
3081 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, | ||
3082 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, | ||
3083 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, | ||
2974 | 3084 | ||
2975 | /* keep last */ | 3085 | /* keep last */ |
2976 | NUM_NL80211_WOWLAN_TRIG, | 3086 | NUM_NL80211_WOWLAN_TRIG, |
@@ -2978,6 +3088,116 @@ enum nl80211_wowlan_triggers { | |||
2978 | }; | 3088 | }; |
2979 | 3089 | ||
2980 | /** | 3090 | /** |
3091 | * DOC: TCP connection wakeup | ||
3092 | * | ||
3093 | * Some devices can establish a TCP connection in order to be woken up by a | ||
3094 | * packet coming in from outside their network segment, or behind NAT. If | ||
3095 | * configured, the device will establish a TCP connection to the given | ||
3096 | * service, and periodically send data to that service. The first data | ||
3097 | * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK. | ||
3098 | * The data packets can optionally include a (little endian) sequence | ||
3099 | * number (in the TCP payload!) that is generated by the device, and, also | ||
3100 | * optionally, a token from a list of tokens. This serves as a keep-alive | ||
3101 | * with the service, and for NATed connections, etc. | ||
3102 | * | ||
3103 | * During this keep-alive period, the server doesn't send any data to the | ||
3104 | * client. When receiving data, it is compared against the wakeup pattern | ||
3105 | * (and mask) and if it matches, the host is woken up. Similarly, if the | ||
3106 | * connection breaks or cannot be established to start with, the host is | ||
3107 | * also woken up. | ||
3108 | * | ||
3109 | * Developer's note: ARP offload is required for this, otherwise TCP | ||
3110 | * response packets might not go through correctly. | ||
3111 | */ | ||
3112 | |||
3113 | /** | ||
3114 | * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence | ||
3115 | * @start: starting value | ||
3116 | * @offset: offset of sequence number in packet | ||
3117 | * @len: length of the sequence value to write, 1 through 4 | ||
3118 | * | ||
3119 | * Note: don't confuse with the TCP sequence number(s), this is for the | ||
3120 | * keepalive packet payload. The actual value is written into the packet | ||
3121 | * in little endian. | ||
3122 | */ | ||
3123 | struct nl80211_wowlan_tcp_data_seq { | ||
3124 | __u32 start, offset, len; | ||
3125 | }; | ||
3126 | |||
3127 | /** | ||
3128 | * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config | ||
3129 | * @offset: offset of token in packet | ||
3130 | * @len: length of each token | ||
3131 | * @token_stream: stream of data to be used for the tokens, the length must | ||
3132 | * be a multiple of @len for this to make sense | ||
3133 | */ | ||
3134 | struct nl80211_wowlan_tcp_data_token { | ||
3135 | __u32 offset, len; | ||
3136 | __u8 token_stream[]; | ||
3137 | }; | ||
3138 | |||
3139 | /** | ||
3140 | * struct nl80211_wowlan_tcp_data_token_feature - data token features | ||
3141 | * @min_len: minimum token length | ||
3142 | * @max_len: maximum token length | ||
3143 | * @bufsize: total available token buffer size (max size of @token_stream) | ||
3144 | */ | ||
3145 | struct nl80211_wowlan_tcp_data_token_feature { | ||
3146 | __u32 min_len, max_len, bufsize; | ||
3147 | }; | ||
3148 | |||
3149 | /** | ||
3150 | * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters | ||
3151 | * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes | ||
3152 | * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order) | ||
3153 | * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address | ||
3154 | * (in network byte order) | ||
3155 | * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because | ||
3156 | * route lookup when configured might be invalid by the time we suspend, | ||
3157 | * and doing a route lookup when suspending is no longer possible as it | ||
3158 | * might require ARP querying. | ||
3159 | * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a | ||
3160 | * socket and port will be allocated | ||
3161 | * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16) | ||
3162 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte. | ||
3163 | * For feature advertising, a u32 attribute holding the maximum length | ||
3164 | * of the data payload. | ||
3165 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration | ||
3166 | * (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature | ||
3167 | * advertising it is just a flag | ||
3168 | * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration, | ||
3169 | * see &struct nl80211_wowlan_tcp_data_token and for advertising see | ||
3170 | * &struct nl80211_wowlan_tcp_data_token_feature. | ||
3171 | * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum | ||
3172 | * interval in feature advertising (u32) | ||
3173 | * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a | ||
3174 | * u32 attribute holding the maximum length | ||
3175 | * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for | ||
3176 | * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK | ||
3177 | * but on the TCP payload only. | ||
3178 | * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes | ||
3179 | * @MAX_NL80211_WOWLAN_TCP: highest attribute number | ||
3180 | */ | ||
3181 | enum nl80211_wowlan_tcp_attrs { | ||
3182 | __NL80211_WOWLAN_TCP_INVALID, | ||
3183 | NL80211_WOWLAN_TCP_SRC_IPV4, | ||
3184 | NL80211_WOWLAN_TCP_DST_IPV4, | ||
3185 | NL80211_WOWLAN_TCP_DST_MAC, | ||
3186 | NL80211_WOWLAN_TCP_SRC_PORT, | ||
3187 | NL80211_WOWLAN_TCP_DST_PORT, | ||
3188 | NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
3189 | NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
3190 | NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
3191 | NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
3192 | NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
3193 | NL80211_WOWLAN_TCP_WAKE_MASK, | ||
3194 | |||
3195 | /* keep last */ | ||
3196 | NUM_NL80211_WOWLAN_TCP, | ||
3197 | MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1 | ||
3198 | }; | ||
3199 | |||
3200 | /** | ||
2981 | * enum nl80211_iface_limit_attrs - limit attributes | 3201 | * enum nl80211_iface_limit_attrs - limit attributes |
2982 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) | 3202 | * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) |
2983 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that | 3203 | * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that |
@@ -3234,6 +3454,8 @@ enum nl80211_ap_sme_features { | |||
3234 | * Note that even for drivers that support this, the default is to add | 3454 | * Note that even for drivers that support this, the default is to add |
3235 | * stations in authenticated/associated state, so to add unauthenticated | 3455 | * stations in authenticated/associated state, so to add unauthenticated |
3236 | * stations the authenticated/associated bits have to be set in the mask. | 3456 | * stations the authenticated/associated bits have to be set in the mask. |
3457 | * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits | ||
3458 | * (HT40, VHT 80/160 MHz) if this flag is set | ||
3237 | */ | 3459 | */ |
3238 | enum nl80211_feature_flags { | 3460 | enum nl80211_feature_flags { |
3239 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 3461 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
@@ -3249,7 +3471,9 @@ enum nl80211_feature_flags { | |||
3249 | NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, | 3471 | NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, |
3250 | NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, | 3472 | NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, |
3251 | NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, | 3473 | NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, |
3252 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 13, | 3474 | /* bit 13 is reserved */ |
3475 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, | ||
3476 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, | ||
3253 | }; | 3477 | }; |
3254 | 3478 | ||
3255 | /** | 3479 | /** |
@@ -3323,4 +3547,44 @@ enum nl80211_acl_policy { | |||
3323 | NL80211_ACL_POLICY_DENY_UNLESS_LISTED, | 3547 | NL80211_ACL_POLICY_DENY_UNLESS_LISTED, |
3324 | }; | 3548 | }; |
3325 | 3549 | ||
3550 | /** | ||
3551 | * enum nl80211_radar_event - type of radar event for DFS operation | ||
3552 | * | ||
3553 | * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace | ||
3554 | * about detected radars or success of the channel available check (CAC) | ||
3555 | * | ||
3556 | * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is | ||
3557 | * now unusable. | ||
3558 | * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished, | ||
3559 | * the channel is now available. | ||
3560 | * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no | ||
3561 | * change to the channel status. | ||
3562 | * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is | ||
3563 | * over, channel becomes usable. | ||
3564 | */ | ||
3565 | enum nl80211_radar_event { | ||
3566 | NL80211_RADAR_DETECTED, | ||
3567 | NL80211_RADAR_CAC_FINISHED, | ||
3568 | NL80211_RADAR_CAC_ABORTED, | ||
3569 | NL80211_RADAR_NOP_FINISHED, | ||
3570 | }; | ||
3571 | |||
3572 | /** | ||
3573 | * enum nl80211_dfs_state - DFS states for channels | ||
3574 | * | ||
3575 | * Channel states used by the DFS code. | ||
3576 | * | ||
3577 | * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability | ||
3578 | * check (CAC) must be performed before using it for AP or IBSS. | ||
3579 | * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it | ||
3580 | * is therefore marked as not available. | ||
3581 | * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available. | ||
3582 | */ | ||
3583 | |||
3584 | enum nl80211_dfs_state { | ||
3585 | NL80211_DFS_USABLE, | ||
3586 | NL80211_DFS_UNAVAILABLE, | ||
3587 | NL80211_DFS_AVAILABLE, | ||
3588 | }; | ||
3589 | |||
3326 | #endif /* __LINUX_NL80211_H */ | 3590 | #endif /* __LINUX_NL80211_H */ |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index b4ecf267a34b..0ecf947ad378 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -258,6 +258,17 @@ config MAC80211_MESH_SYNC_DEBUG | |||
258 | 258 | ||
259 | Do not select this option. | 259 | Do not select this option. |
260 | 260 | ||
261 | config MAC80211_MESH_PS_DEBUG | ||
262 | bool "Verbose mesh powersave debugging" | ||
263 | depends on MAC80211_DEBUG_MENU | ||
264 | depends on MAC80211_MESH | ||
265 | ---help--- | ||
266 | Selecting this option causes mac80211 to print out very verbose mesh | ||
267 | powersave debugging messages (when mac80211 is taking part in a | ||
268 | mesh network). | ||
269 | |||
270 | Do not select this option. | ||
271 | |||
261 | config MAC80211_TDLS_DEBUG | 272 | config MAC80211_TDLS_DEBUG |
262 | bool "Verbose TDLS debugging" | 273 | bool "Verbose TDLS debugging" |
263 | depends on MAC80211_DEBUG_MENU | 274 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4911202334d9..9d7d840aac6d 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -39,7 +39,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ | |||
39 | mesh_pathtbl.o \ | 39 | mesh_pathtbl.o \ |
40 | mesh_plink.o \ | 40 | mesh_plink.o \ |
41 | mesh_hwmp.o \ | 41 | mesh_hwmp.o \ |
42 | mesh_sync.o | 42 | mesh_sync.o \ |
43 | mesh_ps.o | ||
43 | 44 | ||
44 | mac80211-$(CONFIG_PM) += pm.o | 45 | mac80211-$(CONFIG_PM) += pm.o |
45 | 46 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 15d886c639e9..179dcbd8be1c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -492,7 +492,10 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
492 | #ifdef CONFIG_MAC80211_MESH | 492 | #ifdef CONFIG_MAC80211_MESH |
493 | sinfo->filled |= STATION_INFO_LLID | | 493 | sinfo->filled |= STATION_INFO_LLID | |
494 | STATION_INFO_PLID | | 494 | STATION_INFO_PLID | |
495 | STATION_INFO_PLINK_STATE; | 495 | STATION_INFO_PLINK_STATE | |
496 | STATION_INFO_LOCAL_PM | | ||
497 | STATION_INFO_PEER_PM | | ||
498 | STATION_INFO_NONPEER_PM; | ||
496 | 499 | ||
497 | sinfo->llid = le16_to_cpu(sta->llid); | 500 | sinfo->llid = le16_to_cpu(sta->llid); |
498 | sinfo->plid = le16_to_cpu(sta->plid); | 501 | sinfo->plid = le16_to_cpu(sta->plid); |
@@ -501,6 +504,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
501 | sinfo->filled |= STATION_INFO_T_OFFSET; | 504 | sinfo->filled |= STATION_INFO_T_OFFSET; |
502 | sinfo->t_offset = sta->t_offset; | 505 | sinfo->t_offset = sta->t_offset; |
503 | } | 506 | } |
507 | sinfo->local_pm = sta->local_pm; | ||
508 | sinfo->peer_pm = sta->peer_pm; | ||
509 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
504 | #endif | 510 | #endif |
505 | } | 511 | } |
506 | 512 | ||
@@ -922,11 +928,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
922 | /* TODO: make hostapd tell us what it wants */ | 928 | /* TODO: make hostapd tell us what it wants */ |
923 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 929 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
924 | sdata->needed_rx_chains = sdata->local->rx_chains; | 930 | sdata->needed_rx_chains = sdata->local->rx_chains; |
931 | sdata->radar_required = params->radar_required; | ||
925 | 932 | ||
926 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, | 933 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, |
927 | IEEE80211_CHANCTX_SHARED); | 934 | IEEE80211_CHANCTX_SHARED); |
928 | if (err) | 935 | if (err) |
929 | return err; | 936 | return err; |
937 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
930 | 938 | ||
931 | /* | 939 | /* |
932 | * Apply control port protocol, this allows us to | 940 | * Apply control port protocol, this allows us to |
@@ -1041,6 +1049,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1041 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | 1049 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); |
1042 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | 1050 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); |
1043 | 1051 | ||
1052 | ieee80211_vif_copy_chanctx_to_vlans(sdata, true); | ||
1044 | ieee80211_vif_release_channel(sdata); | 1053 | ieee80211_vif_release_channel(sdata); |
1045 | 1054 | ||
1046 | return 0; | 1055 | return 0; |
@@ -1243,25 +1252,26 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1243 | 1252 | ||
1244 | if (params->ht_capa) | 1253 | if (params->ht_capa) |
1245 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 1254 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1246 | params->ht_capa, | 1255 | params->ht_capa, sta); |
1247 | &sta->sta.ht_cap); | ||
1248 | 1256 | ||
1249 | if (params->vht_capa) | 1257 | if (params->vht_capa) |
1250 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1258 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
1251 | params->vht_capa, | 1259 | params->vht_capa, sta); |
1252 | &sta->sta.vht_cap); | ||
1253 | 1260 | ||
1254 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1261 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
1255 | #ifdef CONFIG_MAC80211_MESH | 1262 | #ifdef CONFIG_MAC80211_MESH |
1263 | u32 changed = 0; | ||
1256 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) { | 1264 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) { |
1257 | u32 changed = 0; | ||
1258 | |||
1259 | switch (params->plink_state) { | 1265 | switch (params->plink_state) { |
1260 | case NL80211_PLINK_ESTAB: | 1266 | case NL80211_PLINK_ESTAB: |
1261 | if (sta->plink_state != NL80211_PLINK_ESTAB) | 1267 | if (sta->plink_state != NL80211_PLINK_ESTAB) |
1262 | changed = mesh_plink_inc_estab_count( | 1268 | changed = mesh_plink_inc_estab_count( |
1263 | sdata); | 1269 | sdata); |
1264 | sta->plink_state = params->plink_state; | 1270 | sta->plink_state = params->plink_state; |
1271 | |||
1272 | ieee80211_mps_sta_status_update(sta); | ||
1273 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
1274 | sdata->u.mesh.mshcfg.power_mode); | ||
1265 | break; | 1275 | break; |
1266 | case NL80211_PLINK_LISTEN: | 1276 | case NL80211_PLINK_LISTEN: |
1267 | case NL80211_PLINK_BLOCKED: | 1277 | case NL80211_PLINK_BLOCKED: |
@@ -1273,22 +1283,31 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1273 | changed = mesh_plink_dec_estab_count( | 1283 | changed = mesh_plink_dec_estab_count( |
1274 | sdata); | 1284 | sdata); |
1275 | sta->plink_state = params->plink_state; | 1285 | sta->plink_state = params->plink_state; |
1286 | |||
1287 | ieee80211_mps_sta_status_update(sta); | ||
1288 | changed |= | ||
1289 | ieee80211_mps_local_status_update(sdata); | ||
1276 | break; | 1290 | break; |
1277 | default: | 1291 | default: |
1278 | /* nothing */ | 1292 | /* nothing */ |
1279 | break; | 1293 | break; |
1280 | } | 1294 | } |
1281 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1282 | } else { | 1295 | } else { |
1283 | switch (params->plink_action) { | 1296 | switch (params->plink_action) { |
1284 | case PLINK_ACTION_OPEN: | 1297 | case PLINK_ACTION_OPEN: |
1285 | mesh_plink_open(sta); | 1298 | changed |= mesh_plink_open(sta); |
1286 | break; | 1299 | break; |
1287 | case PLINK_ACTION_BLOCK: | 1300 | case PLINK_ACTION_BLOCK: |
1288 | mesh_plink_block(sta); | 1301 | changed |= mesh_plink_block(sta); |
1289 | break; | 1302 | break; |
1290 | } | 1303 | } |
1291 | } | 1304 | } |
1305 | |||
1306 | if (params->local_pm) | ||
1307 | changed |= | ||
1308 | ieee80211_mps_set_sta_local_pm(sta, | ||
1309 | params->local_pm); | ||
1310 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1292 | #endif | 1311 | #endif |
1293 | } | 1312 | } |
1294 | 1313 | ||
@@ -1393,9 +1412,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1393 | return -ENOENT; | 1412 | return -ENOENT; |
1394 | } | 1413 | } |
1395 | 1414 | ||
1396 | /* in station mode, supported rates are only valid with TDLS */ | 1415 | /* in station mode, some updates are only valid with TDLS */ |
1397 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1416 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
1398 | params->supported_rates && | 1417 | (params->supported_rates || params->ht_capa || params->vht_capa || |
1418 | params->sta_modify_mask || | ||
1419 | (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) && | ||
1399 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | 1420 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
1400 | mutex_unlock(&local->sta_mtx); | 1421 | mutex_unlock(&local->sta_mtx); |
1401 | return -EINVAL; | 1422 | return -EINVAL; |
@@ -1777,6 +1798,14 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1777 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) | 1798 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) |
1778 | conf->dot11MeshHWMPconfirmationInterval = | 1799 | conf->dot11MeshHWMPconfirmationInterval = |
1779 | nconf->dot11MeshHWMPconfirmationInterval; | 1800 | nconf->dot11MeshHWMPconfirmationInterval; |
1801 | if (_chg_mesh_attr(NL80211_MESHCONF_POWER_MODE, mask)) { | ||
1802 | conf->power_mode = nconf->power_mode; | ||
1803 | ieee80211_mps_local_status_update(sdata); | ||
1804 | } | ||
1805 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) | ||
1806 | conf->dot11MeshAwakeWindowDuration = | ||
1807 | nconf->dot11MeshAwakeWindowDuration; | ||
1808 | ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
1780 | return 0; | 1809 | return 0; |
1781 | } | 1810 | } |
1782 | 1811 | ||
@@ -1802,9 +1831,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
1802 | if (err) | 1831 | if (err) |
1803 | return err; | 1832 | return err; |
1804 | 1833 | ||
1805 | ieee80211_start_mesh(sdata); | 1834 | return ieee80211_start_mesh(sdata); |
1806 | |||
1807 | return 0; | ||
1808 | } | 1835 | } |
1809 | 1836 | ||
1810 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | 1837 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) |
@@ -2369,7 +2396,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2369 | INIT_LIST_HEAD(&roc->dependents); | 2396 | INIT_LIST_HEAD(&roc->dependents); |
2370 | 2397 | ||
2371 | /* if there's one pending or we're scanning, queue this one */ | 2398 | /* if there's one pending or we're scanning, queue this one */ |
2372 | if (!list_empty(&local->roc_list) || local->scanning) | 2399 | if (!list_empty(&local->roc_list) || |
2400 | local->scanning || local->radar_detect_enabled) | ||
2373 | goto out_check_combine; | 2401 | goto out_check_combine; |
2374 | 2402 | ||
2375 | /* if not HW assist, just queue & schedule work */ | 2403 | /* if not HW assist, just queue & schedule work */ |
@@ -2619,6 +2647,37 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
2619 | return ieee80211_cancel_roc(local, cookie, false); | 2647 | return ieee80211_cancel_roc(local, cookie, false); |
2620 | } | 2648 | } |
2621 | 2649 | ||
2650 | static int ieee80211_start_radar_detection(struct wiphy *wiphy, | ||
2651 | struct net_device *dev, | ||
2652 | struct cfg80211_chan_def *chandef) | ||
2653 | { | ||
2654 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2655 | struct ieee80211_local *local = sdata->local; | ||
2656 | unsigned long timeout; | ||
2657 | int err; | ||
2658 | |||
2659 | if (!list_empty(&local->roc_list) || local->scanning) | ||
2660 | return -EBUSY; | ||
2661 | |||
2662 | /* whatever, but channel contexts should not complain about that one */ | ||
2663 | sdata->smps_mode = IEEE80211_SMPS_OFF; | ||
2664 | sdata->needed_rx_chains = local->rx_chains; | ||
2665 | sdata->radar_required = true; | ||
2666 | |||
2667 | mutex_lock(&local->iflist_mtx); | ||
2668 | err = ieee80211_vif_use_channel(sdata, chandef, | ||
2669 | IEEE80211_CHANCTX_SHARED); | ||
2670 | mutex_unlock(&local->iflist_mtx); | ||
2671 | if (err) | ||
2672 | return err; | ||
2673 | |||
2674 | timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | ||
2675 | ieee80211_queue_delayed_work(&sdata->local->hw, | ||
2676 | &sdata->dfs_cac_timer_work, timeout); | ||
2677 | |||
2678 | return 0; | ||
2679 | } | ||
2680 | |||
2622 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 2681 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
2623 | struct ieee80211_channel *chan, bool offchan, | 2682 | struct ieee80211_channel *chan, bool offchan, |
2624 | unsigned int wait, const u8 *buf, size_t len, | 2683 | unsigned int wait, const u8 *buf, size_t len, |
@@ -2723,7 +2782,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
2723 | goto out_unlock; | 2782 | goto out_unlock; |
2724 | } | 2783 | } |
2725 | 2784 | ||
2726 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | 2785 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN | |
2786 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | ||
2727 | if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) | 2787 | if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) |
2728 | IEEE80211_SKB_CB(skb)->hw_queue = | 2788 | IEEE80211_SKB_CB(skb)->hw_queue = |
2729 | local->hw.offchannel_tx_hw_queue; | 2789 | local->hw.offchannel_tx_hw_queue; |
@@ -3323,4 +3383,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
3323 | .get_et_stats = ieee80211_get_et_stats, | 3383 | .get_et_stats = ieee80211_get_et_stats, |
3324 | .get_et_strings = ieee80211_get_et_strings, | 3384 | .get_et_strings = ieee80211_get_et_strings, |
3325 | .get_channel = ieee80211_cfg_get_channel, | 3385 | .get_channel = ieee80211_cfg_get_channel, |
3386 | .start_radar_detection = ieee80211_start_radar_detection, | ||
3326 | }; | 3387 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 1bfe0a8b19d2..78c0d90dd641 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -9,7 +9,7 @@ | |||
9 | #include "ieee80211_i.h" | 9 | #include "ieee80211_i.h" |
10 | #include "driver-ops.h" | 10 | #include "driver-ops.h" |
11 | 11 | ||
12 | static void ieee80211_change_chandef(struct ieee80211_local *local, | 12 | static void ieee80211_change_chanctx(struct ieee80211_local *local, |
13 | struct ieee80211_chanctx *ctx, | 13 | struct ieee80211_chanctx *ctx, |
14 | const struct cfg80211_chan_def *chandef) | 14 | const struct cfg80211_chan_def *chandef) |
15 | { | 15 | { |
@@ -49,7 +49,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
49 | if (!compat) | 49 | if (!compat) |
50 | continue; | 50 | continue; |
51 | 51 | ||
52 | ieee80211_change_chandef(local, ctx, compat); | 52 | ieee80211_change_chanctx(local, ctx, compat); |
53 | 53 | ||
54 | return ctx; | 54 | return ctx; |
55 | } | 55 | } |
@@ -91,6 +91,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
91 | 91 | ||
92 | list_add_rcu(&ctx->list, &local->chanctx_list); | 92 | list_add_rcu(&ctx->list, &local->chanctx_list); |
93 | 93 | ||
94 | mutex_lock(&local->mtx); | ||
95 | ieee80211_recalc_idle(local); | ||
96 | mutex_unlock(&local->mtx); | ||
97 | |||
94 | return ctx; | 98 | return ctx; |
95 | } | 99 | } |
96 | 100 | ||
@@ -110,6 +114,10 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
110 | 114 | ||
111 | list_del_rcu(&ctx->list); | 115 | list_del_rcu(&ctx->list); |
112 | kfree_rcu(ctx, rcu_head); | 116 | kfree_rcu(ctx, rcu_head); |
117 | |||
118 | mutex_lock(&local->mtx); | ||
119 | ieee80211_recalc_idle(local); | ||
120 | mutex_unlock(&local->mtx); | ||
113 | } | 121 | } |
114 | 122 | ||
115 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 123 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
@@ -128,6 +136,11 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
128 | ctx->refcount++; | 136 | ctx->refcount++; |
129 | 137 | ||
130 | ieee80211_recalc_txpower(sdata); | 138 | ieee80211_recalc_txpower(sdata); |
139 | sdata->vif.bss_conf.idle = false; | ||
140 | |||
141 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | ||
142 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
143 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
131 | 144 | ||
132 | return 0; | 145 | return 0; |
133 | } | 146 | } |
@@ -162,7 +175,7 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | |||
162 | if (WARN_ON_ONCE(!compat)) | 175 | if (WARN_ON_ONCE(!compat)) |
163 | return; | 176 | return; |
164 | 177 | ||
165 | ieee80211_change_chandef(local, ctx, compat); | 178 | ieee80211_change_chanctx(local, ctx, compat); |
166 | } | 179 | } |
167 | 180 | ||
168 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 181 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
@@ -175,11 +188,18 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
175 | ctx->refcount--; | 188 | ctx->refcount--; |
176 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | 189 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); |
177 | 190 | ||
191 | sdata->vif.bss_conf.idle = true; | ||
192 | |||
193 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | ||
194 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
195 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
196 | |||
178 | drv_unassign_vif_chanctx(local, sdata, ctx); | 197 | drv_unassign_vif_chanctx(local, sdata, ctx); |
179 | 198 | ||
180 | if (ctx->refcount > 0) { | 199 | if (ctx->refcount > 0) { |
181 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | 200 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); |
182 | ieee80211_recalc_smps_chanctx(local, ctx); | 201 | ieee80211_recalc_smps_chanctx(local, ctx); |
202 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
183 | } | 203 | } |
184 | } | 204 | } |
185 | 205 | ||
@@ -198,20 +218,42 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
198 | 218 | ||
199 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 219 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
200 | 220 | ||
201 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
202 | struct ieee80211_sub_if_data *vlan; | ||
203 | |||
204 | /* for the VLAN list */ | ||
205 | ASSERT_RTNL(); | ||
206 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
207 | rcu_assign_pointer(vlan->vif.chanctx_conf, NULL); | ||
208 | } | ||
209 | |||
210 | ieee80211_unassign_vif_chanctx(sdata, ctx); | 221 | ieee80211_unassign_vif_chanctx(sdata, ctx); |
211 | if (ctx->refcount == 0) | 222 | if (ctx->refcount == 0) |
212 | ieee80211_free_chanctx(local, ctx); | 223 | ieee80211_free_chanctx(local, ctx); |
213 | } | 224 | } |
214 | 225 | ||
226 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | ||
227 | struct ieee80211_chanctx *chanctx) | ||
228 | { | ||
229 | struct ieee80211_sub_if_data *sdata; | ||
230 | bool radar_enabled = false; | ||
231 | |||
232 | lockdep_assert_held(&local->chanctx_mtx); | ||
233 | |||
234 | rcu_read_lock(); | ||
235 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
236 | if (sdata->radar_required) { | ||
237 | radar_enabled = true; | ||
238 | break; | ||
239 | } | ||
240 | } | ||
241 | rcu_read_unlock(); | ||
242 | |||
243 | if (radar_enabled == chanctx->conf.radar_enabled) | ||
244 | return; | ||
245 | |||
246 | chanctx->conf.radar_enabled = radar_enabled; | ||
247 | local->radar_detect_enabled = chanctx->conf.radar_enabled; | ||
248 | |||
249 | if (!local->use_chanctx) { | ||
250 | local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; | ||
251 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
252 | } | ||
253 | |||
254 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); | ||
255 | } | ||
256 | |||
215 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 257 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
216 | struct ieee80211_chanctx *chanctx) | 258 | struct ieee80211_chanctx *chanctx) |
217 | { | 259 | { |
@@ -326,16 +368,57 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
326 | goto out; | 368 | goto out; |
327 | } | 369 | } |
328 | 370 | ||
329 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 371 | ieee80211_recalc_smps_chanctx(local, ctx); |
330 | struct ieee80211_sub_if_data *vlan; | 372 | ieee80211_recalc_radar_chanctx(local, ctx); |
373 | out: | ||
374 | mutex_unlock(&local->chanctx_mtx); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | ||
379 | const struct cfg80211_chan_def *chandef, | ||
380 | u32 *changed) | ||
381 | { | ||
382 | struct ieee80211_local *local = sdata->local; | ||
383 | struct ieee80211_chanctx_conf *conf; | ||
384 | struct ieee80211_chanctx *ctx; | ||
385 | int ret; | ||
386 | |||
387 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
388 | IEEE80211_CHAN_DISABLED)) | ||
389 | return -EINVAL; | ||
390 | |||
391 | mutex_lock(&local->chanctx_mtx); | ||
392 | if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) { | ||
393 | ret = 0; | ||
394 | goto out; | ||
395 | } | ||
396 | |||
397 | if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT || | ||
398 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) { | ||
399 | ret = -EINVAL; | ||
400 | goto out; | ||
401 | } | ||
331 | 402 | ||
332 | /* for the VLAN list */ | 403 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
333 | ASSERT_RTNL(); | 404 | lockdep_is_held(&local->chanctx_mtx)); |
334 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 405 | if (!conf) { |
335 | rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf); | 406 | ret = -EINVAL; |
407 | goto out; | ||
336 | } | 408 | } |
337 | 409 | ||
338 | ieee80211_recalc_smps_chanctx(local, ctx); | 410 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
411 | if (!cfg80211_chandef_compatible(&conf->def, chandef)) { | ||
412 | ret = -EINVAL; | ||
413 | goto out; | ||
414 | } | ||
415 | |||
416 | sdata->vif.bss_conf.chandef = *chandef; | ||
417 | |||
418 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
419 | |||
420 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
421 | ret = 0; | ||
339 | out: | 422 | out: |
340 | mutex_unlock(&local->chanctx_mtx); | 423 | mutex_unlock(&local->chanctx_mtx); |
341 | return ret; | 424 | return ret; |
@@ -369,6 +452,40 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) | |||
369 | mutex_unlock(&local->chanctx_mtx); | 452 | mutex_unlock(&local->chanctx_mtx); |
370 | } | 453 | } |
371 | 454 | ||
455 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
456 | bool clear) | ||
457 | { | ||
458 | struct ieee80211_local *local = sdata->local; | ||
459 | struct ieee80211_sub_if_data *vlan; | ||
460 | struct ieee80211_chanctx_conf *conf; | ||
461 | |||
462 | ASSERT_RTNL(); | ||
463 | |||
464 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
465 | return; | ||
466 | |||
467 | mutex_lock(&local->chanctx_mtx); | ||
468 | |||
469 | /* | ||
470 | * Check that conf exists, even when clearing this function | ||
471 | * must be called with the AP's channel context still there | ||
472 | * as it would otherwise cause VLANs to have an invalid | ||
473 | * channel context pointer for a while, possibly pointing | ||
474 | * to a channel context that has already been freed. | ||
475 | */ | ||
476 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
477 | lockdep_is_held(&local->chanctx_mtx)); | ||
478 | WARN_ON(!conf); | ||
479 | |||
480 | if (clear) | ||
481 | conf = NULL; | ||
482 | |||
483 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
484 | rcu_assign_pointer(vlan->vif.chanctx_conf, conf); | ||
485 | |||
486 | mutex_unlock(&local->chanctx_mtx); | ||
487 | } | ||
488 | |||
372 | void ieee80211_iter_chan_contexts_atomic( | 489 | void ieee80211_iter_chan_contexts_atomic( |
373 | struct ieee80211_hw *hw, | 490 | struct ieee80211_hw *hw, |
374 | void (*iter)(struct ieee80211_hw *hw, | 491 | void (*iter)(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index 8f383a576016..4ccc5ed6237d 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h | |||
@@ -44,6 +44,12 @@ | |||
44 | #define MAC80211_MESH_SYNC_DEBUG 0 | 44 | #define MAC80211_MESH_SYNC_DEBUG 0 |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #ifdef CONFIG_MAC80211_MESH_PS_DEBUG | ||
48 | #define MAC80211_MESH_PS_DEBUG 1 | ||
49 | #else | ||
50 | #define MAC80211_MESH_PS_DEBUG 0 | ||
51 | #endif | ||
52 | |||
47 | #ifdef CONFIG_MAC80211_TDLS_DEBUG | 53 | #ifdef CONFIG_MAC80211_TDLS_DEBUG |
48 | #define MAC80211_TDLS_DEBUG 1 | 54 | #define MAC80211_TDLS_DEBUG 1 |
49 | #else | 55 | #else |
@@ -151,6 +157,10 @@ do { \ | |||
151 | _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \ | 157 | _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \ |
152 | sdata, fmt, ##__VA_ARGS__) | 158 | sdata, fmt, ##__VA_ARGS__) |
153 | 159 | ||
160 | #define mps_dbg(sdata, fmt, ...) \ | ||
161 | _sdata_dbg(MAC80211_MESH_PS_DEBUG, \ | ||
162 | sdata, fmt, ##__VA_ARGS__) | ||
163 | |||
154 | #define tdls_dbg(sdata, fmt, ...) \ | 164 | #define tdls_dbg(sdata, fmt, ...) \ |
155 | _sdata_dbg(MAC80211_TDLS_DEBUG, \ | 165 | _sdata_dbg(MAC80211_TDLS_DEBUG, \ |
156 | sdata, fmt, ##__VA_ARGS__) | 166 | sdata, fmt, ##__VA_ARGS__) |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 466f4b45dd94..b0e32d628114 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -121,8 +121,8 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, | |||
121 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); | 121 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); |
122 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 122 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
123 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); | 123 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); |
124 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | 124 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC) |
125 | sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n"); | 125 | sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n"); |
126 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) | 126 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) |
127 | sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); | 127 | sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); |
128 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | 128 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) |
@@ -151,8 +151,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, | |||
151 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); | 151 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); |
152 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) | 152 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) |
153 | sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); | 153 | sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); |
154 | if (local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE) | ||
155 | sf += snprintf(buf + sf, mxln - sf, "SCAN_WHILE_IDLE\n"); | ||
156 | 154 | ||
157 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | 155 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
158 | kfree(buf); | 156 | kfree(buf); |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index cbde5cc49a40..059bbb82e84f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -515,6 +515,9 @@ IEEE80211_IF_FILE(dot11MeshHWMProotInterval, | |||
515 | u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC); | 515 | u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC); |
516 | IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval, | 516 | IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval, |
517 | u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC); | 517 | u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC); |
518 | IEEE80211_IF_FILE(power_mode, u.mesh.mshcfg.power_mode, DEC); | ||
519 | IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration, | ||
520 | u.mesh.mshcfg.dot11MeshAwakeWindowDuration, DEC); | ||
518 | #endif | 521 | #endif |
519 | 522 | ||
520 | #define DEBUGFS_ADD_MODE(name, mode) \ | 523 | #define DEBUGFS_ADD_MODE(name, mode) \ |
@@ -620,6 +623,8 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) | |||
620 | MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout); | 623 | MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout); |
621 | MESHPARAMS_ADD(dot11MeshHWMProotInterval); | 624 | MESHPARAMS_ADD(dot11MeshHWMProotInterval); |
622 | MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval); | 625 | MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval); |
626 | MESHPARAMS_ADD(power_mode); | ||
627 | MESHPARAMS_ADD(dot11MeshAwakeWindowDuration); | ||
623 | #undef MESHPARAMS_ADD | 628 | #undef MESHPARAMS_ADD |
624 | } | 629 | } |
625 | #endif | 630 | #endif |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6fb1168b9f16..c7591f73dbc3 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -65,7 +65,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
65 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 65 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
66 | 66 | ||
67 | int res = scnprintf(buf, sizeof(buf), | 67 | int res = scnprintf(buf, sizeof(buf), |
68 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 68 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
69 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 69 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
70 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 70 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
71 | TEST(SHORT_PREAMBLE), | 71 | TEST(SHORT_PREAMBLE), |
@@ -74,7 +74,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
74 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 74 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
75 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 75 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), |
76 | TEST(INSERTED), TEST(RATE_CONTROL), | 76 | TEST(INSERTED), TEST(RATE_CONTROL), |
77 | TEST(TOFFSET_KNOWN)); | 77 | TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER), |
78 | TEST(MPSP_RECIPIENT)); | ||
78 | #undef TEST | 79 | #undef TEST |
79 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 80 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
80 | } | 81 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 434b3c4f31b5..ee56d0779d8b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -207,13 +207,16 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
207 | { | 207 | { |
208 | might_sleep(); | 208 | might_sleep(); |
209 | 209 | ||
210 | WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | | 210 | if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | |
211 | BSS_CHANGED_BEACON_ENABLED) && | 211 | BSS_CHANGED_BEACON_ENABLED) && |
212 | sdata->vif.type != NL80211_IFTYPE_AP && | 212 | sdata->vif.type != NL80211_IFTYPE_AP && |
213 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 213 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
214 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT); | 214 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) |
215 | WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE && | 215 | return; |
216 | changed & ~BSS_CHANGED_IDLE); | 216 | |
217 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | ||
218 | sdata->vif.type == NL80211_IFTYPE_MONITOR)) | ||
219 | return; | ||
217 | 220 | ||
218 | check_sdata_in_driver(sdata); | 221 | check_sdata_in_driver(sdata); |
219 | 222 | ||
@@ -528,6 +531,43 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, | |||
528 | local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, | 531 | local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, |
529 | sta, dir); | 532 | sta, dir); |
530 | } | 533 | } |
534 | |||
535 | static inline | ||
536 | void drv_add_interface_debugfs(struct ieee80211_local *local, | ||
537 | struct ieee80211_sub_if_data *sdata) | ||
538 | { | ||
539 | might_sleep(); | ||
540 | |||
541 | check_sdata_in_driver(sdata); | ||
542 | |||
543 | if (!local->ops->add_interface_debugfs) | ||
544 | return; | ||
545 | |||
546 | local->ops->add_interface_debugfs(&local->hw, &sdata->vif, | ||
547 | sdata->debugfs.dir); | ||
548 | } | ||
549 | |||
550 | static inline | ||
551 | void drv_remove_interface_debugfs(struct ieee80211_local *local, | ||
552 | struct ieee80211_sub_if_data *sdata) | ||
553 | { | ||
554 | might_sleep(); | ||
555 | |||
556 | check_sdata_in_driver(sdata); | ||
557 | |||
558 | if (!local->ops->remove_interface_debugfs) | ||
559 | return; | ||
560 | |||
561 | local->ops->remove_interface_debugfs(&local->hw, &sdata->vif, | ||
562 | sdata->debugfs.dir); | ||
563 | } | ||
564 | #else | ||
565 | static inline | ||
566 | void drv_add_interface_debugfs(struct ieee80211_local *local, | ||
567 | struct ieee80211_sub_if_data *sdata) {} | ||
568 | static inline | ||
569 | void drv_remove_interface_debugfs(struct ieee80211_local *local, | ||
570 | struct ieee80211_sub_if_data *sdata) {} | ||
531 | #endif | 571 | #endif |
532 | 572 | ||
533 | static inline __must_check | 573 | static inline __must_check |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 61ac7c48ac0c..0db25d4bb223 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -37,6 +37,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); | 37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); |
38 | int i; | 38 | int i; |
39 | 39 | ||
40 | if (!ht_cap->ht_supported) | ||
41 | return; | ||
42 | |||
40 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | 43 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { |
41 | /* AP interfaces call this code when adding new stations, | 44 | /* AP interfaces call this code when adding new stations, |
42 | * so just silently ignore non station interfaces. | 45 | * so just silently ignore non station interfaces. |
@@ -89,22 +92,24 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
89 | } | 92 | } |
90 | 93 | ||
91 | 94 | ||
92 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 95 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
93 | struct ieee80211_supported_band *sband, | 96 | struct ieee80211_supported_band *sband, |
94 | struct ieee80211_ht_cap *ht_cap_ie, | 97 | const struct ieee80211_ht_cap *ht_cap_ie, |
95 | struct ieee80211_sta_ht_cap *ht_cap) | 98 | struct sta_info *sta) |
96 | { | 99 | { |
100 | struct ieee80211_sta_ht_cap ht_cap; | ||
97 | u8 ampdu_info, tx_mcs_set_cap; | 101 | u8 ampdu_info, tx_mcs_set_cap; |
98 | int i, max_tx_streams; | 102 | int i, max_tx_streams; |
103 | bool changed; | ||
104 | enum ieee80211_sta_rx_bandwidth bw; | ||
105 | enum ieee80211_smps_mode smps_mode; | ||
99 | 106 | ||
100 | BUG_ON(!ht_cap); | 107 | memset(&ht_cap, 0, sizeof(ht_cap)); |
101 | |||
102 | memset(ht_cap, 0, sizeof(*ht_cap)); | ||
103 | 108 | ||
104 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) | 109 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) |
105 | return; | 110 | goto apply; |
106 | 111 | ||
107 | ht_cap->ht_supported = true; | 112 | ht_cap.ht_supported = true; |
108 | 113 | ||
109 | /* | 114 | /* |
110 | * The bits listed in this expression should be | 115 | * The bits listed in this expression should be |
@@ -112,7 +117,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
112 | * advertises more then we can't use those thus | 117 | * advertises more then we can't use those thus |
113 | * we mask them out. | 118 | * we mask them out. |
114 | */ | 119 | */ |
115 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & | 120 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & |
116 | (sband->ht_cap.cap | | 121 | (sband->ht_cap.cap | |
117 | ~(IEEE80211_HT_CAP_LDPC_CODING | | 122 | ~(IEEE80211_HT_CAP_LDPC_CODING | |
118 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 123 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
@@ -121,44 +126,30 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
121 | IEEE80211_HT_CAP_SGI_40 | | 126 | IEEE80211_HT_CAP_SGI_40 | |
122 | IEEE80211_HT_CAP_DSSSCCK40)); | 127 | IEEE80211_HT_CAP_DSSSCCK40)); |
123 | 128 | ||
124 | /* Unset 40 MHz if we're not using a 40 MHz channel */ | ||
125 | switch (sdata->vif.bss_conf.chandef.width) { | ||
126 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
127 | case NL80211_CHAN_WIDTH_20: | ||
128 | ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
129 | ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
130 | break; | ||
131 | case NL80211_CHAN_WIDTH_40: | ||
132 | case NL80211_CHAN_WIDTH_80: | ||
133 | case NL80211_CHAN_WIDTH_80P80: | ||
134 | case NL80211_CHAN_WIDTH_160: | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | /* | 129 | /* |
139 | * The STBC bits are asymmetric -- if we don't have | 130 | * The STBC bits are asymmetric -- if we don't have |
140 | * TX then mask out the peer's RX and vice versa. | 131 | * TX then mask out the peer's RX and vice versa. |
141 | */ | 132 | */ |
142 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) | 133 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) |
143 | ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; | 134 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; |
144 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) | 135 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) |
145 | ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; | 136 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; |
146 | 137 | ||
147 | ampdu_info = ht_cap_ie->ampdu_params_info; | 138 | ampdu_info = ht_cap_ie->ampdu_params_info; |
148 | ht_cap->ampdu_factor = | 139 | ht_cap.ampdu_factor = |
149 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; | 140 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; |
150 | ht_cap->ampdu_density = | 141 | ht_cap.ampdu_density = |
151 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | 142 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
152 | 143 | ||
153 | /* own MCS TX capabilities */ | 144 | /* own MCS TX capabilities */ |
154 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 145 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; |
155 | 146 | ||
156 | /* Copy peer MCS TX capabilities, the driver might need them. */ | 147 | /* Copy peer MCS TX capabilities, the driver might need them. */ |
157 | ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params; | 148 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; |
158 | 149 | ||
159 | /* can we TX with MCS rates? */ | 150 | /* can we TX with MCS rates? */ |
160 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | 151 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) |
161 | return; | 152 | goto apply; |
162 | 153 | ||
163 | /* Counting from 0, therefore +1 */ | 154 | /* Counting from 0, therefore +1 */ |
164 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) | 155 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) |
@@ -176,25 +167,75 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
176 | * - remainder are multiple spatial streams using unequal modulation | 167 | * - remainder are multiple spatial streams using unequal modulation |
177 | */ | 168 | */ |
178 | for (i = 0; i < max_tx_streams; i++) | 169 | for (i = 0; i < max_tx_streams; i++) |
179 | ht_cap->mcs.rx_mask[i] = | 170 | ht_cap.mcs.rx_mask[i] = |
180 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; | 171 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; |
181 | 172 | ||
182 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | 173 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) |
183 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | 174 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; |
184 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | 175 | i < IEEE80211_HT_MCS_MASK_LEN; i++) |
185 | ht_cap->mcs.rx_mask[i] = | 176 | ht_cap.mcs.rx_mask[i] = |
186 | sband->ht_cap.mcs.rx_mask[i] & | 177 | sband->ht_cap.mcs.rx_mask[i] & |
187 | ht_cap_ie->mcs.rx_mask[i]; | 178 | ht_cap_ie->mcs.rx_mask[i]; |
188 | 179 | ||
189 | /* handle MCS rate 32 too */ | 180 | /* handle MCS rate 32 too */ |
190 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 181 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
191 | ht_cap->mcs.rx_mask[32/8] |= 1; | 182 | ht_cap.mcs.rx_mask[32/8] |= 1; |
192 | 183 | ||
184 | apply: | ||
193 | /* | 185 | /* |
194 | * If user has specified capability over-rides, take care | 186 | * If user has specified capability over-rides, take care |
195 | * of that here. | 187 | * of that here. |
196 | */ | 188 | */ |
197 | ieee80211_apply_htcap_overrides(sdata, ht_cap); | 189 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); |
190 | |||
191 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | ||
192 | |||
193 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | ||
194 | |||
195 | switch (sdata->vif.bss_conf.chandef.width) { | ||
196 | default: | ||
197 | WARN_ON_ONCE(1); | ||
198 | /* fall through */ | ||
199 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
200 | case NL80211_CHAN_WIDTH_20: | ||
201 | bw = IEEE80211_STA_RX_BW_20; | ||
202 | break; | ||
203 | case NL80211_CHAN_WIDTH_40: | ||
204 | case NL80211_CHAN_WIDTH_80: | ||
205 | case NL80211_CHAN_WIDTH_80P80: | ||
206 | case NL80211_CHAN_WIDTH_160: | ||
207 | bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
208 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | if (bw != sta->sta.bandwidth) | ||
213 | changed = true; | ||
214 | sta->sta.bandwidth = bw; | ||
215 | |||
216 | sta->cur_max_bandwidth = | ||
217 | ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
218 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
219 | |||
220 | switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS) | ||
221 | >> IEEE80211_HT_CAP_SM_PS_SHIFT) { | ||
222 | case WLAN_HT_CAP_SM_PS_INVALID: | ||
223 | case WLAN_HT_CAP_SM_PS_STATIC: | ||
224 | smps_mode = IEEE80211_SMPS_STATIC; | ||
225 | break; | ||
226 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | ||
227 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
228 | break; | ||
229 | case WLAN_HT_CAP_SM_PS_DISABLED: | ||
230 | smps_mode = IEEE80211_SMPS_OFF; | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | if (smps_mode != sta->sta.smps_mode) | ||
235 | changed = true; | ||
236 | sta->sta.smps_mode = smps_mode; | ||
237 | |||
238 | return changed; | ||
198 | } | 239 | } |
199 | 240 | ||
200 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, | 241 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |
@@ -406,6 +447,9 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, | |||
406 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) | 447 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) |
407 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 448 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
408 | 449 | ||
450 | if (sdata->u.mgd.driver_smps_mode == smps_mode) | ||
451 | return; | ||
452 | |||
409 | sdata->u.mgd.driver_smps_mode = smps_mode; | 453 | sdata->u.mgd.driver_smps_mode = smps_mode; |
410 | 454 | ||
411 | ieee80211_queue_work(&sdata->local->hw, | 455 | ieee80211_queue_work(&sdata->local->hw, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b4b866f41919..40b71dfcc79d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
228 | 228 | ||
229 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, | 229 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, |
230 | mgmt, skb->len, 0, GFP_KERNEL); | 230 | mgmt, skb->len, 0, GFP_KERNEL); |
231 | cfg80211_put_bss(bss); | 231 | cfg80211_put_bss(local->hw.wiphy, bss); |
232 | netif_carrier_on(sdata->dev); | 232 | netif_carrier_on(sdata->dev); |
233 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | 233 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); |
234 | } | 234 | } |
@@ -242,6 +242,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
242 | u32 basic_rates; | 242 | u32 basic_rates; |
243 | int i, j; | 243 | int i, j; |
244 | u16 beacon_int = cbss->beacon_interval; | 244 | u16 beacon_int = cbss->beacon_interval; |
245 | const struct cfg80211_bss_ies *ies; | ||
246 | u64 tsf; | ||
245 | 247 | ||
246 | lockdep_assert_held(&sdata->u.ibss.mtx); | 248 | lockdep_assert_held(&sdata->u.ibss.mtx); |
247 | 249 | ||
@@ -265,13 +267,17 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
265 | } | 267 | } |
266 | } | 268 | } |
267 | 269 | ||
270 | rcu_read_lock(); | ||
271 | ies = rcu_dereference(cbss->ies); | ||
272 | tsf = ies->tsf; | ||
273 | rcu_read_unlock(); | ||
274 | |||
268 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, | 275 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, |
269 | beacon_int, | 276 | beacon_int, |
270 | cbss->channel, | 277 | cbss->channel, |
271 | basic_rates, | 278 | basic_rates, |
272 | cbss->capability, | 279 | cbss->capability, |
273 | cbss->tsf, | 280 | tsf, false); |
274 | false); | ||
275 | } | 281 | } |
276 | 282 | ||
277 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | 283 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, |
@@ -302,7 +308,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
302 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", | 308 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", |
303 | sdata->vif.addr, addr, sdata->u.ibss.bssid); | 309 | sdata->vif.addr, addr, sdata->u.ibss.bssid); |
304 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, | 310 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, |
305 | addr, sdata->u.ibss.bssid, NULL, 0, 0); | 311 | addr, sdata->u.ibss.bssid, NULL, 0, 0, 0); |
306 | } | 312 | } |
307 | return sta; | 313 | return sta; |
308 | } | 314 | } |
@@ -422,7 +428,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
422 | * has actually implemented this. | 428 | * has actually implemented this. |
423 | */ | 429 | */ |
424 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, | 430 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, |
425 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); | 431 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0); |
426 | } | 432 | } |
427 | 433 | ||
428 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 434 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
@@ -490,33 +496,26 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
490 | if (sta && elems->ht_operation && elems->ht_cap_elem && | 496 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
491 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 497 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
492 | /* we both use HT */ | 498 | /* we both use HT */ |
493 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 499 | struct ieee80211_ht_cap htcap_ie; |
494 | struct cfg80211_chan_def chandef; | 500 | struct cfg80211_chan_def chandef; |
495 | 501 | ||
496 | ieee80211_ht_oper_to_chandef(channel, | 502 | ieee80211_ht_oper_to_chandef(channel, |
497 | elems->ht_operation, | 503 | elems->ht_operation, |
498 | &chandef); | 504 | &chandef); |
499 | 505 | ||
500 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 506 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); |
501 | elems->ht_cap_elem, | ||
502 | &sta_ht_cap_new); | ||
503 | 507 | ||
504 | /* | 508 | /* |
505 | * fall back to HT20 if we don't use or use | 509 | * fall back to HT20 if we don't use or use |
506 | * the other extension channel | 510 | * the other extension channel |
507 | */ | 511 | */ |
508 | if (chandef.width != NL80211_CHAN_WIDTH_40 || | 512 | if (cfg80211_get_chandef_type(&chandef) != |
509 | cfg80211_get_chandef_type(&chandef) != | ||
510 | sdata->u.ibss.channel_type) | 513 | sdata->u.ibss.channel_type) |
511 | sta_ht_cap_new.cap &= | 514 | htcap_ie.cap_info &= |
512 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 515 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
513 | 516 | ||
514 | if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new, | 517 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap( |
515 | sizeof(sta_ht_cap_new))) { | 518 | sdata, sband, &htcap_ie, sta); |
516 | memcpy(&sta->sta.ht_cap, &sta_ht_cap_new, | ||
517 | sizeof(sta_ht_cap_new)); | ||
518 | rates_updated = true; | ||
519 | } | ||
520 | } | 519 | } |
521 | 520 | ||
522 | if (sta && rates_updated) { | 521 | if (sta && rates_updated) { |
@@ -535,8 +534,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
535 | 534 | ||
536 | cbss = container_of((void *)bss, struct cfg80211_bss, priv); | 535 | cbss = container_of((void *)bss, struct cfg80211_bss, priv); |
537 | 536 | ||
538 | /* was just updated in ieee80211_bss_info_update */ | 537 | /* same for beacon and probe response */ |
539 | beacon_timestamp = cbss->tsf; | 538 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); |
540 | 539 | ||
541 | /* check if we need to merge IBSS */ | 540 | /* check if we need to merge IBSS */ |
542 | 541 | ||
@@ -1102,10 +1101,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1102 | 1101 | ||
1103 | mutex_unlock(&sdata->u.ibss.mtx); | 1102 | mutex_unlock(&sdata->u.ibss.mtx); |
1104 | 1103 | ||
1105 | mutex_lock(&sdata->local->mtx); | ||
1106 | ieee80211_recalc_idle(sdata->local); | ||
1107 | mutex_unlock(&sdata->local->mtx); | ||
1108 | |||
1109 | /* | 1104 | /* |
1110 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is | 1105 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is |
1111 | * reserved, but an HT STA shall protect HT transmissions as though | 1106 | * reserved, but an HT STA shall protect HT transmissions as though |
@@ -1159,7 +1154,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1159 | 1154 | ||
1160 | if (cbss) { | 1155 | if (cbss) { |
1161 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | 1156 | cfg80211_unlink_bss(local->hw.wiphy, cbss); |
1162 | cfg80211_put_bss(cbss); | 1157 | cfg80211_put_bss(local->hw.wiphy, cbss); |
1163 | } | 1158 | } |
1164 | } | 1159 | } |
1165 | 1160 | ||
@@ -1203,9 +1198,5 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1203 | 1198 | ||
1204 | mutex_unlock(&sdata->u.ibss.mtx); | 1199 | mutex_unlock(&sdata->u.ibss.mtx); |
1205 | 1200 | ||
1206 | mutex_lock(&local->mtx); | ||
1207 | ieee80211_recalc_idle(sdata->local); | ||
1208 | mutex_unlock(&local->mtx); | ||
1209 | |||
1210 | return 0; | 1201 | return 0; |
1211 | } | 1202 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5fba867d9e2e..388580a1bada 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -86,23 +86,11 @@ struct ieee80211_fragment_entry { | |||
86 | 86 | ||
87 | 87 | ||
88 | struct ieee80211_bss { | 88 | struct ieee80211_bss { |
89 | /* don't want to look up all the time */ | 89 | u32 device_ts_beacon, device_ts_presp; |
90 | size_t ssid_len; | ||
91 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
92 | |||
93 | u32 device_ts; | ||
94 | 90 | ||
95 | bool wmm_used; | 91 | bool wmm_used; |
96 | bool uapsd_supported; | 92 | bool uapsd_supported; |
97 | 93 | ||
98 | unsigned long last_probe_resp; | ||
99 | |||
100 | #ifdef CONFIG_MAC80211_MESH | ||
101 | u8 *mesh_id; | ||
102 | size_t mesh_id_len; | ||
103 | u8 *mesh_cfg; | ||
104 | #endif | ||
105 | |||
106 | #define IEEE80211_MAX_SUPP_RATES 32 | 94 | #define IEEE80211_MAX_SUPP_RATES 32 |
107 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 95 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
108 | size_t supp_rates_len; | 96 | size_t supp_rates_len; |
@@ -153,31 +141,6 @@ enum ieee80211_bss_valid_data_flags { | |||
153 | IEEE80211_BSS_VALID_ERP = BIT(3) | 141 | IEEE80211_BSS_VALID_ERP = BIT(3) |
154 | }; | 142 | }; |
155 | 143 | ||
156 | static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss) | ||
157 | { | ||
158 | #ifdef CONFIG_MAC80211_MESH | ||
159 | return bss->mesh_cfg; | ||
160 | #endif | ||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | static inline u8 *bss_mesh_id(struct ieee80211_bss *bss) | ||
165 | { | ||
166 | #ifdef CONFIG_MAC80211_MESH | ||
167 | return bss->mesh_id; | ||
168 | #endif | ||
169 | return NULL; | ||
170 | } | ||
171 | |||
172 | static inline u8 bss_mesh_id_len(struct ieee80211_bss *bss) | ||
173 | { | ||
174 | #ifdef CONFIG_MAC80211_MESH | ||
175 | return bss->mesh_id_len; | ||
176 | #endif | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | |||
181 | typedef unsigned __bitwise__ ieee80211_tx_result; | 144 | typedef unsigned __bitwise__ ieee80211_tx_result; |
182 | #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) | 145 | #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) |
183 | #define TX_DROP ((__force ieee80211_tx_result) 1u) | 146 | #define TX_DROP ((__force ieee80211_tx_result) 1u) |
@@ -380,6 +343,7 @@ struct ieee80211_mgd_auth_data { | |||
380 | u8 key[WLAN_KEY_LEN_WEP104]; | 343 | u8 key[WLAN_KEY_LEN_WEP104]; |
381 | u8 key_len, key_idx; | 344 | u8 key_len, key_idx; |
382 | bool done; | 345 | bool done; |
346 | bool timeout_started; | ||
383 | 347 | ||
384 | u16 sae_trans, sae_status; | 348 | u16 sae_trans, sae_status; |
385 | size_t data_len; | 349 | size_t data_len; |
@@ -399,9 +363,9 @@ struct ieee80211_mgd_assoc_data { | |||
399 | u8 ssid_len; | 363 | u8 ssid_len; |
400 | u8 supp_rates_len; | 364 | u8 supp_rates_len; |
401 | bool wmm, uapsd; | 365 | bool wmm, uapsd; |
402 | bool have_beacon; | 366 | bool have_beacon, need_beacon; |
403 | bool sent_assoc; | ||
404 | bool synced; | 367 | bool synced; |
368 | bool timeout_started; | ||
405 | 369 | ||
406 | u8 ap_ht_param; | 370 | u8 ap_ht_param; |
407 | 371 | ||
@@ -425,6 +389,7 @@ struct ieee80211_if_managed { | |||
425 | unsigned long probe_timeout; | 389 | unsigned long probe_timeout; |
426 | int probe_send_count; | 390 | int probe_send_count; |
427 | bool nullfunc_failed; | 391 | bool nullfunc_failed; |
392 | bool connection_loss; | ||
428 | 393 | ||
429 | struct mutex mtx; | 394 | struct mutex mtx; |
430 | struct cfg80211_bss *associated; | 395 | struct cfg80211_bss *associated; |
@@ -449,6 +414,10 @@ struct ieee80211_if_managed { | |||
449 | bool beacon_crc_valid; | 414 | bool beacon_crc_valid; |
450 | u32 beacon_crc; | 415 | u32 beacon_crc; |
451 | 416 | ||
417 | bool status_acked; | ||
418 | bool status_received; | ||
419 | __le16 status_fc; | ||
420 | |||
452 | enum { | 421 | enum { |
453 | IEEE80211_MFP_DISABLED, | 422 | IEEE80211_MFP_DISABLED, |
454 | IEEE80211_MFP_OPTIONAL, | 423 | IEEE80211_MFP_OPTIONAL, |
@@ -611,6 +580,9 @@ struct ieee80211_if_mesh { | |||
611 | u32 mesh_seqnum; | 580 | u32 mesh_seqnum; |
612 | bool accepting_plinks; | 581 | bool accepting_plinks; |
613 | int num_gates; | 582 | int num_gates; |
583 | struct beacon_data __rcu *beacon; | ||
584 | /* just protects beacon updates for now */ | ||
585 | struct mutex mtx; | ||
614 | const u8 *ie; | 586 | const u8 *ie; |
615 | u8 ie_len; | 587 | u8 ie_len; |
616 | enum { | 588 | enum { |
@@ -623,6 +595,11 @@ struct ieee80211_if_mesh { | |||
623 | s64 sync_offset_clockdrift_max; | 595 | s64 sync_offset_clockdrift_max; |
624 | spinlock_t sync_offset_lock; | 596 | spinlock_t sync_offset_lock; |
625 | bool adjusting_tbtt; | 597 | bool adjusting_tbtt; |
598 | /* mesh power save */ | ||
599 | enum nl80211_mesh_power_mode nonpeer_pm; | ||
600 | int ps_peers_light_sleep; | ||
601 | int ps_peers_deep_sleep; | ||
602 | struct ps_data ps; | ||
626 | }; | 603 | }; |
627 | 604 | ||
628 | #ifdef CONFIG_MAC80211_MESH | 605 | #ifdef CONFIG_MAC80211_MESH |
@@ -717,9 +694,6 @@ struct ieee80211_sub_if_data { | |||
717 | 694 | ||
718 | char name[IFNAMSIZ]; | 695 | char name[IFNAMSIZ]; |
719 | 696 | ||
720 | /* to detect idle changes */ | ||
721 | bool old_idle; | ||
722 | |||
723 | /* Fragment table for host-based reassembly */ | 697 | /* Fragment table for host-based reassembly */ |
724 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 698 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
725 | unsigned int fragment_next; | 699 | unsigned int fragment_next; |
@@ -753,6 +727,9 @@ struct ieee80211_sub_if_data { | |||
753 | int user_power_level; /* in dBm */ | 727 | int user_power_level; /* in dBm */ |
754 | int ap_power_level; /* in dBm */ | 728 | int ap_power_level; /* in dBm */ |
755 | 729 | ||
730 | bool radar_required; | ||
731 | struct delayed_work dfs_cac_timer_work; | ||
732 | |||
756 | /* | 733 | /* |
757 | * AP this belongs to: self in AP mode and | 734 | * AP this belongs to: self in AP mode and |
758 | * corresponding AP in VLAN mode, NULL for | 735 | * corresponding AP in VLAN mode, NULL for |
@@ -840,6 +817,7 @@ enum queue_stop_reason { | |||
840 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, | 817 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
841 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, | 818 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
842 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, | 819 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
820 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | ||
843 | }; | 821 | }; |
844 | 822 | ||
845 | #ifdef CONFIG_MAC80211_LEDS | 823 | #ifdef CONFIG_MAC80211_LEDS |
@@ -972,6 +950,10 @@ struct ieee80211_local { | |||
972 | /* wowlan is enabled -- don't reconfig on resume */ | 950 | /* wowlan is enabled -- don't reconfig on resume */ |
973 | bool wowlan; | 951 | bool wowlan; |
974 | 952 | ||
953 | /* DFS/radar detection is enabled */ | ||
954 | bool radar_detect_enabled; | ||
955 | struct work_struct radar_detected_work; | ||
956 | |||
975 | /* number of RX chains the hardware has */ | 957 | /* number of RX chains the hardware has */ |
976 | u8 rx_chains; | 958 | u8 rx_chains; |
977 | 959 | ||
@@ -986,14 +968,7 @@ struct ieee80211_local { | |||
986 | struct sk_buff_head skb_queue; | 968 | struct sk_buff_head skb_queue; |
987 | struct sk_buff_head skb_queue_unreliable; | 969 | struct sk_buff_head skb_queue_unreliable; |
988 | 970 | ||
989 | /* | 971 | spinlock_t rx_path_lock; |
990 | * Internal FIFO queue which is shared between multiple rx path | ||
991 | * stages. Its main task is to provide a serialization mechanism, | ||
992 | * so all rx handlers can enjoy having exclusive access to their | ||
993 | * private data structures. | ||
994 | */ | ||
995 | struct sk_buff_head rx_skb_queue; | ||
996 | bool running_rx_handler; /* protected by rx_skb_queue.lock */ | ||
997 | 972 | ||
998 | /* Station data */ | 973 | /* Station data */ |
999 | /* | 974 | /* |
@@ -1134,8 +1109,6 @@ struct ieee80211_local { | |||
1134 | * this will override whatever chosen by mac80211 internally. | 1109 | * this will override whatever chosen by mac80211 internally. |
1135 | */ | 1110 | */ |
1136 | int dynamic_ps_forced_timeout; | 1111 | int dynamic_ps_forced_timeout; |
1137 | int dynamic_ps_user_timeout; | ||
1138 | bool disable_dynamic_ps; | ||
1139 | 1112 | ||
1140 | int user_power_level; /* in dBm, for all interfaces */ | 1113 | int user_power_level; /* in dBm, for all interfaces */ |
1141 | 1114 | ||
@@ -1193,40 +1166,41 @@ struct ieee80211_ra_tid { | |||
1193 | 1166 | ||
1194 | /* Parsed Information Elements */ | 1167 | /* Parsed Information Elements */ |
1195 | struct ieee802_11_elems { | 1168 | struct ieee802_11_elems { |
1196 | u8 *ie_start; | 1169 | const u8 *ie_start; |
1197 | size_t total_len; | 1170 | size_t total_len; |
1198 | 1171 | ||
1199 | /* pointers to IEs */ | 1172 | /* pointers to IEs */ |
1200 | u8 *ssid; | 1173 | const u8 *ssid; |
1201 | u8 *supp_rates; | 1174 | const u8 *supp_rates; |
1202 | u8 *fh_params; | 1175 | const u8 *fh_params; |
1203 | u8 *ds_params; | 1176 | const u8 *ds_params; |
1204 | u8 *cf_params; | 1177 | const u8 *cf_params; |
1205 | struct ieee80211_tim_ie *tim; | 1178 | const struct ieee80211_tim_ie *tim; |
1206 | u8 *ibss_params; | 1179 | const u8 *ibss_params; |
1207 | u8 *challenge; | 1180 | const u8 *challenge; |
1208 | u8 *wpa; | 1181 | const u8 *rsn; |
1209 | u8 *rsn; | 1182 | const u8 *erp_info; |
1210 | u8 *erp_info; | 1183 | const u8 *ext_supp_rates; |
1211 | u8 *ext_supp_rates; | 1184 | const u8 *wmm_info; |
1212 | u8 *wmm_info; | 1185 | const u8 *wmm_param; |
1213 | u8 *wmm_param; | 1186 | const struct ieee80211_ht_cap *ht_cap_elem; |
1214 | struct ieee80211_ht_cap *ht_cap_elem; | 1187 | const struct ieee80211_ht_operation *ht_operation; |
1215 | struct ieee80211_ht_operation *ht_operation; | 1188 | const struct ieee80211_vht_cap *vht_cap_elem; |
1216 | struct ieee80211_vht_cap *vht_cap_elem; | 1189 | const struct ieee80211_vht_operation *vht_operation; |
1217 | struct ieee80211_vht_operation *vht_operation; | 1190 | const struct ieee80211_meshconf_ie *mesh_config; |
1218 | struct ieee80211_meshconf_ie *mesh_config; | 1191 | const u8 *mesh_id; |
1219 | u8 *mesh_id; | 1192 | const u8 *peering; |
1220 | u8 *peering; | 1193 | const __le16 *awake_window; |
1221 | u8 *preq; | 1194 | const u8 *preq; |
1222 | u8 *prep; | 1195 | const u8 *prep; |
1223 | u8 *perr; | 1196 | const u8 *perr; |
1224 | struct ieee80211_rann_ie *rann; | 1197 | const struct ieee80211_rann_ie *rann; |
1225 | struct ieee80211_channel_sw_ie *ch_switch_ie; | 1198 | const struct ieee80211_channel_sw_ie *ch_switch_ie; |
1226 | u8 *country_elem; | 1199 | const u8 *country_elem; |
1227 | u8 *pwr_constr_elem; | 1200 | const u8 *pwr_constr_elem; |
1228 | u8 *quiet_elem; /* first quite element */ | 1201 | const u8 *quiet_elem; /* first quite element */ |
1229 | u8 *timeout_int; | 1202 | const u8 *timeout_int; |
1203 | const u8 *opmode_notif; | ||
1230 | 1204 | ||
1231 | /* length of them, respectively */ | 1205 | /* length of them, respectively */ |
1232 | u8 ssid_len; | 1206 | u8 ssid_len; |
@@ -1237,7 +1211,6 @@ struct ieee802_11_elems { | |||
1237 | u8 tim_len; | 1211 | u8 tim_len; |
1238 | u8 ibss_params_len; | 1212 | u8 ibss_params_len; |
1239 | u8 challenge_len; | 1213 | u8 challenge_len; |
1240 | u8 wpa_len; | ||
1241 | u8 rsn_len; | 1214 | u8 rsn_len; |
1242 | u8 erp_info_len; | 1215 | u8 erp_info_len; |
1243 | u8 ext_supp_rates_len; | 1216 | u8 ext_supp_rates_len; |
@@ -1306,10 +1279,10 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); | |||
1306 | int ieee80211_max_network_latency(struct notifier_block *nb, | 1279 | int ieee80211_max_network_latency(struct notifier_block *nb, |
1307 | unsigned long data, void *dummy); | 1280 | unsigned long data, void *dummy); |
1308 | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); | 1281 | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); |
1309 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1282 | void |
1310 | struct ieee80211_channel_sw_ie *sw_elem, | 1283 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1311 | struct ieee80211_bss *bss, | 1284 | const struct ieee80211_channel_sw_ie *sw_elem, |
1312 | u64 timestamp); | 1285 | struct ieee80211_bss *bss, u64 timestamp); |
1313 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); | 1286 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); |
1314 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | 1287 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
1315 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); | 1288 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
@@ -1318,6 +1291,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1318 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); | 1291 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); |
1319 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); | 1292 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); |
1320 | void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); | 1293 | void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); |
1294 | void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, | ||
1295 | __le16 fc, bool acked); | ||
1321 | 1296 | ||
1322 | /* IBSS code */ | 1297 | /* IBSS code */ |
1323 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1298 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -1413,10 +1388,10 @@ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | |||
1413 | /* HT */ | 1388 | /* HT */ |
1414 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1389 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
1415 | struct ieee80211_sta_ht_cap *ht_cap); | 1390 | struct ieee80211_sta_ht_cap *ht_cap); |
1416 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 1391 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
1417 | struct ieee80211_supported_band *sband, | 1392 | struct ieee80211_supported_band *sband, |
1418 | struct ieee80211_ht_cap *ht_cap_ie, | 1393 | const struct ieee80211_ht_cap *ht_cap_ie, |
1419 | struct ieee80211_sta_ht_cap *ht_cap); | 1394 | struct sta_info *sta); |
1420 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 1395 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
1421 | const u8 *da, u16 tid, | 1396 | const u8 *da, u16 tid, |
1422 | u16 initiator, u16 reason_code); | 1397 | u16 initiator, u16 reason_code); |
@@ -1456,10 +1431,17 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); | |||
1456 | u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); | 1431 | u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); |
1457 | 1432 | ||
1458 | /* VHT */ | 1433 | /* VHT */ |
1459 | void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 1434 | void |
1460 | struct ieee80211_supported_band *sband, | 1435 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
1461 | struct ieee80211_vht_cap *vht_cap_ie, | 1436 | struct ieee80211_supported_band *sband, |
1462 | struct ieee80211_sta_vht_cap *vht_cap); | 1437 | const struct ieee80211_vht_cap *vht_cap_ie, |
1438 | struct sta_info *sta); | ||
1439 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); | ||
1440 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); | ||
1441 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||
1442 | struct sta_info *sta, u8 opmode, | ||
1443 | enum ieee80211_band band, bool nss_only); | ||
1444 | |||
1463 | /* Spectrum management */ | 1445 | /* Spectrum management */ |
1464 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1446 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
1465 | struct ieee80211_mgmt *mgmt, | 1447 | struct ieee80211_mgmt *mgmt, |
@@ -1577,8 +1559,9 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
1577 | 1559 | ||
1578 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1560 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1579 | u16 transaction, u16 auth_alg, u16 status, | 1561 | u16 transaction, u16 auth_alg, u16 status, |
1580 | u8 *extra, size_t extra_len, const u8 *bssid, | 1562 | const u8 *extra, size_t extra_len, const u8 *bssid, |
1581 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); | 1563 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx, |
1564 | u32 tx_flags); | ||
1582 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 1565 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
1583 | const u8 *bssid, u16 stype, u16 reason, | 1566 | const u8 *bssid, u16 stype, u16 reason, |
1584 | bool send_frame, u8 *frame_buf); | 1567 | bool send_frame, u8 *frame_buf); |
@@ -1595,7 +1578,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1595 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1578 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1596 | const u8 *ssid, size_t ssid_len, | 1579 | const u8 *ssid, size_t ssid_len, |
1597 | const u8 *ie, size_t ie_len, | 1580 | const u8 *ie, size_t ie_len, |
1598 | u32 ratemask, bool directed, bool no_cck, | 1581 | u32 ratemask, bool directed, u32 tx_flags, |
1599 | struct ieee80211_channel *channel, bool scan); | 1582 | struct ieee80211_channel *channel, bool scan); |
1600 | 1583 | ||
1601 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 1584 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
@@ -1627,18 +1610,31 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
1627 | 1610 | ||
1628 | /* channel management */ | 1611 | /* channel management */ |
1629 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1612 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
1630 | struct ieee80211_ht_operation *ht_oper, | 1613 | const struct ieee80211_ht_operation *ht_oper, |
1631 | struct cfg80211_chan_def *chandef); | 1614 | struct cfg80211_chan_def *chandef); |
1632 | 1615 | ||
1633 | int __must_check | 1616 | int __must_check |
1634 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 1617 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
1635 | const struct cfg80211_chan_def *chandef, | 1618 | const struct cfg80211_chan_def *chandef, |
1636 | enum ieee80211_chanctx_mode mode); | 1619 | enum ieee80211_chanctx_mode mode); |
1620 | int __must_check | ||
1621 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | ||
1622 | const struct cfg80211_chan_def *chandef, | ||
1623 | u32 *changed); | ||
1637 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1624 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
1638 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1625 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
1626 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
1627 | bool clear); | ||
1639 | 1628 | ||
1640 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1629 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
1641 | struct ieee80211_chanctx *chanctx); | 1630 | struct ieee80211_chanctx *chanctx); |
1631 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | ||
1632 | struct ieee80211_chanctx *chanctx); | ||
1633 | |||
1634 | void ieee80211_dfs_cac_timer(unsigned long data); | ||
1635 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); | ||
1636 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); | ||
1637 | void ieee80211_dfs_radar_detected_work(struct work_struct *work); | ||
1642 | 1638 | ||
1643 | #ifdef CONFIG_MAC80211_NOINLINE | 1639 | #ifdef CONFIG_MAC80211_NOINLINE |
1644 | #define debug_noinline noinline | 1640 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 0a36dc6346bb..86c83084542a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -78,8 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | |||
78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); | 78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); |
79 | } | 79 | } |
80 | 80 | ||
81 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | 81 | static u32 ieee80211_idle_off(struct ieee80211_local *local) |
82 | const char *reason) | ||
83 | { | 82 | { |
84 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | 83 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) |
85 | return 0; | 84 | return 0; |
@@ -99,110 +98,45 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
99 | return IEEE80211_CONF_CHANGE_IDLE; | 98 | return IEEE80211_CONF_CHANGE_IDLE; |
100 | } | 99 | } |
101 | 100 | ||
102 | static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | 101 | void ieee80211_recalc_idle(struct ieee80211_local *local) |
103 | { | 102 | { |
104 | struct ieee80211_sub_if_data *sdata; | 103 | bool working = false, scanning, active; |
105 | int count = 0; | ||
106 | bool working = false, scanning = false; | ||
107 | unsigned int led_trig_start = 0, led_trig_stop = 0; | 104 | unsigned int led_trig_start = 0, led_trig_stop = 0; |
108 | struct ieee80211_roc_work *roc; | 105 | struct ieee80211_roc_work *roc; |
106 | u32 change; | ||
109 | 107 | ||
110 | #ifdef CONFIG_PROVE_LOCKING | ||
111 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
112 | !lockdep_is_held(&local->iflist_mtx)); | ||
113 | #endif | ||
114 | lockdep_assert_held(&local->mtx); | 108 | lockdep_assert_held(&local->mtx); |
115 | 109 | ||
116 | list_for_each_entry(sdata, &local->interfaces, list) { | 110 | active = !list_empty(&local->chanctx_list); |
117 | if (!ieee80211_sdata_running(sdata)) { | ||
118 | sdata->vif.bss_conf.idle = true; | ||
119 | continue; | ||
120 | } | ||
121 | |||
122 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
123 | |||
124 | /* do not count disabled managed interfaces */ | ||
125 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
126 | !sdata->u.mgd.associated && | ||
127 | !sdata->u.mgd.auth_data && | ||
128 | !sdata->u.mgd.assoc_data) { | ||
129 | sdata->vif.bss_conf.idle = true; | ||
130 | continue; | ||
131 | } | ||
132 | /* do not count unused IBSS interfaces */ | ||
133 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
134 | !sdata->u.ibss.ssid_len) { | ||
135 | sdata->vif.bss_conf.idle = true; | ||
136 | continue; | ||
137 | } | ||
138 | |||
139 | if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||
140 | continue; | ||
141 | |||
142 | /* count everything else */ | ||
143 | sdata->vif.bss_conf.idle = false; | ||
144 | count++; | ||
145 | } | ||
146 | 111 | ||
147 | if (!local->ops->remain_on_channel) { | 112 | if (!local->ops->remain_on_channel) { |
148 | list_for_each_entry(roc, &local->roc_list, list) { | 113 | list_for_each_entry(roc, &local->roc_list, list) { |
149 | working = true; | 114 | working = true; |
150 | roc->sdata->vif.bss_conf.idle = false; | 115 | break; |
151 | } | 116 | } |
152 | } | 117 | } |
153 | 118 | ||
154 | sdata = rcu_dereference_protected(local->scan_sdata, | 119 | scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || |
155 | lockdep_is_held(&local->mtx)); | 120 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning); |
156 | if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
157 | scanning = true; | ||
158 | sdata->vif.bss_conf.idle = false; | ||
159 | } | ||
160 | |||
161 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
162 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
163 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||
164 | sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||
165 | continue; | ||
166 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
167 | continue; | ||
168 | if (!ieee80211_sdata_running(sdata)) | ||
169 | continue; | ||
170 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
171 | } | ||
172 | 121 | ||
173 | if (working || scanning) | 122 | if (working || scanning) |
174 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | 123 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; |
175 | else | 124 | else |
176 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | 125 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; |
177 | 126 | ||
178 | if (count) | 127 | if (active) |
179 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | 128 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; |
180 | else | 129 | else |
181 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | 130 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; |
182 | 131 | ||
183 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | 132 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); |
184 | 133 | ||
185 | if (working) | 134 | if (working || scanning || active) |
186 | return ieee80211_idle_off(local, "working"); | 135 | change = ieee80211_idle_off(local); |
187 | if (scanning) | ||
188 | return ieee80211_idle_off(local, "scanning"); | ||
189 | if (!count) | ||
190 | return ieee80211_idle_on(local); | ||
191 | else | 136 | else |
192 | return ieee80211_idle_off(local, "in use"); | 137 | change = ieee80211_idle_on(local); |
193 | 138 | if (change) | |
194 | return 0; | 139 | ieee80211_hw_config(local, change); |
195 | } | ||
196 | |||
197 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
198 | { | ||
199 | u32 chg; | ||
200 | |||
201 | mutex_lock(&local->iflist_mtx); | ||
202 | chg = __ieee80211_recalc_idle(local); | ||
203 | mutex_unlock(&local->iflist_mtx); | ||
204 | if (chg) | ||
205 | ieee80211_hw_config(local, chg); | ||
206 | } | 140 | } |
207 | 141 | ||
208 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 142 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
@@ -621,6 +555,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
621 | goto err_del_interface; | 555 | goto err_del_interface; |
622 | } | 556 | } |
623 | 557 | ||
558 | drv_add_interface_debugfs(local, sdata); | ||
559 | |||
624 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 560 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
625 | local->fif_pspoll++; | 561 | local->fif_pspoll++; |
626 | local->fif_probe_req++; | 562 | local->fif_probe_req++; |
@@ -694,10 +630,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
694 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 630 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
695 | atomic_inc(&local->iff_promiscs); | 631 | atomic_inc(&local->iff_promiscs); |
696 | 632 | ||
697 | mutex_lock(&local->mtx); | ||
698 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | ||
699 | mutex_unlock(&local->mtx); | ||
700 | |||
701 | if (coming_up) | 633 | if (coming_up) |
702 | local->open_count++; | 634 | local->open_count++; |
703 | 635 | ||
@@ -748,6 +680,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
748 | struct sk_buff *skb, *tmp; | 680 | struct sk_buff *skb, *tmp; |
749 | u32 hw_reconf_flags = 0; | 681 | u32 hw_reconf_flags = 0; |
750 | int i, flushed; | 682 | int i, flushed; |
683 | struct ps_data *ps; | ||
751 | 684 | ||
752 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 685 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
753 | 686 | ||
@@ -817,6 +750,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
817 | 750 | ||
818 | cancel_work_sync(&sdata->recalc_smps); | 751 | cancel_work_sync(&sdata->recalc_smps); |
819 | 752 | ||
753 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | ||
754 | |||
755 | if (sdata->wdev.cac_started) { | ||
756 | mutex_lock(&local->iflist_mtx); | ||
757 | ieee80211_vif_release_channel(sdata); | ||
758 | mutex_unlock(&local->iflist_mtx); | ||
759 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | ||
760 | GFP_KERNEL); | ||
761 | } | ||
762 | |||
820 | /* APs need special treatment */ | 763 | /* APs need special treatment */ |
821 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 764 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
822 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 765 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
@@ -826,6 +769,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
826 | u.vlan.list) | 769 | u.vlan.list) |
827 | dev_close(vlan->dev); | 770 | dev_close(vlan->dev); |
828 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 771 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
772 | } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | ||
773 | /* remove all packets in parent bc_buf pointing to this dev */ | ||
774 | ps = &sdata->bss->ps; | ||
775 | |||
776 | spin_lock_irqsave(&ps->bc_buf.lock, flags); | ||
777 | skb_queue_walk_safe(&ps->bc_buf, skb, tmp) { | ||
778 | if (skb->dev == sdata->dev) { | ||
779 | __skb_unlink(skb, &ps->bc_buf); | ||
780 | local->total_ps_buffered--; | ||
781 | ieee80211_free_txskb(&local->hw, skb); | ||
782 | } | ||
783 | } | ||
784 | spin_unlock_irqrestore(&ps->bc_buf.lock, flags); | ||
829 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 785 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
830 | ieee80211_mgd_stop(sdata); | 786 | ieee80211_mgd_stop(sdata); |
831 | } | 787 | } |
@@ -882,16 +838,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
882 | */ | 838 | */ |
883 | ieee80211_free_keys(sdata); | 839 | ieee80211_free_keys(sdata); |
884 | 840 | ||
841 | drv_remove_interface_debugfs(local, sdata); | ||
842 | |||
885 | if (going_down) | 843 | if (going_down) |
886 | drv_remove_interface(local, sdata); | 844 | drv_remove_interface(local, sdata); |
887 | } | 845 | } |
888 | 846 | ||
889 | sdata->bss = NULL; | 847 | sdata->bss = NULL; |
890 | 848 | ||
891 | mutex_lock(&local->mtx); | ||
892 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | ||
893 | mutex_unlock(&local->mtx); | ||
894 | |||
895 | ieee80211_recalc_ps(local, -1); | 849 | ieee80211_recalc_ps(local, -1); |
896 | 850 | ||
897 | if (local->open_count == 0) { | 851 | if (local->open_count == 0) { |
@@ -1583,6 +1537,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1583 | spin_lock_init(&sdata->cleanup_stations_lock); | 1537 | spin_lock_init(&sdata->cleanup_stations_lock); |
1584 | INIT_LIST_HEAD(&sdata->cleanup_stations); | 1538 | INIT_LIST_HEAD(&sdata->cleanup_stations); |
1585 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | 1539 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); |
1540 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | ||
1541 | ieee80211_dfs_cac_timer_work); | ||
1586 | 1542 | ||
1587 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1543 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1588 | struct ieee80211_supported_band *sband; | 1544 | struct ieee80211_supported_band *sband; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2bdd454e8bcf..f9747689d604 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -34,8 +34,6 @@ | |||
34 | #include "cfg.h" | 34 | #include "cfg.h" |
35 | #include "debugfs.h" | 35 | #include "debugfs.h" |
36 | 36 | ||
37 | static struct lock_class_key ieee80211_rx_skb_queue_class; | ||
38 | |||
39 | void ieee80211_configure_filter(struct ieee80211_local *local) | 37 | void ieee80211_configure_filter(struct ieee80211_local *local) |
40 | { | 38 | { |
41 | u64 mc; | 39 | u64 mc; |
@@ -503,6 +501,11 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
503 | }, | 501 | }, |
504 | }; | 502 | }; |
505 | 503 | ||
504 | static const u8 extended_capabilities[] = { | ||
505 | 0, 0, 0, 0, 0, 0, 0, | ||
506 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | ||
507 | }; | ||
508 | |||
506 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 509 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
507 | const struct ieee80211_ops *ops) | 510 | const struct ieee80211_ops *ops) |
508 | { | 511 | { |
@@ -559,14 +562,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
559 | WIPHY_FLAG_REPORTS_OBSS | | 562 | WIPHY_FLAG_REPORTS_OBSS | |
560 | WIPHY_FLAG_OFFCHAN_TX; | 563 | WIPHY_FLAG_OFFCHAN_TX; |
561 | 564 | ||
565 | wiphy->extended_capabilities = extended_capabilities; | ||
566 | wiphy->extended_capabilities_mask = extended_capabilities; | ||
567 | wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); | ||
568 | |||
562 | if (ops->remain_on_channel) | 569 | if (ops->remain_on_channel) |
563 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 570 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
564 | 571 | ||
565 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 572 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
566 | NL80211_FEATURE_SAE | | 573 | NL80211_FEATURE_SAE | |
567 | NL80211_FEATURE_HT_IBSS | | 574 | NL80211_FEATURE_HT_IBSS | |
568 | NL80211_FEATURE_VIF_TXPOWER | | 575 | NL80211_FEATURE_VIF_TXPOWER; |
569 | NL80211_FEATURE_FULL_AP_CLIENT_STATE; | ||
570 | 576 | ||
571 | if (!ops->hw_scan) | 577 | if (!ops->hw_scan) |
572 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 578 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
@@ -613,25 +619,19 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
613 | 619 | ||
614 | mutex_init(&local->key_mtx); | 620 | mutex_init(&local->key_mtx); |
615 | spin_lock_init(&local->filter_lock); | 621 | spin_lock_init(&local->filter_lock); |
622 | spin_lock_init(&local->rx_path_lock); | ||
616 | spin_lock_init(&local->queue_stop_reason_lock); | 623 | spin_lock_init(&local->queue_stop_reason_lock); |
617 | 624 | ||
618 | INIT_LIST_HEAD(&local->chanctx_list); | 625 | INIT_LIST_HEAD(&local->chanctx_list); |
619 | mutex_init(&local->chanctx_mtx); | 626 | mutex_init(&local->chanctx_mtx); |
620 | 627 | ||
621 | /* | ||
622 | * The rx_skb_queue is only accessed from tasklets, | ||
623 | * but other SKB queues are used from within IRQ | ||
624 | * context. Therefore, this one needs a different | ||
625 | * locking class so our direct, non-irq-safe use of | ||
626 | * the queue's lock doesn't throw lockdep warnings. | ||
627 | */ | ||
628 | skb_queue_head_init_class(&local->rx_skb_queue, | ||
629 | &ieee80211_rx_skb_queue_class); | ||
630 | |||
631 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 628 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
632 | 629 | ||
633 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 630 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
634 | 631 | ||
632 | INIT_WORK(&local->radar_detected_work, | ||
633 | ieee80211_dfs_radar_detected_work); | ||
634 | |||
635 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 635 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
636 | local->smps_mode = IEEE80211_SMPS_OFF; | 636 | local->smps_mode = IEEE80211_SMPS_OFF; |
637 | 637 | ||
@@ -707,9 +707,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
707 | return -EINVAL; | 707 | return -EINVAL; |
708 | #endif | 708 | #endif |
709 | 709 | ||
710 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | ||
711 | return -EINVAL; | ||
712 | |||
713 | if (!local->use_chanctx) { | 710 | if (!local->use_chanctx) { |
714 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | 711 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { |
715 | const struct ieee80211_iface_combination *comb; | 712 | const struct ieee80211_iface_combination *comb; |
@@ -727,6 +724,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
727 | */ | 724 | */ |
728 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | 725 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) |
729 | return -EINVAL; | 726 | return -EINVAL; |
727 | |||
728 | /* DFS currently not supported with channel context drivers */ | ||
729 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | ||
730 | const struct ieee80211_iface_combination *comb; | ||
731 | |||
732 | comb = &local->hw.wiphy->iface_combinations[i]; | ||
733 | |||
734 | if (comb->radar_detect_widths) | ||
735 | return -EINVAL; | ||
736 | } | ||
730 | } | 737 | } |
731 | 738 | ||
732 | /* Only HW csum features are currently compatible with mac80211 */ | 739 | /* Only HW csum features are currently compatible with mac80211 */ |
@@ -1089,7 +1096,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1089 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); | 1096 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); |
1090 | skb_queue_purge(&local->skb_queue); | 1097 | skb_queue_purge(&local->skb_queue); |
1091 | skb_queue_purge(&local->skb_queue_unreliable); | 1098 | skb_queue_purge(&local->skb_queue_unreliable); |
1092 | skb_queue_purge(&local->rx_skb_queue); | ||
1093 | 1099 | ||
1094 | destroy_workqueue(local->workqueue); | 1100 | destroy_workqueue(local->workqueue); |
1095 | wiphy_unregister(local->hw.wiphy); | 1101 | wiphy_unregister(local->hw.wiphy); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 694e27376afa..a77d40ed4e61 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -149,6 +149,31 @@ u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
149 | return changed; | 149 | return changed; |
150 | } | 150 | } |
151 | 151 | ||
152 | /* | ||
153 | * mesh_sta_cleanup - clean up any mesh sta state | ||
154 | * | ||
155 | * @sta: mesh sta to clean up. | ||
156 | */ | ||
157 | void mesh_sta_cleanup(struct sta_info *sta) | ||
158 | { | ||
159 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
160 | u32 changed; | ||
161 | |||
162 | /* | ||
163 | * maybe userspace handles peer allocation and peering, but in either | ||
164 | * case the beacon is still generated by the kernel and we might need | ||
165 | * an update. | ||
166 | */ | ||
167 | changed = mesh_accept_plinks_update(sdata); | ||
168 | if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | ||
169 | changed |= mesh_plink_deactivate(sta); | ||
170 | del_timer_sync(&sta->plink_timer); | ||
171 | } | ||
172 | |||
173 | if (changed) | ||
174 | ieee80211_mbss_info_change_notify(sdata, changed); | ||
175 | } | ||
176 | |||
152 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 177 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
153 | { | 178 | { |
154 | int i; | 179 | int i; |
@@ -261,6 +286,9 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
261 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; | 286 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; |
262 | *pos |= ifmsh->accepting_plinks ? | 287 | *pos |= ifmsh->accepting_plinks ? |
263 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 288 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
289 | /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ | ||
290 | *pos |= ifmsh->ps_peers_deep_sleep ? | ||
291 | IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00; | ||
264 | *pos++ |= ifmsh->adjusting_tbtt ? | 292 | *pos++ |= ifmsh->adjusting_tbtt ? |
265 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; | 293 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; |
266 | *pos++ = 0x00; | 294 | *pos++ = 0x00; |
@@ -286,6 +314,29 @@ mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
286 | return 0; | 314 | return 0; |
287 | } | 315 | } |
288 | 316 | ||
317 | int mesh_add_awake_window_ie(struct sk_buff *skb, | ||
318 | struct ieee80211_sub_if_data *sdata) | ||
319 | { | ||
320 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
321 | u8 *pos; | ||
322 | |||
323 | /* see IEEE802.11-2012 13.14.6 */ | ||
324 | if (ifmsh->ps_peers_light_sleep == 0 && | ||
325 | ifmsh->ps_peers_deep_sleep == 0 && | ||
326 | ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE) | ||
327 | return 0; | ||
328 | |||
329 | if (skb_tailroom(skb) < 4) | ||
330 | return -ENOMEM; | ||
331 | |||
332 | pos = skb_put(skb, 2 + 2); | ||
333 | *pos++ = WLAN_EID_MESH_AWAKE_WINDOW; | ||
334 | *pos++ = 2; | ||
335 | put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos); | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
289 | int | 340 | int |
290 | mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | 341 | mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) |
291 | { | 342 | { |
@@ -342,8 +393,6 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
342 | int mesh_add_ds_params_ie(struct sk_buff *skb, | 393 | int mesh_add_ds_params_ie(struct sk_buff *skb, |
343 | struct ieee80211_sub_if_data *sdata) | 394 | struct ieee80211_sub_if_data *sdata) |
344 | { | 395 | { |
345 | struct ieee80211_local *local = sdata->local; | ||
346 | struct ieee80211_supported_band *sband; | ||
347 | struct ieee80211_chanctx_conf *chanctx_conf; | 396 | struct ieee80211_chanctx_conf *chanctx_conf; |
348 | struct ieee80211_channel *chan; | 397 | struct ieee80211_channel *chan; |
349 | u8 *pos; | 398 | u8 *pos; |
@@ -360,13 +409,10 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | |||
360 | chan = chanctx_conf->def.chan; | 409 | chan = chanctx_conf->def.chan; |
361 | rcu_read_unlock(); | 410 | rcu_read_unlock(); |
362 | 411 | ||
363 | sband = local->hw.wiphy->bands[chan->band]; | 412 | pos = skb_put(skb, 2 + 1); |
364 | if (sband->band == IEEE80211_BAND_2GHZ) { | 413 | *pos++ = WLAN_EID_DS_PARAMS; |
365 | pos = skb_put(skb, 2 + 1); | 414 | *pos++ = 1; |
366 | *pos++ = WLAN_EID_DS_PARAMS; | 415 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); |
367 | *pos++ = 1; | ||
368 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); | ||
369 | } | ||
370 | 416 | ||
371 | return 0; | 417 | return 0; |
372 | } | 418 | } |
@@ -547,7 +593,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
547 | mesh_path_expire(sdata); | 593 | mesh_path_expire(sdata); |
548 | 594 | ||
549 | changed = mesh_accept_plinks_update(sdata); | 595 | changed = mesh_accept_plinks_update(sdata); |
550 | ieee80211_bss_info_change_notify(sdata, changed); | 596 | ieee80211_mbss_info_change_notify(sdata, changed); |
551 | 597 | ||
552 | mod_timer(&ifmsh->housekeeping_timer, | 598 | mod_timer(&ifmsh->housekeeping_timer, |
553 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 599 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
@@ -598,7 +644,140 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
598 | } | 644 | } |
599 | #endif | 645 | #endif |
600 | 646 | ||
601 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | 647 | static int |
648 | ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | ||
649 | { | ||
650 | struct beacon_data *bcn; | ||
651 | int head_len, tail_len; | ||
652 | struct sk_buff *skb; | ||
653 | struct ieee80211_mgmt *mgmt; | ||
654 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
655 | enum ieee80211_band band; | ||
656 | u8 *pos; | ||
657 | struct ieee80211_sub_if_data *sdata; | ||
658 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | ||
659 | sizeof(mgmt->u.beacon); | ||
660 | |||
661 | sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); | ||
662 | rcu_read_lock(); | ||
663 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
664 | band = chanctx_conf->def.chan->band; | ||
665 | rcu_read_unlock(); | ||
666 | |||
667 | head_len = hdr_len + | ||
668 | 2 + /* NULL SSID */ | ||
669 | 2 + 8 + /* supported rates */ | ||
670 | 2 + 3; /* DS params */ | ||
671 | tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | ||
672 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
673 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
674 | 2 + ifmsh->mesh_id_len + | ||
675 | 2 + sizeof(struct ieee80211_meshconf_ie) + | ||
676 | 2 + sizeof(__le16) + /* awake window */ | ||
677 | ifmsh->ie_len; | ||
678 | |||
679 | bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); | ||
680 | /* need an skb for IE builders to operate on */ | ||
681 | skb = dev_alloc_skb(max(head_len, tail_len)); | ||
682 | |||
683 | if (!bcn || !skb) | ||
684 | goto out_free; | ||
685 | |||
686 | /* | ||
687 | * pointers go into the block we allocated, | ||
688 | * memory is | beacon_data | head | tail | | ||
689 | */ | ||
690 | bcn->head = ((u8 *) bcn) + sizeof(*bcn); | ||
691 | |||
692 | /* fill in the head */ | ||
693 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | ||
694 | memset(mgmt, 0, hdr_len); | ||
695 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
696 | IEEE80211_STYPE_BEACON); | ||
697 | eth_broadcast_addr(mgmt->da); | ||
698 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
699 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||
700 | ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt); | ||
701 | mgmt->u.beacon.beacon_int = | ||
702 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | ||
703 | mgmt->u.beacon.capab_info |= cpu_to_le16( | ||
704 | sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0); | ||
705 | |||
706 | pos = skb_put(skb, 2); | ||
707 | *pos++ = WLAN_EID_SSID; | ||
708 | *pos++ = 0x0; | ||
709 | |||
710 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | ||
711 | mesh_add_ds_params_ie(skb, sdata)) | ||
712 | goto out_free; | ||
713 | |||
714 | bcn->head_len = skb->len; | ||
715 | memcpy(bcn->head, skb->data, bcn->head_len); | ||
716 | |||
717 | /* now the tail */ | ||
718 | skb_trim(skb, 0); | ||
719 | bcn->tail = bcn->head + bcn->head_len; | ||
720 | |||
721 | if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | ||
722 | mesh_add_rsn_ie(skb, sdata) || | ||
723 | mesh_add_ht_cap_ie(skb, sdata) || | ||
724 | mesh_add_ht_oper_ie(skb, sdata) || | ||
725 | mesh_add_meshid_ie(skb, sdata) || | ||
726 | mesh_add_meshconf_ie(skb, sdata) || | ||
727 | mesh_add_awake_window_ie(skb, sdata) || | ||
728 | mesh_add_vendor_ies(skb, sdata)) | ||
729 | goto out_free; | ||
730 | |||
731 | bcn->tail_len = skb->len; | ||
732 | memcpy(bcn->tail, skb->data, bcn->tail_len); | ||
733 | |||
734 | dev_kfree_skb(skb); | ||
735 | rcu_assign_pointer(ifmsh->beacon, bcn); | ||
736 | return 0; | ||
737 | out_free: | ||
738 | kfree(bcn); | ||
739 | dev_kfree_skb(skb); | ||
740 | return -ENOMEM; | ||
741 | } | ||
742 | |||
743 | static int | ||
744 | ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh) | ||
745 | { | ||
746 | struct ieee80211_sub_if_data *sdata; | ||
747 | struct beacon_data *old_bcn; | ||
748 | int ret; | ||
749 | sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); | ||
750 | |||
751 | mutex_lock(&ifmsh->mtx); | ||
752 | |||
753 | old_bcn = rcu_dereference_protected(ifmsh->beacon, | ||
754 | lockdep_is_held(&ifmsh->mtx)); | ||
755 | ret = ieee80211_mesh_build_beacon(ifmsh); | ||
756 | if (ret) | ||
757 | /* just reuse old beacon */ | ||
758 | goto out; | ||
759 | |||
760 | if (old_bcn) | ||
761 | kfree_rcu(old_bcn, rcu_head); | ||
762 | out: | ||
763 | mutex_unlock(&ifmsh->mtx); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||
768 | u32 changed) | ||
769 | { | ||
770 | if (sdata->vif.bss_conf.enable_beacon && | ||
771 | (changed & (BSS_CHANGED_BEACON | | ||
772 | BSS_CHANGED_HT | | ||
773 | BSS_CHANGED_BASIC_RATES | | ||
774 | BSS_CHANGED_BEACON_INT))) | ||
775 | if (ieee80211_mesh_rebuild_beacon(&sdata->u.mesh)) | ||
776 | return; | ||
777 | ieee80211_bss_info_change_notify(sdata, changed); | ||
778 | } | ||
779 | |||
780 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | ||
602 | { | 781 | { |
603 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 782 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
604 | struct ieee80211_local *local = sdata->local; | 783 | struct ieee80211_local *local = sdata->local; |
@@ -629,20 +808,24 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
629 | sdata->vif.bss_conf.basic_rates = | 808 | sdata->vif.bss_conf.basic_rates = |
630 | ieee80211_mandatory_rates(local, band); | 809 | ieee80211_mandatory_rates(local, band); |
631 | 810 | ||
632 | if (band == IEEE80211_BAND_5GHZ) { | 811 | changed |= ieee80211_mps_local_status_update(sdata); |
633 | sdata->vif.bss_conf.use_short_slot = true; | 812 | |
634 | changed |= BSS_CHANGED_ERP_SLOT; | 813 | if (ieee80211_mesh_build_beacon(ifmsh)) { |
814 | ieee80211_stop_mesh(sdata); | ||
815 | return -ENOMEM; | ||
635 | } | 816 | } |
636 | 817 | ||
637 | ieee80211_bss_info_change_notify(sdata, changed); | 818 | ieee80211_bss_info_change_notify(sdata, changed); |
638 | 819 | ||
639 | netif_carrier_on(sdata->dev); | 820 | netif_carrier_on(sdata->dev); |
821 | return 0; | ||
640 | } | 822 | } |
641 | 823 | ||
642 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 824 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
643 | { | 825 | { |
644 | struct ieee80211_local *local = sdata->local; | 826 | struct ieee80211_local *local = sdata->local; |
645 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 827 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
828 | struct beacon_data *bcn; | ||
646 | 829 | ||
647 | netif_carrier_off(sdata->dev); | 830 | netif_carrier_off(sdata->dev); |
648 | 831 | ||
@@ -651,11 +834,21 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
651 | sdata->vif.bss_conf.enable_beacon = false; | 834 | sdata->vif.bss_conf.enable_beacon = false; |
652 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 835 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
653 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 836 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
837 | mutex_lock(&ifmsh->mtx); | ||
838 | bcn = rcu_dereference_protected(ifmsh->beacon, | ||
839 | lockdep_is_held(&ifmsh->mtx)); | ||
840 | rcu_assign_pointer(ifmsh->beacon, NULL); | ||
841 | kfree_rcu(bcn, rcu_head); | ||
842 | mutex_unlock(&ifmsh->mtx); | ||
654 | 843 | ||
655 | /* flush STAs and mpaths on this iface */ | 844 | /* flush STAs and mpaths on this iface */ |
656 | sta_info_flush(sdata); | 845 | sta_info_flush(sdata); |
657 | mesh_path_flush_by_iface(sdata); | 846 | mesh_path_flush_by_iface(sdata); |
658 | 847 | ||
848 | /* free all potentially still buffered group-addressed frames */ | ||
849 | local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf); | ||
850 | skb_queue_purge(&ifmsh->ps.bc_buf); | ||
851 | |||
659 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 852 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
660 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 853 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
661 | del_timer_sync(&sdata->u.mesh.mesh_path_timer); | 854 | del_timer_sync(&sdata->u.mesh.mesh_path_timer); |
@@ -675,6 +868,63 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
675 | sdata->u.mesh.timers_running = 0; | 868 | sdata->u.mesh.timers_running = 0; |
676 | } | 869 | } |
677 | 870 | ||
871 | static void | ||
872 | ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, | ||
873 | struct ieee80211_mgmt *mgmt, size_t len) | ||
874 | { | ||
875 | struct ieee80211_local *local = sdata->local; | ||
876 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
877 | struct sk_buff *presp; | ||
878 | struct beacon_data *bcn; | ||
879 | struct ieee80211_mgmt *hdr; | ||
880 | struct ieee802_11_elems elems; | ||
881 | size_t baselen; | ||
882 | u8 *pos, *end; | ||
883 | |||
884 | end = ((u8 *) mgmt) + len; | ||
885 | pos = mgmt->u.probe_req.variable; | ||
886 | baselen = (u8 *) pos - (u8 *) mgmt; | ||
887 | if (baselen > len) | ||
888 | return; | ||
889 | |||
890 | ieee802_11_parse_elems(pos, len - baselen, &elems); | ||
891 | |||
892 | /* 802.11-2012 10.1.4.3.2 */ | ||
893 | if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && | ||
894 | !is_broadcast_ether_addr(mgmt->da)) || | ||
895 | elems.ssid_len != 0) | ||
896 | return; | ||
897 | |||
898 | if (elems.mesh_id_len != 0 && | ||
899 | (elems.mesh_id_len != ifmsh->mesh_id_len || | ||
900 | memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) | ||
901 | return; | ||
902 | |||
903 | rcu_read_lock(); | ||
904 | bcn = rcu_dereference(ifmsh->beacon); | ||
905 | |||
906 | if (!bcn) | ||
907 | goto out; | ||
908 | |||
909 | presp = dev_alloc_skb(local->tx_headroom + | ||
910 | bcn->head_len + bcn->tail_len); | ||
911 | if (!presp) | ||
912 | goto out; | ||
913 | |||
914 | skb_reserve(presp, local->tx_headroom); | ||
915 | memcpy(skb_put(presp, bcn->head_len), bcn->head, bcn->head_len); | ||
916 | memcpy(skb_put(presp, bcn->tail_len), bcn->tail, bcn->tail_len); | ||
917 | hdr = (struct ieee80211_mgmt *) presp->data; | ||
918 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
919 | IEEE80211_STYPE_PROBE_RESP); | ||
920 | memcpy(hdr->da, mgmt->sa, ETH_ALEN); | ||
921 | mpl_dbg(sdata, "sending probe resp. to %pM\n", hdr->da); | ||
922 | IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
923 | ieee80211_tx_skb(sdata, presp); | ||
924 | out: | ||
925 | rcu_read_unlock(); | ||
926 | } | ||
927 | |||
678 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | 928 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, |
679 | u16 stype, | 929 | u16 stype, |
680 | struct ieee80211_mgmt *mgmt, | 930 | struct ieee80211_mgmt *mgmt, |
@@ -764,6 +1014,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
764 | ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, | 1014 | ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, |
765 | rx_status); | 1015 | rx_status); |
766 | break; | 1016 | break; |
1017 | case IEEE80211_STYPE_PROBE_REQ: | ||
1018 | ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len); | ||
1019 | break; | ||
767 | case IEEE80211_STYPE_ACTION: | 1020 | case IEEE80211_STYPE_ACTION: |
768 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); | 1021 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); |
769 | break; | 1022 | break; |
@@ -833,8 +1086,11 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
833 | ieee80211_mesh_path_root_timer, | 1086 | ieee80211_mesh_path_root_timer, |
834 | (unsigned long) sdata); | 1087 | (unsigned long) sdata); |
835 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 1088 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
1089 | skb_queue_head_init(&ifmsh->ps.bc_buf); | ||
836 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 1090 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
837 | spin_lock_init(&ifmsh->sync_offset_lock); | 1091 | spin_lock_init(&ifmsh->sync_offset_lock); |
1092 | RCU_INIT_POINTER(ifmsh->beacon, NULL); | ||
1093 | mutex_init(&ifmsh->mtx); | ||
838 | 1094 | ||
839 | sdata->vif.bss_conf.bssid = zero_addr; | 1095 | sdata->vif.bss_conf.bssid = zero_addr; |
840 | } | 1096 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index aff301544c7f..1a1da877b1d2 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -222,6 +222,8 @@ int mesh_add_meshid_ie(struct sk_buff *skb, | |||
222 | struct ieee80211_sub_if_data *sdata); | 222 | struct ieee80211_sub_if_data *sdata); |
223 | int mesh_add_rsn_ie(struct sk_buff *skb, | 223 | int mesh_add_rsn_ie(struct sk_buff *skb, |
224 | struct ieee80211_sub_if_data *sdata); | 224 | struct ieee80211_sub_if_data *sdata); |
225 | int mesh_add_awake_window_ie(struct sk_buff *skb, | ||
226 | struct ieee80211_sub_if_data *sdata); | ||
225 | int mesh_add_vendor_ies(struct sk_buff *skb, | 227 | int mesh_add_vendor_ies(struct sk_buff *skb, |
226 | struct ieee80211_sub_if_data *sdata); | 228 | struct ieee80211_sub_if_data *sdata); |
227 | int mesh_add_ds_params_ie(struct sk_buff *skb, | 229 | int mesh_add_ds_params_ie(struct sk_buff *skb, |
@@ -237,10 +239,28 @@ void ieee80211s_update_metric(struct ieee80211_local *local, | |||
237 | struct sta_info *sta, struct sk_buff *skb); | 239 | struct sta_info *sta, struct sk_buff *skb); |
238 | void ieee80211s_stop(void); | 240 | void ieee80211s_stop(void); |
239 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | 241 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); |
240 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 242 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
241 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 243 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
242 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | 244 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); |
243 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); | 245 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); |
246 | /* wrapper for ieee80211_bss_info_change_notify() */ | ||
247 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||
248 | u32 changed); | ||
249 | |||
250 | /* mesh power save */ | ||
251 | u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); | ||
252 | u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, | ||
253 | enum nl80211_mesh_power_mode pm); | ||
254 | void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, | ||
255 | struct sta_info *sta, | ||
256 | struct ieee80211_hdr *hdr); | ||
257 | void ieee80211_mps_sta_status_update(struct sta_info *sta); | ||
258 | void ieee80211_mps_rx_h_sta_process(struct sta_info *sta, | ||
259 | struct ieee80211_hdr *hdr); | ||
260 | void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta, | ||
261 | bool tx, bool acked); | ||
262 | void ieee80211_mps_frame_release(struct sta_info *sta, | ||
263 | struct ieee802_11_elems *elems); | ||
244 | 264 | ||
245 | /* Mesh paths */ | 265 | /* Mesh paths */ |
246 | int mesh_nexthop_lookup(struct sk_buff *skb, | 266 | int mesh_nexthop_lookup(struct sk_buff *skb, |
@@ -248,8 +268,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
248 | int mesh_nexthop_resolve(struct sk_buff *skb, | 268 | int mesh_nexthop_resolve(struct sk_buff *skb, |
249 | struct ieee80211_sub_if_data *sdata); | 269 | struct ieee80211_sub_if_data *sdata); |
250 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); | 270 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); |
251 | struct mesh_path *mesh_path_lookup(u8 *dst, | 271 | struct mesh_path *mesh_path_lookup(const u8 *dst, |
252 | struct ieee80211_sub_if_data *sdata); | 272 | struct ieee80211_sub_if_data *sdata); |
253 | struct mesh_path *mpp_path_lookup(u8 *dst, | 273 | struct mesh_path *mpp_path_lookup(u8 *dst, |
254 | struct ieee80211_sub_if_data *sdata); | 274 | struct ieee80211_sub_if_data *sdata); |
255 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); | 275 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); |
@@ -259,7 +279,7 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | |||
259 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 279 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
260 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 280 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
261 | struct ieee80211_mgmt *mgmt, size_t len); | 281 | struct ieee80211_mgmt *mgmt, size_t len); |
262 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); | 282 | int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata); |
263 | 283 | ||
264 | int mesh_path_add_gate(struct mesh_path *mpath); | 284 | int mesh_path_add_gate(struct mesh_path *mpath); |
265 | int mesh_path_send_to_gates(struct mesh_path *mpath); | 285 | int mesh_path_send_to_gates(struct mesh_path *mpath); |
@@ -271,20 +291,22 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
271 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); | 291 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); |
272 | u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); | 292 | u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); |
273 | void mesh_plink_broken(struct sta_info *sta); | 293 | void mesh_plink_broken(struct sta_info *sta); |
274 | void mesh_plink_deactivate(struct sta_info *sta); | 294 | u32 mesh_plink_deactivate(struct sta_info *sta); |
275 | int mesh_plink_open(struct sta_info *sta); | 295 | u32 mesh_plink_open(struct sta_info *sta); |
276 | void mesh_plink_block(struct sta_info *sta); | 296 | u32 mesh_plink_block(struct sta_info *sta); |
277 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | 297 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, |
278 | struct ieee80211_mgmt *mgmt, size_t len, | 298 | struct ieee80211_mgmt *mgmt, size_t len, |
279 | struct ieee80211_rx_status *rx_status); | 299 | struct ieee80211_rx_status *rx_status); |
300 | void mesh_sta_cleanup(struct sta_info *sta); | ||
280 | 301 | ||
281 | /* Private interfaces */ | 302 | /* Private interfaces */ |
282 | /* Mesh tables */ | 303 | /* Mesh tables */ |
283 | void mesh_mpath_table_grow(void); | 304 | void mesh_mpath_table_grow(void); |
284 | void mesh_mpp_table_grow(void); | 305 | void mesh_mpp_table_grow(void); |
285 | /* Mesh paths */ | 306 | /* Mesh paths */ |
286 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, | 307 | int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn, |
287 | const u8 *ra, struct ieee80211_sub_if_data *sdata); | 308 | __le16 target_rcode, const u8 *ra, |
309 | struct ieee80211_sub_if_data *sdata); | ||
288 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 310 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
289 | void mesh_path_flush_pending(struct mesh_path *mpath); | 311 | void mesh_path_flush_pending(struct mesh_path *mpath); |
290 | void mesh_path_tx_pending(struct mesh_path *mpath); | 312 | void mesh_path_tx_pending(struct mesh_path *mpath); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 6b4603a90031..585c1e26cca8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -30,14 +30,14 @@ | |||
30 | 30 | ||
31 | static void mesh_queue_preq(struct mesh_path *, u8); | 31 | static void mesh_queue_preq(struct mesh_path *, u8); |
32 | 32 | ||
33 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | 33 | static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae) |
34 | { | 34 | { |
35 | if (ae) | 35 | if (ae) |
36 | offset += 6; | 36 | offset += 6; |
37 | return get_unaligned_le32(preq_elem + offset); | 37 | return get_unaligned_le32(preq_elem + offset); |
38 | } | 38 | } |
39 | 39 | ||
40 | static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) | 40 | static inline u32 u16_field_get(const u8 *preq_elem, int offset, bool ae) |
41 | { | 41 | { |
42 | if (ae) | 42 | if (ae) |
43 | offset += 6; | 43 | offset += 6; |
@@ -102,10 +102,13 @@ enum mpath_frame_type { | |||
102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
103 | 103 | ||
104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
105 | u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, | 105 | const u8 *orig_addr, __le32 orig_sn, |
106 | __le32 target_sn, const u8 *da, u8 hop_count, u8 ttl, | 106 | u8 target_flags, const u8 *target, |
107 | __le32 lifetime, __le32 metric, __le32 preq_id, | 107 | __le32 target_sn, const u8 *da, |
108 | struct ieee80211_sub_if_data *sdata) | 108 | u8 hop_count, u8 ttl, |
109 | __le32 lifetime, __le32 metric, | ||
110 | __le32 preq_id, | ||
111 | struct ieee80211_sub_if_data *sdata) | ||
109 | { | 112 | { |
110 | struct ieee80211_local *local = sdata->local; | 113 | struct ieee80211_local *local = sdata->local; |
111 | struct sk_buff *skb; | 114 | struct sk_buff *skb; |
@@ -205,6 +208,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, | |||
205 | struct sk_buff *skb) | 208 | struct sk_buff *skb) |
206 | { | 209 | { |
207 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 210 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
211 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
208 | 212 | ||
209 | skb_set_mac_header(skb, 0); | 213 | skb_set_mac_header(skb, 0); |
210 | skb_set_network_header(skb, 0); | 214 | skb_set_network_header(skb, 0); |
@@ -217,6 +221,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, | |||
217 | info->control.vif = &sdata->vif; | 221 | info->control.vif = &sdata->vif; |
218 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 222 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
219 | ieee80211_set_qos_hdr(sdata, skb); | 223 | ieee80211_set_qos_hdr(sdata, skb); |
224 | ieee80211_mps_set_frame_flags(sdata, NULL, hdr); | ||
220 | } | 225 | } |
221 | 226 | ||
222 | /** | 227 | /** |
@@ -233,7 +238,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, | |||
233 | * also acquires in the TX path. To avoid a deadlock we don't transmit the | 238 | * also acquires in the TX path. To avoid a deadlock we don't transmit the |
234 | * frame directly but add it to the pending queue instead. | 239 | * frame directly but add it to the pending queue instead. |
235 | */ | 240 | */ |
236 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, | 241 | int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn, |
237 | __le16 target_rcode, const u8 *ra, | 242 | __le16 target_rcode, const u8 *ra, |
238 | struct ieee80211_sub_if_data *sdata) | 243 | struct ieee80211_sub_if_data *sdata) |
239 | { | 244 | { |
@@ -367,14 +372,14 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, | |||
367 | * path routing information is updated. | 372 | * path routing information is updated. |
368 | */ | 373 | */ |
369 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | 374 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, |
370 | struct ieee80211_mgmt *mgmt, | 375 | struct ieee80211_mgmt *mgmt, |
371 | u8 *hwmp_ie, enum mpath_frame_type action) | 376 | const u8 *hwmp_ie, enum mpath_frame_type action) |
372 | { | 377 | { |
373 | struct ieee80211_local *local = sdata->local; | 378 | struct ieee80211_local *local = sdata->local; |
374 | struct mesh_path *mpath; | 379 | struct mesh_path *mpath; |
375 | struct sta_info *sta; | 380 | struct sta_info *sta; |
376 | bool fresh_info; | 381 | bool fresh_info; |
377 | u8 *orig_addr, *ta; | 382 | const u8 *orig_addr, *ta; |
378 | u32 orig_sn, orig_metric; | 383 | u32 orig_sn, orig_metric; |
379 | unsigned long orig_lifetime, exp_time; | 384 | unsigned long orig_lifetime, exp_time; |
380 | u32 last_hop_metric, new_metric; | 385 | u32 last_hop_metric, new_metric; |
@@ -509,11 +514,11 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
509 | 514 | ||
510 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | 515 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, |
511 | struct ieee80211_mgmt *mgmt, | 516 | struct ieee80211_mgmt *mgmt, |
512 | u8 *preq_elem, u32 metric) | 517 | const u8 *preq_elem, u32 metric) |
513 | { | 518 | { |
514 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 519 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
515 | struct mesh_path *mpath = NULL; | 520 | struct mesh_path *mpath = NULL; |
516 | u8 *target_addr, *orig_addr; | 521 | const u8 *target_addr, *orig_addr; |
517 | const u8 *da; | 522 | const u8 *da; |
518 | u8 target_flags, ttl, flags; | 523 | u8 target_flags, ttl, flags; |
519 | u32 orig_sn, target_sn, lifetime, orig_metric; | 524 | u32 orig_sn, target_sn, lifetime, orig_metric; |
@@ -646,11 +651,11 @@ next_hop_deref_protected(struct mesh_path *mpath) | |||
646 | 651 | ||
647 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | 652 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, |
648 | struct ieee80211_mgmt *mgmt, | 653 | struct ieee80211_mgmt *mgmt, |
649 | u8 *prep_elem, u32 metric) | 654 | const u8 *prep_elem, u32 metric) |
650 | { | 655 | { |
651 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 656 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
652 | struct mesh_path *mpath; | 657 | struct mesh_path *mpath; |
653 | u8 *target_addr, *orig_addr; | 658 | const u8 *target_addr, *orig_addr; |
654 | u8 ttl, hopcount, flags; | 659 | u8 ttl, hopcount, flags; |
655 | u8 next_hop[ETH_ALEN]; | 660 | u8 next_hop[ETH_ALEN]; |
656 | u32 target_sn, orig_sn, lifetime; | 661 | u32 target_sn, orig_sn, lifetime; |
@@ -709,12 +714,13 @@ fail: | |||
709 | } | 714 | } |
710 | 715 | ||
711 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | 716 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, |
712 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) | 717 | struct ieee80211_mgmt *mgmt, |
718 | const u8 *perr_elem) | ||
713 | { | 719 | { |
714 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 720 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
715 | struct mesh_path *mpath; | 721 | struct mesh_path *mpath; |
716 | u8 ttl; | 722 | u8 ttl; |
717 | u8 *ta, *target_addr; | 723 | const u8 *ta, *target_addr; |
718 | u32 target_sn; | 724 | u32 target_sn; |
719 | u16 target_rcode; | 725 | u16 target_rcode; |
720 | 726 | ||
@@ -756,15 +762,15 @@ endperr: | |||
756 | } | 762 | } |
757 | 763 | ||
758 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | 764 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, |
759 | struct ieee80211_mgmt *mgmt, | 765 | struct ieee80211_mgmt *mgmt, |
760 | struct ieee80211_rann_ie *rann) | 766 | const struct ieee80211_rann_ie *rann) |
761 | { | 767 | { |
762 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 768 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
763 | struct ieee80211_local *local = sdata->local; | 769 | struct ieee80211_local *local = sdata->local; |
764 | struct sta_info *sta; | 770 | struct sta_info *sta; |
765 | struct mesh_path *mpath; | 771 | struct mesh_path *mpath; |
766 | u8 ttl, flags, hopcount; | 772 | u8 ttl, flags, hopcount; |
767 | u8 *orig_addr; | 773 | const u8 *orig_addr; |
768 | u32 orig_sn, metric, metric_txsta, interval; | 774 | u32 orig_sn, metric, metric_txsta, interval; |
769 | bool root_is_gate; | 775 | bool root_is_gate; |
770 | 776 | ||
@@ -1080,6 +1086,10 @@ int mesh_nexthop_resolve(struct sk_buff *skb, | |||
1080 | u8 *target_addr = hdr->addr3; | 1086 | u8 *target_addr = hdr->addr3; |
1081 | int err = 0; | 1087 | int err = 0; |
1082 | 1088 | ||
1089 | /* Nulls are only sent to peers for PS and should be pre-addressed */ | ||
1090 | if (ieee80211_is_qos_nullfunc(hdr->frame_control)) | ||
1091 | return 0; | ||
1092 | |||
1083 | rcu_read_lock(); | 1093 | rcu_read_lock(); |
1084 | err = mesh_nexthop_lookup(skb, sdata); | 1094 | err = mesh_nexthop_lookup(skb, sdata); |
1085 | if (!err) | 1095 | if (!err) |
@@ -1151,6 +1161,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
1151 | if (next_hop) { | 1161 | if (next_hop) { |
1152 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); | 1162 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); |
1153 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | 1163 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
1164 | ieee80211_mps_set_frame_flags(sdata, next_hop, hdr); | ||
1154 | err = 0; | 1165 | err = 0; |
1155 | } | 1166 | } |
1156 | 1167 | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index aa749818860e..2ce4c4023a97 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -181,7 +181,7 @@ errcopy: | |||
181 | return -ENOMEM; | 181 | return -ENOMEM; |
182 | } | 182 | } |
183 | 183 | ||
184 | static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 184 | static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata, |
185 | struct mesh_table *tbl) | 185 | struct mesh_table *tbl) |
186 | { | 186 | { |
187 | /* Use last four bytes of hw addr and interface index as hash index */ | 187 | /* Use last four bytes of hw addr and interface index as hash index */ |
@@ -212,6 +212,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | |||
212 | hdr = (struct ieee80211_hdr *) skb->data; | 212 | hdr = (struct ieee80211_hdr *) skb->data; |
213 | memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); | 213 | memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); |
214 | memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); | 214 | memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); |
215 | ieee80211_mps_set_frame_flags(sta->sdata, sta, hdr); | ||
215 | } | 216 | } |
216 | 217 | ||
217 | spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); | 218 | spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); |
@@ -325,8 +326,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, | |||
325 | } | 326 | } |
326 | 327 | ||
327 | 328 | ||
328 | static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, | 329 | static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst, |
329 | struct ieee80211_sub_if_data *sdata) | 330 | struct ieee80211_sub_if_data *sdata) |
330 | { | 331 | { |
331 | struct mesh_path *mpath; | 332 | struct mesh_path *mpath; |
332 | struct hlist_node *n; | 333 | struct hlist_node *n; |
@@ -358,7 +359,8 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, | |||
358 | * | 359 | * |
359 | * Locking: must be called within a read rcu section. | 360 | * Locking: must be called within a read rcu section. |
360 | */ | 361 | */ |
361 | struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | 362 | struct mesh_path *mesh_path_lookup(const u8 *dst, |
363 | struct ieee80211_sub_if_data *sdata) | ||
362 | { | 364 | { |
363 | return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); | 365 | return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); |
364 | } | 366 | } |
@@ -493,7 +495,7 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata) | |||
493 | * | 495 | * |
494 | * State: the initial state of the new path is set to 0 | 496 | * State: the initial state of the new path is set to 0 |
495 | */ | 497 | */ |
496 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | 498 | int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata) |
497 | { | 499 | { |
498 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 500 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
499 | struct ieee80211_local *local = sdata->local; | 501 | struct ieee80211_local *local = sdata->local; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 81e612682bc3..f7526e509aa8 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -55,6 +55,66 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) | |||
55 | sta->plink_retries = 0; | 55 | sta->plink_retries = 0; |
56 | } | 56 | } |
57 | 57 | ||
58 | /* | ||
59 | * mesh_set_short_slot_time - enable / disable ERP short slot time. | ||
60 | * | ||
61 | * The standard indirectly mandates mesh STAs to turn off short slot time by | ||
62 | * disallowing advertising this (802.11-2012 8.4.1.4), but that doesn't mean we | ||
63 | * can't be sneaky about it. Enable short slot time if all mesh STAs in the | ||
64 | * MBSS support ERP rates. | ||
65 | * | ||
66 | * Returns BSS_CHANGED_ERP_SLOT or 0 for no change. | ||
67 | */ | ||
68 | static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) | ||
69 | { | ||
70 | struct ieee80211_local *local = sdata->local; | ||
71 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
72 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; | ||
73 | struct sta_info *sta; | ||
74 | u32 erp_rates = 0, changed = 0; | ||
75 | int i; | ||
76 | bool short_slot = false; | ||
77 | |||
78 | if (band == IEEE80211_BAND_5GHZ) { | ||
79 | /* (IEEE 802.11-2012 19.4.5) */ | ||
80 | short_slot = true; | ||
81 | goto out; | ||
82 | } else if (band != IEEE80211_BAND_2GHZ || | ||
83 | (band == IEEE80211_BAND_2GHZ && | ||
84 | local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
85 | goto out; | ||
86 | |||
87 | for (i = 0; i < sband->n_bitrates; i++) | ||
88 | if (sband->bitrates[i].flags & IEEE80211_RATE_ERP_G) | ||
89 | erp_rates |= BIT(i); | ||
90 | |||
91 | if (!erp_rates) | ||
92 | goto out; | ||
93 | |||
94 | rcu_read_lock(); | ||
95 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
96 | if (sdata != sta->sdata || | ||
97 | sta->plink_state != NL80211_PLINK_ESTAB) | ||
98 | continue; | ||
99 | |||
100 | short_slot = false; | ||
101 | if (erp_rates & sta->sta.supp_rates[band]) | ||
102 | short_slot = true; | ||
103 | else | ||
104 | break; | ||
105 | } | ||
106 | rcu_read_unlock(); | ||
107 | |||
108 | out: | ||
109 | if (sdata->vif.bss_conf.use_short_slot != short_slot) { | ||
110 | sdata->vif.bss_conf.use_short_slot = short_slot; | ||
111 | changed = BSS_CHANGED_ERP_SLOT; | ||
112 | mpl_dbg(sdata, "mesh_plink %pM: ERP short slot time %d\n", | ||
113 | sdata->vif.addr, short_slot); | ||
114 | } | ||
115 | return changed; | ||
116 | } | ||
117 | |||
58 | /** | 118 | /** |
59 | * mesh_set_ht_prot_mode - set correct HT protection mode | 119 | * mesh_set_ht_prot_mode - set correct HT protection mode |
60 | * | 120 | * |
@@ -141,6 +201,9 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta) | |||
141 | sta->plink_state = NL80211_PLINK_BLOCKED; | 201 | sta->plink_state = NL80211_PLINK_BLOCKED; |
142 | mesh_path_flush_by_nexthop(sta); | 202 | mesh_path_flush_by_nexthop(sta); |
143 | 203 | ||
204 | ieee80211_mps_sta_status_update(sta); | ||
205 | changed |= ieee80211_mps_local_status_update(sdata); | ||
206 | |||
144 | return changed; | 207 | return changed; |
145 | } | 208 | } |
146 | 209 | ||
@@ -151,7 +214,7 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta) | |||
151 | * | 214 | * |
152 | * All mesh paths with this peer as next hop will be flushed | 215 | * All mesh paths with this peer as next hop will be flushed |
153 | */ | 216 | */ |
154 | void mesh_plink_deactivate(struct sta_info *sta) | 217 | u32 mesh_plink_deactivate(struct sta_info *sta) |
155 | { | 218 | { |
156 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 219 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
157 | u32 changed; | 220 | u32 changed; |
@@ -164,7 +227,7 @@ void mesh_plink_deactivate(struct sta_info *sta) | |||
164 | sta->reason); | 227 | sta->reason); |
165 | spin_unlock_bh(&sta->lock); | 228 | spin_unlock_bh(&sta->lock); |
166 | 229 | ||
167 | ieee80211_bss_info_change_notify(sdata, changed); | 230 | return changed; |
168 | } | 231 | } |
169 | 232 | ||
170 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 233 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
@@ -310,8 +373,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
310 | if (elems->ht_cap_elem && | 373 | if (elems->ht_cap_elem && |
311 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | 374 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
312 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 375 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
313 | elems->ht_cap_elem, | 376 | elems->ht_cap_elem, sta); |
314 | &sta->sta.ht_cap); | ||
315 | else | 377 | else |
316 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); | 378 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); |
317 | 379 | ||
@@ -320,8 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
320 | 382 | ||
321 | if (!(elems->ht_operation->ht_param & | 383 | if (!(elems->ht_operation->ht_param & |
322 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 384 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) |
323 | sta->sta.ht_cap.cap &= | 385 | sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; |
324 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
325 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, | 386 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
326 | elems->ht_operation, &chandef); | 387 | elems->ht_operation, &chandef); |
327 | if (sta->ch_width != chandef.width) | 388 | if (sta->ch_width != chandef.width) |
@@ -431,6 +492,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
431 | struct ieee802_11_elems *elems) | 492 | struct ieee802_11_elems *elems) |
432 | { | 493 | { |
433 | struct sta_info *sta; | 494 | struct sta_info *sta; |
495 | u32 changed = 0; | ||
434 | 496 | ||
435 | sta = mesh_sta_info_get(sdata, hw_addr, elems); | 497 | sta = mesh_sta_info_get(sdata, hw_addr, elems); |
436 | if (!sta) | 498 | if (!sta) |
@@ -441,10 +503,12 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
441 | sdata->u.mesh.accepting_plinks && | 503 | sdata->u.mesh.accepting_plinks && |
442 | sdata->u.mesh.mshcfg.auto_open_plinks && | 504 | sdata->u.mesh.mshcfg.auto_open_plinks && |
443 | rssi_threshold_check(sta, sdata)) | 505 | rssi_threshold_check(sta, sdata)) |
444 | mesh_plink_open(sta); | 506 | changed = mesh_plink_open(sta); |
445 | 507 | ||
508 | ieee80211_mps_frame_release(sta, elems); | ||
446 | out: | 509 | out: |
447 | rcu_read_unlock(); | 510 | rcu_read_unlock(); |
511 | ieee80211_mbss_info_change_notify(sdata, changed); | ||
448 | } | 512 | } |
449 | 513 | ||
450 | static void mesh_plink_timer(unsigned long data) | 514 | static void mesh_plink_timer(unsigned long data) |
@@ -528,6 +592,13 @@ static void mesh_plink_timer(unsigned long data) | |||
528 | #ifdef CONFIG_PM | 592 | #ifdef CONFIG_PM |
529 | void mesh_plink_quiesce(struct sta_info *sta) | 593 | void mesh_plink_quiesce(struct sta_info *sta) |
530 | { | 594 | { |
595 | if (!ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
596 | return; | ||
597 | |||
598 | /* no kernel mesh sta timers have been initialized */ | ||
599 | if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | ||
600 | return; | ||
601 | |||
531 | if (del_timer_sync(&sta->plink_timer)) | 602 | if (del_timer_sync(&sta->plink_timer)) |
532 | sta->plink_timer_was_running = true; | 603 | sta->plink_timer_was_running = true; |
533 | } | 604 | } |
@@ -550,13 +621,14 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | |||
550 | add_timer(&sta->plink_timer); | 621 | add_timer(&sta->plink_timer); |
551 | } | 622 | } |
552 | 623 | ||
553 | int mesh_plink_open(struct sta_info *sta) | 624 | u32 mesh_plink_open(struct sta_info *sta) |
554 | { | 625 | { |
555 | __le16 llid; | 626 | __le16 llid; |
556 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 627 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
628 | u32 changed; | ||
557 | 629 | ||
558 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) | 630 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) |
559 | return -EPERM; | 631 | return 0; |
560 | 632 | ||
561 | spin_lock_bh(&sta->lock); | 633 | spin_lock_bh(&sta->lock); |
562 | get_random_bytes(&llid, 2); | 634 | get_random_bytes(&llid, 2); |
@@ -564,7 +636,7 @@ int mesh_plink_open(struct sta_info *sta) | |||
564 | if (sta->plink_state != NL80211_PLINK_LISTEN && | 636 | if (sta->plink_state != NL80211_PLINK_LISTEN && |
565 | sta->plink_state != NL80211_PLINK_BLOCKED) { | 637 | sta->plink_state != NL80211_PLINK_BLOCKED) { |
566 | spin_unlock_bh(&sta->lock); | 638 | spin_unlock_bh(&sta->lock); |
567 | return -EBUSY; | 639 | return 0; |
568 | } | 640 | } |
569 | sta->plink_state = NL80211_PLINK_OPN_SNT; | 641 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
570 | mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); | 642 | mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); |
@@ -573,13 +645,16 @@ int mesh_plink_open(struct sta_info *sta) | |||
573 | "Mesh plink: starting establishment with %pM\n", | 645 | "Mesh plink: starting establishment with %pM\n", |
574 | sta->sta.addr); | 646 | sta->sta.addr); |
575 | 647 | ||
576 | return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | 648 | /* set the non-peer mode to active during peering */ |
577 | sta->sta.addr, llid, 0, 0); | 649 | changed = ieee80211_mps_local_status_update(sdata); |
650 | |||
651 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | ||
652 | sta->sta.addr, llid, 0, 0); | ||
653 | return changed; | ||
578 | } | 654 | } |
579 | 655 | ||
580 | void mesh_plink_block(struct sta_info *sta) | 656 | u32 mesh_plink_block(struct sta_info *sta) |
581 | { | 657 | { |
582 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
583 | u32 changed; | 658 | u32 changed; |
584 | 659 | ||
585 | spin_lock_bh(&sta->lock); | 660 | spin_lock_bh(&sta->lock); |
@@ -587,7 +662,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
587 | sta->plink_state = NL80211_PLINK_BLOCKED; | 662 | sta->plink_state = NL80211_PLINK_BLOCKED; |
588 | spin_unlock_bh(&sta->lock); | 663 | spin_unlock_bh(&sta->lock); |
589 | 664 | ||
590 | ieee80211_bss_info_change_notify(sdata, changed); | 665 | return changed; |
591 | } | 666 | } |
592 | 667 | ||
593 | 668 | ||
@@ -806,6 +881,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
806 | sta->llid = llid; | 881 | sta->llid = llid; |
807 | mesh_plink_timer_set(sta, | 882 | mesh_plink_timer_set(sta, |
808 | mshcfg->dot11MeshRetryTimeout); | 883 | mshcfg->dot11MeshRetryTimeout); |
884 | |||
885 | /* set the non-peer mode to active during peering */ | ||
886 | changed |= ieee80211_mps_local_status_update(sdata); | ||
887 | |||
809 | spin_unlock_bh(&sta->lock); | 888 | spin_unlock_bh(&sta->lock); |
810 | mesh_plink_frame_tx(sdata, | 889 | mesh_plink_frame_tx(sdata, |
811 | WLAN_SP_MESH_PEERING_OPEN, | 890 | WLAN_SP_MESH_PEERING_OPEN, |
@@ -896,8 +975,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
896 | spin_unlock_bh(&sta->lock); | 975 | spin_unlock_bh(&sta->lock); |
897 | changed |= mesh_plink_inc_estab_count(sdata); | 976 | changed |= mesh_plink_inc_estab_count(sdata); |
898 | changed |= mesh_set_ht_prot_mode(sdata); | 977 | changed |= mesh_set_ht_prot_mode(sdata); |
978 | changed |= mesh_set_short_slot_time(sdata); | ||
899 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | 979 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", |
900 | sta->sta.addr); | 980 | sta->sta.addr); |
981 | ieee80211_mps_sta_status_update(sta); | ||
982 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
983 | mshcfg->power_mode); | ||
901 | break; | 984 | break; |
902 | default: | 985 | default: |
903 | spin_unlock_bh(&sta->lock); | 986 | spin_unlock_bh(&sta->lock); |
@@ -931,11 +1014,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
931 | spin_unlock_bh(&sta->lock); | 1014 | spin_unlock_bh(&sta->lock); |
932 | changed |= mesh_plink_inc_estab_count(sdata); | 1015 | changed |= mesh_plink_inc_estab_count(sdata); |
933 | changed |= mesh_set_ht_prot_mode(sdata); | 1016 | changed |= mesh_set_ht_prot_mode(sdata); |
1017 | changed |= mesh_set_short_slot_time(sdata); | ||
934 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | 1018 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", |
935 | sta->sta.addr); | 1019 | sta->sta.addr); |
936 | mesh_plink_frame_tx(sdata, | 1020 | mesh_plink_frame_tx(sdata, |
937 | WLAN_SP_MESH_PEERING_CONFIRM, | 1021 | WLAN_SP_MESH_PEERING_CONFIRM, |
938 | sta->sta.addr, llid, plid, 0); | 1022 | sta->sta.addr, llid, plid, 0); |
1023 | ieee80211_mps_sta_status_update(sta); | ||
1024 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
1025 | mshcfg->power_mode); | ||
939 | break; | 1026 | break; |
940 | default: | 1027 | default: |
941 | spin_unlock_bh(&sta->lock); | 1028 | spin_unlock_bh(&sta->lock); |
@@ -954,6 +1041,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
954 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); | 1041 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
955 | spin_unlock_bh(&sta->lock); | 1042 | spin_unlock_bh(&sta->lock); |
956 | changed |= mesh_set_ht_prot_mode(sdata); | 1043 | changed |= mesh_set_ht_prot_mode(sdata); |
1044 | changed |= mesh_set_short_slot_time(sdata); | ||
957 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 1045 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
958 | sta->sta.addr, llid, plid, reason); | 1046 | sta->sta.addr, llid, plid, reason); |
959 | break; | 1047 | break; |
@@ -1002,5 +1090,5 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
1002 | rcu_read_unlock(); | 1090 | rcu_read_unlock(); |
1003 | 1091 | ||
1004 | if (changed) | 1092 | if (changed) |
1005 | ieee80211_bss_info_change_notify(sdata, changed); | 1093 | ieee80211_mbss_info_change_notify(sdata, changed); |
1006 | } | 1094 | } |
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c new file mode 100644 index 000000000000..3b7bfc01ee36 --- /dev/null +++ b/net/mac80211/mesh_ps.c | |||
@@ -0,0 +1,598 @@ | |||
1 | /* | ||
2 | * Copyright 2012-2013, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de> | ||
3 | * Copyright 2012-2013, cozybit Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include "mesh.h" | ||
11 | #include "wme.h" | ||
12 | |||
13 | |||
14 | /* mesh PS management */ | ||
15 | |||
16 | /** | ||
17 | * mps_qos_null_get - create pre-addressed QoS Null frame for mesh powersave | ||
18 | */ | ||
19 | static struct sk_buff *mps_qos_null_get(struct sta_info *sta) | ||
20 | { | ||
21 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
22 | struct ieee80211_local *local = sdata->local; | ||
23 | struct ieee80211_hdr *nullfunc; /* use 4addr header */ | ||
24 | struct sk_buff *skb; | ||
25 | int size = sizeof(*nullfunc); | ||
26 | __le16 fc; | ||
27 | |||
28 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + size + 2); | ||
29 | if (!skb) | ||
30 | return NULL; | ||
31 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
32 | |||
33 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, size); | ||
34 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); | ||
35 | ieee80211_fill_mesh_addresses(nullfunc, &fc, sta->sta.addr, | ||
36 | sdata->vif.addr); | ||
37 | nullfunc->frame_control = fc; | ||
38 | nullfunc->duration_id = 0; | ||
39 | /* no address resolution for this frame -> set addr 1 immediately */ | ||
40 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); | ||
41 | memset(skb_put(skb, 2), 0, 2); /* append QoS control field */ | ||
42 | ieee80211_mps_set_frame_flags(sdata, sta, nullfunc); | ||
43 | |||
44 | return skb; | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * mps_qos_null_tx - send a QoS Null to indicate link-specific power mode | ||
49 | */ | ||
50 | static void mps_qos_null_tx(struct sta_info *sta) | ||
51 | { | ||
52 | struct sk_buff *skb; | ||
53 | |||
54 | skb = mps_qos_null_get(sta); | ||
55 | if (!skb) | ||
56 | return; | ||
57 | |||
58 | mps_dbg(sta->sdata, "announcing peer-specific power mode to %pM\n", | ||
59 | sta->sta.addr); | ||
60 | |||
61 | /* don't unintentionally start a MPSP */ | ||
62 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
63 | u8 *qc = ieee80211_get_qos_ctl((void *) skb->data); | ||
64 | |||
65 | qc[0] |= IEEE80211_QOS_CTL_EOSP; | ||
66 | } | ||
67 | |||
68 | ieee80211_tx_skb(sta->sdata, skb); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * ieee80211_mps_local_status_update - track status of local link-specific PMs | ||
73 | * | ||
74 | * @sdata: local mesh subif | ||
75 | * | ||
76 | * sets the non-peer power mode and triggers the driver PS (re-)configuration | ||
77 | * Return BSS_CHANGED_BEACON if a beacon update is necessary. | ||
78 | */ | ||
79 | u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) | ||
80 | { | ||
81 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
82 | struct sta_info *sta; | ||
83 | bool peering = false; | ||
84 | int light_sleep_cnt = 0; | ||
85 | int deep_sleep_cnt = 0; | ||
86 | u32 changed = 0; | ||
87 | enum nl80211_mesh_power_mode nonpeer_pm; | ||
88 | |||
89 | rcu_read_lock(); | ||
90 | list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { | ||
91 | if (sdata != sta->sdata) | ||
92 | continue; | ||
93 | |||
94 | switch (sta->plink_state) { | ||
95 | case NL80211_PLINK_OPN_SNT: | ||
96 | case NL80211_PLINK_OPN_RCVD: | ||
97 | case NL80211_PLINK_CNF_RCVD: | ||
98 | peering = true; | ||
99 | break; | ||
100 | case NL80211_PLINK_ESTAB: | ||
101 | if (sta->local_pm == NL80211_MESH_POWER_LIGHT_SLEEP) | ||
102 | light_sleep_cnt++; | ||
103 | else if (sta->local_pm == NL80211_MESH_POWER_DEEP_SLEEP) | ||
104 | deep_sleep_cnt++; | ||
105 | break; | ||
106 | default: | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | rcu_read_unlock(); | ||
111 | |||
112 | /* | ||
113 | * Set non-peer mode to active during peering/scanning/authentication | ||
114 | * (see IEEE802.11-2012 13.14.8.3). The non-peer mesh power mode is | ||
115 | * deep sleep if the local STA is in light or deep sleep towards at | ||
116 | * least one mesh peer (see 13.14.3.1). Otherwise, set it to the | ||
117 | * user-configured default value. | ||
118 | */ | ||
119 | if (peering) { | ||
120 | mps_dbg(sdata, "setting non-peer PM to active for peering\n"); | ||
121 | nonpeer_pm = NL80211_MESH_POWER_ACTIVE; | ||
122 | } else if (light_sleep_cnt || deep_sleep_cnt) { | ||
123 | mps_dbg(sdata, "setting non-peer PM to deep sleep\n"); | ||
124 | nonpeer_pm = NL80211_MESH_POWER_DEEP_SLEEP; | ||
125 | } else { | ||
126 | mps_dbg(sdata, "setting non-peer PM to user value\n"); | ||
127 | nonpeer_pm = ifmsh->mshcfg.power_mode; | ||
128 | } | ||
129 | |||
130 | /* need update if sleep counts move between 0 and non-zero */ | ||
131 | if (ifmsh->nonpeer_pm != nonpeer_pm || | ||
132 | !ifmsh->ps_peers_light_sleep != !light_sleep_cnt || | ||
133 | !ifmsh->ps_peers_deep_sleep != !deep_sleep_cnt) | ||
134 | changed = BSS_CHANGED_BEACON; | ||
135 | |||
136 | ifmsh->nonpeer_pm = nonpeer_pm; | ||
137 | ifmsh->ps_peers_light_sleep = light_sleep_cnt; | ||
138 | ifmsh->ps_peers_deep_sleep = deep_sleep_cnt; | ||
139 | |||
140 | return changed; | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * ieee80211_mps_set_sta_local_pm - set local PM towards a mesh STA | ||
145 | * | ||
146 | * @sta: mesh STA | ||
147 | * @pm: the power mode to set | ||
148 | * Return BSS_CHANGED_BEACON if a beacon update is in order. | ||
149 | */ | ||
150 | u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, | ||
151 | enum nl80211_mesh_power_mode pm) | ||
152 | { | ||
153 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
154 | |||
155 | mps_dbg(sdata, "local STA operates in mode %d with %pM\n", | ||
156 | pm, sta->sta.addr); | ||
157 | |||
158 | sta->local_pm = pm; | ||
159 | |||
160 | /* | ||
161 | * announce peer-specific power mode transition | ||
162 | * (see IEEE802.11-2012 13.14.3.2 and 13.14.3.3) | ||
163 | */ | ||
164 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
165 | mps_qos_null_tx(sta); | ||
166 | |||
167 | return ieee80211_mps_local_status_update(sdata); | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * ieee80211_mps_set_frame_flags - set mesh PS flags in FC (and QoS Control) | ||
172 | * | ||
173 | * @sdata: local mesh subif | ||
174 | * @sta: mesh STA | ||
175 | * @hdr: 802.11 frame header | ||
176 | * | ||
177 | * see IEEE802.11-2012 8.2.4.1.7 and 8.2.4.5.11 | ||
178 | * | ||
179 | * NOTE: sta must be given when an individually-addressed QoS frame header | ||
180 | * is handled, for group-addressed and management frames it is not used | ||
181 | */ | ||
182 | void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, | ||
183 | struct sta_info *sta, | ||
184 | struct ieee80211_hdr *hdr) | ||
185 | { | ||
186 | enum nl80211_mesh_power_mode pm; | ||
187 | u8 *qc; | ||
188 | |||
189 | if (WARN_ON(is_unicast_ether_addr(hdr->addr1) && | ||
190 | ieee80211_is_data_qos(hdr->frame_control) && | ||
191 | !sta)) | ||
192 | return; | ||
193 | |||
194 | if (is_unicast_ether_addr(hdr->addr1) && | ||
195 | ieee80211_is_data_qos(hdr->frame_control) && | ||
196 | sta->plink_state == NL80211_PLINK_ESTAB) | ||
197 | pm = sta->local_pm; | ||
198 | else | ||
199 | pm = sdata->u.mesh.nonpeer_pm; | ||
200 | |||
201 | if (pm == NL80211_MESH_POWER_ACTIVE) | ||
202 | hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_PM); | ||
203 | else | ||
204 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
205 | |||
206 | if (!ieee80211_is_data_qos(hdr->frame_control)) | ||
207 | return; | ||
208 | |||
209 | qc = ieee80211_get_qos_ctl(hdr); | ||
210 | |||
211 | if ((is_unicast_ether_addr(hdr->addr1) && | ||
212 | pm == NL80211_MESH_POWER_DEEP_SLEEP) || | ||
213 | (is_multicast_ether_addr(hdr->addr1) && | ||
214 | sdata->u.mesh.ps_peers_deep_sleep > 0)) | ||
215 | qc[1] |= (IEEE80211_QOS_CTL_MESH_PS_LEVEL >> 8); | ||
216 | else | ||
217 | qc[1] &= ~(IEEE80211_QOS_CTL_MESH_PS_LEVEL >> 8); | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * ieee80211_mps_sta_status_update - update buffering status of neighbor STA | ||
222 | * | ||
223 | * @sta: mesh STA | ||
224 | * | ||
225 | * called after change of peering status or non-peer/peer-specific power mode | ||
226 | */ | ||
227 | void ieee80211_mps_sta_status_update(struct sta_info *sta) | ||
228 | { | ||
229 | enum nl80211_mesh_power_mode pm; | ||
230 | bool do_buffer; | ||
231 | |||
232 | /* | ||
233 | * use peer-specific power mode if peering is established and the | ||
234 | * peer's power mode is known | ||
235 | */ | ||
236 | if (sta->plink_state == NL80211_PLINK_ESTAB && | ||
237 | sta->peer_pm != NL80211_MESH_POWER_UNKNOWN) | ||
238 | pm = sta->peer_pm; | ||
239 | else | ||
240 | pm = sta->nonpeer_pm; | ||
241 | |||
242 | do_buffer = (pm != NL80211_MESH_POWER_ACTIVE); | ||
243 | |||
244 | /* Don't let the same PS state be set twice */ | ||
245 | if (test_sta_flag(sta, WLAN_STA_PS_STA) == do_buffer) | ||
246 | return; | ||
247 | |||
248 | if (do_buffer) { | ||
249 | set_sta_flag(sta, WLAN_STA_PS_STA); | ||
250 | atomic_inc(&sta->sdata->u.mesh.ps.num_sta_ps); | ||
251 | mps_dbg(sta->sdata, "start PS buffering frames towards %pM\n", | ||
252 | sta->sta.addr); | ||
253 | } else { | ||
254 | ieee80211_sta_ps_deliver_wakeup(sta); | ||
255 | } | ||
256 | |||
257 | /* clear the MPSP flags for non-peers or active STA */ | ||
258 | if (sta->plink_state != NL80211_PLINK_ESTAB) { | ||
259 | clear_sta_flag(sta, WLAN_STA_MPSP_OWNER); | ||
260 | clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); | ||
261 | } else if (!do_buffer) { | ||
262 | clear_sta_flag(sta, WLAN_STA_MPSP_OWNER); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static void mps_set_sta_peer_pm(struct sta_info *sta, | ||
267 | struct ieee80211_hdr *hdr) | ||
268 | { | ||
269 | enum nl80211_mesh_power_mode pm; | ||
270 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
271 | |||
272 | /* | ||
273 | * Test Power Management field of frame control (PW) and | ||
274 | * mesh power save level subfield of QoS control field (PSL) | ||
275 | * | ||
276 | * | PM | PSL| Mesh PM | | ||
277 | * +----+----+---------+ | ||
278 | * | 0 |Rsrv| Active | | ||
279 | * | 1 | 0 | Light | | ||
280 | * | 1 | 1 | Deep | | ||
281 | */ | ||
282 | if (ieee80211_has_pm(hdr->frame_control)) { | ||
283 | if (qc[1] & (IEEE80211_QOS_CTL_MESH_PS_LEVEL >> 8)) | ||
284 | pm = NL80211_MESH_POWER_DEEP_SLEEP; | ||
285 | else | ||
286 | pm = NL80211_MESH_POWER_LIGHT_SLEEP; | ||
287 | } else { | ||
288 | pm = NL80211_MESH_POWER_ACTIVE; | ||
289 | } | ||
290 | |||
291 | if (sta->peer_pm == pm) | ||
292 | return; | ||
293 | |||
294 | mps_dbg(sta->sdata, "STA %pM enters mode %d\n", | ||
295 | sta->sta.addr, pm); | ||
296 | |||
297 | sta->peer_pm = pm; | ||
298 | |||
299 | ieee80211_mps_sta_status_update(sta); | ||
300 | } | ||
301 | |||
302 | static void mps_set_sta_nonpeer_pm(struct sta_info *sta, | ||
303 | struct ieee80211_hdr *hdr) | ||
304 | { | ||
305 | enum nl80211_mesh_power_mode pm; | ||
306 | |||
307 | if (ieee80211_has_pm(hdr->frame_control)) | ||
308 | pm = NL80211_MESH_POWER_DEEP_SLEEP; | ||
309 | else | ||
310 | pm = NL80211_MESH_POWER_ACTIVE; | ||
311 | |||
312 | if (sta->nonpeer_pm == pm) | ||
313 | return; | ||
314 | |||
315 | mps_dbg(sta->sdata, "STA %pM sets non-peer mode to %d\n", | ||
316 | sta->sta.addr, pm); | ||
317 | |||
318 | sta->nonpeer_pm = pm; | ||
319 | |||
320 | ieee80211_mps_sta_status_update(sta); | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * ieee80211_mps_rx_h_sta_process - frame receive handler for mesh powersave | ||
325 | * | ||
326 | * @sta: STA info that transmitted the frame | ||
327 | * @hdr: IEEE 802.11 (QoS) Header | ||
328 | */ | ||
329 | void ieee80211_mps_rx_h_sta_process(struct sta_info *sta, | ||
330 | struct ieee80211_hdr *hdr) | ||
331 | { | ||
332 | if (is_unicast_ether_addr(hdr->addr1) && | ||
333 | ieee80211_is_data_qos(hdr->frame_control)) { | ||
334 | /* | ||
335 | * individually addressed QoS Data/Null frames contain | ||
336 | * peer link-specific PS mode towards the local STA | ||
337 | */ | ||
338 | mps_set_sta_peer_pm(sta, hdr); | ||
339 | |||
340 | /* check for mesh Peer Service Period trigger frames */ | ||
341 | ieee80211_mpsp_trigger_process(ieee80211_get_qos_ctl(hdr), | ||
342 | sta, false, false); | ||
343 | } else { | ||
344 | /* | ||
345 | * can only determine non-peer PS mode | ||
346 | * (see IEEE802.11-2012 8.2.4.1.7) | ||
347 | */ | ||
348 | mps_set_sta_nonpeer_pm(sta, hdr); | ||
349 | } | ||
350 | } | ||
351 | |||
352 | |||
353 | /* mesh PS frame release */ | ||
354 | |||
355 | static void mpsp_trigger_send(struct sta_info *sta, bool rspi, bool eosp) | ||
356 | { | ||
357 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
358 | struct sk_buff *skb; | ||
359 | struct ieee80211_hdr *nullfunc; | ||
360 | struct ieee80211_tx_info *info; | ||
361 | u8 *qc; | ||
362 | |||
363 | skb = mps_qos_null_get(sta); | ||
364 | if (!skb) | ||
365 | return; | ||
366 | |||
367 | nullfunc = (struct ieee80211_hdr *) skb->data; | ||
368 | if (!eosp) | ||
369 | nullfunc->frame_control |= | ||
370 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
371 | /* | ||
372 | * | RSPI | EOSP | MPSP triggering | | ||
373 | * +------+------+--------------------+ | ||
374 | * | 0 | 0 | local STA is owner | | ||
375 | * | 0 | 1 | no MPSP (MPSP end) | | ||
376 | * | 1 | 0 | both STA are owner | | ||
377 | * | 1 | 1 | peer STA is owner | see IEEE802.11-2012 13.14.9.2 | ||
378 | */ | ||
379 | qc = ieee80211_get_qos_ctl(nullfunc); | ||
380 | if (rspi) | ||
381 | qc[1] |= (IEEE80211_QOS_CTL_RSPI >> 8); | ||
382 | if (eosp) | ||
383 | qc[0] |= IEEE80211_QOS_CTL_EOSP; | ||
384 | |||
385 | info = IEEE80211_SKB_CB(skb); | ||
386 | |||
387 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | | ||
388 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
389 | |||
390 | mps_dbg(sdata, "sending MPSP trigger%s%s to %pM\n", | ||
391 | rspi ? " RSPI" : "", eosp ? " EOSP" : "", sta->sta.addr); | ||
392 | |||
393 | ieee80211_tx_skb(sdata, skb); | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * mpsp_qos_null_append - append QoS Null frame to MPSP skb queue if needed | ||
398 | * | ||
399 | * To properly end a mesh MPSP the last transmitted frame has to set the EOSP | ||
400 | * flag in the QoS Control field. In case the current tailing frame is not a | ||
401 | * QoS Data frame, append a QoS Null to carry the flag. | ||
402 | */ | ||
403 | static void mpsp_qos_null_append(struct sta_info *sta, | ||
404 | struct sk_buff_head *frames) | ||
405 | { | ||
406 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
407 | struct sk_buff *new_skb, *skb = skb_peek_tail(frames); | ||
408 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
409 | struct ieee80211_tx_info *info; | ||
410 | |||
411 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
412 | return; | ||
413 | |||
414 | new_skb = mps_qos_null_get(sta); | ||
415 | if (!new_skb) | ||
416 | return; | ||
417 | |||
418 | mps_dbg(sdata, "appending QoS Null in MPSP towards %pM\n", | ||
419 | sta->sta.addr); | ||
420 | /* | ||
421 | * This frame has to be transmitted last. Assign lowest priority to | ||
422 | * make sure it cannot pass other frames when releasing multiple ACs. | ||
423 | */ | ||
424 | new_skb->priority = 1; | ||
425 | skb_set_queue_mapping(new_skb, IEEE80211_AC_BK); | ||
426 | ieee80211_set_qos_hdr(sdata, new_skb); | ||
427 | |||
428 | info = IEEE80211_SKB_CB(new_skb); | ||
429 | info->control.vif = &sdata->vif; | ||
430 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | ||
431 | |||
432 | __skb_queue_tail(frames, new_skb); | ||
433 | } | ||
434 | |||
435 | /** | ||
436 | * mps_frame_deliver - transmit frames during mesh powersave | ||
437 | * | ||
438 | * @sta: STA info to transmit to | ||
439 | * @n_frames: number of frames to transmit. -1 for all | ||
440 | */ | ||
441 | static void mps_frame_deliver(struct sta_info *sta, int n_frames) | ||
442 | { | ||
443 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
444 | struct ieee80211_local *local = sdata->local; | ||
445 | int ac; | ||
446 | struct sk_buff_head frames; | ||
447 | struct sk_buff *skb; | ||
448 | bool more_data = false; | ||
449 | |||
450 | skb_queue_head_init(&frames); | ||
451 | |||
452 | /* collect frame(s) from buffers */ | ||
453 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
454 | while (n_frames != 0) { | ||
455 | skb = skb_dequeue(&sta->tx_filtered[ac]); | ||
456 | if (!skb) { | ||
457 | skb = skb_dequeue( | ||
458 | &sta->ps_tx_buf[ac]); | ||
459 | if (skb) | ||
460 | local->total_ps_buffered--; | ||
461 | } | ||
462 | if (!skb) | ||
463 | break; | ||
464 | n_frames--; | ||
465 | __skb_queue_tail(&frames, skb); | ||
466 | } | ||
467 | |||
468 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || | ||
469 | !skb_queue_empty(&sta->ps_tx_buf[ac])) | ||
470 | more_data = true; | ||
471 | } | ||
472 | |||
473 | /* nothing to send? -> EOSP */ | ||
474 | if (skb_queue_empty(&frames)) { | ||
475 | mpsp_trigger_send(sta, false, true); | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | /* in a MPSP make sure the last skb is a QoS Data frame */ | ||
480 | if (test_sta_flag(sta, WLAN_STA_MPSP_OWNER)) | ||
481 | mpsp_qos_null_append(sta, &frames); | ||
482 | |||
483 | mps_dbg(sta->sdata, "sending %d frames to PS STA %pM\n", | ||
484 | skb_queue_len(&frames), sta->sta.addr); | ||
485 | |||
486 | /* prepare collected frames for transmission */ | ||
487 | skb_queue_walk(&frames, skb) { | ||
488 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
489 | struct ieee80211_hdr *hdr = (void *) skb->data; | ||
490 | |||
491 | /* | ||
492 | * Tell TX path to send this frame even though the | ||
493 | * STA may still remain is PS mode after this frame | ||
494 | * exchange. | ||
495 | */ | ||
496 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; | ||
497 | |||
498 | if (more_data || !skb_queue_is_last(&frames, skb)) | ||
499 | hdr->frame_control |= | ||
500 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
501 | else | ||
502 | hdr->frame_control &= | ||
503 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
504 | |||
505 | if (skb_queue_is_last(&frames, skb) && | ||
506 | ieee80211_is_data_qos(hdr->frame_control)) { | ||
507 | u8 *qoshdr = ieee80211_get_qos_ctl(hdr); | ||
508 | |||
509 | /* MPSP trigger frame ends service period */ | ||
510 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; | ||
511 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | ieee80211_add_pending_skbs(local, &frames); | ||
516 | sta_info_recalc_tim(sta); | ||
517 | } | ||
518 | |||
519 | /** | ||
520 | * ieee80211_mpsp_trigger_process - track status of mesh Peer Service Periods | ||
521 | * | ||
522 | * @qc: QoS Control field | ||
523 | * @sta: peer to start a MPSP with | ||
524 | * @tx: frame was transmitted by the local STA | ||
525 | * @acked: frame has been transmitted successfully | ||
526 | * | ||
527 | * NOTE: active mode STA may only serve as MPSP owner | ||
528 | */ | ||
529 | void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta, | ||
530 | bool tx, bool acked) | ||
531 | { | ||
532 | u8 rspi = qc[1] & (IEEE80211_QOS_CTL_RSPI >> 8); | ||
533 | u8 eosp = qc[0] & IEEE80211_QOS_CTL_EOSP; | ||
534 | |||
535 | if (tx) { | ||
536 | if (rspi && acked) | ||
537 | set_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); | ||
538 | |||
539 | if (eosp) | ||
540 | clear_sta_flag(sta, WLAN_STA_MPSP_OWNER); | ||
541 | else if (acked && | ||
542 | test_sta_flag(sta, WLAN_STA_PS_STA) && | ||
543 | !test_and_set_sta_flag(sta, WLAN_STA_MPSP_OWNER)) | ||
544 | mps_frame_deliver(sta, -1); | ||
545 | } else { | ||
546 | if (eosp) | ||
547 | clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); | ||
548 | else if (sta->local_pm != NL80211_MESH_POWER_ACTIVE) | ||
549 | set_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); | ||
550 | |||
551 | if (rspi && !test_and_set_sta_flag(sta, WLAN_STA_MPSP_OWNER)) | ||
552 | mps_frame_deliver(sta, -1); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | /** | ||
557 | * ieee80211_mps_frame_release - release buffered frames in response to beacon | ||
558 | * | ||
559 | * @sta: mesh STA | ||
560 | * @elems: beacon IEs | ||
561 | * | ||
562 | * For peers if we have individually-addressed frames buffered or the peer | ||
563 | * indicates buffered frames, send a corresponding MPSP trigger frame. Since | ||
564 | * we do not evaluate the awake window duration, QoS Nulls are used as MPSP | ||
565 | * trigger frames. If the neighbour STA is not a peer, only send single frames. | ||
566 | */ | ||
567 | void ieee80211_mps_frame_release(struct sta_info *sta, | ||
568 | struct ieee802_11_elems *elems) | ||
569 | { | ||
570 | int ac, buffer_local = 0; | ||
571 | bool has_buffered = false; | ||
572 | |||
573 | /* TIM map only for LLID <= IEEE80211_MAX_AID */ | ||
574 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
575 | has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, | ||
576 | le16_to_cpu(sta->llid) % IEEE80211_MAX_AID); | ||
577 | |||
578 | if (has_buffered) | ||
579 | mps_dbg(sta->sdata, "%pM indicates buffered frames\n", | ||
580 | sta->sta.addr); | ||
581 | |||
582 | /* only transmit to PS STA with announced, non-zero awake window */ | ||
583 | if (test_sta_flag(sta, WLAN_STA_PS_STA) && | ||
584 | (!elems->awake_window || !le16_to_cpu(*elems->awake_window))) | ||
585 | return; | ||
586 | |||
587 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
588 | buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) + | ||
589 | skb_queue_len(&sta->tx_filtered[ac]); | ||
590 | |||
591 | if (!has_buffered && !buffer_local) | ||
592 | return; | ||
593 | |||
594 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
595 | mpsp_trigger_send(sta, has_buffered, !buffer_local); | ||
596 | else | ||
597 | mps_frame_deliver(sta, 1); | ||
598 | } | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 72924399077e..9f6464f3e05f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -30,11 +30,13 @@ | |||
30 | #include "rate.h" | 30 | #include "rate.h" |
31 | #include "led.h" | 31 | #include "led.h" |
32 | 32 | ||
33 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 33 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
34 | #define IEEE80211_AUTH_MAX_TRIES 3 | 34 | #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10) |
35 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) | 35 | #define IEEE80211_AUTH_MAX_TRIES 3 |
36 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 36 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) |
37 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 37 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
38 | #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10) | ||
39 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
38 | 40 | ||
39 | static int max_nullfunc_tries = 2; | 41 | static int max_nullfunc_tries = 2; |
40 | module_param(max_nullfunc_tries, int, 0644); | 42 | module_param(max_nullfunc_tries, int, 0644); |
@@ -112,6 +114,9 @@ enum rx_mgmt_action { | |||
112 | 114 | ||
113 | /* caller must call cfg80211_send_assoc_timeout() */ | 115 | /* caller must call cfg80211_send_assoc_timeout() */ |
114 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, | 116 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, |
117 | |||
118 | /* used when a processed beacon causes a deauth */ | ||
119 | RX_MGMT_CFG80211_TX_DEAUTH, | ||
115 | }; | 120 | }; |
116 | 121 | ||
117 | /* utils */ | 122 | /* utils */ |
@@ -172,79 +177,331 @@ static int ecw2cw(int ecw) | |||
172 | return (1 << ecw) - 1; | 177 | return (1 << ecw) - 1; |
173 | } | 178 | } |
174 | 179 | ||
175 | static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | 180 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) |
176 | struct ieee80211_ht_operation *ht_oper, | 181 | { |
177 | const u8 *bssid, bool reconfig) | 182 | u32 ret; |
183 | int tmp; | ||
184 | |||
185 | switch (c->width) { | ||
186 | case NL80211_CHAN_WIDTH_20: | ||
187 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
188 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
189 | break; | ||
190 | case NL80211_CHAN_WIDTH_40: | ||
191 | c->width = NL80211_CHAN_WIDTH_20; | ||
192 | c->center_freq1 = c->chan->center_freq; | ||
193 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
194 | IEEE80211_STA_DISABLE_VHT; | ||
195 | break; | ||
196 | case NL80211_CHAN_WIDTH_80: | ||
197 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
198 | /* n_P40 */ | ||
199 | tmp /= 2; | ||
200 | /* freq_P40 */ | ||
201 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
202 | c->width = NL80211_CHAN_WIDTH_40; | ||
203 | ret = IEEE80211_STA_DISABLE_VHT; | ||
204 | break; | ||
205 | case NL80211_CHAN_WIDTH_80P80: | ||
206 | c->center_freq2 = 0; | ||
207 | c->width = NL80211_CHAN_WIDTH_80; | ||
208 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
209 | IEEE80211_STA_DISABLE_160MHZ; | ||
210 | break; | ||
211 | case NL80211_CHAN_WIDTH_160: | ||
212 | /* n_P20 */ | ||
213 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
214 | /* n_P80 */ | ||
215 | tmp /= 4; | ||
216 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
217 | c->width = NL80211_CHAN_WIDTH_80; | ||
218 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
219 | IEEE80211_STA_DISABLE_160MHZ; | ||
220 | break; | ||
221 | default: | ||
222 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
223 | WARN_ON_ONCE(1); | ||
224 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
225 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static u32 | ||
235 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | ||
236 | struct ieee80211_supported_band *sband, | ||
237 | struct ieee80211_channel *channel, | ||
238 | const struct ieee80211_ht_operation *ht_oper, | ||
239 | const struct ieee80211_vht_operation *vht_oper, | ||
240 | struct cfg80211_chan_def *chandef, bool verbose) | ||
241 | { | ||
242 | struct cfg80211_chan_def vht_chandef; | ||
243 | u32 ht_cfreq, ret; | ||
244 | |||
245 | chandef->chan = channel; | ||
246 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
247 | chandef->center_freq1 = channel->center_freq; | ||
248 | chandef->center_freq2 = 0; | ||
249 | |||
250 | if (!ht_oper || !sband->ht_cap.ht_supported) { | ||
251 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
252 | goto out; | ||
253 | } | ||
254 | |||
255 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
256 | |||
257 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
258 | channel->band); | ||
259 | /* check that channel matches the right operating channel */ | ||
260 | if (channel->center_freq != ht_cfreq) { | ||
261 | /* | ||
262 | * It's possible that some APs are confused here; | ||
263 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
264 | * the actual channel in association responses, but | ||
265 | * since we look at probe response/beacon data here | ||
266 | * it should be OK. | ||
267 | */ | ||
268 | if (verbose) | ||
269 | sdata_info(sdata, | ||
270 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | ||
271 | channel->center_freq, ht_cfreq, | ||
272 | ht_oper->primary_chan, channel->band); | ||
273 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
274 | goto out; | ||
275 | } | ||
276 | |||
277 | /* check 40 MHz support, if we have it */ | ||
278 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
279 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
280 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
281 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
282 | chandef->center_freq1 += 10; | ||
283 | break; | ||
284 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
285 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
286 | chandef->center_freq1 -= 10; | ||
287 | break; | ||
288 | } | ||
289 | } else { | ||
290 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | ||
291 | ret = IEEE80211_STA_DISABLE_VHT; | ||
292 | goto out; | ||
293 | } | ||
294 | |||
295 | if (!vht_oper || !sband->vht_cap.vht_supported) { | ||
296 | ret = IEEE80211_STA_DISABLE_VHT; | ||
297 | goto out; | ||
298 | } | ||
299 | |||
300 | vht_chandef.chan = channel; | ||
301 | vht_chandef.center_freq1 = | ||
302 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
303 | channel->band); | ||
304 | vht_chandef.center_freq2 = 0; | ||
305 | |||
306 | if (vht_oper->center_freq_seg2_idx) | ||
307 | vht_chandef.center_freq2 = | ||
308 | ieee80211_channel_to_frequency( | ||
309 | vht_oper->center_freq_seg2_idx, | ||
310 | channel->band); | ||
311 | |||
312 | switch (vht_oper->chan_width) { | ||
313 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
314 | vht_chandef.width = chandef->width; | ||
315 | break; | ||
316 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
317 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
318 | break; | ||
319 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
320 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
321 | break; | ||
322 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
323 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
324 | break; | ||
325 | default: | ||
326 | if (verbose) | ||
327 | sdata_info(sdata, | ||
328 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | ||
329 | vht_oper->chan_width); | ||
330 | ret = IEEE80211_STA_DISABLE_VHT; | ||
331 | goto out; | ||
332 | } | ||
333 | |||
334 | if (!cfg80211_chandef_valid(&vht_chandef)) { | ||
335 | if (verbose) | ||
336 | sdata_info(sdata, | ||
337 | "AP VHT information is invalid, disable VHT\n"); | ||
338 | ret = IEEE80211_STA_DISABLE_VHT; | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | if (cfg80211_chandef_identical(chandef, &vht_chandef)) { | ||
343 | ret = 0; | ||
344 | goto out; | ||
345 | } | ||
346 | |||
347 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | ||
348 | if (verbose) | ||
349 | sdata_info(sdata, | ||
350 | "AP VHT information doesn't match HT, disable VHT\n"); | ||
351 | ret = IEEE80211_STA_DISABLE_VHT; | ||
352 | goto out; | ||
353 | } | ||
354 | |||
355 | *chandef = vht_chandef; | ||
356 | |||
357 | ret = 0; | ||
358 | |||
359 | out: | ||
360 | /* don't print the message below for VHT mismatch if VHT is disabled */ | ||
361 | if (ret & IEEE80211_STA_DISABLE_VHT) | ||
362 | vht_chandef = *chandef; | ||
363 | |||
364 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
365 | IEEE80211_CHAN_DISABLED)) { | ||
366 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | ||
367 | ret = IEEE80211_STA_DISABLE_HT | | ||
368 | IEEE80211_STA_DISABLE_VHT; | ||
369 | goto out; | ||
370 | } | ||
371 | |||
372 | ret |= chandef_downgrade(chandef); | ||
373 | } | ||
374 | |||
375 | if (chandef->width != vht_chandef.width && verbose) | ||
376 | sdata_info(sdata, | ||
377 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); | ||
378 | |||
379 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | ||
384 | struct sta_info *sta, | ||
385 | const struct ieee80211_ht_operation *ht_oper, | ||
386 | const struct ieee80211_vht_operation *vht_oper, | ||
387 | const u8 *bssid, u32 *changed) | ||
178 | { | 388 | { |
179 | struct ieee80211_local *local = sdata->local; | 389 | struct ieee80211_local *local = sdata->local; |
390 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
180 | struct ieee80211_supported_band *sband; | 391 | struct ieee80211_supported_band *sband; |
181 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
182 | struct ieee80211_channel *chan; | 392 | struct ieee80211_channel *chan; |
183 | struct sta_info *sta; | 393 | struct cfg80211_chan_def chandef; |
184 | u32 changed = 0; | ||
185 | u16 ht_opmode; | 394 | u16 ht_opmode; |
186 | bool disable_40 = false; | 395 | u32 flags; |
396 | enum ieee80211_sta_rx_bandwidth new_sta_bw; | ||
397 | int ret; | ||
187 | 398 | ||
188 | rcu_read_lock(); | 399 | /* if HT was/is disabled, don't track any bandwidth changes */ |
189 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 400 | if (ifmgd->flags & IEEE80211_STA_DISABLE_HT || !ht_oper) |
190 | if (WARN_ON(!chanctx_conf)) { | ||
191 | rcu_read_unlock(); | ||
192 | return 0; | 401 | return 0; |
193 | } | 402 | |
194 | chan = chanctx_conf->def.chan; | 403 | /* don't check VHT if we associated as non-VHT station */ |
195 | rcu_read_unlock(); | 404 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) |
405 | vht_oper = NULL; | ||
406 | |||
407 | if (WARN_ON_ONCE(!sta)) | ||
408 | return -EINVAL; | ||
409 | |||
410 | chan = sdata->vif.bss_conf.chandef.chan; | ||
196 | sband = local->hw.wiphy->bands[chan->band]; | 411 | sband = local->hw.wiphy->bands[chan->band]; |
197 | 412 | ||
198 | switch (sdata->vif.bss_conf.chandef.width) { | 413 | /* calculate new channel (type) based on HT/VHT operation IEs */ |
414 | flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, | ||
415 | vht_oper, &chandef, false); | ||
416 | |||
417 | /* | ||
418 | * Downgrade the new channel if we associated with restricted | ||
419 | * capabilities. For example, if we associated as a 20 MHz STA | ||
420 | * to a 40 MHz AP (due to regulatory, capabilities or config | ||
421 | * reasons) then switching to a 40 MHz channel now won't do us | ||
422 | * any good -- we couldn't use it with the AP. | ||
423 | */ | ||
424 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
425 | chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
426 | flags |= chandef_downgrade(&chandef); | ||
427 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | ||
428 | chandef.width == NL80211_CHAN_WIDTH_160) | ||
429 | flags |= chandef_downgrade(&chandef); | ||
430 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
431 | chandef.width > NL80211_CHAN_WIDTH_20) | ||
432 | flags |= chandef_downgrade(&chandef); | ||
433 | |||
434 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) | ||
435 | return 0; | ||
436 | |||
437 | sdata_info(sdata, | ||
438 | "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n", | ||
439 | ifmgd->bssid, chandef.chan->center_freq, chandef.width, | ||
440 | chandef.center_freq1, chandef.center_freq2); | ||
441 | |||
442 | if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | ||
443 | IEEE80211_STA_DISABLE_VHT | | ||
444 | IEEE80211_STA_DISABLE_40MHZ | | ||
445 | IEEE80211_STA_DISABLE_80P80MHZ | | ||
446 | IEEE80211_STA_DISABLE_160MHZ)) || | ||
447 | !cfg80211_chandef_valid(&chandef)) { | ||
448 | sdata_info(sdata, | ||
449 | "AP %pM changed bandwidth in a way we can't support - disconnect\n", | ||
450 | ifmgd->bssid); | ||
451 | return -EINVAL; | ||
452 | } | ||
453 | |||
454 | switch (chandef.width) { | ||
455 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
456 | case NL80211_CHAN_WIDTH_20: | ||
457 | new_sta_bw = IEEE80211_STA_RX_BW_20; | ||
458 | break; | ||
199 | case NL80211_CHAN_WIDTH_40: | 459 | case NL80211_CHAN_WIDTH_40: |
200 | if (sdata->vif.bss_conf.chandef.chan->center_freq > | 460 | new_sta_bw = IEEE80211_STA_RX_BW_40; |
201 | sdata->vif.bss_conf.chandef.center_freq1 && | ||
202 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
203 | disable_40 = true; | ||
204 | if (sdata->vif.bss_conf.chandef.chan->center_freq < | ||
205 | sdata->vif.bss_conf.chandef.center_freq1 && | ||
206 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
207 | disable_40 = true; | ||
208 | break; | 461 | break; |
209 | default: | 462 | case NL80211_CHAN_WIDTH_80: |
463 | new_sta_bw = IEEE80211_STA_RX_BW_80; | ||
464 | break; | ||
465 | case NL80211_CHAN_WIDTH_80P80: | ||
466 | case NL80211_CHAN_WIDTH_160: | ||
467 | new_sta_bw = IEEE80211_STA_RX_BW_160; | ||
210 | break; | 468 | break; |
469 | default: | ||
470 | return -EINVAL; | ||
211 | } | 471 | } |
212 | 472 | ||
213 | /* This can change during the lifetime of the BSS */ | 473 | if (new_sta_bw > sta->cur_max_bandwidth) |
214 | if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 474 | new_sta_bw = sta->cur_max_bandwidth; |
215 | disable_40 = true; | ||
216 | |||
217 | mutex_lock(&local->sta_mtx); | ||
218 | sta = sta_info_get(sdata, bssid); | ||
219 | |||
220 | WARN_ON_ONCE(!sta); | ||
221 | |||
222 | if (sta && !sta->supports_40mhz) | ||
223 | disable_40 = true; | ||
224 | 475 | ||
225 | if (sta && (!reconfig || | 476 | if (new_sta_bw < sta->sta.bandwidth) { |
226 | (disable_40 != !(sta->sta.ht_cap.cap & | 477 | sta->sta.bandwidth = new_sta_bw; |
227 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) { | 478 | rate_control_rate_update(local, sband, sta, |
479 | IEEE80211_RC_BW_CHANGED); | ||
480 | } | ||
228 | 481 | ||
229 | if (disable_40) | 482 | ret = ieee80211_vif_change_bandwidth(sdata, &chandef, changed); |
230 | sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 483 | if (ret) { |
231 | else | 484 | sdata_info(sdata, |
232 | sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 485 | "AP %pM changed bandwidth to incompatible one - disconnect\n", |
486 | ifmgd->bssid); | ||
487 | return ret; | ||
488 | } | ||
233 | 489 | ||
490 | if (new_sta_bw > sta->sta.bandwidth) { | ||
491 | sta->sta.bandwidth = new_sta_bw; | ||
234 | rate_control_rate_update(local, sband, sta, | 492 | rate_control_rate_update(local, sband, sta, |
235 | IEEE80211_RC_BW_CHANGED); | 493 | IEEE80211_RC_BW_CHANGED); |
236 | } | 494 | } |
237 | mutex_unlock(&local->sta_mtx); | ||
238 | 495 | ||
239 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | 496 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); |
240 | 497 | ||
241 | /* if bss configuration changed store the new one */ | 498 | /* if bss configuration changed store the new one */ |
242 | if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) { | 499 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { |
243 | changed |= BSS_CHANGED_HT; | 500 | *changed |= BSS_CHANGED_HT; |
244 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | 501 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; |
245 | } | 502 | } |
246 | 503 | ||
247 | return changed; | 504 | return 0; |
248 | } | 505 | } |
249 | 506 | ||
250 | /* frame sending functions */ | 507 | /* frame sending functions */ |
@@ -644,6 +901,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
644 | drv_mgd_prepare_tx(local, sdata); | 901 | drv_mgd_prepare_tx(local, sdata); |
645 | 902 | ||
646 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 903 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
904 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
905 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
906 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
647 | ieee80211_tx_skb(sdata, skb); | 907 | ieee80211_tx_skb(sdata, skb); |
648 | } | 908 | } |
649 | 909 | ||
@@ -680,7 +940,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
680 | if (powersave) | 940 | if (powersave) |
681 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | 941 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
682 | 942 | ||
683 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 943 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | |
944 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | ||
684 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 945 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
685 | IEEE80211_STA_CONNECTION_POLL)) | 946 | IEEE80211_STA_CONNECTION_POLL)) |
686 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; | 947 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; |
@@ -784,10 +1045,10 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
784 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | 1045 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
785 | } | 1046 | } |
786 | 1047 | ||
787 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1048 | void |
788 | struct ieee80211_channel_sw_ie *sw_elem, | 1049 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
789 | struct ieee80211_bss *bss, | 1050 | const struct ieee80211_channel_sw_ie *sw_elem, |
790 | u64 timestamp) | 1051 | struct ieee80211_bss *bss, u64 timestamp) |
791 | { | 1052 | { |
792 | struct cfg80211_bss *cbss = | 1053 | struct cfg80211_bss *cbss = |
793 | container_of((void *)bss, struct cfg80211_bss, priv); | 1054 | container_of((void *)bss, struct cfg80211_bss, priv); |
@@ -946,39 +1207,6 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
946 | return 0; | 1207 | return 0; |
947 | } | 1208 | } |
948 | 1209 | ||
949 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | ||
950 | { | ||
951 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
952 | struct ieee80211_local *local = sdata->local; | ||
953 | struct ieee80211_conf *conf = &local->hw.conf; | ||
954 | |||
955 | WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION || | ||
956 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) || | ||
957 | (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)); | ||
958 | |||
959 | local->disable_dynamic_ps = false; | ||
960 | conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout; | ||
961 | } | ||
962 | EXPORT_SYMBOL(ieee80211_enable_dyn_ps); | ||
963 | |||
964 | void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif) | ||
965 | { | ||
966 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
967 | struct ieee80211_local *local = sdata->local; | ||
968 | struct ieee80211_conf *conf = &local->hw.conf; | ||
969 | |||
970 | WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION || | ||
971 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) || | ||
972 | (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)); | ||
973 | |||
974 | local->disable_dynamic_ps = true; | ||
975 | conf->dynamic_ps_timeout = 0; | ||
976 | del_timer_sync(&local->dynamic_ps_timer); | ||
977 | ieee80211_queue_work(&local->hw, | ||
978 | &local->dynamic_ps_enable_work); | ||
979 | } | ||
980 | EXPORT_SYMBOL(ieee80211_disable_dyn_ps); | ||
981 | |||
982 | /* powersave */ | 1210 | /* powersave */ |
983 | static void ieee80211_enable_ps(struct ieee80211_local *local, | 1211 | static void ieee80211_enable_ps(struct ieee80211_local *local, |
984 | struct ieee80211_sub_if_data *sdata) | 1212 | struct ieee80211_sub_if_data *sdata) |
@@ -1081,7 +1309,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
1081 | } | 1309 | } |
1082 | 1310 | ||
1083 | if (count == 1 && ieee80211_powersave_allowed(found)) { | 1311 | if (count == 1 && ieee80211_powersave_allowed(found)) { |
1084 | struct ieee80211_conf *conf = &local->hw.conf; | ||
1085 | s32 beaconint_us; | 1312 | s32 beaconint_us; |
1086 | 1313 | ||
1087 | if (latency < 0) | 1314 | if (latency < 0) |
@@ -1105,10 +1332,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
1105 | else | 1332 | else |
1106 | timeout = 100; | 1333 | timeout = 100; |
1107 | } | 1334 | } |
1108 | local->dynamic_ps_user_timeout = timeout; | 1335 | local->hw.conf.dynamic_ps_timeout = timeout; |
1109 | if (!local->disable_dynamic_ps) | ||
1110 | conf->dynamic_ps_timeout = | ||
1111 | local->dynamic_ps_user_timeout; | ||
1112 | 1336 | ||
1113 | if (beaconint_us > latency) { | 1337 | if (beaconint_us > latency) { |
1114 | local->ps_sdata = NULL; | 1338 | local->ps_sdata = NULL; |
@@ -1178,8 +1402,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
1178 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 1402 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
1179 | return; | 1403 | return; |
1180 | 1404 | ||
1181 | if (!local->disable_dynamic_ps && | 1405 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
1182 | local->hw.conf.dynamic_ps_timeout > 0) { | ||
1183 | /* don't enter PS if TX frames are pending */ | 1406 | /* don't enter PS if TX frames are pending */ |
1184 | if (drv_tx_frames_pending(local)) { | 1407 | if (drv_tx_frames_pending(local)) { |
1185 | mod_timer(&local->dynamic_ps_timer, jiffies + | 1408 | mod_timer(&local->dynamic_ps_timer, jiffies + |
@@ -1244,16 +1467,30 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
1244 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); | 1467 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); |
1245 | } | 1468 | } |
1246 | 1469 | ||
1470 | void ieee80211_dfs_cac_timer_work(struct work_struct *work) | ||
1471 | { | ||
1472 | struct delayed_work *delayed_work = | ||
1473 | container_of(work, struct delayed_work, work); | ||
1474 | struct ieee80211_sub_if_data *sdata = | ||
1475 | container_of(delayed_work, struct ieee80211_sub_if_data, | ||
1476 | dfs_cac_timer_work); | ||
1477 | |||
1478 | ieee80211_vif_release_channel(sdata); | ||
1479 | |||
1480 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); | ||
1481 | } | ||
1482 | |||
1247 | /* MLME */ | 1483 | /* MLME */ |
1248 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | 1484 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, |
1249 | struct ieee80211_sub_if_data *sdata, | 1485 | struct ieee80211_sub_if_data *sdata, |
1250 | u8 *wmm_param, size_t wmm_param_len) | 1486 | const u8 *wmm_param, size_t wmm_param_len) |
1251 | { | 1487 | { |
1252 | struct ieee80211_tx_queue_params params; | 1488 | struct ieee80211_tx_queue_params params; |
1253 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1489 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1254 | size_t left; | 1490 | size_t left; |
1255 | int count; | 1491 | int count; |
1256 | u8 *pos, uapsd_queues = 0; | 1492 | const u8 *pos; |
1493 | u8 uapsd_queues = 0; | ||
1257 | 1494 | ||
1258 | if (!local->ops->conf_tx) | 1495 | if (!local->ops->conf_tx) |
1259 | return false; | 1496 | return false; |
@@ -1445,7 +1682,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1445 | 1682 | ||
1446 | ieee80211_led_assoc(local, 1); | 1683 | ieee80211_led_assoc(local, 1); |
1447 | 1684 | ||
1448 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { | 1685 | if (sdata->u.mgd.assoc_data->have_beacon) { |
1449 | /* | 1686 | /* |
1450 | * If the AP is buggy we may get here with no DTIM period | 1687 | * If the AP is buggy we may get here with no DTIM period |
1451 | * known, so assume it's 1 which is the only safe assumption | 1688 | * known, so assume it's 1 which is the only safe assumption |
@@ -1453,6 +1690,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1453 | * probably just won't work at all. | 1690 | * probably just won't work at all. |
1454 | */ | 1691 | */ |
1455 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; | 1692 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; |
1693 | bss_info_changed |= BSS_CHANGED_DTIM_PERIOD; | ||
1456 | } else { | 1694 | } else { |
1457 | bss_conf->dtim_period = 0; | 1695 | bss_conf->dtim_period = 0; |
1458 | } | 1696 | } |
@@ -1655,17 +1893,18 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | |||
1655 | if (!ieee80211_is_data(hdr->frame_control)) | 1893 | if (!ieee80211_is_data(hdr->frame_control)) |
1656 | return; | 1894 | return; |
1657 | 1895 | ||
1658 | if (ack) | ||
1659 | ieee80211_sta_reset_conn_monitor(sdata); | ||
1660 | |||
1661 | if (ieee80211_is_nullfunc(hdr->frame_control) && | 1896 | if (ieee80211_is_nullfunc(hdr->frame_control) && |
1662 | sdata->u.mgd.probe_send_count > 0) { | 1897 | sdata->u.mgd.probe_send_count > 0) { |
1663 | if (ack) | 1898 | if (ack) |
1664 | sdata->u.mgd.probe_send_count = 0; | 1899 | ieee80211_sta_reset_conn_monitor(sdata); |
1665 | else | 1900 | else |
1666 | sdata->u.mgd.nullfunc_failed = true; | 1901 | sdata->u.mgd.nullfunc_failed = true; |
1667 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 1902 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
1903 | return; | ||
1668 | } | 1904 | } |
1905 | |||
1906 | if (ack) | ||
1907 | ieee80211_sta_reset_conn_monitor(sdata); | ||
1669 | } | 1908 | } |
1670 | 1909 | ||
1671 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1910 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
@@ -1706,7 +1945,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1706 | ssid_len = ssid[1]; | 1945 | ssid_len = ssid[1]; |
1707 | 1946 | ||
1708 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 1947 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, |
1709 | 0, (u32) -1, true, false, | 1948 | 0, (u32) -1, true, 0, |
1710 | ifmgd->associated->channel, false); | 1949 | ifmgd->associated->channel, false); |
1711 | rcu_read_unlock(); | 1950 | rcu_read_unlock(); |
1712 | } | 1951 | } |
@@ -1740,7 +1979,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
1740 | 1979 | ||
1741 | if (beacon) | 1980 | if (beacon) |
1742 | mlme_dbg_ratelimited(sdata, | 1981 | mlme_dbg_ratelimited(sdata, |
1743 | "detected beacon loss from AP - sending probe request\n"); | 1982 | "detected beacon loss from AP - probing\n"); |
1744 | 1983 | ||
1745 | ieee80211_cqm_rssi_notify(&sdata->vif, | 1984 | ieee80211_cqm_rssi_notify(&sdata->vif, |
1746 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL); | 1985 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL); |
@@ -1821,11 +2060,9 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1821 | } | 2060 | } |
1822 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 2061 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
1823 | 2062 | ||
1824 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, | 2063 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) |
1825 | bool transmit_frame) | ||
1826 | { | 2064 | { |
1827 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2065 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1828 | struct ieee80211_local *local = sdata->local; | ||
1829 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 2066 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
1830 | 2067 | ||
1831 | mutex_lock(&ifmgd->mtx); | 2068 | mutex_lock(&ifmgd->mtx); |
@@ -1836,8 +2073,10 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, | |||
1836 | 2073 | ||
1837 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 2074 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
1838 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2075 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1839 | transmit_frame, frame_buf); | 2076 | true, frame_buf); |
1840 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 2077 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
2078 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
2079 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1841 | mutex_unlock(&ifmgd->mtx); | 2080 | mutex_unlock(&ifmgd->mtx); |
1842 | 2081 | ||
1843 | /* | 2082 | /* |
@@ -1845,10 +2084,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, | |||
1845 | * but that's not a problem. | 2084 | * but that's not a problem. |
1846 | */ | 2085 | */ |
1847 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); | 2086 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
1848 | |||
1849 | mutex_lock(&local->mtx); | ||
1850 | ieee80211_recalc_idle(local); | ||
1851 | mutex_unlock(&local->mtx); | ||
1852 | } | 2087 | } |
1853 | 2088 | ||
1854 | static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | 2089 | static void ieee80211_beacon_connection_loss_work(struct work_struct *work) |
@@ -1867,10 +2102,10 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | |||
1867 | rcu_read_unlock(); | 2102 | rcu_read_unlock(); |
1868 | } | 2103 | } |
1869 | 2104 | ||
1870 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { | 2105 | if (ifmgd->connection_loss) { |
1871 | sdata_info(sdata, "Connection to AP %pM lost\n", | 2106 | sdata_info(sdata, "Connection to AP %pM lost\n", |
1872 | ifmgd->bssid); | 2107 | ifmgd->bssid); |
1873 | __ieee80211_disconnect(sdata, false); | 2108 | __ieee80211_disconnect(sdata); |
1874 | } else { | 2109 | } else { |
1875 | ieee80211_mgd_probe_ap(sdata, true); | 2110 | ieee80211_mgd_probe_ap(sdata, true); |
1876 | } | 2111 | } |
@@ -1882,9 +2117,7 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work) | |||
1882 | container_of(work, struct ieee80211_sub_if_data, | 2117 | container_of(work, struct ieee80211_sub_if_data, |
1883 | u.mgd.csa_connection_drop_work); | 2118 | u.mgd.csa_connection_drop_work); |
1884 | 2119 | ||
1885 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 2120 | __ieee80211_disconnect(sdata); |
1886 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1887 | __ieee80211_disconnect(sdata, true); | ||
1888 | } | 2121 | } |
1889 | 2122 | ||
1890 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 2123 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -1895,6 +2128,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
1895 | trace_api_beacon_loss(sdata); | 2128 | trace_api_beacon_loss(sdata); |
1896 | 2129 | ||
1897 | WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); | 2130 | WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); |
2131 | sdata->u.mgd.connection_loss = false; | ||
1898 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | 2132 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); |
1899 | } | 2133 | } |
1900 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 2134 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
@@ -1906,7 +2140,7 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) | |||
1906 | 2140 | ||
1907 | trace_api_connection_loss(sdata); | 2141 | trace_api_connection_loss(sdata); |
1908 | 2142 | ||
1909 | WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR)); | 2143 | sdata->u.mgd.connection_loss = true; |
1910 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | 2144 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); |
1911 | } | 2145 | } |
1912 | EXPORT_SYMBOL(ieee80211_connection_loss); | 2146 | EXPORT_SYMBOL(ieee80211_connection_loss); |
@@ -1928,7 +2162,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
1928 | ieee80211_vif_release_channel(sdata); | 2162 | ieee80211_vif_release_channel(sdata); |
1929 | } | 2163 | } |
1930 | 2164 | ||
1931 | cfg80211_put_bss(auth_data->bss); | 2165 | cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); |
1932 | kfree(auth_data); | 2166 | kfree(auth_data); |
1933 | sdata->u.mgd.auth_data = NULL; | 2167 | sdata->u.mgd.auth_data = NULL; |
1934 | } | 2168 | } |
@@ -1936,9 +2170,11 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
1936 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | 2170 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, |
1937 | struct ieee80211_mgmt *mgmt, size_t len) | 2171 | struct ieee80211_mgmt *mgmt, size_t len) |
1938 | { | 2172 | { |
2173 | struct ieee80211_local *local = sdata->local; | ||
1939 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | 2174 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; |
1940 | u8 *pos; | 2175 | u8 *pos; |
1941 | struct ieee802_11_elems elems; | 2176 | struct ieee802_11_elems elems; |
2177 | u32 tx_flags = 0; | ||
1942 | 2178 | ||
1943 | pos = mgmt->u.auth.variable; | 2179 | pos = mgmt->u.auth.variable; |
1944 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 2180 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
@@ -1946,11 +2182,14 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1946 | return; | 2182 | return; |
1947 | auth_data->expected_transaction = 4; | 2183 | auth_data->expected_transaction = 4; |
1948 | drv_mgd_prepare_tx(sdata->local, sdata); | 2184 | drv_mgd_prepare_tx(sdata->local, sdata); |
2185 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
2186 | tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
2187 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
1949 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, | 2188 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, |
1950 | elems.challenge - 2, elems.challenge_len + 2, | 2189 | elems.challenge - 2, elems.challenge_len + 2, |
1951 | auth_data->bss->bssid, auth_data->bss->bssid, | 2190 | auth_data->bss->bssid, auth_data->bss->bssid, |
1952 | auth_data->key, auth_data->key_len, | 2191 | auth_data->key, auth_data->key_len, |
1953 | auth_data->key_idx); | 2192 | auth_data->key_idx, tx_flags); |
1954 | } | 2193 | } |
1955 | 2194 | ||
1956 | static enum rx_mgmt_action __must_check | 2195 | static enum rx_mgmt_action __must_check |
@@ -2017,6 +2256,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2017 | sdata_info(sdata, "authenticated\n"); | 2256 | sdata_info(sdata, "authenticated\n"); |
2018 | ifmgd->auth_data->done = true; | 2257 | ifmgd->auth_data->done = true; |
2019 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | 2258 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
2259 | ifmgd->auth_data->timeout_started = true; | ||
2020 | run_again(ifmgd, ifmgd->auth_data->timeout); | 2260 | run_again(ifmgd, ifmgd->auth_data->timeout); |
2021 | 2261 | ||
2022 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && | 2262 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && |
@@ -2075,10 +2315,6 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
2075 | 2315 | ||
2076 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2316 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2077 | 2317 | ||
2078 | mutex_lock(&sdata->local->mtx); | ||
2079 | ieee80211_recalc_idle(sdata->local); | ||
2080 | mutex_unlock(&sdata->local->mtx); | ||
2081 | |||
2082 | return RX_MGMT_CFG80211_DEAUTH; | 2318 | return RX_MGMT_CFG80211_DEAUTH; |
2083 | } | 2319 | } |
2084 | 2320 | ||
@@ -2106,10 +2342,6 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2106 | 2342 | ||
2107 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2343 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2108 | 2344 | ||
2109 | mutex_lock(&sdata->local->mtx); | ||
2110 | ieee80211_recalc_idle(sdata->local); | ||
2111 | mutex_unlock(&sdata->local->mtx); | ||
2112 | |||
2113 | return RX_MGMT_CFG80211_DISASSOC; | 2345 | return RX_MGMT_CFG80211_DISASSOC; |
2114 | } | 2346 | } |
2115 | 2347 | ||
@@ -2219,6 +2451,24 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2219 | 2451 | ||
2220 | ifmgd->aid = aid; | 2452 | ifmgd->aid = aid; |
2221 | 2453 | ||
2454 | /* | ||
2455 | * We previously checked these in the beacon/probe response, so | ||
2456 | * they should be present here. This is just a safety net. | ||
2457 | */ | ||
2458 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
2459 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { | ||
2460 | sdata_info(sdata, | ||
2461 | "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); | ||
2462 | return false; | ||
2463 | } | ||
2464 | |||
2465 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | ||
2466 | (!elems.vht_cap_elem || !elems.vht_operation)) { | ||
2467 | sdata_info(sdata, | ||
2468 | "VHT AP is missing VHT capability/operation in AssocResp\n"); | ||
2469 | return false; | ||
2470 | } | ||
2471 | |||
2222 | mutex_lock(&sdata->local->sta_mtx); | 2472 | mutex_lock(&sdata->local->sta_mtx); |
2223 | /* | 2473 | /* |
2224 | * station info was already allocated and inserted before | 2474 | * station info was already allocated and inserted before |
@@ -2232,17 +2482,36 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2232 | 2482 | ||
2233 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; | 2483 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
2234 | 2484 | ||
2485 | /* Set up internal HT/VHT capabilities */ | ||
2235 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | 2486 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
2236 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2487 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
2237 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2488 | elems.ht_cap_elem, sta); |
2238 | |||
2239 | sta->supports_40mhz = | ||
2240 | sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2241 | 2489 | ||
2242 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 2490 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
2243 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 2491 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
2244 | elems.vht_cap_elem, | 2492 | elems.vht_cap_elem, sta); |
2245 | &sta->sta.vht_cap); | 2493 | |
2494 | /* | ||
2495 | * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data | ||
2496 | * in their association response, so ignore that data for our own | ||
2497 | * configuration. If it changed since the last beacon, we'll get the | ||
2498 | * next beacon and update then. | ||
2499 | */ | ||
2500 | |||
2501 | /* | ||
2502 | * If an operating mode notification IE is present, override the | ||
2503 | * NSS calculation (that would be done in rate_control_rate_init()) | ||
2504 | * and use the # of streams from that element. | ||
2505 | */ | ||
2506 | if (elems.opmode_notif && | ||
2507 | !(*elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) { | ||
2508 | u8 nss; | ||
2509 | |||
2510 | nss = *elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; | ||
2511 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; | ||
2512 | nss += 1; | ||
2513 | sta->sta.rx_nss = nss; | ||
2514 | } | ||
2246 | 2515 | ||
2247 | rate_control_rate_init(sta); | 2516 | rate_control_rate_init(sta); |
2248 | 2517 | ||
@@ -2252,9 +2521,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2252 | if (elems.wmm_param) | 2521 | if (elems.wmm_param) |
2253 | set_sta_flag(sta, WLAN_STA_WME); | 2522 | set_sta_flag(sta, WLAN_STA_WME); |
2254 | 2523 | ||
2255 | err = sta_info_move_state(sta, IEEE80211_STA_AUTH); | 2524 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
2256 | if (!err) | ||
2257 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
2258 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 2525 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
2259 | err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | 2526 | err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); |
2260 | if (err) { | 2527 | if (err) { |
@@ -2283,11 +2550,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2283 | ieee80211_set_wmm_default(sdata, false); | 2550 | ieee80211_set_wmm_default(sdata, false); |
2284 | changed |= BSS_CHANGED_QOS; | 2551 | changed |= BSS_CHANGED_QOS; |
2285 | 2552 | ||
2286 | if (elems.ht_operation && elems.wmm_param && | ||
2287 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | ||
2288 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | ||
2289 | cbss->bssid, false); | ||
2290 | |||
2291 | /* set AID and assoc capability, | 2553 | /* set AID and assoc capability, |
2292 | * ieee80211_set_associated() will tell the driver */ | 2554 | * ieee80211_set_associated() will tell the driver */ |
2293 | bss_conf->aid = aid; | 2555 | bss_conf->aid = aid; |
@@ -2361,6 +2623,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2361 | "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", | 2623 | "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", |
2362 | mgmt->sa, tu, ms); | 2624 | mgmt->sa, tu, ms); |
2363 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); | 2625 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); |
2626 | assoc_data->timeout_started = true; | ||
2364 | if (ms > IEEE80211_ASSOC_TIMEOUT) | 2627 | if (ms > IEEE80211_ASSOC_TIMEOUT) |
2365 | run_again(ifmgd, assoc_data->timeout); | 2628 | run_again(ifmgd, assoc_data->timeout); |
2366 | return RX_MGMT_NONE; | 2629 | return RX_MGMT_NONE; |
@@ -2376,7 +2639,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2376 | if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { | 2639 | if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { |
2377 | /* oops -- internal error -- send timeout for now */ | 2640 | /* oops -- internal error -- send timeout for now */ |
2378 | ieee80211_destroy_assoc_data(sdata, false); | 2641 | ieee80211_destroy_assoc_data(sdata, false); |
2379 | cfg80211_put_bss(*bss); | 2642 | cfg80211_put_bss(sdata->local->hw.wiphy, *bss); |
2380 | return RX_MGMT_CFG80211_ASSOC_TIMEOUT; | 2643 | return RX_MGMT_CFG80211_ASSOC_TIMEOUT; |
2381 | } | 2644 | } |
2382 | sdata_info(sdata, "associated\n"); | 2645 | sdata_info(sdata, "associated\n"); |
@@ -2412,7 +2675,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2412 | need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period; | 2675 | need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period; |
2413 | 2676 | ||
2414 | if (elems->tim && !elems->parse_error) { | 2677 | if (elems->tim && !elems->parse_error) { |
2415 | struct ieee80211_tim_ie *tim_ie = elems->tim; | 2678 | const struct ieee80211_tim_ie *tim_ie = elems->tim; |
2416 | sdata->u.mgd.dtim_period = tim_ie->dtim_period; | 2679 | sdata->u.mgd.dtim_period = tim_ie->dtim_period; |
2417 | } | 2680 | } |
2418 | } | 2681 | } |
@@ -2484,6 +2747,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
2484 | sdata_info(sdata, "direct probe responded\n"); | 2747 | sdata_info(sdata, "direct probe responded\n"); |
2485 | ifmgd->auth_data->tries = 0; | 2748 | ifmgd->auth_data->tries = 0; |
2486 | ifmgd->auth_data->timeout = jiffies; | 2749 | ifmgd->auth_data->timeout = jiffies; |
2750 | ifmgd->auth_data->timeout_started = true; | ||
2487 | run_again(ifmgd, ifmgd->auth_data->timeout); | 2751 | run_again(ifmgd, ifmgd->auth_data->timeout); |
2488 | } | 2752 | } |
2489 | } | 2753 | } |
@@ -2509,10 +2773,10 @@ static const u64 care_about_ies = | |||
2509 | (1ULL << WLAN_EID_HT_CAPABILITY) | | 2773 | (1ULL << WLAN_EID_HT_CAPABILITY) | |
2510 | (1ULL << WLAN_EID_HT_OPERATION); | 2774 | (1ULL << WLAN_EID_HT_OPERATION); |
2511 | 2775 | ||
2512 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 2776 | static enum rx_mgmt_action |
2513 | struct ieee80211_mgmt *mgmt, | 2777 | ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
2514 | size_t len, | 2778 | struct ieee80211_mgmt *mgmt, size_t len, |
2515 | struct ieee80211_rx_status *rx_status) | 2779 | u8 *deauth_buf, struct ieee80211_rx_status *rx_status) |
2516 | { | 2780 | { |
2517 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2781 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2518 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 2782 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
@@ -2521,6 +2785,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2521 | struct ieee80211_local *local = sdata->local; | 2785 | struct ieee80211_local *local = sdata->local; |
2522 | struct ieee80211_chanctx_conf *chanctx_conf; | 2786 | struct ieee80211_chanctx_conf *chanctx_conf; |
2523 | struct ieee80211_channel *chan; | 2787 | struct ieee80211_channel *chan; |
2788 | struct sta_info *sta; | ||
2524 | u32 changed = 0; | 2789 | u32 changed = 0; |
2525 | bool erp_valid; | 2790 | bool erp_valid; |
2526 | u8 erp_value = 0; | 2791 | u8 erp_value = 0; |
@@ -2532,39 +2797,51 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2532 | /* Process beacon from the current BSS */ | 2797 | /* Process beacon from the current BSS */ |
2533 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 2798 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
2534 | if (baselen > len) | 2799 | if (baselen > len) |
2535 | return; | 2800 | return RX_MGMT_NONE; |
2536 | 2801 | ||
2537 | rcu_read_lock(); | 2802 | rcu_read_lock(); |
2538 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2803 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2539 | if (!chanctx_conf) { | 2804 | if (!chanctx_conf) { |
2540 | rcu_read_unlock(); | 2805 | rcu_read_unlock(); |
2541 | return; | 2806 | return RX_MGMT_NONE; |
2542 | } | 2807 | } |
2543 | 2808 | ||
2544 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { | 2809 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { |
2545 | rcu_read_unlock(); | 2810 | rcu_read_unlock(); |
2546 | return; | 2811 | return RX_MGMT_NONE; |
2547 | } | 2812 | } |
2548 | chan = chanctx_conf->def.chan; | 2813 | chan = chanctx_conf->def.chan; |
2549 | rcu_read_unlock(); | 2814 | rcu_read_unlock(); |
2550 | 2815 | ||
2551 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && | 2816 | if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && |
2552 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { | 2817 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { |
2553 | ieee802_11_parse_elems(mgmt->u.beacon.variable, | 2818 | ieee802_11_parse_elems(mgmt->u.beacon.variable, |
2554 | len - baselen, &elems); | 2819 | len - baselen, &elems); |
2555 | 2820 | ||
2556 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 2821 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
2557 | ifmgd->assoc_data->have_beacon = true; | 2822 | ifmgd->assoc_data->have_beacon = true; |
2558 | ifmgd->assoc_data->sent_assoc = false; | 2823 | ifmgd->assoc_data->need_beacon = false; |
2824 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
2825 | sdata->vif.bss_conf.sync_tsf = | ||
2826 | le64_to_cpu(mgmt->u.beacon.timestamp); | ||
2827 | sdata->vif.bss_conf.sync_device_ts = | ||
2828 | rx_status->device_timestamp; | ||
2829 | if (elems.tim) | ||
2830 | sdata->vif.bss_conf.sync_dtim_count = | ||
2831 | elems.tim->dtim_count; | ||
2832 | else | ||
2833 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
2834 | } | ||
2559 | /* continue assoc process */ | 2835 | /* continue assoc process */ |
2560 | ifmgd->assoc_data->timeout = jiffies; | 2836 | ifmgd->assoc_data->timeout = jiffies; |
2837 | ifmgd->assoc_data->timeout_started = true; | ||
2561 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 2838 | run_again(ifmgd, ifmgd->assoc_data->timeout); |
2562 | return; | 2839 | return RX_MGMT_NONE; |
2563 | } | 2840 | } |
2564 | 2841 | ||
2565 | if (!ifmgd->associated || | 2842 | if (!ifmgd->associated || |
2566 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) | 2843 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
2567 | return; | 2844 | return RX_MGMT_NONE; |
2568 | bssid = ifmgd->associated->bssid; | 2845 | bssid = ifmgd->associated->bssid; |
2569 | 2846 | ||
2570 | /* Track average RSSI from the Beacon frames of the current AP */ | 2847 | /* Track average RSSI from the Beacon frames of the current AP */ |
@@ -2630,7 +2907,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2630 | 2907 | ||
2631 | if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { | 2908 | if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { |
2632 | mlme_dbg_ratelimited(sdata, | 2909 | mlme_dbg_ratelimited(sdata, |
2633 | "cancelling probereq poll due to a received beacon\n"); | 2910 | "cancelling AP probe due to a received beacon\n"); |
2634 | mutex_lock(&local->mtx); | 2911 | mutex_lock(&local->mtx); |
2635 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; | 2912 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; |
2636 | ieee80211_run_deferred_scan(local); | 2913 | ieee80211_run_deferred_scan(local); |
@@ -2702,7 +2979,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2702 | } | 2979 | } |
2703 | 2980 | ||
2704 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 2981 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
2705 | return; | 2982 | return RX_MGMT_NONE; |
2706 | ifmgd->beacon_crc = ncrc; | 2983 | ifmgd->beacon_crc = ncrc; |
2707 | ifmgd->beacon_crc_valid = true; | 2984 | ifmgd->beacon_crc_valid = true; |
2708 | 2985 | ||
@@ -2712,6 +2989,32 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2712 | elems.wmm_param_len)) | 2989 | elems.wmm_param_len)) |
2713 | changed |= BSS_CHANGED_QOS; | 2990 | changed |= BSS_CHANGED_QOS; |
2714 | 2991 | ||
2992 | /* | ||
2993 | * If we haven't had a beacon before, tell the driver about the | ||
2994 | * DTIM period (and beacon timing if desired) now. | ||
2995 | */ | ||
2996 | if (!bss_conf->dtim_period) { | ||
2997 | /* a few bogus AP send dtim_period = 0 or no TIM IE */ | ||
2998 | if (elems.tim) | ||
2999 | bss_conf->dtim_period = elems.tim->dtim_period ?: 1; | ||
3000 | else | ||
3001 | bss_conf->dtim_period = 1; | ||
3002 | |||
3003 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
3004 | sdata->vif.bss_conf.sync_tsf = | ||
3005 | le64_to_cpu(mgmt->u.beacon.timestamp); | ||
3006 | sdata->vif.bss_conf.sync_device_ts = | ||
3007 | rx_status->device_timestamp; | ||
3008 | if (elems.tim) | ||
3009 | sdata->vif.bss_conf.sync_dtim_count = | ||
3010 | elems.tim->dtim_count; | ||
3011 | else | ||
3012 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3013 | } | ||
3014 | |||
3015 | changed |= BSS_CHANGED_DTIM_PERIOD; | ||
3016 | } | ||
3017 | |||
2715 | if (elems.erp_info && elems.erp_info_len >= 1) { | 3018 | if (elems.erp_info && elems.erp_info_len >= 1) { |
2716 | erp_valid = true; | 3019 | erp_valid = true; |
2717 | erp_value = elems.erp_info[0]; | 3020 | erp_value = elems.erp_info[0]; |
@@ -2722,11 +3025,22 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2722 | le16_to_cpu(mgmt->u.beacon.capab_info), | 3025 | le16_to_cpu(mgmt->u.beacon.capab_info), |
2723 | erp_valid, erp_value); | 3026 | erp_valid, erp_value); |
2724 | 3027 | ||
3028 | mutex_lock(&local->sta_mtx); | ||
3029 | sta = sta_info_get(sdata, bssid); | ||
2725 | 3030 | ||
2726 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && | 3031 | if (ieee80211_config_bw(sdata, sta, elems.ht_operation, |
2727 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | 3032 | elems.vht_operation, bssid, &changed)) { |
2728 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 3033 | mutex_unlock(&local->sta_mtx); |
2729 | bssid, true); | 3034 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3035 | WLAN_REASON_DEAUTH_LEAVING, | ||
3036 | true, deauth_buf); | ||
3037 | return RX_MGMT_CFG80211_TX_DEAUTH; | ||
3038 | } | ||
3039 | |||
3040 | if (sta && elems.opmode_notif) | ||
3041 | ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, | ||
3042 | rx_status->band, true); | ||
3043 | mutex_unlock(&local->sta_mtx); | ||
2730 | 3044 | ||
2731 | if (elems.country_elem && elems.pwr_constr_elem && | 3045 | if (elems.country_elem && elems.pwr_constr_elem && |
2732 | mgmt->u.probe_resp.capab_info & | 3046 | mgmt->u.probe_resp.capab_info & |
@@ -2737,6 +3051,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2737 | elems.pwr_constr_elem); | 3051 | elems.pwr_constr_elem); |
2738 | 3052 | ||
2739 | ieee80211_bss_info_change_notify(sdata, changed); | 3053 | ieee80211_bss_info_change_notify(sdata, changed); |
3054 | |||
3055 | return RX_MGMT_NONE; | ||
2740 | } | 3056 | } |
2741 | 3057 | ||
2742 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 3058 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
@@ -2747,6 +3063,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2747 | struct ieee80211_mgmt *mgmt; | 3063 | struct ieee80211_mgmt *mgmt; |
2748 | struct cfg80211_bss *bss = NULL; | 3064 | struct cfg80211_bss *bss = NULL; |
2749 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 3065 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
3066 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
2750 | u16 fc; | 3067 | u16 fc; |
2751 | 3068 | ||
2752 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 3069 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
@@ -2757,7 +3074,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2757 | 3074 | ||
2758 | switch (fc & IEEE80211_FCTL_STYPE) { | 3075 | switch (fc & IEEE80211_FCTL_STYPE) { |
2759 | case IEEE80211_STYPE_BEACON: | 3076 | case IEEE80211_STYPE_BEACON: |
2760 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | 3077 | rma = ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
3078 | deauth_buf, rx_status); | ||
2761 | break; | 3079 | break; |
2762 | case IEEE80211_STYPE_PROBE_RESP: | 3080 | case IEEE80211_STYPE_PROBE_RESP: |
2763 | ieee80211_rx_mgmt_probe_resp(sdata, skb); | 3081 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
@@ -2806,6 +3124,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2806 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: | 3124 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: |
2807 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | 3125 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); |
2808 | break; | 3126 | break; |
3127 | case RX_MGMT_CFG80211_TX_DEAUTH: | ||
3128 | cfg80211_send_deauth(sdata->dev, deauth_buf, | ||
3129 | sizeof(deauth_buf)); | ||
3130 | break; | ||
2809 | default: | 3131 | default: |
2810 | WARN(1, "unexpected: %d", rma); | 3132 | WARN(1, "unexpected: %d", rma); |
2811 | } | 3133 | } |
@@ -2827,14 +3149,13 @@ static void ieee80211_sta_timer(unsigned long data) | |||
2827 | } | 3149 | } |
2828 | 3150 | ||
2829 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | 3151 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
2830 | u8 *bssid, u8 reason) | 3152 | u8 *bssid, u8 reason, bool tx) |
2831 | { | 3153 | { |
2832 | struct ieee80211_local *local = sdata->local; | ||
2833 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3154 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2834 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 3155 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2835 | 3156 | ||
2836 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 3157 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
2837 | false, frame_buf); | 3158 | tx, frame_buf); |
2838 | mutex_unlock(&ifmgd->mtx); | 3159 | mutex_unlock(&ifmgd->mtx); |
2839 | 3160 | ||
2840 | /* | 3161 | /* |
@@ -2843,10 +3164,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2843 | */ | 3164 | */ |
2844 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); | 3165 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
2845 | 3166 | ||
2846 | mutex_lock(&local->mtx); | ||
2847 | ieee80211_recalc_idle(local); | ||
2848 | mutex_unlock(&local->mtx); | ||
2849 | |||
2850 | mutex_lock(&ifmgd->mtx); | 3167 | mutex_lock(&ifmgd->mtx); |
2851 | } | 3168 | } |
2852 | 3169 | ||
@@ -2855,12 +3172,17 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2855 | struct ieee80211_local *local = sdata->local; | 3172 | struct ieee80211_local *local = sdata->local; |
2856 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3173 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2857 | struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; | 3174 | struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; |
3175 | u32 tx_flags = 0; | ||
2858 | 3176 | ||
2859 | lockdep_assert_held(&ifmgd->mtx); | 3177 | lockdep_assert_held(&ifmgd->mtx); |
2860 | 3178 | ||
2861 | if (WARN_ON_ONCE(!auth_data)) | 3179 | if (WARN_ON_ONCE(!auth_data)) |
2862 | return -EINVAL; | 3180 | return -EINVAL; |
2863 | 3181 | ||
3182 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
3183 | tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
3184 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
3185 | |||
2864 | auth_data->tries++; | 3186 | auth_data->tries++; |
2865 | 3187 | ||
2866 | if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { | 3188 | if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { |
@@ -2897,7 +3219,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2897 | ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, | 3219 | ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, |
2898 | auth_data->data, auth_data->data_len, | 3220 | auth_data->data, auth_data->data_len, |
2899 | auth_data->bss->bssid, | 3221 | auth_data->bss->bssid, |
2900 | auth_data->bss->bssid, NULL, 0, 0); | 3222 | auth_data->bss->bssid, NULL, 0, 0, |
3223 | tx_flags); | ||
2901 | } else { | 3224 | } else { |
2902 | const u8 *ssidie; | 3225 | const u8 *ssidie; |
2903 | 3226 | ||
@@ -2916,13 +3239,18 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2916 | * will not answer to direct packet in unassociated state. | 3239 | * will not answer to direct packet in unassociated state. |
2917 | */ | 3240 | */ |
2918 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 3241 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], |
2919 | NULL, 0, (u32) -1, true, false, | 3242 | NULL, 0, (u32) -1, true, tx_flags, |
2920 | auth_data->bss->channel, false); | 3243 | auth_data->bss->channel, false); |
2921 | rcu_read_unlock(); | 3244 | rcu_read_unlock(); |
2922 | } | 3245 | } |
2923 | 3246 | ||
2924 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 3247 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
2925 | run_again(ifmgd, auth_data->timeout); | 3248 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
3249 | ifmgd->auth_data->timeout_started = true; | ||
3250 | run_again(ifmgd, auth_data->timeout); | ||
3251 | } else { | ||
3252 | auth_data->timeout_started = false; | ||
3253 | } | ||
2926 | 3254 | ||
2927 | return 0; | 3255 | return 0; |
2928 | } | 3256 | } |
@@ -2953,12 +3281,29 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | |||
2953 | IEEE80211_ASSOC_MAX_TRIES); | 3281 | IEEE80211_ASSOC_MAX_TRIES); |
2954 | ieee80211_send_assoc(sdata); | 3282 | ieee80211_send_assoc(sdata); |
2955 | 3283 | ||
2956 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | 3284 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
2957 | run_again(&sdata->u.mgd, assoc_data->timeout); | 3285 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; |
3286 | assoc_data->timeout_started = true; | ||
3287 | run_again(&sdata->u.mgd, assoc_data->timeout); | ||
3288 | } else { | ||
3289 | assoc_data->timeout_started = false; | ||
3290 | } | ||
2958 | 3291 | ||
2959 | return 0; | 3292 | return 0; |
2960 | } | 3293 | } |
2961 | 3294 | ||
3295 | void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, | ||
3296 | __le16 fc, bool acked) | ||
3297 | { | ||
3298 | struct ieee80211_local *local = sdata->local; | ||
3299 | |||
3300 | sdata->u.mgd.status_fc = fc; | ||
3301 | sdata->u.mgd.status_acked = acked; | ||
3302 | sdata->u.mgd.status_received = true; | ||
3303 | |||
3304 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
3305 | } | ||
3306 | |||
2962 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | 3307 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
2963 | { | 3308 | { |
2964 | struct ieee80211_local *local = sdata->local; | 3309 | struct ieee80211_local *local = sdata->local; |
@@ -2966,7 +3311,36 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2966 | 3311 | ||
2967 | mutex_lock(&ifmgd->mtx); | 3312 | mutex_lock(&ifmgd->mtx); |
2968 | 3313 | ||
2969 | if (ifmgd->auth_data && | 3314 | if (ifmgd->status_received) { |
3315 | __le16 fc = ifmgd->status_fc; | ||
3316 | bool status_acked = ifmgd->status_acked; | ||
3317 | |||
3318 | ifmgd->status_received = false; | ||
3319 | if (ifmgd->auth_data && | ||
3320 | (ieee80211_is_probe_req(fc) || ieee80211_is_auth(fc))) { | ||
3321 | if (status_acked) { | ||
3322 | ifmgd->auth_data->timeout = | ||
3323 | jiffies + IEEE80211_AUTH_TIMEOUT_SHORT; | ||
3324 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
3325 | } else { | ||
3326 | ifmgd->auth_data->timeout = jiffies - 1; | ||
3327 | } | ||
3328 | ifmgd->auth_data->timeout_started = true; | ||
3329 | } else if (ifmgd->assoc_data && | ||
3330 | (ieee80211_is_assoc_req(fc) || | ||
3331 | ieee80211_is_reassoc_req(fc))) { | ||
3332 | if (status_acked) { | ||
3333 | ifmgd->assoc_data->timeout = | ||
3334 | jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT; | ||
3335 | run_again(ifmgd, ifmgd->assoc_data->timeout); | ||
3336 | } else { | ||
3337 | ifmgd->assoc_data->timeout = jiffies - 1; | ||
3338 | } | ||
3339 | ifmgd->assoc_data->timeout_started = true; | ||
3340 | } | ||
3341 | } | ||
3342 | |||
3343 | if (ifmgd->auth_data && ifmgd->auth_data->timeout_started && | ||
2970 | time_after(jiffies, ifmgd->auth_data->timeout)) { | 3344 | time_after(jiffies, ifmgd->auth_data->timeout)) { |
2971 | if (ifmgd->auth_data->done) { | 3345 | if (ifmgd->auth_data->done) { |
2972 | /* | 3346 | /* |
@@ -2985,12 +3359,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2985 | cfg80211_send_auth_timeout(sdata->dev, bssid); | 3359 | cfg80211_send_auth_timeout(sdata->dev, bssid); |
2986 | mutex_lock(&ifmgd->mtx); | 3360 | mutex_lock(&ifmgd->mtx); |
2987 | } | 3361 | } |
2988 | } else if (ifmgd->auth_data) | 3362 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) |
2989 | run_again(ifmgd, ifmgd->auth_data->timeout); | 3363 | run_again(ifmgd, ifmgd->auth_data->timeout); |
2990 | 3364 | ||
2991 | if (ifmgd->assoc_data && | 3365 | if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && |
2992 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | 3366 | time_after(jiffies, ifmgd->assoc_data->timeout)) { |
2993 | if (!ifmgd->assoc_data->have_beacon || | 3367 | if ((ifmgd->assoc_data->need_beacon && |
3368 | !ifmgd->assoc_data->have_beacon) || | ||
2994 | ieee80211_do_assoc(sdata)) { | 3369 | ieee80211_do_assoc(sdata)) { |
2995 | u8 bssid[ETH_ALEN]; | 3370 | u8 bssid[ETH_ALEN]; |
2996 | 3371 | ||
@@ -3002,7 +3377,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3002 | cfg80211_send_assoc_timeout(sdata->dev, bssid); | 3377 | cfg80211_send_assoc_timeout(sdata->dev, bssid); |
3003 | mutex_lock(&ifmgd->mtx); | 3378 | mutex_lock(&ifmgd->mtx); |
3004 | } | 3379 | } |
3005 | } else if (ifmgd->assoc_data) | 3380 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3006 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 3381 | run_again(ifmgd, ifmgd->assoc_data->timeout); |
3007 | 3382 | ||
3008 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 3383 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
@@ -3033,7 +3408,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3033 | "No ack for nullfunc frame to AP %pM, disconnecting.\n", | 3408 | "No ack for nullfunc frame to AP %pM, disconnecting.\n", |
3034 | bssid); | 3409 | bssid); |
3035 | ieee80211_sta_connection_lost(sdata, bssid, | 3410 | ieee80211_sta_connection_lost(sdata, bssid, |
3036 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | 3411 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
3412 | false); | ||
3037 | } | 3413 | } |
3038 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | 3414 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) |
3039 | run_again(ifmgd, ifmgd->probe_timeout); | 3415 | run_again(ifmgd, ifmgd->probe_timeout); |
@@ -3042,7 +3418,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3042 | "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", | 3418 | "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", |
3043 | bssid, probe_wait_ms); | 3419 | bssid, probe_wait_ms); |
3044 | ieee80211_sta_connection_lost(sdata, bssid, | 3420 | ieee80211_sta_connection_lost(sdata, bssid, |
3045 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | 3421 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); |
3046 | } else if (ifmgd->probe_send_count < max_tries) { | 3422 | } else if (ifmgd->probe_send_count < max_tries) { |
3047 | mlme_dbg(sdata, | 3423 | mlme_dbg(sdata, |
3048 | "No probe response from AP %pM after %dms, try %d/%i\n", | 3424 | "No probe response from AP %pM after %dms, try %d/%i\n", |
@@ -3061,15 +3437,11 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3061 | bssid, probe_wait_ms); | 3437 | bssid, probe_wait_ms); |
3062 | 3438 | ||
3063 | ieee80211_sta_connection_lost(sdata, bssid, | 3439 | ieee80211_sta_connection_lost(sdata, bssid, |
3064 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | 3440 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false); |
3065 | } | 3441 | } |
3066 | } | 3442 | } |
3067 | 3443 | ||
3068 | mutex_unlock(&ifmgd->mtx); | 3444 | mutex_unlock(&ifmgd->mtx); |
3069 | |||
3070 | mutex_lock(&local->mtx); | ||
3071 | ieee80211_recalc_idle(local); | ||
3072 | mutex_unlock(&local->mtx); | ||
3073 | } | 3445 | } |
3074 | 3446 | ||
3075 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 3447 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -3081,6 +3453,7 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3081 | if (local->quiescing) | 3453 | if (local->quiescing) |
3082 | return; | 3454 | return; |
3083 | 3455 | ||
3456 | sdata->u.mgd.connection_loss = false; | ||
3084 | ieee80211_queue_work(&sdata->local->hw, | 3457 | ieee80211_queue_work(&sdata->local->hw, |
3085 | &sdata->u.mgd.beacon_connection_loss_work); | 3458 | &sdata->u.mgd.beacon_connection_loss_work); |
3086 | } | 3459 | } |
@@ -3167,7 +3540,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
3167 | mlme_dbg(sdata, "driver requested disconnect after resume\n"); | 3540 | mlme_dbg(sdata, "driver requested disconnect after resume\n"); |
3168 | ieee80211_sta_connection_lost(sdata, | 3541 | ieee80211_sta_connection_lost(sdata, |
3169 | ifmgd->associated->bssid, | 3542 | ifmgd->associated->bssid, |
3170 | WLAN_REASON_UNSPECIFIED); | 3543 | WLAN_REASON_UNSPECIFIED, |
3544 | true); | ||
3171 | mutex_unlock(&ifmgd->mtx); | 3545 | mutex_unlock(&ifmgd->mtx); |
3172 | return; | 3546 | return; |
3173 | } | 3547 | } |
@@ -3247,201 +3621,6 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
3247 | return 0; | 3621 | return 0; |
3248 | } | 3622 | } |
3249 | 3623 | ||
3250 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
3251 | { | ||
3252 | u32 ret; | ||
3253 | int tmp; | ||
3254 | |||
3255 | switch (c->width) { | ||
3256 | case NL80211_CHAN_WIDTH_20: | ||
3257 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
3258 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3259 | break; | ||
3260 | case NL80211_CHAN_WIDTH_40: | ||
3261 | c->width = NL80211_CHAN_WIDTH_20; | ||
3262 | c->center_freq1 = c->chan->center_freq; | ||
3263 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
3264 | IEEE80211_STA_DISABLE_VHT; | ||
3265 | break; | ||
3266 | case NL80211_CHAN_WIDTH_80: | ||
3267 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
3268 | /* n_P40 */ | ||
3269 | tmp /= 2; | ||
3270 | /* freq_P40 */ | ||
3271 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
3272 | c->width = NL80211_CHAN_WIDTH_40; | ||
3273 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3274 | break; | ||
3275 | case NL80211_CHAN_WIDTH_80P80: | ||
3276 | c->center_freq2 = 0; | ||
3277 | c->width = NL80211_CHAN_WIDTH_80; | ||
3278 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
3279 | IEEE80211_STA_DISABLE_160MHZ; | ||
3280 | break; | ||
3281 | case NL80211_CHAN_WIDTH_160: | ||
3282 | /* n_P20 */ | ||
3283 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
3284 | /* n_P80 */ | ||
3285 | tmp /= 4; | ||
3286 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
3287 | c->width = NL80211_CHAN_WIDTH_80; | ||
3288 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
3289 | IEEE80211_STA_DISABLE_160MHZ; | ||
3290 | break; | ||
3291 | default: | ||
3292 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
3293 | WARN_ON_ONCE(1); | ||
3294 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
3295 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3296 | break; | ||
3297 | } | ||
3298 | |||
3299 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
3300 | |||
3301 | return ret; | ||
3302 | } | ||
3303 | |||
3304 | static u32 | ||
3305 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | ||
3306 | struct ieee80211_supported_band *sband, | ||
3307 | struct ieee80211_channel *channel, | ||
3308 | const struct ieee80211_ht_operation *ht_oper, | ||
3309 | const struct ieee80211_vht_operation *vht_oper, | ||
3310 | struct cfg80211_chan_def *chandef) | ||
3311 | { | ||
3312 | struct cfg80211_chan_def vht_chandef; | ||
3313 | u32 ht_cfreq, ret; | ||
3314 | |||
3315 | chandef->chan = channel; | ||
3316 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
3317 | chandef->center_freq1 = channel->center_freq; | ||
3318 | chandef->center_freq2 = 0; | ||
3319 | |||
3320 | if (!ht_oper || !sband->ht_cap.ht_supported) { | ||
3321 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3322 | goto out; | ||
3323 | } | ||
3324 | |||
3325 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
3326 | |||
3327 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
3328 | channel->band); | ||
3329 | /* check that channel matches the right operating channel */ | ||
3330 | if (channel->center_freq != ht_cfreq) { | ||
3331 | /* | ||
3332 | * It's possible that some APs are confused here; | ||
3333 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
3334 | * the actual channel in association responses, but | ||
3335 | * since we look at probe response/beacon data here | ||
3336 | * it should be OK. | ||
3337 | */ | ||
3338 | sdata_info(sdata, | ||
3339 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | ||
3340 | channel->center_freq, ht_cfreq, | ||
3341 | ht_oper->primary_chan, channel->band); | ||
3342 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
3343 | goto out; | ||
3344 | } | ||
3345 | |||
3346 | /* check 40 MHz support, if we have it */ | ||
3347 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
3348 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
3349 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
3350 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
3351 | chandef->center_freq1 += 10; | ||
3352 | break; | ||
3353 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
3354 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
3355 | chandef->center_freq1 -= 10; | ||
3356 | break; | ||
3357 | } | ||
3358 | } else { | ||
3359 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | ||
3360 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3361 | goto out; | ||
3362 | } | ||
3363 | |||
3364 | if (!vht_oper || !sband->vht_cap.vht_supported) { | ||
3365 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3366 | goto out; | ||
3367 | } | ||
3368 | |||
3369 | vht_chandef.chan = channel; | ||
3370 | vht_chandef.center_freq1 = | ||
3371 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
3372 | channel->band); | ||
3373 | vht_chandef.center_freq2 = 0; | ||
3374 | |||
3375 | if (vht_oper->center_freq_seg2_idx) | ||
3376 | vht_chandef.center_freq2 = | ||
3377 | ieee80211_channel_to_frequency( | ||
3378 | vht_oper->center_freq_seg2_idx, | ||
3379 | channel->band); | ||
3380 | |||
3381 | switch (vht_oper->chan_width) { | ||
3382 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
3383 | vht_chandef.width = chandef->width; | ||
3384 | break; | ||
3385 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
3386 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
3387 | break; | ||
3388 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
3389 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
3390 | break; | ||
3391 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
3392 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
3393 | break; | ||
3394 | default: | ||
3395 | sdata_info(sdata, | ||
3396 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | ||
3397 | vht_oper->chan_width); | ||
3398 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3399 | goto out; | ||
3400 | } | ||
3401 | |||
3402 | if (!cfg80211_chandef_valid(&vht_chandef)) { | ||
3403 | sdata_info(sdata, | ||
3404 | "AP VHT information is invalid, disable VHT\n"); | ||
3405 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3406 | goto out; | ||
3407 | } | ||
3408 | |||
3409 | if (cfg80211_chandef_identical(chandef, &vht_chandef)) { | ||
3410 | ret = 0; | ||
3411 | goto out; | ||
3412 | } | ||
3413 | |||
3414 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | ||
3415 | sdata_info(sdata, | ||
3416 | "AP VHT information doesn't match HT, disable VHT\n"); | ||
3417 | ret = IEEE80211_STA_DISABLE_VHT; | ||
3418 | goto out; | ||
3419 | } | ||
3420 | |||
3421 | *chandef = vht_chandef; | ||
3422 | |||
3423 | ret = 0; | ||
3424 | |||
3425 | out: | ||
3426 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
3427 | IEEE80211_CHAN_DISABLED)) { | ||
3428 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | ||
3429 | ret = IEEE80211_STA_DISABLE_HT | | ||
3430 | IEEE80211_STA_DISABLE_VHT; | ||
3431 | goto out; | ||
3432 | } | ||
3433 | |||
3434 | ret |= chandef_downgrade(chandef); | ||
3435 | } | ||
3436 | |||
3437 | if (chandef->width != vht_chandef.width) | ||
3438 | sdata_info(sdata, | ||
3439 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); | ||
3440 | |||
3441 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | ||
3442 | return ret; | ||
3443 | } | ||
3444 | |||
3445 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | 3624 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, |
3446 | struct cfg80211_bss *cbss) | 3625 | struct cfg80211_bss *cbss) |
3447 | { | 3626 | { |
@@ -3507,16 +3686,22 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3507 | 3686 | ||
3508 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | 3687 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
3509 | sband->ht_cap.ht_supported) { | 3688 | sband->ht_cap.ht_supported) { |
3510 | const u8 *ht_oper_ie; | 3689 | const u8 *ht_oper_ie, *ht_cap; |
3511 | 3690 | ||
3512 | ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); | 3691 | ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); |
3513 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) | 3692 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) |
3514 | ht_oper = (void *)(ht_oper_ie + 2); | 3693 | ht_oper = (void *)(ht_oper_ie + 2); |
3694 | |||
3695 | ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); | ||
3696 | if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) { | ||
3697 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; | ||
3698 | ht_oper = NULL; | ||
3699 | } | ||
3515 | } | 3700 | } |
3516 | 3701 | ||
3517 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | 3702 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
3518 | sband->vht_cap.vht_supported) { | 3703 | sband->vht_cap.vht_supported) { |
3519 | const u8 *vht_oper_ie; | 3704 | const u8 *vht_oper_ie, *vht_cap; |
3520 | 3705 | ||
3521 | vht_oper_ie = ieee80211_bss_get_ie(cbss, | 3706 | vht_oper_ie = ieee80211_bss_get_ie(cbss, |
3522 | WLAN_EID_VHT_OPERATION); | 3707 | WLAN_EID_VHT_OPERATION); |
@@ -3526,15 +3711,21 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3526 | vht_oper = NULL; | 3711 | vht_oper = NULL; |
3527 | sdata_info(sdata, | 3712 | sdata_info(sdata, |
3528 | "AP advertised VHT without HT, disabling both\n"); | 3713 | "AP advertised VHT without HT, disabling both\n"); |
3529 | sdata->flags |= IEEE80211_STA_DISABLE_HT; | 3714 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
3530 | sdata->flags |= IEEE80211_STA_DISABLE_VHT; | 3715 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
3716 | } | ||
3717 | |||
3718 | vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY); | ||
3719 | if (!vht_cap || vht_cap[1] < sizeof(struct ieee80211_vht_cap)) { | ||
3720 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
3721 | vht_oper = NULL; | ||
3531 | } | 3722 | } |
3532 | } | 3723 | } |
3533 | 3724 | ||
3534 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, | 3725 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, |
3535 | cbss->channel, | 3726 | cbss->channel, |
3536 | ht_oper, vht_oper, | 3727 | ht_oper, vht_oper, |
3537 | &chandef); | 3728 | &chandef, true); |
3538 | 3729 | ||
3539 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), | 3730 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), |
3540 | local->rx_chains); | 3731 | local->rx_chains); |
@@ -3584,15 +3775,12 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3584 | return -ENOMEM; | 3775 | return -ENOMEM; |
3585 | } | 3776 | } |
3586 | 3777 | ||
3587 | mutex_lock(&local->mtx); | ||
3588 | ieee80211_recalc_idle(sdata->local); | ||
3589 | mutex_unlock(&local->mtx); | ||
3590 | |||
3591 | if (new_sta) { | 3778 | if (new_sta) { |
3592 | u32 rates = 0, basic_rates = 0; | 3779 | u32 rates = 0, basic_rates = 0; |
3593 | bool have_higher_than_11mbit; | 3780 | bool have_higher_than_11mbit; |
3594 | int min_rate = INT_MAX, min_rate_index = -1; | 3781 | int min_rate = INT_MAX, min_rate_index = -1; |
3595 | struct ieee80211_supported_band *sband; | 3782 | struct ieee80211_supported_band *sband; |
3783 | const struct cfg80211_bss_ies *ies; | ||
3596 | 3784 | ||
3597 | sband = local->hw.wiphy->bands[cbss->channel->band]; | 3785 | sband = local->hw.wiphy->bands[cbss->channel->band]; |
3598 | 3786 | ||
@@ -3636,8 +3824,34 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3636 | 3824 | ||
3637 | /* set timing information */ | 3825 | /* set timing information */ |
3638 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; | 3826 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; |
3639 | sdata->vif.bss_conf.sync_tsf = cbss->tsf; | 3827 | rcu_read_lock(); |
3640 | sdata->vif.bss_conf.sync_device_ts = bss->device_ts; | 3828 | ies = rcu_dereference(cbss->beacon_ies); |
3829 | if (ies) { | ||
3830 | const u8 *tim_ie; | ||
3831 | |||
3832 | sdata->vif.bss_conf.sync_tsf = ies->tsf; | ||
3833 | sdata->vif.bss_conf.sync_device_ts = | ||
3834 | bss->device_ts_beacon; | ||
3835 | tim_ie = cfg80211_find_ie(WLAN_EID_TIM, | ||
3836 | ies->data, ies->len); | ||
3837 | if (tim_ie && tim_ie[1] >= 2) | ||
3838 | sdata->vif.bss_conf.sync_dtim_count = tim_ie[2]; | ||
3839 | else | ||
3840 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3841 | } else if (!(local->hw.flags & | ||
3842 | IEEE80211_HW_TIMING_BEACON_ONLY)) { | ||
3843 | ies = rcu_dereference(cbss->proberesp_ies); | ||
3844 | /* must be non-NULL since beacon IEs were NULL */ | ||
3845 | sdata->vif.bss_conf.sync_tsf = ies->tsf; | ||
3846 | sdata->vif.bss_conf.sync_device_ts = | ||
3847 | bss->device_ts_presp; | ||
3848 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3849 | } else { | ||
3850 | sdata->vif.bss_conf.sync_tsf = 0; | ||
3851 | sdata->vif.bss_conf.sync_device_ts = 0; | ||
3852 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3853 | } | ||
3854 | rcu_read_unlock(); | ||
3641 | 3855 | ||
3642 | /* tell driver about BSSID, basic rates and timing */ | 3856 | /* tell driver about BSSID, basic rates and timing */ |
3643 | ieee80211_bss_info_change_notify(sdata, | 3857 | ieee80211_bss_info_change_notify(sdata, |
@@ -3757,7 +3971,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
3757 | } | 3971 | } |
3758 | 3972 | ||
3759 | /* hold our own reference */ | 3973 | /* hold our own reference */ |
3760 | cfg80211_ref_bss(auth_data->bss); | 3974 | cfg80211_ref_bss(local->hw.wiphy, auth_data->bss); |
3761 | err = 0; | 3975 | err = 0; |
3762 | goto out_unlock; | 3976 | goto out_unlock; |
3763 | 3977 | ||
@@ -3780,6 +3994,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3780 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3994 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3781 | struct ieee80211_bss *bss = (void *)req->bss->priv; | 3995 | struct ieee80211_bss *bss = (void *)req->bss->priv; |
3782 | struct ieee80211_mgd_assoc_data *assoc_data; | 3996 | struct ieee80211_mgd_assoc_data *assoc_data; |
3997 | const struct cfg80211_bss_ies *beacon_ies; | ||
3783 | struct ieee80211_supported_band *sband; | 3998 | struct ieee80211_supported_band *sband; |
3784 | const u8 *ssidie, *ht_ie, *vht_ie; | 3999 | const u8 *ssidie, *ht_ie, *vht_ie; |
3785 | int i, err; | 4000 | int i, err; |
@@ -3945,40 +4160,48 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3945 | if (err) | 4160 | if (err) |
3946 | goto err_clear; | 4161 | goto err_clear; |
3947 | 4162 | ||
3948 | if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { | 4163 | rcu_read_lock(); |
3949 | const struct cfg80211_bss_ies *beacon_ies; | 4164 | beacon_ies = rcu_dereference(req->bss->beacon_ies); |
3950 | 4165 | ||
3951 | rcu_read_lock(); | 4166 | if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC && |
3952 | beacon_ies = rcu_dereference(req->bss->beacon_ies); | 4167 | !beacon_ies) { |
3953 | if (!beacon_ies) { | 4168 | /* |
3954 | /* | 4169 | * Wait up to one beacon interval ... |
3955 | * Wait up to one beacon interval ... | 4170 | * should this be more if we miss one? |
3956 | * should this be more if we miss one? | 4171 | */ |
3957 | */ | 4172 | sdata_info(sdata, "waiting for beacon from %pM\n", |
3958 | sdata_info(sdata, "waiting for beacon from %pM\n", | 4173 | ifmgd->bssid); |
3959 | ifmgd->bssid); | 4174 | assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); |
3960 | assoc_data->timeout = | 4175 | assoc_data->timeout_started = true; |
3961 | TU_TO_EXP_TIME(req->bss->beacon_interval); | 4176 | assoc_data->need_beacon = true; |
3962 | } else { | 4177 | } else if (beacon_ies) { |
3963 | const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, | 4178 | const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, |
3964 | beacon_ies->data, | 4179 | beacon_ies->data, |
3965 | beacon_ies->len); | 4180 | beacon_ies->len); |
3966 | if (tim_ie && tim_ie[1] >= | 4181 | u8 dtim_count = 0; |
3967 | sizeof(struct ieee80211_tim_ie)) { | 4182 | |
3968 | const struct ieee80211_tim_ie *tim; | 4183 | if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) { |
3969 | tim = (void *)(tim_ie + 2); | 4184 | const struct ieee80211_tim_ie *tim; |
3970 | ifmgd->dtim_period = tim->dtim_period; | 4185 | tim = (void *)(tim_ie + 2); |
3971 | } | 4186 | ifmgd->dtim_period = tim->dtim_period; |
3972 | assoc_data->have_beacon = true; | 4187 | dtim_count = tim->dtim_count; |
3973 | assoc_data->sent_assoc = false; | ||
3974 | assoc_data->timeout = jiffies; | ||
3975 | } | 4188 | } |
3976 | rcu_read_unlock(); | ||
3977 | } else { | ||
3978 | assoc_data->have_beacon = true; | 4189 | assoc_data->have_beacon = true; |
3979 | assoc_data->sent_assoc = false; | ||
3980 | assoc_data->timeout = jiffies; | 4190 | assoc_data->timeout = jiffies; |
4191 | assoc_data->timeout_started = true; | ||
4192 | |||
4193 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
4194 | sdata->vif.bss_conf.sync_tsf = beacon_ies->tsf; | ||
4195 | sdata->vif.bss_conf.sync_device_ts = | ||
4196 | bss->device_ts_beacon; | ||
4197 | sdata->vif.bss_conf.sync_dtim_count = dtim_count; | ||
4198 | } | ||
4199 | } else { | ||
4200 | assoc_data->timeout = jiffies; | ||
4201 | assoc_data->timeout_started = true; | ||
3981 | } | 4202 | } |
4203 | rcu_read_unlock(); | ||
4204 | |||
3982 | run_again(ifmgd, assoc_data->timeout); | 4205 | run_again(ifmgd, assoc_data->timeout); |
3983 | 4206 | ||
3984 | if (bss->corrupt_data) { | 4207 | if (bss->corrupt_data) { |
@@ -4045,10 +4268,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4045 | mutex_unlock(&ifmgd->mtx); | 4268 | mutex_unlock(&ifmgd->mtx); |
4046 | 4269 | ||
4047 | out: | 4270 | out: |
4048 | mutex_lock(&sdata->local->mtx); | ||
4049 | ieee80211_recalc_idle(sdata->local); | ||
4050 | mutex_unlock(&sdata->local->mtx); | ||
4051 | |||
4052 | if (sent_frame) | 4271 | if (sent_frame) |
4053 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 4272 | __cfg80211_send_deauth(sdata->dev, frame_buf, |
4054 | IEEE80211_DEAUTH_FRAME_LEN); | 4273 | IEEE80211_DEAUTH_FRAME_LEN); |
@@ -4089,10 +4308,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4089 | __cfg80211_send_disassoc(sdata->dev, frame_buf, | 4308 | __cfg80211_send_disassoc(sdata->dev, frame_buf, |
4090 | IEEE80211_DEAUTH_FRAME_LEN); | 4309 | IEEE80211_DEAUTH_FRAME_LEN); |
4091 | 4310 | ||
4092 | mutex_lock(&sdata->local->mtx); | ||
4093 | ieee80211_recalc_idle(sdata->local); | ||
4094 | mutex_unlock(&sdata->local->mtx); | ||
4095 | |||
4096 | return 0; | 4311 | return 0; |
4097 | } | 4312 | } |
4098 | 4313 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 82baf5b6ecf4..cc79b4a2e821 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -113,6 +113,15 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) | |||
113 | * notify the AP about us leaving the channel and stop all | 113 | * notify the AP about us leaving the channel and stop all |
114 | * STA interfaces. | 114 | * STA interfaces. |
115 | */ | 115 | */ |
116 | |||
117 | /* | ||
118 | * Stop queues and transmit all frames queued by the driver | ||
119 | * before sending nullfunc to enable powersave at the AP. | ||
120 | */ | ||
121 | ieee80211_stop_queues_by_reason(&local->hw, | ||
122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); | ||
123 | drv_flush(local, false); | ||
124 | |||
116 | mutex_lock(&local->iflist_mtx); | 125 | mutex_lock(&local->iflist_mtx); |
117 | list_for_each_entry(sdata, &local->interfaces, list) { | 126 | list_for_each_entry(sdata, &local->interfaces, list) { |
118 | if (!ieee80211_sdata_running(sdata)) | 127 | if (!ieee80211_sdata_running(sdata)) |
@@ -133,12 +142,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) | |||
133 | sdata, BSS_CHANGED_BEACON_ENABLED); | 142 | sdata, BSS_CHANGED_BEACON_ENABLED); |
134 | } | 143 | } |
135 | 144 | ||
136 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { | 145 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
137 | netif_tx_stop_all_queues(sdata->dev); | 146 | sdata->u.mgd.associated) |
138 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 147 | ieee80211_offchannel_ps_enable(sdata); |
139 | sdata->u.mgd.associated) | ||
140 | ieee80211_offchannel_ps_enable(sdata); | ||
141 | } | ||
142 | } | 148 | } |
143 | mutex_unlock(&local->iflist_mtx); | 149 | mutex_unlock(&local->iflist_mtx); |
144 | } | 150 | } |
@@ -166,20 +172,6 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) | |||
166 | sdata->u.mgd.associated) | 172 | sdata->u.mgd.associated) |
167 | ieee80211_offchannel_ps_disable(sdata); | 173 | ieee80211_offchannel_ps_disable(sdata); |
168 | 174 | ||
169 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { | ||
170 | /* | ||
171 | * This may wake up queues even though the driver | ||
172 | * currently has them stopped. This is not very | ||
173 | * likely, since the driver won't have gotten any | ||
174 | * (or hardly any) new packets while we weren't | ||
175 | * on the right channel, and even if it happens | ||
176 | * it will at most lead to queueing up one more | ||
177 | * packet per queue in mac80211 rather than on | ||
178 | * the interface qdisc. | ||
179 | */ | ||
180 | netif_tx_wake_all_queues(sdata->dev); | ||
181 | } | ||
182 | |||
183 | if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, | 175 | if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, |
184 | &sdata->state)) { | 176 | &sdata->state)) { |
185 | sdata->vif.bss_conf.enable_beacon = true; | 177 | sdata->vif.bss_conf.enable_beacon = true; |
@@ -188,6 +180,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) | |||
188 | } | 180 | } |
189 | } | 181 | } |
190 | mutex_unlock(&local->iflist_mtx); | 182 | mutex_unlock(&local->iflist_mtx); |
183 | |||
184 | ieee80211_wake_queues_by_reason(&local->hw, | ||
185 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); | ||
191 | } | 186 | } |
192 | 187 | ||
193 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) | 188 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e45b83610e85..d0275f34bf70 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -38,6 +38,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
38 | 38 | ||
39 | ieee80211_scan_cancel(local); | 39 | ieee80211_scan_cancel(local); |
40 | 40 | ||
41 | ieee80211_dfs_cac_cancel(local); | ||
42 | |||
41 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 43 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
42 | mutex_lock(&local->sta_mtx); | 44 | mutex_lock(&local->sta_mtx); |
43 | list_for_each_entry(sta, &local->sta_list, list) { | 45 | list_for_each_entry(sta, &local->sta_list, list) { |
@@ -228,3 +230,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
228 | * ieee80211_reconfig(), which is also needed for hardware | 230 | * ieee80211_reconfig(), which is also needed for hardware |
229 | * hang/firmware failure/etc. recovery. | 231 | * hang/firmware failure/etc. recovery. |
230 | */ | 232 | */ |
233 | |||
234 | void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif, | ||
235 | struct cfg80211_wowlan_wakeup *wakeup, | ||
236 | gfp_t gfp) | ||
237 | { | ||
238 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
239 | |||
240 | cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp); | ||
241 | } | ||
242 | EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup); | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 301386dabf88..d35a5dd3fb13 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -68,6 +68,8 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; | 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; |
69 | rcu_read_unlock(); | 69 | rcu_read_unlock(); |
70 | 70 | ||
71 | ieee80211_sta_set_rx_nss(sta); | ||
72 | |||
71 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 73 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
72 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | 74 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); |
73 | } | 75 | } |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 8c5acdc06226..eea45a2c7c35 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -494,6 +494,33 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) | |||
494 | kfree(mi); | 494 | kfree(mi); |
495 | } | 495 | } |
496 | 496 | ||
497 | static void | ||
498 | minstrel_init_cck_rates(struct minstrel_priv *mp) | ||
499 | { | ||
500 | static const int bitrates[4] = { 10, 20, 55, 110 }; | ||
501 | struct ieee80211_supported_band *sband; | ||
502 | int i, j; | ||
503 | |||
504 | sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
505 | if (!sband) | ||
506 | return; | ||
507 | |||
508 | for (i = 0, j = 0; i < sband->n_bitrates; i++) { | ||
509 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
510 | |||
511 | if (rate->flags & IEEE80211_RATE_ERP_G) | ||
512 | continue; | ||
513 | |||
514 | for (j = 0; j < ARRAY_SIZE(bitrates); j++) { | ||
515 | if (rate->bitrate != bitrates[j]) | ||
516 | continue; | ||
517 | |||
518 | mp->cck_rates[j] = i; | ||
519 | break; | ||
520 | } | ||
521 | } | ||
522 | } | ||
523 | |||
497 | static void * | 524 | static void * |
498 | minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 525 | minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
499 | { | 526 | { |
@@ -539,6 +566,8 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | |||
539 | S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); | 566 | S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); |
540 | #endif | 567 | #endif |
541 | 568 | ||
569 | minstrel_init_cck_rates(mp); | ||
570 | |||
542 | return mp; | 571 | return mp; |
543 | } | 572 | } |
544 | 573 | ||
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 5d278eccaef0..5ecf757817f2 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
@@ -79,6 +79,8 @@ struct minstrel_priv { | |||
79 | unsigned int lookaround_rate; | 79 | unsigned int lookaround_rate; |
80 | unsigned int lookaround_rate_mrr; | 80 | unsigned int lookaround_rate_mrr; |
81 | 81 | ||
82 | u8 cck_rates[4]; | ||
83 | |||
82 | #ifdef CONFIG_MAC80211_DEBUGFS | 84 | #ifdef CONFIG_MAC80211_DEBUGFS |
83 | /* | 85 | /* |
84 | * enable fixed rate processing per RC | 86 | * enable fixed rate processing per RC |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 9f9c453bc45d..3af141c69712 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> | 2 | * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org> |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
@@ -63,6 +63,30 @@ | |||
63 | } \ | 63 | } \ |
64 | } | 64 | } |
65 | 65 | ||
66 | #define CCK_DURATION(_bitrate, _short, _len) \ | ||
67 | (10 /* SIFS */ + \ | ||
68 | (_short ? 72 + 24 : 144 + 48 ) + \ | ||
69 | (8 * (_len + 4) * 10) / (_bitrate)) | ||
70 | |||
71 | #define CCK_ACK_DURATION(_bitrate, _short) \ | ||
72 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ | ||
73 | CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE)) | ||
74 | |||
75 | #define CCK_DURATION_LIST(_short) \ | ||
76 | CCK_ACK_DURATION(10, _short), \ | ||
77 | CCK_ACK_DURATION(20, _short), \ | ||
78 | CCK_ACK_DURATION(55, _short), \ | ||
79 | CCK_ACK_DURATION(110, _short) | ||
80 | |||
81 | #define CCK_GROUP \ | ||
82 | [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \ | ||
83 | .streams = 0, \ | ||
84 | .duration = { \ | ||
85 | CCK_DURATION_LIST(false), \ | ||
86 | CCK_DURATION_LIST(true) \ | ||
87 | } \ | ||
88 | } | ||
89 | |||
66 | /* | 90 | /* |
67 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 91 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
68 | * groups, based on the number of streams and flags (HT40, SGI) that they | 92 | * groups, based on the number of streams and flags (HT40, SGI) that they |
@@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = { | |||
95 | #if MINSTREL_MAX_STREAMS >= 3 | 119 | #if MINSTREL_MAX_STREAMS >= 3 |
96 | MCS_GROUP(3, 1, 1), | 120 | MCS_GROUP(3, 1, 1), |
97 | #endif | 121 | #endif |
122 | |||
123 | /* must be last */ | ||
124 | CCK_GROUP | ||
98 | }; | 125 | }; |
99 | 126 | ||
127 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) | ||
128 | |||
100 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 129 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; |
101 | 130 | ||
102 | /* | 131 | /* |
@@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | |||
119 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 148 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
120 | } | 149 | } |
121 | 150 | ||
151 | static struct minstrel_rate_stats * | ||
152 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | ||
153 | struct ieee80211_tx_rate *rate) | ||
154 | { | ||
155 | int group, idx; | ||
156 | |||
157 | if (rate->flags & IEEE80211_TX_RC_MCS) { | ||
158 | group = minstrel_ht_get_group_idx(rate); | ||
159 | idx = rate->idx % MCS_GROUP_RATES; | ||
160 | } else { | ||
161 | group = MINSTREL_CCK_GROUP; | ||
162 | |||
163 | for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) | ||
164 | if (rate->idx == mp->cck_rates[idx]) | ||
165 | break; | ||
166 | |||
167 | /* short preamble */ | ||
168 | if (!(mi->groups[group].supported & BIT(idx))) | ||
169 | idx += 4; | ||
170 | } | ||
171 | return &mi->groups[group].rates[idx]; | ||
172 | } | ||
173 | |||
122 | static inline struct minstrel_rate_stats * | 174 | static inline struct minstrel_rate_stats * |
123 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | 175 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) |
124 | { | 176 | { |
@@ -159,7 +211,7 @@ static void | |||
159 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | 211 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) |
160 | { | 212 | { |
161 | struct minstrel_rate_stats *mr; | 213 | struct minstrel_rate_stats *mr; |
162 | unsigned int usecs; | 214 | unsigned int usecs = 0; |
163 | 215 | ||
164 | mr = &mi->groups[group].rates[rate]; | 216 | mr = &mi->groups[group].rates[rate]; |
165 | 217 | ||
@@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
168 | return; | 220 | return; |
169 | } | 221 | } |
170 | 222 | ||
171 | usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | 223 | if (group != MINSTREL_CCK_GROUP) |
224 | usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | ||
225 | |||
172 | usecs += minstrel_mcs_groups[group].duration[rate]; | 226 | usecs += minstrel_mcs_groups[group].duration[rate]; |
173 | mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); | 227 | mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); |
174 | } | 228 | } |
@@ -231,10 +285,6 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
231 | if (!mr->cur_tp) | 285 | if (!mr->cur_tp) |
232 | continue; | 286 | continue; |
233 | 287 | ||
234 | /* ignore the lowest rate of each single-stream group */ | ||
235 | if (!i && minstrel_mcs_groups[group].streams == 1) | ||
236 | continue; | ||
237 | |||
238 | if ((mr->cur_tp > cur_prob_tp && mr->probability > | 288 | if ((mr->cur_tp > cur_prob_tp && mr->probability > |
239 | MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { | 289 | MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { |
240 | mg->max_prob_rate = index; | 290 | mg->max_prob_rate = index; |
@@ -297,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
297 | } | 347 | } |
298 | 348 | ||
299 | static bool | 349 | static bool |
300 | minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | 350 | minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate) |
301 | { | 351 | { |
302 | if (rate->idx < 0) | 352 | if (rate->idx < 0) |
303 | return false; | 353 | return false; |
@@ -305,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | |||
305 | if (!rate->count) | 355 | if (!rate->count) |
306 | return false; | 356 | return false; |
307 | 357 | ||
308 | return !!(rate->flags & IEEE80211_TX_RC_MCS); | 358 | if (rate->flags & IEEE80211_TX_RC_MCS) |
359 | return true; | ||
360 | |||
361 | return rate->idx == mp->cck_rates[0] || | ||
362 | rate->idx == mp->cck_rates[1] || | ||
363 | rate->idx == mp->cck_rates[2] || | ||
364 | rate->idx == mp->cck_rates[3]; | ||
309 | } | 365 | } |
310 | 366 | ||
311 | static void | 367 | static void |
@@ -390,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
390 | struct minstrel_rate_stats *rate, *rate2; | 446 | struct minstrel_rate_stats *rate, *rate2; |
391 | struct minstrel_priv *mp = priv; | 447 | struct minstrel_priv *mp = priv; |
392 | bool last; | 448 | bool last; |
393 | int group; | ||
394 | int i; | 449 | int i; |
395 | 450 | ||
396 | if (!msp->is_ht) | 451 | if (!msp->is_ht) |
@@ -419,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
419 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | 474 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) |
420 | mi->sample_packets += info->status.ampdu_len; | 475 | mi->sample_packets += info->status.ampdu_len; |
421 | 476 | ||
422 | last = !minstrel_ht_txstat_valid(&ar[0]); | 477 | last = !minstrel_ht_txstat_valid(mp, &ar[0]); |
423 | for (i = 0; !last; i++) { | 478 | for (i = 0; !last; i++) { |
424 | last = (i == IEEE80211_TX_MAX_RATES - 1) || | 479 | last = (i == IEEE80211_TX_MAX_RATES - 1) || |
425 | !minstrel_ht_txstat_valid(&ar[i + 1]); | 480 | !minstrel_ht_txstat_valid(mp, &ar[i + 1]); |
426 | 481 | ||
427 | group = minstrel_ht_get_group_idx(&ar[i]); | 482 | rate = minstrel_ht_get_stats(mp, mi, &ar[i]); |
428 | rate = &mi->groups[group].rates[ar[i].idx % 8]; | ||
429 | 483 | ||
430 | if (last) | 484 | if (last) |
431 | rate->success += info->status.ampdu_ack_len; | 485 | rate->success += info->status.ampdu_ack_len; |
@@ -451,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
451 | 505 | ||
452 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { | 506 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { |
453 | minstrel_ht_update_stats(mp, mi); | 507 | minstrel_ht_update_stats(mp, mi); |
454 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) | 508 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && |
509 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) | ||
455 | minstrel_aggr_check(sta, skb); | 510 | minstrel_aggr_check(sta, skb); |
456 | } | 511 | } |
457 | } | 512 | } |
@@ -467,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
467 | unsigned int ctime = 0; | 522 | unsigned int ctime = 0; |
468 | unsigned int t_slot = 9; /* FIXME */ | 523 | unsigned int t_slot = 9; /* FIXME */ |
469 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); | 524 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); |
525 | unsigned int overhead = 0, overhead_rtscts = 0; | ||
470 | 526 | ||
471 | mr = minstrel_get_ratestats(mi, index); | 527 | mr = minstrel_get_ratestats(mi, index); |
472 | if (mr->probability < MINSTREL_FRAC(1, 10)) { | 528 | if (mr->probability < MINSTREL_FRAC(1, 10)) { |
@@ -488,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
488 | ctime += (t_slot * cw) >> 1; | 544 | ctime += (t_slot * cw) >> 1; |
489 | cw = min((cw << 1) | 1, mp->cw_max); | 545 | cw = min((cw << 1) | 1, mp->cw_max); |
490 | 546 | ||
547 | if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) { | ||
548 | overhead = mi->overhead; | ||
549 | overhead_rtscts = mi->overhead_rtscts; | ||
550 | } | ||
551 | |||
491 | /* Total TX time for data and Contention after first 2 tries */ | 552 | /* Total TX time for data and Contention after first 2 tries */ |
492 | tx_time = ctime + 2 * (mi->overhead + tx_time_data); | 553 | tx_time = ctime + 2 * (overhead + tx_time_data); |
493 | tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); | 554 | tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data); |
494 | 555 | ||
495 | /* See how many more tries we can fit inside segment size */ | 556 | /* See how many more tries we can fit inside segment size */ |
496 | do { | 557 | do { |
@@ -499,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
499 | cw = min((cw << 1) | 1, mp->cw_max); | 560 | cw = min((cw << 1) | 1, mp->cw_max); |
500 | 561 | ||
501 | /* Total TX time after this try */ | 562 | /* Total TX time after this try */ |
502 | tx_time += ctime + mi->overhead + tx_time_data; | 563 | tx_time += ctime + overhead + tx_time_data; |
503 | tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; | 564 | tx_time_rtscts += ctime + overhead_rtscts + tx_time_data; |
504 | 565 | ||
505 | if (tx_time_rtscts < mp->segment_size) | 566 | if (tx_time_rtscts < mp->segment_size) |
506 | mr->retry_count_rtscts++; | 567 | mr->retry_count_rtscts++; |
@@ -530,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
530 | else | 591 | else |
531 | rate->count = mr->retry_count; | 592 | rate->count = mr->retry_count; |
532 | 593 | ||
533 | rate->flags = IEEE80211_TX_RC_MCS | group->flags; | 594 | rate->flags = 0; |
534 | if (rtscts) | 595 | if (rtscts) |
535 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; | 596 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; |
597 | |||
598 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | ||
599 | rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | ||
600 | return; | ||
601 | } | ||
602 | |||
603 | rate->flags |= IEEE80211_TX_RC_MCS | group->flags; | ||
536 | rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; | 604 | rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; |
537 | } | 605 | } |
538 | 606 | ||
@@ -596,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
596 | } | 664 | } |
597 | 665 | ||
598 | static void | 666 | static void |
667 | minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp, | ||
668 | struct minstrel_ht_sta *mi, bool val) | ||
669 | { | ||
670 | u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported; | ||
671 | |||
672 | if (!supported || !mi->cck_supported_short) | ||
673 | return; | ||
674 | |||
675 | if (supported & (mi->cck_supported_short << (val * 4))) | ||
676 | return; | ||
677 | |||
678 | supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4); | ||
679 | mi->groups[MINSTREL_CCK_GROUP].supported = supported; | ||
680 | } | ||
681 | |||
682 | static void | ||
599 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 683 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, |
600 | struct ieee80211_tx_rate_control *txrc) | 684 | struct ieee80211_tx_rate_control *txrc) |
601 | { | 685 | { |
@@ -614,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
614 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); | 698 | return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); |
615 | 699 | ||
616 | info->flags |= mi->tx_flags; | 700 | info->flags |= mi->tx_flags; |
701 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); | ||
617 | 702 | ||
618 | /* Don't use EAPOL frames for sampling on non-mrr hw */ | 703 | /* Don't use EAPOL frames for sampling on non-mrr hw */ |
619 | if (mp->hw->max_rates == 1 && | 704 | if (mp->hw->max_rates == 1 && |
@@ -687,6 +772,30 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
687 | } | 772 | } |
688 | 773 | ||
689 | static void | 774 | static void |
775 | minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | ||
776 | struct ieee80211_supported_band *sband, | ||
777 | struct ieee80211_sta *sta) | ||
778 | { | ||
779 | int i; | ||
780 | |||
781 | if (sband->band != IEEE80211_BAND_2GHZ) | ||
782 | return; | ||
783 | |||
784 | mi->cck_supported = 0; | ||
785 | mi->cck_supported_short = 0; | ||
786 | for (i = 0; i < 4; i++) { | ||
787 | if (!rate_supported(sta, sband->band, mp->cck_rates[i])) | ||
788 | continue; | ||
789 | |||
790 | mi->cck_supported |= BIT(i); | ||
791 | if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE) | ||
792 | mi->cck_supported_short |= BIT(i); | ||
793 | } | ||
794 | |||
795 | mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported; | ||
796 | } | ||
797 | |||
798 | static void | ||
690 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 799 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, |
691 | struct ieee80211_sta *sta, void *priv_sta) | 800 | struct ieee80211_sta *sta, void *priv_sta) |
692 | { | 801 | { |
@@ -699,14 +808,13 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
699 | int ack_dur; | 808 | int ack_dur; |
700 | int stbc; | 809 | int stbc; |
701 | int i; | 810 | int i; |
702 | unsigned int smps; | ||
703 | 811 | ||
704 | /* fall back to the old minstrel for legacy stations */ | 812 | /* fall back to the old minstrel for legacy stations */ |
705 | if (!sta->ht_cap.ht_supported) | 813 | if (!sta->ht_cap.ht_supported) |
706 | goto use_legacy; | 814 | goto use_legacy; |
707 | 815 | ||
708 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != | 816 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != |
709 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); | 817 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1); |
710 | 818 | ||
711 | msp->is_ht = true; | 819 | msp->is_ht = true; |
712 | memset(mi, 0, sizeof(*mi)); | 820 | memset(mi, 0, sizeof(*mi)); |
@@ -735,28 +843,29 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
735 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) | 843 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
736 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 844 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
737 | 845 | ||
738 | smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >> | ||
739 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
740 | |||
741 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 846 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
742 | u16 req = 0; | ||
743 | |||
744 | mi->groups[i].supported = 0; | 847 | mi->groups[i].supported = 0; |
745 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { | 848 | if (i == MINSTREL_CCK_GROUP) { |
746 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 849 | minstrel_ht_update_cck(mp, mi, sband, sta); |
747 | req |= IEEE80211_HT_CAP_SGI_40; | 850 | continue; |
748 | else | ||
749 | req |= IEEE80211_HT_CAP_SGI_20; | ||
750 | } | 851 | } |
751 | 852 | ||
752 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 853 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { |
753 | req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 854 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
855 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) | ||
856 | continue; | ||
857 | } else { | ||
858 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_20)) | ||
859 | continue; | ||
860 | } | ||
861 | } | ||
754 | 862 | ||
755 | if ((sta_cap & req) != req) | 863 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH && |
864 | sta->bandwidth < IEEE80211_STA_RX_BW_40) | ||
756 | continue; | 865 | continue; |
757 | 866 | ||
758 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 867 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ |
759 | if (smps == WLAN_HT_CAP_SM_PS_STATIC && | 868 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && |
760 | minstrel_mcs_groups[i].streams > 1) | 869 | minstrel_mcs_groups[i].streams > 1) |
761 | continue; | 870 | continue; |
762 | 871 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 462d2b227ed5..302dbd52180d 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -107,8 +107,11 @@ struct minstrel_ht_sta { | |||
107 | /* current MCS group to be sampled */ | 107 | /* current MCS group to be sampled */ |
108 | u8 sample_group; | 108 | u8 sample_group; |
109 | 109 | ||
110 | u8 cck_supported; | ||
111 | u8 cck_supported_short; | ||
112 | |||
110 | /* MCS rate group info and statistics */ | 113 | /* MCS rate group info and statistics */ |
111 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; | 114 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1]; |
112 | }; | 115 | }; |
113 | 116 | ||
114 | struct minstrel_ht_sta_priv { | 117 | struct minstrel_ht_sta_priv { |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index e788f76a1dfe..df44a5ad8270 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -15,13 +15,76 @@ | |||
15 | #include "rc80211_minstrel.h" | 15 | #include "rc80211_minstrel.h" |
16 | #include "rc80211_minstrel_ht.h" | 16 | #include "rc80211_minstrel_ht.h" |
17 | 17 | ||
18 | static char * | ||
19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | ||
20 | { | ||
21 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
22 | const struct mcs_group *mg; | ||
23 | unsigned int j, tp, prob, eprob; | ||
24 | char htmode = '2'; | ||
25 | char gimode = 'L'; | ||
26 | |||
27 | if (!mi->groups[i].supported) | ||
28 | return p; | ||
29 | |||
30 | mg = &minstrel_mcs_groups[i]; | ||
31 | if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
32 | htmode = '4'; | ||
33 | if (mg->flags & IEEE80211_TX_RC_SHORT_GI) | ||
34 | gimode = 'S'; | ||
35 | |||
36 | for (j = 0; j < MCS_GROUP_RATES; j++) { | ||
37 | struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; | ||
38 | static const int bitrates[4] = { 10, 20, 55, 110 }; | ||
39 | int idx = i * MCS_GROUP_RATES + j; | ||
40 | |||
41 | if (!(mi->groups[i].supported & BIT(j))) | ||
42 | continue; | ||
43 | |||
44 | if (i == max_mcs) | ||
45 | p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); | ||
46 | else | ||
47 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | ||
48 | |||
49 | *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; | ||
50 | *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; | ||
51 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | ||
52 | |||
53 | if (i == max_mcs) { | ||
54 | int r = bitrates[j % 4]; | ||
55 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | ||
56 | } else { | ||
57 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * | ||
58 | MCS_GROUP_RATES + j); | ||
59 | } | ||
60 | |||
61 | tp = mr->cur_tp / 10; | ||
62 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); | ||
63 | eprob = MINSTREL_TRUNC(mr->probability * 1000); | ||
64 | |||
65 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | ||
66 | "%3u %3u(%3u) %8llu %8llu\n", | ||
67 | tp / 10, tp % 10, | ||
68 | eprob / 10, eprob % 10, | ||
69 | prob / 10, prob % 10, | ||
70 | mr->retry_count, | ||
71 | mr->last_success, | ||
72 | mr->last_attempts, | ||
73 | (unsigned long long)mr->succ_hist, | ||
74 | (unsigned long long)mr->att_hist); | ||
75 | } | ||
76 | |||
77 | return p; | ||
78 | } | ||
79 | |||
18 | static int | 80 | static int |
19 | minstrel_ht_stats_open(struct inode *inode, struct file *file) | 81 | minstrel_ht_stats_open(struct inode *inode, struct file *file) |
20 | { | 82 | { |
21 | struct minstrel_ht_sta_priv *msp = inode->i_private; | 83 | struct minstrel_ht_sta_priv *msp = inode->i_private; |
22 | struct minstrel_ht_sta *mi = &msp->ht; | 84 | struct minstrel_ht_sta *mi = &msp->ht; |
23 | struct minstrel_debugfs_info *ms; | 85 | struct minstrel_debugfs_info *ms; |
24 | unsigned int i, j, tp, prob, eprob; | 86 | unsigned int i; |
87 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
25 | char *p; | 88 | char *p; |
26 | int ret; | 89 | int ret; |
27 | 90 | ||
@@ -38,50 +101,13 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
38 | 101 | ||
39 | file->private_data = ms; | 102 | file->private_data = ms; |
40 | p = ms->buf; | 103 | p = ms->buf; |
41 | p += sprintf(p, "type rate throughput ewma prob this prob " | 104 | p += sprintf(p, "type rate throughput ewma prob this prob " |
42 | "this succ/attempt success attempts\n"); | 105 | "retry this succ/attempt success attempts\n"); |
43 | for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) { | ||
44 | char htmode = '2'; | ||
45 | char gimode = 'L'; | ||
46 | |||
47 | if (!mi->groups[i].supported) | ||
48 | continue; | ||
49 | |||
50 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
51 | htmode = '4'; | ||
52 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) | ||
53 | gimode = 'S'; | ||
54 | 106 | ||
55 | for (j = 0; j < MCS_GROUP_RATES; j++) { | 107 | p = minstrel_ht_stats_dump(mi, max_mcs, p); |
56 | struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; | 108 | for (i = 0; i < max_mcs; i++) |
57 | int idx = i * MCS_GROUP_RATES + j; | 109 | p = minstrel_ht_stats_dump(mi, i, p); |
58 | 110 | ||
59 | if (!(mi->groups[i].supported & BIT(j))) | ||
60 | continue; | ||
61 | |||
62 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | ||
63 | |||
64 | *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; | ||
65 | *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; | ||
66 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | ||
67 | p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) * | ||
68 | MCS_GROUP_RATES + j); | ||
69 | |||
70 | tp = mr->cur_tp / 10; | ||
71 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); | ||
72 | eprob = MINSTREL_TRUNC(mr->probability * 1000); | ||
73 | |||
74 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | ||
75 | "%3u(%3u) %8llu %8llu\n", | ||
76 | tp / 10, tp % 10, | ||
77 | eprob / 10, eprob % 10, | ||
78 | prob / 10, prob % 10, | ||
79 | mr->last_success, | ||
80 | mr->last_attempts, | ||
81 | (unsigned long long)mr->succ_hist, | ||
82 | (unsigned long long)mr->att_hist); | ||
83 | } | ||
84 | } | ||
85 | p += sprintf(p, "\nTotal packet count:: ideal %d " | 111 | p += sprintf(p, "\nTotal packet count:: ideal %d " |
86 | "lookaround %d\n", | 112 | "lookaround %d\n", |
87 | max(0, (int) mi->total_packets - (int) mi->sample_packets), | 113 | max(0, (int) mi->total_packets - (int) mi->sample_packets), |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a19089565c4b..3acb70b73e22 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -668,9 +668,9 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) | |||
668 | 668 | ||
669 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 669 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
670 | struct tid_ampdu_rx *tid_agg_rx, | 670 | struct tid_ampdu_rx *tid_agg_rx, |
671 | int index) | 671 | int index, |
672 | struct sk_buff_head *frames) | ||
672 | { | 673 | { |
673 | struct ieee80211_local *local = sdata->local; | ||
674 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 674 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; |
675 | struct ieee80211_rx_status *status; | 675 | struct ieee80211_rx_status *status; |
676 | 676 | ||
@@ -684,7 +684,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
684 | tid_agg_rx->reorder_buf[index] = NULL; | 684 | tid_agg_rx->reorder_buf[index] = NULL; |
685 | status = IEEE80211_SKB_RXCB(skb); | 685 | status = IEEE80211_SKB_RXCB(skb); |
686 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; | 686 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; |
687 | skb_queue_tail(&local->rx_skb_queue, skb); | 687 | __skb_queue_tail(frames, skb); |
688 | 688 | ||
689 | no_frame: | 689 | no_frame: |
690 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 690 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); |
@@ -692,7 +692,8 @@ no_frame: | |||
692 | 692 | ||
693 | static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, | 693 | static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, |
694 | struct tid_ampdu_rx *tid_agg_rx, | 694 | struct tid_ampdu_rx *tid_agg_rx, |
695 | u16 head_seq_num) | 695 | u16 head_seq_num, |
696 | struct sk_buff_head *frames) | ||
696 | { | 697 | { |
697 | int index; | 698 | int index; |
698 | 699 | ||
@@ -701,7 +702,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata | |||
701 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 702 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
702 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 703 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
703 | tid_agg_rx->buf_size; | 704 | tid_agg_rx->buf_size; |
704 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index); | 705 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
706 | frames); | ||
705 | } | 707 | } |
706 | } | 708 | } |
707 | 709 | ||
@@ -717,7 +719,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata | |||
717 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) | 719 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) |
718 | 720 | ||
719 | static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | 721 | static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, |
720 | struct tid_ampdu_rx *tid_agg_rx) | 722 | struct tid_ampdu_rx *tid_agg_rx, |
723 | struct sk_buff_head *frames) | ||
721 | { | 724 | { |
722 | int index, j; | 725 | int index, j; |
723 | 726 | ||
@@ -746,7 +749,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
746 | 749 | ||
747 | ht_dbg_ratelimited(sdata, | 750 | ht_dbg_ratelimited(sdata, |
748 | "release an RX reorder frame due to timeout on earlier frames\n"); | 751 | "release an RX reorder frame due to timeout on earlier frames\n"); |
749 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j); | 752 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, |
753 | frames); | ||
750 | 754 | ||
751 | /* | 755 | /* |
752 | * Increment the head seq# also for the skipped slots. | 756 | * Increment the head seq# also for the skipped slots. |
@@ -756,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
756 | skipped = 0; | 760 | skipped = 0; |
757 | } | 761 | } |
758 | } else while (tid_agg_rx->reorder_buf[index]) { | 762 | } else while (tid_agg_rx->reorder_buf[index]) { |
759 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index); | 763 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
764 | frames); | ||
760 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 765 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
761 | tid_agg_rx->buf_size; | 766 | tid_agg_rx->buf_size; |
762 | } | 767 | } |
@@ -788,7 +793,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
788 | */ | 793 | */ |
789 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata, | 794 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata, |
790 | struct tid_ampdu_rx *tid_agg_rx, | 795 | struct tid_ampdu_rx *tid_agg_rx, |
791 | struct sk_buff *skb) | 796 | struct sk_buff *skb, |
797 | struct sk_buff_head *frames) | ||
792 | { | 798 | { |
793 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 799 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
794 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | 800 | u16 sc = le16_to_cpu(hdr->seq_ctrl); |
@@ -816,7 +822,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
816 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); | 822 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); |
817 | /* release stored frames up to new head to stack */ | 823 | /* release stored frames up to new head to stack */ |
818 | ieee80211_release_reorder_frames(sdata, tid_agg_rx, | 824 | ieee80211_release_reorder_frames(sdata, tid_agg_rx, |
819 | head_seq_num); | 825 | head_seq_num, frames); |
820 | } | 826 | } |
821 | 827 | ||
822 | /* Now the new frame is always in the range of the reordering buffer */ | 828 | /* Now the new frame is always in the range of the reordering buffer */ |
@@ -846,7 +852,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
846 | tid_agg_rx->reorder_buf[index] = skb; | 852 | tid_agg_rx->reorder_buf[index] = skb; |
847 | tid_agg_rx->reorder_time[index] = jiffies; | 853 | tid_agg_rx->reorder_time[index] = jiffies; |
848 | tid_agg_rx->stored_mpdu_num++; | 854 | tid_agg_rx->stored_mpdu_num++; |
849 | ieee80211_sta_reorder_release(sdata, tid_agg_rx); | 855 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); |
850 | 856 | ||
851 | out: | 857 | out: |
852 | spin_unlock(&tid_agg_rx->reorder_lock); | 858 | spin_unlock(&tid_agg_rx->reorder_lock); |
@@ -857,7 +863,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
857 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns | 863 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns |
858 | * true if the MPDU was buffered, false if it should be processed. | 864 | * true if the MPDU was buffered, false if it should be processed. |
859 | */ | 865 | */ |
860 | static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) | 866 | static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, |
867 | struct sk_buff_head *frames) | ||
861 | { | 868 | { |
862 | struct sk_buff *skb = rx->skb; | 869 | struct sk_buff *skb = rx->skb; |
863 | struct ieee80211_local *local = rx->local; | 870 | struct ieee80211_local *local = rx->local; |
@@ -922,11 +929,12 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) | |||
922 | * sure that we cannot get to it any more before doing | 929 | * sure that we cannot get to it any more before doing |
923 | * anything with it. | 930 | * anything with it. |
924 | */ | 931 | */ |
925 | if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb)) | 932 | if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb, |
933 | frames)) | ||
926 | return; | 934 | return; |
927 | 935 | ||
928 | dont_reorder: | 936 | dont_reorder: |
929 | skb_queue_tail(&local->rx_skb_queue, skb); | 937 | __skb_queue_tail(frames, skb); |
930 | } | 938 | } |
931 | 939 | ||
932 | static ieee80211_rx_result debug_noinline | 940 | static ieee80211_rx_result debug_noinline |
@@ -1452,6 +1460,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1452 | } | 1460 | } |
1453 | } | 1461 | } |
1454 | 1462 | ||
1463 | /* mesh power save support */ | ||
1464 | if (ieee80211_vif_is_mesh(&rx->sdata->vif)) | ||
1465 | ieee80211_mps_rx_h_sta_process(sta, hdr); | ||
1466 | |||
1455 | /* | 1467 | /* |
1456 | * Drop (qos-)data::nullfunc frames silently, since they | 1468 | * Drop (qos-)data::nullfunc frames silently, since they |
1457 | * are used only to control station power saving mode. | 1469 | * are used only to control station power saving mode. |
@@ -2090,7 +2102,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2090 | if (is_multicast_ether_addr(fwd_hdr->addr1)) { | 2102 | if (is_multicast_ether_addr(fwd_hdr->addr1)) { |
2091 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast); | 2103 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast); |
2092 | memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); | 2104 | memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); |
2105 | /* update power mode indication when forwarding */ | ||
2106 | ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr); | ||
2093 | } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) { | 2107 | } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) { |
2108 | /* mesh power mode flags updated in mesh_nexthop_lookup */ | ||
2094 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast); | 2109 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast); |
2095 | } else { | 2110 | } else { |
2096 | /* unable to resolve next hop */ | 2111 | /* unable to resolve next hop */ |
@@ -2177,7 +2192,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
2177 | } | 2192 | } |
2178 | 2193 | ||
2179 | static ieee80211_rx_result debug_noinline | 2194 | static ieee80211_rx_result debug_noinline |
2180 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | 2195 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) |
2181 | { | 2196 | { |
2182 | struct sk_buff *skb = rx->skb; | 2197 | struct sk_buff *skb = rx->skb; |
2183 | struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; | 2198 | struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; |
@@ -2216,7 +2231,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
2216 | spin_lock(&tid_agg_rx->reorder_lock); | 2231 | spin_lock(&tid_agg_rx->reorder_lock); |
2217 | /* release stored frames up to start of BAR */ | 2232 | /* release stored frames up to start of BAR */ |
2218 | ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx, | 2233 | ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx, |
2219 | start_seq_num); | 2234 | start_seq_num, frames); |
2220 | spin_unlock(&tid_agg_rx->reorder_lock); | 2235 | spin_unlock(&tid_agg_rx->reorder_lock); |
2221 | 2236 | ||
2222 | kfree_skb(skb); | 2237 | kfree_skb(skb); |
@@ -2360,31 +2375,27 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2360 | switch (mgmt->u.action.u.ht_smps.action) { | 2375 | switch (mgmt->u.action.u.ht_smps.action) { |
2361 | case WLAN_HT_ACTION_SMPS: { | 2376 | case WLAN_HT_ACTION_SMPS: { |
2362 | struct ieee80211_supported_band *sband; | 2377 | struct ieee80211_supported_band *sband; |
2363 | u8 smps; | 2378 | enum ieee80211_smps_mode smps_mode; |
2364 | 2379 | ||
2365 | /* convert to HT capability */ | 2380 | /* convert to HT capability */ |
2366 | switch (mgmt->u.action.u.ht_smps.smps_control) { | 2381 | switch (mgmt->u.action.u.ht_smps.smps_control) { |
2367 | case WLAN_HT_SMPS_CONTROL_DISABLED: | 2382 | case WLAN_HT_SMPS_CONTROL_DISABLED: |
2368 | smps = WLAN_HT_CAP_SM_PS_DISABLED; | 2383 | smps_mode = IEEE80211_SMPS_OFF; |
2369 | break; | 2384 | break; |
2370 | case WLAN_HT_SMPS_CONTROL_STATIC: | 2385 | case WLAN_HT_SMPS_CONTROL_STATIC: |
2371 | smps = WLAN_HT_CAP_SM_PS_STATIC; | 2386 | smps_mode = IEEE80211_SMPS_STATIC; |
2372 | break; | 2387 | break; |
2373 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: | 2388 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: |
2374 | smps = WLAN_HT_CAP_SM_PS_DYNAMIC; | 2389 | smps_mode = IEEE80211_SMPS_DYNAMIC; |
2375 | break; | 2390 | break; |
2376 | default: | 2391 | default: |
2377 | goto invalid; | 2392 | goto invalid; |
2378 | } | 2393 | } |
2379 | smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
2380 | 2394 | ||
2381 | /* if no change do nothing */ | 2395 | /* if no change do nothing */ |
2382 | if ((rx->sta->sta.ht_cap.cap & | 2396 | if (rx->sta->sta.smps_mode == smps_mode) |
2383 | IEEE80211_HT_CAP_SM_PS) == smps) | ||
2384 | goto handled; | 2397 | goto handled; |
2385 | 2398 | rx->sta->sta.smps_mode = smps_mode; | |
2386 | rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
2387 | rx->sta->sta.ht_cap.cap |= smps; | ||
2388 | 2399 | ||
2389 | sband = rx->local->hw.wiphy->bands[status->band]; | 2400 | sband = rx->local->hw.wiphy->bands[status->band]; |
2390 | 2401 | ||
@@ -2395,26 +2406,21 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2395 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { | 2406 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { |
2396 | struct ieee80211_supported_band *sband; | 2407 | struct ieee80211_supported_band *sband; |
2397 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; | 2408 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; |
2398 | bool old_40mhz, new_40mhz; | 2409 | enum ieee80211_sta_rx_bandwidth new_bw; |
2399 | 2410 | ||
2400 | /* If it doesn't support 40 MHz it can't change ... */ | 2411 | /* If it doesn't support 40 MHz it can't change ... */ |
2401 | if (!rx->sta->supports_40mhz) | 2412 | if (!(rx->sta->sta.ht_cap.cap & |
2413 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
2402 | goto handled; | 2414 | goto handled; |
2403 | 2415 | ||
2404 | old_40mhz = rx->sta->sta.ht_cap.cap & | 2416 | if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) |
2405 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 2417 | new_bw = IEEE80211_STA_RX_BW_20; |
2406 | new_40mhz = chanwidth == IEEE80211_HT_CHANWIDTH_ANY; | 2418 | else |
2419 | new_bw = ieee80211_sta_cur_vht_bw(rx->sta); | ||
2407 | 2420 | ||
2408 | if (old_40mhz == new_40mhz) | 2421 | if (rx->sta->sta.bandwidth == new_bw) |
2409 | goto handled; | 2422 | goto handled; |
2410 | 2423 | ||
2411 | if (new_40mhz) | ||
2412 | rx->sta->sta.ht_cap.cap |= | ||
2413 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2414 | else | ||
2415 | rx->sta->sta.ht_cap.cap &= | ||
2416 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2417 | |||
2418 | sband = rx->local->hw.wiphy->bands[status->band]; | 2424 | sband = rx->local->hw.wiphy->bands[status->band]; |
2419 | 2425 | ||
2420 | rate_control_rate_update(local, sband, rx->sta, | 2426 | rate_control_rate_update(local, sband, rx->sta, |
@@ -2426,6 +2432,37 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2426 | } | 2432 | } |
2427 | 2433 | ||
2428 | break; | 2434 | break; |
2435 | case WLAN_CATEGORY_VHT: | ||
2436 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
2437 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | ||
2438 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
2439 | sdata->vif.type != NL80211_IFTYPE_AP && | ||
2440 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
2441 | break; | ||
2442 | |||
2443 | /* verify action code is present */ | ||
2444 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
2445 | goto invalid; | ||
2446 | |||
2447 | switch (mgmt->u.action.u.vht_opmode_notif.action_code) { | ||
2448 | case WLAN_VHT_ACTION_OPMODE_NOTIF: { | ||
2449 | u8 opmode; | ||
2450 | |||
2451 | /* verify opmode is present */ | ||
2452 | if (len < IEEE80211_MIN_ACTION_SIZE + 2) | ||
2453 | goto invalid; | ||
2454 | |||
2455 | opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode; | ||
2456 | |||
2457 | ieee80211_vht_handle_opmode(rx->sdata, rx->sta, | ||
2458 | opmode, status->band, | ||
2459 | false); | ||
2460 | goto handled; | ||
2461 | } | ||
2462 | default: | ||
2463 | break; | ||
2464 | } | ||
2465 | break; | ||
2429 | case WLAN_CATEGORY_BACK: | 2466 | case WLAN_CATEGORY_BACK: |
2430 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 2467 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
2431 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | 2468 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
@@ -2677,8 +2714,9 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2677 | return RX_DROP_MONITOR; | 2714 | return RX_DROP_MONITOR; |
2678 | break; | 2715 | break; |
2679 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | 2716 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): |
2680 | /* process only for ibss */ | 2717 | /* process only for ibss and mesh */ |
2681 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | 2718 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2719 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
2682 | return RX_DROP_MONITOR; | 2720 | return RX_DROP_MONITOR; |
2683 | break; | 2721 | break; |
2684 | default: | 2722 | default: |
@@ -2801,7 +2839,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, | |||
2801 | } | 2839 | } |
2802 | } | 2840 | } |
2803 | 2841 | ||
2804 | static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) | 2842 | static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, |
2843 | struct sk_buff_head *frames) | ||
2805 | { | 2844 | { |
2806 | ieee80211_rx_result res = RX_DROP_MONITOR; | 2845 | ieee80211_rx_result res = RX_DROP_MONITOR; |
2807 | struct sk_buff *skb; | 2846 | struct sk_buff *skb; |
@@ -2813,15 +2852,9 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) | |||
2813 | goto rxh_next; \ | 2852 | goto rxh_next; \ |
2814 | } while (0); | 2853 | } while (0); |
2815 | 2854 | ||
2816 | spin_lock(&rx->local->rx_skb_queue.lock); | 2855 | spin_lock_bh(&rx->local->rx_path_lock); |
2817 | if (rx->local->running_rx_handler) | ||
2818 | goto unlock; | ||
2819 | |||
2820 | rx->local->running_rx_handler = true; | ||
2821 | |||
2822 | while ((skb = __skb_dequeue(&rx->local->rx_skb_queue))) { | ||
2823 | spin_unlock(&rx->local->rx_skb_queue.lock); | ||
2824 | 2856 | ||
2857 | while ((skb = __skb_dequeue(frames))) { | ||
2825 | /* | 2858 | /* |
2826 | * all the other fields are valid across frames | 2859 | * all the other fields are valid across frames |
2827 | * that belong to an aMPDU since they are on the | 2860 | * that belong to an aMPDU since they are on the |
@@ -2842,7 +2875,12 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) | |||
2842 | #endif | 2875 | #endif |
2843 | CALL_RXH(ieee80211_rx_h_amsdu) | 2876 | CALL_RXH(ieee80211_rx_h_amsdu) |
2844 | CALL_RXH(ieee80211_rx_h_data) | 2877 | CALL_RXH(ieee80211_rx_h_data) |
2845 | CALL_RXH(ieee80211_rx_h_ctrl); | 2878 | |
2879 | /* special treatment -- needs the queue */ | ||
2880 | res = ieee80211_rx_h_ctrl(rx, frames); | ||
2881 | if (res != RX_CONTINUE) | ||
2882 | goto rxh_next; | ||
2883 | |||
2846 | CALL_RXH(ieee80211_rx_h_mgmt_check) | 2884 | CALL_RXH(ieee80211_rx_h_mgmt_check) |
2847 | CALL_RXH(ieee80211_rx_h_action) | 2885 | CALL_RXH(ieee80211_rx_h_action) |
2848 | CALL_RXH(ieee80211_rx_h_userspace_mgmt) | 2886 | CALL_RXH(ieee80211_rx_h_userspace_mgmt) |
@@ -2851,20 +2889,20 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) | |||
2851 | 2889 | ||
2852 | rxh_next: | 2890 | rxh_next: |
2853 | ieee80211_rx_handlers_result(rx, res); | 2891 | ieee80211_rx_handlers_result(rx, res); |
2854 | spin_lock(&rx->local->rx_skb_queue.lock); | 2892 | |
2855 | #undef CALL_RXH | 2893 | #undef CALL_RXH |
2856 | } | 2894 | } |
2857 | 2895 | ||
2858 | rx->local->running_rx_handler = false; | 2896 | spin_unlock_bh(&rx->local->rx_path_lock); |
2859 | |||
2860 | unlock: | ||
2861 | spin_unlock(&rx->local->rx_skb_queue.lock); | ||
2862 | } | 2897 | } |
2863 | 2898 | ||
2864 | static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | 2899 | static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) |
2865 | { | 2900 | { |
2901 | struct sk_buff_head reorder_release; | ||
2866 | ieee80211_rx_result res = RX_DROP_MONITOR; | 2902 | ieee80211_rx_result res = RX_DROP_MONITOR; |
2867 | 2903 | ||
2904 | __skb_queue_head_init(&reorder_release); | ||
2905 | |||
2868 | #define CALL_RXH(rxh) \ | 2906 | #define CALL_RXH(rxh) \ |
2869 | do { \ | 2907 | do { \ |
2870 | res = rxh(rx); \ | 2908 | res = rxh(rx); \ |
@@ -2874,9 +2912,9 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
2874 | 2912 | ||
2875 | CALL_RXH(ieee80211_rx_h_check) | 2913 | CALL_RXH(ieee80211_rx_h_check) |
2876 | 2914 | ||
2877 | ieee80211_rx_reorder_ampdu(rx); | 2915 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); |
2878 | 2916 | ||
2879 | ieee80211_rx_handlers(rx); | 2917 | ieee80211_rx_handlers(rx, &reorder_release); |
2880 | return; | 2918 | return; |
2881 | 2919 | ||
2882 | rxh_next: | 2920 | rxh_next: |
@@ -2891,6 +2929,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
2891 | */ | 2929 | */ |
2892 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | 2930 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) |
2893 | { | 2931 | { |
2932 | struct sk_buff_head frames; | ||
2894 | struct ieee80211_rx_data rx = { | 2933 | struct ieee80211_rx_data rx = { |
2895 | .sta = sta, | 2934 | .sta = sta, |
2896 | .sdata = sta->sdata, | 2935 | .sdata = sta->sdata, |
@@ -2906,11 +2945,13 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | |||
2906 | if (!tid_agg_rx) | 2945 | if (!tid_agg_rx) |
2907 | return; | 2946 | return; |
2908 | 2947 | ||
2948 | __skb_queue_head_init(&frames); | ||
2949 | |||
2909 | spin_lock(&tid_agg_rx->reorder_lock); | 2950 | spin_lock(&tid_agg_rx->reorder_lock); |
2910 | ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx); | 2951 | ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames); |
2911 | spin_unlock(&tid_agg_rx->reorder_lock); | 2952 | spin_unlock(&tid_agg_rx->reorder_lock); |
2912 | 2953 | ||
2913 | ieee80211_rx_handlers(&rx); | 2954 | ieee80211_rx_handlers(&rx, &frames); |
2914 | } | 2955 | } |
2915 | 2956 | ||
2916 | /* main receive path */ | 2957 | /* main receive path */ |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 607684c47d55..43a45cf00e06 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -27,22 +27,15 @@ | |||
27 | 27 | ||
28 | #define IEEE80211_PROBE_DELAY (HZ / 33) | 28 | #define IEEE80211_PROBE_DELAY (HZ / 33) |
29 | #define IEEE80211_CHANNEL_TIME (HZ / 33) | 29 | #define IEEE80211_CHANNEL_TIME (HZ / 33) |
30 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8) | 30 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 9) |
31 | |||
32 | static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) | ||
33 | { | ||
34 | struct ieee80211_bss *bss = (void *)cbss->priv; | ||
35 | |||
36 | kfree(bss_mesh_id(bss)); | ||
37 | kfree(bss_mesh_cfg(bss)); | ||
38 | } | ||
39 | 31 | ||
40 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 32 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
41 | struct ieee80211_bss *bss) | 33 | struct ieee80211_bss *bss) |
42 | { | 34 | { |
43 | if (!bss) | 35 | if (!bss) |
44 | return; | 36 | return; |
45 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); | 37 | cfg80211_put_bss(local->hw.wiphy, |
38 | container_of((void *)bss, struct cfg80211_bss, priv)); | ||
46 | } | 39 | } |
47 | 40 | ||
48 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) | 41 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) |
@@ -85,10 +78,12 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
85 | if (!cbss) | 78 | if (!cbss) |
86 | return NULL; | 79 | return NULL; |
87 | 80 | ||
88 | cbss->free_priv = ieee80211_rx_bss_free; | ||
89 | bss = (void *)cbss->priv; | 81 | bss = (void *)cbss->priv; |
90 | 82 | ||
91 | bss->device_ts = rx_status->device_timestamp; | 83 | if (beacon) |
84 | bss->device_ts_beacon = rx_status->device_timestamp; | ||
85 | else | ||
86 | bss->device_ts_presp = rx_status->device_timestamp; | ||
92 | 87 | ||
93 | if (elems->parse_error) { | 88 | if (elems->parse_error) { |
94 | if (beacon) | 89 | if (beacon) |
@@ -146,9 +141,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
146 | bss->valid_data |= IEEE80211_BSS_VALID_WMM; | 141 | bss->valid_data |= IEEE80211_BSS_VALID_WMM; |
147 | } | 142 | } |
148 | 143 | ||
149 | if (!beacon) | ||
150 | bss->last_probe_resp = jiffies; | ||
151 | |||
152 | return bss; | 144 | return bss; |
153 | } | 145 | } |
154 | 146 | ||
@@ -342,6 +334,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
342 | 334 | ||
343 | ieee80211_offchannel_stop_vifs(local); | 335 | ieee80211_offchannel_stop_vifs(local); |
344 | 336 | ||
337 | /* ensure nullfunc is transmitted before leaving operating channel */ | ||
338 | drv_flush(local, false); | ||
339 | |||
345 | ieee80211_configure_filter(local); | 340 | ieee80211_configure_filter(local); |
346 | 341 | ||
347 | /* We need to set power level at maximum rate for scanning. */ | 342 | /* We need to set power level at maximum rate for scanning. */ |
@@ -356,6 +351,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
356 | static bool ieee80211_can_scan(struct ieee80211_local *local, | 351 | static bool ieee80211_can_scan(struct ieee80211_local *local, |
357 | struct ieee80211_sub_if_data *sdata) | 352 | struct ieee80211_sub_if_data *sdata) |
358 | { | 353 | { |
354 | if (local->radar_detect_enabled) | ||
355 | return false; | ||
356 | |||
359 | if (!list_empty(&local->roc_list)) | 357 | if (!list_empty(&local->roc_list)) |
360 | return false; | 358 | return false; |
361 | 359 | ||
@@ -390,6 +388,11 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
390 | int i; | 388 | int i; |
391 | struct ieee80211_sub_if_data *sdata; | 389 | struct ieee80211_sub_if_data *sdata; |
392 | enum ieee80211_band band = local->hw.conf.channel->band; | 390 | enum ieee80211_band band = local->hw.conf.channel->band; |
391 | u32 tx_flags; | ||
392 | |||
393 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | ||
394 | if (local->scan_req->no_cck) | ||
395 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | ||
393 | 396 | ||
394 | sdata = rcu_dereference_protected(local->scan_sdata, | 397 | sdata = rcu_dereference_protected(local->scan_sdata, |
395 | lockdep_is_held(&local->mtx)); | 398 | lockdep_is_held(&local->mtx)); |
@@ -401,8 +404,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
401 | local->scan_req->ssids[i].ssid_len, | 404 | local->scan_req->ssids[i].ssid_len, |
402 | local->scan_req->ie, local->scan_req->ie_len, | 405 | local->scan_req->ie, local->scan_req->ie_len, |
403 | local->scan_req->rates[band], false, | 406 | local->scan_req->rates[band], false, |
404 | local->scan_req->no_cck, | 407 | tx_flags, local->hw.conf.channel, true); |
405 | local->hw.conf.channel, true); | ||
406 | 408 | ||
407 | /* | 409 | /* |
408 | * After sending probe requests, wait for probe responses | 410 | * After sending probe requests, wait for probe responses |
@@ -546,8 +548,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
546 | bool associated = false; | 548 | bool associated = false; |
547 | bool tx_empty = true; | 549 | bool tx_empty = true; |
548 | bool bad_latency; | 550 | bool bad_latency; |
549 | bool listen_int_exceeded; | ||
550 | unsigned long min_beacon_int = 0; | ||
551 | struct ieee80211_sub_if_data *sdata; | 551 | struct ieee80211_sub_if_data *sdata; |
552 | struct ieee80211_channel *next_chan; | 552 | struct ieee80211_channel *next_chan; |
553 | enum mac80211_scan_state next_scan_state; | 553 | enum mac80211_scan_state next_scan_state; |
@@ -566,11 +566,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
566 | if (sdata->u.mgd.associated) { | 566 | if (sdata->u.mgd.associated) { |
567 | associated = true; | 567 | associated = true; |
568 | 568 | ||
569 | if (sdata->vif.bss_conf.beacon_int < | ||
570 | min_beacon_int || min_beacon_int == 0) | ||
571 | min_beacon_int = | ||
572 | sdata->vif.bss_conf.beacon_int; | ||
573 | |||
574 | if (!qdisc_all_tx_empty(sdata->dev)) { | 569 | if (!qdisc_all_tx_empty(sdata->dev)) { |
575 | tx_empty = false; | 570 | tx_empty = false; |
576 | break; | 571 | break; |
@@ -587,34 +582,19 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
587 | * see if we can scan another channel without interfering | 582 | * see if we can scan another channel without interfering |
588 | * with the current traffic situation. | 583 | * with the current traffic situation. |
589 | * | 584 | * |
590 | * Since we don't know if the AP has pending frames for us | 585 | * Keep good latency, do not stay off-channel more than 125 ms. |
591 | * we can only check for our tx queues and use the current | ||
592 | * pm_qos requirements for rx. Hence, if no tx traffic occurs | ||
593 | * at all we will scan as many channels in a row as the pm_qos | ||
594 | * latency allows us to. Additionally we also check for the | ||
595 | * currently negotiated listen interval to prevent losing | ||
596 | * frames unnecessarily. | ||
597 | * | ||
598 | * Otherwise switch back to the operating channel. | ||
599 | */ | 586 | */ |
600 | 587 | ||
601 | bad_latency = time_after(jiffies + | 588 | bad_latency = time_after(jiffies + |
602 | ieee80211_scan_get_channel_time(next_chan), | 589 | ieee80211_scan_get_channel_time(next_chan), |
603 | local->leave_oper_channel_time + | 590 | local->leave_oper_channel_time + HZ / 8); |
604 | usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY))); | ||
605 | |||
606 | listen_int_exceeded = time_after(jiffies + | ||
607 | ieee80211_scan_get_channel_time(next_chan), | ||
608 | local->leave_oper_channel_time + | ||
609 | usecs_to_jiffies(min_beacon_int * 1024) * | ||
610 | local->hw.conf.listen_interval); | ||
611 | 591 | ||
612 | if (associated && !tx_empty) { | 592 | if (associated && !tx_empty) { |
613 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | 593 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
614 | next_scan_state = SCAN_ABORT; | 594 | next_scan_state = SCAN_ABORT; |
615 | else | 595 | else |
616 | next_scan_state = SCAN_SUSPEND; | 596 | next_scan_state = SCAN_SUSPEND; |
617 | } else if (associated && (bad_latency || listen_int_exceeded)) { | 597 | } else if (associated && bad_latency) { |
618 | next_scan_state = SCAN_SUSPEND; | 598 | next_scan_state = SCAN_SUSPEND; |
619 | } else { | 599 | } else { |
620 | next_scan_state = SCAN_SET_CHANNEL; | 600 | next_scan_state = SCAN_SET_CHANNEL; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 227233c3ff7f..a79ce820cb50 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -120,6 +120,8 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
120 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 120 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
121 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 121 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
122 | ps = &sdata->bss->ps; | 122 | ps = &sdata->bss->ps; |
123 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
124 | ps = &sdata->u.mesh.ps; | ||
123 | else | 125 | else |
124 | return; | 126 | return; |
125 | 127 | ||
@@ -135,13 +137,8 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
135 | ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]); | 137 | ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]); |
136 | } | 138 | } |
137 | 139 | ||
138 | #ifdef CONFIG_MAC80211_MESH | 140 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
139 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 141 | mesh_sta_cleanup(sta); |
140 | mesh_accept_plinks_update(sdata); | ||
141 | mesh_plink_deactivate(sta); | ||
142 | del_timer_sync(&sta->plink_timer); | ||
143 | } | ||
144 | #endif | ||
145 | 142 | ||
146 | cancel_work_sync(&sta->drv_unblock_wk); | 143 | cancel_work_sync(&sta->drv_unblock_wk); |
147 | 144 | ||
@@ -378,6 +375,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
378 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | 375 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
379 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); | 376 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
380 | 377 | ||
378 | sta->sta.smps_mode = IEEE80211_SMPS_OFF; | ||
379 | |||
381 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 380 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
382 | 381 | ||
383 | return sta; | 382 | return sta; |
@@ -574,7 +573,6 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
574 | { | 573 | { |
575 | struct ieee80211_local *local = sta->local; | 574 | struct ieee80211_local *local = sta->local; |
576 | struct ps_data *ps; | 575 | struct ps_data *ps; |
577 | unsigned long flags; | ||
578 | bool indicate_tim = false; | 576 | bool indicate_tim = false; |
579 | u8 ignore_for_tim = sta->sta.uapsd_queues; | 577 | u8 ignore_for_tim = sta->sta.uapsd_queues; |
580 | int ac; | 578 | int ac; |
@@ -587,6 +585,12 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
587 | 585 | ||
588 | ps = &sta->sdata->bss->ps; | 586 | ps = &sta->sdata->bss->ps; |
589 | id = sta->sta.aid; | 587 | id = sta->sta.aid; |
588 | #ifdef CONFIG_MAC80211_MESH | ||
589 | } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
590 | ps = &sta->sdata->u.mesh.ps; | ||
591 | /* TIM map only for PLID <= IEEE80211_MAX_AID */ | ||
592 | id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID; | ||
593 | #endif | ||
590 | } else { | 594 | } else { |
591 | return; | 595 | return; |
592 | } | 596 | } |
@@ -625,7 +629,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
625 | } | 629 | } |
626 | 630 | ||
627 | done: | 631 | done: |
628 | spin_lock_irqsave(&local->tim_lock, flags); | 632 | spin_lock_bh(&local->tim_lock); |
629 | 633 | ||
630 | if (indicate_tim) | 634 | if (indicate_tim) |
631 | __bss_tim_set(ps->tim, id); | 635 | __bss_tim_set(ps->tim, id); |
@@ -638,7 +642,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
638 | local->tim_in_locked_section = false; | 642 | local->tim_in_locked_section = false; |
639 | } | 643 | } |
640 | 644 | ||
641 | spin_unlock_irqrestore(&local->tim_lock, flags); | 645 | spin_unlock_bh(&local->tim_lock); |
642 | } | 646 | } |
643 | 647 | ||
644 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) | 648 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) |
@@ -745,8 +749,9 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
745 | bool have_buffered = false; | 749 | bool have_buffered = false; |
746 | int ac; | 750 | int ac; |
747 | 751 | ||
748 | /* This is only necessary for stations on BSS interfaces */ | 752 | /* This is only necessary for stations on BSS/MBSS interfaces */ |
749 | if (!sta->sdata->bss) | 753 | if (!sta->sdata->bss && |
754 | !ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
750 | return false; | 755 | return false; |
751 | 756 | ||
752 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 757 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
@@ -934,6 +939,11 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
934 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 939 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
935 | sta_dbg(sta->sdata, "expiring inactive STA %pM\n", | 940 | sta_dbg(sta->sdata, "expiring inactive STA %pM\n", |
936 | sta->sta.addr); | 941 | sta->sta.addr); |
942 | |||
943 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
944 | test_sta_flag(sta, WLAN_STA_PS_STA)) | ||
945 | atomic_dec(&sdata->u.mesh.ps.num_sta_ps); | ||
946 | |||
937 | WARN_ON(__sta_info_destroy(sta)); | 947 | WARN_ON(__sta_info_destroy(sta)); |
938 | } | 948 | } |
939 | } | 949 | } |
@@ -992,6 +1002,8 @@ static void clear_sta_ps_flags(void *_sta) | |||
992 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 1002 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
993 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1003 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
994 | ps = &sdata->bss->ps; | 1004 | ps = &sdata->bss->ps; |
1005 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
1006 | ps = &sdata->u.mesh.ps; | ||
995 | else | 1007 | else |
996 | return; | 1008 | return; |
997 | 1009 | ||
@@ -1109,6 +1121,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1109 | 1121 | ||
1110 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); | 1122 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); |
1111 | 1123 | ||
1124 | skb->dev = sdata->dev; | ||
1125 | |||
1112 | rcu_read_lock(); | 1126 | rcu_read_lock(); |
1113 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1127 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1114 | if (WARN_ON(!chanctx_conf)) { | 1128 | if (WARN_ON(!chanctx_conf)) { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index af7d78aa5523..63dfdb5e91da 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -56,6 +56,8 @@ | |||
56 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. | 56 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. |
57 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. | 57 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. |
58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. | 58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. |
59 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. | ||
60 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. | ||
59 | */ | 61 | */ |
60 | enum ieee80211_sta_info_flags { | 62 | enum ieee80211_sta_info_flags { |
61 | WLAN_STA_AUTH, | 63 | WLAN_STA_AUTH, |
@@ -78,6 +80,8 @@ enum ieee80211_sta_info_flags { | |||
78 | WLAN_STA_INSERTED, | 80 | WLAN_STA_INSERTED, |
79 | WLAN_STA_RATE_CONTROL, | 81 | WLAN_STA_RATE_CONTROL, |
80 | WLAN_STA_TOFFSET_KNOWN, | 82 | WLAN_STA_TOFFSET_KNOWN, |
83 | WLAN_STA_MPSP_OWNER, | ||
84 | WLAN_STA_MPSP_RECIPIENT, | ||
81 | }; | 85 | }; |
82 | 86 | ||
83 | #define ADDBA_RESP_INTERVAL HZ | 87 | #define ADDBA_RESP_INTERVAL HZ |
@@ -282,6 +286,9 @@ struct sta_ampdu_mlme { | |||
282 | * @t_offset_setpoint: reference timing offset of this sta to be used when | 286 | * @t_offset_setpoint: reference timing offset of this sta to be used when |
283 | * calculating clockdrift | 287 | * calculating clockdrift |
284 | * @ch_width: peer's channel width | 288 | * @ch_width: peer's channel width |
289 | * @local_pm: local link-specific power save mode | ||
290 | * @peer_pm: peer-specific power save mode towards local STA | ||
291 | * @nonpeer_pm: STA power save mode towards non-peer neighbors | ||
285 | * @debugfs: debug filesystem info | 292 | * @debugfs: debug filesystem info |
286 | * @dead: set to true when sta is unlinked | 293 | * @dead: set to true when sta is unlinked |
287 | * @uploaded: set to true when sta is uploaded to the driver | 294 | * @uploaded: set to true when sta is uploaded to the driver |
@@ -289,8 +296,9 @@ struct sta_ampdu_mlme { | |||
289 | * @sta: station information we share with the driver | 296 | * @sta: station information we share with the driver |
290 | * @sta_state: duplicates information about station state (for debug) | 297 | * @sta_state: duplicates information about station state (for debug) |
291 | * @beacon_loss_count: number of times beacon loss has triggered | 298 | * @beacon_loss_count: number of times beacon loss has triggered |
292 | * @supports_40mhz: tracks whether the station advertised 40 MHz support | 299 | * @rcu_head: RCU head used for freeing this station struct |
293 | * as we overwrite its HT parameters with the currently used value | 300 | * @cur_max_bandwidth: maximum bandwidth to use for TX to the station, |
301 | * taken from HT/VHT capabilities or VHT operating mode notification | ||
294 | */ | 302 | */ |
295 | struct sta_info { | 303 | struct sta_info { |
296 | /* General information, mostly static */ | 304 | /* General information, mostly static */ |
@@ -379,6 +387,10 @@ struct sta_info { | |||
379 | s64 t_offset; | 387 | s64 t_offset; |
380 | s64 t_offset_setpoint; | 388 | s64 t_offset_setpoint; |
381 | enum nl80211_chan_width ch_width; | 389 | enum nl80211_chan_width ch_width; |
390 | /* mesh power save */ | ||
391 | enum nl80211_mesh_power_mode local_pm; | ||
392 | enum nl80211_mesh_power_mode peer_pm; | ||
393 | enum nl80211_mesh_power_mode nonpeer_pm; | ||
382 | #endif | 394 | #endif |
383 | 395 | ||
384 | #ifdef CONFIG_MAC80211_DEBUGFS | 396 | #ifdef CONFIG_MAC80211_DEBUGFS |
@@ -388,11 +400,11 @@ struct sta_info { | |||
388 | } debugfs; | 400 | } debugfs; |
389 | #endif | 401 | #endif |
390 | 402 | ||
403 | enum ieee80211_sta_rx_bandwidth cur_max_bandwidth; | ||
404 | |||
391 | unsigned int lost_packets; | 405 | unsigned int lost_packets; |
392 | unsigned int beacon_loss_count; | 406 | unsigned int beacon_loss_count; |
393 | 407 | ||
394 | bool supports_40mhz; | ||
395 | |||
396 | /* keep last! */ | 408 | /* keep last! */ |
397 | struct ieee80211_sta sta; | 409 | struct ieee80211_sta sta; |
398 | }; | 410 | }; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 07d99578a2b1..43439203f4e4 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -335,7 +335,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
335 | if (dropped) | 335 | if (dropped) |
336 | acked = false; | 336 | acked = false; |
337 | 337 | ||
338 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 338 | if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX | |
339 | IEEE80211_TX_INTFL_MLME_CONN_TX)) { | ||
339 | struct ieee80211_sub_if_data *sdata = NULL; | 340 | struct ieee80211_sub_if_data *sdata = NULL; |
340 | struct ieee80211_sub_if_data *iter_sdata; | 341 | struct ieee80211_sub_if_data *iter_sdata; |
341 | u64 cookie = (unsigned long)skb; | 342 | u64 cookie = (unsigned long)skb; |
@@ -357,10 +358,13 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
357 | sdata = rcu_dereference(local->p2p_sdata); | 358 | sdata = rcu_dereference(local->p2p_sdata); |
358 | } | 359 | } |
359 | 360 | ||
360 | if (!sdata) | 361 | if (!sdata) { |
361 | skb->dev = NULL; | 362 | skb->dev = NULL; |
362 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | 363 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { |
363 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 364 | ieee80211_mgd_conn_tx_status(sdata, hdr->frame_control, |
365 | acked); | ||
366 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
367 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
364 | cfg80211_probe_status(sdata->dev, hdr->addr1, | 368 | cfg80211_probe_status(sdata->dev, hdr->addr1, |
365 | cookie, acked, GFP_ATOMIC); | 369 | cookie, acked, GFP_ATOMIC); |
366 | } else { | 370 | } else { |
@@ -468,6 +472,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
468 | return; | 472 | return; |
469 | } | 473 | } |
470 | 474 | ||
475 | /* mesh Peer Service Period support */ | ||
476 | if (ieee80211_vif_is_mesh(&sta->sdata->vif) && | ||
477 | ieee80211_is_data_qos(fc)) | ||
478 | ieee80211_mpsp_trigger_process( | ||
479 | ieee80211_get_qos_ctl(hdr), | ||
480 | sta, true, acked); | ||
481 | |||
471 | if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) && | 482 | if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) && |
472 | (rates_idx != -1)) | 483 | (rates_idx != -1)) |
473 | sta->last_tx_rate = info->status.rates[rates_idx]; | 484 | sta->last_tx_rate = info->status.rates[rates_idx]; |
@@ -502,11 +513,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
502 | IEEE80211_BAR_CTRL_TID_INFO_MASK) >> | 513 | IEEE80211_BAR_CTRL_TID_INFO_MASK) >> |
503 | IEEE80211_BAR_CTRL_TID_INFO_SHIFT; | 514 | IEEE80211_BAR_CTRL_TID_INFO_SHIFT; |
504 | 515 | ||
505 | if (local->hw.flags & | 516 | ieee80211_set_bar_pending(sta, tid, ssn); |
506 | IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL) | ||
507 | ieee80211_stop_tx_ba_session(&sta->sta, tid); | ||
508 | else | ||
509 | ieee80211_set_bar_pending(sta, tid, ssn); | ||
510 | } | 517 | } |
511 | } | 518 | } |
512 | 519 | ||
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 57e14d59e12f..3ed801d90f1e 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -177,12 +177,11 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, | |||
177 | struct ieee80211_key *key = (struct ieee80211_key *) | 177 | struct ieee80211_key *key = (struct ieee80211_key *) |
178 | container_of(keyconf, struct ieee80211_key, conf); | 178 | container_of(keyconf, struct ieee80211_key, conf); |
179 | struct tkip_ctx *ctx = &key->u.tkip.tx; | 179 | struct tkip_ctx *ctx = &key->u.tkip.tx; |
180 | unsigned long flags; | ||
181 | 180 | ||
182 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | 181 | spin_lock_bh(&key->u.tkip.txlock); |
183 | ieee80211_compute_tkip_p1k(key, iv32); | 182 | ieee80211_compute_tkip_p1k(key, iv32); |
184 | memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); | 183 | memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); |
185 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | 184 | spin_unlock_bh(&key->u.tkip.txlock); |
186 | } | 185 | } |
187 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); | 186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); |
188 | 187 | ||
@@ -208,12 +207,11 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, | |||
208 | const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); | 207 | const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); |
209 | u32 iv32 = get_unaligned_le32(&data[4]); | 208 | u32 iv32 = get_unaligned_le32(&data[4]); |
210 | u16 iv16 = data[2] | (data[0] << 8); | 209 | u16 iv16 = data[2] | (data[0] << 8); |
211 | unsigned long flags; | ||
212 | 210 | ||
213 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | 211 | spin_lock_bh(&key->u.tkip.txlock); |
214 | ieee80211_compute_tkip_p1k(key, iv32); | 212 | ieee80211_compute_tkip_p1k(key, iv32); |
215 | tkip_mixing_phase2(tk, ctx, iv16, p2k); | 213 | tkip_mixing_phase2(tk, ctx, iv16, p2k); |
216 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | 214 | spin_unlock_bh(&key->u.tkip.txlock); |
217 | } | 215 | } |
218 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); | 216 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); |
219 | 217 | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 6ca53d64cb28..1183c4a4fee5 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -36,7 +36,7 @@ | |||
36 | __entry->control_freq = (c)->chan->center_freq; \ | 36 | __entry->control_freq = (c)->chan->center_freq; \ |
37 | __entry->chan_width = (c)->width; \ | 37 | __entry->chan_width = (c)->width; \ |
38 | __entry->center_freq1 = (c)->center_freq1; \ | 38 | __entry->center_freq1 = (c)->center_freq1; \ |
39 | __entry->center_freq1 = (c)->center_freq2; | 39 | __entry->center_freq2 = (c)->center_freq2; |
40 | #define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz" | 40 | #define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz" |
41 | #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ | 41 | #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ |
42 | __entry->center_freq1, __entry->center_freq2 | 42 | __entry->center_freq1, __entry->center_freq2 |
@@ -340,6 +340,7 @@ TRACE_EVENT(drv_bss_info_changed, | |||
340 | __field(u16, assoc_cap) | 340 | __field(u16, assoc_cap) |
341 | __field(u64, sync_tsf) | 341 | __field(u64, sync_tsf) |
342 | __field(u32, sync_device_ts) | 342 | __field(u32, sync_device_ts) |
343 | __field(u8, sync_dtim_count) | ||
343 | __field(u32, basic_rates) | 344 | __field(u32, basic_rates) |
344 | __array(int, mcast_rate, IEEE80211_NUM_BANDS) | 345 | __array(int, mcast_rate, IEEE80211_NUM_BANDS) |
345 | __field(u16, ht_operation_mode) | 346 | __field(u16, ht_operation_mode) |
@@ -379,6 +380,7 @@ TRACE_EVENT(drv_bss_info_changed, | |||
379 | __entry->assoc_cap = info->assoc_capability; | 380 | __entry->assoc_cap = info->assoc_capability; |
380 | __entry->sync_tsf = info->sync_tsf; | 381 | __entry->sync_tsf = info->sync_tsf; |
381 | __entry->sync_device_ts = info->sync_device_ts; | 382 | __entry->sync_device_ts = info->sync_device_ts; |
383 | __entry->sync_dtim_count = info->sync_dtim_count; | ||
382 | __entry->basic_rates = info->basic_rates; | 384 | __entry->basic_rates = info->basic_rates; |
383 | memcpy(__entry->mcast_rate, info->mcast_rate, | 385 | memcpy(__entry->mcast_rate, info->mcast_rate, |
384 | sizeof(__entry->mcast_rate)); | 386 | sizeof(__entry->mcast_rate)); |
@@ -1860,6 +1862,25 @@ TRACE_EVENT(drv_set_default_unicast_key, | |||
1860 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx) | 1862 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx) |
1861 | ); | 1863 | ); |
1862 | 1864 | ||
1865 | TRACE_EVENT(api_radar_detected, | ||
1866 | TP_PROTO(struct ieee80211_local *local), | ||
1867 | |||
1868 | TP_ARGS(local), | ||
1869 | |||
1870 | TP_STRUCT__entry( | ||
1871 | LOCAL_ENTRY | ||
1872 | ), | ||
1873 | |||
1874 | TP_fast_assign( | ||
1875 | LOCAL_ASSIGN; | ||
1876 | ), | ||
1877 | |||
1878 | TP_printk( | ||
1879 | LOCAL_PR_FMT " radar detected", | ||
1880 | LOCAL_PR_ARG | ||
1881 | ) | ||
1882 | ); | ||
1883 | |||
1863 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 1884 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
1864 | #undef TRACE_SYSTEM | 1885 | #undef TRACE_SYSTEM |
1865 | #define TRACE_SYSTEM mac80211_msg | 1886 | #define TRACE_SYSTEM mac80211_msg |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a2cb6a302cc7..fe644f91ae05 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -329,6 +329,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
329 | 329 | ||
330 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 330 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
331 | ps = &sdata->u.ap.ps; | 331 | ps = &sdata->u.ap.ps; |
332 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
333 | ps = &sdata->u.mesh.ps; | ||
332 | else | 334 | else |
333 | continue; | 335 | continue; |
334 | 336 | ||
@@ -372,18 +374,20 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
372 | /* | 374 | /* |
373 | * broadcast/multicast frame | 375 | * broadcast/multicast frame |
374 | * | 376 | * |
375 | * If any of the associated stations is in power save mode, | 377 | * If any of the associated/peer stations is in power save mode, |
376 | * the frame is buffered to be sent after DTIM beacon frame. | 378 | * the frame is buffered to be sent after DTIM beacon frame. |
377 | * This is done either by the hardware or us. | 379 | * This is done either by the hardware or us. |
378 | */ | 380 | */ |
379 | 381 | ||
380 | /* powersaving STAs currently only in AP/VLAN mode */ | 382 | /* powersaving STAs currently only in AP/VLAN/mesh mode */ |
381 | if (tx->sdata->vif.type == NL80211_IFTYPE_AP || | 383 | if (tx->sdata->vif.type == NL80211_IFTYPE_AP || |
382 | tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | 384 | tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
383 | if (!tx->sdata->bss) | 385 | if (!tx->sdata->bss) |
384 | return TX_CONTINUE; | 386 | return TX_CONTINUE; |
385 | 387 | ||
386 | ps = &tx->sdata->bss->ps; | 388 | ps = &tx->sdata->bss->ps; |
389 | } else if (ieee80211_vif_is_mesh(&tx->sdata->vif)) { | ||
390 | ps = &tx->sdata->u.mesh.ps; | ||
387 | } else { | 391 | } else { |
388 | return TX_CONTINUE; | 392 | return TX_CONTINUE; |
389 | } | 393 | } |
@@ -594,7 +598,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
594 | break; | 598 | break; |
595 | } | 599 | } |
596 | 600 | ||
597 | if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED)) | 601 | if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED && |
602 | !ieee80211_is_deauth(hdr->frame_control))) | ||
598 | return TX_DROP; | 603 | return TX_DROP; |
599 | 604 | ||
600 | if (!skip_hw && tx->key && | 605 | if (!skip_hw && tx->key && |
@@ -1225,6 +1230,21 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
1225 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1230 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1226 | if (local->queue_stop_reasons[q] || | 1231 | if (local->queue_stop_reasons[q] || |
1227 | (!txpending && !skb_queue_empty(&local->pending[q]))) { | 1232 | (!txpending && !skb_queue_empty(&local->pending[q]))) { |
1233 | if (unlikely(info->flags & | ||
1234 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK && | ||
1235 | local->queue_stop_reasons[q] & | ||
1236 | ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))) { | ||
1237 | /* | ||
1238 | * Drop off-channel frames if queues are stopped | ||
1239 | * for any reason other than off-channel | ||
1240 | * operation. Never queue them. | ||
1241 | */ | ||
1242 | spin_unlock_irqrestore( | ||
1243 | &local->queue_stop_reason_lock, flags); | ||
1244 | ieee80211_purge_tx_queue(&local->hw, skbs); | ||
1245 | return true; | ||
1246 | } | ||
1247 | |||
1228 | /* | 1248 | /* |
1229 | * Since queue is stopped, queue up frames for later | 1249 | * Since queue is stopped, queue up frames for later |
1230 | * transmission from the tx-pending tasklet when the | 1250 | * transmission from the tx-pending tasklet when the |
@@ -1472,12 +1492,14 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
1472 | hdr = (struct ieee80211_hdr *) skb->data; | 1492 | hdr = (struct ieee80211_hdr *) skb->data; |
1473 | info->control.vif = &sdata->vif; | 1493 | info->control.vif = &sdata->vif; |
1474 | 1494 | ||
1475 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 1495 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
1476 | ieee80211_is_data(hdr->frame_control) && | 1496 | if (ieee80211_is_data(hdr->frame_control) && |
1477 | !is_multicast_ether_addr(hdr->addr1) && | 1497 | is_unicast_ether_addr(hdr->addr1)) { |
1478 | mesh_nexthop_resolve(skb, sdata)) { | 1498 | if (mesh_nexthop_resolve(skb, sdata)) |
1479 | /* skb queued: don't free */ | 1499 | return; /* skb queued: don't free */ |
1480 | return; | 1500 | } else { |
1501 | ieee80211_mps_set_frame_flags(sdata, NULL, hdr); | ||
1502 | } | ||
1481 | } | 1503 | } |
1482 | 1504 | ||
1483 | ieee80211_set_qos_hdr(sdata, skb); | 1505 | ieee80211_set_qos_hdr(sdata, skb); |
@@ -2342,11 +2364,9 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
2342 | if (local->tim_in_locked_section) { | 2364 | if (local->tim_in_locked_section) { |
2343 | __ieee80211_beacon_add_tim(sdata, ps, skb); | 2365 | __ieee80211_beacon_add_tim(sdata, ps, skb); |
2344 | } else { | 2366 | } else { |
2345 | unsigned long flags; | 2367 | spin_lock(&local->tim_lock); |
2346 | |||
2347 | spin_lock_irqsave(&local->tim_lock, flags); | ||
2348 | __ieee80211_beacon_add_tim(sdata, ps, skb); | 2368 | __ieee80211_beacon_add_tim(sdata, ps, skb); |
2349 | spin_unlock_irqrestore(&local->tim_lock, flags); | 2369 | spin_unlock(&local->tim_lock); |
2350 | } | 2370 | } |
2351 | 2371 | ||
2352 | return 0; | 2372 | return 0; |
@@ -2424,66 +2444,26 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2424 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2444 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2425 | IEEE80211_STYPE_BEACON); | 2445 | IEEE80211_STYPE_BEACON); |
2426 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2446 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2427 | struct ieee80211_mgmt *mgmt; | ||
2428 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2447 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2429 | u8 *pos; | 2448 | struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); |
2430 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | ||
2431 | sizeof(mgmt->u.beacon); | ||
2432 | 2449 | ||
2433 | #ifdef CONFIG_MAC80211_MESH | 2450 | if (!bcn) |
2434 | if (!sdata->u.mesh.mesh_id_len) | ||
2435 | goto out; | 2451 | goto out; |
2436 | #endif | ||
2437 | 2452 | ||
2438 | if (ifmsh->sync_ops) | 2453 | if (ifmsh->sync_ops) |
2439 | ifmsh->sync_ops->adjust_tbtt( | 2454 | ifmsh->sync_ops->adjust_tbtt( |
2440 | sdata); | 2455 | sdata); |
2441 | 2456 | ||
2442 | skb = dev_alloc_skb(local->tx_headroom + | 2457 | skb = dev_alloc_skb(local->tx_headroom + |
2443 | hdr_len + | 2458 | bcn->head_len + |
2444 | 2 + /* NULL SSID */ | 2459 | 256 + /* TIM IE */ |
2445 | 2 + 8 + /* supported rates */ | 2460 | bcn->tail_len); |
2446 | 2 + 3 + /* DS params */ | ||
2447 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | ||
2448 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
2449 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
2450 | 2 + sdata->u.mesh.mesh_id_len + | ||
2451 | 2 + sizeof(struct ieee80211_meshconf_ie) + | ||
2452 | sdata->u.mesh.ie_len); | ||
2453 | if (!skb) | 2461 | if (!skb) |
2454 | goto out; | 2462 | goto out; |
2455 | 2463 | skb_reserve(skb, local->tx_headroom); | |
2456 | skb_reserve(skb, local->hw.extra_tx_headroom); | 2464 | memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); |
2457 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 2465 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb); |
2458 | memset(mgmt, 0, hdr_len); | 2466 | memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); |
2459 | mgmt->frame_control = | ||
2460 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | ||
2461 | eth_broadcast_addr(mgmt->da); | ||
2462 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
2463 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); | ||
2464 | mgmt->u.beacon.beacon_int = | ||
2465 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | ||
2466 | mgmt->u.beacon.capab_info |= cpu_to_le16( | ||
2467 | sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0); | ||
2468 | |||
2469 | pos = skb_put(skb, 2); | ||
2470 | *pos++ = WLAN_EID_SSID; | ||
2471 | *pos++ = 0x0; | ||
2472 | |||
2473 | band = chanctx_conf->def.chan->band; | ||
2474 | |||
2475 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | ||
2476 | mesh_add_ds_params_ie(skb, sdata) || | ||
2477 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | ||
2478 | mesh_add_rsn_ie(skb, sdata) || | ||
2479 | mesh_add_ht_cap_ie(skb, sdata) || | ||
2480 | mesh_add_ht_oper_ie(skb, sdata) || | ||
2481 | mesh_add_meshid_ie(skb, sdata) || | ||
2482 | mesh_add_meshconf_ie(skb, sdata) || | ||
2483 | mesh_add_vendor_ies(skb, sdata)) { | ||
2484 | pr_err("o11s: couldn't add ies!\n"); | ||
2485 | goto out; | ||
2486 | } | ||
2487 | } else { | 2467 | } else { |
2488 | WARN_ON(1); | 2468 | WARN_ON(1); |
2489 | goto out; | 2469 | goto out; |
@@ -2733,6 +2713,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2733 | goto out; | 2713 | goto out; |
2734 | 2714 | ||
2735 | ps = &sdata->u.ap.ps; | 2715 | ps = &sdata->u.ap.ps; |
2716 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2717 | ps = &sdata->u.mesh.ps; | ||
2736 | } else { | 2718 | } else { |
2737 | goto out; | 2719 | goto out; |
2738 | } | 2720 | } |
@@ -2756,6 +2738,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2756 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 2738 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
2757 | } | 2739 | } |
2758 | 2740 | ||
2741 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); | ||
2759 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) | 2742 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) |
2760 | break; | 2743 | break; |
2761 | dev_kfree_skb_any(skb); | 2744 | dev_kfree_skb_any(skb); |
@@ -2788,6 +2771,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | |||
2788 | skb_set_queue_mapping(skb, ac); | 2771 | skb_set_queue_mapping(skb, ac); |
2789 | skb->priority = tid; | 2772 | skb->priority = tid; |
2790 | 2773 | ||
2774 | skb->dev = sdata->dev; | ||
2775 | |||
2791 | /* | 2776 | /* |
2792 | * The other path calling ieee80211_xmit is from the tasklet, | 2777 | * The other path calling ieee80211_xmit is from the tasklet, |
2793 | * and while we can handle concurrent transmissions locking | 2778 | * and while we can handle concurrent transmissions locking |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7519018ff71a..0f38f43ac62e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -739,11 +739,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
739 | if (calc_crc) | 739 | if (calc_crc) |
740 | crc = crc32_be(crc, pos - 2, elen + 2); | 740 | crc = crc32_be(crc, pos - 2, elen + 2); |
741 | 741 | ||
742 | if (pos[3] == 1) { | 742 | if (elen >= 5 && pos[3] == 2) { |
743 | /* OUI Type 1 - WPA IE */ | ||
744 | elems->wpa = pos; | ||
745 | elems->wpa_len = elen; | ||
746 | } else if (elen >= 5 && pos[3] == 2) { | ||
747 | /* OUI Type 2 - WMM IE */ | 743 | /* OUI Type 2 - WMM IE */ |
748 | if (pos[4] == 0) { | 744 | if (pos[4] == 0) { |
749 | elems->wmm_info = pos; | 745 | elems->wmm_info = pos; |
@@ -791,6 +787,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
791 | else | 787 | else |
792 | elem_parse_failed = true; | 788 | elem_parse_failed = true; |
793 | break; | 789 | break; |
790 | case WLAN_EID_OPMODE_NOTIF: | ||
791 | if (elen > 0) | ||
792 | elems->opmode_notif = pos; | ||
793 | else | ||
794 | elem_parse_failed = true; | ||
795 | break; | ||
794 | case WLAN_EID_MESH_ID: | 796 | case WLAN_EID_MESH_ID: |
795 | elems->mesh_id = pos; | 797 | elems->mesh_id = pos; |
796 | elems->mesh_id_len = elen; | 798 | elems->mesh_id_len = elen; |
@@ -805,6 +807,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
805 | elems->peering = pos; | 807 | elems->peering = pos; |
806 | elems->peering_len = elen; | 808 | elems->peering_len = elen; |
807 | break; | 809 | break; |
810 | case WLAN_EID_MESH_AWAKE_WINDOW: | ||
811 | if (elen >= 2) | ||
812 | elems->awake_window = (void *)pos; | ||
813 | break; | ||
808 | case WLAN_EID_PREQ: | 814 | case WLAN_EID_PREQ: |
809 | elems->preq = pos; | 815 | elems->preq = pos; |
810 | elems->preq_len = elen; | 816 | elems->preq_len = elen; |
@@ -1029,8 +1035,9 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
1029 | 1035 | ||
1030 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1036 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1031 | u16 transaction, u16 auth_alg, u16 status, | 1037 | u16 transaction, u16 auth_alg, u16 status, |
1032 | u8 *extra, size_t extra_len, const u8 *da, | 1038 | const u8 *extra, size_t extra_len, const u8 *da, |
1033 | const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) | 1039 | const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx, |
1040 | u32 tx_flags) | ||
1034 | { | 1041 | { |
1035 | struct ieee80211_local *local = sdata->local; | 1042 | struct ieee80211_local *local = sdata->local; |
1036 | struct sk_buff *skb; | 1043 | struct sk_buff *skb; |
@@ -1063,7 +1070,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1063 | WARN_ON(err); | 1070 | WARN_ON(err); |
1064 | } | 1071 | } |
1065 | 1072 | ||
1066 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1073 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | |
1074 | tx_flags; | ||
1067 | ieee80211_tx_skb(sdata, skb); | 1075 | ieee80211_tx_skb(sdata, skb); |
1068 | } | 1076 | } |
1069 | 1077 | ||
@@ -1277,7 +1285,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1277 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1285 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1278 | const u8 *ssid, size_t ssid_len, | 1286 | const u8 *ssid, size_t ssid_len, |
1279 | const u8 *ie, size_t ie_len, | 1287 | const u8 *ie, size_t ie_len, |
1280 | u32 ratemask, bool directed, bool no_cck, | 1288 | u32 ratemask, bool directed, u32 tx_flags, |
1281 | struct ieee80211_channel *channel, bool scan) | 1289 | struct ieee80211_channel *channel, bool scan) |
1282 | { | 1290 | { |
1283 | struct sk_buff *skb; | 1291 | struct sk_buff *skb; |
@@ -1286,9 +1294,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1286 | ssid, ssid_len, | 1294 | ssid, ssid_len, |
1287 | ie, ie_len, directed); | 1295 | ie, ie_len, directed); |
1288 | if (skb) { | 1296 | if (skb) { |
1289 | if (no_cck) | 1297 | IEEE80211_SKB_CB(skb)->flags |= tx_flags; |
1290 | IEEE80211_SKB_CB(skb)->flags |= | ||
1291 | IEEE80211_TX_CTL_NO_CCK_RATE; | ||
1292 | if (scan) | 1298 | if (scan) |
1293 | ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); | 1299 | ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); |
1294 | else | 1300 | else |
@@ -1538,6 +1544,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1538 | changed |= BSS_CHANGED_ASSOC | | 1544 | changed |= BSS_CHANGED_ASSOC | |
1539 | BSS_CHANGED_ARP_FILTER | | 1545 | BSS_CHANGED_ARP_FILTER | |
1540 | BSS_CHANGED_PS; | 1546 | BSS_CHANGED_PS; |
1547 | |||
1548 | if (sdata->u.mgd.dtim_period) | ||
1549 | changed |= BSS_CHANGED_DTIM_PERIOD; | ||
1550 | |||
1541 | mutex_lock(&sdata->u.mgd.mtx); | 1551 | mutex_lock(&sdata->u.mgd.mtx); |
1542 | ieee80211_bss_info_change_notify(sdata, changed); | 1552 | ieee80211_bss_info_change_notify(sdata, changed); |
1543 | mutex_unlock(&sdata->u.mgd.mtx); | 1553 | mutex_unlock(&sdata->u.mgd.mtx); |
@@ -1937,7 +1947,7 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1937 | } | 1947 | } |
1938 | 1948 | ||
1939 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1949 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
1940 | struct ieee80211_ht_operation *ht_oper, | 1950 | const struct ieee80211_ht_operation *ht_oper, |
1941 | struct cfg80211_chan_def *chandef) | 1951 | struct cfg80211_chan_def *chandef) |
1942 | { | 1952 | { |
1943 | enum nl80211_channel_type channel_type; | 1953 | enum nl80211_channel_type channel_type; |
@@ -2125,3 +2135,49 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
2125 | 2135 | ||
2126 | return ts; | 2136 | return ts; |
2127 | } | 2137 | } |
2138 | |||
2139 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) | ||
2140 | { | ||
2141 | struct ieee80211_sub_if_data *sdata; | ||
2142 | |||
2143 | mutex_lock(&local->iflist_mtx); | ||
2144 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
2145 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | ||
2146 | |||
2147 | if (sdata->wdev.cac_started) { | ||
2148 | ieee80211_vif_release_channel(sdata); | ||
2149 | cfg80211_cac_event(sdata->dev, | ||
2150 | NL80211_RADAR_CAC_ABORTED, | ||
2151 | GFP_KERNEL); | ||
2152 | } | ||
2153 | } | ||
2154 | mutex_unlock(&local->iflist_mtx); | ||
2155 | } | ||
2156 | |||
2157 | void ieee80211_dfs_radar_detected_work(struct work_struct *work) | ||
2158 | { | ||
2159 | struct ieee80211_local *local = | ||
2160 | container_of(work, struct ieee80211_local, radar_detected_work); | ||
2161 | struct cfg80211_chan_def chandef; | ||
2162 | |||
2163 | ieee80211_dfs_cac_cancel(local); | ||
2164 | |||
2165 | if (local->use_chanctx) | ||
2166 | /* currently not handled */ | ||
2167 | WARN_ON(1); | ||
2168 | else { | ||
2169 | cfg80211_chandef_create(&chandef, local->hw.conf.channel, | ||
2170 | local->hw.conf.channel_type); | ||
2171 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); | ||
2172 | } | ||
2173 | } | ||
2174 | |||
2175 | void ieee80211_radar_detected(struct ieee80211_hw *hw) | ||
2176 | { | ||
2177 | struct ieee80211_local *local = hw_to_local(hw); | ||
2178 | |||
2179 | trace_api_radar_detected(local); | ||
2180 | |||
2181 | ieee80211_queue_work(hw, &local->radar_detected_work); | ||
2182 | } | ||
2183 | EXPORT_SYMBOL(ieee80211_radar_detected); | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index f311388aeedf..a2c2258bc84e 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -10,21 +10,29 @@ | |||
10 | #include <linux/export.h> | 10 | #include <linux/export.h> |
11 | #include <net/mac80211.h> | 11 | #include <net/mac80211.h> |
12 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
13 | #include "rate.h" | ||
13 | 14 | ||
14 | 15 | ||
15 | void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 16 | void |
16 | struct ieee80211_supported_band *sband, | 17 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
17 | struct ieee80211_vht_cap *vht_cap_ie, | 18 | struct ieee80211_supported_band *sband, |
18 | struct ieee80211_sta_vht_cap *vht_cap) | 19 | const struct ieee80211_vht_cap *vht_cap_ie, |
20 | struct sta_info *sta) | ||
19 | { | 21 | { |
20 | if (WARN_ON_ONCE(!vht_cap)) | 22 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; |
21 | return; | ||
22 | 23 | ||
23 | memset(vht_cap, 0, sizeof(*vht_cap)); | 24 | memset(vht_cap, 0, sizeof(*vht_cap)); |
24 | 25 | ||
26 | if (!sta->sta.ht_cap.ht_supported) | ||
27 | return; | ||
28 | |||
25 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 29 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) |
26 | return; | 30 | return; |
27 | 31 | ||
32 | /* A VHT STA must support 40 MHz */ | ||
33 | if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
34 | return; | ||
35 | |||
28 | vht_cap->vht_supported = true; | 36 | vht_cap->vht_supported = true; |
29 | 37 | ||
30 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); | 38 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); |
@@ -32,4 +40,156 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
32 | /* Copy peer MCS info, the driver might need them. */ | 40 | /* Copy peer MCS info, the driver might need them. */ |
33 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, | 41 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, |
34 | sizeof(struct ieee80211_vht_mcs_info)); | 42 | sizeof(struct ieee80211_vht_mcs_info)); |
43 | |||
44 | switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { | ||
45 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: | ||
46 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: | ||
47 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; | ||
48 | break; | ||
49 | default: | ||
50 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; | ||
51 | } | ||
52 | |||
53 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); | ||
54 | } | ||
55 | |||
56 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | ||
57 | { | ||
58 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
59 | u32 cap = sta->sta.vht_cap.cap; | ||
60 | enum ieee80211_sta_rx_bandwidth bw; | ||
61 | |||
62 | if (!sta->sta.vht_cap.vht_supported) { | ||
63 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
64 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
65 | goto check_max; | ||
66 | } | ||
67 | |||
68 | switch (sdata->vif.bss_conf.chandef.width) { | ||
69 | default: | ||
70 | WARN_ON_ONCE(1); | ||
71 | /* fall through */ | ||
72 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
73 | case NL80211_CHAN_WIDTH_20: | ||
74 | case NL80211_CHAN_WIDTH_40: | ||
75 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
76 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
77 | break; | ||
78 | case NL80211_CHAN_WIDTH_160: | ||
79 | if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == | ||
80 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) { | ||
81 | bw = IEEE80211_STA_RX_BW_160; | ||
82 | break; | ||
83 | } | ||
84 | /* fall through */ | ||
85 | case NL80211_CHAN_WIDTH_80P80: | ||
86 | if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == | ||
87 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { | ||
88 | bw = IEEE80211_STA_RX_BW_160; | ||
89 | break; | ||
90 | } | ||
91 | /* fall through */ | ||
92 | case NL80211_CHAN_WIDTH_80: | ||
93 | bw = IEEE80211_STA_RX_BW_80; | ||
94 | } | ||
95 | |||
96 | check_max: | ||
97 | if (bw > sta->cur_max_bandwidth) | ||
98 | bw = sta->cur_max_bandwidth; | ||
99 | return bw; | ||
100 | } | ||
101 | |||
102 | void ieee80211_sta_set_rx_nss(struct sta_info *sta) | ||
103 | { | ||
104 | u8 ht_rx_nss = 0, vht_rx_nss = 0; | ||
105 | |||
106 | /* if we received a notification already don't overwrite it */ | ||
107 | if (sta->sta.rx_nss) | ||
108 | return; | ||
109 | |||
110 | if (sta->sta.ht_cap.ht_supported) { | ||
111 | if (sta->sta.ht_cap.mcs.rx_mask[0]) | ||
112 | ht_rx_nss++; | ||
113 | if (sta->sta.ht_cap.mcs.rx_mask[1]) | ||
114 | ht_rx_nss++; | ||
115 | if (sta->sta.ht_cap.mcs.rx_mask[2]) | ||
116 | ht_rx_nss++; | ||
117 | if (sta->sta.ht_cap.mcs.rx_mask[3]) | ||
118 | ht_rx_nss++; | ||
119 | /* FIXME: consider rx_highest? */ | ||
120 | } | ||
121 | |||
122 | if (sta->sta.vht_cap.vht_supported) { | ||
123 | int i; | ||
124 | u16 rx_mcs_map; | ||
125 | |||
126 | rx_mcs_map = le16_to_cpu(sta->sta.vht_cap.vht_mcs.rx_mcs_map); | ||
127 | |||
128 | for (i = 7; i >= 0; i--) { | ||
129 | u8 mcs = (rx_mcs_map >> (2 * i)) & 3; | ||
130 | |||
131 | if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) { | ||
132 | vht_rx_nss = i + 1; | ||
133 | break; | ||
134 | } | ||
135 | } | ||
136 | /* FIXME: consider rx_highest? */ | ||
137 | } | ||
138 | |||
139 | ht_rx_nss = max(ht_rx_nss, vht_rx_nss); | ||
140 | sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss); | ||
141 | } | ||
142 | |||
143 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||
144 | struct sta_info *sta, u8 opmode, | ||
145 | enum ieee80211_band band, bool nss_only) | ||
146 | { | ||
147 | struct ieee80211_local *local = sdata->local; | ||
148 | struct ieee80211_supported_band *sband; | ||
149 | enum ieee80211_sta_rx_bandwidth new_bw; | ||
150 | u32 changed = 0; | ||
151 | u8 nss; | ||
152 | |||
153 | sband = local->hw.wiphy->bands[band]; | ||
154 | |||
155 | /* ignore - no support for BF yet */ | ||
156 | if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF) | ||
157 | return; | ||
158 | |||
159 | nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; | ||
160 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; | ||
161 | nss += 1; | ||
162 | |||
163 | if (sta->sta.rx_nss != nss) { | ||
164 | sta->sta.rx_nss = nss; | ||
165 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
166 | } | ||
167 | |||
168 | if (nss_only) | ||
169 | goto change; | ||
170 | |||
171 | switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { | ||
172 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: | ||
173 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; | ||
174 | break; | ||
175 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: | ||
176 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; | ||
177 | break; | ||
178 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: | ||
179 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; | ||
180 | break; | ||
181 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: | ||
182 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; | ||
183 | break; | ||
184 | } | ||
185 | |||
186 | new_bw = ieee80211_sta_cur_vht_bw(sta); | ||
187 | if (new_bw != sta->sta.bandwidth) { | ||
188 | sta->sta.bandwidth = new_bw; | ||
189 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
190 | } | ||
191 | |||
192 | change: | ||
193 | if (changed) | ||
194 | rate_control_rate_update(local, sband, sta, changed); | ||
35 | } | 195 | } |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 906f00cd6d2f..afba19cb6f87 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -191,6 +191,15 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | |||
191 | 191 | ||
192 | /* qos header is 2 bytes */ | 192 | /* qos header is 2 bytes */ |
193 | *p++ = ack_policy | tid; | 193 | *p++ = ack_policy | tid; |
194 | *p = ieee80211_vif_is_mesh(&sdata->vif) ? | 194 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
195 | (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; | 195 | /* preserve RSPI and Mesh PS Level bit */ |
196 | *p &= ((IEEE80211_QOS_CTL_RSPI | | ||
197 | IEEE80211_QOS_CTL_MESH_PS_LEVEL) >> 8); | ||
198 | |||
199 | /* Nulls don't have a mesh header (frame body) */ | ||
200 | if (!ieee80211_is_qos_nullfunc(hdr->frame_control)) | ||
201 | *p |= (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8); | ||
202 | } else { | ||
203 | *p = 0; | ||
204 | } | ||
196 | } | 205 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index c175ee866ff4..c7c6d644486f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -181,7 +181,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
181 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 181 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
182 | struct ieee80211_key *key = tx->key; | 182 | struct ieee80211_key *key = tx->key; |
183 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 183 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
184 | unsigned long flags; | ||
185 | unsigned int hdrlen; | 184 | unsigned int hdrlen; |
186 | int len, tail; | 185 | int len, tail; |
187 | u8 *pos; | 186 | u8 *pos; |
@@ -216,12 +215,12 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
216 | return 0; | 215 | return 0; |
217 | 216 | ||
218 | /* Increase IV for the frame */ | 217 | /* Increase IV for the frame */ |
219 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | 218 | spin_lock(&key->u.tkip.txlock); |
220 | key->u.tkip.tx.iv16++; | 219 | key->u.tkip.tx.iv16++; |
221 | if (key->u.tkip.tx.iv16 == 0) | 220 | if (key->u.tkip.tx.iv16 == 0) |
222 | key->u.tkip.tx.iv32++; | 221 | key->u.tkip.tx.iv32++; |
223 | pos = ieee80211_tkip_add_iv(pos, key); | 222 | pos = ieee80211_tkip_add_iv(pos, key); |
224 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | 223 | spin_unlock(&key->u.tkip.txlock); |
225 | 224 | ||
226 | /* hwaccel - with software IV */ | 225 | /* hwaccel - with software IV */ |
227 | if (info->control.hw_key) | 226 | if (info->control.hw_key) |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 85bc75c38dea..746f5a2f9804 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -549,14 +549,13 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) | |||
549 | pr_err("No LLCP device\n"); | 549 | pr_err("No LLCP device\n"); |
550 | return -ENODEV; | 550 | return -ENODEV; |
551 | } | 551 | } |
552 | if (gb_len < 3) | ||
553 | return -EINVAL; | ||
552 | 554 | ||
553 | memset(local->remote_gb, 0, NFC_MAX_GT_LEN); | 555 | memset(local->remote_gb, 0, NFC_MAX_GT_LEN); |
554 | memcpy(local->remote_gb, gb, gb_len); | 556 | memcpy(local->remote_gb, gb, gb_len); |
555 | local->remote_gb_len = gb_len; | 557 | local->remote_gb_len = gb_len; |
556 | 558 | ||
557 | if (local->remote_gb == NULL || local->remote_gb_len == 0) | ||
558 | return -ENODEV; | ||
559 | |||
560 | if (memcmp(local->remote_gb, llcp_magic, 3)) { | 559 | if (memcmp(local->remote_gb, llcp_magic, 3)) { |
561 | pr_err("MAC does not support LLCP\n"); | 560 | pr_err("MAC does not support LLCP\n"); |
562 | return -EINVAL; | 561 | return -EINVAL; |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 396373f3ec26..fd556ac05fdb 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -147,6 +147,32 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c, | |||
147 | } | 147 | } |
148 | } | 148 | } |
149 | 149 | ||
150 | static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) | ||
151 | { | ||
152 | int width; | ||
153 | |||
154 | switch (c->width) { | ||
155 | case NL80211_CHAN_WIDTH_20: | ||
156 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
157 | width = 20; | ||
158 | break; | ||
159 | case NL80211_CHAN_WIDTH_40: | ||
160 | width = 40; | ||
161 | break; | ||
162 | case NL80211_CHAN_WIDTH_80P80: | ||
163 | case NL80211_CHAN_WIDTH_80: | ||
164 | width = 80; | ||
165 | break; | ||
166 | case NL80211_CHAN_WIDTH_160: | ||
167 | width = 160; | ||
168 | break; | ||
169 | default: | ||
170 | WARN_ON_ONCE(1); | ||
171 | return -1; | ||
172 | } | ||
173 | return width; | ||
174 | } | ||
175 | |||
150 | const struct cfg80211_chan_def * | 176 | const struct cfg80211_chan_def * |
151 | cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | 177 | cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, |
152 | const struct cfg80211_chan_def *c2) | 178 | const struct cfg80211_chan_def *c2) |
@@ -192,6 +218,93 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | |||
192 | } | 218 | } |
193 | EXPORT_SYMBOL(cfg80211_chandef_compatible); | 219 | EXPORT_SYMBOL(cfg80211_chandef_compatible); |
194 | 220 | ||
221 | static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq, | ||
222 | u32 bandwidth, | ||
223 | enum nl80211_dfs_state dfs_state) | ||
224 | { | ||
225 | struct ieee80211_channel *c; | ||
226 | u32 freq; | ||
227 | |||
228 | for (freq = center_freq - bandwidth/2 + 10; | ||
229 | freq <= center_freq + bandwidth/2 - 10; | ||
230 | freq += 20) { | ||
231 | c = ieee80211_get_channel(wiphy, freq); | ||
232 | if (!c || !(c->flags & IEEE80211_CHAN_RADAR)) | ||
233 | continue; | ||
234 | |||
235 | c->dfs_state = dfs_state; | ||
236 | c->dfs_state_entered = jiffies; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | ||
241 | const struct cfg80211_chan_def *chandef, | ||
242 | enum nl80211_dfs_state dfs_state) | ||
243 | { | ||
244 | int width; | ||
245 | |||
246 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
247 | return; | ||
248 | |||
249 | width = cfg80211_chandef_get_width(chandef); | ||
250 | if (width < 0) | ||
251 | return; | ||
252 | |||
253 | cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1, | ||
254 | width, dfs_state); | ||
255 | |||
256 | if (!chandef->center_freq2) | ||
257 | return; | ||
258 | cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2, | ||
259 | width, dfs_state); | ||
260 | } | ||
261 | |||
262 | static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | ||
263 | u32 center_freq, | ||
264 | u32 bandwidth) | ||
265 | { | ||
266 | struct ieee80211_channel *c; | ||
267 | u32 freq; | ||
268 | |||
269 | for (freq = center_freq - bandwidth/2 + 10; | ||
270 | freq <= center_freq + bandwidth/2 - 10; | ||
271 | freq += 20) { | ||
272 | c = ieee80211_get_channel(wiphy, freq); | ||
273 | if (!c) | ||
274 | return -EINVAL; | ||
275 | |||
276 | if (c->flags & IEEE80211_CHAN_RADAR) | ||
277 | return 1; | ||
278 | } | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | |||
283 | int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | ||
284 | const struct cfg80211_chan_def *chandef) | ||
285 | { | ||
286 | int width; | ||
287 | int r; | ||
288 | |||
289 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
290 | return -EINVAL; | ||
291 | |||
292 | width = cfg80211_chandef_get_width(chandef); | ||
293 | if (width < 0) | ||
294 | return -EINVAL; | ||
295 | |||
296 | r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1, | ||
297 | width); | ||
298 | if (r) | ||
299 | return r; | ||
300 | |||
301 | if (!chandef->center_freq2) | ||
302 | return 0; | ||
303 | |||
304 | return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2, | ||
305 | width); | ||
306 | } | ||
307 | |||
195 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 308 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
196 | u32 center_freq, u32 bandwidth, | 309 | u32 center_freq, u32 bandwidth, |
197 | u32 prohibited_flags) | 310 | u32 prohibited_flags) |
@@ -203,7 +316,16 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | |||
203 | freq <= center_freq + bandwidth/2 - 10; | 316 | freq <= center_freq + bandwidth/2 - 10; |
204 | freq += 20) { | 317 | freq += 20) { |
205 | c = ieee80211_get_channel(wiphy, freq); | 318 | c = ieee80211_get_channel(wiphy, freq); |
206 | if (!c || c->flags & prohibited_flags) | 319 | if (!c) |
320 | return false; | ||
321 | |||
322 | /* check for radar flags */ | ||
323 | if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) && | ||
324 | (c->dfs_state != NL80211_DFS_AVAILABLE)) | ||
325 | return false; | ||
326 | |||
327 | /* check for the other flags */ | ||
328 | if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) | ||
207 | return false; | 329 | return false; |
208 | } | 330 | } |
209 | 331 | ||
@@ -253,6 +375,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
253 | case NL80211_CHAN_WIDTH_80: | 375 | case NL80211_CHAN_WIDTH_80: |
254 | if (!vht_cap->vht_supported) | 376 | if (!vht_cap->vht_supported) |
255 | return false; | 377 | return false; |
378 | prohibited_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
256 | width = 80; | 379 | width = 80; |
257 | break; | 380 | break; |
258 | case NL80211_CHAN_WIDTH_160: | 381 | case NL80211_CHAN_WIDTH_160: |
@@ -260,6 +383,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
260 | return false; | 383 | return false; |
261 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) | 384 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) |
262 | return false; | 385 | return false; |
386 | prohibited_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
263 | width = 160; | 387 | width = 160; |
264 | break; | 388 | break; |
265 | default: | 389 | default: |
@@ -267,7 +391,16 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
267 | return false; | 391 | return false; |
268 | } | 392 | } |
269 | 393 | ||
270 | /* TODO: missing regulatory check on 80/160 bandwidth */ | 394 | /* |
395 | * TODO: What if there are only certain 80/160/80+80 MHz channels | ||
396 | * allowed by the driver, or only certain combinations? | ||
397 | * For 40 MHz the driver can set the NO_HT40 flags, but for | ||
398 | * 80/160 MHz and in particular 80+80 MHz this isn't really | ||
399 | * feasible and we only have NO_80MHZ/NO_160MHZ so far but | ||
400 | * no way to cover 80+80 MHz or more complex restrictions. | ||
401 | * Note that such restrictions also need to be advertised to | ||
402 | * userspace, for example for P2P channel selection. | ||
403 | */ | ||
271 | 404 | ||
272 | if (width > 20) | 405 | if (width > 20) |
273 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; | 406 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; |
@@ -344,7 +477,10 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
344 | break; | 477 | break; |
345 | case NL80211_IFTYPE_AP: | 478 | case NL80211_IFTYPE_AP: |
346 | case NL80211_IFTYPE_P2P_GO: | 479 | case NL80211_IFTYPE_P2P_GO: |
347 | if (wdev->beacon_interval) { | 480 | if (wdev->cac_started) { |
481 | *chan = wdev->channel; | ||
482 | *chanmode = CHAN_MODE_SHARED; | ||
483 | } else if (wdev->beacon_interval) { | ||
348 | *chan = wdev->channel; | 484 | *chan = wdev->channel; |
349 | *chanmode = CHAN_MODE_SHARED; | 485 | *chanmode = CHAN_MODE_SHARED; |
350 | } | 486 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 40dbe37cfbf6..5ffff039b017 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -324,6 +324,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
324 | INIT_LIST_HEAD(&rdev->bss_list); | 324 | INIT_LIST_HEAD(&rdev->bss_list); |
325 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 325 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
326 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); | 326 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); |
327 | INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk, | ||
328 | cfg80211_dfs_channels_update_work); | ||
327 | #ifdef CONFIG_CFG80211_WEXT | 329 | #ifdef CONFIG_CFG80211_WEXT |
328 | rdev->wiphy.wext = &cfg80211_wext_handler; | 330 | rdev->wiphy.wext = &cfg80211_wext_handler; |
329 | #endif | 331 | #endif |
@@ -365,7 +367,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
365 | rdev->wiphy.rts_threshold = (u32) -1; | 367 | rdev->wiphy.rts_threshold = (u32) -1; |
366 | rdev->wiphy.coverage_class = 0; | 368 | rdev->wiphy.coverage_class = 0; |
367 | 369 | ||
368 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; | 370 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH | |
371 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | ||
369 | 372 | ||
370 | return &rdev->wiphy; | 373 | return &rdev->wiphy; |
371 | } | 374 | } |
@@ -695,6 +698,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
695 | flush_work(&rdev->scan_done_wk); | 698 | flush_work(&rdev->scan_done_wk); |
696 | cancel_work_sync(&rdev->conn_work); | 699 | cancel_work_sync(&rdev->conn_work); |
697 | flush_work(&rdev->event_work); | 700 | flush_work(&rdev->event_work); |
701 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | ||
698 | 702 | ||
699 | if (rdev->wowlan && rdev->ops->set_wakeup) | 703 | if (rdev->wowlan && rdev->ops->set_wakeup) |
700 | rdev_set_wakeup(rdev, false); | 704 | rdev_set_wakeup(rdev, false); |
@@ -715,7 +719,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
715 | kfree(reg); | 719 | kfree(reg); |
716 | } | 720 | } |
717 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 721 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
718 | cfg80211_put_bss(&scan->pub); | 722 | cfg80211_put_bss(&rdev->wiphy, &scan->pub); |
719 | kfree(rdev); | 723 | kfree(rdev); |
720 | } | 724 | } |
721 | 725 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 8396f7671c8d..3aec0e429d8a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/mutex.h> | 8 | #include <linux/mutex.h> |
9 | #include <linux/list.h> | 9 | #include <linux/list.h> |
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/kref.h> | ||
12 | #include <linux/rbtree.h> | 11 | #include <linux/rbtree.h> |
13 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | 13 | #include <linux/rfkill.h> |
@@ -87,6 +86,8 @@ struct cfg80211_registered_device { | |||
87 | 86 | ||
88 | struct cfg80211_wowlan *wowlan; | 87 | struct cfg80211_wowlan *wowlan; |
89 | 88 | ||
89 | struct delayed_work dfs_update_channels_wk; | ||
90 | |||
90 | /* must be last because of the way we do wiphy_priv(), | 91 | /* must be last because of the way we do wiphy_priv(), |
91 | * and it should at least be aligned to NETDEV_ALIGN */ | 92 | * and it should at least be aligned to NETDEV_ALIGN */ |
92 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 93 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
@@ -109,6 +110,9 @@ cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | |||
109 | for (i = 0; i < rdev->wowlan->n_patterns; i++) | 110 | for (i = 0; i < rdev->wowlan->n_patterns; i++) |
110 | kfree(rdev->wowlan->patterns[i].mask); | 111 | kfree(rdev->wowlan->patterns[i].mask); |
111 | kfree(rdev->wowlan->patterns); | 112 | kfree(rdev->wowlan->patterns); |
113 | if (rdev->wowlan->tcp && rdev->wowlan->tcp->sock) | ||
114 | sock_release(rdev->wowlan->tcp->sock); | ||
115 | kfree(rdev->wowlan->tcp); | ||
112 | kfree(rdev->wowlan); | 116 | kfree(rdev->wowlan); |
113 | } | 117 | } |
114 | 118 | ||
@@ -124,9 +128,10 @@ static inline void assert_cfg80211_lock(void) | |||
124 | 128 | ||
125 | struct cfg80211_internal_bss { | 129 | struct cfg80211_internal_bss { |
126 | struct list_head list; | 130 | struct list_head list; |
131 | struct list_head hidden_list; | ||
127 | struct rb_node rbn; | 132 | struct rb_node rbn; |
128 | unsigned long ts; | 133 | unsigned long ts; |
129 | struct kref ref; | 134 | unsigned long refcount; |
130 | atomic_t hold; | 135 | atomic_t hold; |
131 | 136 | ||
132 | /* must be last because of priv member */ | 137 | /* must be last because of priv member */ |
@@ -428,6 +433,22 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
428 | enum cfg80211_chan_mode chanmode, | 433 | enum cfg80211_chan_mode chanmode, |
429 | u8 radar_detect); | 434 | u8 radar_detect); |
430 | 435 | ||
436 | /** | ||
437 | * cfg80211_chandef_dfs_required - checks if radar detection is required | ||
438 | * @wiphy: the wiphy to validate against | ||
439 | * @chandef: the channel definition to check | ||
440 | * Return: 1 if radar detection is required, 0 if it is not, < 0 on error | ||
441 | */ | ||
442 | int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | ||
443 | const struct cfg80211_chan_def *c); | ||
444 | |||
445 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | ||
446 | const struct cfg80211_chan_def *chandef, | ||
447 | enum nl80211_dfs_state dfs_state); | ||
448 | |||
449 | void cfg80211_dfs_channels_update_work(struct work_struct *work); | ||
450 | |||
451 | |||
431 | static inline int | 452 | static inline int |
432 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 453 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, |
433 | struct wireless_dev *wdev, | 454 | struct wireless_dev *wdev, |
@@ -454,6 +475,16 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | |||
454 | chan, chanmode, 0); | 475 | chan, chanmode, 0); |
455 | } | 476 | } |
456 | 477 | ||
478 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
479 | { | ||
480 | unsigned long end = jiffies; | ||
481 | |||
482 | if (end >= start) | ||
483 | return jiffies_to_msecs(end - start); | ||
484 | |||
485 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
486 | } | ||
487 | |||
457 | void | 488 | void |
458 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 489 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
459 | struct ieee80211_channel **chan, | 490 | struct ieee80211_channel **chan, |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 9b9551e4a6f9..d80e47194d49 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -37,7 +37,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
37 | 37 | ||
38 | if (wdev->current_bss) { | 38 | if (wdev->current_bss) { |
39 | cfg80211_unhold_bss(wdev->current_bss); | 39 | cfg80211_unhold_bss(wdev->current_bss); |
40 | cfg80211_put_bss(&wdev->current_bss->pub); | 40 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
41 | } | 41 | } |
42 | 42 | ||
43 | cfg80211_hold_bss(bss_from_pub(bss)); | 43 | cfg80211_hold_bss(bss_from_pub(bss)); |
@@ -182,7 +182,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
182 | 182 | ||
183 | if (wdev->current_bss) { | 183 | if (wdev->current_bss) { |
184 | cfg80211_unhold_bss(wdev->current_bss); | 184 | cfg80211_unhold_bss(wdev->current_bss); |
185 | cfg80211_put_bss(&wdev->current_bss->pub); | 185 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
186 | } | 186 | } |
187 | 187 | ||
188 | wdev->current_bss = NULL; | 188 | wdev->current_bss = NULL; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 461e692cdfec..caddca35d686 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -58,7 +58,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
58 | */ | 58 | */ |
59 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | 59 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && |
60 | cfg80211_sme_failed_reassoc(wdev)) { | 60 | cfg80211_sme_failed_reassoc(wdev)) { |
61 | cfg80211_put_bss(bss); | 61 | cfg80211_put_bss(wiphy, bss); |
62 | goto out; | 62 | goto out; |
63 | } | 63 | } |
64 | 64 | ||
@@ -70,7 +70,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
70 | * do not call connect_result() now because the | 70 | * do not call connect_result() now because the |
71 | * sme will schedule work that does it later. | 71 | * sme will schedule work that does it later. |
72 | */ | 72 | */ |
73 | cfg80211_put_bss(bss); | 73 | cfg80211_put_bss(wiphy, bss); |
74 | goto out; | 74 | goto out; |
75 | } | 75 | } |
76 | 76 | ||
@@ -108,7 +108,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
108 | if (wdev->current_bss && | 108 | if (wdev->current_bss && |
109 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { | 109 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { |
110 | cfg80211_unhold_bss(wdev->current_bss); | 110 | cfg80211_unhold_bss(wdev->current_bss); |
111 | cfg80211_put_bss(&wdev->current_bss->pub); | 111 | cfg80211_put_bss(wiphy, &wdev->current_bss->pub); |
112 | wdev->current_bss = NULL; | 112 | wdev->current_bss = NULL; |
113 | was_current = true; | 113 | was_current = true; |
114 | } | 114 | } |
@@ -164,7 +164,7 @@ void __cfg80211_send_disassoc(struct net_device *dev, | |||
164 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { | 164 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { |
165 | cfg80211_sme_disassoc(dev, wdev->current_bss); | 165 | cfg80211_sme_disassoc(dev, wdev->current_bss); |
166 | cfg80211_unhold_bss(wdev->current_bss); | 166 | cfg80211_unhold_bss(wdev->current_bss); |
167 | cfg80211_put_bss(&wdev->current_bss->pub); | 167 | cfg80211_put_bss(wiphy, &wdev->current_bss->pub); |
168 | wdev->current_bss = NULL; | 168 | wdev->current_bss = NULL; |
169 | } else | 169 | } else |
170 | WARN_ON(1); | 170 | WARN_ON(1); |
@@ -324,7 +324,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
324 | err = rdev_auth(rdev, dev, &req); | 324 | err = rdev_auth(rdev, dev, &req); |
325 | 325 | ||
326 | out: | 326 | out: |
327 | cfg80211_put_bss(req.bss); | 327 | cfg80211_put_bss(&rdev->wiphy, req.bss); |
328 | return err; | 328 | return err; |
329 | } | 329 | } |
330 | 330 | ||
@@ -432,7 +432,7 @@ out: | |||
432 | if (err) { | 432 | if (err) { |
433 | if (was_connected) | 433 | if (was_connected) |
434 | wdev->sme_state = CFG80211_SME_CONNECTED; | 434 | wdev->sme_state = CFG80211_SME_CONNECTED; |
435 | cfg80211_put_bss(req.bss); | 435 | cfg80211_put_bss(&rdev->wiphy, req.bss); |
436 | } | 436 | } |
437 | 437 | ||
438 | return err; | 438 | return err; |
@@ -514,7 +514,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
514 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 514 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
515 | return -ENOTCONN; | 515 | return -ENOTCONN; |
516 | 516 | ||
517 | if (WARN_ON(!wdev->current_bss)) | 517 | if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state)) |
518 | return -ENOTCONN; | 518 | return -ENOTCONN; |
519 | 519 | ||
520 | memset(&req, 0, sizeof(req)); | 520 | memset(&req, 0, sizeof(req)); |
@@ -572,7 +572,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
572 | 572 | ||
573 | if (wdev->current_bss) { | 573 | if (wdev->current_bss) { |
574 | cfg80211_unhold_bss(wdev->current_bss); | 574 | cfg80211_unhold_bss(wdev->current_bss); |
575 | cfg80211_put_bss(&wdev->current_bss->pub); | 575 | cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub); |
576 | wdev->current_bss = NULL; | 576 | wdev->current_bss = NULL; |
577 | } | 577 | } |
578 | } | 578 | } |
@@ -987,3 +987,123 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, | |||
987 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | 987 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); |
988 | } | 988 | } |
989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | 989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); |
990 | |||
991 | void cfg80211_dfs_channels_update_work(struct work_struct *work) | ||
992 | { | ||
993 | struct delayed_work *delayed_work; | ||
994 | struct cfg80211_registered_device *rdev; | ||
995 | struct cfg80211_chan_def chandef; | ||
996 | struct ieee80211_supported_band *sband; | ||
997 | struct ieee80211_channel *c; | ||
998 | struct wiphy *wiphy; | ||
999 | bool check_again = false; | ||
1000 | unsigned long timeout, next_time = 0; | ||
1001 | int bandid, i; | ||
1002 | |||
1003 | delayed_work = container_of(work, struct delayed_work, work); | ||
1004 | rdev = container_of(delayed_work, struct cfg80211_registered_device, | ||
1005 | dfs_update_channels_wk); | ||
1006 | wiphy = &rdev->wiphy; | ||
1007 | |||
1008 | mutex_lock(&cfg80211_mutex); | ||
1009 | for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) { | ||
1010 | sband = wiphy->bands[bandid]; | ||
1011 | if (!sband) | ||
1012 | continue; | ||
1013 | |||
1014 | for (i = 0; i < sband->n_channels; i++) { | ||
1015 | c = &sband->channels[i]; | ||
1016 | |||
1017 | if (c->dfs_state != NL80211_DFS_UNAVAILABLE) | ||
1018 | continue; | ||
1019 | |||
1020 | timeout = c->dfs_state_entered + | ||
1021 | IEEE80211_DFS_MIN_NOP_TIME_MS; | ||
1022 | |||
1023 | if (time_after_eq(jiffies, timeout)) { | ||
1024 | c->dfs_state = NL80211_DFS_USABLE; | ||
1025 | cfg80211_chandef_create(&chandef, c, | ||
1026 | NL80211_CHAN_NO_HT); | ||
1027 | |||
1028 | nl80211_radar_notify(rdev, &chandef, | ||
1029 | NL80211_RADAR_NOP_FINISHED, | ||
1030 | NULL, GFP_ATOMIC); | ||
1031 | continue; | ||
1032 | } | ||
1033 | |||
1034 | if (!check_again) | ||
1035 | next_time = timeout - jiffies; | ||
1036 | else | ||
1037 | next_time = min(next_time, timeout - jiffies); | ||
1038 | check_again = true; | ||
1039 | } | ||
1040 | } | ||
1041 | mutex_unlock(&cfg80211_mutex); | ||
1042 | |||
1043 | /* reschedule if there are other channels waiting to be cleared again */ | ||
1044 | if (check_again) | ||
1045 | queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, | ||
1046 | next_time); | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | void cfg80211_radar_event(struct wiphy *wiphy, | ||
1051 | struct cfg80211_chan_def *chandef, | ||
1052 | gfp_t gfp) | ||
1053 | { | ||
1054 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
1055 | unsigned long timeout; | ||
1056 | |||
1057 | trace_cfg80211_radar_event(wiphy, chandef); | ||
1058 | |||
1059 | /* only set the chandef supplied channel to unavailable, in | ||
1060 | * case the radar is detected on only one of multiple channels | ||
1061 | * spanned by the chandef. | ||
1062 | */ | ||
1063 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); | ||
1064 | |||
1065 | timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS); | ||
1066 | queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, | ||
1067 | timeout); | ||
1068 | |||
1069 | nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); | ||
1070 | } | ||
1071 | EXPORT_SYMBOL(cfg80211_radar_event); | ||
1072 | |||
1073 | void cfg80211_cac_event(struct net_device *netdev, | ||
1074 | enum nl80211_radar_event event, gfp_t gfp) | ||
1075 | { | ||
1076 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | ||
1077 | struct wiphy *wiphy = wdev->wiphy; | ||
1078 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
1079 | struct cfg80211_chan_def chandef; | ||
1080 | unsigned long timeout; | ||
1081 | |||
1082 | trace_cfg80211_cac_event(netdev, event); | ||
1083 | |||
1084 | if (WARN_ON(!wdev->cac_started)) | ||
1085 | return; | ||
1086 | |||
1087 | if (WARN_ON(!wdev->channel)) | ||
1088 | return; | ||
1089 | |||
1090 | cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT); | ||
1091 | |||
1092 | switch (event) { | ||
1093 | case NL80211_RADAR_CAC_FINISHED: | ||
1094 | timeout = wdev->cac_start_time + | ||
1095 | msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | ||
1096 | WARN_ON(!time_after_eq(jiffies, timeout)); | ||
1097 | cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE); | ||
1098 | break; | ||
1099 | case NL80211_RADAR_CAC_ABORTED: | ||
1100 | break; | ||
1101 | default: | ||
1102 | WARN_ON(1); | ||
1103 | return; | ||
1104 | } | ||
1105 | wdev->cac_started = false; | ||
1106 | |||
1107 | nl80211_radar_notify(rdev, &chandef, event, netdev, gfp); | ||
1108 | } | ||
1109 | EXPORT_SYMBOL(cfg80211_cac_event); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b5978ab4ad7a..580ffeaef3d5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <net/genetlink.h> | 19 | #include <net/genetlink.h> |
20 | #include <net/cfg80211.h> | 20 | #include <net/cfg80211.h> |
21 | #include <net/sock.h> | 21 | #include <net/sock.h> |
22 | #include <net/inet_connection_sock.h> | ||
22 | #include "core.h" | 23 | #include "core.h" |
23 | #include "nl80211.h" | 24 | #include "nl80211.h" |
24 | #include "reg.h" | 25 | #include "reg.h" |
@@ -367,6 +368,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
367 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, | 368 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, |
368 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, | 369 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, |
369 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, | 370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, |
371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, | ||
372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, | ||
370 | }; | 373 | }; |
371 | 374 | ||
372 | /* policy for the key attributes */ | 375 | /* policy for the key attributes */ |
@@ -399,6 +402,26 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
399 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | 402 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, |
400 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | 403 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, |
401 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | 404 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, |
405 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, | ||
406 | }; | ||
407 | |||
408 | static const struct nla_policy | ||
409 | nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = { | ||
410 | [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 }, | ||
411 | [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 }, | ||
412 | [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN }, | ||
413 | [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 }, | ||
414 | [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 }, | ||
415 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 }, | ||
416 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = { | ||
417 | .len = sizeof(struct nl80211_wowlan_tcp_data_seq) | ||
418 | }, | ||
419 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = { | ||
420 | .len = sizeof(struct nl80211_wowlan_tcp_data_token) | ||
421 | }, | ||
422 | [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 }, | ||
423 | [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 }, | ||
424 | [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, | ||
402 | }; | 425 | }; |
403 | 426 | ||
404 | /* policy for GTK rekey offload attributes */ | 427 | /* policy for GTK rekey offload attributes */ |
@@ -531,8 +554,27 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
531 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 554 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && |
532 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 555 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) |
533 | goto nla_put_failure; | 556 | goto nla_put_failure; |
534 | if ((chan->flags & IEEE80211_CHAN_RADAR) && | 557 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
535 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 558 | u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered); |
559 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | ||
560 | goto nla_put_failure; | ||
561 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
562 | chan->dfs_state)) | ||
563 | goto nla_put_failure; | ||
564 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time)) | ||
565 | goto nla_put_failure; | ||
566 | } | ||
567 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
568 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
569 | goto nla_put_failure; | ||
570 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
572 | goto nla_put_failure; | ||
573 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
574 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
575 | goto nla_put_failure; | ||
576 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && | ||
577 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
536 | goto nla_put_failure; | 578 | goto nla_put_failure; |
537 | 579 | ||
538 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 580 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
@@ -872,6 +914,48 @@ nla_put_failure: | |||
872 | return -ENOBUFS; | 914 | return -ENOBUFS; |
873 | } | 915 | } |
874 | 916 | ||
917 | #ifdef CONFIG_PM | ||
918 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, | ||
919 | struct sk_buff *msg) | ||
920 | { | ||
921 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; | ||
922 | struct nlattr *nl_tcp; | ||
923 | |||
924 | if (!tcp) | ||
925 | return 0; | ||
926 | |||
927 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
928 | if (!nl_tcp) | ||
929 | return -ENOBUFS; | ||
930 | |||
931 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
932 | tcp->data_payload_max)) | ||
933 | return -ENOBUFS; | ||
934 | |||
935 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
936 | tcp->data_payload_max)) | ||
937 | return -ENOBUFS; | ||
938 | |||
939 | if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ)) | ||
940 | return -ENOBUFS; | ||
941 | |||
942 | if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
943 | sizeof(*tcp->tok), tcp->tok)) | ||
944 | return -ENOBUFS; | ||
945 | |||
946 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
947 | tcp->data_interval_max)) | ||
948 | return -ENOBUFS; | ||
949 | |||
950 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
951 | tcp->wake_payload_max)) | ||
952 | return -ENOBUFS; | ||
953 | |||
954 | nla_nest_end(msg, nl_tcp); | ||
955 | return 0; | ||
956 | } | ||
957 | #endif | ||
958 | |||
875 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 959 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
876 | struct cfg80211_registered_device *dev) | 960 | struct cfg80211_registered_device *dev) |
877 | { | 961 | { |
@@ -1238,12 +1322,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1238 | dev->wiphy.wowlan.pattern_min_len, | 1322 | dev->wiphy.wowlan.pattern_min_len, |
1239 | .max_pattern_len = | 1323 | .max_pattern_len = |
1240 | dev->wiphy.wowlan.pattern_max_len, | 1324 | dev->wiphy.wowlan.pattern_max_len, |
1325 | .max_pkt_offset = | ||
1326 | dev->wiphy.wowlan.max_pkt_offset, | ||
1241 | }; | 1327 | }; |
1242 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | 1328 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, |
1243 | sizeof(pat), &pat)) | 1329 | sizeof(pat), &pat)) |
1244 | goto nla_put_failure; | 1330 | goto nla_put_failure; |
1245 | } | 1331 | } |
1246 | 1332 | ||
1333 | if (nl80211_send_wowlan_tcp_caps(dev, msg)) | ||
1334 | goto nla_put_failure; | ||
1335 | |||
1247 | nla_nest_end(msg, nl_wowlan); | 1336 | nla_nest_end(msg, nl_wowlan); |
1248 | } | 1337 | } |
1249 | #endif | 1338 | #endif |
@@ -1276,6 +1365,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1276 | dev->wiphy.max_acl_mac_addrs)) | 1365 | dev->wiphy.max_acl_mac_addrs)) |
1277 | goto nla_put_failure; | 1366 | goto nla_put_failure; |
1278 | 1367 | ||
1368 | if (dev->wiphy.extended_capabilities && | ||
1369 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | ||
1370 | dev->wiphy.extended_capabilities_len, | ||
1371 | dev->wiphy.extended_capabilities) || | ||
1372 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | ||
1373 | dev->wiphy.extended_capabilities_len, | ||
1374 | dev->wiphy.extended_capabilities_mask))) | ||
1375 | goto nla_put_failure; | ||
1376 | |||
1279 | return genlmsg_end(msg, hdr); | 1377 | return genlmsg_end(msg, hdr); |
1280 | 1378 | ||
1281 | nla_put_failure: | 1379 | nla_put_failure: |
@@ -2707,6 +2805,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2707 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 2805 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
2708 | struct cfg80211_ap_settings params; | 2806 | struct cfg80211_ap_settings params; |
2709 | int err; | 2807 | int err; |
2808 | u8 radar_detect_width = 0; | ||
2710 | 2809 | ||
2711 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2810 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2712 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2811 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
@@ -2825,9 +2924,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2825 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | 2924 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) |
2826 | return -EINVAL; | 2925 | return -EINVAL; |
2827 | 2926 | ||
2927 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | ||
2928 | if (err < 0) | ||
2929 | return err; | ||
2930 | if (err) { | ||
2931 | radar_detect_width = BIT(params.chandef.width); | ||
2932 | params.radar_required = true; | ||
2933 | } | ||
2934 | |||
2828 | mutex_lock(&rdev->devlist_mtx); | 2935 | mutex_lock(&rdev->devlist_mtx); |
2829 | err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, | 2936 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
2830 | CHAN_MODE_SHARED); | 2937 | params.chandef.chan, |
2938 | CHAN_MODE_SHARED, | ||
2939 | radar_detect_width); | ||
2831 | mutex_unlock(&rdev->devlist_mtx); | 2940 | mutex_unlock(&rdev->devlist_mtx); |
2832 | 2941 | ||
2833 | if (err) | 2942 | if (err) |
@@ -3057,12 +3166,22 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3057 | nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 3166 | nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME, |
3058 | sinfo->inactive_time)) | 3167 | sinfo->inactive_time)) |
3059 | goto nla_put_failure; | 3168 | goto nla_put_failure; |
3060 | if ((sinfo->filled & STATION_INFO_RX_BYTES) && | 3169 | if ((sinfo->filled & (STATION_INFO_RX_BYTES | |
3170 | STATION_INFO_RX_BYTES64)) && | ||
3061 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, | 3171 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, |
3062 | sinfo->rx_bytes)) | 3172 | (u32)sinfo->rx_bytes)) |
3063 | goto nla_put_failure; | 3173 | goto nla_put_failure; |
3064 | if ((sinfo->filled & STATION_INFO_TX_BYTES) && | 3174 | if ((sinfo->filled & (STATION_INFO_TX_BYTES | |
3175 | NL80211_STA_INFO_TX_BYTES64)) && | ||
3065 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, | 3176 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, |
3177 | (u32)sinfo->tx_bytes)) | ||
3178 | goto nla_put_failure; | ||
3179 | if ((sinfo->filled & STATION_INFO_RX_BYTES64) && | ||
3180 | nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64, | ||
3181 | sinfo->rx_bytes)) | ||
3182 | goto nla_put_failure; | ||
3183 | if ((sinfo->filled & STATION_INFO_TX_BYTES64) && | ||
3184 | nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64, | ||
3066 | sinfo->tx_bytes)) | 3185 | sinfo->tx_bytes)) |
3067 | goto nla_put_failure; | 3186 | goto nla_put_failure; |
3068 | if ((sinfo->filled & STATION_INFO_LLID) && | 3187 | if ((sinfo->filled & STATION_INFO_LLID) && |
@@ -3290,6 +3409,63 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3290 | return ERR_PTR(ret); | 3409 | return ERR_PTR(ret); |
3291 | } | 3410 | } |
3292 | 3411 | ||
3412 | static struct nla_policy | ||
3413 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
3414 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
3415 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
3416 | }; | ||
3417 | |||
3418 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
3419 | struct station_parameters *params) | ||
3420 | { | ||
3421 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3422 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
3423 | struct nlattr *nla; | ||
3424 | int err; | ||
3425 | |||
3426 | /* Can only set if TDLS ... */ | ||
3427 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
3428 | return -EOPNOTSUPP; | ||
3429 | |||
3430 | /* ... with external setup is supported */ | ||
3431 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | ||
3432 | return -EOPNOTSUPP; | ||
3433 | |||
3434 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3435 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3436 | params->ht_capa = | ||
3437 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3438 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3439 | params->vht_capa = | ||
3440 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3441 | |||
3442 | /* parse WME attributes if present */ | ||
3443 | if (!info->attrs[NL80211_ATTR_STA_WME]) | ||
3444 | return 0; | ||
3445 | |||
3446 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
3447 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
3448 | nl80211_sta_wme_policy); | ||
3449 | if (err) | ||
3450 | return err; | ||
3451 | |||
3452 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | ||
3453 | params->uapsd_queues = nla_get_u8( | ||
3454 | tb[NL80211_STA_WME_UAPSD_QUEUES]); | ||
3455 | if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
3456 | return -EINVAL; | ||
3457 | |||
3458 | if (tb[NL80211_STA_WME_MAX_SP]) | ||
3459 | params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | ||
3460 | |||
3461 | if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
3462 | return -EINVAL; | ||
3463 | |||
3464 | params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
3465 | |||
3466 | return 0; | ||
3467 | } | ||
3468 | |||
3293 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3469 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
3294 | { | 3470 | { |
3295 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3471 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -3318,8 +3494,20 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3318 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 3494 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
3319 | } | 3495 | } |
3320 | 3496 | ||
3321 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] || | 3497 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { |
3322 | info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3498 | params.capability = |
3499 | nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); | ||
3500 | params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY; | ||
3501 | } | ||
3502 | |||
3503 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) { | ||
3504 | params.ext_capab = | ||
3505 | nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3506 | params.ext_capab_len = | ||
3507 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3508 | } | ||
3509 | |||
3510 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
3323 | return -EINVAL; | 3511 | return -EINVAL; |
3324 | 3512 | ||
3325 | if (!rdev->ops->change_station) | 3513 | if (!rdev->ops->change_station) |
@@ -3388,6 +3576,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3388 | /* reject other things that can't change */ | 3576 | /* reject other things that can't change */ |
3389 | if (params.supported_rates) | 3577 | if (params.supported_rates) |
3390 | return -EINVAL; | 3578 | return -EINVAL; |
3579 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3580 | return -EINVAL; | ||
3581 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3582 | return -EINVAL; | ||
3583 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3584 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3585 | return -EINVAL; | ||
3391 | 3586 | ||
3392 | /* must be last in here for error handling */ | 3587 | /* must be last in here for error handling */ |
3393 | params.vlan = get_vlan(info, rdev); | 3588 | params.vlan = get_vlan(info, rdev); |
@@ -3403,13 +3598,29 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3403 | * to change the flag. | 3598 | * to change the flag. |
3404 | */ | 3599 | */ |
3405 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | 3600 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
3406 | /* fall through */ | 3601 | /* Include parameters for TDLS peer (driver will check) */ |
3602 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3603 | if (err) | ||
3604 | return err; | ||
3605 | /* disallow things sta doesn't support */ | ||
3606 | if (params.plink_action) | ||
3607 | return -EINVAL; | ||
3608 | if (params.local_pm) | ||
3609 | return -EINVAL; | ||
3610 | /* reject any changes other than AUTHORIZED or WME (for TDLS) */ | ||
3611 | if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3612 | BIT(NL80211_STA_FLAG_WME))) | ||
3613 | return -EINVAL; | ||
3614 | break; | ||
3407 | case NL80211_IFTYPE_ADHOC: | 3615 | case NL80211_IFTYPE_ADHOC: |
3408 | /* disallow things sta doesn't support */ | 3616 | /* disallow things sta doesn't support */ |
3409 | if (params.plink_action) | 3617 | if (params.plink_action) |
3410 | return -EINVAL; | 3618 | return -EINVAL; |
3411 | if (params.local_pm) | 3619 | if (params.local_pm) |
3412 | return -EINVAL; | 3620 | return -EINVAL; |
3621 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3622 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3623 | return -EINVAL; | ||
3413 | /* reject any changes other than AUTHORIZED */ | 3624 | /* reject any changes other than AUTHORIZED */ |
3414 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 3625 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) |
3415 | return -EINVAL; | 3626 | return -EINVAL; |
@@ -3420,6 +3631,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3420 | return -EINVAL; | 3631 | return -EINVAL; |
3421 | if (params.supported_rates) | 3632 | if (params.supported_rates) |
3422 | return -EINVAL; | 3633 | return -EINVAL; |
3634 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3635 | return -EINVAL; | ||
3636 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3637 | return -EINVAL; | ||
3638 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3639 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3640 | return -EINVAL; | ||
3423 | /* | 3641 | /* |
3424 | * No special handling for TDLS here -- the userspace | 3642 | * No special handling for TDLS here -- the userspace |
3425 | * mesh code doesn't have this bug. | 3643 | * mesh code doesn't have this bug. |
@@ -3444,12 +3662,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3444 | return err; | 3662 | return err; |
3445 | } | 3663 | } |
3446 | 3664 | ||
3447 | static struct nla_policy | ||
3448 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
3449 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
3450 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
3451 | }; | ||
3452 | |||
3453 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 3665 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
3454 | { | 3666 | { |
3455 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3667 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -3484,6 +3696,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3484 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 3696 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
3485 | return -EINVAL; | 3697 | return -EINVAL; |
3486 | 3698 | ||
3699 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { | ||
3700 | params.capability = | ||
3701 | nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); | ||
3702 | params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY; | ||
3703 | } | ||
3704 | |||
3705 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) { | ||
3706 | params.ext_capab = | ||
3707 | nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3708 | params.ext_capab_len = | ||
3709 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3710 | } | ||
3711 | |||
3487 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3712 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
3488 | params.ht_capa = | 3713 | params.ht_capa = |
3489 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 3714 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
@@ -4977,6 +5202,54 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
4977 | return err; | 5202 | return err; |
4978 | } | 5203 | } |
4979 | 5204 | ||
5205 | static int nl80211_start_radar_detection(struct sk_buff *skb, | ||
5206 | struct genl_info *info) | ||
5207 | { | ||
5208 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5209 | struct net_device *dev = info->user_ptr[1]; | ||
5210 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5211 | struct cfg80211_chan_def chandef; | ||
5212 | int err; | ||
5213 | |||
5214 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
5215 | if (err) | ||
5216 | return err; | ||
5217 | |||
5218 | if (wdev->cac_started) | ||
5219 | return -EBUSY; | ||
5220 | |||
5221 | err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef); | ||
5222 | if (err < 0) | ||
5223 | return err; | ||
5224 | |||
5225 | if (err == 0) | ||
5226 | return -EINVAL; | ||
5227 | |||
5228 | if (chandef.chan->dfs_state != NL80211_DFS_USABLE) | ||
5229 | return -EINVAL; | ||
5230 | |||
5231 | if (!rdev->ops->start_radar_detection) | ||
5232 | return -EOPNOTSUPP; | ||
5233 | |||
5234 | mutex_lock(&rdev->devlist_mtx); | ||
5235 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
5236 | chandef.chan, CHAN_MODE_SHARED, | ||
5237 | BIT(chandef.width)); | ||
5238 | if (err) | ||
5239 | goto err_locked; | ||
5240 | |||
5241 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | ||
5242 | if (!err) { | ||
5243 | wdev->channel = chandef.chan; | ||
5244 | wdev->cac_started = true; | ||
5245 | wdev->cac_start_time = jiffies; | ||
5246 | } | ||
5247 | err_locked: | ||
5248 | mutex_unlock(&rdev->devlist_mtx); | ||
5249 | |||
5250 | return err; | ||
5251 | } | ||
5252 | |||
4980 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | 5253 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
4981 | u32 seq, int flags, | 5254 | u32 seq, int flags, |
4982 | struct cfg80211_registered_device *rdev, | 5255 | struct cfg80211_registered_device *rdev, |
@@ -4987,6 +5260,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
4987 | const struct cfg80211_bss_ies *ies; | 5260 | const struct cfg80211_bss_ies *ies; |
4988 | void *hdr; | 5261 | void *hdr; |
4989 | struct nlattr *bss; | 5262 | struct nlattr *bss; |
5263 | bool tsf = false; | ||
4990 | 5264 | ||
4991 | ASSERT_WDEV_LOCK(wdev); | 5265 | ASSERT_WDEV_LOCK(wdev); |
4992 | 5266 | ||
@@ -5010,22 +5284,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
5010 | 5284 | ||
5011 | rcu_read_lock(); | 5285 | rcu_read_lock(); |
5012 | ies = rcu_dereference(res->ies); | 5286 | ies = rcu_dereference(res->ies); |
5013 | if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, | 5287 | if (ies) { |
5014 | ies->len, ies->data)) { | 5288 | if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf)) |
5015 | rcu_read_unlock(); | 5289 | goto fail_unlock_rcu; |
5016 | goto nla_put_failure; | 5290 | tsf = true; |
5291 | if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, | ||
5292 | ies->len, ies->data)) | ||
5293 | goto fail_unlock_rcu; | ||
5017 | } | 5294 | } |
5018 | ies = rcu_dereference(res->beacon_ies); | 5295 | ies = rcu_dereference(res->beacon_ies); |
5019 | if (ies && ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, | 5296 | if (ies) { |
5020 | ies->len, ies->data)) { | 5297 | if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf)) |
5021 | rcu_read_unlock(); | 5298 | goto fail_unlock_rcu; |
5022 | goto nla_put_failure; | 5299 | if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, |
5300 | ies->len, ies->data)) | ||
5301 | goto fail_unlock_rcu; | ||
5023 | } | 5302 | } |
5024 | rcu_read_unlock(); | 5303 | rcu_read_unlock(); |
5025 | 5304 | ||
5026 | if (res->tsf && | ||
5027 | nla_put_u64(msg, NL80211_BSS_TSF, res->tsf)) | ||
5028 | goto nla_put_failure; | ||
5029 | if (res->beacon_interval && | 5305 | if (res->beacon_interval && |
5030 | nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval)) | 5306 | nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval)) |
5031 | goto nla_put_failure; | 5307 | goto nla_put_failure; |
@@ -5070,6 +5346,8 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
5070 | 5346 | ||
5071 | return genlmsg_end(msg, hdr); | 5347 | return genlmsg_end(msg, hdr); |
5072 | 5348 | ||
5349 | fail_unlock_rcu: | ||
5350 | rcu_read_unlock(); | ||
5073 | nla_put_failure: | 5351 | nla_put_failure: |
5074 | genlmsg_cancel(msg, hdr); | 5352 | genlmsg_cancel(msg, hdr); |
5075 | return -EMSGSIZE; | 5353 | return -EMSGSIZE; |
@@ -6880,16 +7158,100 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6880 | } | 7158 | } |
6881 | 7159 | ||
6882 | #ifdef CONFIG_PM | 7160 | #ifdef CONFIG_PM |
7161 | static int nl80211_send_wowlan_patterns(struct sk_buff *msg, | ||
7162 | struct cfg80211_registered_device *rdev) | ||
7163 | { | ||
7164 | struct nlattr *nl_pats, *nl_pat; | ||
7165 | int i, pat_len; | ||
7166 | |||
7167 | if (!rdev->wowlan->n_patterns) | ||
7168 | return 0; | ||
7169 | |||
7170 | nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN); | ||
7171 | if (!nl_pats) | ||
7172 | return -ENOBUFS; | ||
7173 | |||
7174 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | ||
7175 | nl_pat = nla_nest_start(msg, i + 1); | ||
7176 | if (!nl_pat) | ||
7177 | return -ENOBUFS; | ||
7178 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
7179 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
7180 | DIV_ROUND_UP(pat_len, 8), | ||
7181 | rdev->wowlan->patterns[i].mask) || | ||
7182 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
7183 | pat_len, rdev->wowlan->patterns[i].pattern) || | ||
7184 | nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, | ||
7185 | rdev->wowlan->patterns[i].pkt_offset)) | ||
7186 | return -ENOBUFS; | ||
7187 | nla_nest_end(msg, nl_pat); | ||
7188 | } | ||
7189 | nla_nest_end(msg, nl_pats); | ||
7190 | |||
7191 | return 0; | ||
7192 | } | ||
7193 | |||
7194 | static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | ||
7195 | struct cfg80211_wowlan_tcp *tcp) | ||
7196 | { | ||
7197 | struct nlattr *nl_tcp; | ||
7198 | |||
7199 | if (!tcp) | ||
7200 | return 0; | ||
7201 | |||
7202 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
7203 | if (!nl_tcp) | ||
7204 | return -ENOBUFS; | ||
7205 | |||
7206 | if (nla_put_be32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) || | ||
7207 | nla_put_be32(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) || | ||
7208 | nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) || | ||
7209 | nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) || | ||
7210 | nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) || | ||
7211 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
7212 | tcp->payload_len, tcp->payload) || | ||
7213 | nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
7214 | tcp->data_interval) || | ||
7215 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
7216 | tcp->wake_len, tcp->wake_data) || | ||
7217 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK, | ||
7218 | DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask)) | ||
7219 | return -ENOBUFS; | ||
7220 | |||
7221 | if (tcp->payload_seq.len && | ||
7222 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
7223 | sizeof(tcp->payload_seq), &tcp->payload_seq)) | ||
7224 | return -ENOBUFS; | ||
7225 | |||
7226 | if (tcp->payload_tok.len && | ||
7227 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
7228 | sizeof(tcp->payload_tok) + tcp->tokens_size, | ||
7229 | &tcp->payload_tok)) | ||
7230 | return -ENOBUFS; | ||
7231 | |||
7232 | return 0; | ||
7233 | } | ||
7234 | |||
6883 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 7235 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6884 | { | 7236 | { |
6885 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7237 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6886 | struct sk_buff *msg; | 7238 | struct sk_buff *msg; |
6887 | void *hdr; | 7239 | void *hdr; |
7240 | u32 size = NLMSG_DEFAULT_SIZE; | ||
6888 | 7241 | ||
6889 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7242 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7243 | !rdev->wiphy.wowlan.tcp) | ||
6890 | return -EOPNOTSUPP; | 7244 | return -EOPNOTSUPP; |
6891 | 7245 | ||
6892 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7246 | if (rdev->wowlan && rdev->wowlan->tcp) { |
7247 | /* adjust size to have room for all the data */ | ||
7248 | size += rdev->wowlan->tcp->tokens_size + | ||
7249 | rdev->wowlan->tcp->payload_len + | ||
7250 | rdev->wowlan->tcp->wake_len + | ||
7251 | rdev->wowlan->tcp->wake_len / 8; | ||
7252 | } | ||
7253 | |||
7254 | msg = nlmsg_new(size, GFP_KERNEL); | ||
6893 | if (!msg) | 7255 | if (!msg) |
6894 | return -ENOMEM; | 7256 | return -ENOMEM; |
6895 | 7257 | ||
@@ -6920,31 +7282,12 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6920 | (rdev->wowlan->rfkill_release && | 7282 | (rdev->wowlan->rfkill_release && |
6921 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | 7283 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
6922 | goto nla_put_failure; | 7284 | goto nla_put_failure; |
6923 | if (rdev->wowlan->n_patterns) { | ||
6924 | struct nlattr *nl_pats, *nl_pat; | ||
6925 | int i, pat_len; | ||
6926 | 7285 | ||
6927 | nl_pats = nla_nest_start(msg, | 7286 | if (nl80211_send_wowlan_patterns(msg, rdev)) |
6928 | NL80211_WOWLAN_TRIG_PKT_PATTERN); | 7287 | goto nla_put_failure; |
6929 | if (!nl_pats) | ||
6930 | goto nla_put_failure; | ||
6931 | 7288 | ||
6932 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | 7289 | if (nl80211_send_wowlan_tcp(msg, rdev->wowlan->tcp)) |
6933 | nl_pat = nla_nest_start(msg, i + 1); | 7290 | goto nla_put_failure; |
6934 | if (!nl_pat) | ||
6935 | goto nla_put_failure; | ||
6936 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
6937 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
6938 | DIV_ROUND_UP(pat_len, 8), | ||
6939 | rdev->wowlan->patterns[i].mask) || | ||
6940 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
6941 | pat_len, | ||
6942 | rdev->wowlan->patterns[i].pattern)) | ||
6943 | goto nla_put_failure; | ||
6944 | nla_nest_end(msg, nl_pat); | ||
6945 | } | ||
6946 | nla_nest_end(msg, nl_pats); | ||
6947 | } | ||
6948 | 7291 | ||
6949 | nla_nest_end(msg, nl_wowlan); | 7292 | nla_nest_end(msg, nl_wowlan); |
6950 | } | 7293 | } |
@@ -6957,6 +7300,150 @@ nla_put_failure: | |||
6957 | return -ENOBUFS; | 7300 | return -ENOBUFS; |
6958 | } | 7301 | } |
6959 | 7302 | ||
7303 | static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | ||
7304 | struct nlattr *attr, | ||
7305 | struct cfg80211_wowlan *trig) | ||
7306 | { | ||
7307 | struct nlattr *tb[NUM_NL80211_WOWLAN_TCP]; | ||
7308 | struct cfg80211_wowlan_tcp *cfg; | ||
7309 | struct nl80211_wowlan_tcp_data_token *tok = NULL; | ||
7310 | struct nl80211_wowlan_tcp_data_seq *seq = NULL; | ||
7311 | u32 size; | ||
7312 | u32 data_size, wake_size, tokens_size = 0, wake_mask_size; | ||
7313 | int err, port; | ||
7314 | |||
7315 | if (!rdev->wiphy.wowlan.tcp) | ||
7316 | return -EINVAL; | ||
7317 | |||
7318 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, | ||
7319 | nla_data(attr), nla_len(attr), | ||
7320 | nl80211_wowlan_tcp_policy); | ||
7321 | if (err) | ||
7322 | return err; | ||
7323 | |||
7324 | if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] || | ||
7325 | !tb[NL80211_WOWLAN_TCP_DST_IPV4] || | ||
7326 | !tb[NL80211_WOWLAN_TCP_DST_MAC] || | ||
7327 | !tb[NL80211_WOWLAN_TCP_DST_PORT] || | ||
7328 | !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] || | ||
7329 | !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] || | ||
7330 | !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] || | ||
7331 | !tb[NL80211_WOWLAN_TCP_WAKE_MASK]) | ||
7332 | return -EINVAL; | ||
7333 | |||
7334 | data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]); | ||
7335 | if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max) | ||
7336 | return -EINVAL; | ||
7337 | |||
7338 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | ||
7339 | rdev->wiphy.wowlan.tcp->data_interval_max) | ||
7340 | return -EINVAL; | ||
7341 | |||
7342 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | ||
7343 | if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max) | ||
7344 | return -EINVAL; | ||
7345 | |||
7346 | wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]); | ||
7347 | if (wake_mask_size != DIV_ROUND_UP(wake_size, 8)) | ||
7348 | return -EINVAL; | ||
7349 | |||
7350 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) { | ||
7351 | u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
7352 | |||
7353 | tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
7354 | tokens_size = tokln - sizeof(*tok); | ||
7355 | |||
7356 | if (!tok->len || tokens_size % tok->len) | ||
7357 | return -EINVAL; | ||
7358 | if (!rdev->wiphy.wowlan.tcp->tok) | ||
7359 | return -EINVAL; | ||
7360 | if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len) | ||
7361 | return -EINVAL; | ||
7362 | if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len) | ||
7363 | return -EINVAL; | ||
7364 | if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize) | ||
7365 | return -EINVAL; | ||
7366 | if (tok->offset + tok->len > data_size) | ||
7367 | return -EINVAL; | ||
7368 | } | ||
7369 | |||
7370 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) { | ||
7371 | seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]); | ||
7372 | if (!rdev->wiphy.wowlan.tcp->seq) | ||
7373 | return -EINVAL; | ||
7374 | if (seq->len == 0 || seq->len > 4) | ||
7375 | return -EINVAL; | ||
7376 | if (seq->len + seq->offset > data_size) | ||
7377 | return -EINVAL; | ||
7378 | } | ||
7379 | |||
7380 | size = sizeof(*cfg); | ||
7381 | size += data_size; | ||
7382 | size += wake_size + wake_mask_size; | ||
7383 | size += tokens_size; | ||
7384 | |||
7385 | cfg = kzalloc(size, GFP_KERNEL); | ||
7386 | if (!cfg) | ||
7387 | return -ENOMEM; | ||
7388 | cfg->src = nla_get_be32(tb[NL80211_WOWLAN_TCP_SRC_IPV4]); | ||
7389 | cfg->dst = nla_get_be32(tb[NL80211_WOWLAN_TCP_DST_IPV4]); | ||
7390 | memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]), | ||
7391 | ETH_ALEN); | ||
7392 | if (tb[NL80211_WOWLAN_TCP_SRC_PORT]) | ||
7393 | port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]); | ||
7394 | else | ||
7395 | port = 0; | ||
7396 | #ifdef CONFIG_INET | ||
7397 | /* allocate a socket and port for it and use it */ | ||
7398 | err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM, | ||
7399 | IPPROTO_TCP, &cfg->sock, 1); | ||
7400 | if (err) { | ||
7401 | kfree(cfg); | ||
7402 | return err; | ||
7403 | } | ||
7404 | if (inet_csk_get_port(cfg->sock->sk, port)) { | ||
7405 | sock_release(cfg->sock); | ||
7406 | kfree(cfg); | ||
7407 | return -EADDRINUSE; | ||
7408 | } | ||
7409 | cfg->src_port = inet_sk(cfg->sock->sk)->inet_num; | ||
7410 | #else | ||
7411 | if (!port) { | ||
7412 | kfree(cfg); | ||
7413 | return -EINVAL; | ||
7414 | } | ||
7415 | cfg->src_port = port; | ||
7416 | #endif | ||
7417 | |||
7418 | cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]); | ||
7419 | cfg->payload_len = data_size; | ||
7420 | cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size; | ||
7421 | memcpy((void *)cfg->payload, | ||
7422 | nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]), | ||
7423 | data_size); | ||
7424 | if (seq) | ||
7425 | cfg->payload_seq = *seq; | ||
7426 | cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]); | ||
7427 | cfg->wake_len = wake_size; | ||
7428 | cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size; | ||
7429 | memcpy((void *)cfg->wake_data, | ||
7430 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]), | ||
7431 | wake_size); | ||
7432 | cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size + | ||
7433 | data_size + wake_size; | ||
7434 | memcpy((void *)cfg->wake_mask, | ||
7435 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]), | ||
7436 | wake_mask_size); | ||
7437 | if (tok) { | ||
7438 | cfg->tokens_size = tokens_size; | ||
7439 | memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size); | ||
7440 | } | ||
7441 | |||
7442 | trig->tcp = cfg; | ||
7443 | |||
7444 | return 0; | ||
7445 | } | ||
7446 | |||
6960 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | 7447 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) |
6961 | { | 7448 | { |
6962 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7449 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6967,7 +7454,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6967 | int err, i; | 7454 | int err, i; |
6968 | bool prev_enabled = rdev->wowlan; | 7455 | bool prev_enabled = rdev->wowlan; |
6969 | 7456 | ||
6970 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7457 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7458 | !rdev->wiphy.wowlan.tcp) | ||
6971 | return -EOPNOTSUPP; | 7459 | return -EOPNOTSUPP; |
6972 | 7460 | ||
6973 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { | 7461 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
@@ -7031,7 +7519,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7031 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 7519 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
7032 | struct nlattr *pat; | 7520 | struct nlattr *pat; |
7033 | int n_patterns = 0; | 7521 | int n_patterns = 0; |
7034 | int rem, pat_len, mask_len; | 7522 | int rem, pat_len, mask_len, pkt_offset; |
7035 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; | 7523 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; |
7036 | 7524 | ||
7037 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 7525 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
@@ -7066,6 +7554,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7066 | pat_len < wowlan->pattern_min_len) | 7554 | pat_len < wowlan->pattern_min_len) |
7067 | goto error; | 7555 | goto error; |
7068 | 7556 | ||
7557 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]) | ||
7558 | pkt_offset = 0; | ||
7559 | else | ||
7560 | pkt_offset = nla_get_u32( | ||
7561 | pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]); | ||
7562 | if (pkt_offset > wowlan->max_pkt_offset) | ||
7563 | goto error; | ||
7564 | new_triggers.patterns[i].pkt_offset = pkt_offset; | ||
7565 | |||
7069 | new_triggers.patterns[i].mask = | 7566 | new_triggers.patterns[i].mask = |
7070 | kmalloc(mask_len + pat_len, GFP_KERNEL); | 7567 | kmalloc(mask_len + pat_len, GFP_KERNEL); |
7071 | if (!new_triggers.patterns[i].mask) { | 7568 | if (!new_triggers.patterns[i].mask) { |
@@ -7085,6 +7582,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7085 | } | 7582 | } |
7086 | } | 7583 | } |
7087 | 7584 | ||
7585 | if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { | ||
7586 | err = nl80211_parse_wowlan_tcp( | ||
7587 | rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], | ||
7588 | &new_triggers); | ||
7589 | if (err) | ||
7590 | goto error; | ||
7591 | } | ||
7592 | |||
7088 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 7593 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
7089 | if (!ntrig) { | 7594 | if (!ntrig) { |
7090 | err = -ENOMEM; | 7595 | err = -ENOMEM; |
@@ -7102,6 +7607,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7102 | for (i = 0; i < new_triggers.n_patterns; i++) | 7607 | for (i = 0; i < new_triggers.n_patterns; i++) |
7103 | kfree(new_triggers.patterns[i].mask); | 7608 | kfree(new_triggers.patterns[i].mask); |
7104 | kfree(new_triggers.patterns); | 7609 | kfree(new_triggers.patterns); |
7610 | if (new_triggers.tcp && new_triggers.tcp->sock) | ||
7611 | sock_release(new_triggers.tcp->sock); | ||
7612 | kfree(new_triggers.tcp); | ||
7105 | return err; | 7613 | return err; |
7106 | } | 7614 | } |
7107 | #endif | 7615 | #endif |
@@ -7992,6 +8500,14 @@ static struct genl_ops nl80211_ops[] = { | |||
7992 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 8500 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
7993 | NL80211_FLAG_NEED_RTNL, | 8501 | NL80211_FLAG_NEED_RTNL, |
7994 | }, | 8502 | }, |
8503 | { | ||
8504 | .cmd = NL80211_CMD_RADAR_DETECT, | ||
8505 | .doit = nl80211_start_radar_detection, | ||
8506 | .policy = nl80211_policy, | ||
8507 | .flags = GENL_ADMIN_PERM, | ||
8508 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
8509 | NL80211_FLAG_NEED_RTNL, | ||
8510 | }, | ||
7995 | }; | 8511 | }; |
7996 | 8512 | ||
7997 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8513 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -9189,6 +9705,57 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9189 | } | 9705 | } |
9190 | 9706 | ||
9191 | void | 9707 | void |
9708 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | ||
9709 | struct cfg80211_chan_def *chandef, | ||
9710 | enum nl80211_radar_event event, | ||
9711 | struct net_device *netdev, gfp_t gfp) | ||
9712 | { | ||
9713 | struct sk_buff *msg; | ||
9714 | void *hdr; | ||
9715 | |||
9716 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
9717 | if (!msg) | ||
9718 | return; | ||
9719 | |||
9720 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT); | ||
9721 | if (!hdr) { | ||
9722 | nlmsg_free(msg); | ||
9723 | return; | ||
9724 | } | ||
9725 | |||
9726 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) | ||
9727 | goto nla_put_failure; | ||
9728 | |||
9729 | /* NOP and radar events don't need a netdev parameter */ | ||
9730 | if (netdev) { | ||
9731 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | ||
9732 | |||
9733 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
9734 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
9735 | goto nla_put_failure; | ||
9736 | } | ||
9737 | |||
9738 | if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event)) | ||
9739 | goto nla_put_failure; | ||
9740 | |||
9741 | if (nl80211_send_chandef(msg, chandef)) | ||
9742 | goto nla_put_failure; | ||
9743 | |||
9744 | if (genlmsg_end(msg, hdr) < 0) { | ||
9745 | nlmsg_free(msg); | ||
9746 | return; | ||
9747 | } | ||
9748 | |||
9749 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
9750 | nl80211_mlme_mcgrp.id, gfp); | ||
9751 | return; | ||
9752 | |||
9753 | nla_put_failure: | ||
9754 | genlmsg_cancel(msg, hdr); | ||
9755 | nlmsg_free(msg); | ||
9756 | } | ||
9757 | |||
9758 | void | ||
9192 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 9759 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
9193 | struct net_device *netdev, const u8 *peer, | 9760 | struct net_device *netdev, const u8 *peer, |
9194 | u32 num_packets, gfp_t gfp) | 9761 | u32 num_packets, gfp_t gfp) |
@@ -9323,6 +9890,114 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, | |||
9323 | } | 9890 | } |
9324 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 9891 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); |
9325 | 9892 | ||
9893 | #ifdef CONFIG_PM | ||
9894 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | ||
9895 | struct cfg80211_wowlan_wakeup *wakeup, | ||
9896 | gfp_t gfp) | ||
9897 | { | ||
9898 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
9899 | struct sk_buff *msg; | ||
9900 | void *hdr; | ||
9901 | int err, size = 200; | ||
9902 | |||
9903 | trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup); | ||
9904 | |||
9905 | if (wakeup) | ||
9906 | size += wakeup->packet_present_len; | ||
9907 | |||
9908 | msg = nlmsg_new(size, gfp); | ||
9909 | if (!msg) | ||
9910 | return; | ||
9911 | |||
9912 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_WOWLAN); | ||
9913 | if (!hdr) | ||
9914 | goto free_msg; | ||
9915 | |||
9916 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
9917 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
9918 | goto free_msg; | ||
9919 | |||
9920 | if (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, | ||
9921 | wdev->netdev->ifindex)) | ||
9922 | goto free_msg; | ||
9923 | |||
9924 | if (wakeup) { | ||
9925 | struct nlattr *reasons; | ||
9926 | |||
9927 | reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); | ||
9928 | |||
9929 | if (wakeup->disconnect && | ||
9930 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) | ||
9931 | goto free_msg; | ||
9932 | if (wakeup->magic_pkt && | ||
9933 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) | ||
9934 | goto free_msg; | ||
9935 | if (wakeup->gtk_rekey_failure && | ||
9936 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) | ||
9937 | goto free_msg; | ||
9938 | if (wakeup->eap_identity_req && | ||
9939 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) | ||
9940 | goto free_msg; | ||
9941 | if (wakeup->four_way_handshake && | ||
9942 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) | ||
9943 | goto free_msg; | ||
9944 | if (wakeup->rfkill_release && | ||
9945 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)) | ||
9946 | goto free_msg; | ||
9947 | |||
9948 | if (wakeup->pattern_idx >= 0 && | ||
9949 | nla_put_u32(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
9950 | wakeup->pattern_idx)) | ||
9951 | goto free_msg; | ||
9952 | |||
9953 | if (wakeup->tcp_match) | ||
9954 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH); | ||
9955 | |||
9956 | if (wakeup->tcp_connlost) | ||
9957 | nla_put_flag(msg, | ||
9958 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST); | ||
9959 | |||
9960 | if (wakeup->tcp_nomoretokens) | ||
9961 | nla_put_flag(msg, | ||
9962 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS); | ||
9963 | |||
9964 | if (wakeup->packet) { | ||
9965 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; | ||
9966 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; | ||
9967 | |||
9968 | if (!wakeup->packet_80211) { | ||
9969 | pkt_attr = | ||
9970 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023; | ||
9971 | len_attr = | ||
9972 | NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN; | ||
9973 | } | ||
9974 | |||
9975 | if (wakeup->packet_len && | ||
9976 | nla_put_u32(msg, len_attr, wakeup->packet_len)) | ||
9977 | goto free_msg; | ||
9978 | |||
9979 | if (nla_put(msg, pkt_attr, wakeup->packet_present_len, | ||
9980 | wakeup->packet)) | ||
9981 | goto free_msg; | ||
9982 | } | ||
9983 | |||
9984 | nla_nest_end(msg, reasons); | ||
9985 | } | ||
9986 | |||
9987 | err = genlmsg_end(msg, hdr); | ||
9988 | if (err < 0) | ||
9989 | goto free_msg; | ||
9990 | |||
9991 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
9992 | nl80211_mlme_mcgrp.id, gfp); | ||
9993 | return; | ||
9994 | |||
9995 | free_msg: | ||
9996 | nlmsg_free(msg); | ||
9997 | } | ||
9998 | EXPORT_SYMBOL(cfg80211_report_wowlan_wakeup); | ||
9999 | #endif | ||
10000 | |||
9326 | void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, | 10001 | void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, |
9327 | enum nl80211_tdls_operation oper, | 10002 | enum nl80211_tdls_operation oper, |
9328 | u16 reason_code, gfp_t gfp) | 10003 | u16 reason_code, gfp_t gfp) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2acba8477e9d..b061da4919e1 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -108,6 +108,13 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
108 | struct net_device *netdev, | 108 | struct net_device *netdev, |
109 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 109 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
110 | gfp_t gfp); | 110 | gfp_t gfp); |
111 | |||
112 | void | ||
113 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | ||
114 | struct cfg80211_chan_def *chandef, | ||
115 | enum nl80211_radar_event event, | ||
116 | struct net_device *netdev, gfp_t gfp); | ||
117 | |||
111 | void | 118 | void |
112 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 119 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
113 | struct net_device *netdev, const u8 *peer, | 120 | struct net_device *netdev, const u8 *peer, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index de02d633c212..98532c00242d 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -866,6 +866,10 @@ static void handle_channel(struct wiphy *wiphy, | |||
866 | 866 | ||
867 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 867 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) |
868 | bw_flags = IEEE80211_CHAN_NO_HT40; | 868 | bw_flags = IEEE80211_CHAN_NO_HT40; |
869 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | ||
870 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
871 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | ||
872 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
869 | 873 | ||
870 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 874 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
871 | request_wiphy && request_wiphy == wiphy && | 875 | request_wiphy && request_wiphy == wiphy && |
@@ -884,6 +888,9 @@ static void handle_channel(struct wiphy *wiphy, | |||
884 | return; | 888 | return; |
885 | } | 889 | } |
886 | 890 | ||
891 | chan->dfs_state = NL80211_DFS_USABLE; | ||
892 | chan->dfs_state_entered = jiffies; | ||
893 | |||
887 | chan->beacon_found = false; | 894 | chan->beacon_found = false; |
888 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); | 895 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
889 | chan->max_antenna_gain = | 896 | chan->max_antenna_gain = |
@@ -1261,6 +1268,10 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1261 | 1268 | ||
1262 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1269 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) |
1263 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1270 | bw_flags = IEEE80211_CHAN_NO_HT40; |
1271 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | ||
1272 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
1273 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | ||
1274 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
1264 | 1275 | ||
1265 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1276 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1266 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1277 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
@@ -2189,10 +2200,15 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2189 | * However if a driver requested this specific regulatory | 2200 | * However if a driver requested this specific regulatory |
2190 | * domain we keep it for its private use | 2201 | * domain we keep it for its private use |
2191 | */ | 2202 | */ |
2192 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) | 2203 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) { |
2204 | const struct ieee80211_regdomain *tmp; | ||
2205 | |||
2206 | tmp = get_wiphy_regdom(request_wiphy); | ||
2193 | rcu_assign_pointer(request_wiphy->regd, rd); | 2207 | rcu_assign_pointer(request_wiphy->regd, rd); |
2194 | else | 2208 | rcu_free_regdom(tmp); |
2209 | } else { | ||
2195 | kfree(rd); | 2210 | kfree(rd); |
2211 | } | ||
2196 | 2212 | ||
2197 | rd = NULL; | 2213 | rd = NULL; |
2198 | 2214 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 45f1618c8e23..674aadca0079 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -19,55 +19,142 @@ | |||
19 | #include "wext-compat.h" | 19 | #include "wext-compat.h" |
20 | #include "rdev-ops.h" | 20 | #include "rdev-ops.h" |
21 | 21 | ||
22 | /** | ||
23 | * DOC: BSS tree/list structure | ||
24 | * | ||
25 | * At the top level, the BSS list is kept in both a list in each | ||
26 | * registered device (@bss_list) as well as an RB-tree for faster | ||
27 | * lookup. In the RB-tree, entries can be looked up using their | ||
28 | * channel, MESHID, MESHCONF (for MBSSes) or channel, BSSID, SSID | ||
29 | * for other BSSes. | ||
30 | * | ||
31 | * Due to the possibility of hidden SSIDs, there's a second level | ||
32 | * structure, the "hidden_list" and "hidden_beacon_bss" pointer. | ||
33 | * The hidden_list connects all BSSes belonging to a single AP | ||
34 | * that has a hidden SSID, and connects beacon and probe response | ||
35 | * entries. For a probe response entry for a hidden SSID, the | ||
36 | * hidden_beacon_bss pointer points to the BSS struct holding the | ||
37 | * beacon's information. | ||
38 | * | ||
39 | * Reference counting is done for all these references except for | ||
40 | * the hidden_list, so that a beacon BSS struct that is otherwise | ||
41 | * not referenced has one reference for being on the bss_list and | ||
42 | * one for each probe response entry that points to it using the | ||
43 | * hidden_beacon_bss pointer. When a BSS struct that has such a | ||
44 | * pointer is get/put, the refcount update is also propagated to | ||
45 | * the referenced struct, this ensure that it cannot get removed | ||
46 | * while somebody is using the probe response version. | ||
47 | * | ||
48 | * Note that the hidden_beacon_bss pointer never changes, due to | ||
49 | * the reference counting. Therefore, no locking is needed for | ||
50 | * it. | ||
51 | * | ||
52 | * Also note that the hidden_beacon_bss pointer is only relevant | ||
53 | * if the driver uses something other than the IEs, e.g. private | ||
54 | * data stored stored in the BSS struct, since the beacon IEs are | ||
55 | * also linked into the probe response struct. | ||
56 | */ | ||
57 | |||
22 | #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) | 58 | #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) |
23 | 59 | ||
24 | static void bss_release(struct kref *ref) | 60 | static void bss_free(struct cfg80211_internal_bss *bss) |
25 | { | 61 | { |
26 | struct cfg80211_bss_ies *ies; | 62 | struct cfg80211_bss_ies *ies; |
27 | struct cfg80211_internal_bss *bss; | ||
28 | |||
29 | bss = container_of(ref, struct cfg80211_internal_bss, ref); | ||
30 | 63 | ||
31 | if (WARN_ON(atomic_read(&bss->hold))) | 64 | if (WARN_ON(atomic_read(&bss->hold))) |
32 | return; | 65 | return; |
33 | 66 | ||
34 | if (bss->pub.free_priv) | ||
35 | bss->pub.free_priv(&bss->pub); | ||
36 | |||
37 | ies = (void *)rcu_access_pointer(bss->pub.beacon_ies); | 67 | ies = (void *)rcu_access_pointer(bss->pub.beacon_ies); |
38 | if (ies) | 68 | if (ies && !bss->pub.hidden_beacon_bss) |
39 | kfree_rcu(ies, rcu_head); | 69 | kfree_rcu(ies, rcu_head); |
40 | ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies); | 70 | ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies); |
41 | if (ies) | 71 | if (ies) |
42 | kfree_rcu(ies, rcu_head); | 72 | kfree_rcu(ies, rcu_head); |
43 | 73 | ||
74 | /* | ||
75 | * This happens when the module is removed, it doesn't | ||
76 | * really matter any more save for completeness | ||
77 | */ | ||
78 | if (!list_empty(&bss->hidden_list)) | ||
79 | list_del(&bss->hidden_list); | ||
80 | |||
44 | kfree(bss); | 81 | kfree(bss); |
45 | } | 82 | } |
46 | 83 | ||
47 | /* must hold dev->bss_lock! */ | 84 | static inline void bss_ref_get(struct cfg80211_registered_device *dev, |
48 | static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, | 85 | struct cfg80211_internal_bss *bss) |
86 | { | ||
87 | lockdep_assert_held(&dev->bss_lock); | ||
88 | |||
89 | bss->refcount++; | ||
90 | if (bss->pub.hidden_beacon_bss) { | ||
91 | bss = container_of(bss->pub.hidden_beacon_bss, | ||
92 | struct cfg80211_internal_bss, | ||
93 | pub); | ||
94 | bss->refcount++; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static inline void bss_ref_put(struct cfg80211_registered_device *dev, | ||
99 | struct cfg80211_internal_bss *bss) | ||
100 | { | ||
101 | lockdep_assert_held(&dev->bss_lock); | ||
102 | |||
103 | if (bss->pub.hidden_beacon_bss) { | ||
104 | struct cfg80211_internal_bss *hbss; | ||
105 | hbss = container_of(bss->pub.hidden_beacon_bss, | ||
106 | struct cfg80211_internal_bss, | ||
107 | pub); | ||
108 | hbss->refcount--; | ||
109 | if (hbss->refcount == 0) | ||
110 | bss_free(hbss); | ||
111 | } | ||
112 | bss->refcount--; | ||
113 | if (bss->refcount == 0) | ||
114 | bss_free(bss); | ||
115 | } | ||
116 | |||
117 | static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, | ||
49 | struct cfg80211_internal_bss *bss) | 118 | struct cfg80211_internal_bss *bss) |
50 | { | 119 | { |
120 | lockdep_assert_held(&dev->bss_lock); | ||
121 | |||
122 | if (!list_empty(&bss->hidden_list)) { | ||
123 | /* | ||
124 | * don't remove the beacon entry if it has | ||
125 | * probe responses associated with it | ||
126 | */ | ||
127 | if (!bss->pub.hidden_beacon_bss) | ||
128 | return false; | ||
129 | /* | ||
130 | * if it's a probe response entry break its | ||
131 | * link to the other entries in the group | ||
132 | */ | ||
133 | list_del_init(&bss->hidden_list); | ||
134 | } | ||
135 | |||
51 | list_del_init(&bss->list); | 136 | list_del_init(&bss->list); |
52 | rb_erase(&bss->rbn, &dev->bss_tree); | 137 | rb_erase(&bss->rbn, &dev->bss_tree); |
53 | kref_put(&bss->ref, bss_release); | 138 | bss_ref_put(dev, bss); |
139 | return true; | ||
54 | } | 140 | } |
55 | 141 | ||
56 | /* must hold dev->bss_lock! */ | ||
57 | static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, | 142 | static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, |
58 | unsigned long expire_time) | 143 | unsigned long expire_time) |
59 | { | 144 | { |
60 | struct cfg80211_internal_bss *bss, *tmp; | 145 | struct cfg80211_internal_bss *bss, *tmp; |
61 | bool expired = false; | 146 | bool expired = false; |
62 | 147 | ||
148 | lockdep_assert_held(&dev->bss_lock); | ||
149 | |||
63 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { | 150 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { |
64 | if (atomic_read(&bss->hold)) | 151 | if (atomic_read(&bss->hold)) |
65 | continue; | 152 | continue; |
66 | if (!time_after(expire_time, bss->ts)) | 153 | if (!time_after(expire_time, bss->ts)) |
67 | continue; | 154 | continue; |
68 | 155 | ||
69 | __cfg80211_unlink_bss(dev, bss); | 156 | if (__cfg80211_unlink_bss(dev, bss)) |
70 | expired = true; | 157 | expired = true; |
71 | } | 158 | } |
72 | 159 | ||
73 | if (expired) | 160 | if (expired) |
@@ -234,15 +321,16 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | |||
234 | return 0; | 321 | return 0; |
235 | } | 322 | } |
236 | 323 | ||
237 | /* must hold dev->bss_lock! */ | ||
238 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | 324 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, |
239 | unsigned long age_secs) | 325 | unsigned long age_secs) |
240 | { | 326 | { |
241 | struct cfg80211_internal_bss *bss; | 327 | struct cfg80211_internal_bss *bss; |
242 | unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); | 328 | unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); |
243 | 329 | ||
330 | spin_lock_bh(&dev->bss_lock); | ||
244 | list_for_each_entry(bss, &dev->bss_list, list) | 331 | list_for_each_entry(bss, &dev->bss_list, list) |
245 | bss->ts -= age_jiffies; | 332 | bss->ts -= age_jiffies; |
333 | spin_unlock_bh(&dev->bss_lock); | ||
246 | } | 334 | } |
247 | 335 | ||
248 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | 336 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) |
@@ -277,40 +365,24 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, | |||
277 | if (!pos) | 365 | if (!pos) |
278 | return NULL; | 366 | return NULL; |
279 | 367 | ||
280 | if (end - pos < sizeof(*ie)) | ||
281 | return NULL; | ||
282 | |||
283 | ie = (struct ieee80211_vendor_ie *)pos; | 368 | ie = (struct ieee80211_vendor_ie *)pos; |
369 | |||
370 | /* make sure we can access ie->len */ | ||
371 | BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1); | ||
372 | |||
373 | if (ie->len < sizeof(*ie)) | ||
374 | goto cont; | ||
375 | |||
284 | ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; | 376 | ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; |
285 | if (ie_oui == oui && ie->oui_type == oui_type) | 377 | if (ie_oui == oui && ie->oui_type == oui_type) |
286 | return pos; | 378 | return pos; |
287 | 379 | cont: | |
288 | pos += 2 + ie->len; | 380 | pos += 2 + ie->len; |
289 | } | 381 | } |
290 | return NULL; | 382 | return NULL; |
291 | } | 383 | } |
292 | EXPORT_SYMBOL(cfg80211_find_vendor_ie); | 384 | EXPORT_SYMBOL(cfg80211_find_vendor_ie); |
293 | 385 | ||
294 | static int cmp_ies(u8 num, const u8 *ies1, int len1, const u8 *ies2, int len2) | ||
295 | { | ||
296 | const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); | ||
297 | const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); | ||
298 | |||
299 | /* equal if both missing */ | ||
300 | if (!ie1 && !ie2) | ||
301 | return 0; | ||
302 | /* sort missing IE before (left of) present IE */ | ||
303 | if (!ie1) | ||
304 | return -1; | ||
305 | if (!ie2) | ||
306 | return 1; | ||
307 | |||
308 | /* sort by length first, then by contents */ | ||
309 | if (ie1[1] != ie2[1]) | ||
310 | return ie2[1] - ie1[1]; | ||
311 | return memcmp(ie1 + 2, ie2 + 2, ie1[1]); | ||
312 | } | ||
313 | |||
314 | static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, | 386 | static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, |
315 | const u8 *ssid, size_t ssid_len) | 387 | const u8 *ssid, size_t ssid_len) |
316 | { | 388 | { |
@@ -334,109 +406,30 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, | |||
334 | return memcmp(ssidie + 2, ssid, ssid_len) == 0; | 406 | return memcmp(ssidie + 2, ssid, ssid_len) == 0; |
335 | } | 407 | } |
336 | 408 | ||
337 | static bool is_mesh_bss(struct cfg80211_bss *a) | 409 | /** |
338 | { | 410 | * enum bss_compare_mode - BSS compare mode |
339 | const struct cfg80211_bss_ies *ies; | 411 | * @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find) |
340 | const u8 *ie; | 412 | * @BSS_CMP_HIDE_ZLEN: find hidden SSID with zero-length mode |
341 | 413 | * @BSS_CMP_HIDE_NUL: find hidden SSID with NUL-ed out mode | |
342 | if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) | 414 | */ |
343 | return false; | 415 | enum bss_compare_mode { |
344 | 416 | BSS_CMP_REGULAR, | |
345 | ies = rcu_access_pointer(a->ies); | 417 | BSS_CMP_HIDE_ZLEN, |
346 | if (!ies) | 418 | BSS_CMP_HIDE_NUL, |
347 | return false; | 419 | }; |
348 | |||
349 | ie = cfg80211_find_ie(WLAN_EID_MESH_ID, ies->data, ies->len); | ||
350 | if (!ie) | ||
351 | return false; | ||
352 | |||
353 | ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, ies->data, ies->len); | ||
354 | if (!ie) | ||
355 | return false; | ||
356 | |||
357 | return true; | ||
358 | } | ||
359 | |||
360 | static bool is_mesh(struct cfg80211_bss *a, | ||
361 | const u8 *meshid, size_t meshidlen, | ||
362 | const u8 *meshcfg) | ||
363 | { | ||
364 | const struct cfg80211_bss_ies *ies; | ||
365 | const u8 *ie; | ||
366 | |||
367 | if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) | ||
368 | return false; | ||
369 | |||
370 | ies = rcu_access_pointer(a->ies); | ||
371 | if (!ies) | ||
372 | return false; | ||
373 | |||
374 | ie = cfg80211_find_ie(WLAN_EID_MESH_ID, ies->data, ies->len); | ||
375 | if (!ie) | ||
376 | return false; | ||
377 | if (ie[1] != meshidlen) | ||
378 | return false; | ||
379 | if (memcmp(ie + 2, meshid, meshidlen)) | ||
380 | return false; | ||
381 | |||
382 | ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, ies->data, ies->len); | ||
383 | if (!ie) | ||
384 | return false; | ||
385 | if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) | ||
386 | return false; | ||
387 | |||
388 | /* | ||
389 | * Ignore mesh capability (last two bytes of the IE) when | ||
390 | * comparing since that may differ between stations taking | ||
391 | * part in the same mesh. | ||
392 | */ | ||
393 | return memcmp(ie + 2, meshcfg, | ||
394 | sizeof(struct ieee80211_meshconf_ie) - 2) == 0; | ||
395 | } | ||
396 | 420 | ||
397 | static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) | 421 | static int cmp_bss(struct cfg80211_bss *a, |
422 | struct cfg80211_bss *b, | ||
423 | enum bss_compare_mode mode) | ||
398 | { | 424 | { |
399 | const struct cfg80211_bss_ies *a_ies, *b_ies; | 425 | const struct cfg80211_bss_ies *a_ies, *b_ies; |
400 | int r; | 426 | const u8 *ie1 = NULL; |
427 | const u8 *ie2 = NULL; | ||
428 | int i, r; | ||
401 | 429 | ||
402 | if (a->channel != b->channel) | 430 | if (a->channel != b->channel) |
403 | return b->channel->center_freq - a->channel->center_freq; | 431 | return b->channel->center_freq - a->channel->center_freq; |
404 | 432 | ||
405 | if (is_mesh_bss(a) && is_mesh_bss(b)) { | ||
406 | a_ies = rcu_access_pointer(a->ies); | ||
407 | if (!a_ies) | ||
408 | return -1; | ||
409 | b_ies = rcu_access_pointer(b->ies); | ||
410 | if (!b_ies) | ||
411 | return 1; | ||
412 | |||
413 | r = cmp_ies(WLAN_EID_MESH_ID, | ||
414 | a_ies->data, a_ies->len, | ||
415 | b_ies->data, b_ies->len); | ||
416 | if (r) | ||
417 | return r; | ||
418 | return cmp_ies(WLAN_EID_MESH_CONFIG, | ||
419 | a_ies->data, a_ies->len, | ||
420 | b_ies->data, b_ies->len); | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * we can't use compare_ether_addr here since we need a < > operator. | ||
425 | * The binary return value of compare_ether_addr isn't enough | ||
426 | */ | ||
427 | return memcmp(a->bssid, b->bssid, sizeof(a->bssid)); | ||
428 | } | ||
429 | |||
430 | static int cmp_bss(struct cfg80211_bss *a, | ||
431 | struct cfg80211_bss *b) | ||
432 | { | ||
433 | const struct cfg80211_bss_ies *a_ies, *b_ies; | ||
434 | int r; | ||
435 | |||
436 | r = cmp_bss_core(a, b); | ||
437 | if (r) | ||
438 | return r; | ||
439 | |||
440 | a_ies = rcu_access_pointer(a->ies); | 433 | a_ies = rcu_access_pointer(a->ies); |
441 | if (!a_ies) | 434 | if (!a_ies) |
442 | return -1; | 435 | return -1; |
@@ -444,42 +437,51 @@ static int cmp_bss(struct cfg80211_bss *a, | |||
444 | if (!b_ies) | 437 | if (!b_ies) |
445 | return 1; | 438 | return 1; |
446 | 439 | ||
447 | return cmp_ies(WLAN_EID_SSID, | 440 | if (WLAN_CAPABILITY_IS_STA_BSS(a->capability)) |
448 | a_ies->data, a_ies->len, | 441 | ie1 = cfg80211_find_ie(WLAN_EID_MESH_ID, |
449 | b_ies->data, b_ies->len); | 442 | a_ies->data, a_ies->len); |
450 | } | 443 | if (WLAN_CAPABILITY_IS_STA_BSS(b->capability)) |
451 | 444 | ie2 = cfg80211_find_ie(WLAN_EID_MESH_ID, | |
452 | static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) | 445 | b_ies->data, b_ies->len); |
453 | { | 446 | if (ie1 && ie2) { |
454 | const struct cfg80211_bss_ies *a_ies, *b_ies; | 447 | int mesh_id_cmp; |
455 | const u8 *ie1; | 448 | |
456 | const u8 *ie2; | 449 | if (ie1[1] == ie2[1]) |
457 | int i; | 450 | mesh_id_cmp = memcmp(ie1 + 2, ie2 + 2, ie1[1]); |
458 | int r; | 451 | else |
452 | mesh_id_cmp = ie2[1] - ie1[1]; | ||
453 | |||
454 | ie1 = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, | ||
455 | a_ies->data, a_ies->len); | ||
456 | ie2 = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, | ||
457 | b_ies->data, b_ies->len); | ||
458 | if (ie1 && ie2) { | ||
459 | if (mesh_id_cmp) | ||
460 | return mesh_id_cmp; | ||
461 | if (ie1[1] != ie2[1]) | ||
462 | return ie2[1] - ie1[1]; | ||
463 | return memcmp(ie1 + 2, ie2 + 2, ie1[1]); | ||
464 | } | ||
465 | } | ||
459 | 466 | ||
460 | r = cmp_bss_core(a, b); | 467 | /* |
468 | * we can't use compare_ether_addr here since we need a < > operator. | ||
469 | * The binary return value of compare_ether_addr isn't enough | ||
470 | */ | ||
471 | r = memcmp(a->bssid, b->bssid, sizeof(a->bssid)); | ||
461 | if (r) | 472 | if (r) |
462 | return r; | 473 | return r; |
463 | 474 | ||
464 | a_ies = rcu_access_pointer(a->ies); | ||
465 | if (!a_ies) | ||
466 | return -1; | ||
467 | b_ies = rcu_access_pointer(b->ies); | ||
468 | if (!b_ies) | ||
469 | return 1; | ||
470 | |||
471 | ie1 = cfg80211_find_ie(WLAN_EID_SSID, a_ies->data, a_ies->len); | 475 | ie1 = cfg80211_find_ie(WLAN_EID_SSID, a_ies->data, a_ies->len); |
472 | ie2 = cfg80211_find_ie(WLAN_EID_SSID, b_ies->data, b_ies->len); | 476 | ie2 = cfg80211_find_ie(WLAN_EID_SSID, b_ies->data, b_ies->len); |
473 | 477 | ||
478 | if (!ie1 && !ie2) | ||
479 | return 0; | ||
480 | |||
474 | /* | 481 | /* |
475 | * Key comparator must use same algorithm in any rb-tree | 482 | * Note that with "hide_ssid", the function returns a match if |
476 | * search function (order is important), otherwise ordering | 483 | * the already-present BSS ("b") is a hidden SSID beacon for |
477 | * of items in the tree is broken and search gives incorrect | 484 | * the new BSS ("a"). |
478 | * results. This code uses same order as cmp_ies() does. | ||
479 | * | ||
480 | * Note that due to the differring behaviour with hidden SSIDs | ||
481 | * this function only works when "b" is the tree element and | ||
482 | * "a" is the key we're looking for. | ||
483 | */ | 485 | */ |
484 | 486 | ||
485 | /* sort missing IE before (left of) present IE */ | 487 | /* sort missing IE before (left of) present IE */ |
@@ -488,24 +490,36 @@ static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) | |||
488 | if (!ie2) | 490 | if (!ie2) |
489 | return 1; | 491 | return 1; |
490 | 492 | ||
491 | /* zero-size SSID is used as an indication of the hidden bss */ | 493 | switch (mode) { |
492 | if (!ie2[1]) | 494 | case BSS_CMP_HIDE_ZLEN: |
495 | /* | ||
496 | * In ZLEN mode we assume the BSS entry we're | ||
497 | * looking for has a zero-length SSID. So if | ||
498 | * the one we're looking at right now has that, | ||
499 | * return 0. Otherwise, return the difference | ||
500 | * in length, but since we're looking for the | ||
501 | * 0-length it's really equivalent to returning | ||
502 | * the length of the one we're looking at. | ||
503 | * | ||
504 | * No content comparison is needed as we assume | ||
505 | * the content length is zero. | ||
506 | */ | ||
507 | return ie2[1]; | ||
508 | case BSS_CMP_REGULAR: | ||
509 | default: | ||
510 | /* sort by length first, then by contents */ | ||
511 | if (ie1[1] != ie2[1]) | ||
512 | return ie2[1] - ie1[1]; | ||
513 | return memcmp(ie1 + 2, ie2 + 2, ie1[1]); | ||
514 | case BSS_CMP_HIDE_NUL: | ||
515 | if (ie1[1] != ie2[1]) | ||
516 | return ie2[1] - ie1[1]; | ||
517 | /* this is equivalent to memcmp(zeroes, ie2 + 2, len) */ | ||
518 | for (i = 0; i < ie2[1]; i++) | ||
519 | if (ie2[i + 2]) | ||
520 | return -1; | ||
493 | return 0; | 521 | return 0; |
494 | 522 | } | |
495 | /* sort by length first, then by contents */ | ||
496 | if (ie1[1] != ie2[1]) | ||
497 | return ie2[1] - ie1[1]; | ||
498 | |||
499 | /* | ||
500 | * zeroed SSID ie is another indication of a hidden bss; | ||
501 | * if it isn't zeroed just return the regular sort value | ||
502 | * to find the next candidate | ||
503 | */ | ||
504 | for (i = 0; i < ie2[1]; i++) | ||
505 | if (ie2[i + 2]) | ||
506 | return memcmp(ie1 + 2, ie2 + 2, ie1[1]); | ||
507 | |||
508 | return 0; | ||
509 | } | 523 | } |
510 | 524 | ||
511 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | 525 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, |
@@ -534,7 +548,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | |||
534 | continue; | 548 | continue; |
535 | if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { | 549 | if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { |
536 | res = bss; | 550 | res = bss; |
537 | kref_get(&res->ref); | 551 | bss_ref_get(dev, res); |
538 | break; | 552 | break; |
539 | } | 553 | } |
540 | } | 554 | } |
@@ -547,34 +561,6 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | |||
547 | } | 561 | } |
548 | EXPORT_SYMBOL(cfg80211_get_bss); | 562 | EXPORT_SYMBOL(cfg80211_get_bss); |
549 | 563 | ||
550 | struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, | ||
551 | struct ieee80211_channel *channel, | ||
552 | const u8 *meshid, size_t meshidlen, | ||
553 | const u8 *meshcfg) | ||
554 | { | ||
555 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | ||
556 | struct cfg80211_internal_bss *bss, *res = NULL; | ||
557 | |||
558 | spin_lock_bh(&dev->bss_lock); | ||
559 | |||
560 | list_for_each_entry(bss, &dev->bss_list, list) { | ||
561 | if (channel && bss->pub.channel != channel) | ||
562 | continue; | ||
563 | if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) { | ||
564 | res = bss; | ||
565 | kref_get(&res->ref); | ||
566 | break; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | spin_unlock_bh(&dev->bss_lock); | ||
571 | if (!res) | ||
572 | return NULL; | ||
573 | return &res->pub; | ||
574 | } | ||
575 | EXPORT_SYMBOL(cfg80211_get_mesh); | ||
576 | |||
577 | |||
578 | static void rb_insert_bss(struct cfg80211_registered_device *dev, | 564 | static void rb_insert_bss(struct cfg80211_registered_device *dev, |
579 | struct cfg80211_internal_bss *bss) | 565 | struct cfg80211_internal_bss *bss) |
580 | { | 566 | { |
@@ -587,7 +573,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev, | |||
587 | parent = *p; | 573 | parent = *p; |
588 | tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn); | 574 | tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn); |
589 | 575 | ||
590 | cmp = cmp_bss(&bss->pub, &tbss->pub); | 576 | cmp = cmp_bss(&bss->pub, &tbss->pub, BSS_CMP_REGULAR); |
591 | 577 | ||
592 | if (WARN_ON(!cmp)) { | 578 | if (WARN_ON(!cmp)) { |
593 | /* will sort of leak this BSS */ | 579 | /* will sort of leak this BSS */ |
@@ -606,7 +592,8 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev, | |||
606 | 592 | ||
607 | static struct cfg80211_internal_bss * | 593 | static struct cfg80211_internal_bss * |
608 | rb_find_bss(struct cfg80211_registered_device *dev, | 594 | rb_find_bss(struct cfg80211_registered_device *dev, |
609 | struct cfg80211_internal_bss *res) | 595 | struct cfg80211_internal_bss *res, |
596 | enum bss_compare_mode mode) | ||
610 | { | 597 | { |
611 | struct rb_node *n = dev->bss_tree.rb_node; | 598 | struct rb_node *n = dev->bss_tree.rb_node; |
612 | struct cfg80211_internal_bss *bss; | 599 | struct cfg80211_internal_bss *bss; |
@@ -614,7 +601,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, | |||
614 | 601 | ||
615 | while (n) { | 602 | while (n) { |
616 | bss = rb_entry(n, struct cfg80211_internal_bss, rbn); | 603 | bss = rb_entry(n, struct cfg80211_internal_bss, rbn); |
617 | r = cmp_bss(&res->pub, &bss->pub); | 604 | r = cmp_bss(&res->pub, &bss->pub, mode); |
618 | 605 | ||
619 | if (r == 0) | 606 | if (r == 0) |
620 | return bss; | 607 | return bss; |
@@ -627,46 +614,67 @@ rb_find_bss(struct cfg80211_registered_device *dev, | |||
627 | return NULL; | 614 | return NULL; |
628 | } | 615 | } |
629 | 616 | ||
630 | static struct cfg80211_internal_bss * | 617 | static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, |
631 | rb_find_hidden_bss(struct cfg80211_registered_device *dev, | 618 | struct cfg80211_internal_bss *new) |
632 | struct cfg80211_internal_bss *res) | ||
633 | { | 619 | { |
634 | struct rb_node *n = dev->bss_tree.rb_node; | 620 | const struct cfg80211_bss_ies *ies; |
635 | struct cfg80211_internal_bss *bss; | 621 | struct cfg80211_internal_bss *bss; |
636 | int r; | 622 | const u8 *ie; |
623 | int i, ssidlen; | ||
624 | u8 fold = 0; | ||
637 | 625 | ||
638 | while (n) { | 626 | ies = rcu_access_pointer(new->pub.beacon_ies); |
639 | bss = rb_entry(n, struct cfg80211_internal_bss, rbn); | 627 | if (WARN_ON(!ies)) |
640 | r = cmp_hidden_bss(&res->pub, &bss->pub); | 628 | return false; |
641 | 629 | ||
642 | if (r == 0) | 630 | ie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); |
643 | return bss; | 631 | if (!ie) { |
644 | else if (r < 0) | 632 | /* nothing to do */ |
645 | n = n->rb_left; | 633 | return true; |
646 | else | ||
647 | n = n->rb_right; | ||
648 | } | 634 | } |
649 | 635 | ||
650 | return NULL; | 636 | ssidlen = ie[1]; |
651 | } | 637 | for (i = 0; i < ssidlen; i++) |
638 | fold |= ie[2 + i]; | ||
652 | 639 | ||
653 | static void | 640 | if (fold) { |
654 | copy_hidden_ies(struct cfg80211_internal_bss *res, | 641 | /* not a hidden SSID */ |
655 | struct cfg80211_internal_bss *hidden) | 642 | return true; |
656 | { | 643 | } |
657 | const struct cfg80211_bss_ies *ies; | ||
658 | 644 | ||
659 | if (rcu_access_pointer(res->pub.beacon_ies)) | 645 | /* This is the bad part ... */ |
660 | return; | ||
661 | 646 | ||
662 | ies = rcu_access_pointer(hidden->pub.beacon_ies); | 647 | list_for_each_entry(bss, &dev->bss_list, list) { |
663 | if (WARN_ON(!ies)) | 648 | if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid)) |
664 | return; | 649 | continue; |
650 | if (bss->pub.channel != new->pub.channel) | ||
651 | continue; | ||
652 | if (rcu_access_pointer(bss->pub.beacon_ies)) | ||
653 | continue; | ||
654 | ies = rcu_access_pointer(bss->pub.ies); | ||
655 | if (!ies) | ||
656 | continue; | ||
657 | ie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); | ||
658 | if (!ie) | ||
659 | continue; | ||
660 | if (ssidlen && ie[1] != ssidlen) | ||
661 | continue; | ||
662 | /* that would be odd ... */ | ||
663 | if (bss->pub.beacon_ies) | ||
664 | continue; | ||
665 | if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss)) | ||
666 | continue; | ||
667 | if (WARN_ON_ONCE(!list_empty(&bss->hidden_list))) | ||
668 | list_del(&bss->hidden_list); | ||
669 | /* combine them */ | ||
670 | list_add(&bss->hidden_list, &new->hidden_list); | ||
671 | bss->pub.hidden_beacon_bss = &new->pub; | ||
672 | new->refcount += bss->refcount; | ||
673 | rcu_assign_pointer(bss->pub.beacon_ies, | ||
674 | new->pub.beacon_ies); | ||
675 | } | ||
665 | 676 | ||
666 | ies = kmemdup(ies, sizeof(*ies) + ies->len, GFP_ATOMIC); | 677 | return true; |
667 | if (unlikely(!ies)) | ||
668 | return; | ||
669 | rcu_assign_pointer(res->pub.beacon_ies, ies); | ||
670 | } | 678 | } |
671 | 679 | ||
672 | static struct cfg80211_internal_bss * | 680 | static struct cfg80211_internal_bss * |
@@ -687,11 +695,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
687 | return NULL; | 695 | return NULL; |
688 | } | 696 | } |
689 | 697 | ||
690 | found = rb_find_bss(dev, tmp); | 698 | found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR); |
691 | 699 | ||
692 | if (found) { | 700 | if (found) { |
693 | found->pub.beacon_interval = tmp->pub.beacon_interval; | 701 | found->pub.beacon_interval = tmp->pub.beacon_interval; |
694 | found->pub.tsf = tmp->pub.tsf; | ||
695 | found->pub.signal = tmp->pub.signal; | 702 | found->pub.signal = tmp->pub.signal; |
696 | found->pub.capability = tmp->pub.capability; | 703 | found->pub.capability = tmp->pub.capability; |
697 | found->ts = tmp->ts; | 704 | found->ts = tmp->ts; |
@@ -711,19 +718,45 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
711 | kfree_rcu((struct cfg80211_bss_ies *)old, | 718 | kfree_rcu((struct cfg80211_bss_ies *)old, |
712 | rcu_head); | 719 | rcu_head); |
713 | } else if (rcu_access_pointer(tmp->pub.beacon_ies)) { | 720 | } else if (rcu_access_pointer(tmp->pub.beacon_ies)) { |
714 | const struct cfg80211_bss_ies *old, *ies; | 721 | const struct cfg80211_bss_ies *old; |
722 | struct cfg80211_internal_bss *bss; | ||
723 | |||
724 | if (found->pub.hidden_beacon_bss && | ||
725 | !list_empty(&found->hidden_list)) { | ||
726 | /* | ||
727 | * The found BSS struct is one of the probe | ||
728 | * response members of a group, but we're | ||
729 | * receiving a beacon (beacon_ies in the tmp | ||
730 | * bss is used). This can only mean that the | ||
731 | * AP changed its beacon from not having an | ||
732 | * SSID to showing it, which is confusing so | ||
733 | * drop this information. | ||
734 | */ | ||
735 | goto drop; | ||
736 | } | ||
715 | 737 | ||
716 | old = rcu_access_pointer(found->pub.beacon_ies); | 738 | old = rcu_access_pointer(found->pub.beacon_ies); |
717 | ies = rcu_access_pointer(found->pub.ies); | ||
718 | 739 | ||
719 | rcu_assign_pointer(found->pub.beacon_ies, | 740 | rcu_assign_pointer(found->pub.beacon_ies, |
720 | tmp->pub.beacon_ies); | 741 | tmp->pub.beacon_ies); |
721 | 742 | ||
722 | /* Override IEs if they were from a beacon before */ | 743 | /* Override IEs if they were from a beacon before */ |
723 | if (old == ies) | 744 | if (old == rcu_access_pointer(found->pub.ies)) |
724 | rcu_assign_pointer(found->pub.ies, | 745 | rcu_assign_pointer(found->pub.ies, |
725 | tmp->pub.beacon_ies); | 746 | tmp->pub.beacon_ies); |
726 | 747 | ||
748 | /* Assign beacon IEs to all sub entries */ | ||
749 | list_for_each_entry(bss, &found->hidden_list, | ||
750 | hidden_list) { | ||
751 | const struct cfg80211_bss_ies *ies; | ||
752 | |||
753 | ies = rcu_access_pointer(bss->pub.beacon_ies); | ||
754 | WARN_ON(ies != old); | ||
755 | |||
756 | rcu_assign_pointer(bss->pub.beacon_ies, | ||
757 | tmp->pub.beacon_ies); | ||
758 | } | ||
759 | |||
727 | if (old) | 760 | if (old) |
728 | kfree_rcu((struct cfg80211_bss_ies *)old, | 761 | kfree_rcu((struct cfg80211_bss_ies *)old, |
729 | rcu_head); | 762 | rcu_head); |
@@ -733,19 +766,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
733 | struct cfg80211_internal_bss *hidden; | 766 | struct cfg80211_internal_bss *hidden; |
734 | struct cfg80211_bss_ies *ies; | 767 | struct cfg80211_bss_ies *ies; |
735 | 768 | ||
736 | /* First check if the beacon is a probe response from | ||
737 | * a hidden bss. If so, copy beacon ies (with nullified | ||
738 | * ssid) into the probe response bss entry (with real ssid). | ||
739 | * It is required basically for PSM implementation | ||
740 | * (probe responses do not contain tim ie) */ | ||
741 | |||
742 | /* TODO: The code is not trying to update existing probe | ||
743 | * response bss entries when beacon ies are | ||
744 | * getting changed. */ | ||
745 | hidden = rb_find_hidden_bss(dev, tmp); | ||
746 | if (hidden) | ||
747 | copy_hidden_ies(tmp, hidden); | ||
748 | |||
749 | /* | 769 | /* |
750 | * create a copy -- the "res" variable that is passed in | 770 | * create a copy -- the "res" variable that is passed in |
751 | * is allocated on the stack since it's not needed in the | 771 | * is allocated on the stack since it's not needed in the |
@@ -760,21 +780,51 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
760 | ies = (void *)rcu_dereference(tmp->pub.proberesp_ies); | 780 | ies = (void *)rcu_dereference(tmp->pub.proberesp_ies); |
761 | if (ies) | 781 | if (ies) |
762 | kfree_rcu(ies, rcu_head); | 782 | kfree_rcu(ies, rcu_head); |
763 | spin_unlock_bh(&dev->bss_lock); | 783 | goto drop; |
764 | return NULL; | ||
765 | } | 784 | } |
766 | memcpy(new, tmp, sizeof(*new)); | 785 | memcpy(new, tmp, sizeof(*new)); |
767 | kref_init(&new->ref); | 786 | new->refcount = 1; |
787 | INIT_LIST_HEAD(&new->hidden_list); | ||
788 | |||
789 | if (rcu_access_pointer(tmp->pub.proberesp_ies)) { | ||
790 | hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN); | ||
791 | if (!hidden) | ||
792 | hidden = rb_find_bss(dev, tmp, | ||
793 | BSS_CMP_HIDE_NUL); | ||
794 | if (hidden) { | ||
795 | new->pub.hidden_beacon_bss = &hidden->pub; | ||
796 | list_add(&new->hidden_list, | ||
797 | &hidden->hidden_list); | ||
798 | hidden->refcount++; | ||
799 | rcu_assign_pointer(new->pub.beacon_ies, | ||
800 | hidden->pub.beacon_ies); | ||
801 | } | ||
802 | } else { | ||
803 | /* | ||
804 | * Ok so we found a beacon, and don't have an entry. If | ||
805 | * it's a beacon with hidden SSID, we might be in for an | ||
806 | * expensive search for any probe responses that should | ||
807 | * be grouped with this beacon for updates ... | ||
808 | */ | ||
809 | if (!cfg80211_combine_bsses(dev, new)) { | ||
810 | kfree(new); | ||
811 | goto drop; | ||
812 | } | ||
813 | } | ||
814 | |||
768 | list_add_tail(&new->list, &dev->bss_list); | 815 | list_add_tail(&new->list, &dev->bss_list); |
769 | rb_insert_bss(dev, new); | 816 | rb_insert_bss(dev, new); |
770 | found = new; | 817 | found = new; |
771 | } | 818 | } |
772 | 819 | ||
773 | dev->bss_generation++; | 820 | dev->bss_generation++; |
821 | bss_ref_get(dev, found); | ||
774 | spin_unlock_bh(&dev->bss_lock); | 822 | spin_unlock_bh(&dev->bss_lock); |
775 | 823 | ||
776 | kref_get(&found->ref); | ||
777 | return found; | 824 | return found; |
825 | drop: | ||
826 | spin_unlock_bh(&dev->bss_lock); | ||
827 | return NULL; | ||
778 | } | 828 | } |
779 | 829 | ||
780 | static struct ieee80211_channel * | 830 | static struct ieee80211_channel * |
@@ -833,7 +883,6 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
833 | memcpy(tmp.pub.bssid, bssid, ETH_ALEN); | 883 | memcpy(tmp.pub.bssid, bssid, ETH_ALEN); |
834 | tmp.pub.channel = channel; | 884 | tmp.pub.channel = channel; |
835 | tmp.pub.signal = signal; | 885 | tmp.pub.signal = signal; |
836 | tmp.pub.tsf = tsf; | ||
837 | tmp.pub.beacon_interval = beacon_interval; | 886 | tmp.pub.beacon_interval = beacon_interval; |
838 | tmp.pub.capability = capability; | 887 | tmp.pub.capability = capability; |
839 | /* | 888 | /* |
@@ -841,16 +890,14 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
841 | * Response frame, we need to pick one of the options and only use it | 890 | * Response frame, we need to pick one of the options and only use it |
842 | * with the driver that does not provide the full Beacon/Probe Response | 891 | * with the driver that does not provide the full Beacon/Probe Response |
843 | * frame. Use Beacon frame pointer to avoid indicating that this should | 892 | * frame. Use Beacon frame pointer to avoid indicating that this should |
844 | * override the iies pointer should we have received an earlier | 893 | * override the IEs pointer should we have received an earlier |
845 | * indication of Probe Response data. | 894 | * indication of Probe Response data. |
846 | * | ||
847 | * The initial buffer for the IEs is allocated with the BSS entry and | ||
848 | * is located after the private area. | ||
849 | */ | 895 | */ |
850 | ies = kmalloc(sizeof(*ies) + ielen, gfp); | 896 | ies = kmalloc(sizeof(*ies) + ielen, gfp); |
851 | if (!ies) | 897 | if (!ies) |
852 | return NULL; | 898 | return NULL; |
853 | ies->len = ielen; | 899 | ies->len = ielen; |
900 | ies->tsf = tsf; | ||
854 | memcpy(ies->data, ie, ielen); | 901 | memcpy(ies->data, ie, ielen); |
855 | 902 | ||
856 | rcu_assign_pointer(tmp.pub.beacon_ies, ies); | 903 | rcu_assign_pointer(tmp.pub.beacon_ies, ies); |
@@ -907,6 +954,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
907 | if (!ies) | 954 | if (!ies) |
908 | return NULL; | 955 | return NULL; |
909 | ies->len = ielen; | 956 | ies->len = ielen; |
957 | ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | ||
910 | memcpy(ies->data, mgmt->u.probe_resp.variable, ielen); | 958 | memcpy(ies->data, mgmt->u.probe_resp.variable, ielen); |
911 | 959 | ||
912 | if (ieee80211_is_probe_resp(mgmt->frame_control)) | 960 | if (ieee80211_is_probe_resp(mgmt->frame_control)) |
@@ -918,7 +966,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
918 | memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); | 966 | memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); |
919 | tmp.pub.channel = channel; | 967 | tmp.pub.channel = channel; |
920 | tmp.pub.signal = signal; | 968 | tmp.pub.signal = signal; |
921 | tmp.pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | ||
922 | tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | 969 | tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
923 | tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); | 970 | tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
924 | 971 | ||
@@ -935,27 +982,35 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
935 | } | 982 | } |
936 | EXPORT_SYMBOL(cfg80211_inform_bss_frame); | 983 | EXPORT_SYMBOL(cfg80211_inform_bss_frame); |
937 | 984 | ||
938 | void cfg80211_ref_bss(struct cfg80211_bss *pub) | 985 | void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) |
939 | { | 986 | { |
987 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | ||
940 | struct cfg80211_internal_bss *bss; | 988 | struct cfg80211_internal_bss *bss; |
941 | 989 | ||
942 | if (!pub) | 990 | if (!pub) |
943 | return; | 991 | return; |
944 | 992 | ||
945 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | 993 | bss = container_of(pub, struct cfg80211_internal_bss, pub); |
946 | kref_get(&bss->ref); | 994 | |
995 | spin_lock_bh(&dev->bss_lock); | ||
996 | bss_ref_get(dev, bss); | ||
997 | spin_unlock_bh(&dev->bss_lock); | ||
947 | } | 998 | } |
948 | EXPORT_SYMBOL(cfg80211_ref_bss); | 999 | EXPORT_SYMBOL(cfg80211_ref_bss); |
949 | 1000 | ||
950 | void cfg80211_put_bss(struct cfg80211_bss *pub) | 1001 | void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) |
951 | { | 1002 | { |
1003 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | ||
952 | struct cfg80211_internal_bss *bss; | 1004 | struct cfg80211_internal_bss *bss; |
953 | 1005 | ||
954 | if (!pub) | 1006 | if (!pub) |
955 | return; | 1007 | return; |
956 | 1008 | ||
957 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | 1009 | bss = container_of(pub, struct cfg80211_internal_bss, pub); |
958 | kref_put(&bss->ref, bss_release); | 1010 | |
1011 | spin_lock_bh(&dev->bss_lock); | ||
1012 | bss_ref_put(dev, bss); | ||
1013 | spin_unlock_bh(&dev->bss_lock); | ||
959 | } | 1014 | } |
960 | EXPORT_SYMBOL(cfg80211_put_bss); | 1015 | EXPORT_SYMBOL(cfg80211_put_bss); |
961 | 1016 | ||
@@ -971,8 +1026,8 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
971 | 1026 | ||
972 | spin_lock_bh(&dev->bss_lock); | 1027 | spin_lock_bh(&dev->bss_lock); |
973 | if (!list_empty(&bss->list)) { | 1028 | if (!list_empty(&bss->list)) { |
974 | __cfg80211_unlink_bss(dev, bss); | 1029 | if (__cfg80211_unlink_bss(dev, bss)) |
975 | dev->bss_generation++; | 1030 | dev->bss_generation++; |
976 | } | 1031 | } |
977 | spin_unlock_bh(&dev->bss_lock); | 1032 | spin_unlock_bh(&dev->bss_lock); |
978 | } | 1033 | } |
@@ -1155,16 +1210,6 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, | |||
1155 | } | 1210 | } |
1156 | } | 1211 | } |
1157 | 1212 | ||
1158 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
1159 | { | ||
1160 | unsigned long end = jiffies; | ||
1161 | |||
1162 | if (end >= start) | ||
1163 | return jiffies_to_msecs(end - start); | ||
1164 | |||
1165 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
1166 | } | ||
1167 | |||
1168 | static char * | 1213 | static char * |
1169 | ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | 1214 | ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, |
1170 | struct cfg80211_internal_bss *bss, char *current_ev, | 1215 | struct cfg80211_internal_bss *bss, char *current_ev, |
@@ -1241,15 +1286,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1241 | 1286 | ||
1242 | rcu_read_lock(); | 1287 | rcu_read_lock(); |
1243 | ies = rcu_dereference(bss->pub.ies); | 1288 | ies = rcu_dereference(bss->pub.ies); |
1244 | if (ies) { | 1289 | rem = ies->len; |
1245 | rem = ies->len; | 1290 | ie = ies->data; |
1246 | ie = ies->data; | ||
1247 | } else { | ||
1248 | rem = 0; | ||
1249 | ie = NULL; | ||
1250 | } | ||
1251 | 1291 | ||
1252 | while (ies && rem >= 2) { | 1292 | while (rem >= 2) { |
1253 | /* invalid data */ | 1293 | /* invalid data */ |
1254 | if (ie[1] > rem - 2) | 1294 | if (ie[1] > rem - 2) |
1255 | break; | 1295 | break; |
@@ -1362,7 +1402,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1362 | if (buf) { | 1402 | if (buf) { |
1363 | memset(&iwe, 0, sizeof(iwe)); | 1403 | memset(&iwe, 0, sizeof(iwe)); |
1364 | iwe.cmd = IWEVCUSTOM; | 1404 | iwe.cmd = IWEVCUSTOM; |
1365 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf)); | 1405 | sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf)); |
1366 | iwe.u.data.length = strlen(buf); | 1406 | iwe.u.data.length = strlen(buf); |
1367 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | 1407 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, |
1368 | &iwe, buf); | 1408 | &iwe, buf); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a825dfe12cf7..f432bd3755b1 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -301,7 +301,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
301 | 301 | ||
302 | bss = cfg80211_get_conn_bss(wdev); | 302 | bss = cfg80211_get_conn_bss(wdev); |
303 | if (bss) { | 303 | if (bss) { |
304 | cfg80211_put_bss(bss); | 304 | cfg80211_put_bss(&rdev->wiphy, bss); |
305 | } else { | 305 | } else { |
306 | /* not found */ | 306 | /* not found */ |
307 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) | 307 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) |
@@ -464,7 +464,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
464 | 464 | ||
465 | if (wdev->current_bss) { | 465 | if (wdev->current_bss) { |
466 | cfg80211_unhold_bss(wdev->current_bss); | 466 | cfg80211_unhold_bss(wdev->current_bss); |
467 | cfg80211_put_bss(&wdev->current_bss->pub); | 467 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
468 | wdev->current_bss = NULL; | 468 | wdev->current_bss = NULL; |
469 | } | 469 | } |
470 | 470 | ||
@@ -480,7 +480,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
480 | kfree(wdev->connect_keys); | 480 | kfree(wdev->connect_keys); |
481 | wdev->connect_keys = NULL; | 481 | wdev->connect_keys = NULL; |
482 | wdev->ssid_len = 0; | 482 | wdev->ssid_len = 0; |
483 | cfg80211_put_bss(bss); | 483 | cfg80211_put_bss(wdev->wiphy, bss); |
484 | return; | 484 | return; |
485 | } | 485 | } |
486 | 486 | ||
@@ -586,7 +586,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, | |||
586 | } | 586 | } |
587 | 587 | ||
588 | cfg80211_unhold_bss(wdev->current_bss); | 588 | cfg80211_unhold_bss(wdev->current_bss); |
589 | cfg80211_put_bss(&wdev->current_bss->pub); | 589 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
590 | wdev->current_bss = NULL; | 590 | wdev->current_bss = NULL; |
591 | 591 | ||
592 | cfg80211_hold_bss(bss_from_pub(bss)); | 592 | cfg80211_hold_bss(bss_from_pub(bss)); |
@@ -621,7 +621,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, | |||
621 | 621 | ||
622 | return; | 622 | return; |
623 | out: | 623 | out: |
624 | cfg80211_put_bss(bss); | 624 | cfg80211_put_bss(wdev->wiphy, bss); |
625 | } | 625 | } |
626 | 626 | ||
627 | void cfg80211_roamed(struct net_device *dev, | 627 | void cfg80211_roamed(struct net_device *dev, |
@@ -663,7 +663,7 @@ void cfg80211_roamed_bss(struct net_device *dev, | |||
663 | 663 | ||
664 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | 664 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); |
665 | if (!ev) { | 665 | if (!ev) { |
666 | cfg80211_put_bss(bss); | 666 | cfg80211_put_bss(wdev->wiphy, bss); |
667 | return; | 667 | return; |
668 | } | 668 | } |
669 | 669 | ||
@@ -704,7 +704,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
704 | 704 | ||
705 | if (wdev->current_bss) { | 705 | if (wdev->current_bss) { |
706 | cfg80211_unhold_bss(wdev->current_bss); | 706 | cfg80211_unhold_bss(wdev->current_bss); |
707 | cfg80211_put_bss(&wdev->current_bss->pub); | 707 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
708 | } | 708 | } |
709 | 709 | ||
710 | wdev->current_bss = NULL; | 710 | wdev->current_bss = NULL; |
@@ -875,7 +875,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
875 | if (bss) { | 875 | if (bss) { |
876 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 876 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
877 | err = cfg80211_conn_do_work(wdev); | 877 | err = cfg80211_conn_do_work(wdev); |
878 | cfg80211_put_bss(bss); | 878 | cfg80211_put_bss(wdev->wiphy, bss); |
879 | } else { | 879 | } else { |
880 | /* otherwise we'll need to scan for the AP first */ | 880 | /* otherwise we'll need to scan for the AP first */ |
881 | err = cfg80211_conn_scan(wdev); | 881 | err = cfg80211_conn_scan(wdev); |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 1f6f01e2dc4c..238ee49b3868 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -106,9 +106,7 @@ static int wiphy_resume(struct device *dev) | |||
106 | int ret = 0; | 106 | int ret = 0; |
107 | 107 | ||
108 | /* Age scan results with time spent in suspend */ | 108 | /* Age scan results with time spent in suspend */ |
109 | spin_lock_bh(&rdev->bss_lock); | ||
110 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); | 109 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); |
111 | spin_unlock_bh(&rdev->bss_lock); | ||
112 | 110 | ||
113 | if (rdev->ops->resume) { | 111 | if (rdev->ops->resume) { |
114 | rtnl_lock(); | 112 | rtnl_lock(); |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 8bc553199686..b7a531380e19 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2051,6 +2051,21 @@ TRACE_EVENT(cfg80211_reg_can_beacon, | |||
2051 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | 2051 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
2052 | ); | 2052 | ); |
2053 | 2053 | ||
2054 | TRACE_EVENT(cfg80211_chandef_dfs_required, | ||
2055 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), | ||
2056 | TP_ARGS(wiphy, chandef), | ||
2057 | TP_STRUCT__entry( | ||
2058 | WIPHY_ENTRY | ||
2059 | CHAN_DEF_ENTRY | ||
2060 | ), | ||
2061 | TP_fast_assign( | ||
2062 | WIPHY_ASSIGN; | ||
2063 | CHAN_DEF_ASSIGN(chandef); | ||
2064 | ), | ||
2065 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
2066 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | ||
2067 | ); | ||
2068 | |||
2054 | TRACE_EVENT(cfg80211_ch_switch_notify, | 2069 | TRACE_EVENT(cfg80211_ch_switch_notify, |
2055 | TP_PROTO(struct net_device *netdev, | 2070 | TP_PROTO(struct net_device *netdev, |
2056 | struct cfg80211_chan_def *chandef), | 2071 | struct cfg80211_chan_def *chandef), |
@@ -2067,6 +2082,36 @@ TRACE_EVENT(cfg80211_ch_switch_notify, | |||
2067 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) | 2082 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) |
2068 | ); | 2083 | ); |
2069 | 2084 | ||
2085 | TRACE_EVENT(cfg80211_radar_event, | ||
2086 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), | ||
2087 | TP_ARGS(wiphy, chandef), | ||
2088 | TP_STRUCT__entry( | ||
2089 | WIPHY_ENTRY | ||
2090 | CHAN_DEF_ENTRY | ||
2091 | ), | ||
2092 | TP_fast_assign( | ||
2093 | WIPHY_ASSIGN; | ||
2094 | CHAN_DEF_ASSIGN(chandef); | ||
2095 | ), | ||
2096 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
2097 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | ||
2098 | ); | ||
2099 | |||
2100 | TRACE_EVENT(cfg80211_cac_event, | ||
2101 | TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt), | ||
2102 | TP_ARGS(netdev, evt), | ||
2103 | TP_STRUCT__entry( | ||
2104 | NETDEV_ENTRY | ||
2105 | __field(enum nl80211_radar_event, evt) | ||
2106 | ), | ||
2107 | TP_fast_assign( | ||
2108 | NETDEV_ASSIGN; | ||
2109 | __entry->evt = evt; | ||
2110 | ), | ||
2111 | TP_printk(NETDEV_PR_FMT ", event: %d", | ||
2112 | NETDEV_PR_ARG, __entry->evt) | ||
2113 | ); | ||
2114 | |||
2070 | DECLARE_EVENT_CLASS(cfg80211_rx_evt, | 2115 | DECLARE_EVENT_CLASS(cfg80211_rx_evt, |
2071 | TP_PROTO(struct net_device *netdev, const u8 *addr), | 2116 | TP_PROTO(struct net_device *netdev, const u8 *addr), |
2072 | TP_ARGS(netdev, addr), | 2117 | TP_ARGS(netdev, addr), |
@@ -2333,6 +2378,41 @@ TRACE_EVENT(cfg80211_return_u32, | |||
2333 | TP_printk("ret: %u", __entry->ret) | 2378 | TP_printk("ret: %u", __entry->ret) |
2334 | ); | 2379 | ); |
2335 | 2380 | ||
2381 | TRACE_EVENT(cfg80211_report_wowlan_wakeup, | ||
2382 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
2383 | struct cfg80211_wowlan_wakeup *wakeup), | ||
2384 | TP_ARGS(wiphy, wdev, wakeup), | ||
2385 | TP_STRUCT__entry( | ||
2386 | WIPHY_ENTRY | ||
2387 | WDEV_ENTRY | ||
2388 | __field(bool, disconnect) | ||
2389 | __field(bool, magic_pkt) | ||
2390 | __field(bool, gtk_rekey_failure) | ||
2391 | __field(bool, eap_identity_req) | ||
2392 | __field(bool, four_way_handshake) | ||
2393 | __field(bool, rfkill_release) | ||
2394 | __field(s32, pattern_idx) | ||
2395 | __field(u32, packet_len) | ||
2396 | __dynamic_array(u8, packet, wakeup->packet_present_len) | ||
2397 | ), | ||
2398 | TP_fast_assign( | ||
2399 | WIPHY_ASSIGN; | ||
2400 | WDEV_ASSIGN; | ||
2401 | __entry->disconnect = wakeup->disconnect; | ||
2402 | __entry->magic_pkt = wakeup->magic_pkt; | ||
2403 | __entry->gtk_rekey_failure = wakeup->gtk_rekey_failure; | ||
2404 | __entry->eap_identity_req = wakeup->eap_identity_req; | ||
2405 | __entry->four_way_handshake = wakeup->four_way_handshake; | ||
2406 | __entry->rfkill_release = wakeup->rfkill_release; | ||
2407 | __entry->pattern_idx = wakeup->pattern_idx; | ||
2408 | __entry->packet_len = wakeup->packet_len; | ||
2409 | if (wakeup->packet && wakeup->packet_present_len) | ||
2410 | memcpy(__get_dynamic_array(packet), wakeup->packet, | ||
2411 | wakeup->packet_present_len); | ||
2412 | ), | ||
2413 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | ||
2414 | ); | ||
2415 | |||
2336 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 2416 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
2337 | 2417 | ||
2338 | #undef TRACE_INCLUDE_PATH | 2418 | #undef TRACE_INCLUDE_PATH |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d7873c7ae0ec..37a56ee1e1ed 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -1217,10 +1217,10 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1217 | break; | 1217 | break; |
1218 | case NL80211_IFTYPE_P2P_CLIENT: | 1218 | case NL80211_IFTYPE_P2P_CLIENT: |
1219 | case NL80211_IFTYPE_STATION: | 1219 | case NL80211_IFTYPE_STATION: |
1220 | case NL80211_IFTYPE_P2P_DEVICE: | ||
1220 | case NL80211_IFTYPE_MONITOR: | 1221 | case NL80211_IFTYPE_MONITOR: |
1221 | radar_required = false; | 1222 | radar_required = false; |
1222 | break; | 1223 | break; |
1223 | case NL80211_IFTYPE_P2P_DEVICE: | ||
1224 | case NUM_NL80211_IFTYPES: | 1224 | case NUM_NL80211_IFTYPES: |
1225 | case NL80211_IFTYPE_UNSPECIFIED: | 1225 | case NL80211_IFTYPE_UNSPECIFIED: |
1226 | default: | 1226 | default: |