Extend offloaded ACS QCA vendor command to support VHT
Update ACS driver offload feature for VHT configuration. In addition, this allows the chanlist parameter to be used to specify which channels are included as options for the offloaded ACS case. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
0fd52a612a
commit
857d94225a
15 changed files with 229 additions and 51 deletions
|
@ -775,6 +775,24 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
|
||||||
|
{
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
/* for backwards compatibility, translate ' ' in conf str to ',' */
|
||||||
|
pos = val;
|
||||||
|
while (pos) {
|
||||||
|
pos = os_strchr(pos, ' ');
|
||||||
|
if (pos)
|
||||||
|
*pos++ = ',';
|
||||||
|
}
|
||||||
|
if (freq_range_list_parse(&conf->acs_ch_list, val))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hostapd_parse_intlist(int **int_list, char *val)
|
static int hostapd_parse_intlist(int **int_list, char *val)
|
||||||
{
|
{
|
||||||
int *list;
|
int *list;
|
||||||
|
@ -2542,12 +2560,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
line);
|
line);
|
||||||
return 1;
|
return 1;
|
||||||
#else /* CONFIG_ACS */
|
#else /* CONFIG_ACS */
|
||||||
|
conf->acs = 1;
|
||||||
conf->channel = 0;
|
conf->channel = 0;
|
||||||
#endif /* CONFIG_ACS */
|
#endif /* CONFIG_ACS */
|
||||||
} else
|
} else {
|
||||||
conf->channel = atoi(pos);
|
conf->channel = atoi(pos);
|
||||||
|
conf->acs = conf->channel == 0;
|
||||||
|
}
|
||||||
} else if (os_strcmp(buf, "chanlist") == 0) {
|
} else if (os_strcmp(buf, "chanlist") == 0) {
|
||||||
if (hostapd_parse_intlist(&conf->chanlist, pos)) {
|
if (hostapd_parse_chanlist(conf, pos)) {
|
||||||
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
|
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
|
||||||
line);
|
line);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -170,8 +170,11 @@ channel=1
|
||||||
|
|
||||||
# Channel list restriction. This option allows hostapd to select one of the
|
# Channel list restriction. This option allows hostapd to select one of the
|
||||||
# provided channels when a channel should be automatically selected.
|
# provided channels when a channel should be automatically selected.
|
||||||
# Default: not set (allow any enabled channel to be selected)
|
# Channel list can be provided as range using hyphen ('-') or individual
|
||||||
|
# channels can be specified by space (' ') seperated values
|
||||||
|
# Default: all channels allowed in selected hw_mode
|
||||||
#chanlist=100 104 108 112 116
|
#chanlist=100 104 108 112 116
|
||||||
|
#chanlist=1 6 11-13
|
||||||
|
|
||||||
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
||||||
beacon_int=100
|
beacon_int=100
|
||||||
|
|
10
src/ap/acs.c
10
src/ap/acs.c
|
@ -479,16 +479,10 @@ static int acs_usable_chan(struct hostapd_channel_data *chan)
|
||||||
static int is_in_chanlist(struct hostapd_iface *iface,
|
static int is_in_chanlist(struct hostapd_iface *iface,
|
||||||
struct hostapd_channel_data *chan)
|
struct hostapd_channel_data *chan)
|
||||||
{
|
{
|
||||||
int *entry;
|
if (!iface->conf->acs_ch_list.num)
|
||||||
|
|
||||||
if (!iface->conf->chanlist)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
|
return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
|
||||||
if (*entry == chan->chan)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,8 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||||
conf->corrupt_gtk_rekey_mic_probability = 0.0;
|
conf->corrupt_gtk_rekey_mic_probability = 0.0;
|
||||||
#endif /* CONFIG_TESTING_OPTIONS */
|
#endif /* CONFIG_TESTING_OPTIONS */
|
||||||
|
|
||||||
|
conf->acs = 0;
|
||||||
|
conf->acs_ch_list.num = 0;
|
||||||
#ifdef CONFIG_ACS
|
#ifdef CONFIG_ACS
|
||||||
conf->acs_num_scans = 5;
|
conf->acs_num_scans = 5;
|
||||||
#endif /* CONFIG_ACS */
|
#endif /* CONFIG_ACS */
|
||||||
|
@ -579,7 +581,7 @@ void hostapd_config_free(struct hostapd_config *conf)
|
||||||
os_free(conf->bss);
|
os_free(conf->bss);
|
||||||
os_free(conf->supported_rates);
|
os_free(conf->supported_rates);
|
||||||
os_free(conf->basic_rates);
|
os_free(conf->basic_rates);
|
||||||
os_free(conf->chanlist);
|
os_free(conf->acs_ch_list.range);
|
||||||
os_free(conf->driver_params);
|
os_free(conf->driver_params);
|
||||||
#ifdef CONFIG_ACS
|
#ifdef CONFIG_ACS
|
||||||
os_free(conf->acs_chan_bias);
|
os_free(conf->acs_chan_bias);
|
||||||
|
|
|
@ -568,7 +568,8 @@ struct hostapd_config {
|
||||||
int fragm_threshold;
|
int fragm_threshold;
|
||||||
u8 send_probe_response;
|
u8 send_probe_response;
|
||||||
u8 channel;
|
u8 channel;
|
||||||
int *chanlist;
|
u8 acs;
|
||||||
|
struct wpa_freq_range_list acs_ch_list;
|
||||||
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||||
enum {
|
enum {
|
||||||
LONG_PREAMBLE = 0,
|
LONG_PREAMBLE = 0,
|
||||||
|
|
|
@ -715,13 +715,66 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
|
||||||
int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||||
{
|
{
|
||||||
struct drv_acs_params params;
|
struct drv_acs_params params;
|
||||||
|
int ret, i, acs_ch_list_all = 0;
|
||||||
|
u8 *channels = NULL;
|
||||||
|
unsigned int num_channels = 0;
|
||||||
|
struct hostapd_hw_modes *mode;
|
||||||
|
|
||||||
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
|
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
os_memset(¶ms, 0, sizeof(params));
|
os_memset(¶ms, 0, sizeof(params));
|
||||||
params.hw_mode = hapd->iface->conf->hw_mode;
|
params.hw_mode = hapd->iface->conf->hw_mode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If no chanlist config parameter is provided, include all enabled
|
||||||
|
* channels of the selected hw_mode.
|
||||||
|
*/
|
||||||
|
if (!hapd->iface->conf->acs_ch_list.num)
|
||||||
|
acs_ch_list_all = 1;
|
||||||
|
|
||||||
|
mode = hapd->iface->current_mode;
|
||||||
|
if (mode == NULL)
|
||||||
|
return -1;
|
||||||
|
channels = os_malloc(mode->num_channels);
|
||||||
|
if (channels == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < mode->num_channels; i++) {
|
||||||
|
struct hostapd_channel_data *chan = &mode->channels[i];
|
||||||
|
if (!acs_ch_list_all &&
|
||||||
|
!freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
|
||||||
|
chan->chan))
|
||||||
|
continue;
|
||||||
|
if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||||
|
channels[num_channels++] = chan->chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.ch_list = channels;
|
||||||
|
params.ch_list_len = num_channels;
|
||||||
|
|
||||||
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
|
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
|
||||||
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
|
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
|
||||||
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
|
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
|
||||||
return hapd->driver->do_acs(hapd->drv_priv, ¶ms);
|
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
|
||||||
|
params.ch_width = 20;
|
||||||
|
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
|
||||||
|
params.ch_width = 40;
|
||||||
|
|
||||||
|
/* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
|
||||||
|
*/
|
||||||
|
if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
|
||||||
|
if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||||
|
params.ch_width = 80;
|
||||||
|
else if (hapd->iface->conf->vht_oper_chwidth ==
|
||||||
|
VHT_CHANWIDTH_160MHZ ||
|
||||||
|
hapd->iface->conf->vht_oper_chwidth ==
|
||||||
|
VHT_CHANWIDTH_80P80MHZ)
|
||||||
|
params.ch_width = 160;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms);
|
||||||
|
os_free(channels);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
10
src/ap/dfs.c
10
src/ap/dfs.c
|
@ -165,16 +165,10 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||||
static int is_in_chanlist(struct hostapd_iface *iface,
|
static int is_in_chanlist(struct hostapd_iface *iface,
|
||||||
struct hostapd_channel_data *chan)
|
struct hostapd_channel_data *chan)
|
||||||
{
|
{
|
||||||
int *entry;
|
if (!iface->conf->acs_ch_list.num)
|
||||||
|
|
||||||
if (!iface->conf->chanlist)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
|
return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
|
||||||
if (*entry == chan->chan)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -532,9 +532,8 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
|
||||||
|
|
||||||
#ifdef CONFIG_ACS
|
#ifdef CONFIG_ACS
|
||||||
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||||
u8 pri_channel, u8 sec_channel)
|
struct acs_selected_channels *acs_res)
|
||||||
{
|
{
|
||||||
int channel;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (hapd->iconf->channel) {
|
if (hapd->iconf->channel) {
|
||||||
|
@ -543,29 +542,55 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
|
hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
|
||||||
|
|
||||||
channel = pri_channel;
|
if (!acs_res->pri_channel) {
|
||||||
if (!channel) {
|
|
||||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
HOSTAPD_LEVEL_WARNING,
|
HOSTAPD_LEVEL_WARNING,
|
||||||
"driver switched to bad channel");
|
"driver switched to bad channel");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hapd->iconf->channel = channel;
|
hapd->iconf->channel = acs_res->pri_channel;
|
||||||
|
hapd->iconf->acs = 1;
|
||||||
|
|
||||||
if (sec_channel == 0)
|
if (acs_res->sec_channel == 0)
|
||||||
hapd->iconf->secondary_channel = 0;
|
hapd->iconf->secondary_channel = 0;
|
||||||
else if (sec_channel < pri_channel)
|
else if (acs_res->sec_channel < acs_res->pri_channel)
|
||||||
hapd->iconf->secondary_channel = -1;
|
hapd->iconf->secondary_channel = -1;
|
||||||
else if (sec_channel > pri_channel)
|
else if (acs_res->sec_channel > acs_res->pri_channel)
|
||||||
hapd->iconf->secondary_channel = 1;
|
hapd->iconf->secondary_channel = 1;
|
||||||
else {
|
else {
|
||||||
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
|
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hapd->iface->conf->ieee80211ac) {
|
||||||
|
/* set defaults for backwards compatibility */
|
||||||
|
hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
|
||||||
|
hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
|
||||||
|
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||||
|
if (acs_res->ch_width == 80) {
|
||||||
|
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||||
|
acs_res->vht_seg0_center_ch;
|
||||||
|
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
|
||||||
|
} else if (acs_res->ch_width == 160) {
|
||||||
|
if (acs_res->vht_seg1_center_ch == 0) {
|
||||||
|
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||||
|
acs_res->vht_seg0_center_ch;
|
||||||
|
hapd->iconf->vht_oper_chwidth =
|
||||||
|
VHT_CHANWIDTH_160MHZ;
|
||||||
|
} else {
|
||||||
|
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||||
|
acs_res->vht_seg0_center_ch;
|
||||||
|
hapd->iconf->vht_oper_centr_freq_seg1_idx =
|
||||||
|
acs_res->vht_seg1_center_ch;
|
||||||
|
hapd->iconf->vht_oper_chwidth =
|
||||||
|
VHT_CHANWIDTH_80P80MHZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = hostapd_acs_completed(hapd->iface, 0);
|
ret = hostapd_acs_completed(hapd->iface, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wpa_printf(MSG_ERROR,
|
wpa_printf(MSG_ERROR,
|
||||||
|
@ -1248,9 +1273,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_ACS
|
#ifdef CONFIG_ACS
|
||||||
case EVENT_ACS_CHANNEL_SELECTED:
|
case EVENT_ACS_CHANNEL_SELECTED:
|
||||||
hostapd_acs_channel_selected(
|
hostapd_acs_channel_selected(hapd,
|
||||||
hapd, data->acs_selected_channels.pri_channel,
|
&data->acs_selected_channels);
|
||||||
data->acs_selected_channels.sec_channel);
|
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_ACS */
|
#endif /* CONFIG_ACS */
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -179,6 +179,7 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||||
hapd = iface->bss[j];
|
hapd = iface->bss[j];
|
||||||
hapd->iconf = newconf;
|
hapd->iconf = newconf;
|
||||||
hapd->iconf->channel = oldconf->channel;
|
hapd->iconf->channel = oldconf->channel;
|
||||||
|
hapd->iconf->acs = oldconf->acs;
|
||||||
hapd->iconf->secondary_channel = oldconf->secondary_channel;
|
hapd->iconf->secondary_channel = oldconf->secondary_channel;
|
||||||
hapd->iconf->ieee80211n = oldconf->ieee80211n;
|
hapd->iconf->ieee80211n = oldconf->ieee80211n;
|
||||||
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
|
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
|
||||||
|
|
|
@ -510,7 +510,11 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
|
/*
|
||||||
|
* Driver ACS chosen channel may not be HT40 due to internal driver
|
||||||
|
* restrictions.
|
||||||
|
*/
|
||||||
|
if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
|
||||||
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
|
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
|
||||||
wpa_printf(MSG_ERROR, "Driver does not support configured "
|
wpa_printf(MSG_ERROR, "Driver does not support configured "
|
||||||
"HT capability [HT40*]");
|
"HT capability [HT40*]");
|
||||||
|
|
|
@ -363,8 +363,6 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||||
int vht_oper_chwidth, int center_segment0,
|
int vht_oper_chwidth, int center_segment0,
|
||||||
int center_segment1, u32 vht_caps)
|
int center_segment1, u32 vht_caps)
|
||||||
{
|
{
|
||||||
int tmp;
|
|
||||||
|
|
||||||
os_memset(data, 0, sizeof(*data));
|
os_memset(data, 0, sizeof(*data));
|
||||||
data->mode = mode;
|
data->mode = mode;
|
||||||
data->freq = freq;
|
data->freq = freq;
|
||||||
|
@ -404,13 +402,34 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||||
return -1;
|
return -1;
|
||||||
if (!sec_channel_offset)
|
if (!sec_channel_offset)
|
||||||
return -1;
|
return -1;
|
||||||
/* primary 40 part must match the HT configuration */
|
if (!center_segment0) {
|
||||||
tmp = (30 + freq - 5000 - center_segment0 * 5) / 20;
|
if (channel <= 48)
|
||||||
tmp /= 2;
|
center_segment0 = 42;
|
||||||
if (data->center_freq1 != 5000 +
|
else if (channel <= 64)
|
||||||
center_segment0 * 5 - 20 + 40 * tmp)
|
center_segment0 = 58;
|
||||||
return -1;
|
else if (channel <= 112)
|
||||||
|
center_segment0 = 106;
|
||||||
|
else if (channel <= 128)
|
||||||
|
center_segment0 = 122;
|
||||||
|
else if (channel <= 144)
|
||||||
|
center_segment0 = 138;
|
||||||
|
else if (channel <= 161)
|
||||||
|
center_segment0 = 155;
|
||||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Note: HT/VHT config and params are coupled. Check if
|
||||||
|
* HT40 channel band is in VHT80 Pri channel band
|
||||||
|
* configuration.
|
||||||
|
*/
|
||||||
|
if (center_segment0 == channel + 6 ||
|
||||||
|
center_segment0 == channel + 2 ||
|
||||||
|
center_segment0 == channel - 2 ||
|
||||||
|
center_segment0 == channel - 6)
|
||||||
|
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case VHT_CHANWIDTH_160MHZ:
|
case VHT_CHANWIDTH_160MHZ:
|
||||||
data->bandwidth = 160;
|
data->bandwidth = 160;
|
||||||
|
@ -424,13 +443,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||||
return -1;
|
return -1;
|
||||||
if (!sec_channel_offset)
|
if (!sec_channel_offset)
|
||||||
return -1;
|
return -1;
|
||||||
/* primary 40 part must match the HT configuration */
|
/*
|
||||||
tmp = (70 + freq - 5000 - center_segment0 * 5) / 20;
|
* Note: HT/VHT config and params are coupled. Check if
|
||||||
tmp /= 2;
|
* HT40 channel band is in VHT160 channel band configuration.
|
||||||
if (data->center_freq1 != 5000 +
|
*/
|
||||||
center_segment0 * 5 - 60 + 40 * tmp)
|
if (center_segment0 == channel + 14 ||
|
||||||
return -1;
|
center_segment0 == channel + 10 ||
|
||||||
|
center_segment0 == channel + 6 ||
|
||||||
|
center_segment0 == channel + 2 ||
|
||||||
|
center_segment0 == channel - 2 ||
|
||||||
|
center_segment0 == channel - 6 ||
|
||||||
|
center_segment0 == channel - 10 ||
|
||||||
|
center_segment0 == channel - 14)
|
||||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,11 @@ enum qca_wlan_vendor_attr_acs_offload {
|
||||||
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
|
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
|
||||||
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
|
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
|
||||||
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
|
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
|
||||||
|
QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
|
||||||
|
QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
|
||||||
|
QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
|
||||||
|
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
|
||||||
|
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
|
||||||
/* keep last */
|
/* keep last */
|
||||||
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
|
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
|
||||||
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
|
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
|
||||||
|
|
|
@ -1588,6 +1588,16 @@ struct drv_acs_params {
|
||||||
|
|
||||||
/* Indicates whether HT40 is enabled */
|
/* Indicates whether HT40 is enabled */
|
||||||
int ht40_enabled;
|
int ht40_enabled;
|
||||||
|
|
||||||
|
/* Indicates whether VHT is enabled */
|
||||||
|
int vht_enabled;
|
||||||
|
|
||||||
|
/* Configured ACS channel width */
|
||||||
|
u16 ch_width;
|
||||||
|
|
||||||
|
/* ACS channel list info */
|
||||||
|
unsigned int ch_list_len;
|
||||||
|
const u8 *ch_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4546,10 +4556,18 @@ union wpa_event_data {
|
||||||
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
|
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
|
||||||
* @pri_channel: Selected primary channel
|
* @pri_channel: Selected primary channel
|
||||||
* @sec_channel: Selected secondary channel
|
* @sec_channel: Selected secondary channel
|
||||||
|
* @vht_seg0_center_ch: VHT mode Segment0 center channel
|
||||||
|
* @vht_seg1_center_ch: VHT mode Segment1 center channel
|
||||||
|
* @ch_width: Selected Channel width by driver. Driver may choose to
|
||||||
|
* change hostapd configured ACS channel width due driver internal
|
||||||
|
* channel restrictions.
|
||||||
*/
|
*/
|
||||||
struct acs_selected_channels {
|
struct acs_selected_channels {
|
||||||
u8 pri_channel;
|
u8 pri_channel;
|
||||||
u8 sec_channel;
|
u8 sec_channel;
|
||||||
|
u8 vht_seg0_center_ch;
|
||||||
|
u8 vht_seg1_center_ch;
|
||||||
|
u16 ch_width;
|
||||||
} acs_selected_channels;
|
} acs_selected_channels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8382,12 +8382,24 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
|
||||||
(params->ht_enabled &&
|
(params->ht_enabled &&
|
||||||
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
|
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
|
||||||
(params->ht40_enabled &&
|
(params->ht40_enabled &&
|
||||||
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
|
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
|
||||||
|
(params->vht_enabled &&
|
||||||
|
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
|
||||||
|
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
|
||||||
|
params->ch_width) ||
|
||||||
|
(params->ch_list_len &&
|
||||||
|
nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
|
||||||
|
params->ch_list))) {
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
}
|
}
|
||||||
nla_nest_end(msg, data);
|
nla_nest_end(msg, data);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
|
||||||
|
params->hw_mode, params->ht_enabled, params->ht40_enabled,
|
||||||
|
params->vht_enabled, params->ch_width, params->ch_list_len);
|
||||||
|
|
||||||
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
|
|
|
@ -1500,6 +1500,25 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
|
||||||
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
|
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
|
||||||
event.acs_selected_channels.sec_channel =
|
event.acs_selected_channels.sec_channel =
|
||||||
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
|
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
|
||||||
|
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
|
||||||
|
event.acs_selected_channels.vht_seg0_center_ch =
|
||||||
|
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
|
||||||
|
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
|
||||||
|
event.acs_selected_channels.vht_seg1_center_ch =
|
||||||
|
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
|
||||||
|
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
|
||||||
|
event.acs_selected_channels.ch_width =
|
||||||
|
nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
|
||||||
|
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d",
|
||||||
|
event.acs_selected_channels.pri_channel,
|
||||||
|
event.acs_selected_channels.sec_channel,
|
||||||
|
event.acs_selected_channels.ch_width,
|
||||||
|
event.acs_selected_channels.vht_seg0_center_ch,
|
||||||
|
event.acs_selected_channels.vht_seg1_center_ch);
|
||||||
|
|
||||||
|
/* Ignore ACS channel list check for backwards compatibility */
|
||||||
|
|
||||||
wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
|
wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue