From d4f3003c56f800b82ec212fe5b64fca4bb160a4c Mon Sep 17 00:00:00 2001 From: Purushottam Kushwaha Date: Thu, 24 Nov 2016 20:39:47 +0530 Subject: [PATCH] nl80211: Configure Beacon frame TX rate if driver advertises support If the driver advertises support for setting Beacon frame data rate, allow the user to configure this rate as part of starting the AP. Only one Beacon frame TX rate is allowed. Drivers advertising such support should set corresponding flag via the NL80211_ATTR_EXT_FEATURES attribute. Signed-off-by: Jouni Malinen --- src/drivers/driver_nl80211.c | 98 +++++++++++++++++++++++++++++++ src/drivers/driver_nl80211_capa.c | 12 ++++ 2 files changed, 110 insertions(+) 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; }