This commit adds support for specifying a frequency in khz. The predominate use case is S1G. Many S1G channels are centered on frequencies which a MHz value does not support. Additional freq_khz parameters have been added as required to the key structures that maintain the operating parameters of a hostapd AP. These freq_khz params have been added to key functions alongside the traditional freq parameter as an alternative. The extent of this commit is the support of core BSS functionality using freq_khz. It is intended that several follow up commits will make use of this concept to support more advanced features. Because this commit has introduced an alternative parameter that is used instead of the traditional freq param we needed to introduce logic that would support this change. We opted for logic that checks if freq_khz is set, and if so, uses that parameter going forward, otherwise if freq_khz is not set, freq is used as per the existing use case. This approach prevents regression for existing code. The kernel maintains frequencies by using a combination of freq and freq_offset parameters. This patch includes a number of changes to support this concept. Signed-off-by: Gilad Itzkovitch <gilad.itzkovitch@xxxxxxxxxxxxxx> --- src/ap/ap_drv_ops.c | 8 +++-- src/ap/ap_drv_ops.h | 3 +- src/ap/beacon.c | 1 + src/ap/dfs.c | 9 ++++-- src/ap/drv_callbacks.c | 10 ++++--- src/ap/hostapd.c | 6 ++-- src/ap/hostapd.h | 10 +++++-- src/ap/hw_features.c | 48 ++++++++++++++++++------------ src/ap/hw_features.h | 2 +- src/common/defs.h | 6 ++++ src/common/hw_features_common.c | 28 ++++++++++------- src/common/hw_features_common.h | 13 ++++---- src/common/ieee802_11_common.c | 13 ++++++++ src/common/ieee802_11_common.h | 2 ++ src/drivers/driver.h | 14 +++++++++ src/drivers/driver_nl80211.c | 25 ++++++++++++++-- src/drivers/driver_nl80211_capa.c | 7 ++++- src/drivers/driver_nl80211_event.c | 26 +++++++++------- wpa_supplicant/ap.c | 11 ++++--- wpa_supplicant/ap.h | 4 +-- wpa_supplicant/config_ssid.h | 5 ++++ wpa_supplicant/events.c | 1 + wpa_supplicant/mesh.c | 1 + wpa_supplicant/wpa_supplicant.c | 4 ++- wpa_supplicant/wpa_supplicant_i.h | 1 + 25 files changed, 188 insertions(+), 70 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index aa4dbe9eb..2433657b3 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -558,7 +558,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_khz, 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, @@ -567,7 +568,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_khz, + channel, edmg, edmg_channel, ht_enabled, vht_enabled, he_enabled, eht_enabled, sec_channel_offset, oper_chwidth, @@ -846,7 +848,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 023cbf1f8..be486be77 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -65,7 +65,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, const u8 *addr, int idx, 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_khz, + 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 de944fed3..159c69baf 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -2134,6 +2134,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_khz, 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 e8c5ec9ac..2e275de7e 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -826,6 +826,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) if (is_6ghz_freq(iface->freq)) return 1; + if (is_s1g_freq(iface->freq_khz)) + return 1; + if (!iface->current_mode) { /* * This can happen with drivers that do not provide mode @@ -955,6 +958,7 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface, int channel, int freq, + int freq_khz, int secondary_channel, u8 current_vht_oper_chwidth, u8 oper_centr_freq_seg0_idx, @@ -984,7 +988,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, freq_khz, channel, iface->conf->enable_edmg, iface->conf->edmg_channel, iface->conf->ieee80211n, @@ -1117,7 +1121,7 @@ hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface) hostpad_dfs_update_background_chain(iface); return hostapd_dfs_request_channel_switch( - iface, iface->conf->channel, iface->freq, + iface, iface->conf->channel, iface->freq, 0, iface->conf->secondary_channel, current_vht_oper_chwidth, hostapd_get_oper_centr_freq_seg0_idx(iface->conf), hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); @@ -1409,6 +1413,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) return hostapd_dfs_request_channel_switch(iface, channel->chan, channel->freq, + channel->freq_khz, secondary_channel, current_vht_oper_chwidth, oper_centr_freq_seg0_idx, diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 7da5c524c..d06cf1e2f 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -857,8 +857,8 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, } -void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset, int width, int cf1, int cf2, +void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int freq_khz, + int ht, int offset, int width, int cf1, int cf2, u16 punct_bitmap, int finished) { #ifdef NEED_AP_MLME @@ -888,7 +888,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, freq_khz); if (!channel) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, @@ -1111,6 +1111,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd, if (hapd->iface->freq > 0 && !hw_get_chan(mode->mode, hapd->iface->freq, + hapd->iface->freq_khz, hapd->iface->hw_features, hapd->iface->num_hw_features)) continue; @@ -1135,7 +1136,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) { @@ -2024,6 +2025,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (!data) break; hostapd_event_ch_switch(hapd, data->ch_switch.freq, + data->ch_switch.freq_khz, data->ch_switch.ht_enabled, data->ch_switch.ch_offset, data->ch_switch.ch_width, diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index ef8800c8c..af0028d58 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2156,7 +2156,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_khz, hapd->iconf->channel, hapd->iconf->enable_edmg, hapd->iconf->edmg_channel, @@ -3566,7 +3567,7 @@ static 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; @@ -3579,6 +3580,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, if (old_params && hostapd_set_freq_params(old_params, conf->hw_mode, hostapd_hw_get_freq(hapd, conf->channel), + 0, conf->channel, conf->enable_edmg, conf->edmg_channel, conf->ieee80211n, conf->ieee80211ac, conf->ieee80211ax, diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 5e16bc389..25a4e3a50 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -551,6 +551,12 @@ struct hostapd_iface { struct hostapd_rate_data *current_rates; int *basic_rates; int freq; + /* + * freq_khz was added to support S1G frequencies. + * This variable could be use in other modes of operation. + * However, this is not currently supported. + */ + int freq_khz; /* Background radar configuration */ struct { @@ -724,8 +730,8 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len, int ssi_signal); -void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset, int width, int cf1, int cf2, +void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int freq_khz, + int ht, int offset, int width, int cf1, int cf2, u16 punct_bitmap, int finished); struct survey_results; void hostapd_event_get_survey(struct hostapd_iface *iface, diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index f836be488..1a785f877 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -235,11 +235,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); @@ -274,10 +274,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); @@ -795,15 +795,16 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface) static int hostapd_is_usable_chan(struct hostapd_iface *iface, - int frequency, int primary) + int frequency, int frequency_khz, 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, + frequency_khz, NULL, iface->hw_features, + iface->num_hw_features); if (!chan) return 0; @@ -813,7 +814,8 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface, wpa_printf(MSG_INFO, "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s", - frequency, primary ? "primary" : "secondary", + frequency_khz ? frequency_khz : frequency, + primary ? "primary" : "secondary", chan->flag, chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); @@ -835,7 +837,8 @@ 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, + iface->freq_khz, NULL, iface->hw_features, iface->num_hw_features); if (!pri_chan) @@ -865,7 +868,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface) if (num_of_enabled > 4) return 0; - if (!hostapd_is_usable_chan(iface, freq, 1)) + if (!hostapd_is_usable_chan(iface, freq, 0, 1)) return 0; if (contiguous > max_contiguous) @@ -949,18 +952,23 @@ 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_khz, NULL, iface->hw_features, iface->num_hw_features); if (!pri_chan) { wpa_printf(MSG_ERROR, "Primary frequency not present"); return 0; } - if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) { + if (!hostapd_is_usable_chan(iface, pri_chan->freq, + pri_chan->freq_khz, + pri_chan->freq_khz ? 0 : 1)) { wpa_printf(MSG_ERROR, "Primary frequency not allowed"); return 0; } + if (!hostapd_is_usable_edmg(iface)) return 0; @@ -971,7 +979,7 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) return 1; if (hostapd_is_usable_chan(iface, iface->freq + - iface->conf->secondary_channel * 20, 0)) { + iface->conf->secondary_channel * 20, 0, 0)) { if (iface->conf->secondary_channel == 1 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) return 1; @@ -984,14 +992,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; - if (hostapd_is_usable_chan(iface, secondary_freq, 0) && + if (hostapd_is_usable_chan(iface, secondary_freq, 0, 0) && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) { iface->conf->secondary_channel = 1; return 1; } secondary_freq = iface->freq - 20; - if (hostapd_is_usable_chan(iface, secondary_freq, 0) && + if (hostapd_is_usable_chan(iface, secondary_freq, 0, 0) && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) { iface->conf->secondary_channel = -1; return 1; @@ -1006,7 +1014,8 @@ 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 || iface->freq_khz > 0) && + !hw_mode_get_channel(mode, iface->freq, iface->freq_khz, &chan)) return true; if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 && @@ -1057,7 +1066,7 @@ static void hostapd_determine_mode(struct hostapd_iface *iface) static enum hostapd_chan_status hostapd_check_chans(struct hostapd_iface *iface) { - if (iface->freq) { + if (iface->freq || iface->freq_khz) { hostapd_determine_mode(iface); if (hostapd_is_usable_chans(iface)) return HOSTAPD_CHAN_VALID; @@ -1240,13 +1249,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_khz) { int i, channel; struct hostapd_hw_modes *mode; if (hapd->iface->current_mode) { channel = hw_get_chan(hapd->iface->current_mode->mode, freq, + freq_khz, hapd->iface->hw_features, hapd->iface->num_hw_features); if (channel) @@ -1259,7 +1269,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_khz, 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 ad0ddf7ff..5029c6560 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -19,7 +19,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_khz); 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/common/defs.h b/src/common/defs.h index c0c6dbe84..b92146406 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -529,4 +529,10 @@ enum sae_pwe { SAE_PWE_NOT_SET = 4, }; +#define MHZ_TO_KHZ(x) ((x) * 1000) +#define KHZ_TO_MHZ(x) ((x) / 1000) +#define KHZ_TO_S1G_OFFSET(x) ((x) % 1000) +/* If x (freq_khz) is 0 then print "MHz" else print "kHz" */ +#define KHZ_PRINT_FREQ_UNITS(x) (x) == 0 ? "MHz" : "kHz" + #endif /* DEFS_H */ diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index 584c6d275..0efddadbf 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -41,14 +41,17 @@ 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_khz, 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 (freq_khz && (ch->freq_khz == freq_khz)) { + return ch; + } + if (freq && (ch->freq == freq)) { if (chan) *chan = ch->chan; return ch; @@ -60,8 +63,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_khz, + int *chan, struct hostapd_hw_modes *hw_features, + int num_hw_features) { struct hostapd_channel_data *chan_data; int i; @@ -78,7 +82,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_khz, chan); if (chan_data) return chan_data; } @@ -97,12 +102,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_khz, 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_khz, &chan, hw_features, + num_hw_features); return chan; } @@ -380,10 +386,11 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode, 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_khz, + int channel, int enable_edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, int he_enabled, - bool eht_enabled, int sec_channel_offset, + bool eht_enabled, int sec_channel_offset, enum oper_chan_width oper_chwidth, int center_segment0, int center_segment1, u32 vht_caps, @@ -397,6 +404,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_khz = freq_khz; 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 82e028238..5402fd970 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_khz, 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_khz, + 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_khz, struct hostapd_hw_modes *hw_features, int num_hw_features); int allowed_ht40_channel_pair(enum hostapd_hw_mode mode, @@ -37,7 +39,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode, int sec_chan); 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_khz, + 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 a8f16b3d1..b039f828b 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1372,6 +1372,10 @@ ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel, /* TODO: more operating classes */ + /* S1G is not currently supported */ + if (is_s1g_freq(MHZ_TO_KHZ(freq))) + return NUM_HOSTAPD_MODES; + if (sec_channel > 1 || sec_channel < -1) return NUM_HOSTAPD_MODES; @@ -2824,6 +2828,15 @@ int get_6ghz_sec_channel(int channel) } +bool is_s1g_freq(int freq_khz) +{ + if (freq_khz < 1000000 && freq_khz > 0) + return true; + + return false; +} + + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len) { diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 785fe608a..fbc691034 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -281,6 +281,8 @@ bool is_6ghz_op_class(u8 op_class); bool is_6ghz_psc_frequency(int freq); int get_6ghz_sec_channel(int channel); +bool is_s1g_freq(int freq_khz); + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 101f98a72..bd58a8701 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -119,6 +119,11 @@ struct hostapd_channel_data { */ int freq; + /** + * freq_khz - Frequency in kHz + */ + int freq_khz; + /** * flag - Channel flags (HOSTAPD_CHAN_*) */ @@ -766,6 +771,11 @@ struct hostapd_freq_params { */ int freq; + /** + * freq_khz - Primary channel center frequency in kHz + */ + int freq_khz; + /** * channel - Channel number */ @@ -6357,6 +6367,7 @@ union wpa_event_data { /** * struct ch_switch * @freq: Frequency of new channel in MHz + * @freq_khz: Frequency of new channel in kHz * @ht_enabled: Whether this is an HT channel * @ch_offset: Secondary channel offset * @ch_width: Channel width @@ -6367,6 +6378,7 @@ union wpa_event_data { */ struct ch_switch { int freq; + int freq_khz; int ht_enabled; int ch_offset; enum chan_width ch_width; @@ -6450,6 +6462,7 @@ union wpa_event_data { /** * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED * @pri_freq: Selected primary frequency + * @pri_freq_khz: Selected primary frequency in kHz * @sec_freq: Selected secondary frequency * @edmg_channel: Selected EDMG channel * @vht_seg0_center_ch: VHT mode Segment0 center channel @@ -6469,6 +6482,7 @@ union wpa_event_data { */ struct acs_selected_channels { unsigned int pri_freq; + unsigned int pri_freq_khz; unsigned int sec_freq; u8 edmg_channel; u8 vht_seg0_center_ch; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index eb25730c5..32ee7cf87 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4847,6 +4847,15 @@ static int wpa_driver_nl80211_set_ap(void *priv, nl80211_put_dtim_period(msg, params->dtim_period) || nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) goto fail; + + if (is_s1g_freq(params->freq->freq_khz)) { + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + KHZ_TO_MHZ(params->freq->freq_khz)) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, + KHZ_TO_S1G_OFFSET(params->freq->freq_khz))) + goto fail; + } + if (params->proberesp && params->proberesp_len) { wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)", params->proberesp, params->proberesp_len); @@ -5190,8 +5199,20 @@ static int nl80211_put_freq_params(struct nl_msg *msg, u8 channel; wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq); - if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq)) - return -ENOBUFS; + if (is_s1g_freq(freq->freq_khz)) { + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + KHZ_TO_MHZ(freq->freq_khz))) + return -ENOBUFS; + wpa_printf(MSG_DEBUG, " * freq_offset=%d", + KHZ_TO_S1G_OFFSET(freq->freq_khz)); + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, + KHZ_TO_S1G_OFFSET(freq->freq_khz))) + return -ENOBUFS; + } else { + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq)) + return -ENOBUFS; + } + wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled); wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled); diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index b904398ca..ef18e9338 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -1644,6 +1644,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, os_memset(chan, 0, sizeof(*chan)); chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + chan->freq_khz = MHZ_TO_KHZ(chan->freq) + + nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_OFFSET]); chan->flag = 0; chan->allowed_bw = ~0; chan->dfs_cac_ms = 0; @@ -2126,7 +2128,10 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes, for (m = 0; m < *num_modes; m++) { if (!modes[m].num_channels) continue; - if (modes[m].channels[0].freq < 2000) { + if (modes[m].channels[0].freq_khz < 1000000 && + modes[m].channels[0].freq_khz > 0){ + modes[m].mode = HOSTAPD_MODE_IEEE80211A; + } else if (modes[m].channels[0].freq < 2000) { modes[m].num_channels = 0; continue; } else if (modes[m].channels[0].freq < 4000) { diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index a6f8c97ca..478158a91 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -993,11 +993,9 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, struct nlattr *ifindex, struct nlattr *link, - struct nlattr *freq, struct nlattr *type, - struct nlattr *bw, struct nlattr *cf1, - struct nlattr *cf2, - struct nlattr *punct_bitmap, - int finished) + struct nlattr *freq, struct nlattr *freq_off, + struct nlattr *type, struct nlattr *bw, struct nlattr *cf1, + struct nlattr *cf2, struct nlattr *punct_bitmap, int finished) { struct i802_bss *bss; union wpa_event_data data; @@ -1050,6 +1048,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, os_memset(&data, 0, sizeof(data)); data.ch_switch.freq = nla_get_u32(freq); + data.ch_switch.freq_khz = MHZ_TO_KHZ(data.ch_switch.freq) + + nla_get_u32(freq_off); data.ch_switch.ht_enabled = ht_enabled; data.ch_switch.ch_offset = chan_offset; if (punct_bitmap) @@ -1409,10 +1409,9 @@ static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv, static void mlme_event(struct i802_bss *bss, enum nl80211_commands cmd, struct nlattr *frame, struct nlattr *addr, struct nlattr *timed_out, - struct nlattr *freq, struct nlattr *ack, - struct nlattr *cookie, struct nlattr *sig, - struct nlattr *wmm, struct nlattr *req_ie, - struct nlattr *link) + struct nlattr *freq, struct nlattr *freq_offset, + struct nlattr *ack, struct nlattr *cookie, struct nlattr *sig, + struct nlattr *wmm, struct nlattr *req_ie, struct nlattr *link) { struct wpa_driver_nl80211_data *drv = bss->drv; u16 stype = 0, auth_type = 0; @@ -3570,7 +3569,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_UNPROT_DISASSOCIATE: mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], - tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_WIPHY_FREQ], + tb[NL80211_ATTR_WIPHY_FREQ_OFFSET], + tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE], tb[NL80211_ATTR_RX_SIGNAL_DBM], tb[NL80211_ATTR_STA_WME], @@ -3599,6 +3600,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_IFINDEX], tb[NL80211_ATTR_MLO_LINK_ID], tb[NL80211_ATTR_WIPHY_FREQ], + tb[NL80211_ATTR_WIPHY_FREQ_OFFSET], tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], @@ -3611,6 +3613,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_IFINDEX], tb[NL80211_ATTR_MLO_LINK_ID], tb[NL80211_ATTR_WIPHY_FREQ], + tb[NL80211_ATTR_WIPHY_FREQ_OFFSET], tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], @@ -3800,7 +3803,8 @@ int process_bss_event(struct nl_msg *msg, void *arg) case NL80211_CMD_FRAME_TX_STATUS: mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], - tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_WIPHY_FREQ_OFFSET], + tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE], tb[NL80211_ATTR_RX_SIGNAL_DBM], tb[NL80211_ATTR_STA_WME], NULL, diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index ff7c75644..10c2ece9e 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1838,8 +1838,8 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos) #endif /* CONFIG_CTRL_IFACE */ -void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, - int offset, int width, int cf1, int cf2, +void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int freq_khz, + int ht, int offset, int width, int cf1, int cf2, u16 punct_bitmap, int finished) { struct hostapd_iface *iface = wpa_s->ap_iface; @@ -1849,9 +1849,12 @@ void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, if (!iface) return; wpa_s->assoc_freq = freq; - if (wpa_s->current_ssid) + wpa_s->assoc_freq_khz = freq_khz; + if (wpa_s->current_ssid) { wpa_s->current_ssid->frequency = freq; - hostapd_event_ch_switch(iface->bss[0], freq, ht, + wpa_s->current_ssid->frequency_khz = freq_khz; + } + hostapd_event_ch_switch(iface->bss[0], freq, freq_khz, ht, offset, width, cf1, cf2, punct_bitmap, finished); } diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 5835ecd87..612999fe8 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -72,8 +72,8 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s); int ap_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings); int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr); -void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, - int offset, int width, int cf1, int cf2, +void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int freq_khz, + int ht, int offset, int width, int cf1, int cf2, u16 punct_bitmap, int finished); struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index ff045380e..7ee8d1d1a 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -524,6 +524,11 @@ struct wpa_ssid { */ int frequency; + /** + * frequency_khz - Channel frequency in kilohertz (kHz) + */ + int frequency_khz; + /** * enable_edmg - Enable EDMG feature in STA/AP mode * diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 896c53841..a8abe3568 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -5630,6 +5630,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s->current_ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) { wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, + data->ch_switch.freq_khz, data->ch_switch.ht_enabled, data->ch_switch.ch_offset, data->ch_switch.ch_width, diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c index 486fc6a09..90771e2d9 100644 --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c @@ -219,6 +219,7 @@ static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s) ¶ms->freq, ifmsh->conf->hw_mode, ifmsh->freq, + ifmsh->freq_khz, ifmsh->conf->channel, ifmsh->conf->enable_edmg, ifmsh->conf->edmg_channel, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 909a4bcfe..9d2d143ac 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2997,6 +2997,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_khz, freq->channel, ssid->enable_edmg, ssid->edmg_channel, freq->ht_enabled, freq->vht_enabled, freq->he_enabled, @@ -3027,6 +3028,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, bool is_6ghz; freq->freq = ssid->frequency; + freq->freq_khz = ssid->frequency_khz; if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) { struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid); @@ -3043,7 +3045,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) { if (wpa_s->hw.modes[i].mode == hw_mode && - hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq, + hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq, freq->freq_khz, NULL) != NULL) { mode = &wpa_s->hw.modes[i]; break; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index d5b3dab67..d333f9cbe 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -685,6 +685,7 @@ struct wpa_supplicant { struct wpa_bss *current_bss; int ap_ies_from_associnfo; unsigned int assoc_freq; + unsigned int assoc_freq_khz; u8 ap_mld_addr[ETH_ALEN]; u8 mlo_assoc_link_id; u16 valid_links; /* bitmap of valid MLO link IDs */ base-commit: 73372322038d2617f2be4542c0f2a5fa846fe911 -- 2.25.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap