[RFC 1/8] AP/STA: introduce support for freq_offset
Lachlan Hodges
lachlan.hodges at morsemicro.com
Wed May 27 23:38:50 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. This requires the introduction of a 'freq_offset'
parameter that sits alongside the 'freq' parameter. Where `freq_offset`
exists as a KHz component to be added to `freq`. This parameter is
introduced anywhere we pass `freq` such that an S1G channel
can be correctly defined.
Additionally, internal channel calculation functions have been
converted to KHz - similarly to cfg80211 - whilst the external
callers such as ieee80211_chan_to_freq() simply convert the internal
KHz result to MHz to reduce API churn.
Signed-off-by: Lachlan Hodges <lachlan.hodges at morsemicro.com>
---
src/ap/ap_drv_ops.c | 10 ++-
src/ap/ap_drv_ops.h | 3 +-
src/ap/beacon.c | 1 +
src/ap/dfs.c | 4 +-
src/ap/drv_callbacks.c | 6 +-
src/ap/hostapd.c | 29 ++++---
src/ap/hostapd.h | 1 +
src/ap/hw_features.c | 43 +++++-----
src/ap/hw_features.h | 2 +-
src/ap/interference.c | 2 +-
src/common/defs.h | 4 +
src/common/hw_features_common.c | 22 +++--
src/common/hw_features_common.h | 13 +--
src/common/ieee802_11_common.c | 136 ++++++++++++++++++------------
src/common/ieee802_11_common.h | 1 +
src/common/privsep_commands.h | 1 +
src/common/proximity_ranging.h | 3 +-
src/drivers/driver.h | 44 +++++++++-
src/drivers/driver_nl80211.c | 2 +-
src/drivers/driver_privsep.c | 7 +-
wpa_supplicant/ap.c | 4 +-
wpa_supplicant/bss.c | 5 +-
wpa_supplicant/bss.h | 2 +
wpa_supplicant/config.c | 1 +
wpa_supplicant/config_ssid.h | 12 +++
wpa_supplicant/ctrl_iface.c | 1 +
wpa_supplicant/driver_i.h | 9 +-
wpa_supplicant/events.c | 8 +-
wpa_supplicant/ibss_rsn.c | 2 +-
wpa_supplicant/mesh.c | 2 +-
wpa_supplicant/nan_supplicant.c | 2 +-
wpa_supplicant/p2p_supplicant.c | 4 +-
wpa_supplicant/pasn_supplicant.c | 4 +-
wpa_supplicant/scan.c | 10 ++-
wpa_supplicant/sme.c | 14 +--
wpa_supplicant/wpa_priv.c | 1 +
wpa_supplicant/wpa_supplicant.c | 7 +-
wpa_supplicant/wpa_supplicant_i.h | 2 +
38 files changed, 280 insertions(+), 144 deletions(-)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 61b823abe138..5862bedff238 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -646,7 +646,8 @@ int hostapd_flush(struct hostapd_data *hapd)
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int edmg, u8 edmg_channel,
+ int freq, int freq_offset, int channel,
+ int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
@@ -655,7 +656,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
struct hostapd_freq_params data;
struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
- if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+ if (hostapd_set_freq_params(&data, mode, freq, freq_offset,
+ channel, edmg,
edmg_channel, ht_enabled,
vht_enabled, he_enabled, eht_enabled,
sec_channel_offset, oper_chwidth,
@@ -883,7 +885,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, 0,
csa_offs, csa_offs_len, no_encrypt, 0,
link_id);
}
@@ -1094,7 +1096,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
return -1;
}
- if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+ if (hostapd_set_freq_params(&data, mode, freq, 0, channel, 0, 0,
ht_enabled,
vht_enabled, he_enabled, eht_enabled,
sec_channel_offset,
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 66913ed0fca7..fa84f709de91 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -71,7 +71,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, int link_id, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int edmg, u8 edmg_channel,
+ int freq, int freq_offset,
+ int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled, int he_enabled,
bool eht_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2521e3ab293e..2610106871a6 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2808,6 +2808,7 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+ iface->freq_offset,
iconf->channel, iconf->enable_edmg,
iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index d72c8ddb4464..2758454ff033 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1014,7 +1014,7 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
#endif /* CONFIG_MESH */
err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode,
- freq, channel,
+ freq, 0, channel,
iface->conf->enable_edmg,
iface->conf->edmg_channel,
iface->conf->ieee80211n,
@@ -1138,7 +1138,7 @@ hostapd_is_freq_in_current_hw_info(struct hostapd_iface *iface, int freq)
if (!iface->current_mode)
return false;
- chan = hw_mode_get_channel(iface->current_mode, freq, NULL);
+ chan = hw_mode_get_channel(iface->current_mode, freq, 0, NULL);
/* If channel data is not found for the given frequency, consider it is
* out of the current hardware info. */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 0c1e1c67c105..71e09cacfa56 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1275,7 +1275,7 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
is_dfs0 = hostapd_is_dfs_required(hapd->iface);
hapd->iface->freq = freq;
- channel = hostapd_hw_get_channel(hapd, freq);
+ channel = hostapd_hw_get_channel(hapd, freq, 0);
if (!channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
@@ -1528,7 +1528,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
if (mode->mode == acs_res->hw_mode) {
if (hapd->iface->freq > 0 &&
!hw_get_chan(mode->mode,
- hapd->iface->freq,
+ hapd->iface->freq, 0,
hapd->iface->hw_features,
hapd->iface->num_hw_features))
continue;
@@ -1553,7 +1553,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out;
}
pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
- acs_res->pri_freq, NULL,
+ acs_res->pri_freq, 0, NULL,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (!pri_chan) {
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 72a0bf503efe..a15e17919b3f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1976,7 +1976,7 @@ static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
if (mode->mode == iface->conf->hw_mode) {
if (iface->freq > 0 &&
- !hw_mode_get_channel(mode, iface->freq, NULL)) {
+ !hw_mode_get_channel(mode, iface->freq, iface->freq_offset, NULL)) {
mode = NULL;
continue;
}
@@ -2001,7 +2001,8 @@ static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
struct hostapd_channel_data *chan;
chan = hw_get_channel_freq(mode->mode,
- iface->freq, NULL,
+ iface->freq,
+ iface->freq_offset, NULL,
hw_features,
num_hw_features);
@@ -2036,7 +2037,8 @@ static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
struct hostapd_channel_data *chan;
chan = hw_get_channel_freq(mode->mode,
- iface->freq, NULL,
+ iface->freq,
+ iface->freq_offset, NULL,
hw_features,
num_hw_features);
if (!chan) {
@@ -2177,20 +2179,21 @@ static int setup_interface(struct hostapd_iface *iface)
static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
{
- int freq, i, j;
+ int freq_khz, i, j;
if (!iface->conf->channel)
return 0;
if (iface->conf->op_class) {
- freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
- iface->conf->channel);
- if (freq < 0) {
+ freq_khz = ieee80211_chan_to_freq_khz(NULL, iface->conf->op_class,
+ iface->conf->channel);
+ if (freq_khz < 0) {
wpa_printf(MSG_INFO,
"Could not convert op_class %u channel %u to operating frequency",
iface->conf->op_class, iface->conf->channel);
return -1;
}
- iface->freq = freq;
+ iface->freq = KHZ_TO_MHZ(freq_khz);
+ iface->freq_offset = KHZ_TO_S1G_OFFSET(freq_khz);
return 0;
}
@@ -2642,7 +2645,8 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
#endif /* CONFIG_MESH */
if (!delay_apply_cfg &&
- hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+ hostapd_set_freq(hapd, hapd->iconf->hw_mode,
+ iface->freq, iface->freq_offset,
hapd->iconf->channel,
hapd->iconf->enable_edmg,
hapd->iconf->edmg_channel,
@@ -4511,7 +4515,7 @@ int hostapd_change_config_freq(struct hostapd_data *hapd,
if (!params->channel) {
/* check if the new channel is supported by hw */
- params->channel = hostapd_hw_get_channel(hapd, params->freq);
+ params->channel = hostapd_hw_get_channel(hapd, params->freq, 0);
}
channel = params->channel;
@@ -4524,7 +4528,7 @@ int hostapd_change_config_freq(struct hostapd_data *hapd,
/* if a pointer to old_params is provided we save previous state */
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
- hostapd_hw_get_freq(hapd, conf->channel),
+ hostapd_hw_get_freq(hapd, conf->channel), 0,
conf->channel, conf->enable_edmg,
conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
@@ -4794,7 +4798,8 @@ int hostapd_force_channel_switch(struct hostapd_iface *iface,
if (!settings->freq_params.channel) {
/* Check if the new channel is supported */
settings->freq_params.channel = hostapd_hw_get_channel(
- iface->bss[0], settings->freq_params.freq);
+ iface->bss[0], settings->freq_params.freq,
+ settings->freq_params.freq_offset);
if (!settings->freq_params.channel)
return -1;
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index fb06a5afd935..362924aeff54 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -646,6 +646,7 @@ struct hostapd_iface {
int num_hw_features;
struct hostapd_hw_modes *current_mode;
int freq;
+ int freq_offset;
bool radar_detected;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index be8ed53522a8..6ac7cd9d8837 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -197,10 +197,11 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
continue;
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
- "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
+ "chan=%d freq=%d MHz freq_offset=%d KHz max_tx_power=%d dBm%s",
feature->mode,
feature->channels[j].chan,
feature->channels[j].freq,
+ feature->channels[j].freq_offset,
feature->channels[j].max_tx_power,
dfs ? dfs_info(&feature->channels[j]) : "");
}
@@ -333,11 +334,11 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
if (!iface->current_mode)
return 0;
- p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+ p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, 0, NULL,
iface->hw_features,
iface->num_hw_features);
- s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+ s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, 0, NULL,
iface->hw_features,
iface->num_hw_features);
@@ -372,10 +373,10 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
if (!iface->current_mode)
return 0;
- pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, 0,
NULL, iface->hw_features,
iface->num_hw_features);
- sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+ sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, 0,
NULL, iface->hw_features,
iface->num_hw_features);
@@ -920,15 +921,16 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
* -1 = not currently usable due to 6 GHz NO-IR
*/
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
- int frequency, int primary)
+ int frequency, int freq_offset, int primary)
{
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
- iface->hw_features, iface->num_hw_features);
+ chan = hw_get_channel_freq(iface->current_mode->mode, frequency,
+ freq_offset, NULL, iface->hw_features,
+ iface->num_hw_features);
if (!chan)
return 0;
@@ -965,7 +967,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
if (!iface->current_mode)
return 0;
pri_chan = hw_get_channel_freq(iface->current_mode->mode,
- iface->freq, NULL,
+ iface->freq, 0, NULL,
iface->hw_features,
iface->num_hw_features);
if (!pri_chan)
@@ -995,7 +997,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
if (num_of_enabled > 4)
return 0;
- err = hostapd_is_usable_chan(iface, freq, 1);
+ err = hostapd_is_usable_chan(iface, freq, 0, 1);
if (err <= 0)
return err;
@@ -1097,7 +1099,8 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
if (!iface->current_mode)
return 0;
pri_chan = hw_get_channel_freq(iface->current_mode->mode,
- iface->freq, NULL,
+ iface->freq,
+ iface->freq_offset, NULL,
iface->hw_features,
iface->num_hw_features);
if (!pri_chan) {
@@ -1105,7 +1108,8 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
return 0;
}
- err = hostapd_is_usable_chan(iface, pri_chan->freq, 1);
+ err = hostapd_is_usable_chan(iface, pri_chan->freq,
+ pri_chan->freq_offset, 1);
if (err <= 0) {
wpa_printf(MSG_ERROR, "Primary frequency not allowed");
return err;
@@ -1121,7 +1125,7 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
return 1;
err = hostapd_is_usable_chan(iface, iface->freq +
- iface->conf->secondary_channel * 20, 0);
+ iface->conf->secondary_channel * 20, 0, 0);
if (err > 0) {
if (iface->conf->secondary_channel == 1 &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
@@ -1135,14 +1139,14 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_freq = iface->freq + 20;
- err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
+ err2 = hostapd_is_usable_chan(iface, secondary_freq, 0, 0);
if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
secondary_freq = iface->freq - 20;
- err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
+ err2 = hostapd_is_usable_chan(iface, secondary_freq, 0, 0);
if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
@@ -1157,7 +1161,7 @@ static bool skip_mode(struct hostapd_iface *iface,
{
int chan;
- if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan))
+ if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, iface->freq_offset, &chan))
return true;
if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 &&
@@ -1427,13 +1431,14 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
}
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq, int freq_offset)
{
int i, channel;
struct hostapd_hw_modes *mode;
if (hapd->iface->current_mode) {
- channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+ channel = hw_get_chan(hapd->iface->current_mode->mode,
+ freq, freq_offset,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (channel)
@@ -1446,7 +1451,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
- channel = hw_get_chan(mode->mode, freq,
+ channel = hw_get_chan(mode->mode, freq, freq_offset,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (channel)
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 6f945cc7736b..4d73c3656146 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -20,7 +20,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err);
int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq, int freq_offset);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_check_edmg_capab(struct hostapd_iface *iface);
int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
diff --git a/src/ap/interference.c b/src/ap/interference.c
index c93cdc75f13f..44aa6c0019ef 100644
--- a/src/ap/interference.c
+++ b/src/ap/interference.c
@@ -552,7 +552,7 @@ int hostapd_incumbt_sig_intf_detected(struct hostapd_iface *iface, int freq,
goto exit;
}
if (hostapd_set_freq(
- iface->bss[0], iface->conf->hw_mode, iface->freq,
+ iface->bss[0], iface->conf->hw_mode, iface->freq, 0,
iface->conf->channel, iface->conf->enable_edmg,
iface->conf->edmg_channel, iface->conf->ieee80211n,
iface->conf->ieee80211ac,
diff --git a/src/common/defs.h b/src/common/defs.h
index c88766e7512a..ec602d660ace 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -585,4 +585,8 @@ 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)
+#define KHZ_TO_S1G_OFFSET(x) ((x) % 1000)
+
#endif /* DEFS_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index e928738ee568..32471ce36651 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -41,14 +41,15 @@ struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *
-hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq,
+ int freq_offset, int *chan)
{
int i;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *ch = &mode->channels[i];
- if (ch->freq == freq) {
+ if (MHZ_TO_KHZ(ch->freq) + ch->freq_offset == MHZ_TO_KHZ(freq) + freq_offset) {
if (chan)
*chan = ch->chan;
return ch;
@@ -60,8 +61,9 @@ hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
struct hostapd_channel_data *
-hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
- struct hostapd_hw_modes *hw_features, int num_hw_features)
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int freq_offset,
+ int *chan, struct hostapd_hw_modes *hw_features,
+ int num_hw_features)
{
struct hostapd_channel_data *chan_data;
int i;
@@ -78,7 +80,8 @@ hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
if (curr_mode->mode != mode)
continue;
- chan_data = hw_mode_get_channel(curr_mode, freq, chan);
+ chan_data = hw_mode_get_channel(curr_mode, freq,
+ freq_offset, chan);
if (chan_data)
return chan_data;
}
@@ -97,12 +100,13 @@ int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
}
-int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+int hw_get_chan(enum hostapd_hw_mode mode, int freq, int freq_offset,
struct hostapd_hw_modes *hw_features, int num_hw_features)
{
int chan;
- hw_get_channel_freq(mode, freq, &chan, hw_features, num_hw_features);
+ hw_get_channel_freq(mode, freq, freq_offset, &chan, hw_features,
+ num_hw_features);
return chan;
}
@@ -477,7 +481,8 @@ void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int enable_edmg,
+ int freq, int freq_offset,
+ int channel, int enable_edmg,
u8 edmg_channel, int ht_enabled,
int vht_enabled, int he_enabled,
bool eht_enabled, int sec_channel_offset,
@@ -498,6 +503,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
+ data->freq_offset = freq_offset;
data->channel = channel;
data->ht_enabled = ht_enabled;
data->vht_enabled = vht_enabled;
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 80e33adf2d5c..63c0893e2c2b 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -15,14 +15,16 @@
struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
int chan, int *freq);
struct hostapd_channel_data *
-hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan);
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq,
+ int freq_offset, int *chan);
struct hostapd_channel_data *
-hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
- struct hostapd_hw_modes *hw_features, int num_hw_features);
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int freq_offset,
+ int *chan, struct hostapd_hw_modes *hw_features,
+ int num_hw_features);
int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
-int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+int hw_get_chan(enum hostapd_hw_mode mode, int freq, int freq_offset,
struct hostapd_hw_modes *hw_features, int num_hw_features);
int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
@@ -39,7 +41,8 @@ void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
enum oper_chan_width *width, u8 *seg0, u8 *seg1);
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int edmg, u8 edmg_channel,
+ int freq, int freq_offset,
+ int channel, int edmg, u8 edmg_channel,
int ht_enabled,
int vht_enabled, int he_enabled,
bool eht_enabled, int sec_channel_offset,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 32342f7d991c..a3b9592e23bc 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1825,7 +1825,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 */
@@ -1833,7 +1833,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 */
@@ -1842,12 +1842,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 */
@@ -1855,11 +1855,11 @@ 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;
@@ -1867,22 +1867,22 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 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 */
@@ -1890,7 +1890,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 */
@@ -1899,41 +1899,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) {
@@ -1942,11 +1942,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 */
@@ -1958,7 +1958,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 */
@@ -1968,30 +1968,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 */
@@ -1999,44 +1999,56 @@ 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) {
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ if (chan < 1 || chan > 51)
+ return -1;
+ return 902000 + chan * 500;
case 81:
/* 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 */
@@ -2045,32 +2057,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.. */
@@ -2079,7 +2091,7 @@ 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;
@@ -2087,60 +2099,76 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
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 5d9c840cee76..ed0147812fde 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -264,6 +264,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,
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index d2c4bbd5e8b6..85e1e89977b2 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -63,6 +63,7 @@ struct privsep_cmd_associate {
size_t ssid_len;
int hwmode;
int freq;
+ int freq_offset;
int channel;
int pairwise_suite;
int group_suite;
diff --git a/src/common/proximity_ranging.h b/src/common/proximity_ranging.h
index 902ced541040..dbcd04a0ae9e 100644
--- a/src/common/proximity_ranging.h
+++ b/src/common/proximity_ranging.h
@@ -563,7 +563,8 @@ struct pr_config {
* Returns: 0 on success, -1 on failure
*/
int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len,
- int noack, unsigned int freq, unsigned int wait);
+ int noack, unsigned int freq, unsigned int freq_offset,
+ unsigned int wait);
/**
* negotiation_started - Called when PASN negotiation begins
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6450c66b5d3a..c382bf90ccf6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -126,6 +126,11 @@ struct hostapd_channel_data {
*/
int freq;
+ /**
+ * freq_offset - Frequency offset from @freq in KHz
+ */
+ int freq_offset;
+
/**
* flag - Channel flags (HOSTAPD_CHAN_*)
*/
@@ -374,6 +379,7 @@ struct hostapd_multi_hw_info {
* @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
* @bssid: BSSID
* @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
+ * @freq_offset: frequency offset of the channel from @freq in KHz
* @max_cw: the max channel width of the connection (calculated during scan
* result processing)
* @beacon_int: beacon interval in TUs (host byte order)
@@ -414,6 +420,7 @@ struct wpa_scan_res {
unsigned int flags;
u8 bssid[ETH_ALEN];
int freq;
+ int freq_offset;
enum chan_width max_cw;
u16 beacon_int;
u16 caps;
@@ -521,6 +528,13 @@ struct wpa_driver_scan_params {
*/
int *freqs;
+ /**
+ * freq_offset - Frequency offset in KHz
+ *
+ * Each @freqs value will have this frequency offset applied.
+ */
+ int freq_offset;
+
/**
* filter_ssids - Filter for reporting SSIDs
*
@@ -759,6 +773,7 @@ struct wpa_driver_scan_params {
*/
struct wpa_driver_auth_params {
int freq;
+ int freq_offset;
const u8 *bssid;
const u8 *ssid;
size_t ssid_len;
@@ -839,6 +854,11 @@ struct hostapd_freq_params {
*/
int freq;
+ /**
+ * freq_offset - Frequency offset in KHz from @freq
+ */
+ int freq_offset;
+
/**
* channel - Channel number
*/
@@ -875,6 +895,13 @@ struct hostapd_freq_params {
*/
int center_freq1;
+ /**
+ * center_freq1_offset - Segment 0 center frequency offset in KHz
+ *
+ * Valid for S1G.
+ */
+ int center_freq1_offset;
+
/**
* center_freq2 - Segment 1 center frequency in MHz
*
@@ -3891,6 +3918,7 @@ struct wpa_driver_ops {
* @noack: Do not wait for this frame to be acked (disable retries)
* @freq: Frequency (in MHz) to send the frame on, or 0 to let the
* driver decide
+ * @freq_offset: Frequency offset (in KHz) from @freq to send the frame on
* @csa_offs: Array of CSA offsets or %NULL
* @csa_offs_len: Number of elements in csa_offs
* @no_encrypt: Do not encrypt frame even if appropriate key exists
@@ -3900,8 +3928,8 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
- int noack, unsigned int freq, const u16 *csa_offs,
- size_t csa_offs_len, int no_encrypt,
+ int noack, unsigned int freq, unsigned int freq_offset,
+ const u16 *csa_offs, size_t csa_offs_len, int no_encrypt,
unsigned int wait, int link_id);
/**
@@ -6822,6 +6850,11 @@ union wpa_event_data {
*/
unsigned int freq;
+ /**
+ * freq_offset - Frequency offset from @freq in KHz
+ */
+ unsigned int freq_offset;
+
/**
* wmm_params - WMM parameters used in this association.
*/
@@ -7215,6 +7248,11 @@ union wpa_event_data {
*/
int freq;
+ /**
+ * freq_offset - Frequency offset (in KHz) from @freq on which the frame was received
+ */
+ int freq_offset;
+
/**
* ssi_signal - Signal strength in dBm (or 0 if not available)
*/
@@ -7418,6 +7456,7 @@ union wpa_event_data {
/**
* struct ch_switch
* @freq: Frequency of new channel in MHz
+ * @freq_offset: Frequency offset from @freq in KHz
* @ht_enabled: Whether this is an HT channel
* @ch_offset: Secondary channel offset
* @ch_width: Channel width
@@ -7428,6 +7467,7 @@ union wpa_event_data {
*/
struct ch_switch {
int freq;
+ int freq_offset;
int ht_enabled;
int ch_offset;
enum chan_width ch_width;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 033e4eb46e8b..f79558911feb 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -11850,7 +11850,7 @@ static bool nl80211_is_drv_shared(void *priv, int link_id)
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len, int noack,
- unsigned int freq,
+ unsigned int freq, unsigned int freq_offset,
const u16 *csa_offs, size_t csa_offs_len,
int no_encrypt, unsigned int wait,
int link_id)
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index d7c6b01a317e..e53421179d01 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -306,10 +306,10 @@ static int wpa_driver_privsep_associate(
int res;
size_t buflen;
- wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d freq_offset=%d pairwise_suite=%d "
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
- __func__, priv, params->freq.freq, params->pairwise_suite,
- params->group_suite, params->key_mgmt_suite,
+ __func__, priv, params->freq.freq, params->freq.freq_offset,
+ params->pairwise_suite, params->group_suite, params->key_mgmt_suite,
params->auth_alg, params->mode);
buflen = sizeof(*data) + params->wpa_ie_len;
@@ -323,6 +323,7 @@ static int wpa_driver_privsep_associate(
data->ssid_len = params->ssid_len;
data->hwmode = params->freq.mode;
data->freq = params->freq.freq;
+ data->freq_offset = params->freq.freq_offset;
data->channel = params->freq.channel;
data->pairwise_suite = params->pairwise_suite;
data->group_suite = params->group_suite;
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index d0a1a96fd5b4..8a3f86c2e0ff 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -457,7 +457,8 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
{
if (iface == wpa_s ||
iface->wpa_state < WPA_AUTHENTICATING ||
- (int) iface->assoc_freq != ssid->frequency)
+ MHZ_TO_KHZ(iface->assoc_freq) + iface->assoc_freq_offset !=
+ MHZ_TO_KHZ(ssid->frequency) + ssid->freq_offset)
continue;
/*
@@ -1182,6 +1183,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->assoc_freq_offset = ssid->freq_offset;
wpa_s->ap_iface->conf->enable_edmg = ssid->enable_edmg;
wpa_s->ap_iface->conf->edmg_channel = ssid->edmg_channel;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 2cd9cc8c73f5..304486f4b650 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -384,6 +384,7 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
dst->flags = src->flags;
os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
dst->freq = src->freq;
+ dst->freq_offset = src->freq_offset;
dst->max_cw = src->max_cw;
dst->beacon_int = src->beacon_int;
dst->caps = src->caps;
@@ -635,9 +636,9 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
}
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
- " SSID '%s' freq %d%s",
+ " SSID '%s' freq %d freq_offset %d%s",
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
- bss->freq, extra);
+ bss->freq, bss->freq_offset, extra);
wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
return bss;
}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index d9d0401cef32..5580fc0d32c4 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -93,6 +93,8 @@ struct wpa_bss {
size_t ssid_len;
/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
int freq;
+ /** Frequency offset from @freq of the channel in KHz */
+ int freq_offset;
/** The max channel width supported by both the AP and the STA */
enum chan_width max_cw;
/** Beacon interval in TUs (host byte order) */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index e99036366681..6bb57ae7dc19 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2959,6 +2959,7 @@ static const struct parse_data ssid_fields[] = {
#ifdef CONFIG_PASN
{ FUNC(pasn_groups) },
#endif /* CONFIG_PASN */
+ { INT_RANGE(scan_freq_offset, 0, 999)},
};
#undef OFFSET
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 7c60d4e38cab..aa3c1a166819 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -547,6 +547,11 @@ struct wpa_ssid {
*/
int frequency;
+ /**
+ * freq_offset - Channel frequency offset from @frequency in KHz
+ */
+ int freq_offset;
+
/**
* enable_edmg - Enable EDMG feature in STA/AP mode
*
@@ -653,6 +658,13 @@ struct wpa_ssid {
*/
int *scan_freq;
+ /**
+ * scan_freq_offset - Frequency offset in KHz
+ *
+ * To be applied to each entry in @scan_freq array.
+ */
+ int scan_freq_offset;
+
/**
* bgscan - Background scan and roaming parameters or %NULL if none
*
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ce9bc3277a32..93ceeb223cd9 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10582,6 +10582,7 @@ static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
params.freq.freq = wpa_s->sme.freq;
+ params.freq.freq_offset = wpa_s->sme.freq_offset;
if (wpa_s->last_assoc_req_wpa_ie) {
params.wpa_ie = wpabuf_head(wpa_s->last_assoc_req_wpa_ie);
params.wpa_ie_len = wpabuf_len(wpa_s->last_assoc_req_wpa_ie);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 13ac06bfd8b2..930946ebcd7a 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -334,12 +334,13 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
const u8 *data, size_t data_len, int noack,
- unsigned int freq, unsigned int wait)
+ unsigned int freq, unsigned int freq_offset,
+ unsigned int wait)
{
if (wpa_s->driver->send_mlme)
- return wpa_s->driver->send_mlme(wpa_s->drv_priv,
- data, data_len, noack,
- freq, NULL, 0, 0, wait, -1);
+ return wpa_s->driver->send_mlme(wpa_s->drv_priv, data, data_len,
+ noack, freq, freq_offset, NULL,
+ 0, 0, wait, -1);
return -1;
}
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 1d203a8004b7..f9c51994cae4 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1659,11 +1659,11 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
if (debug_print) {
wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR
- " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s",
+ " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d freq_offset=%d %s%s",
i, MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len),
wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
- bss->freq,
+ bss->freq, bss->freq_offset,
wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ?
" wps" : "",
(wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
@@ -5557,8 +5557,10 @@ static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
{
struct wpa_bss *bss;
bss = wpa_bss_get_bssid(wpa_s, target_ap_addr);
- if (bss)
+ if (bss) {
wpa_s->sme.freq = bss->freq;
+ wpa_s->sme.freq_offset = bss->freq_offset;
+ }
wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT;
sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr,
WLAN_AUTH_FT);
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 06228d0ef6c9..3d26bc1368a4 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -533,7 +533,7 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
seq, MAC2STR(da));
- return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0);
+ return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0, 0);
}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 8f7143f6ea63..30547b19d108 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -198,7 +198,7 @@ static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s)
if (hostapd_set_freq_params(
¶ms->freq,
ifmsh->conf->hw_mode,
- ifmsh->freq,
+ ifmsh->freq, 0,
ifmsh->conf->channel,
ifmsh->conf->enable_edmg,
ifmsh->conf->edmg_channel,
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index b842293dfccc..4ad92a7993ab 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -1044,7 +1044,7 @@ static int wpas_nan_pasn_send_cb(void *ctx, const u8 *data, size_t data_len)
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_mlme(wpa_s, data, data_len, 0, 0, 0);
+ return wpa_drv_send_mlme(wpa_s, data, data_len, 0, 0, 0, 0);
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 7ae584a5a9d9..66d396826d56 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3349,7 +3349,7 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- freq, 0);
+ freq, 0, 0);
}
@@ -5739,7 +5739,7 @@ static int wpas_p2p_pasn_send_mgmt(void *ctx, const u8 *data, size_t data_len,
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+ return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, 0, wait);
}
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index e2862c6fab0c..b3939ed24d04 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -76,7 +76,7 @@ static int wpas_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+ return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, 0, wait);
}
@@ -1637,7 +1637,7 @@ int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr,
* without a radio work.
*/
ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- bss->freq, 0);
+ bss->freq, 0, 0);
wpabuf_free(buf);
wpa_printf(MSG_DEBUG, "PASN: deauth: send_mlme ret=%d", ret);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index b7050585651f..92c1143700f6 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1327,6 +1327,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
os_free(params.freqs);
params.freqs = NULL;
}
+ params.freq_offset = tssid->scan_freq_offset;
freqs_set = 1;
}
int_array_sort_unique(params.freqs);
@@ -2553,20 +2554,20 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
wpa_printf(MSG_EXCESSIVE, MACSTR
- " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
+ " ssid=%s freq=%d freq_offset=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
MAC2STR(r->bssid),
wpa_ssid_txt(ssid, ssid_len),
- r->freq, r->qual,
+ r->freq, r->freq_offset, r->qual,
r->noise, noise_valid ? "" : "~", r->level,
r->snr, r->snr >= GREAT_SNR ? "*" : "",
r->flags,
r->age, r->est_throughput);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR
- " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u",
+ " ssid=%s freq=%d freq_offset=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u",
MAC2STR(r->bssid),
wpa_ssid_txt(ssid, ssid_len),
- r->freq, r->qual,
+ r->freq, r->freq_offset, r->qual,
r->noise, r->level, r->flags, r->age,
r->est_throughput);
}
@@ -3872,6 +3873,7 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->p2p_include_6ghz = src->p2p_include_6ghz;
params->non_coloc_6ghz = src->non_coloc_6ghz;
params->min_probe_req_content = src->min_probe_req_content;
+ params->freq_offset = src->freq_offset;
return params;
failed:
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index b0b77fe60335..1dd1f79601b3 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1257,6 +1257,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_s->reassociate = 0;
params.freq = bss->freq;
+ params.freq_offset = bss->freq_offset;
params.bssid = bss->bssid;
params.ssid = bss->ssid;
params.ssid_len = bss->ssid_len;
@@ -1267,6 +1268,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_s->sme.prev_bssid_set = 0;
wpa_s->sme.freq = params.freq;
+ wpa_s->sme.freq_offset = params.freq_offset;
os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
wpa_s->sme.ssid_len = params.ssid_len;
@@ -1892,8 +1894,9 @@ no_fils:
wpa_supplicant_cancel_scan(wpa_s);
wpa_msg(wpa_s, MSG_INFO, "SME: Trying to authenticate with " MACSTR
- " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
- wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
+ " (SSID='%s' freq=%d freq_offset=%d)", MAC2STR(params.bssid),
+ wpa_ssid_txt(params.ssid, params.ssid_len),
+ params.freq, params.freq_offset);
eapol_sm_notify_portValid(wpa_s->eapol, false);
wpa_clear_keys(wpa_s, bss->bssid);
@@ -2153,7 +2156,7 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
wpa_s->sme.ext_ml_auth ?
wpa_s->own_addr : NULL);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- wpa_s->sme.ext_auth_freq, 0);
+ wpa_s->sme.ext_auth_freq, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -2272,7 +2275,7 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
wpa_s->own_addr : NULL);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- wpa_s->sme.ext_auth_freq, 0);
+ wpa_s->sme.ext_auth_freq, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
}
@@ -2476,7 +2479,7 @@ static int sme_external_auth_send_802_1x(struct wpa_supplicant *wpa_s,
wpa_s->own_addr : NULL);
if (wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf),
- 0, 0, 0) < 0) {
+ 0, 0, 0, 0) < 0) {
wpa_printf(MSG_INFO,
"IEEE 802.1X: Failed to send Authentication frame");
goto fail;
@@ -4509,6 +4512,7 @@ mscs_fail:
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
params.freq.freq = wpa_s->sme.freq;
+ params.freq.freq_offset = wpa_s->sme.freq_offset;
params.bg_scan_period = ssid ? ssid->bg_scan_period : -1;
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 88f3f2a52356..b49da9f299d1 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -325,6 +325,7 @@ static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
params.ssid_len = assoc->ssid_len;
params.freq.mode = assoc->hwmode;
params.freq.freq = assoc->freq;
+ params.freq.freq_offset = assoc->freq_offset;
params.freq.channel = assoc->channel;
if (assoc->wpa_ie_len) {
params.wpa_ie = (u8 *) (assoc + 1);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 367448eaf70b..be9db6d646fd 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2953,8 +2953,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"Driver does not support mesh mode");
return;
}
- if (bss)
+ if (bss) {
ssid->frequency = bss->freq;
+ ssid->freq_offset = bss->freq_offset;
+ }
if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
@@ -3525,6 +3527,7 @@ static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s,
skip_80mhz:
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
+ freq->freq_offset,
freq->channel, ssid->enable_edmg,
ssid->edmg_channel, freq->ht_enabled,
freq->vht_enabled, freq->he_enabled,
@@ -3555,6 +3558,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
bool is_6ghz, is_24ghz;
freq->freq = ssid->frequency;
+ freq->freq_offset = ssid->freq_offset;
if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
@@ -4737,6 +4741,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
params.bssid = bss->bssid;
params.freq.freq = bss->freq;
+ params.freq.freq_offset = bss->freq_offset;
}
params.bssid_hint = bss->bssid;
params.freq_hint = bss->freq;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index fd327cdb37dc..e446f683a002 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -798,6 +798,7 @@ struct wpa_supplicant {
struct wpa_bss *current_bss;
int ap_ies_from_associnfo;
unsigned int assoc_freq;
+ unsigned int assoc_freq_offset;
u8 ap_mld_addr[ETH_ALEN];
u8 mlo_assoc_link_id;
u16 valid_links; /* bitmap of valid MLO link IDs */
@@ -1077,6 +1078,7 @@ struct wpa_supplicant {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int freq;
+ int freq_offset;
u8 assoc_req_ie[1500];
size_t assoc_req_ie_len;
int mfp;
--
2.43.0
More information about the Hostap
mailing list