]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
ACS: Allow specific channels to be preferred
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 6 Feb 2015 15:59:57 +0000 (17:59 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 6 Feb 2015 15:59:57 +0000 (17:59 +0200)
The new acs_chan_bias configuration parameter is a space-separated list
of <channel>:<bias> pairs. It can be used to increase (or decrease) the
likelihood of a specific channel to be selected by the ACS algorithm.
The total interference factor for each channel gets multiplied by the
specified bias value before finding the channel with the lowest value.
In other words, values between 0.0 and 1.0 can be used to make a channel
more likely to be picked while values larger than 1.0 make the specified
channel less likely to be picked. This can be used, e.g., to prefer the
commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default
behavior on 2.4 GHz band if no acs_chan_bias parameter is specified).

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/acs.c
src/ap/ap_config.c
src/ap/ap_config.h

index e3cad7c9fd2470d25515315670487447663f2c86..3466f285172ecb62b073a18cc6b7d5270dcd4684 100644 (file)
@@ -1856,6 +1856,48 @@ static struct wpabuf * hostapd_parse_bin(const char *buf)
 #endif /* CONFIG_WPS_NFC */
 
 
+#ifdef CONFIG_ACS
+static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
+                                             char *pos)
+{
+       struct acs_bias *bias = NULL, *tmp;
+       unsigned int num = 0;
+       char *end;
+
+       while (*pos) {
+               tmp = os_realloc_array(bias, num + 1, sizeof(*bias));
+               if (!tmp)
+                       goto fail;
+               bias = tmp;
+
+               bias[num].channel = atoi(pos);
+               if (bias[num].channel <= 0)
+                       goto fail;
+               pos = os_strchr(pos, ':');
+               if (!pos)
+                       goto fail;
+               pos++;
+               bias[num].bias = strtod(pos, &end);
+               if (end == pos || bias[num].bias < 0.0)
+                       goto fail;
+               pos = end;
+               if (*pos != ' ' && *pos != '\0')
+                       goto fail;
+               num++;
+       }
+
+       os_free(conf->acs_chan_bias);
+       conf->acs_chan_bias = bias;
+       conf->num_acs_chan_bias = num;
+
+       return 0;
+fail:
+       os_free(bias);
+       return -1;
+}
+#endif /* CONFIG_ACS */
+
+
 static int hostapd_config_fill(struct hostapd_config *conf,
                               struct hostapd_bss_config *bss,
                               char *buf, char *pos, int line)
@@ -2508,6 +2550,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
                }
                conf->acs_num_scans = val;
+       } else if (os_strcmp(buf, "acs_chan_bias") == 0) {
+               if (hostapd_config_parse_acs_chan_bias(conf, pos)) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias",
+                                  line);
+                       return -1;
+               }
 #endif /* CONFIG_ACS */
        } else if (os_strcmp(buf, "dtim_period") == 0) {
                bss->dtim_period = atoi(pos);
index 1e5695984783d9a77d0ade2e1a1ed91192a89a23..dd05c2ffde46da60fdfda0ab79a6056c639abe44 100644 (file)
@@ -154,8 +154,19 @@ channel=1
 # interference that may help choosing a better channel. This can also help fine
 # tune the ACS scan time in case a driver has different scan dwell times.
 #
+# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be
+# used to increase (or decrease) the likelihood of a specific channel to be
+# selected by the ACS algorithm. The total interference factor for each channel
+# gets multiplied by the specified bias value before finding the channel with
+# the lowest value. In other words, values between 0.0 and 1.0 can be used to
+# make a channel more likely to be picked while values larger than 1.0 make the
+# specified channel less likely to be picked. This can be used, e.g., to prefer
+# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default
+# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified).
+#
 # Defaults:
 #acs_num_scans=5
+#acs_chan_bias=1:0.8 6:0.8 11:0.8
 
 # Channel list restriction. This option allows hostapd to select one of the
 # provided channels when a channel should be automatically selected.
index 78fd949aff83393a2ba9df344fdc8c9066adc2ad..15a4741642882a895cd37988209ffe237b97fd2f 100644 (file)
@@ -517,6 +517,19 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
 }
 
 
