From patchwork Thu Feb 5 16:18:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jouni Malinen X-Patchwork-Id: 436865 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from maxx.maxx.shmoo.com (maxx.shmoo.com [205.134.188.171]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 7883E140119 for ; Fri, 6 Feb 2015 03:18:46 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 0756C17C0BC; Thu, 5 Feb 2015 11:18:44 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id fCrOQAbMq9CI; Thu, 5 Feb 2015 11:18:43 -0500 (EST) Received: from maxx.shmoo.com (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 7874517C0B2; Thu, 5 Feb 2015 11:18:38 -0500 (EST) X-Original-To: mailman-post+hostap@maxx.shmoo.com Delivered-To: mailman-post+hostap@maxx.shmoo.com Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 3423E17C0B2 for ; Thu, 5 Feb 2015 11:18:37 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZfHCu3wkEi6k for ; Thu, 5 Feb 2015 11:18:31 -0500 (EST) Received: from li674-96.members.linode.com (mail.w1.fi [212.71.239.96]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 4058017C0A9 for ; Thu, 5 Feb 2015 11:18:31 -0500 (EST) Received: from jm (37-33-206-17.bb.dnainternet.fi [37.33.206.17]) by li674-96.members.linode.com (Postfix) with ESMTPSA id BAE4D1117B for ; Thu, 5 Feb 2015 16:18:28 +0000 (UTC) Received: by jm (sSMTP sendmail emulation); Thu, 05 Feb 2015 18:18:27 +0200 Date: Thu, 5 Feb 2015 18:18:27 +0200 From: Jouni Malinen To: hostap@lists.shmoo.com Subject: Re: ACS seems not to select the best channel in 2.4GHz. Message-ID: <20150205161827.GA10519@w1.fi> Mail-Followup-To: hostap@lists.shmoo.com References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) X-BeenThere: hostap@lists.shmoo.com X-Mailman-Version: 2.1.11 Precedence: list List-Id: HostAP Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: hostap-bounces@lists.shmoo.com Errors-To: hostap-bounces@lists.shmoo.com On Fri, Jan 30, 2015 at 02:45:25PM -0800, Fumikazu Yobimoto wrote: > I verified the ACS(Auto Channel Select) in 2.4GHz environment. > Set 2 APs, one is ch.1 and one is ch.11, and then transmit a heavy traffic > at each channel. > I'm expecting ACS should choose ch.6 for ideal channel, but it always > choose ch.1 or ch.11 in any case. > However, acs.c tries to add adjacent channel's value. Thus eventually, > those values go like as following. > 1=1.928 (1+2+3) > 2=2.658 (1+2+3+4) > 3=3.024 (1+2+3+4+5) I guess the logic here could have been to assume that "channels" 0 and -1 would have zero interference. That would not really be the case and I agree that this would give way too much preference to channels 1 and 11 (and too much for 2 and 10 as well). > I think it's not necessary to add adjacent value. Because radio survey data > of each channel would detect the adjacent interference actually 20MHz. > In fact, the test result shows that ch.4 detect the interference of ch.1, > similarly ch.8 detect the interference of ch.11. > I attached a patch file for hostapd-v2.3 . I'm not sure skipping the adjacent channels completely on 2.4 GHz would be ideal solution here. It is clear that the channels at each end of the band will require something more accurate. It may also be reasonable to at least drop the importance of the impact from adjacent channels. I'm consider the following patch as a way of addressing this. If you define ACS_ADJ_WEIGHT 0, ACS_NEXT_ADJ_WEIGHT 0, and ACS_24GHZ_PREFER_1_6_11 1, you'd get the behavior you should saw with the patch you sent. If someone has good suggestions on what the best numbers to use here as the default would be, I'm certainly open to changing these. As noted in the commit message, I did not really do any real research on picking the numbers. [PATCH] ACS: Fix 2.4 GHz adjacent channel interference summing The interference factors for adjacent 2.4 GHz channels were summed together without doing any kind of weighted average on them. This resulted in the channels at the band edges getting undue preference due to only including interference factors from three channels vs. five for the channels in the middle of the band. While it is somewhat unclear whether the design here was supposed to count overlapping channels together in this way or whether that is already covered in channel survey results, it is clear that this summing of three to five values together and then comparing the sum rather than average of some kind cannot be correct. Use weighted average of the interference factors rather than a sum from different number of values. For now, the adjacent 2.4 GHz channels get weight of 0.5 (1.0 for the main channel itself) and the neighboring channels to those adjacent ones get 0.25 weight. Band-edge channels are handled in a way that takes average over the channels that were actually considered instead of assuming zero interference from neighboring bands. This change results in significantly less preference for the band-edge channels. That is arguable good thing to do here, but it would also be good to avoid picking some arbitrary 2.4 GHz channel and rather give significant extra preference for the commonly used channels 1, 6, 11. This is now done by picking those channels over the other ones unless another channel has significantly better interference factor (0.8 or smaller times the one on 1, 6, 11). The initially used multiplier values used here are not based on any real research, i.e., these are just a wild guess of somethign semi-reasonable. The values can be optimized in the future and can also be overridden in build parameters with C preprocessor macros (ACS_ADJ_WEIGHT, ACS_NEXT_ADJ_WEIGHT, ACS_24GHZ_PREFER_1_6_11). Signed-off-by: Jouni Malinen --- src/ap/acs.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/src/ap/acs.c b/src/ap/acs.c index e4c834c..616b810 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -517,6 +517,23 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, } +#ifndef ACS_ADJ_WEIGHT +#define ACS_ADJ_WEIGHT 0.5 +#endif /* ACS_ADJ_WEIGHT */ + +#ifndef ACS_NEXT_ADJ_WEIGHT +#define ACS_NEXT_ADJ_WEIGHT 0.25 +#endif /* ACS_NEXT_ADJ_WEIGHT */ + +#ifndef ACS_24GHZ_PREFER_1_6_11 +/* + * Select commonly used channels 1, 6, 11 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 @@ -529,7 +546,8 @@ acs_find_ideal_chan(struct hostapd_iface *iface) struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL, *rand_chan = NULL; long double factor, ideal_factor = 0; - int i, j; + long double factor_chans[13]; + int i, j, max_chans, ideal_idx = -1; int n_chans = 1; /* TODO: HT40- support */ @@ -556,7 +574,16 @@ acs_find_ideal_chan(struct hostapd_iface *iface) n_chans == 4 ? 80 : -1); + max_chans = iface->current_mode->num_channels; + if (max_chans > 13) + max_chans = 13; + for (i = 0; i < max_chans; i++) + factor_chans[i] = 0; + for (i = 0; i < iface->current_mode->num_channels; i++) { + double total_weight; + int usable; + chan = &iface->current_mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_DISABLED) @@ -586,16 +613,20 @@ acs_find_ideal_chan(struct hostapd_iface *iface) } factor = 0; - if (acs_usable_chan(chan)) + usable = acs_usable_chan(chan); + if (usable) factor = chan->interference_factor; + total_weight = 1; for (j = 1; j < n_chans; j++) { adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); if (!adj_chan) break; - if (acs_usable_chan(adj_chan)) + if (acs_usable_chan(adj_chan)) { factor += adj_chan->interference_factor; + total_weight += 1; + } } if (j != n_chans) { @@ -609,38 +640,53 @@ acs_find_ideal_chan(struct hostapd_iface *iface) if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B || iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) { for (j = 0; j < n_chans; j++) { - /* TODO: perhaps a multiplier should be used - * here? */ - adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 5); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_ADJ_WEIGHT; + } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 10); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_NEXT_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_NEXT_ADJ_WEIGHT; + } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 5); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_ADJ_WEIGHT; + } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 10); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_NEXT_ADJ_WEIGHT + + adj_chan->interference_factor; + total_weight += ACS_NEXT_ADJ_WEIGHT; + } } } + factor /= total_weight; + wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg", chan->chan, factor); - if (acs_usable_chan(chan) && - (!ideal_chan || factor < ideal_factor)) { - ideal_factor = factor; - ideal_chan = chan; + if (usable) { + if (i < max_chans) + factor_chans[i] = factor; + if (!ideal_chan || factor < ideal_factor) { + ideal_factor = factor; + ideal_chan = chan; + ideal_idx = i; + } } /* This channel would at least be usable */ @@ -648,6 +694,46 @@ acs_find_ideal_chan(struct hostapd_iface *iface) rand_chan = chan; } + /* + * Try to prefer commonly used channels 1, 6, and 11 unless + * there is a significantly better channel available. + */ + if ((iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B || + iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) && + ideal_idx >= 0 && ideal_chan) { + if ((ideal_idx == 1 || ideal_idx == 2) && + factor_chans[0] > 0 && + factor_chans[ideal_idx] > + ACS_24GHZ_PREFER_1_6_11 * factor_chans[0]) { + wpa_printf(MSG_DEBUG, + "ACS: Prefer common 2.4 GHz channel 1 over ideal channel %d", + ideal_chan->chan); + ideal_chan = &iface->current_mode->channels[0]; + } + + if ((ideal_idx == 3 || ideal_idx == 4 || + ideal_idx == 6 || ideal_idx == 7) && + factor_chans[5] > 0 && + factor_chans[ideal_idx] > + ACS_24GHZ_PREFER_1_6_11 * factor_chans[5]) { + wpa_printf(MSG_DEBUG, + "ACS: Prefer common 2.4 GHz channel 6 over ideal channel %d", + ideal_chan->chan); + ideal_chan = &iface->current_mode->channels[5]; + } + + if ((ideal_idx == 8 || ideal_idx == 9 || + ideal_idx == 11 || ideal_idx == 12) && + factor_chans[10] > 0 && + factor_chans[ideal_idx] > + ACS_24GHZ_PREFER_1_6_11 * factor_chans[10]) { + wpa_printf(MSG_DEBUG, + "ACS: Prefer common 2.4 GHz channel 11 over ideal channel %d", + ideal_chan->chan); + ideal_chan = &iface->current_mode->channels[10]; + } + } + if (ideal_chan) { wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg", ideal_chan->chan, ideal_chan->freq, ideal_factor);