]> git.baikalelectronics.ru Git - kernel.git/commitdiff
rtw88: fix EAPOL 4-way failure by finish IQK earlier
authorPing-Ke Shih <pkshih@realtek.com>
Fri, 29 May 2020 02:50:09 +0000 (10:50 +0800)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 29 May 2020 17:36:05 +0000 (20:36 +0300)
Connecting to an AP with WPA2 security may fail. The IQK
and the EAPOL 4-way handshake may overlap because the
driver does IQK right after assoc success.

For 802.11n devices, the IQK is done in the driver and it
could require more than 100ms to complete. During IQK, any
TX/RX events are paused. So if the EAPOL 4-way handshake
started before IQK finished, then the 1/4 and 2/4 part of
the handshake could be dropped. The AP will then issue
deauth with reason IEEE8021X_FAILED (23).

To resolve this, move IQK routine into managed TX prepare
(ieee80211_ops::mgd_prepare_tx()). The callback is called
before the managed frames (auth/assoc) are sent. This will
make sure that the IQK is completed before the handshake
starts. But don't do IQK during scanning because doing it
on each channel will take too long.

For 802.11ac devices, the IQK is done in firmware and it
takes less time to complete. Therefore we don't see a
failure during the EAPOL 4-way handshake. But it is still
worth moving the IQK into ieee80211_ops::mgd_prepare_tx().

Fixes: fda8a5ded852 ("rtw88: 8723d: Add 8723DE to Kconfig and Makefile")
Tested-by: You-Sheng Yang <vicamo.yang@canonical.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200529025009.2468-4-yhchuang@realtek.com
drivers/net/wireless/realtek/rtw88/mac80211.c
drivers/net/wireless/realtek/rtw88/main.c
drivers/net/wireless/realtek/rtw88/main.h

index 98d2ac22f6f6345186fd4a89415e918c5fbd4a37..c412bc54efde1bc513793b5e7f188c781d5bcd95 100644 (file)
@@ -341,13 +341,11 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
        rtw_leave_lps_deep(rtwdev);
 
        if (changed & BSS_CHANGED_ASSOC) {
-               struct rtw_chip_info *chip = rtwdev->chip;
                enum rtw_net_type net_type;
 
                if (conf->assoc) {
                        rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH);
                        net_type = RTW_NET_MGD_LINKED;
-                       chip->ops->phy_calibration(rtwdev);
 
                        rtwvif->aid = conf->aid;
                        rtw_fw_download_rsvd_page(rtwdev);
@@ -663,6 +661,7 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,
        mutex_lock(&rtwdev->mutex);
        rtw_leave_lps_deep(rtwdev);
        rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START);
+       rtw_chip_prepare_tx(rtwdev);
        mutex_unlock(&rtwdev->mutex);
 }
 
index f88a7d2370aa8c117e7f383f62d69d4e408648d6..0eefafc51c62e722566b7e984ecfafef7e718058 100644 (file)
@@ -408,6 +408,23 @@ void rtw_set_channel(struct rtw_dev *rtwdev)
        }
 
        rtw_phy_set_tx_power_level(rtwdev, center_chan);
+
+       /* if the channel isn't set for scanning, we will do RF calibration
+        * in ieee80211_ops::mgd_prepare_tx(). Performing the calibration
+        * during scanning on each channel takes too long.
+        */
+       if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
+               rtwdev->need_rfk = true;
+}
+
+void rtw_chip_prepare_tx(struct rtw_dev *rtwdev)
+{
+       struct rtw_chip_info *chip = rtwdev->chip;
+
+       if (rtwdev->need_rfk) {
+               rtwdev->need_rfk = false;
+               chip->ops->phy_calibration(rtwdev);
+       }
 }
 
 static void rtw_vif_write_addr(struct rtw_dev *rtwdev, u32 start, u8 *addr)
index 2ae424869f8bd904277f114eb724cb6ae526fea2..0841f5fa4bf27d555c92ba6810752af1477be2e8 100644 (file)
@@ -1720,6 +1720,8 @@ struct rtw_dev {
        struct rtw_fw_state wow_fw;
        struct rtw_wow_param wow;
 
+       bool need_rfk;
+
        /* hci related data, must be last */
        u8 priv[] __aligned(sizeof(void *));
 };
@@ -1793,6 +1795,7 @@ void rtw_restore_reg(struct rtw_dev *rtwdev,
                     struct rtw_backup_info *bckp, u32 num);
 void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss);
 void rtw_set_channel(struct rtw_dev *rtwdev);
+void rtw_chip_prepare_tx(struct rtw_dev *rtwdev);
 void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
                         u32 config);
 void rtw_tx_report_purge_timer(struct timer_list *t);