Fix generating offloaded ACS channel list when hw_mode is set to any
authorPeng Xu <pxu@qca.qualcomm.com>
Sat, 20 Jun 2015 00:19:27 +0000 (17:19 -0700)
committerJouni Malinen <j@w1.fi>
Tue, 28 Jul 2015 20:22:24 +0000 (23:22 +0300)
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>
src/ap/ap_drv_ops.c
src/common/qca-vendor.h
src/drivers/driver.h
src/drivers/driver_nl80211.c

index e417614..6cafcb7 100644 (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)
 {
        struct drv_acs_params params;
@@ -750,6 +769,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
        u8 *channels = NULL;
        unsigned int num_channels = 0;
        struct hostapd_hw_modes *mode;
+       int *freq_list = NULL;
 
        if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
                return 0;
@@ -765,24 +785,35 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
                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;
+       if (mode) {
+               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;
+                               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_len = num_channels;
+       params.freq_list = freq_list;
 
        params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
        params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
index 2a6e242..b9f5f84 100644 (file)
@@ -223,6 +223,7 @@ enum qca_wlan_vendor_attr_acs_offload {
        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,
+       QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
        /* keep last */
        QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
        QCA_WLAN_VENDOR_ATTR_ACS_MAX =
index 6e39aa3..e3d3229 100644 (file)
@@ -1602,6 +1602,7 @@ struct drv_acs_params {
        /* ACS channel list info */
        unsigned int ch_list_len;
        const u8 *ch_list;
+       const int *freq_list;
 };
 
 
index a6441e3..15210ff 100644 (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)
 {
        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_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);
                return -ENOBUFS;
        }