Skip to content

Commit c6aa9a9

Browse files
Po-Hao HuangKalle Valo
authored andcommitted
wifi: rtw89: add RNR support for 6 GHz scan
Since 6 GHz band has around 60 channels and more strict rules for active probing. Reduced neighbor report can be used to reduce the channels we scan and get specific target BSS info to probe for. Declare flag WIPHY_FLAG_SPLIT_SCAN_6GHZ so the scan request could be divided into two portions: legacy bands and 6 GHz bands. So RNR information from legacy bands could later be used when 6 GHz scan. When the scan flag NL80211_SCAN_FLAG_COLOCATED_6GHZ is set, cfg80211 will pass down a reduced channel set which contains PSCs and non-PSC with RNR info received in the 2 GHz/5 GHz band. This reduces the scan duration by allowing us to only scan for channels in which APs are currently operating. Signed-off-by: Po-Hao Huang <[email protected]> Signed-off-by: Ping-Ke Shih <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent db5e4b3 commit c6aa9a9

File tree

3 files changed

+162
-16
lines changed

3 files changed

+162
-16
lines changed

drivers/net/wireless/realtek/rtw89/core.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,34 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
14001400
}
14011401
}
14021402

1403+
static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
1404+
struct sk_buff *skb)
1405+
{
1406+
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
1407+
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
1408+
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
1409+
struct rtw89_pktofld_info *info;
1410+
const u8 *ies = mgmt->u.beacon.variable, *ssid_ie;
1411+
1412+
if (rx_status->band != NL80211_BAND_6GHZ)
1413+
return;
1414+
1415+
ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len);
1416+
1417+
list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) {
1418+
if (ether_addr_equal(info->bssid, mgmt->bssid)) {
1419+
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
1420+
continue;
1421+
}
1422+
1423+
if (!ssid_ie || ssid_ie[1] != info->ssid_len || info->ssid_len == 0)
1424+
continue;
1425+
1426+
if (memcmp(&ssid_ie[2], info->ssid, info->ssid_len) == 0)
1427+
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
1428+
}
1429+
}
1430+
14031431
static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
14041432
struct ieee80211_vif *vif)
14051433
{
@@ -1412,6 +1440,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
14121440
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
14131441
const u8 *bssid = iter_data->bssid;
14141442

1443+
if (rtwdev->scanning &&
1444+
(ieee80211_is_beacon(hdr->frame_control) ||
1445+
ieee80211_is_probe_resp(hdr->frame_control)))
1446+
rtw89_core_cancel_6ghz_probe_tx(rtwdev, skb);
1447+
14151448
if (!vif->bss_conf.bssid)
14161449
return;
14171450

@@ -3372,7 +3405,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
33723405

33733406
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
33743407
WIPHY_FLAG_TDLS_EXTERNAL_SETUP |
3375-
WIPHY_FLAG_AP_UAPSD;
3408+
WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_SPLIT_SCAN_6GHZ;
33763409
hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
33773410

33783411
hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID;

drivers/net/wireless/realtek/rtw89/fw.c

Lines changed: 121 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,9 +2702,29 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
27022702
}
27032703
}
27042704

2705+
static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
2706+
struct rtw89_vif *rtwvif,
2707+
struct rtw89_pktofld_info *info,
2708+
enum nl80211_band band, u8 ssid_idx)
2709+
{
2710+
struct cfg80211_scan_request *req = rtwvif->scan_req;
2711+
2712+
if (band != NL80211_BAND_6GHZ)
2713+
return false;
2714+
2715+
if (req->ssids[ssid_idx].ssid_len) {
2716+
memcpy(info->ssid, req->ssids[ssid_idx].ssid,
2717+
req->ssids[ssid_idx].ssid_len);
2718+
info->ssid_len = req->ssids[ssid_idx].ssid_len;
2719+
return false;
2720+
} else {
2721+
return true;
2722+
}
2723+
}
2724+
27052725
static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
27062726
struct rtw89_vif *rtwvif,
2707-
struct sk_buff *skb)
2727+
struct sk_buff *skb, u8 ssid_idx)
27082728
{
27092729
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
27102730
struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
@@ -2732,6 +2752,13 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
27322752
goto out;
27332753
}
27342754

2755+
if (rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band,
2756+
ssid_idx)) {
2757+
kfree_skb(new);
2758+
kfree(info);
2759+
goto out;
2760+
}
2761+
27352762
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new);
27362763
if (ret) {
27372764
kfree_skb(new);
@@ -2762,7 +2789,7 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
27622789
if (!skb)
27632790
return -ENOMEM;
27642791

2765-
ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb);
2792+
ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb, i);
27662793
kfree_skb(skb);
27672794

27682795
if (ret)
@@ -2772,6 +2799,77 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
27722799
return 0;
27732800
}
27742801

