| From 9fa953a895c969b3f7a33c35e1e810b4695a2ca3 Mon Sep 17 00:00:00 2001 |
| From: Chin-Yen Lee <timlee@realtek.com> |
| Date: Thu, 22 Jul 2021 18:09:17 +0800 |
| Subject: [PATCH] CHROMIUM: rtw88: replace RADAR flag with NO_IR for dfs |
| channel |
| |
| Currently mac80211 don't allow active scan on DFS channels, it limits |
| connecting hidden AP on DFS channel. We take advantage of beacon hint |
| in cfg80211, by replacing IEEE80211_CHAN_RADAR of channel flags with |
| IEEE80211_CHAN_NO_IR, to allow active scan in channels where beacon is |
| found. Another, to avoid keeping active scan when radar signal suddenly |
| exists, restore IEEE80211_CHAN_NO_IR if the interval of two scans exceeds |
| set time. |
| |
| Signed-off-by: Chin-Yen Lee <timlee@realtek.com> |
| |
| BUG=b:190353955 |
| TEST=suite:wifi_matfunc; |
| DFS channel Test |
| a) check no probe request is sent if no AP exists |
| b) check probe request is sent after power on one AP; |
| power off AP, check no probe req is sent after 10s |
| c) connect to AP with hidden SSID |
| d) disconnect AP and repeat step a,b,c |
| |
| Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com> |
| Signed-off-by: Abhishek Kumar <kuabhs@chromium.org> |
| [kuabhs: Extend the TEST section with additional test details] |
| Change-Id: Ia02fa35ae1f589a6bdf60a2834359a4152c645aa |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3074386 |
| Reviewed-by: Matthew Wang <matthewmwang@chromium.org> |
| Commit-Queue: Matthew Wang <matthewmwang@chromium.org> |
| |
| [rebase515(groeck): Context conflicts] |
| Signed-off-by: Guenter Roeck <groeck@google.com> |
| Change-Id: I3760b55af57a2c7bdae8611dcb608d39cb6e320d |
| --- |
| drivers/net/wireless/realtek/rtw88/mac80211.c | 1 + |
| drivers/net/wireless/realtek/rtw88/main.c | 81 +++++++++++++++++++ |
| drivers/net/wireless/realtek/rtw88/main.h | 10 +++ |
| drivers/net/wireless/realtek/rtw88/regd.c | 2 + |
| 4 files changed, 94 insertions(+) |
| |
| diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c |
| --- a/drivers/net/wireless/realtek/rtw88/mac80211.c |
| +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c |
| @@ -605,6 +605,7 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, |
| |
| mutex_lock(&rtwdev->mutex); |
| rtw_core_scan_start(rtwdev, rtwvif, mac_addr, false); |
| + rtw_restore_no_ir_flag(rtwdev); |
| mutex_unlock(&rtwdev->mutex); |
| } |
| |
| diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c |
| --- a/drivers/net/wireless/realtek/rtw88/main.c |
| +++ b/drivers/net/wireless/realtek/rtw88/main.c |
| @@ -510,6 +510,87 @@ int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size) |
| } |
| EXPORT_SYMBOL(rtw_dump_reg); |
| |
| +void rtw_replace_radar_flag_with_no_ir(struct ieee80211_hw *hw) |
| +{ |
| + struct wiphy *wiphy = hw->wiphy; |
| + struct rtw_dev *rtwdev = hw->priv; |
| + struct ieee80211_channel *ch; |
| + struct ieee80211_supported_band *sband; |
| + int i; |
| + |
| + if (!wiphy || !wiphy->bands[NL80211_BAND_5GHZ]) |
| + return; |
| + |
| + /* Currently mac80211 just don't allow active scan on DFS channels |
| + * because DFS master support is not yet implemented for client devices. |
| + * This behavior will make client impossible to connect to hidden AP |
| + * on DFS channels. To practice the feature, a common way is to dismiss |
| + * the limit for a period of time after hearing beacon in DFS channels. |
| + * So we take advantage of beacon hint in cfg80211, by replacing |
| + * IEEE80211_CHAN_RADAR of channel flags with IEEE80211_CHAN_NO_IR. |
| + */ |
| + sband = wiphy->bands[NL80211_BAND_5GHZ]; |
| + mutex_lock(&rtwdev->dfs_mutex); |
| + rtwdev->dfs_channel_map = 0; |
| + for (i = 0; i < sband->n_channels; i++) { |
| + ch = &sband->channels[i]; |
| + if (ch->flags & IEEE80211_CHAN_DISABLED) |
| + continue; |
| + if (ch->flags & IEEE80211_CHAN_RADAR) { |
| + rtw_dbg(rtwdev, RTW_DBG_REGD, |
| + "set channel(%d) RADAR flags to NO_IR", |
| + ch->hw_value); |
| + ch->beacon_found = false; |
| + ch->flags |= IEEE80211_CHAN_NO_IR; |
| + ch->flags &= ~IEEE80211_CHAN_RADAR; |
| + rtwdev->dfs_channel_map |= BIT(i); |
| + } |
| + } |
| + rtwdev->dfs_last_update = jiffies; |
| + mutex_unlock(&rtwdev->dfs_mutex); |
| +} |
| + |
| +void rtw_restore_no_ir_flag(struct rtw_dev *rtwdev) |
| +{ |
| + struct ieee80211_hw *hw = rtwdev->hw; |
| + struct wiphy *wiphy = hw->wiphy; |
| + struct ieee80211_channel *ch; |
| + struct ieee80211_supported_band *sband; |
| + int i; |
| + |
| + if (!wiphy || !wiphy->bands[NL80211_BAND_5GHZ]) |
| + return; |
| + |
| + if (!rtwdev->dfs_channel_map) |
| + return; |
| + |
| + mutex_lock(&rtwdev->dfs_mutex); |
| + /* Based on the design of beacon hint, active scan is always allowed |
| + * after beacon is probed in current channel. But we need to avoid it |
| + * once radar signal exits. So restore IEEE80211_CHAN_NO_IR when |
| + * the interval of two scans is longer than 10s, to keep monitoring |
| + * if no beacon is found, maybe due to radar signal. |
| + */ |
| + if (time_after(rtwdev->dfs_last_update + RTW_DFS_TIMEOUT, jiffies)) { |
| + mutex_unlock(&rtwdev->dfs_mutex); |
| + return; |
| + } |
| + |
| + sband = wiphy->bands[NL80211_BAND_5GHZ]; |
| + for (i = 0; i < sband->n_channels; i++) { |
| + ch = &sband->channels[i]; |
| + if (rtwdev->dfs_channel_map & BIT(i)) { |
| + ch->beacon_found = false; |
| + ch->flags |= IEEE80211_CHAN_NO_IR; |
| + rtw_dbg(rtwdev, RTW_DBG_REGD, |
| + "restore NO_IR flag for channel(%d)\n", |
| + ch->hw_value); |
| + } |
| + } |
| + rtwdev->dfs_last_update = jiffies; |
| + mutex_unlock(&rtwdev->dfs_mutex); |
| +} |
| + |
| void rtw_vif_assoc_changed(struct rtw_vif *rtwvif, |
| struct ieee80211_bss_conf *conf) |
| { |
| diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h |
| --- a/drivers/net/wireless/realtek/rtw88/main.h |
| +++ b/drivers/net/wireless/realtek/rtw88/main.h |
| @@ -31,6 +31,11 @@ |
| |
| #define RTW_WATCH_DOG_DELAY_TIME round_jiffies_relative(HZ * 2) |
| |
| +/* AP need to stop beaconing after hearing radar signal in 10s. |
| + * So design 10s to restore NO_IR flag referenced by beacon hint. |
| + */ |
| +#define RTW_DFS_TIMEOUT msecs_to_jiffies(10000) |
| + |
| #define RFREG_MASK 0xfffff |
| #define INV_RF_DATA 0xffffffff |
| #define TX_PAGE_SIZE_SHIFT 7 |
| @@ -2002,6 +2007,11 @@ struct rtw_dev { |
| bool need_rfk; |
| struct completion fw_scan_density; |
| |
| + /* protects dfs channel context */ |
| + struct mutex dfs_mutex; |
| + u32 dfs_channel_map; |
| + unsigned long dfs_last_update; |
| + |
| /* hci related data, must be last */ |
| u8 priv[] __aligned(sizeof(void *)); |
| }; |
| diff --git a/drivers/net/wireless/realtek/rtw88/regd.c b/drivers/net/wireless/realtek/rtw88/regd.c |
| --- a/drivers/net/wireless/realtek/rtw88/regd.c |
| +++ b/drivers/net/wireless/realtek/rtw88/regd.c |
| @@ -465,6 +465,8 @@ void rtw_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) |
| struct rtw_regd next_regd = {0}; |
| bool hdl; |
| |
| + rtw_replace_radar_flag_with_no_ir(hw); |
| + |
| hdl = rtw_regd_state_hdl(rtwdev, &next_regd, request); |
| if (!hdl) { |
| rtw_dbg(rtwdev, RTW_DBG_REGD, |
| -- |
| 2.35.0.rc0.227.g00780c9af4-goog |
| |