diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 1cd9f3959..4f7069bf2 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -3517,6 +3517,101 @@ static int nl80211_set_mesh_config(void *priv, #endif /* CONFIG_MESH */ +static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags, + struct wpa_driver_ap_params *params) +{ + struct nlattr *bands, *band; + struct nl80211_txrate_vht vht_rate; + + if (!params->freq || + (params->beacon_rate == 0 && + params->rate_type == BEACON_RATE_LEGACY)) + return 0; + + bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); + if (!bands) + return -1; + + switch (params->freq->mode) { + case HOSTAPD_MODE_IEEE80211B: + case HOSTAPD_MODE_IEEE80211G: + band = nla_nest_start(msg, NL80211_BAND_2GHZ); + break; + case HOSTAPD_MODE_IEEE80211A: + band = nla_nest_start(msg, NL80211_BAND_5GHZ); + break; + case HOSTAPD_MODE_IEEE80211AD: + band = nla_nest_start(msg, NL80211_BAND_60GHZ); + break; + default: + return 0; + } + + if (!band) + return -1; + + os_memset(&vht_rate, 0, sizeof(vht_rate)); + + switch (params->rate_type) { + case BEACON_RATE_LEGACY: + if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) { + wpa_printf(MSG_INFO, + "nl80211: Driver does not support setting Beacon frame rate (legacy)"); + return -1; + } + + if (nla_put_u8(msg, NL80211_TXRATE_LEGACY, + (u8) params->beacon_rate / 5) || + nla_put(msg, NL80211_TXRATE_HT, 0, NULL) || + (params->freq->vht_enabled && + nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate), + &vht_rate))) + return -1; + + wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)", + params->beacon_rate); + break; + case BEACON_RATE_HT: + if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) { + wpa_printf(MSG_INFO, + "nl80211: Driver does not support setting Beacon frame rate (HT)"); + return -1; + } + if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) || + nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) || + (params->freq->vht_enabled && + nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate), + &vht_rate))) + return -1; + wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u", + params->beacon_rate); + break; + case BEACON_RATE_VHT: + if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) { + wpa_printf(MSG_INFO, + "nl80211: Driver does not support setting Beacon frame rate (VHT)"); + return -1; + } + vht_rate.mcs[0] = BIT(params->beacon_rate); + if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL)) + return -1; + if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL)) + return -1; + if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate), + &vht_rate)) + return -1; + wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u", + params->beacon_rate); + break; + } + + nla_nest_end(msg, band); + nla_nest_end(msg, bands); + + return 0; +} + + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { @@ -3547,6 +3642,8 @@ static int wpa_driver_nl80211_set_ap(void *priv, params->tail, params->tail_len); wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex); wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int); + wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate); + wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type); wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period); wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid", params->ssid, params->ssid_len); @@ -3556,6 +3653,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail) || nl80211_put_beacon_int(msg, params->beacon_int) || + nl80211_put_beacon_rate(msg, drv->capa.flags, params) || nl80211_put_dtim_period(msg, params->dtim_period) || nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) goto fail; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 2507a43ea..85706efe4 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -365,6 +365,18 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_FILS_STA)) capa->flags |= WPA_DRIVER_FLAGS_SUPPORT_FILS; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) + capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_BEACON_RATE_HT)) + capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_HT; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_BEACON_RATE_VHT)) + capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT; }