2802+
static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev,
2803+
struct cfg80211_scan_request *req,
2804+
struct rtw89_mac_chinfo *ch_info)
2805+
{
2806+
struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
2807+
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
2808+
struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
2809+
struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
2810+
struct cfg80211_scan_6ghz_params *params;
2811+
struct rtw89_pktofld_info *info, *tmp;
2812+
struct ieee80211_hdr *hdr;
2813+
struct sk_buff *skb;
2814+
bool found;
2815+
int ret = 0;
2816+
u8 i;
2817+
2818+
if (!req->n_6ghz_params)
2819+
return 0;
2820+
2821+
for (i = 0; i < req->n_6ghz_params; i++) {
2822+
params = &req->scan_6ghz_params[i];
2823+
2824+
if (req->channels[params->channel_idx]->hw_value !=
2825+
ch_info->pri_ch)
2826+
continue;
2827+
2828+
found = false;
2829+
list_for_each_entry(tmp, &pkt_list[NL80211_BAND_6GHZ], list) {
2830+
if (ether_addr_equal(tmp->bssid, params->bssid)) {
2831+
found = true;
2832+
break;
2833+
}
2834+
}
2835+
if (found)
2836+
continue;
2837+
2838+
skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr,
2839+
NULL, 0, req->ie_len);
2840+
skb_put_data(skb, ies->ies[NL80211_BAND_6GHZ], ies->len[NL80211_BAND_6GHZ]);
2841+
skb_put_data(skb, ies->common_ies, ies->common_ie_len);
2842+
hdr = (struct ieee80211_hdr *)skb->data;
2843+
ether_addr_copy(hdr->addr3, params->bssid);
2844+
2845+
info = kzalloc(sizeof(*info), GFP_KERNEL);
2846+
if (!info) {
2847+
ret = -ENOMEM;
2848+
kfree_skb(skb);
2849+
goto out;
2850+
}
2851+
2852+
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb);
2853+
if (ret) {
2854+
kfree_skb(skb);
2855+
kfree(info);
2856+
goto out;
2857+
}
2858+
2859+
ether_addr_copy(info->bssid, params->bssid);
2860+
info->channel_6ghz = req->channels[params->channel_idx]->hw_value;
2861+
list_add_tail(&info->list, &rtwdev->scan_info.pkt_list[NL80211_BAND_6GHZ]);
2862+
2863+
ch_info->tx_pkt = true;
2864+
ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G;
2865+
2866+
kfree_skb(skb);
2867+
}
2868+
2869+
out:
2870+
return ret;
2871+
}
2872+
27752873
static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
27762874
int ssid_num,
27772875
struct rtw89_mac_chinfo *ch_info)
@@ -2782,6 +2880,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
27822880
struct cfg80211_scan_request *req = rtwvif->scan_req;
27832881
struct rtw89_pktofld_info *info;
27842882
u8 band, probe_count = 0;
2883+
int ret;
27852884

27862885
ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK;
27872886
ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS;
@@ -2793,25 +2892,31 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
27932892
ch_info->pause_data = false;
27942893
ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
27952894

2895+
if (ch_info->ch_band == RTW89_BAND_6G) {
2896+
if ((ssid_num == 1 && req->ssids[0].ssid_len == 0) ||
2897+
!ch_info->is_psc) {
2898+
ch_info->tx_pkt = false;
2899+
if (!req->duration_mandatory)
2900+
ch_info->period -= RTW89_DWELL_TIME_6G;
2901+
}
2902+
}
2903+
2904+
ret = rtw89_update_6ghz_rnr_chan(rtwdev, req, ch_info);
2905+
if (ret)
2906+
rtw89_warn(rtwdev, "RNR fails: %d\n", ret);
2907+
27962908
if (ssid_num) {
2797-
ch_info->num_pkt = ssid_num;
27982909
band = rtw89_hw_to_nl80211_band(ch_info->ch_band);
27992910

28002911
list_for_each_entry(info, &scan_info->pkt_list[band], list) {
2801-
ch_info->pkt_id[probe_count] = info->id;
2802-
if (++probe_count >= ssid_num)
2912+
if (info->channel_6ghz &&
2913+
ch_info->pri_ch != info->channel_6ghz)
2914+
continue;
2915+
ch_info->pkt_id[probe_count++] = info->id;
2916+
if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
28032917
break;
28042918
}
2805-
if (probe_count != ssid_num)
2806-
rtw89_err(rtwdev, "SSID num differs from list len\n");
2807-
}
2808-
2809-
if (ch_info->ch_band == RTW89_BAND_6G) {
2810-
if (ssid_num == 1 && req->ssids[0].ssid_len == 0) {
2811-
ch_info->tx_pkt = false;
2812-
if (!req->duration_mandatory)
2813-
ch_info->period -= RTW89_DWELL_TIME_6G;
2814-
}
2919+
ch_info->num_pkt = probe_count;
28152920
}
28162921

28172922
switch (chan_type) {
@@ -2872,6 +2977,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
28722977
ch_info->central_ch = channel->hw_value;
28732978
ch_info->pri_ch = channel->hw_value;
28742979
ch_info->rand_seq_num = random_seq;
2980+
ch_info->is_psc = cfg80211_channel_is_psc(channel);
28752981

28762982
if (channel->flags &
28772983
(IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))

drivers/net/wireless/realtek/rtw89/fw.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ struct rtw89_mac_chinfo {
237237
u16 tx_pwr_idx;
238238
u8 rsvd1;
239239
struct list_head list;
240+
bool is_psc;
240241
};
241242

242243
struct rtw89_scan_option {
@@ -247,6 +248,12 @@ struct rtw89_scan_option {
247248
struct rtw89_pktofld_info {
248249
struct list_head list;
249250
u8 id;
251+
252+
/* Below fields are for 6 GHz RNR use only */
253+
u8 ssid[IEEE80211_MAX_SSID_LEN];
254+
u8 ssid_len;
255+
u8 bssid[ETH_ALEN];
256+
u16 channel_6ghz;
250257
};
251258

252259
static inline void RTW89_SET_FWCMD_RA_IS_DIS(void *cmd, u32 val)

0 commit comments

Comments
 (0)