+static int is_24ghz_mode(enum hostapd_hw_mode mode)
+{
+       return mode == HOSTAPD_MODE_IEEE80211B ||
+               mode == HOSTAPD_MODE_IEEE80211G;
+}
+
+
+static int is_common_24ghz_chan(int chan)
+{
+       return chan == 1 || chan == 6 || chan == 11;
+}
+
+
 #ifndef ACS_ADJ_WEIGHT
 #define ACS_ADJ_WEIGHT 0.85
 #endif /* ACS_ADJ_WEIGHT */
@@ -525,6 +538,15 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
 #define ACS_NEXT_ADJ_WEIGHT 0.55
 #endif /* ACS_NEXT_ADJ_WEIGHT */
 
+#ifndef ACS_24GHZ_PREFER_1_6_11
+/*
+ * Select commonly used channels 1, 6, 11 by default even if a neighboring
+ * channel has a smaller interference factor as long as it is not better by more
+ * than this multiplier.
+ */
+#define ACS_24GHZ_PREFER_1_6_11 0.8
+#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
 /*
  * At this point it's assumed chan->interface_factor has been computed.
  * This function should be reusable regardless of interference computation
@@ -539,6 +561,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
        long double factor, ideal_factor = 0;
        int i, j;
        int n_chans = 1;
+       unsigned int k;
 
        /* TODO: HT40- support */
 
@@ -566,6 +589,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 
        for (i = 0; i < iface->current_mode->num_channels; i++) {
                double total_weight;
+               struct acs_bias *bias, tmp_bias;
 
                chan = &iface->current_mode->channels[i];
 
@@ -619,8 +643,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 
                /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
                 * channel interference factor. */
-               if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B ||
-                   iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) {
+               if (is_24ghz_mode(iface->current_mode->mode)) {
                        for (j = 0; j < n_chans; j++) {
                                adj_chan = acs_find_chan(iface, chan->freq +
                                                         (j * 20) - 5);
@@ -658,8 +681,31 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 
                factor /= total_weight;
 
-               wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg",
-                          chan->chan, factor);
+               bias = NULL;
+               if (iface->conf->acs_chan_bias) {
+                       for (k = 0; k < iface->conf->num_acs_chan_bias; k++) {
+                               bias = &iface->conf->acs_chan_bias[k];
+                               if (bias->channel == chan->chan)
+                                       break;
+                               bias = NULL;
+                       }
+               } else if (is_24ghz_mode(iface->current_mode->mode) &&
+                          is_common_24ghz_chan(chan->chan)) {
+                       tmp_bias.channel = chan->chan;
+                       tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
+                       bias = &tmp_bias;
+               }
+
+               if (bias) {
+                       factor *= bias->bias;
+                       wpa_printf(MSG_DEBUG,
+                                  "ACS:  * channel %d: total interference = %Lg (%f bias)",
+                                  chan->chan, factor, bias->bias);
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "ACS:  * channel %d: total interference = %Lg",
+                                  chan->chan, factor);
+               }
 
                if (acs_usable_chan(chan) &&
                    (!ideal_chan || factor < ideal_factor)) {
index 1c0ed7aa938f0453ce944ca9dae5926667dddb1b..c1861d4f7041a4ce1571b4043dee408737f3a9d9 100644 (file)
@@ -574,6 +574,9 @@ void hostapd_config_free(struct hostapd_config *conf)
        os_free(conf->basic_rates);
        os_free(conf->chanlist);
        os_free(conf->driver_params);
+#ifdef CONFIG_ACS
+       os_free(conf->acs_chan_bias);
+#endif /* CONFIG_ACS */
 
        os_free(conf);
 }
index e5215c52909b737a452cba1a1b55e4c82ed6dc06..0f33ac9a05b6be43a7f94a1ccc2124f5bae4a956 100644 (file)
@@ -639,6 +639,11 @@ struct hostapd_config {
 
 #ifdef CONFIG_ACS
        unsigned int acs_num_scans;
+       struct acs_bias {
+               int channel;
+               double bias;
+       } *acs_chan_bias;
+       unsigned int num_acs_chan_bias;
 #endif /* CONFIG_ACS */
 };