From patchwork Mon Jan 13 08:31:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neo Jou X-Patchwork-Id: 1222011 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=YGRD1iFp; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=IuJFvJB8; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47x6KP23dBz9sP6 for ; Mon, 13 Jan 2020 19:32:41 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=jLgfhF4WzUL1jZqQC/Av69GhByjrTJBhlXq9o6IgUPE=; b=YGR D1iFp7G9i4wCBofobulyM6lKhmlCmdE2HTUncQ7oAgN6l/Yg5jt7uzJhNCusqeGxptS4UEkJJg/TY fLxmjs0o5KgtygGCiBcBZuN24qs7HFC1mTGhoHV8Clpyy+cjUIdC6noKAZqqB8CZnEOh58DQUCaWj rYLjbfml+MYdTGDQ852gF6s/A2A0rSZngVOmIaWcqCqaz3fqzFJhSLauZnCJF/iGq42kzsKTcNK3t ZpUfkK1U3YTKGjVAkdefdwSIUDGrs4N2o78vFGULR+5b0dtK2S0qz/WnQ6AIhXyyDBYMY6Alzkbu+ nQJsamhXGeUQEQ8zkqE6t5DuNxenzsA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1iqv9G-000896-UD; Mon, 13 Jan 2020 08:32:34 +0000 Received: from mail-pl1-x643.google.com ([2607:f8b0:4864:20::643]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1iqv8R-0007Qb-SX for hostap@lists.infradead.org; Mon, 13 Jan 2020 08:31:46 +0000 Received: by mail-pl1-x643.google.com with SMTP id p9so3540183plk.9 for ; Mon, 13 Jan 2020 00:31:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=+r4EY7ksY7sFE0sG9ybQhHx02dGOP9ZqsZAaRCO2oJc=; b=IuJFvJB8d+u/REQQmg5zLJzJvxD+Lolh7cu24oWY0LryqAS7u7K8IKzmz1WloHiL9V DO2W57Ho6udwbydh9GpWWmZ4Ib83XniIxEWHA8MZhH7tNoSQbxk4jipWIbnp5Ae7rGUT iwHveDe3/8QCop2dOpJriUMZO5nWCV4HgkK3WOKtPa4e05lI3NNAHQ4+4pxVOkVQ2wAO t9bIVtoWwrHvpe8ViHk5vUxXwvo18ZvBJDI0ip5X1cKaYZRS9J6ZSXaNN2tYNa5J5HdN ERIyCZdL5FMAzd8kfhjRtPL+96frj2G622XOzUq7VNfAvvmk2VnXshQKd2qw90Ukfrs1 ivAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=+r4EY7ksY7sFE0sG9ybQhHx02dGOP9ZqsZAaRCO2oJc=; b=ZMKzshdN19uf/WfidyjJuaSu3vihwyCBuZZ0P3Hgw+fPjssqgiQCvueUAf7gRgp9ei CJfTBjii3bJlOyXJjO/vTmurGOnUQ8xWSTcdeXLcCOTqpSHdCIx78FfqNWXx+sC+Z+TX dD0oTkLXo6VjOdItF2ZgZF9rFD+xf9hgX5iNRNkdLAti1nIYbex2DmVeqOpvXd3MsifS 60d1wvWjJgQtn1McZlbcnJ4p09QVtTszSwqi3BOUFvqkUwHrl9s1WZMex4m+WAb6W2Rk GaM9EKDLNC+iLhnVcBA6n28HlyAWZ+vPpwRPCLBQjON3/y5XCzWRY5ll7fdm1Hs8k6U/ IpPw== X-Gm-Message-State: APjAAAVwHPpiv9ia5CfmMNBSyTvehD3hWNaQtnx2kYn7GAQIyNeUsOcx HusogWZ3pkBpOHbAwSjM+9JOIa5gwO658g== X-Google-Smtp-Source: APXvYqwPurUr8/cNMtKycBjAz79iLiFmArnfg1AjPL5iz5WpuUj8tfxQaGLKTW9PjvnXpQ9lMMZqbA== X-Received: by 2002:a17:902:8e85:: with SMTP id bg5mr14677142plb.32.1578904301865; Mon, 13 Jan 2020 00:31:41 -0800 (PST) Received: from localhost ([101.13.153.175]) by smtp.gmail.com with ESMTPSA id x4sm12990825pff.143.2020.01.13.00.31.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 13 Jan 2020 00:31:41 -0800 (PST) From: neojou@gmail.com To: hostap@lists.infradead.org Subject: [PATCH] ACS: cover not-offloaded-ACS with hw_mode=any Date: Mon, 13 Jan 2020 16:31:28 +0800 Message-Id: <1578904288-5418-1-git-send-email-neojou@gmail.com> X-Mailer: git-send-email 2.7.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200113_003144_014063_6D2FD9E5 X-CRM114-Status: GOOD ( 20.04 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:643 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (neojou[at]gmail.com) 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: neojou@gmail.com MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Neo Jou This patch is to extend the existing hw_mode=any to cover the not-offloaded-ACS case. We DONOT duplicate for the mode HOSTAPD_MODE_IEEE80211ANY in wpa_driver_nl80211_postprocess_modes(), so hostapd_select_hw_mode() cannot find suitable hw_mode and iface->current_mode is NULL. Thus, ACS code combine channels from multiple hw_mode lists, to determine which channel needs to be surveyed. Thus, there are some patches in src/ap/acs.c to handle the case that iface->current_mode is NULL, and to combine channels. Also in hostapd_is_usable_chans() called by hostapd_check_chans(), it updates the hw_mode, based on the frequency channel ACS picked. By this way, "hw_mode=any" can be used for not-offloaded-ACS case. Signed-off-by: Neo Jou --- src/ap/acs.c | 327 +++++++++++++++++++++++++++++++++++++------------ src/ap/drv_callbacks.c | 23 +++- src/ap/hostapd.h | 1 + src/ap/hw_features.c | 50 +++++++- 4 files changed, 311 insertions(+), 90 deletions(-) diff --git a/src/ap/acs.c b/src/ap/acs.c index 232afa8..2ffa2ff 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -261,13 +261,15 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) } -void acs_cleanup(struct hostapd_iface *iface) +static inline +void acs_cleanup_by_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) { int i; struct hostapd_channel_data *chan; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED) acs_clean_chan_surveys(chan); @@ -276,12 +278,31 @@ void acs_cleanup(struct hostapd_iface *iface) chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED; chan->min_nf = 0; } +} + +void acs_cleanup(struct hostapd_iface *iface) +{ + if (iface->current_mode == NULL) { + int i; + struct hostapd_hw_modes *mode; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + if (iface->hw_modes_has_11g && + (mode->mode == HOSTAPD_MODE_IEEE80211B)) + continue; + + acs_cleanup_by_mode(iface, mode); + } + } else { + acs_cleanup_by_mode(iface, iface->current_mode); + } iface->chans_surveyed = 0; iface->acs_num_completed_scans = 0; } - static void acs_fail(struct hostapd_iface *iface) { wpa_printf(MSG_ERROR, "ACS: Failed to start"); @@ -453,19 +474,45 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan) } -static int acs_surveys_are_sufficient(struct hostapd_iface *iface) +static inline +int acs_surveys_are_sufficient_by_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) { int i; struct hostapd_channel_data *chan; int valid = 0; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && acs_survey_list_is_sufficient(chan)) valid++; } + return valid; +} + +static int acs_surveys_are_sufficient(struct hostapd_iface *iface) +{ + int valid = 0; + + if (iface->current_mode == NULL) { + int i; + struct hostapd_hw_modes *mode; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + if (iface->hw_modes_has_11g && + (mode->mode == HOSTAPD_MODE_IEEE80211B)) + continue; + + valid = acs_surveys_are_sufficient_by_mode(iface, mode); + } + } else { + valid = acs_surveys_are_sufficient_by_mode(iface, iface->current_mode); + } + /* We need at least survey data for one channel */ return !!valid; } @@ -489,14 +536,15 @@ static int is_in_chanlist(struct hostapd_iface *iface, } -static void acs_survey_all_chans_intereference_factor( - struct hostapd_iface *iface) +static void acs_survey_all_chans_intereference_factor_by_mode( + struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) { int i; struct hostapd_channel_data *chan; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (!acs_usable_chan(chan)) continue; @@ -514,15 +562,40 @@ static void acs_survey_all_chans_intereference_factor( } } +static void acs_survey_all_chans_intereference_factor( + struct hostapd_iface *iface) +{ + if (iface->current_mode == NULL) { + int i; + struct hostapd_hw_modes *mode; -static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, - int freq) + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + if (iface->hw_modes_has_11g && + (mode->mode == HOSTAPD_MODE_IEEE80211B)) + continue; + + acs_survey_all_chans_intereference_factor_by_mode( + iface, mode); + + } + } else + acs_survey_all_chans_intereference_factor_by_mode( + iface, iface->current_mode); +} + + +static inline struct hostapd_channel_data * +acs_find_chan_by_mode(struct hostapd_iface *iface, + int freq, + struct hostapd_hw_modes *mode) { struct hostapd_channel_data *chan; int i; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_DISABLED) continue; @@ -534,6 +607,30 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, return NULL; } +static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, + int freq) +{ + struct hostapd_channel_data *chan = NULL; + + if (iface->current_mode == NULL) { + int i; + struct hostapd_hw_modes *mode; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + if (iface->hw_modes_has_11g && + (mode->mode == HOSTAPD_MODE_IEEE80211B)) + continue; + + chan = acs_find_chan_by_mode(iface, freq, mode); + } + } else { + chan = acs_find_chan_by_mode(iface, freq, iface->current_mode); + } + + return chan; +} static int is_24ghz_mode(enum hostapd_hw_mode mode) { @@ -565,58 +662,25 @@ static int is_common_24ghz_chan(int chan) #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 - * option (survey, BSS, spectral, ...). chan->interference factor must be - * summable (i.e., must be always greater than zero). - */ -static struct hostapd_channel_data * -acs_find_ideal_chan(struct hostapd_iface *iface) +static void +acs_find_ideal_chan_by_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode, + int n_chans, + u32 bw, + struct hostapd_channel_data **rand_chan, + struct hostapd_channel_data **ideal_chan, + long double *ideal_factor) { - struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL, - *rand_chan = NULL; - long double factor, ideal_factor = 0; + struct hostapd_channel_data *chan, *adj_chan = NULL; + long double factor; int i, j; - int n_chans = 1; - u32 bw; unsigned int k; - /* TODO: HT40- support */ - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel == -1) { - wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); - return NULL; - } - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel) - n_chans = 2; - - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { - switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_80MHZ: - n_chans = 4; - break; - case CHANWIDTH_160MHZ: - n_chans = 8; - break; - } - } - - bw = num_chan_to_bw(n_chans); - - /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */ - - wpa_printf(MSG_DEBUG, - "ACS: Survey analysis for selected bandwidth %d MHz", bw); - - for (i = 0; i < iface->current_mode->num_channels; i++) { + for (i = 0; i < mode->num_channels; i++) { double total_weight; struct acs_bias *bias, tmp_bias; - chan = &iface->current_mode->channels[i]; + chan = &mode->channels[i]; /* Since in the current ACS implementation the first channel is * always a primary channel, skip channels not available as @@ -637,7 +701,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) /* HT40 on 5 GHz has a limited set of primary channels as per * 11n Annex J */ - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && + if (mode->mode == HOSTAPD_MODE_IEEE80211A && iface->conf->ieee80211n && iface->conf->secondary_channel && !acs_usable_ht40_chan(chan)) { @@ -646,7 +710,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) continue; } - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && + if (mode->mode == HOSTAPD_MODE_IEEE80211A && (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) { if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80MHZ && @@ -698,7 +762,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent * channel interference factor. */ - if (is_24ghz_mode(iface->current_mode->mode)) { + if (is_24ghz_mode(mode->mode)) { for (j = 0; j < n_chans; j++) { adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 5); @@ -744,7 +808,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) break; bias = NULL; } - } else if (is_24ghz_mode(iface->current_mode->mode) && + } else if (is_24ghz_mode(mode->mode) && is_common_24ghz_chan(chan->chan)) { tmp_bias.channel = chan->chan; tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11; @@ -763,14 +827,78 @@ acs_find_ideal_chan(struct hostapd_iface *iface) } if (acs_usable_chan(chan) && - (!ideal_chan || factor < ideal_factor)) { - ideal_factor = factor; - ideal_chan = chan; + (!*ideal_chan || factor < *ideal_factor)) { + *ideal_factor = factor; + *ideal_chan = chan; } /* This channel would at least be usable */ - if (!rand_chan) - rand_chan = chan; + if (!(*rand_chan)) + *rand_chan = chan; + } +} + + + +/* + * At this point it's assumed chan->interface_factor has been computed. + * This function should be reusable regardless of interference computation + * option (survey, BSS, spectral, ...). chan->interference factor must be + * summable (i.e., must be always greater than zero). + */ +static struct hostapd_channel_data * +acs_find_ideal_chan(struct hostapd_iface *iface) +{ + struct hostapd_channel_data *ideal_chan = NULL, + *rand_chan = NULL; + long double ideal_factor = 0; + int i; + int n_chans = 1; + u32 bw; + struct hostapd_hw_modes *mode; + + /* TODO: HT40- support */ + + if (iface->conf->ieee80211n && + iface->conf->secondary_channel == -1) { + wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); + return NULL; + } + + if (iface->conf->ieee80211n && + iface->conf->secondary_channel) + n_chans = 2; + + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { + switch (hostapd_get_oper_chwidth(iface->conf)) { + case CHANWIDTH_80MHZ: + n_chans = 4; + break; + case CHANWIDTH_160MHZ: + n_chans = 8; + break; + } + } + + bw = num_chan_to_bw(n_chans); + + /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */ + + wpa_printf(MSG_DEBUG, + "ACS: Survey analysis for selected bandwidth %d MHz", bw); + + if (iface->current_mode == NULL) { + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + if (iface->hw_modes_has_11g && + (mode->mode == HOSTAPD_MODE_IEEE80211B)) + continue; + + acs_find_ideal_chan_by_mode(iface, mode, n_chans, bw, &rand_chan, &ideal_chan, &ideal_factor); + } + } else { + acs_find_ideal_chan_by_mode(iface, iface->current_mode, n_chans, bw, &rand_chan, &ideal_chan, &ideal_factor); } if (ideal_chan) { @@ -917,30 +1045,68 @@ fail: acs_fail(iface); } +static int *acs_request_scan_add_freq_by_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode, + int *freq) +{ + int i; + struct hostapd_channel_data *chan; + + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; + + if (chan->flag & HOSTAPD_CHAN_DISABLED) + continue; + + if (!is_in_chanlist(iface, chan)) + continue; + + *freq++ = chan->freq; + } + + return freq; +} + static int acs_request_scan(struct hostapd_iface *iface) { struct wpa_driver_scan_params params; - struct hostapd_channel_data *chan; int i, *freq; + int num_channels; + struct hostapd_hw_modes *mode; os_memset(¶ms, 0, sizeof(params)); - params.freqs = os_calloc(iface->current_mode->num_channels + 1, - sizeof(params.freqs[0])); + if (iface->current_mode == NULL) { + num_channels = 0; + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + num_channels += mode->num_channels; + } + } else { + num_channels = iface->current_mode->num_channels; + } + + params.freqs = os_calloc(num_channels + 1, + sizeof(params.freqs[0])); if (params.freqs == NULL) return -1; freq = params.freqs; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - if (!is_in_chanlist(iface, chan)) - continue; + if (iface->current_mode == NULL) { + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; - *freq++ = chan->freq; + if (iface->hw_modes_has_11g && + (mode->mode == HOSTAPD_MODE_IEEE80211B)) + continue; + + freq = acs_request_scan_add_freq_by_mode(iface, mode, freq); + } + } else { + freq = acs_request_scan_add_freq_by_mode(iface, iface->current_mode, freq); } + *freq = 0; if (params.freqs == freq) { @@ -978,7 +1144,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface) return HOSTAPD_CHAN_ACS; } - if (!iface->current_mode) + if ((!iface->current_mode) && + (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)) return HOSTAPD_CHAN_INVALID; acs_cleanup(iface); diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 8a4b0ef..4b3e4ea 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -1429,13 +1429,26 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, static struct hostapd_channel_data * hostapd_get_mode_channel( struct hostapd_iface *iface, unsigned int freq) { - int i; + int i, j; struct hostapd_channel_data *chan; + struct hostapd_hw_modes *mode; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if ((unsigned int) chan->freq == freq) - return chan; + if (iface->current_mode == NULL) { + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + for (j = 0; j < mode->num_channels; j++) { + chan = &mode->channels[j]; + if ((unsigned int) chan->freq == freq) + return chan; + } + } + } else { + for (i = 0; i < iface->current_mode->num_channels; i++) { + chan = &iface->current_mode->channels[i]; + if ((unsigned int) chan->freq == freq) + return chan; + } } return NULL; diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 2358d16..2b4d656 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -480,6 +480,7 @@ struct hostapd_iface { struct hostapd_hw_modes *hw_features; int num_hw_features; + Boolean hw_modes_has_11g; struct hostapd_hw_modes *current_mode; /* Rates that are currently used (i.e., filtered copy of * current_mode->channels */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index ba10752..7ce1f74 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -859,8 +859,37 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) int secondary_freq; struct hostapd_channel_data *pri_chan; - if (!iface->current_mode) - return 0; + if (!iface->current_mode) { + if (iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) { + int i; + enum hostapd_hw_mode target_mode; + + if (iface->freq < 4000) + if (iface->hw_modes_has_11g) + target_mode = HOSTAPD_MODE_IEEE80211G; + else + target_mode = HOSTAPD_MODE_IEEE80211B; + else if (iface->freq > 50000) + target_mode = HOSTAPD_MODE_IEEE80211AD; + else + target_mode = HOSTAPD_MODE_IEEE80211A; + + for (i = 0; i < iface->num_hw_features; i++) { + struct hostapd_hw_modes *mode = &iface->hw_features[i]; + if (mode->mode == target_mode) { + iface->current_mode = mode; + break; + } + } + + if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211ANY) { + wpa_printf(MSG_ERROR, "ACS: cannot decide mode"); + return 0; + } + } else + return 0; + } + pri_chan = hw_get_channel_freq(iface->current_mode->mode, iface->freq, NULL, iface->hw_features, @@ -1031,10 +1060,21 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) } } + /* set if there is 11g already */ + iface->hw_modes_has_11g = FALSE; + for (i = 0; i < iface->num_hw_features; i++) { + struct hostapd_hw_modes *mode = &iface->hw_features[i]; + + if (mode->mode == HOSTAPD_MODE_IEEE80211G) { + iface->hw_modes_has_11g = TRUE; + break; + } + } + if (iface->current_mode == NULL) { - if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || - !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) - { + if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || + !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) && + (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)) { wpa_printf(MSG_ERROR, "Hardware does not support configured mode"); hostapd_logger(iface->bss[0], NULL,