blob: 3f267b0c5e3d600342e4383f3ed354f9430cd94d [file] [log] [blame]
From 12fe53a7919abb791658bcc7a74b8131f0362300 Mon Sep 17 00:00:00 2001
From: "fancy.liu" <fancy.liu@mediatek.com>
Date: Thu, 28 Sep 2023 18:03:08 +0800
Subject: [PATCH 078/104] mtk: hostapd: ACS: Add EHT320 and HT40- support, fix
issue
1. Add 6G EHT320 support;
2. Add 2.4G HT40- support;
3. Fix issue: selected best channel is out of channels;
Signed-off-by: fancy.liu <fancy.liu@mediatek.com>
---
src/ap/acs.c | 191 +++++++++++++++++++++++++++++++++------------------
1 file changed, 124 insertions(+), 67 deletions(-)
diff --git a/src/ap/acs.c b/src/ap/acs.c
index cfa4a7d27..1fa8b8e64 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -245,6 +245,7 @@ enum bw_type {
ACS_BW40,
ACS_BW80,
ACS_BW160,
+ ACS_BW320,
};
struct bw_item {
@@ -286,10 +287,16 @@ 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 },
+ { -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,
};
@@ -769,10 +776,19 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
struct hostapd_channel_data **ideal_chan,
long double *ideal_factor)
{
- struct hostapd_channel_data *chan, *adj_chan = NULL, *best;
+ struct hostapd_channel_data *chan, *adj_chan = NULL, *tmp_chan = NULL, *best;
long double factor;
int i, j;
unsigned int k;
+ int ht40_plus = 1, sec_ch_factor = 1;
+
+ if (is_24ghz_mode(mode->mode)) {
+ ht40_plus = (iface->conf->secondary_channel == -1) ? 0 : 1;
+ sec_ch_factor = (iface->conf->secondary_channel == -1) ? -1 : 1;
+ }
+
+ wpa_printf(MSG_INFO, "%s:%d, bw(%u), n_chans(%d), num_channels(%d), sec_ch(%d)",
+ __func__, __LINE__, bw, n_chans, mode->num_channels, iface->conf->secondary_channel);
for (i = 0; i < mode->num_channels; i++) {
double total_weight;
@@ -780,6 +796,9 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
bool update_best = true;
best = chan = &mode->channels[i];
+ wpa_printf(MSG_INFO,
+ "ACS: Channel[%d] %d: interference_factor %Lg",
+ i, chan->chan, chan->interference_factor);
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
@@ -811,7 +830,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
iface->conf->country[2] == 0x4f)
continue;
- if (!chan_bw_allowed(chan, bw, 1, 1)) {
+ if (!chan_bw_allowed(chan, bw, ht40_plus, 1)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: BW %u is not supported",
chan->chan, bw);
@@ -832,7 +851,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)) {
@@ -850,63 +870,86 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
chan->chan);
continue;
}
- }
- factor = 0;
- if (acs_usable_chan(chan))
- factor = chan->interference_factor;
- total_weight = 1;
-
- for (j = 1; j < n_chans; j++) {
- adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
- if (!adj_chan)
- break;
-
- if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
+ if (iface->conf->ieee80211be &&
+ hostapd_get_oper_chwidth(iface->conf) ==
+ CONF_OPER_CHWIDTH_320MHZ &&
+ !acs_usable_bw_chan(chan, ACS_BW320)) {
wpa_printf(MSG_DEBUG,
- "ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
- chan->chan, adj_chan->chan, bw);
- break;
+ "ACS: Channel %d: not allowed as primary channel for 320 MHz bandwidth",
+ chan->chan);
+ continue;
}
+ }
- if (acs_usable_chan(adj_chan)) {
- factor += adj_chan->interference_factor;
+ factor = 0;
+ total_weight = 0;
+
+ if (!is_24ghz_mode(mode->mode)) {
+ /* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less
+ * crowded primary channel if one was found in the segment */
+ if (acs_usable_chan(chan)) {
+ factor += chan->interference_factor;
total_weight += 1;
- } else {
- update_best = false;
}
- /* find the best channel in this segment */
- if (update_best &&
- adj_chan->interference_factor <
- best->interference_factor)
- best = adj_chan;
- }
+ for (j = 1; j < n_chans; j++) {
+ adj_chan = acs_find_chan(iface, chan->freq + j * 20);
+ if (!adj_chan)
+ break;
- if (j != n_chans) {
- wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth",
- chan->chan);
- continue;
- }
+ if (!is_in_chanlist(iface, adj_chan) || !is_in_freqlist(iface, adj_chan))
+ break;
- /* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less
- * crowded primary channel if one was found in the segment */
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- chan != best) {
- wpa_printf(MSG_DEBUG,
- "ACS: promoting channel %d over %d (less interference %Lg/%Lg)",
- best->chan, chan->chan,
- chan->interference_factor,
- best->interference_factor);
- chan = best;
- }
+ if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
+ chan->chan, adj_chan->chan, bw);
+ break;
+ }
+
+ update_best = true;
+ if (acs_usable_chan(adj_chan)) {
+ factor += adj_chan->interference_factor;
+ total_weight += 1;
+ } else {
+ update_best = false;
+ }
- /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
- * channel interference factor. */
- if (is_24ghz_mode(mode->mode)) {
+ /* find the best channel in this segment */
+ if (update_best &&
+ adj_chan->interference_factor < best->interference_factor)
+ best = adj_chan;
+ }
+
+ if (j != n_chans) {
+ wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth",
+ chan->chan);
+ continue;
+ }
+
+ if (chan != best) {
+ wpa_printf(MSG_INFO,
+ "ACS: promoting channel %d over %d (less interference %Lg/%Lg)",
+ best->chan, chan->chan,
+ chan->interference_factor,
+ best->interference_factor);
+ chan = best;
+ }
+ } else {
for (j = 0; j < n_chans; j++) {
+ /* Will set primary_channel / secondary_channel(40M case) weight to 1 */
+ tmp_chan = acs_find_chan(iface, chan->freq +
+ (j * sec_ch_factor * 20));
+ if (tmp_chan && acs_usable_chan(tmp_chan)) {
+ factor += tmp_chan->interference_factor;
+ total_weight += 1;
+ }
+
+ /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent channel
+ interference factor, separately for primary/secondary channel. */
adj_chan = acs_find_chan(iface, chan->freq +
- (j * 20) - 5);
+ (j * sec_ch_factor * 20) - 5);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -914,7 +957,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
adj_chan = acs_find_chan(iface, chan->freq +
- (j * 20) - 10);
+ (j * sec_ch_factor * 20) - 10);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_NEXT_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -922,7 +965,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
adj_chan = acs_find_chan(iface, chan->freq +
- (j * 20) + 5);
+ (j * sec_ch_factor * 20) + 5);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -930,7 +973,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
adj_chan = acs_find_chan(iface, chan->freq +
- (j * 20) + 10);
+ (j * sec_ch_factor * 20) + 10);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_NEXT_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -939,7 +982,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
}
- factor /= total_weight;
+ if (total_weight)
+ factor /= total_weight;
bias = NULL;
if (iface->conf->acs_chan_bias) {
@@ -958,11 +1002,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
if (bias) {
factor *= bias->bias;
- wpa_printf(MSG_DEBUG,
+ wpa_printf(MSG_INFO,
"ACS: * channel %d: total interference = %Lg (%f bias)",
chan->chan, factor, bias->bias);
} else {
- wpa_printf(MSG_DEBUG,
+ wpa_printf(MSG_INFO,
"ACS: * channel %d: total interference = %Lg",
chan->chan, factor);
}
@@ -1015,19 +1059,12 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
goto bw_selected;
}
- /* TODO: HT40- support */
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel == -1) {
- wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
- return NULL;
- }
-
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
+ iface->conf->ieee80211be) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CONF_OPER_CHWIDTH_80MHZ:
n_chans = 4;
@@ -1037,6 +1074,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
break;
default:
break;
+ /* 320 is supported only in 6GHz 11be mode */
}
}
@@ -1057,7 +1095,7 @@ bw_selected:
}
if (ideal_chan) {
- wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
+ wpa_printf(MSG_INFO, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
ideal_chan->chan, ideal_chan->freq, ideal_factor);
#ifdef CONFIG_IEEE80211BE
@@ -1072,6 +1110,21 @@ bw_selected:
return rand_chan;
}
+static int acs_get_center_freq_320mhz(int channel)
+{
+ if (channel >= 1 && channel <= 45)
+ return 31;
+ else if (channel >= 49 && channel <= 77)
+ return 63;
+ else if (channel >= 81 && channel <= 109)
+ return 95;
+ else if (channel >= 113 && channel <= 141)
+ return 127;
+ else if (channel >= 145 && channel <= 173)
+ return 159;
+ else
+ return 191;
+}
static void acs_adjust_secondary(struct hostapd_iface *iface)
{
@@ -1099,7 +1152,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:
@@ -1115,6 +1168,9 @@ static void acs_adjust_center_freq(struct hostapd_iface *iface)
case CONF_OPER_CHWIDTH_80MHZ:
center = acs_get_bw_center_chan(iface->freq, ACS_BW80);
break;
+ case CONF_OPER_CHWIDTH_320MHZ:
+ center = acs_get_center_freq_320mhz(iface->conf->channel);
+ break;
case CONF_OPER_CHWIDTH_160MHZ:
center = acs_get_bw_center_chan(iface->freq, ACS_BW160);
break;
@@ -1122,7 +1178,7 @@ static void acs_adjust_center_freq(struct hostapd_iface *iface)
/* TODO: How can this be calculated? Adjust
* acs_find_ideal_chan() */
wpa_printf(MSG_INFO,
- "ACS: Only VHT20/40/80/160 is supported now");
+ "ACS: Only VHT20/40/80/160 EHT320 is supported now");
return;
}
@@ -1185,7 +1241,8 @@ static void acs_study(struct hostapd_iface *iface)
iface->conf->punct_bitmap = ideal_chan->punct_bitmap;
#endif /* CONFIG_IEEE80211BE */
- if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
+ iface->conf->ieee80211be) {
acs_adjust_secondary(iface);
acs_adjust_center_freq(iface);
}
--
2.39.2