diff --git a/src/drivers/driver.h b/src/drivers/driver.h index d3f7057d1..e925a59df 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -45,6 +45,15 @@ #define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000 #define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000 +#define HOSTAPD_CHAN_VHT_10_150 0x00100000 +#define HOSTAPD_CHAN_VHT_30_130 0x00200000 +#define HOSTAPD_CHAN_VHT_50_110 0x00400000 +#define HOSTAPD_CHAN_VHT_70_90 0x00800000 +#define HOSTAPD_CHAN_VHT_90_70 0x01000000 +#define HOSTAPD_CHAN_VHT_110_50 0x02000000 +#define HOSTAPD_CHAN_VHT_130_30 0x04000000 +#define HOSTAPD_CHAN_VHT_150_10 0x08000000 + /** * enum reg_change_initiator - Regulatory change initiator */ diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 25fed11ed..1b5752fbb 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -1418,7 +1418,7 @@ static void nl80211_reg_rule_sec(struct nlattr *tb[], static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start, - int end) + int end, int max_bw) { int c; @@ -1435,6 +1435,32 @@ static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start, if (chan->freq - 70 >= start && chan->freq + 10 <= end) chan->flag |= HOSTAPD_CHAN_VHT_70_10; + + if (max_bw >= 160) { + if (chan->freq - 10 >= start && chan->freq + 150 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_10_150; + + if (chan->freq - 30 >= start && chan->freq + 130 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_30_130; + + if (chan->freq - 50 >= start && chan->freq + 110 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_50_110; + + if (chan->freq - 70 >= start && chan->freq + 90 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_70_90; + + if (chan->freq - 90 >= start && chan->freq + 70 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_90_70; + + if (chan->freq - 110 >= start && chan->freq + 50 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_110_50; + + if (chan->freq - 130 >= start && chan->freq + 30 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_130_30; + + if (chan->freq - 150 >= start && chan->freq + 10 <= end) + chan->flag |= HOSTAPD_CHAN_VHT_150_10; + } } } @@ -1465,7 +1491,7 @@ static void nl80211_reg_rule_vht(struct nlattr *tb[], if (!results->modes[m].vht_capab) continue; - nl80211_set_vht_mode(&results->modes[m], start, end); + nl80211_set_vht_mode(&results->modes[m], start, end, max_bw); } } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index bf0336fb6..020a469df 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -3417,6 +3417,75 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, } +static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + u8 channel) +{ + u8 center_channels[] = { 50, 114 }; + unsigned int i; + + if (mode->mode != HOSTAPD_MODE_IEEE80211A) + return 0; + + for (i = 0; i < ARRAY_SIZE(center_channels); i++) + /* + * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64), + * so the center channel is 14 channels away from the start/end. + */ + if (channel >= center_channels[i] - 14 && + channel <= center_channels[i] + 14) + return center_channels[i]; + + return 0; +} + + +static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, + u8 channel, u8 bw) +{ + u8 center_chan; + int i, flags; + enum chan_allowed res, ret = ALLOWED; + + center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel); + if (!center_chan) + return NOT_ALLOWED; + /* VHT 160 MHz uses DFS channels in most countries. */ + + /* Check all the channels are available */ + for (i = 0; i < 8; i++) { + int adj_chan = center_chan - 14 + i * 4; + + res = has_channel(wpa_s->global, mode, adj_chan, &flags); + if (res == NOT_ALLOWED) + return NOT_ALLOWED; + + 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)) + return NOT_ALLOWED; + } + + return ret; +} + + static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel, u8 bw) @@ -3435,6 +3504,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, res2 = has_channel(wpa_s->global, mode, channel + 4, NULL); } else if (bw == BW80) { res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw); + } else if (bw == BW160) { + res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw); } if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) @@ -3548,6 +3619,15 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, } +int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel) +{ + if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160)) + return 0; + return wpas_p2p_get_center_160mhz(wpa_s, mode, channel); +} + + static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf, size_t buf_len) { diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 56e683498..259d604b2 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -140,6 +140,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); +int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel); unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *p2p_dev_addr,