diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index bc8caae50..5b74ddcdf 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1531,6 +1531,16 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, } +/* + * 802.11-2020: Table E-4 - Global operating classes + * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123 + */ +int is_dfs_global_op_class(u8 op_class) +{ + return (op_class >= 118) && (op_class <= 123); +} + + static int is_11b(u8 rate) { return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index e9d7293e7..e4e4c613e 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -218,6 +218,7 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, int sec_channel, u8 *op_class, u8 *channel); int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, u16 num_modes); +int is_dfs_global_op_class(u8 op_class); enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht); int supp_rates_11b_only(struct ieee802_11_elems *elems); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index c4f54ae88..15a7ba2b9 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -6931,6 +6931,10 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) if (allow_6ghz && chwidth == 40) max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + /* Allow DFS to be used for Autonomous GO */ + wpa_s->p2p_go_allow_dfs = !!(wpa_s->drv_flags & + WPA_DRIVER_FLAGS_DFS_OFFLOAD); + if (group_id >= 0) return p2p_ctrl_group_add_persistent(wpa_s, group_id, freq, freq2, ht40, vht, diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 8864d7a84..cc8db3524 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1038,6 +1038,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, wpa_s->p2p_group_common_freqs = NULL; wpa_s->p2p_group_common_freqs_num = 0; wpa_s->p2p_go_do_acs = 0; + wpa_s->p2p_go_allow_dfs = 0; wpa_s->waiting_presence_resp = 0; @@ -3585,12 +3586,12 @@ static enum chan_allowed has_channel(struct wpa_global *global, if ((unsigned int) mode->channels[i].freq == freq) { if (flags) *flags = mode->channels[i].flag; - if (mode->channels[i].flag & - (HOSTAPD_CHAN_DISABLED | - HOSTAPD_CHAN_RADAR)) + if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) return NOT_ALLOWED; if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR) return NO_IR; + if (mode->channels[i].flag & HOSTAPD_CHAN_RADAR) + return RADAR; return ALLOWED; } } @@ -3650,7 +3651,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, chans, num_chans); if (!center_chan) return NOT_ALLOWED; - if (!is_6ghz && center_chan >= 58 && center_chan <= 138) + if (!wpa_s->p2p_go_allow_dfs && + !is_6ghz && center_chan >= 58 && center_chan <= 138) return NOT_ALLOWED; /* Do not allow DFS channels for P2P */ /* check all the channels are available */ @@ -3661,6 +3663,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, &flags); if (res == NOT_ALLOWED) return NOT_ALLOWED; + if (res == RADAR) + ret = RADAR; if (res == NO_IR) ret = NO_IR; if (!is_6ghz) { @@ -3742,6 +3746,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, if (res == NOT_ALLOWED) return NOT_ALLOWED; + if (res == RADAR) + ret = RADAR; if (res == NO_IR) ret = NO_IR; @@ -3828,6 +3834,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, return NOT_ALLOWED; if (res == NO_IR || res2 == NO_IR) return NO_IR; + if (res == RADAR || res2 == RADAR) + return RADAR; return res; } @@ -3936,7 +3944,11 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s, u16 ch; int chan = channel; - if (o->p2p == NO_P2P_SUPP || + /* Allow DFS channels marked as NO_P2P_SUPP to be used with + * driver offloaded DFS. */ + if ((o->p2p == NO_P2P_SUPP && + (!is_dfs_global_op_class(o->op_class) || + !wpa_s->p2p_go_allow_dfs)) || (is_6ghz_op_class(o->op_class) && wpa_s->conf->p2p_6ghz_disable)) continue; @@ -3959,6 +3971,11 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s, return get_6ghz_sec_channel(channel); return (o->bw == BW40MINUS) ? -1 : 1; } + if (ret == RADAR && wpa_s->p2p_go_allow_dfs) { + /* Allow RADAR channels used for driver + * offloaded DFS */ + return (o->bw == BW40MINUS) ? -1 : 1; + } } } return 0; @@ -3971,8 +3988,10 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, { const u8 *chans; size_t num_chans; + enum chan_allowed ret; - if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80)) + ret = wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80); + if (!(ret == ALLOWED || (ret == RADAR && wpa_s->p2p_go_allow_dfs))) return 0; if (is_6ghz_op_class(op_class)) { @@ -3993,8 +4012,10 @@ int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, { const u8 *chans; size_t num_chans; + enum chan_allowed ret; - if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160)) + ret = wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160); + if (!(ret == ALLOWED || (ret == RADAR && wpa_s->p2p_go_allow_dfs))) return 0; if (is_6ghz_op_class(op_class)) { chans = center_channels_6ghz_160mhz; @@ -6766,6 +6787,11 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, wpa_s->p2p_go_do_acs = 0; } + if (go && wpa_s->p2p_go_allow_dfs) { + group_wpa_s->p2p_go_allow_dfs = wpa_s->p2p_go_allow_dfs; + wpa_s->p2p_go_allow_dfs = 0; + } + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s", group_wpa_s->ifname); group_wpa_s->p2p_first_connection_timeout = 0; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index f4b3e0380..951d3ee1b 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1125,6 +1125,7 @@ struct wpa_supplicant { unsigned int p2p_disable_ip_addr_req:1; unsigned int p2ps_method_config_any:1; unsigned int p2p_cli_probe:1; + unsigned int p2p_go_allow_dfs:1; enum hostapd_hw_mode p2p_go_acs_band; int p2p_persistent_go_freq; int p2p_persistent_id; @@ -1675,7 +1676,7 @@ void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s); /* op_classes.c */ enum chan_allowed { - NOT_ALLOWED, NO_IR, ALLOWED + NOT_ALLOWED, NO_IR, RADAR, ALLOWED }; enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,