diff mbox series

[v2,1/4] band: generate HT chandef from frequency

Message ID 20221228214403.2682418-1-prestwoj@gmail.com (mailing list archive)
State Accepted, archived
Headers show
Series [v2,1/4] band: generate HT chandef from frequency | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-alpine-ci-fetch success Fetch PR
prestwoj/iwd-ci-fetch success Fetch PR
prestwoj/iwd-ci-gitlint success GitLint
prestwoj/iwd-alpine-ci-makedistcheck success Make Distcheck
prestwoj/iwd-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-alpine-ci-makecheck success Make Check
prestwoj/iwd-ci-clang success clang PASS
prestwoj/iwd-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-ci-makecheck success Make Check
prestwoj/iwd-alpine-ci-incremental_build fail Make FAIL (patch 2): src/ap.c: In function 'ap_build_ht_operation': src/ap.c:960:17: error: 'struct ap_state' has no member named 'chandef'; did you mean 'channel'? 960 | if (ap->chandef.channel_width == BAND_CHANDEF_WIDTH_20) | ^~~~~~~ | channel src/ap.c:962:22: error: 'struct ap_state' has no member named 'chandef'; did you mean 'channel'? 962 | else if (ap->chandef.frequency < ap->chandef.center1_frequency) | ^~~~~~~ | channel src/ap.c:962:46: error: 'struct ap_state' has no member named 'chandef'; did you mean 'channel'? 962 | else if (ap->chandef.frequency < ap->chandef.center1_frequency) | ^~~~~~~ | channel make[1]: *** [Makefile:2408: src/ap.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1587: all] Error 2
prestwoj/iwd-ci-incremental_build fail Make FAIL (patch 2): src/ap.c: In function ‘ap_build_ht_operation’: src/ap.c:960:17: error: ‘struct ap_state’ has no member named ‘chandef’; did you mean ‘channel’? 960 | if (ap->chandef.channel_width == BAND_CHANDEF_WIDTH_20) | ^~~~~~~ | channel src/ap.c:962:22: error: ‘struct ap_state’ has no member named ‘chandef’; did you mean ‘channel’? 962 | else if (ap->chandef.frequency < ap->chandef.center1_frequency) | ^~~~~~~ | channel src/ap.c:962:46: error: ‘struct ap_state’ has no member named ‘chandef’; did you mean ‘channel’? 962 | else if (ap->chandef.frequency < ap->chandef.center1_frequency) | ^~~~~~~ | channel make[1]: *** [Makefile:2407: src/ap.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1586: all] Error 2
prestwoj/iwd-ci-makedistcheck success Make Distcheck
prestwoj/iwd-ci-testrunner fail test-runner - FAIL: testNetconfig

Commit Message

James Prestwood Dec. 28, 2022, 9:44 p.m. UTC
For AP mode its convenient for IWD to choose an appropriate
channel definition rather than require the user provide very
low level parameters such as channel width, center1 frequency
etc. For now only HT is supported as VHT/HE etc. require
additional secondary channel frequencies.

The HT API tries to find an operating class using 40Mhz which
complies with any hardware restrictions. If an operating class is
found that is supported/not restricted it is marked as 'best' until
a better one is found. In this case 'better' is a larger channel
width. Since this is HT only 20mhz and 40mhz widths are checked.
---
 src/band.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/band.h |  2 ++
 2 files changed, 89 insertions(+)

v2:
 * Removed the non-HT API entirely since the caller can set the
   chandef directly after validating the frequency
diff mbox series

Patch

diff --git a/src/band.c b/src/band.c
index 53ce9495..c89762a9 100644
--- a/src/band.c
+++ b/src/band.c
@@ -1194,6 +1194,93 @@  int oci_from_chandef(const struct band_chandef *own, uint8_t oci[static 3])
 	return -ENOENT;
 }
 
+/* Find an HT chandef for the frequency */
+int band_freq_to_ht_chandef(uint32_t freq, const struct band_freq_attrs *attr,
+				struct band_chandef *chandef)
+{
+	enum band_freq band;
+	enum band_chandef_width width;
+	unsigned int i;
+	const struct operating_class_info *best = NULL;
+
+	if (attr->disabled || !attr->supported)
+		return -EINVAL;
+
+	if (!band_freq_to_channel(freq, &band))
+		return -EINVAL;
+
+	for (i = 0; i < L_ARRAY_SIZE(e4_operating_classes); i++) {
+		const struct operating_class_info *info =
+						&e4_operating_classes[i];
+		enum band_chandef_width w;
+
+		if (e4_has_frequency(info, freq) < 0)
+			continue;
+
+		/* Any restrictions for this channel width? */
+		switch (info->channel_spacing) {
+		case 20:
+			w = BAND_CHANDEF_WIDTH_20;
+			break;
+		case 40:
+			w = BAND_CHANDEF_WIDTH_40;
+
+			/* 6GHz remove the upper/lower 40mhz channel concept */
+			if (band == BAND_FREQ_6_GHZ)
+				break;
+
+			if (info->flags & PRIMARY_CHANNEL_UPPER &&
+						attr->no_ht40_plus)
+				continue;
+
+			if (info->flags & PRIMARY_CHANNEL_LOWER &&
+						attr->no_ht40_minus)
+				continue;
+
+			break;
+		default:
+			continue;
+		}
+
+		if (!best || best->channel_spacing < info->channel_spacing) {
+			best = info;
+			width = w;
+		}
+	}
+
+	if (!best)
+		return -ENOENT;
+
+	chandef->frequency = freq;
+	chandef->channel_width = width;
+
+	/*
+	 * Choose a secondary channel frequency:
+	 * - 20mhz no secondary
+	 * - 40mhz we can base the selection off the channel flags, either
+	 *   higher or lower.
+	 */
+	switch (width) {
+	case BAND_CHANDEF_WIDTH_20:
+		return 0;
+	case BAND_CHANDEF_WIDTH_40:
+		if (band == BAND_FREQ_6_GHZ)
+			return 0;
+
+		if (best->flags & PRIMARY_CHANNEL_UPPER)
+			chandef->center1_frequency = freq - 10;
+		else
+			chandef->center1_frequency = freq + 10;
+
+		return 0;
+	default:
+		/* Should never happen */
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 uint8_t band_freq_to_channel(uint32_t freq, enum band_freq *out_band)
 {
 	uint32_t channel = 0;
diff --git a/src/band.h b/src/band.h
index 0ae5f8c0..676c63d9 100644
--- a/src/band.h
+++ b/src/band.h
@@ -101,6 +101,8 @@  int band_estimate_nonht_rate(const struct band *band,
 				const uint8_t *supported_rates,
 				const uint8_t *ext_supported_rates,
 				int32_t rssi, uint64_t *out_data_rate);
+int band_freq_to_ht_chandef(uint32_t freq, const struct band_freq_attrs *attr,
+				struct band_chandef *chandef);
 
 int oci_to_frequency(uint32_t operating_class, uint32_t channel);