developer | 7e2761e | 2023-10-12 08:11:13 +0800 | [diff] [blame^] | 1 | From 88f5a4c1c67f8fc40c8294c498faa72e1ceea470 Mon Sep 17 00:00:00 2001 |
| 2 | From: "fancy.liu" <fancy.liu@mediatek.com> |
| 3 | Date: Thu, 28 Sep 2023 18:03:08 +0800 |
| 4 | Subject: [PATCH] hostapd: mtk: [ACS] Add EHT320 and HT40- support, fix issue |
| 5 | |
| 6 | 1. Add 6G EHT320 support; |
| 7 | 2. Add 2.4G HT40- support; |
| 8 | 3. Fix issue: selected best channel is out of channels; |
| 9 | |
| 10 | Signed-off-by: fancy.liu <fancy.liu@mediatek.com> |
| 11 | --- |
| 12 | src/ap/acs.c | 222 +++++++++++++++++++++++++++++++-------------------- |
| 13 | 1 file changed, 136 insertions(+), 86 deletions(-) |
| 14 | |
| 15 | diff --git a/src/ap/acs.c b/src/ap/acs.c |
| 16 | index af31405..ed6a47b 100644 |
| 17 | --- a/src/ap/acs.c |
| 18 | +++ b/src/ap/acs.c |
| 19 | @@ -245,6 +245,7 @@ enum bw_type { |
| 20 | ACS_BW40, |
| 21 | ACS_BW80, |
| 22 | ACS_BW160, |
| 23 | + ACS_BW320, |
| 24 | }; |
| 25 | |
| 26 | struct bw_item { |
| 27 | @@ -286,10 +287,16 @@ static const struct bw_item bw_160[] = { |
| 28 | { 6435, 6575, 111 }, { 6595, 6735, 143 }, |
| 29 | { 6755, 6895, 175 }, { 6915, 7055, 207 }, { -1, -1, -1 } |
| 30 | }; |
| 31 | +static const struct bw_item bw_320[] = { |
| 32 | + { 5955, 6255, 31 }, { 6115, 6415, 63 }, { 6275, 6575, 95 }, |
| 33 | + { 6435, 6735, 127 }, { 6595, 6895, 159 }, { 6755, 7055, 191 }, |
| 34 | + { -1, -1, -1 } |
| 35 | +}; |
| 36 | static const struct bw_item *bw_desc[] = { |
| 37 | [ACS_BW40] = bw_40, |
| 38 | [ACS_BW80] = bw_80, |
| 39 | [ACS_BW160] = bw_160, |
| 40 | + [ACS_BW320] = bw_320, |
| 41 | }; |
| 42 | |
| 43 | |
| 44 | @@ -583,12 +590,6 @@ static void acs_survey_mode_interference_factor( |
| 45 | iface->conf->acs_exclude_dfs) |
| 46 | continue; |
| 47 | |
| 48 | - if (!is_in_chanlist(iface, chan)) |
| 49 | - continue; |
| 50 | - |
| 51 | - if (!is_in_freqlist(iface, chan)) |
| 52 | - continue; |
| 53 | - |
| 54 | if (chan->max_tx_power < iface->conf->min_tx_power) |
| 55 | continue; |
| 56 | |
| 57 | @@ -775,17 +776,29 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 58 | struct hostapd_channel_data **ideal_chan, |
| 59 | long double *ideal_factor) |
| 60 | { |
| 61 | - struct hostapd_channel_data *chan, *adj_chan = NULL, *best; |
| 62 | + struct hostapd_channel_data *chan, *adj_chan = NULL, *tmp_chan = NULL, *best; |
| 63 | long double factor; |
| 64 | int i, j; |
| 65 | unsigned int k; |
| 66 | + int ht40_plus = 1, sec_ch_factor = 1; |
| 67 | + |
| 68 | + if (is_24ghz_mode(mode->mode)) { |
| 69 | + ht40_plus = (iface->conf->secondary_channel == -1) ? 0 : 1; |
| 70 | + sec_ch_factor = (iface->conf->secondary_channel == -1) ? -1 : 1; |
| 71 | + } |
| 72 | + |
| 73 | + wpa_printf(MSG_INFO, "%s:%d, bw(%u), n_chans(%d), num_channels(%d), sec_ch(%d)", |
| 74 | + __func__, __LINE__, bw, n_chans, mode->num_channels, iface->conf->secondary_channel); |
| 75 | |
| 76 | for (i = 0; i < mode->num_channels; i++) { |
| 77 | double total_weight; |
| 78 | struct acs_bias *bias, tmp_bias; |
| 79 | - bool update_best = true; |
| 80 | + bool update_best = true, has_candidate = true; |
| 81 | |
| 82 | best = chan = &mode->channels[i]; |
| 83 | + wpa_printf(MSG_INFO, |
| 84 | + "ACS: Channel[%d] %d: interference_factor %Lg", |
| 85 | + i, chan->chan, chan->interference_factor); |
| 86 | |
| 87 | /* Since in the current ACS implementation the first channel is |
| 88 | * always a primary channel, skip channels not available as |
| 89 | @@ -804,11 +817,12 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 90 | iface->conf->acs_exclude_dfs) |
| 91 | continue; |
| 92 | |
| 93 | - if (!is_in_chanlist(iface, chan)) |
| 94 | - continue; |
| 95 | - |
| 96 | - if (!is_in_freqlist(iface, chan)) |
| 97 | - continue; |
| 98 | + if (!is_in_chanlist(iface, chan) || !is_in_freqlist(iface, chan)) { |
| 99 | + if (is_24ghz_mode(mode->mode)) |
| 100 | + continue; |
| 101 | + else |
| 102 | + has_candidate = false; |
| 103 | + } |
| 104 | |
| 105 | if (chan->max_tx_power < iface->conf->min_tx_power) |
| 106 | continue; |
| 107 | @@ -817,7 +831,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 108 | iface->conf->country[2] == 0x4f) |
| 109 | continue; |
| 110 | |
| 111 | - if (!chan_bw_allowed(chan, bw, 1, 1)) { |
| 112 | + if (!chan_bw_allowed(chan, bw, ht40_plus, 1)) { |
| 113 | wpa_printf(MSG_DEBUG, |
| 114 | "ACS: Channel %d: BW %u is not supported", |
| 115 | chan->chan, bw); |
| 116 | @@ -838,7 +852,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 117 | } |
| 118 | |
| 119 | if (mode->mode == HOSTAPD_MODE_IEEE80211A && |
| 120 | - (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) { |
| 121 | + (iface->conf->ieee80211ac || iface->conf->ieee80211ax || |
| 122 | + iface->conf->ieee80211be)) { |
| 123 | if (hostapd_get_oper_chwidth(iface->conf) == |
| 124 | CONF_OPER_CHWIDTH_80MHZ && |
| 125 | !acs_usable_bw_chan(chan, ACS_BW80)) { |
| 126 | @@ -856,63 +871,89 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 127 | chan->chan); |
| 128 | continue; |
| 129 | } |
| 130 | - } |
| 131 | |
| 132 | - factor = 0; |
| 133 | - if (acs_usable_chan(chan)) |
| 134 | - factor = chan->interference_factor; |
| 135 | - total_weight = 1; |
| 136 | - |
| 137 | - for (j = 1; j < n_chans; j++) { |
| 138 | - adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); |
| 139 | - if (!adj_chan) |
| 140 | - break; |
| 141 | - |
| 142 | - if (!chan_bw_allowed(adj_chan, bw, 1, 0)) { |
| 143 | + if (iface->conf->ieee80211be && |
| 144 | + hostapd_get_oper_chwidth(iface->conf) == |
| 145 | + CONF_OPER_CHWIDTH_320MHZ && |
| 146 | + !acs_usable_bw_chan(chan, ACS_BW320)) { |
| 147 | wpa_printf(MSG_DEBUG, |
| 148 | - "ACS: PRI Channel %d: secondary channel %d BW %u is not supported", |
| 149 | - chan->chan, adj_chan->chan, bw); |
| 150 | - break; |
| 151 | + "ACS: Channel %d: not allowed as primary channel for 320 MHz bandwidth", |
| 152 | + chan->chan); |
| 153 | + continue; |
| 154 | } |
| 155 | + } |
| 156 | + |
| 157 | + factor = 0; |
| 158 | + total_weight = 0; |
| 159 | |
| 160 | - if (acs_usable_chan(adj_chan)) { |
| 161 | - factor += adj_chan->interference_factor; |
| 162 | + if (!is_24ghz_mode(mode->mode)) { |
| 163 | + /* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less |
| 164 | + * crowded primary channel if one was found in the segment */ |
| 165 | + if (acs_usable_chan(chan)) { |
| 166 | + factor += chan->interference_factor; |
| 167 | total_weight += 1; |
| 168 | - } else { |
| 169 | - update_best = false; |
| 170 | } |
| 171 | |
| 172 | - /* find the best channel in this segment */ |
| 173 | - if (update_best && |
| 174 | - adj_chan->interference_factor < |
| 175 | - best->interference_factor) |
| 176 | - best = adj_chan; |
| 177 | - } |
| 178 | + for (j = 1; j < n_chans; j++) { |
| 179 | + adj_chan = acs_find_chan(iface, chan->freq + j * 20); |
| 180 | + if (!adj_chan) |
| 181 | + break; |
| 182 | |
| 183 | - if (j != n_chans) { |
| 184 | - wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth", |
| 185 | - chan->chan); |
| 186 | - continue; |
| 187 | - } |
| 188 | + if (!chan_bw_allowed(adj_chan, bw, 1, 0)) { |
| 189 | + wpa_printf(MSG_DEBUG, |
| 190 | + "ACS: PRI Channel %d: secondary channel %d BW %u is not supported", |
| 191 | + chan->chan, adj_chan->chan, bw); |
| 192 | + break; |
| 193 | + } |
| 194 | |
| 195 | - /* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less |
| 196 | - * crowded primary channel if one was found in the segment */ |
| 197 | - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && |
| 198 | - chan != best) { |
| 199 | - wpa_printf(MSG_DEBUG, |
| 200 | - "ACS: promoting channel %d over %d (less interference %Lg/%Lg)", |
| 201 | - best->chan, chan->chan, |
| 202 | - chan->interference_factor, |
| 203 | - best->interference_factor); |
| 204 | - chan = best; |
| 205 | - } |
| 206 | + update_best = true; |
| 207 | + if (acs_usable_chan(adj_chan)) { |
| 208 | + factor += adj_chan->interference_factor; |
| 209 | + total_weight += 1; |
| 210 | + |
| 211 | + if (!is_in_chanlist(iface, adj_chan) || |
| 212 | + !is_in_freqlist(iface, adj_chan)) |
| 213 | + update_best = false; |
| 214 | + } else { |
| 215 | + update_best = false; |
| 216 | + } |
| 217 | + |
| 218 | + /* find the best channel in this segment */ |
| 219 | + if (update_best && (!has_candidate || |
| 220 | + adj_chan->interference_factor < best->interference_factor)) { |
| 221 | + best = adj_chan; |
| 222 | + has_candidate = true; |
| 223 | + } |
| 224 | + } |
| 225 | |
| 226 | - /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent |
| 227 | - * channel interference factor. */ |
| 228 | - if (is_24ghz_mode(mode->mode)) { |
| 229 | + if (j != n_chans || !has_candidate) { |
| 230 | + wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth", |
| 231 | + chan->chan); |
| 232 | + continue; |
| 233 | + } |
| 234 | + |
| 235 | + if (chan != best) { |
| 236 | + wpa_printf(MSG_INFO, |
| 237 | + "ACS: promoting channel %d over %d (less interference %Lg/%Lg)", |
| 238 | + best->chan, chan->chan, |
| 239 | + chan->interference_factor, |
| 240 | + best->interference_factor); |
| 241 | + chan = best; |
| 242 | + } |
| 243 | + } else { |
| 244 | for (j = 0; j < n_chans; j++) { |
| 245 | + /* Will set primary_channel / secondary_channel(40M case) weight to 1 */ |
| 246 | + tmp_chan = acs_find_chan(iface, chan->freq + |
| 247 | + (j * 20) * sec_ch_factor); |
| 248 | + if (tmp_chan && acs_usable_chan(tmp_chan)) { |
| 249 | + factor += tmp_chan->interference_factor; |
| 250 | + total_weight += 1; |
| 251 | + } |
| 252 | + |
| 253 | + /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent channel |
| 254 | + interference factor, separately for primary/secondary channel. */ |
| 255 | adj_chan = acs_find_chan(iface, chan->freq + |
| 256 | - (j * 20) - 5); |
| 257 | + ((j * 20) - 5) * sec_ch_factor); |
| 258 | if (adj_chan && acs_usable_chan(adj_chan)) { |
| 259 | factor += ACS_ADJ_WEIGHT * |
| 260 | adj_chan->interference_factor; |
| 261 | @@ -920,7 +961,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 262 | } |
| 263 | |
| 264 | adj_chan = acs_find_chan(iface, chan->freq + |
| 265 | - (j * 20) - 10); |
| 266 | + ((j * 20) - 10) * sec_ch_factor); |
| 267 | if (adj_chan && acs_usable_chan(adj_chan)) { |
| 268 | factor += ACS_NEXT_ADJ_WEIGHT * |
| 269 | adj_chan->interference_factor; |
| 270 | @@ -928,7 +969,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 271 | } |
| 272 | |
| 273 | adj_chan = acs_find_chan(iface, chan->freq + |
| 274 | - (j * 20) + 5); |
| 275 | + ((j * 20) + 5) * sec_ch_factor); |
| 276 | if (adj_chan && acs_usable_chan(adj_chan)) { |
| 277 | factor += ACS_ADJ_WEIGHT * |
| 278 | adj_chan->interference_factor; |
| 279 | @@ -936,7 +977,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 280 | } |
| 281 | |
| 282 | adj_chan = acs_find_chan(iface, chan->freq + |
| 283 | - (j * 20) + 10); |
| 284 | + ((j * 20) + 10) * sec_ch_factor); |
| 285 | if (adj_chan && acs_usable_chan(adj_chan)) { |
| 286 | factor += ACS_NEXT_ADJ_WEIGHT * |
| 287 | adj_chan->interference_factor; |
| 288 | @@ -945,7 +986,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | - factor /= total_weight; |
| 293 | + if (total_weight) |
| 294 | + factor /= total_weight; |
| 295 | |
| 296 | bias = NULL; |
| 297 | if (iface->conf->acs_chan_bias) { |
| 298 | @@ -964,11 +1006,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, |
| 299 | |
| 300 | if (bias) { |
| 301 | factor *= bias->bias; |
| 302 | - wpa_printf(MSG_DEBUG, |
| 303 | + wpa_printf(MSG_INFO, |
| 304 | "ACS: * channel %d: total interference = %Lg (%f bias)", |
| 305 | chan->chan, factor, bias->bias); |
| 306 | } else { |
| 307 | - wpa_printf(MSG_DEBUG, |
| 308 | + wpa_printf(MSG_INFO, |
| 309 | "ACS: * channel %d: total interference = %Lg", |
| 310 | chan->chan, factor); |
| 311 | } |
| 312 | @@ -1021,19 +1063,12 @@ acs_find_ideal_chan(struct hostapd_iface *iface) |
| 313 | goto bw_selected; |
| 314 | } |
| 315 | |
| 316 | - /* TODO: HT40- support */ |
| 317 | - |
| 318 | - if (iface->conf->ieee80211n && |
| 319 | - iface->conf->secondary_channel == -1) { |
| 320 | - wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); |
| 321 | - return NULL; |
| 322 | - } |
| 323 | - |
| 324 | if (iface->conf->ieee80211n && |
| 325 | iface->conf->secondary_channel) |
| 326 | n_chans = 2; |
| 327 | |
| 328 | - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { |
| 329 | + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax || |
| 330 | + iface->conf->ieee80211be) { |
| 331 | switch (hostapd_get_oper_chwidth(iface->conf)) { |
| 332 | case CONF_OPER_CHWIDTH_80MHZ: |
| 333 | n_chans = 4; |
| 334 | @@ -1043,6 +1078,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) |
| 335 | break; |
| 336 | default: |
| 337 | break; |
| 338 | + /* 320 is supported only in 6GHz 11be mode */ |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | @@ -1063,7 +1099,7 @@ bw_selected: |
| 343 | } |
| 344 | |
| 345 | if (ideal_chan) { |
| 346 | - wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg", |
| 347 | + wpa_printf(MSG_INFO, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg", |
| 348 | ideal_chan->chan, ideal_chan->freq, ideal_factor); |
| 349 | |
| 350 | #ifdef CONFIG_IEEE80211BE |
| 351 | @@ -1078,6 +1114,21 @@ bw_selected: |
| 352 | return rand_chan; |
| 353 | } |
| 354 | |
| 355 | +static int acs_get_center_freq_320mhz(int channel) |
| 356 | +{ |
| 357 | + if (channel >= 1 && channel <= 45) |
| 358 | + return 31; |
| 359 | + else if (channel >= 49 && channel <= 77) |
| 360 | + return 63; |
| 361 | + else if (channel >= 81 && channel <= 109) |
| 362 | + return 95; |
| 363 | + else if (channel >= 113 && channel <= 141) |
| 364 | + return 127; |
| 365 | + else if (channel >= 145 && channel <= 173) |
| 366 | + return 159; |
| 367 | + else |
| 368 | + return 191; |
| 369 | +} |
| 370 | |
| 371 | static void acs_adjust_secondary(struct hostapd_iface *iface) |
| 372 | { |
| 373 | @@ -1104,10 +1155,11 @@ static void acs_adjust_secondary(struct hostapd_iface *iface) |
| 374 | static void acs_adjust_center_freq(struct hostapd_iface *iface) |
| 375 | { |
| 376 | int center; |
| 377 | + u8 bw = hostapd_get_oper_chwidth(iface->conf); |
| 378 | |
| 379 | - wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency"); |
| 380 | + wpa_printf(MSG_DEBUG, "ACS: Adjusting center frequency"); |
| 381 | |
| 382 | - switch (hostapd_get_oper_chwidth(iface->conf)) { |
| 383 | + switch (bw) { |
| 384 | case CONF_OPER_CHWIDTH_USE_HT: |
| 385 | if (iface->conf->secondary_channel && |
| 386 | iface->freq >= 2400 && iface->freq < 2500) |
| 387 | @@ -1121,6 +1173,9 @@ static void acs_adjust_center_freq(struct hostapd_iface *iface) |
| 388 | case CONF_OPER_CHWIDTH_80MHZ: |
| 389 | center = acs_get_bw_center_chan(iface->freq, ACS_BW80); |
| 390 | break; |
| 391 | + case CONF_OPER_CHWIDTH_320MHZ: |
| 392 | + center = acs_get_center_freq_320mhz(iface->conf->channel); |
| 393 | + break; |
| 394 | case CONF_OPER_CHWIDTH_160MHZ: |
| 395 | center = acs_get_bw_center_chan(iface->freq, ACS_BW160); |
| 396 | break; |
| 397 | @@ -1128,7 +1183,7 @@ static void acs_adjust_center_freq(struct hostapd_iface *iface) |
| 398 | /* TODO: How can this be calculated? Adjust |
| 399 | * acs_find_ideal_chan() */ |
| 400 | wpa_printf(MSG_INFO, |
| 401 | - "ACS: Only VHT20/40/80/160 is supported now"); |
| 402 | + "ACS: Only VHT20/40/80/160 EHT320 is supported now"); |
| 403 | return; |
| 404 | } |
| 405 | |
| 406 | @@ -1191,7 +1246,8 @@ static void acs_study(struct hostapd_iface *iface) |
| 407 | iface->conf->punct_bitmap = ideal_chan->punct_bitmap; |
| 408 | #endif /* CONFIG_IEEE80211BE */ |
| 409 | |
| 410 | - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { |
| 411 | + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax || |
| 412 | + iface->conf->ieee80211be) { |
| 413 | acs_adjust_secondary(iface); |
| 414 | acs_adjust_center_freq(iface); |
| 415 | } |
| 416 | @@ -1270,12 +1326,6 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, |
| 417 | iface->conf->acs_exclude_dfs)) |
| 418 | continue; |
| 419 | |
| 420 | - if (!is_in_chanlist(iface, chan)) |
| 421 | - continue; |
| 422 | - |
| 423 | - if (!is_in_freqlist(iface, chan)) |
| 424 | - continue; |
| 425 | - |
| 426 | if (chan->max_tx_power < iface->conf->min_tx_power) |
| 427 | continue; |
| 428 | |
| 429 | -- |
| 430 | 2.25.1 |
| 431 | |