Fix generating offloaded ACS channel list when hw_mode is set to any

When ACS is offloaded to device driver and the hw_mode parameter is set
to any, the current_mode structure is NULL which fails the ACS command.
Fix this by populating the ACS channel list with channels from all bands
when current_mode is NULL.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Peng Xu 2015-06-19 17:19:27 -07:00 committed by Jouni Malinen
parent 844dfeb804
commit d0cdccd307
4 changed files with 68 additions and 14 deletions

View file

@ -743,6 +743,25 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
} }
static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode,
int acs_ch_list_all,
int **freq_list)
{
int i;
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)) &&
!(chan->flag & HOSTAPD_CHAN_DISABLED))
int_array_add_unique(freq_list, chan->freq);
}
}
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;
@ -750,6 +769,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
u8 *channels = NULL; u8 *channels = NULL;
unsigned int num_channels = 0; unsigned int num_channels = 0;
struct hostapd_hw_modes *mode; struct hostapd_hw_modes *mode;
int *freq_list = NULL;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL) if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0; return 0;
@ -765,24 +785,35 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
acs_ch_list_all = 1; acs_ch_list_all = 1;
mode = hapd->iface->current_mode; mode = hapd->iface->current_mode;
if (mode == NULL) if (mode) {
return -1; channels = os_malloc(mode->num_channels);
channels = os_malloc(mode->num_channels); if (channels == NULL)
if (channels == NULL) return -1;
return -1;
for (i = 0; i < mode->num_channels; i++) { for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i]; struct hostapd_channel_data *chan = &mode->channels[i];
if (!acs_ch_list_all && if (!acs_ch_list_all &&
!freq_range_list_includes(&hapd->iface->conf->acs_ch_list, !freq_range_list_includes(
chan->chan)) &hapd->iface->conf->acs_ch_list,
continue; chan->chan))
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) continue;
channels[num_channels++] = chan->chan; if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
channels[num_channels++] = chan->chan;
int_array_add_unique(&freq_list, chan->freq);
}
}
} else {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
hostapd_get_hw_mode_any_channels(hapd, mode,
acs_ch_list_all,
&freq_list);
}
} }
params.ch_list = channels; params.ch_list = channels;
params.ch_list_len = num_channels; params.ch_list_len = num_channels;
params.freq_list = freq_list;
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 &

View file

@ -223,6 +223,7 @@ enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
/* 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 =

View file

@ -1602,6 +1602,7 @@ struct drv_acs_params {
/* ACS channel list info */ /* ACS channel list info */
unsigned int ch_list_len; unsigned int ch_list_len;
const u8 *ch_list; const u8 *ch_list;
const int *freq_list;
}; };

View file

@ -8385,6 +8385,26 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
} }
static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
{
int i, len, ret;
u32 *freqs;
if (!freq_list)
return 0;
len = int_array_len(freq_list);
freqs = os_malloc(sizeof(u32) * len);
if (!freqs)
return -1;
for (i = 0; i < len; i++)
freqs[i] = freq_list[i];
ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
sizeof(u32) * len, freqs);
os_free(freqs);
return ret;
}
static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
{ {
struct i802_bss *bss = priv; struct i802_bss *bss = priv;
@ -8414,7 +8434,8 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
params->ch_width) || params->ch_width) ||
(params->ch_list_len && (params->ch_list_len &&
nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len, nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
params->ch_list))) { params->ch_list)) ||
add_acs_freq_list(msg, params->freq_list)) {
nlmsg_free(msg); nlmsg_free(msg);
return -ENOBUFS; return -ENOBUFS;
} }