From e5173e8b12a8153cf56ad3d35cb4cc02aa44de6e Mon Sep 17 00:00:00 2001 From: Sreeramya Soratkal Date: Thu, 22 Jul 2021 18:11:00 +0530 Subject: [PATCH] P2P: Enable multiple channel widths for P2P in 6 GHz band Enable support for P2P connection in 6 GHz with the channel width of 40 MHz, 80 MHz, and 160 MHz. The flag max_oper_chwidth is used to configure the maximum channel width for P2P connection in 6 GHz with the commands P2P_CONNECT, P2P_INVITE, and P2P_GROUP_ADD. Signed-off-by: Sreeramya Soratkal --- src/common/hw_features_common.c | 16 +++++-- src/common/ieee802_11_common.c | 6 +-- src/common/ieee802_11_defs.h | 1 + wpa_supplicant/ap.c | 78 ++++++++++++++++++++++++++++++--- wpa_supplicant/ctrl_iface.c | 9 ++++ wpa_supplicant/op_classes.c | 8 +++- wpa_supplicant/p2p_supplicant.c | 77 ++++++++++++++++++++++---------- 7 files changed, 156 insertions(+), 39 deletions(-) diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index 8e7aa0b69..8a897fddc 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -417,7 +417,16 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, data->sec_channel_offset = sec_channel_offset; data->center_freq1 = freq + sec_channel_offset * 10; data->center_freq2 = 0; - data->bandwidth = sec_channel_offset ? 40 : 20; + if (oper_chwidth == CHANWIDTH_80MHZ) + data->bandwidth = 80; + else if (oper_chwidth == CHANWIDTH_160MHZ || + oper_chwidth == CHANWIDTH_80P80MHZ) + data->bandwidth = 160; + else if (sec_channel_offset) + data->bandwidth = 40; + else + data->bandwidth = 20; + hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel, &data->edmg); @@ -441,9 +450,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, "Segment 0 center frequency isn't set"); return -1; } - - data->center_freq1 = data->freq; - data->bandwidth = 20; + if (!sec_channel_offset) + data->center_freq1 = data->freq; } else { int freq1, freq2 = 0; int bw = center_idx_to_bw_6ghz(center_segment0); diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index ef68abacd..b51695645 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1895,9 +1895,9 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP }, diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 519a13b1d..2ed2d37b0 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1337,6 +1337,7 @@ struct ieee80211_ampe_ie { #define CHANWIDTH_4320MHZ 5 #define CHANWIDTH_6480MHZ 6 #define CHANWIDTH_8640MHZ 7 +#define CHANWIDTH_40MHZ_6GHZ 8 #define HE_NSS_MAX_STREAMS 8 diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index d3fb239c8..415f08789 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -84,6 +84,11 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, /* Use the maximum oper channel width if it's given. */ if (ssid->max_oper_chwidth) hostapd_set_oper_chwidth(conf, ssid->max_oper_chwidth); + if (hostapd_get_oper_chwidth(conf)) + ieee80211_freq_to_channel_ext(ssid->frequency, 0, + hostapd_get_oper_chwidth(conf), + &conf->op_class, + &conf->channel); if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) { ieee80211_freq_to_chan(ssid->vht_center_freq2, @@ -191,19 +196,75 @@ wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s, } +static int get_max_oper_chwidth_6ghz(int chwidth) +{ + switch (chwidth) { + case CHANWIDTH_USE_HT: + return 20; + case CHANWIDTH_40MHZ_6GHZ: + return 40; + case CHANWIDTH_80MHZ: + return 80; + case CHANWIDTH_80P80MHZ: + case CHANWIDTH_160MHZ: + return 160; + default: + return 0; + } +} + + +static void wpas_conf_ap_he_6ghz(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + struct wpa_ssid *ssid, + struct hostapd_config *conf) +{ + bool is_chanwidth_40_80, is_chanwidth_160; + int he_chanwidth; + + he_chanwidth = + mode->he_capab[wpas_mode_to_ieee80211_mode( + ssid->mode)].phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX]; + is_chanwidth_40_80 = he_chanwidth & + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + is_chanwidth_160 = he_chanwidth & + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + wpa_printf(MSG_DEBUG, + "Enable HE support (p2p_group=%d he_chwidth_cap=%d)", + ssid->p2p_group, he_chanwidth); + + if (mode->he_capab[wpas_mode_to_ieee80211_mode( + ssid->mode)].he_supported && + ssid->he) + conf->ieee80211ax = 1; + + if (is_chanwidth_40_80 && ssid->p2p_group && + get_max_oper_chwidth_6ghz(ssid->max_oper_chwidth) >= 40) { + conf->secondary_channel = + wpas_p2p_get_sec_channel_offset_40mhz( + wpa_s, mode, conf->channel); + wpa_printf(MSG_DEBUG, + "Secondary channel offset %d for P2P group", + conf->secondary_channel); + if (ssid->max_oper_chwidth == CHANWIDTH_40MHZ_6GHZ) + ssid->max_oper_chwidth = CHANWIDTH_USE_HT; + } + + if ((is_chanwidth_40_80 || is_chanwidth_160) && ssid->p2p_group && + get_max_oper_chwidth_6ghz(ssid->max_oper_chwidth) >= 80) + wpas_conf_ap_vht(wpa_s, ssid, conf, mode); +} + + int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct hostapd_config *conf) { conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0, - ssid->max_oper_chwidth, + CHANWIDTH_USE_HT, &conf->op_class, &conf->channel); - /* ssid->max_oper_chwidth is not valid in all cases, so fall back to the - * less specific mechanism, if needed, at least for now */ - if (conf->hw_mode == NUM_HOSTAPD_MODES) - conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, - &conf->channel); if (conf->hw_mode == NUM_HOSTAPD_MODES) { wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz", ssid->frequency); @@ -256,7 +317,10 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, no_ht = 1; } - if (!no_ht && mode && mode->ht_capab) { + if (mode && is_6ghz_freq(ssid->frequency) && + conf->hw_mode == HOSTAPD_MODE_IEEE80211A) { + wpas_conf_ap_he_6ghz(wpa_s, mode, ssid, conf); + } else if (!no_ht && mode && mode->ht_capab) { wpa_printf(MSG_DEBUG, "Enable HT support (p2p_group=%d 11a=%d ht40_hw_capab=%d ssid->ht40=%d)", ssid->p2p_group, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 08b19a3a9..c4f54ae88 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -6126,6 +6126,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, if (max_oper_chwidth < 0) return -1; + if (allow_6ghz && chwidth == 40) + max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + pos2 = os_strstr(pos, " ssid="); if (pos2) { char *end; @@ -6779,6 +6782,9 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL; + if (allow_6ghz && chwidth == 40) + max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, max_oper_chwidth, pref_freq, he, edmg, allow_6ghz); @@ -6922,6 +6928,9 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) if (max_oper_chwidth < 0) return -1; + if (allow_6ghz && chwidth == 40) + max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + if (group_id >= 0) return p2p_ctrl_group_add_persistent(wpa_s, group_id, freq, freq2, ht40, vht, diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c index a0ad0c2ff..bd53c5cec 100644 --- a/wpa_supplicant/op_classes.c +++ b/wpa_supplicant/op_classes.c @@ -207,11 +207,15 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, if (!(flag & HOSTAPD_CHAN_HT40MINUS)) return NOT_ALLOWED; res2 = allow_channel(mode, op_class, channel - 4, NULL); - } else if (bw == BW40PLUS || - (bw == BW40 && !(((channel - 1) / 4) % 2))) { + } else if (bw == BW40PLUS) { if (!(flag & HOSTAPD_CHAN_HT40PLUS)) return NOT_ALLOWED; res2 = allow_channel(mode, op_class, channel + 4, NULL); + } else if (is_6ghz_op_class(op_class) && bw == BW40) { + if (get_6ghz_sec_channel(channel) < 0) + res2 = allow_channel(mode, op_class, channel - 4, NULL); + else + res2 = allow_channel(mode, op_class, channel + 4, NULL); } else if (bw == BW80) { /* * channel is a center channel and as such, not necessarily a diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 51d351a48..8864d7a84 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -164,6 +164,17 @@ wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s, static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx); +static int wpas_get_6ghz_he_chwidth_capab(struct hostapd_hw_modes *mode) +{ + int he_capab = 0; + + if (mode) + he_capab = mode->he_capab[WPAS_MODE_INFRA].phy_cap[ + HE_PHYCAP_CHANNEL_WIDTH_SET_IDX]; + return he_capab; +} + + /* * Get the number of concurrent channels that the HW can operate, but that are * currently not in use by any of the wpa_supplicant interfaces. @@ -3652,15 +3663,20 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, return NOT_ALLOWED; if (res == NO_IR) ret = NO_IR; - - if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) - return NOT_ALLOWED; - if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) - return NOT_ALLOWED; - if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) - return NOT_ALLOWED; - if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)) + if (!is_6ghz) { + if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) + return NOT_ALLOWED; + if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) + return NOT_ALLOWED; + if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) + return NOT_ALLOWED; + if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)) + return NOT_ALLOWED; + } else if (is_6ghz && + (!(wpas_get_6ghz_he_chwidth_capab(mode) & + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G))) { return NOT_ALLOWED; + } } return ret; @@ -3729,22 +3745,28 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, if (res == NO_IR) ret = NO_IR; - if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) - return NOT_ALLOWED; - if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) - return NOT_ALLOWED; - if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) - return NOT_ALLOWED; - if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) - return NOT_ALLOWED; - if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) - return NOT_ALLOWED; - if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) - return NOT_ALLOWED; - if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) - return NOT_ALLOWED; - if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)) + if (!is_6ghz_op_class(op_class)) { + if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) + return NOT_ALLOWED; + if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) + return NOT_ALLOWED; + if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) + return NOT_ALLOWED; + if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) + return NOT_ALLOWED; + if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) + return NOT_ALLOWED; + if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) + return NOT_ALLOWED; + if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) + return NOT_ALLOWED; + if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)) + return NOT_ALLOWED; + } else if (is_6ghz_op_class(op_class) && + (!(wpas_get_6ghz_he_chwidth_capab(mode) & + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G))) { return NOT_ALLOWED; + } } return ret; @@ -3783,6 +3805,15 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, return NOT_ALLOWED; res2 = has_channel(wpa_s->global, mode, op_class, channel + 4, NULL); + } else if (is_6ghz_op_class(op_class) && bw == BW40) { + if (mode->mode != HOSTAPD_MODE_IEEE80211A) + return NOT_ALLOWED; + if (get_6ghz_sec_channel(channel) < 0) + res2 = has_channel(wpa_s->global, mode, op_class, + channel - 4, NULL); + else + res2 = has_channel(wpa_s->global, mode, op_class, + channel + 4, NULL); } else if (bw == BW80) { res2 = wpas_p2p_verify_80mhz(wpa_s, mode, op_class, channel, bw);