P2P: DFS offload for the autonomous GO

Enhance the P2P_GROUP_ADD command to support DFS channel with 80 and 160
MHz bandwidth to be used for autonomous GO when using offloaded DFS.

For example, 'P2P_GROUP_ADD freq=5500 max_oper_chwidth=80 ht40 vht'

- Previous behavior: AP fallback to channel 100 using 20 MHz with
  "No VHT higher bandwidth support for the selected channel 100"
- Enhanced behavior: AP starts on channel 100 using 80 MHz with
  "VHT center channel 106 for 80 or 80+80 MHz bandwidth"

This functionality is on top of the driver's capability to offload DFS,
which is advertized through WPA_DRIVER_FLAGS_DFS_OFFLOAD.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Hu Wang 2021-07-06 15:30:25 +08:00 committed by Jouni Malinen
parent 6ba665c5c3
commit ce267f4da9
5 changed files with 50 additions and 8 deletions

View file

@ -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) static int is_11b(u8 rate)
{ {
return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;

View file

@ -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 sec_channel, u8 *op_class, u8 *channel);
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
u16 num_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); enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
int supp_rates_11b_only(struct ieee802_11_elems *elems); int supp_rates_11b_only(struct ieee802_11_elems *elems);

View file

@ -6931,6 +6931,10 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
if (allow_6ghz && chwidth == 40) if (allow_6ghz && chwidth == 40)
max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; 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) if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id, return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht, freq, freq2, ht40, vht,

View file

@ -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 = NULL;
wpa_s->p2p_group_common_freqs_num = 0; wpa_s->p2p_group_common_freqs_num = 0;
wpa_s->p2p_go_do_acs = 0; wpa_s->p2p_go_do_acs = 0;
wpa_s->p2p_go_allow_dfs = 0;
wpa_s->waiting_presence_resp = 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 ((unsigned int) mode->channels[i].freq == freq) {
if (flags) if (flags)
*flags = mode->channels[i].flag; *flags = mode->channels[i].flag;
if (mode->channels[i].flag & if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
(HOSTAPD_CHAN_DISABLED |
HOSTAPD_CHAN_RADAR))
return NOT_ALLOWED; return NOT_ALLOWED;
if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR) if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
return NO_IR; return NO_IR;
if (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)
return RADAR;
return ALLOWED; return ALLOWED;
} }
} }
@ -3650,7 +3651,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
chans, num_chans); chans, num_chans);
if (!center_chan) if (!center_chan)
return NOT_ALLOWED; 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 */ return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
/* check all the channels are available */ /* check all the channels are available */
@ -3661,6 +3663,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
&flags); &flags);
if (res == NOT_ALLOWED) if (res == NOT_ALLOWED)
return NOT_ALLOWED; return NOT_ALLOWED;
if (res == RADAR)
ret = RADAR;
if (res == NO_IR) if (res == NO_IR)
ret = NO_IR; ret = NO_IR;
if (!is_6ghz) { if (!is_6ghz) {
@ -3742,6 +3746,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
if (res == NOT_ALLOWED) if (res == NOT_ALLOWED)
return NOT_ALLOWED; return NOT_ALLOWED;
if (res == RADAR)
ret = RADAR;
if (res == NO_IR) if (res == NO_IR)
ret = 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; return NOT_ALLOWED;
if (res == NO_IR || res2 == NO_IR) if (res == NO_IR || res2 == NO_IR)
return NO_IR; return NO_IR;
if (res == RADAR || res2 == RADAR)
return RADAR;
return res; return res;
} }
@ -3936,7 +3944,11 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s,
u16 ch; u16 ch;
int chan = channel; 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) && (is_6ghz_op_class(o->op_class) &&
wpa_s->conf->p2p_6ghz_disable)) wpa_s->conf->p2p_6ghz_disable))
continue; 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 get_6ghz_sec_channel(channel);
return (o->bw == BW40MINUS) ? -1 : 1; 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; return 0;
@ -3971,8 +3988,10 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
{ {
const u8 *chans; const u8 *chans;
size_t num_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; return 0;
if (is_6ghz_op_class(op_class)) { 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; const u8 *chans;
size_t num_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; return 0;
if (is_6ghz_op_class(op_class)) { if (is_6ghz_op_class(op_class)) {
chans = center_channels_6ghz_160mhz; 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; 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", wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname); group_wpa_s->ifname);
group_wpa_s->p2p_first_connection_timeout = 0; group_wpa_s->p2p_first_connection_timeout = 0;

View file

@ -1125,6 +1125,7 @@ struct wpa_supplicant {
unsigned int p2p_disable_ip_addr_req:1; unsigned int p2p_disable_ip_addr_req:1;
unsigned int p2ps_method_config_any:1; unsigned int p2ps_method_config_any:1;
unsigned int p2p_cli_probe:1; unsigned int p2p_cli_probe:1;
unsigned int p2p_go_allow_dfs:1;
enum hostapd_hw_mode p2p_go_acs_band; enum hostapd_hw_mode p2p_go_acs_band;
int p2p_persistent_go_freq; int p2p_persistent_go_freq;
int p2p_persistent_id; int p2p_persistent_id;
@ -1675,7 +1676,7 @@ void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s);
/* op_classes.c */ /* op_classes.c */
enum chan_allowed { 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, enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,