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 <jouni@qca.qualcomm.com>
This commit is contained in:
Purushottam Kushwaha 2016-11-24 20:39:47 +05:30 committed by Jouni Malinen
parent 29483a5678
commit d4f3003c56
2 changed files with 110 additions and 0 deletions

View file

@ -3517,6 +3517,101 @@ static int nl80211_set_mesh_config(void *priv,
#endif /* CONFIG_MESH */ #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, static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params) struct wpa_driver_ap_params *params)
{ {
@ -3547,6 +3642,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
params->tail, params->tail_len); params->tail, params->tail_len);
wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex); 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_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_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid", wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
params->ssid, params->ssid_len); 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, nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) || params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) || 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) || nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail; goto fail;

View file

@ -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)) if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_FILS_STA))
capa->flags |= WPA_DRIVER_FLAGS_SUPPORT_FILS; 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;
} }