mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-20 02:43:38 +00:00
422 lines
13 KiB
Diff
422 lines
13 KiB
Diff
From 0fffe1c539734f9dc26a80fb80eddb7ea1f1af46 Mon Sep 17 00:00:00 2001
|
|
From: Hari Chandrakanthan <quic_haric@quicinc.com>
|
|
Date: Mon, 31 Oct 2022 19:51:32 +0530
|
|
Subject: [PATCH] hostapd : awgn - fix new channel selection logic
|
|
|
|
From the list of channels allowed by Australia,
|
|
only one 320 MHz operable channel is available.
|
|
|
|
So if awgn is detected when operating in 320 MHz, the ap
|
|
needs to reduce its bandwidth to next max available bw 160 MHz.
|
|
|
|
But with current design if no other 320 Mhz channel is available,
|
|
hostapd bails out with a log saying that no channel with 320 MHz is available.
|
|
we don't check for next max available bandwidth in our current design and
|
|
this leads to ap to remain in the same channel even if awgn is detected.
|
|
|
|
So the channel selection logic is changed in a way that the next max
|
|
available bandwidth is searched if no new channel is available for current
|
|
bandwidth. The search continues till 20 MHz bandwidth.
|
|
|
|
This generic logic will help to fix similar issues in future.
|
|
|
|
Also optimized the channel selection logic by looping over the list of all
|
|
the channels only once.
|
|
|
|
Signed-off-by: Hari Chandrakanthan <quic_haric@quicinc.com>
|
|
---
|
|
src/ap/interference.c | 249 ++++++++++++++++++++++++++++++++------------------
|
|
1 file changed, 160 insertions(+), 89 deletions(-)
|
|
|
|
diff --git a/src/ap/interference.c b/src/ap/interference.c
|
|
index 4148489..1d66d6f 100644
|
|
--- a/src/ap/interference.c
|
|
+++ b/src/ap/interference.c
|
|
@@ -46,6 +46,23 @@
|
|
#include "eloop.h"
|
|
#include "hw_features.h"
|
|
|
|
+static bool is_chan_disabled(struct hostapd_hw_modes *mode, int chan_num)
|
|
+{
|
|
+ int chan_disabled = 1;
|
|
+ int i;
|
|
+ struct hostapd_channel_data *temp_chan;
|
|
+
|
|
+ for (i = 0; i < mode->num_channels; i++) {
|
|
+ temp_chan = &mode->channels[i];
|
|
+ if (temp_chan->chan == chan_num &&
|
|
+ (!(temp_chan->flag & HOSTAPD_CHAN_DISABLED))) {
|
|
+ chan_disabled = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return chan_disabled;
|
|
+}
|
|
+
|
|
/*
|
|
* intf_awgn_chan_range_available - check whether the channel can operate
|
|
* in the given bandwidth in 6Ghz
|
|
@@ -63,8 +80,11 @@ static int intf_awgn_chan_range_available(struct hostapd_hw_modes *mode,
|
|
193, 209};
|
|
int allowed_160_6g[] = {1, 33, 65, 97, 129, 161, 193};
|
|
int allowed_320_6g[] = {1, 65, 129, 33, 97, 161};
|
|
+ int allowed_arr_size = 0;
|
|
+ int *allowed_arr = NULL;
|
|
int chan_idx_match = 0;
|
|
- int i;
|
|
+ int chan_disabled = 0;
|
|
+ int i, j;
|
|
|
|
first_chan = &mode->channels[first_chan_idx];
|
|
|
|
@@ -77,33 +97,40 @@ static int intf_awgn_chan_range_available(struct hostapd_hw_modes *mode,
|
|
if (num_chans == 1)
|
|
return 1;
|
|
|
|
- if (num_chans == 2) { /* 40Mhz channel */
|
|
- for (i = 0; i < ARRAY_SIZE(allowed_40_6g); i++) {
|
|
- if (first_chan->chan == allowed_40_6g[i]) {
|
|
- chan_idx_match = 1;
|
|
- break;
|
|
- }
|
|
- }
|
|
- } else if (num_chans == 4) { /* 80Mhz channel */
|
|
- for (i = 0; i < ARRAY_SIZE(allowed_80_6g); i++) {
|
|
- if (first_chan->chan == allowed_80_6g[i]) {
|
|
- chan_idx_match = 1;
|
|
- break;
|
|
- }
|
|
- }
|
|
- } else if (num_chans == 8) { /* 160Mhz channel */
|
|
- for (i = 0; i < ARRAY_SIZE(allowed_160_6g); i++) {
|
|
- if (first_chan->chan == allowed_160_6g[i]) {
|
|
- chan_idx_match = 1;
|
|
- break;
|
|
+ switch (num_chans) {
|
|
+ case 2:
|
|
+ allowed_arr_size = ARRAY_SIZE(allowed_40_6g);
|
|
+ allowed_arr = allowed_40_6g;
|
|
+ break;
|
|
+ case 4:
|
|
+ allowed_arr_size = ARRAY_SIZE(allowed_80_6g);
|
|
+ allowed_arr = allowed_80_6g;
|
|
+ break;
|
|
+ case 8:
|
|
+ allowed_arr_size = ARRAY_SIZE(allowed_160_6g);
|
|
+ allowed_arr = allowed_160_6g;
|
|
+ break;
|
|
+ case 16:
|
|
+ allowed_arr_size = ARRAY_SIZE(allowed_320_6g);
|
|
+ allowed_arr = allowed_320_6g;
|
|
+ break;
|
|
+ default:
|
|
+ allowed_arr_size = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* check whether all the 20 MHz channels in the given operating range is enabled */
|
|
+ for (i = 0; i < allowed_arr_size; i++) {
|
|
+ if (first_chan->chan == allowed_arr[i]) {
|
|
+ for (j = 1; j <= num_chans - 1; j++) {
|
|
+ if (is_chan_disabled(mode, first_chan->chan + j * 4)) {
|
|
+ chan_disabled = 1;
|
|
+ break;
|
|
+ }
|
|
}
|
|
- }
|
|
- } else if (num_chans == 16) { /* 320Mhz channel */
|
|
- for (i = 0; i < ARRAY_SIZE(allowed_320_6g); i++) {
|
|
- if (first_chan->chan == allowed_320_6g[i]) {
|
|
+ if (!chan_disabled)
|
|
chan_idx_match = 1;
|
|
- break;
|
|
- }
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
@@ -159,21 +186,28 @@ int get_centre_freq_6g(int chan_idx, int chan_width, int *centre_freq)
|
|
|
|
|
|
/*
|
|
- *intf_awgn_find_channel - find the channel that can operate with bandwidth chan_width.
|
|
- If idx doesn't match with index of any of the existing channel, then the api
|
|
- returns the total number of available chandefs that supports the provided bandwidth
|
|
- * @idx - index of the channel
|
|
- * @chan_width - bandwidth of the channel
|
|
+ * intf_awgn_find_channel_list - find the list of channels that can operate with
|
|
+ channel width chan_width and not present within the range of current operating range.
|
|
+ returns the total number of available chandefs that supports the provided bandwidth
|
|
+ * @chan_width - channel width to be checked
|
|
+ * @curr_centre_freq - current centre frequency
|
|
+ * @curr_chan_width - current channel width
|
|
+ * @chandef_list - pointer array to hold the list of valid available chandef
|
|
*/
|
|
-static int intf_awgn_find_channel(struct hostapd_iface *iface,
|
|
- struct hostapd_channel_data **ret_chan,
|
|
- int idx, int chan_width, int cs1)
|
|
+static int intf_awgn_find_channel_list(struct hostapd_iface *iface,
|
|
+ int chan_width, int curr_centre_freq,
|
|
+ int curr_chan_width,
|
|
+ struct hostapd_channel_data ***chandef_list)
|
|
{
|
|
struct hostapd_hw_modes *mode = iface->current_mode;
|
|
struct hostapd_channel_data *chan;
|
|
int i, channel_idx = 0, n_chans;
|
|
- int temp_centre_freq;
|
|
+ int new_centre_freq;
|
|
int ret;
|
|
+ int curr_start_freq;
|
|
+ int curr_end_freq;
|
|
+ int new_start_freq;
|
|
+ int new_end_freq;
|
|
|
|
switch (chan_width) {
|
|
case CHAN_WIDTH_20_NOHT:
|
|
@@ -198,6 +232,9 @@ static int intf_awgn_find_channel(struct hostapd_iface *iface,
|
|
break;
|
|
}
|
|
|
|
+ curr_start_freq = curr_centre_freq - channel_width_to_int(curr_chan_width) / 2;
|
|
+ curr_end_freq = curr_centre_freq + channel_width_to_int(curr_chan_width) / 2;
|
|
+
|
|
for (i = 0; i < mode->num_channels; i++) {
|
|
chan = &mode->channels[i];
|
|
|
|
@@ -216,44 +253,49 @@ static int intf_awgn_find_channel(struct hostapd_iface *iface,
|
|
continue;
|
|
}
|
|
|
|
- if (chan_width == CHAN_WIDTH_320) {
|
|
- ret = get_centre_freq_6g(chan->chan, CHAN_WIDTH_320,
|
|
- &temp_centre_freq);
|
|
- if (ret) {
|
|
- wpa_printf(MSG_ERROR,
|
|
- "AWGN : couldn't find centre freq for chan : %d"
|
|
- " chan_width : %d", chan->chan, CHAN_WIDTH_320);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (abs(temp_centre_freq - cs1) < 320) {
|
|
- wpa_printf(MSG_DEBUG,
|
|
- "AWGN: channel %d is a overlapping channel so skipping",
|
|
- chan->freq);
|
|
- continue;
|
|
- }
|
|
+ ret = get_centre_freq_6g(chan->chan, chan_width,
|
|
+ &new_centre_freq);
|
|
+ if (ret) {
|
|
+ wpa_printf(MSG_ERROR,
|
|
+ "AWGN : couldn't find centre freq for chan : %d"
|
|
+ " chan_width : %d", chan->chan, chan_width);
|
|
+ return 0;
|
|
}
|
|
|
|
- if (ret_chan && idx == channel_idx) {
|
|
- wpa_printf(MSG_DEBUG, "AWGN: Selected channel %d (%d)",
|
|
- chan->freq, chan->chan);
|
|
- *ret_chan = chan;
|
|
- return idx;
|
|
+ new_start_freq = new_centre_freq - channel_width_to_int(chan_width) / 2;
|
|
+ new_end_freq = new_centre_freq + channel_width_to_int(chan_width) / 2;
|
|
+
|
|
+ /* check whether new operating range is outside the current
|
|
+ * operating range since current operating range contains awgn
|
|
+ * interference
|
|
+ */
|
|
+ if (((new_start_freq > curr_start_freq) && (new_start_freq < curr_end_freq)) ||
|
|
+ ((new_end_freq > curr_start_freq) && (new_end_freq < curr_end_freq)) ||
|
|
+ ((new_centre_freq > curr_start_freq && new_centre_freq < curr_end_freq))) {
|
|
+ wpa_printf(MSG_DEBUG,
|
|
+ "AWGN : freq range overlap new_start_freq : %d"
|
|
+ " new_end_freq : %d curr_start_freq : %d"
|
|
+ " curr_end_freq : %d centre_freq : %d",
|
|
+ new_start_freq, new_end_freq, curr_start_freq,
|
|
+ curr_end_freq, new_centre_freq);
|
|
+ continue;
|
|
}
|
|
|
|
- wpa_printf(MSG_DEBUG, "AWGN: Adding channel %d (%d)",
|
|
+ wpa_printf(MSG_DEBUG, "AWGN: Adding channel %d (%d) to valid chandef list",
|
|
chan->freq, chan->chan);
|
|
+ (*chandef_list)[channel_idx] = chan;
|
|
channel_idx++;
|
|
}
|
|
+
|
|
return channel_idx;
|
|
}
|
|
|
|
enum chan_seg {
|
|
- SEG_PRI20 = 0x1,
|
|
- SEG_SEC20 = 0x2,
|
|
- SEG_SEC40_LOW = 0x4,
|
|
- SEG_SEC40_UP = 0x8,
|
|
- SEG_SEC40 = 0xC,
|
|
+ SEG_PRI20 = 0x1,
|
|
+ SEG_SEC20 = 0x2,
|
|
+ SEG_SEC40_LOW = 0x4,
|
|
+ SEG_SEC40_UP = 0x8,
|
|
+ SEG_SEC40 = 0xC,
|
|
SEG_SEC80_LOW = 0x10,
|
|
SEG_SEC80_LOW_UP = 0x20,
|
|
SEG_SEC80_UP_LOW = 0x40,
|
|
@@ -270,6 +312,31 @@ enum chan_seg {
|
|
SEG_SEC160 = 0xFF00,
|
|
};
|
|
|
|
+int get_next_max_width(int chan_width)
|
|
+{
|
|
+ int next_max_width;
|
|
+
|
|
+ switch (chan_width) {
|
|
+ case CHAN_WIDTH_320:
|
|
+ next_max_width = CHAN_WIDTH_160;
|
|
+ break;
|
|
+ case CHAN_WIDTH_160:
|
|
+ next_max_width = CHAN_WIDTH_80;
|
|
+ break;
|
|
+ case CHAN_WIDTH_80:
|
|
+ next_max_width = CHAN_WIDTH_40;
|
|
+ break;
|
|
+ case CHAN_WIDTH_40:
|
|
+ next_max_width = CHAN_WIDTH_20;
|
|
+ break;
|
|
+ default:
|
|
+ next_max_width = CHAN_WIDTH_20_NOHT;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return next_max_width;
|
|
+}
|
|
+
|
|
/*
|
|
* hostapd_intf_awgn_detected - awgn interference is detected in the operating channel.
|
|
* The interference channel information is available as a
|
|
@@ -283,14 +350,16 @@ int hostapd_intf_awgn_detected(struct hostapd_iface *iface, int freq, int chan_w
|
|
struct csa_settings settings;
|
|
struct hostapd_channel_data *chan_data = NULL;
|
|
struct hostapd_channel_data *chan_temp = NULL;
|
|
+ struct hostapd_channel_data **available_chandef_list = NULL;
|
|
int ret;
|
|
unsigned int i;
|
|
u32 _rand;
|
|
u32 chan_idx;
|
|
- int num_available_chandefs;
|
|
+ int num_available_chandefs = 0;
|
|
u8 channel_switch = 0;
|
|
int new_chan_width;
|
|
int new_centre_freq;
|
|
+ int temp_width;
|
|
struct hostapd_hw_modes *mode = iface->current_mode;
|
|
|
|
wpa_printf(MSG_DEBUG,
|
|
@@ -302,7 +371,7 @@ int hostapd_intf_awgn_detected(struct hostapd_iface *iface, int freq, int chan_w
|
|
|
|
if (iface->conf->discard_6g_awgn_event) {
|
|
wpa_printf(MSG_DEBUG, "discard_6g_awgn_event set ignoring"
|
|
- "AWGN DETECT event from driver");
|
|
+ " AWGN DETECT event from driver");
|
|
return 0;
|
|
}
|
|
|
|
@@ -310,47 +379,47 @@ int hostapd_intf_awgn_detected(struct hostapd_iface *iface, int freq, int chan_w
|
|
if (!chan_bw_interference_bitmap || (chan_bw_interference_bitmap & SEG_PRI20))
|
|
channel_switch = 1;
|
|
|
|
+ available_chandef_list = os_zalloc(sizeof(struct hostapd_channel_data *) *
|
|
+ mode->num_channels);
|
|
if (channel_switch) {
|
|
- /* Find a random channel to be switched */
|
|
- num_available_chandefs = intf_awgn_find_channel(iface, NULL, 0,
|
|
- chan_width, cf1);
|
|
+ /* find a random channel to be switched */
|
|
+ temp_width = chan_width;
|
|
+
|
|
+ while (temp_width > CHAN_WIDTH_20_NOHT) {
|
|
+ num_available_chandefs = intf_awgn_find_channel_list(iface,
|
|
+ temp_width,
|
|
+ cf1, chan_width,
|
|
+ &available_chandef_list);
|
|
+ if (num_available_chandefs == 0)
|
|
+ temp_width = get_next_max_width(temp_width);
|
|
+ else
|
|
+ break;
|
|
+ }
|
|
+
|
|
if (num_available_chandefs == 0) {
|
|
wpa_printf(MSG_ERROR, "AWGN: no available_chandefs");
|
|
- return 0;
|
|
+ goto exit;
|
|
}
|
|
|
|
if (os_get_random((u8 *)&_rand, sizeof(_rand)) < 0) {
|
|
wpa_printf(MSG_ERROR, "AWGN: couldn't get random number");
|
|
- return 0;
|
|
+ goto exit;
|
|
}
|
|
|
|
chan_idx = _rand % num_available_chandefs;
|
|
- intf_awgn_find_channel(iface, &chan_data, chan_idx, chan_width, cf1);
|
|
+
|
|
+ chan_data = available_chandef_list[chan_idx];
|
|
|
|
if (!chan_data) {
|
|
- wpa_printf(MSG_ERROR, "AWGN: no random channel found, chan idx : %d",
|
|
+ wpa_printf(MSG_ERROR, "AWGN: channel info not available for chan_idx : %d",
|
|
chan_idx);
|
|
- return 0;
|
|
+ goto exit;
|
|
}
|
|
|
|
- if(chan_data->freq == freq) {
|
|
- /* New random channel is same as operating channel
|
|
- * so choose another channel
|
|
- */
|
|
- chan_data = NULL;
|
|
- chan_idx = (chan_idx + 1) % num_available_chandefs;
|
|
- intf_awgn_find_channel(iface, &chan_data, chan_idx, chan_width, cf1);
|
|
- if (!chan_data) {
|
|
- wpa_printf(MSG_ERROR,
|
|
- "AWGN: random channel not found, chan idx : %d",
|
|
- chan_idx);
|
|
- return 0;
|
|
- }
|
|
- }
|
|
+ new_chan_width = temp_width;
|
|
|
|
wpa_printf(MSG_DEBUG, "AWGN: got random channel %d (%d)",
|
|
chan_data->freq, chan_data->chan);
|
|
- new_chan_width = chan_width;
|
|
} else {
|
|
/* interference is not present in the primary 20Mhz, so reduce bandwidth*/
|
|
for (i = 0; i < mode->num_channels; i++) {
|
|
@@ -360,7 +429,7 @@ int hostapd_intf_awgn_detected(struct hostapd_iface *iface, int freq, int chan_w
|
|
}
|
|
if (!chan_data) {
|
|
wpa_printf(MSG_ERROR, "AWGN : no channel found");
|
|
- return 0;
|
|
+ goto exit;
|
|
}
|
|
|
|
if ((chan_width > CHAN_WIDTH_160) &&
|
|
@@ -386,7 +455,7 @@ int hostapd_intf_awgn_detected(struct hostapd_iface *iface, int freq, int chan_w
|
|
wpa_printf(MSG_ERROR,
|
|
"AWGN : couldn't find centre freq for chan : %d"
|
|
" chan_width : %d", chan_data->chan, new_chan_width);
|
|
- return 0;
|
|
+ goto exit;
|
|
}
|
|
} else {
|
|
new_centre_freq = chan_data->freq;
|
|
@@ -442,5 +511,7 @@ int hostapd_intf_awgn_detected(struct hostapd_iface *iface, int freq, int chan_w
|
|
}
|
|
}
|
|
|
|
+exit:
|
|
+ os_free(available_chandef_list);
|
|
return 0;
|
|
}
|
|
--
|
|
2.7.4
|
|
|