diff mbox series

ACS: cover not-offloaded-ACS with hw_mode=any

Message ID 1578478348-4095-1-git-send-email-neojou@gmail.com
State Changes Requested
Headers show
Series ACS: cover not-offloaded-ACS with hw_mode=any | expand

Commit Message

Neo Jou Jan. 8, 2020, 10:12 a.m. UTC
From: Neo Jou <neojou@gmail.com>

This patch is to extend the existing hw_mode=any to cover
the not-offloaded-ACS case.

In wpa_driver_nl80211_postprocess_modes, the approach, similar
to the one for 80211.b is used for the mode
HOSTAPD_MODE_IEEE80211ANY. it is for hostapd_select_hw_mode()
to get the support configured mode.

And after ACS computed, the current_mode is changed back to B/G/A/AD,
depends on the frequency ACS decided.

By this way, "hw_mode=any" can be used for not-offloaded-ACS case.

Signed-off-by: Neo Jou <neojou@gmail.com>
---
 src/ap/hw_features.c              | 35 +++++++++++++++++++++++++++++
 src/drivers/driver_nl80211_capa.c | 47 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

Comments

Jouni Malinen Jan. 8, 2020, 12:55 p.m. UTC | #1
On Wed, Jan 08, 2020 at 06:12:28PM +0800, neojou@gmail.com wrote:
> This patch is to extend the existing hw_mode=any to cover
> the not-offloaded-ACS case.
> 
> In wpa_driver_nl80211_postprocess_modes, the approach, similar
> to the one for 80211.b is used for the mode
> HOSTAPD_MODE_IEEE80211ANY. it is for hostapd_select_hw_mode()
> to get the support configured mode.

That does not sound reasonable. Why would we need to duplicate channel
list entries? IEEE 802.11b is a very special case on this front and it
must not be tried to be duplicated for hw_mode=any which is a
completely different use case (select any of the already existing modes;
not create a new mode).

> And after ACS computed, the current_mode is changed back to B/G/A/AD,
> depends on the frequency ACS decided.
> 
> By this way, "hw_mode=any" can be used for not-offloaded-ACS case.

This needs to work without generating duplicated channel list entries.
In other words, ACS code needs to combine channels from multiple hw_mode
lists to determine which channels needs to be surveyed and then pick the
best one and update hw_mode based on that. I would not expect to see any
changes in src/drivers/driver_*.c for this.
Neo Jou Jan. 9, 2020, 1:13 a.m. UTC | #2
Got it. I agree with you, will do that.

Jouni Malinen <j@w1.fi>
> it must not be tried to be duplicated for hw_mode=any which is a
> completely different use case (select any of the already existing modes;
> not create a new mode).
>
> This needs to work without generating duplicated channel list entries.
> In other words, ACS code needs to combine channels from multiple hw_mode
> lists to determine which channels needs to be surveyed and then pick the
> best one and update hw_mode based on that. I would not expect to see any
> changes in src/drivers/driver_*.c for this.
>
Neo Jou Jan. 14, 2020, 2:06 a.m. UTC | #3
> Jouni Malinen <j@w1.fi>
> ACS code needs to combine channels from multiple hw_mode
> lists to determine which channels needs to be surveyed and then pick the
> best one and update hw_mode based on that. I would not expect to see any
> changes in src/drivers/driver_*.c for this.

It is implemented at
https://patchwork.ozlabs.org/patch/1222011/

Thanks.
diff mbox series

Patch

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index ba10752..2db65c5 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -963,6 +963,39 @@  int hostapd_acs_completed(struct hostapd_iface *iface, int err)
 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
 			ACS_EVENT_COMPLETED "freq=%d channel=%d",
 			iface->freq, iface->conf->channel);
+
+		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211ANY) {
+			int i;
+			enum hostapd_hw_mode target_mode;
+
+			if (iface->freq < 4000) {
+				target_mode = HOSTAPD_MODE_IEEE80211B;
+				for (i = 0; i < iface->current_mode->num_rates; i++) {
+					if (iface->current_mode->rates[i] > 200) {
+						target_mode = HOSTAPD_MODE_IEEE80211G;
+						break;
+					}
+				}
+			} 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 error - cannot decide band");
+				wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
+				hostapd_notify_bad_chans(iface);
+				goto out;
+			}
+		}
 		break;
 	case HOSTAPD_CHAN_ACS:
 		wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
@@ -1070,6 +1103,8 @@  const char * hostapd_hw_mode_txt(int mode)
 		return "IEEE 802.11g";
 	case HOSTAPD_MODE_IEEE80211AD:
 		return "IEEE 802.11ad";
+	case HOSTAPD_MODE_IEEE80211ANY:
+		return "IEEE 802.11any";
 	default:
 		return "UNKNOWN";
 	}
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index e1cf9f7..908d1fd 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1808,6 +1808,53 @@  wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
 			modes[m].mode = HOSTAPD_MODE_IEEE80211A;
 	}
 
+	/* Add HOSTAPD_MODE_IEEE80211ANY */
+	nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
+	if (nmodes == NULL)
+		return modes; /* Could not add mode ANY */
+
+	mode = &nmodes[*num_modes];
+	os_memset(mode, 0, sizeof(*mode));
+	modes = nmodes;
+	mode->mode = HOSTAPD_MODE_IEEE80211ANY;
+
+	for (m = 0; m < *num_modes; m++) {
+		struct hostapd_channel_data *m_channels;
+		int *m_rates;
+
+		if (!modes[m].num_channels)
+			continue;
+
+		/* add channels */
+		m_channels = os_realloc_array(mode->channels,
+						  mode->num_channels + modes[m].num_channels,
+						  sizeof(struct hostapd_channel_data));
+		if (m_channels == NULL)
+			return modes;
+
+		mode->channels = m_channels;
+
+		memcpy(&(mode->channels[mode->num_channels]),
+		       modes[m].channels,
+		       modes[m].num_channels * sizeof(struct hostapd_channel_data));
+
+		mode->num_channels += modes[m].num_channels;
+
+		/* add rates */
+		m_rates = os_realloc_array(mode->rates,
+					   mode->num_rates + modes[m].num_rates,
+					   sizeof(int));
+		if (m_rates == NULL)
+			return modes;
+		mode->rates = m_rates;
+		memcpy(&(mode->rates[mode->num_rates]),
+		       modes[m].rates,
+		       modes[m].num_rates * sizeof(int));
+		mode->num_rates += modes[m].num_rates;
+	}
+
+	(*num_modes)++;
+
 	/* If only 802.11g mode is included, use it to construct matching
 	 * 802.11b mode data. */