[PATCH RFC 1/9] common: introduce ieee80211_chan_to_freq_khz()
Lachlan Hodges
lachlan.hodges at morsemicro.com
Thu Oct 8 20:31:58 PDT 2026
80211ah or S1G sits below 1GHz with channel granularity of 500KHz,
meaning MHz alone is not enough to correctly represent a channels
center frequency. Convert the internal channel calculation functions
to KHz - similarly to cfg80211 - and expose the result through a new
ieee80211_chan_to_freq_khz() helper. Existing callers continue to use
ieee80211_chan_to_freq(), which simply converts the internal KHz
result to MHz to reduce API churn.
Signed-off-by: Lachlan Hodges <lachlan.hodges at morsemicro.com>
---
src/common/defs.h | 3 +
src/common/ieee802_11_common.c | 128 ++++++++++++++++++---------------
src/common/ieee802_11_common.h | 1 +
3 files changed, 76 insertions(+), 56 deletions(-)
diff --git a/src/common/defs.h b/src/common/defs.h
index dc120f0cf47f..9f7ea34a2e5a 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -589,4 +589,7 @@ enum wpa_p2p_mode {
#define USEC_TO_TU(m) ((m) / USEC_80211_TU)
#define TU_TO_USEC(m) ((m) * USEC_80211_TU)
+#define MHZ_TO_KHZ(x) ((x) * 1000)
+#define KHZ_TO_MHZ(x) ((x) / 1000)
+
#endif /* DEFS_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 0a1e9a67ba81..eaf6310911a9 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1896,7 +1896,7 @@ static int country_match(const char *const cc[], const char *const country)
}
-static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
+static int ieee80211_chan_to_freq_khz_us(u8 op_class, u8 chan)
{
switch (op_class) {
case 12: /* channels 1..11 */
@@ -1904,7 +1904,7 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
case 33: /* channels 5..11; 40 MHz */
if (chan < 1 || chan > 11)
return -1;
- return 2407 + 5 * chan;
+ return MHZ_TO_KHZ(2407 + 5 * chan);
case 1: /* channels 36,40,44,48 */
case 2: /* channels 52,56,60,64; dfs */
case 22: /* channels 36,44; 40 MHz */
@@ -1913,12 +1913,12 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
case 28: /* channels 56,64; 40 MHz */
if (chan < 36 || chan > 64)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 4: /* channels 100-144 */
case 24: /* channels 100-140; 40 MHz */
if (chan < 100 || chan > 144)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 3: /* channels 149,153,157,161 */
case 25: /* channels 149,157; 40 MHz */
case 26: /* channels 149,157; 40 MHz */
@@ -1926,34 +1926,34 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
case 31: /* channels 153,161; 40 MHz */
if (chan < 149 || chan > 161)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 5: /* channels 149,153,157,161,165 */
if (chan < 149 || chan > 165)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 34: /* 60 GHz band, channels 1..8 */
if (chan < 1 || chan > 8)
return -1;
- return 56160 + 2160 * chan;
+ return MHZ_TO_KHZ(56160 + 2160 * chan);
case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */
if (chan < 9 || chan > 15)
return -1;
- return 56160 + 2160 * (chan - 8);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 8));
case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */
if (chan < 17 || chan > 22)
return -1;
- return 56160 + 2160 * (chan - 16);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 16));
case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */
if (chan < 25 || chan > 29)
return -1;
- return 56160 + 2160 * (chan - 24);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 24));
default:
return -1;
}
}
-static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
+static int ieee80211_chan_to_freq_khz_eu(u8 op_class, u8 chan)
{
switch (op_class) {
case 4: /* channels 1..13 */
@@ -1961,7 +1961,7 @@ static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
case 12: /* channels 5..13; 40 MHz */
if (chan < 1 || chan > 13)
return -1;
- return 2407 + 5 * chan;
+ return MHZ_TO_KHZ(2407 + 5 * chan);
case 1: /* channels 36,40,44,48 */
case 2: /* channels 52,56,60,64; dfs */
case 5: /* channels 36,44; 40 MHz */
@@ -1970,41 +1970,41 @@ static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
case 9: /* channels 56,64; 40 MHz */
if (chan < 36 || chan > 64)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 3: /* channels 100-140 */
case 7: /* channels 100-132; 40 MHz */
case 10: /* channels 104-136; 40 MHz */
case 16: /* channels 100-140 */
if (chan < 100 || chan > 140)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 17: /* channels 149,153,157,161,165,169 */
if (chan < 149 || chan > 169)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 18: /* 60 GHz band, channels 1..6 */
if (chan < 1 || chan > 6)
return -1;
- return 56160 + 2160 * chan;
+ return MHZ_TO_KHZ(56160 + 2160 * chan);
case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */
if (chan < 9 || chan > 11)
return -1;
- return 56160 + 2160 * (chan - 8);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 8));
case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */
if (chan < 17 || chan > 18)
return -1;
- return 56160 + 2160 * (chan - 16);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 16));
case 23: /* 60 GHz band, EDMG CB4, channels 25 */
if (chan != 25)
return -1;
- return 56160 + 2160 * (chan - 24);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 24));
default:
return -1;
}
}
-static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
+static int ieee80211_chan_to_freq_khz_jp(u8 op_class, u8 chan)
{
/* Table E-3 in IEEE Std 802.11-2020 - Operating classes in Japan */
switch (op_class) {
@@ -2013,11 +2013,11 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
case 57: /* channels 5..13; 40 MHz */
if (chan < 1 || chan > 13)
return -1;
- return 2407 + 5 * chan;
+ return MHZ_TO_KHZ(2407 + 5 * chan);
case 31: /* channel 14 */
if (chan != 14)
return -1;
- return 2414 + 5 * chan;
+ return MHZ_TO_KHZ(2414 + 5 * chan);
case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
case 32: /* channels 52,56,60,64 */
case 33: /* channels 52,56,60,64 */
@@ -2029,7 +2029,7 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
case 43: /* channels 56,64; 40 MHz */
if (chan < 34 || chan > 64)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 34: /* channels 100-144 */
case 35: /* reserved */
case 39: /* channels 100-140; 40 MHz */
@@ -2039,30 +2039,30 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
case 58: /* channels 100-144 */
if (chan < 100 || chan > 144)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 59: /* 60 GHz band, channels 1..6 */
if (chan < 1 || chan > 6)
return -1;
- return 56160 + 2160 * chan;
+ return MHZ_TO_KHZ(56160 + 2160 * chan);
case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */
if (chan < 9 || chan > 11)
return -1;
- return 56160 + 2160 * (chan - 8);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 8));
case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */
if (chan < 17 || chan > 18)
return -1;
- return 56160 + 2160 * (chan - 16);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 16));
case 64: /* 60 GHz band, EDMG CB4, channel 25 */
if (chan != 25)
return -1;
- return 56160 + 2160 * (chan - 24);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 24));
default:
return -1;
}
}
-static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
+static int ieee80211_chan_to_freq_khz_cn(u8 op_class, u8 chan)
{
switch (op_class) {
case 7: /* channels 1..13 */
@@ -2070,26 +2070,26 @@ static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
case 9: /* channels 5..13; 40 MHz */
if (chan < 1 || chan > 13)
return -1;
- return 2407 + 5 * chan;
+ return MHZ_TO_KHZ(2407 + 5 * chan);
case 1: /* channels 36,40,44,48 */
case 2: /* channels 52,56,60,64; dfs */
case 4: /* channels 36,44; 40 MHz */
case 5: /* channels 52,60; 40 MHz */
if (chan < 36 || chan > 64)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 3: /* channels 149,153,157,161,165 */
case 6: /* channels 149,157; 40 MHz */
if (chan < 149 || chan > 165)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
default:
return -1;
}
}
-static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
+static int ieee80211_chan_to_freq_khz_global(u8 op_class, u8 chan)
{
/* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */
switch (op_class) {
@@ -2097,17 +2097,17 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
/* channels 1..13 */
if (chan < 1 || chan > 13)
return -1;
- return 2407 + 5 * chan;
+ return MHZ_TO_KHZ(2407 + 5 * chan);
case 82:
/* channel 14 */
if (chan != 14)
return -1;
- return 2414 + 5 * chan;
+ return MHZ_TO_KHZ(2414 + 5 * chan);
case 83: /* channels 1..9; 40 MHz */
case 84: /* channels 5..13; 40 MHz */
if (chan < 1 || chan > 13)
return -1;
- return 2407 + 5 * chan;
+ return MHZ_TO_KHZ(2407 + 5 * chan);
case 115: /* channels 36,40,44,48; indoor only */
case 116: /* channels 36,44; 40 MHz; indoor only */
case 117: /* channels 40,48; 40 MHz; indoor only */
@@ -2116,32 +2116,32 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
case 120: /* channels 56,64; 40 MHz; dfs */
if (chan < 36 || chan > 64)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 121: /* channels 100-144 */
case 122: /* channels 100-140; 40 MHz */
case 123: /* channels 104-144; 40 MHz */
if (chan < 100 || chan > 144)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 124: /* channels 149,153,157,161 */
if (chan < 149 || chan > 161)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 125: /* channels 149,153,157,161,165,169,173,177 */
case 126: /* channels 149,157,165,173; 40 MHz */
case 127: /* channels 153,161,169,177; 40 MHz */
if (chan < 149 || chan > 177)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
if (chan < 36 || chan > 177)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 129: /* center freqs 50, 114, 163; 160 MHz */
if (chan < 36 || chan > 177)
return -1;
- return 5000 + 5 * chan;
+ return MHZ_TO_KHZ(5000 + 5 * chan);
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
@@ -2150,68 +2150,84 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
if (chan < 1 || chan > 233)
return -1;
- return 5950 + chan * 5;
+ return MHZ_TO_KHZ(5950 + chan * 5);
case 136: /* UHB channels, 20 MHz: 2 */
if (chan == 2)
- return 5935;
+ return MHZ_TO_KHZ(5935);
return -1;
case 180: /* 60 GHz band, channels 1..8 */
if (chan < 1 || chan > 8)
return -1;
- return 56160 + 2160 * chan;
+ return MHZ_TO_KHZ(56160 + 2160 * chan);
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
if (chan < 9 || chan > 15)
return -1;
- return 56160 + 2160 * (chan - 8);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 8));
case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
if (chan < 17 || chan > 22)
return -1;
- return 56160 + 2160 * (chan - 16);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 16));
case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
if (chan < 25 || chan > 29)
return -1;
- return 56160 + 2160 * (chan - 24);
+ return MHZ_TO_KHZ(56160 + 2160 * (chan - 24));
default:
return -1;
}
}
/**
- * ieee80211_chan_to_freq - Convert channel info to frequency
+ * ieee80211_chan_to_freq_khz - Convert channel info to frequency KHz
* @country: Country code, if known; otherwise, global operating class is used
* @op_class: Operating class
* @chan: Channel number
- * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ * Returns: Frequency in KHz or -1 if the specified channel is unknown
*/
-int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
+int ieee80211_chan_to_freq_khz(const char *country, u8 op_class, u8 chan)
{
int freq;
if (country_match(us_op_class_cc, country)) {
- freq = ieee80211_chan_to_freq_us(op_class, chan);
+ freq = ieee80211_chan_to_freq_khz_us(op_class, chan);
if (freq > 0)
return freq;
}
if (country_match(eu_op_class_cc, country)) {
- freq = ieee80211_chan_to_freq_eu(op_class, chan);
+ freq = ieee80211_chan_to_freq_khz_eu(op_class, chan);
if (freq > 0)
return freq;
}
if (country_match(jp_op_class_cc, country)) {
- freq = ieee80211_chan_to_freq_jp(op_class, chan);
+ freq = ieee80211_chan_to_freq_khz_jp(op_class, chan);
if (freq > 0)
return freq;
}
if (country_match(cn_op_class_cc, country)) {
- freq = ieee80211_chan_to_freq_cn(op_class, chan);
+ freq = ieee80211_chan_to_freq_khz_cn(op_class, chan);
if (freq > 0)
return freq;
}
- return ieee80211_chan_to_freq_global(op_class, chan);
+ return ieee80211_chan_to_freq_khz_global(op_class, chan);
+}
+
+/**
+ * ieee80211_chan_to_freq - Convert channel info to frequency
+ * @country: Country code, if known; otherwise, global operating class is used
+ * @op_class: Operating class
+ * @chan: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
+{
+ int freq_khz = ieee80211_chan_to_freq_khz(country, op_class, chan);
+ if (freq_khz < 0)
+ return -1;
+
+ return KHZ_TO_MHZ(freq_khz);
}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 8dc38e21515f..ab0031cebe47 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -307,6 +307,7 @@ int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[],
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
+int ieee80211_chan_to_freq_khz(const char *country, u8 op_class, u8 chan);
enum hostapd_hw_mode
ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
enum oper_chan_width chanwidth,
--
2.43.0
More information about the Hostap
mailing list