@@ -190,7 +190,8 @@ static int nl80211_set_legacy_rates(struct i802_bss *bss,
struct wpa_driver_nl80211_data *drv,
int ifindex, int b_disabled,
unsigned int cfg_legacy_mask,
- int is_advert_mask);
+ int is_advert_mask,
+ int disable_ht, int disable_vht);
static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
int reset_mode);
@@ -2343,8 +2344,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
if (drv->if_indices != drv->default_if_indices)
os_free(drv->if_indices);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, 0xFFF, 0);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, 0xFFF, 1);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, 0xFFF, 0, 0, 0);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, 0xFFF, 1, 0, 0);
netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
IF_OPER_UP);
@@ -2878,8 +2879,10 @@ static int wpa_driver_nl80211_authenticate(
int count = 0;
int is_retry;
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->tx_legacy_rates, 0);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->adv_legacy_rates, 1);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->tx_legacy_rates, 0,
+ bss->tx_disable_ht, bss->tx_disable_vht);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->adv_legacy_rates, 1,
+ bss->adv_disable_ht, bss->adv_disable_vht);
is_retry = drv->retry_auth;
drv->retry_auth = 0;
@@ -4103,8 +4106,10 @@ int nl80211_create_iface(struct i802_bss *bss, struct wpa_driver_nl80211_data *d
wpa_printf(MSG_DEBUG,
"nl80211: Interface %s created for P2P - disable 11b rates",
ifname);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->tx_legacy_rates, 0);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->adv_legacy_rates, 1);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->tx_legacy_rates, 0,
+ bss->tx_disable_ht, bss->tx_disable_vht);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->adv_legacy_rates, 1,
+ bss->adv_disable_ht, bss->adv_disable_vht);
}
return ret;
@@ -4796,8 +4801,10 @@ static int wpa_driver_nl80211_associate(
int ret = -1;
struct nl_msg *msg;
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->tx_legacy_rates, 0);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->adv_legacy_rates, 1);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->tx_legacy_rates, 0,
+ bss->tx_disable_ht, bss->tx_disable_vht);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->adv_legacy_rates, 1,
+ bss->adv_disable_ht, bss->adv_disable_vht);
if (params->mode == IEEE80211_MODE_AP)
return wpa_driver_nl80211_ap(drv, params);
@@ -4976,14 +4983,18 @@ done:
wpa_printf(MSG_DEBUG,
"nl80211: Interface %s mode change to P2P - disable 11b rates",
bss->ifname);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->tx_legacy_rates, 0);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->adv_legacy_rates, 1);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->tx_legacy_rates, 0,
+ bss->tx_disable_ht, bss->tx_disable_vht);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 1, bss->adv_legacy_rates, 1,
+ bss->adv_disable_ht, bss->adv_disable_vht);
} else {
wpa_printf(MSG_DEBUG,
"nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
bss->ifname);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->tx_legacy_rates, 0);
- nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->adv_legacy_rates, 1);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->tx_legacy_rates, 0,
+ bss->tx_disable_ht, bss->tx_disable_vht);
+ nl80211_set_legacy_rates(bss, drv, drv->ifindex, 0, bss->adv_legacy_rates, 1,
+ bss->adv_disable_ht, bss->adv_disable_vht);
}
if (is_ap_interface(nlmode)) {
@@ -6366,11 +6377,14 @@ static int nl80211_set_legacy_rates(struct i802_bss *bss,
struct wpa_driver_nl80211_data *drv,
int ifindex, int b_disabled,
unsigned int legacy_rates,
- int is_advert_mask)
+ int is_advert_mask,
+ int disable_ht, int disable_vht)
{
struct nl_msg *msg;
struct nlattr *bands, *band;
int ret;
+ uint8_t ht_mcs[77];
+ struct nl80211_txrate_vht txrate_vht = {};
wpa_printf(MSG_DEBUG,
"nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s cfg-legacy-mask: 0x%x is-advert: %d)",
@@ -6462,18 +6476,27 @@ static int nl80211_set_legacy_rates(struct i802_bss *bss,
if (nla_put(msg, NL80211_TXRATE_LEGACY, i, rates))
goto fail;
}
- }/* if we might need to disable some rates */
+ }/* if we might need to disable some legacy rates */
+
+ if (disable_ht) {
+ if (nla_put(msg, NL80211_TXRATE_HT, 0, ht_mcs))
+ goto fail;
+ }
+ if (disable_vht) {
+ if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht), &txrate_vht))
+ goto fail;
+ }
nla_nest_end(msg, band);
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ if (!band)
+ goto fail;
+
if (legacy_rates & (1<<31)) {
unsigned char rates[8];
int i = 0;
- band = nla_nest_start(msg, NL80211_BAND_5GHZ);
- if (!band)
- goto fail;
-
if (legacy_rates & 0x10) { // 6Mbps
rates[i] = 12;
i++;
@@ -6507,11 +6530,29 @@ static int nl80211_set_legacy_rates(struct i802_bss *bss,
i++;
}
+ /* If we have no rates at all, then set one minimum rate so that
+ * the kernel doesn't reject the setting entirely.
+ */
+ if ((i == 0) && disable_ht && disable_vht) {
+ rates[i] = 12;
+ i++;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set TX Rates 5Ghz, i: %d", i);
if (nla_put(msg, NL80211_TXRATE_LEGACY, i, rates))
goto fail;
+ }
- nla_nest_end(msg, band);
+ if (disable_ht) {
+ if (nla_put(msg, NL80211_TXRATE_HT, 0, ht_mcs))
+ goto fail;
}
+ if (disable_vht) {
+ if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(txrate_vht), &txrate_vht))
+ goto fail;
+ }
+
+ nla_nest_end(msg, band);
nla_nest_end(msg, bands);
@@ -6531,8 +6572,10 @@ fail:
int wpa_driver_nl80211_set_legacy_rates(void *priv)
{
struct i802_bss *bss = priv;
- nl80211_set_legacy_rates(bss, bss->drv, bss->drv->ifindex, 0, bss->tx_legacy_rates, 0);
- return nl80211_set_legacy_rates(bss, bss->drv, bss->drv->ifindex, 0, bss->adv_legacy_rates, 1);
+ nl80211_set_legacy_rates(bss, bss->drv, bss->drv->ifindex, 0, bss->tx_legacy_rates, 0,
+ bss->tx_disable_ht, bss->tx_disable_vht);
+ return nl80211_set_legacy_rates(bss, bss->drv, bss->drv->ifindex, 0, bss->adv_legacy_rates, 1,
+ bss->adv_disable_ht, bss->adv_disable_vht);
}
static int wpa_driver_nl80211_deinit_ap(void *priv)
@@ -6725,6 +6768,21 @@ static int nl80211_set_param(void *priv, const char *param)
bss->adv_legacy_rates |= (1<<31); /* so we know user actually configured something */
}
+ if (os_strstr(param, "tx_disable_ht=1")) {
+ bss->tx_disable_ht = 1;
+ }
+
+ if (os_strstr(param, "tx_disable_vht=1")) {
+ bss->tx_disable_vht = 1;
+ }
+ if (os_strstr(param, "adv_disable_ht=1")) {
+ bss->adv_disable_ht = 1;
+ }
+
+ if (os_strstr(param, "adv_disable_vht=1")) {
+ bss->adv_disable_vht = 1;
+ }
+
return 0;
}
@@ -64,6 +64,10 @@ struct i802_bss {
unsigned int wdev_id_set:1;
unsigned int added_if:1;
unsigned int static_ap:1;
+ unsigned int tx_disable_ht:1; /* Disable Using HT rates? */
+ unsigned int tx_disable_vht:1; /* Disable Using VHT Rates? */
+ unsigned int adv_disable_ht:1; /* Disable Advertised HT rates? */
+ unsigned int adv_disable_vht:1; /* Disable Advertised VHT Rates? */
u8 addr[ETH_ALEN];