ACS: Extend the 320 MHz support

There are bandwidth 320 MHz-1 and 320 MHz-2 channelization in EHT mode.
When using ACS, user might prefer one of the channelization or both, but
original ACS was unable to take such preference.

Another problem is that the original ACS returns only the ideal channel
but no 320 MHz channelization. The function acs_get_bw_center_chan()
also could not correctly return the center frequency of bandwidth 320
MHz that is decided by ACS.

For example, if ACS decide the ideal channel is channel 37 with
channelization 320 MHz-2 (center frequency 6265 MHz),
acs_get_bw_center_chan() returns 6105 MHz, which is 320 MHz-1.

Extend the support for 320 MHz so that ACS can choose the best channel
according to the user's preference. Also, after calling
acs_find_ideal_chan_mode(), the best channel and bandwidth can be
derived.

The changes are:
- bw_type ACS_BW320 is divided into ACS_BW320_1 and ACS_BW320_2
- in bandwidth 320 MHz, find the best channel and bandwidth according to
  user's perference (320 MHz-1, 320 Mhz-2 or both are OK)
- before acs_find_ideal_chan_mode() returns, update bw320_offset in
  iface->conf so that the best channel's channelization is recorded.
- get the best center frequency from bw320_offset

Co-developed-by: Money Wang <money.wang@mediatek.com>
Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
This commit is contained in:
Michael-CY Lee 2023-12-22 12:59:11 +08:00 committed by Jouni Malinen
parent e6f2494c3a
commit 98f3bd26de

View file

@ -245,7 +245,8 @@ enum bw_type {
ACS_BW40,
ACS_BW80,
ACS_BW160,
ACS_BW320,
ACS_BW320_1,
ACS_BW320_2,
};
struct bw_item {
@ -287,16 +288,20 @@ static const struct bw_item bw_160[] = {
{ 6435, 6575, 111 }, { 6595, 6735, 143 },
{ 6755, 6895, 175 }, { 6915, 7055, 207 }, { -1, -1, -1 }
};
static const struct bw_item bw_320[] = {
{ 5955, 6255, 31 }, { 6115, 6415, 63 }, { 6275, 6575, 95 },
{ 6435, 6735, 127 }, { 6595, 6895, 159}, { 6755, 7055, 191 },
static const struct bw_item bw_320_1[] = {
{ 5955, 6255, 31 }, { 6275, 6575, 95 }, { 6595, 6895, 159 },
{ -1, -1, -1 }
};
static const struct bw_item bw_320_2[] = {
{ 6115, 6415, 63 }, { 6435, 6735, 127 }, { 6755, 7055, 191 },
{ -1, -1, -1 }
};
static const struct bw_item *bw_desc[] = {
[ACS_BW40] = bw_40,
[ACS_BW80] = bw_80,
[ACS_BW160] = bw_160,
[ACS_BW320] = bw_320,
[ACS_BW320_1] = bw_320_1,
[ACS_BW320_2] = bw_320_2,
};
@ -775,6 +780,42 @@ static void acs_update_puncturing_bitmap(struct hostapd_iface *iface,
#endif /* CONFIG_IEEE80211BE */
static bool
acs_usable_bw320_chan(struct hostapd_iface *iface,
struct hostapd_channel_data *chan, int *bw320_offset)
{
const char *bw320_str[] = { "320 MHz", "320 MHz-1", "320 MHz-2" };
int conf_bw320_offset = hostapd_get_bw320_offset(iface->conf);
*bw320_offset = 0;
switch (conf_bw320_offset) {
case 1:
if (acs_usable_bw_chan(chan, ACS_BW320_1))
*bw320_offset = 1;
break;
case 2:
if (acs_usable_bw_chan(chan, ACS_BW320_2))
*bw320_offset = 2;
break;
case 0:
default:
conf_bw320_offset = 0;
if (acs_usable_bw_chan(chan, ACS_BW320_1))
*bw320_offset = 1;
else if (acs_usable_bw_chan(chan, ACS_BW320_2))
*bw320_offset = 2;
break;
}
if (!*bw320_offset)
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for %s bandwidth",
chan->chan, bw320_str[conf_bw320_offset]);
return *bw320_offset != 0;
}
static void
acs_find_ideal_chan_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode,
@ -786,6 +827,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
struct hostapd_channel_data *chan, *adj_chan = NULL, *best;
long double factor;
int i, j;
int bw320_offset = 0, ideal_bw320_offset = 0;
unsigned int k;
int secondary_channel = 1, freq_offset;
@ -849,7 +891,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
(iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
iface->conf->ieee80211be)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CONF_OPER_CHWIDTH_80MHZ &&
!acs_usable_bw_chan(chan, ACS_BW80)) {
@ -873,12 +916,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
iface->conf->ieee80211be) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CONF_OPER_CHWIDTH_320MHZ &&
!acs_usable_bw_chan(chan, ACS_BW320)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 320 MHz bandwidth",
chan->chan);
!acs_usable_bw320_chan(iface, chan, &bw320_offset))
continue;
}
}
factor = 0;
@ -1012,6 +1051,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
*ideal_factor = factor;
*ideal_chan = chan;
ideal_bw320_offset = bw320_offset;
#ifdef CONFIG_IEEE80211BE
if (iface->conf->ieee80211be)
@ -1022,9 +1062,13 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
/* This channel would at least be usable */
if (!(*rand_chan))
if (!(*rand_chan)) {
*rand_chan = chan;
ideal_bw320_offset = bw320_offset;
}
}
hostapd_set_and_check_bw320_offset(iface->conf, ideal_bw320_offset);
}
@ -1116,7 +1160,8 @@ static void acs_adjust_secondary(struct hostapd_iface *iface)
acs_find_mode(iface, iface->freq) != HOSTAPD_MODE_IEEE80211A)
return;
wpa_printf(MSG_DEBUG, "ACS: Adjusting HT/VHT/HE secondary frequency");
wpa_printf(MSG_DEBUG,
"ACS: Adjusting HT/VHT/HE/EHT secondary frequency");
for (i = 0; bw_desc[ACS_BW40][i].first != -1; i++) {
if (iface->freq == bw_desc[ACS_BW40][i].first)
@ -1131,7 +1176,7 @@ static void acs_adjust_center_freq(struct hostapd_iface *iface)
{
int center;
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
wpa_printf(MSG_DEBUG, "ACS: Adjusting center frequency");
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CONF_OPER_CHWIDTH_USE_HT:
@ -1151,7 +1196,21 @@ static void acs_adjust_center_freq(struct hostapd_iface *iface)
center = acs_get_bw_center_chan(iface->freq, ACS_BW160);
break;
case CONF_OPER_CHWIDTH_320MHZ:
center = acs_get_bw_center_chan(iface->freq, ACS_BW320);
switch (hostapd_get_bw320_offset(iface->conf)) {
case 1:
center = acs_get_bw_center_chan(iface->freq,
ACS_BW320_1);
break;
case 2:
center = acs_get_bw_center_chan(iface->freq,
ACS_BW320_2);
break;
default:
wpa_printf(MSG_INFO,
"ACS: BW320 offset is not selected");
return;
}
break;
default:
/* TODO: How can this be calculated? Adjust