@@ -519,6 +519,7 @@ struct ieee80211_mgmt {
} STRUCT_PACKED;
+#define IEEE80211_HT_MCS_MASK_LEN 10
struct ieee80211_ht_capabilities {
le16 ht_capabilities_info;
u8 a_mpdu_params;
@@ -26,6 +26,7 @@
#define WPA_SUPPLICANT_DRIVER_VERSION 4
#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
@@ -516,6 +517,24 @@ struct wpa_driver_associate_params {
* STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE
*/
int uapsd;
+
+ /**
+ * disable_ht - Disable HT (802.11n) for this connection.
+ */
+ int disable_ht;
+
+ /**
+ * disable_ht40 - Disable HT40 (802.11n) for this connection.
+ */
+ int disable_ht40;
+
+ /**
+ * HT Capabilities over-rides. Only bits set in the mask will be
+ * used, and not all values are used by the kernel anyway. Currently,
+ * MCS, MPDU and MSDU fields are used.
+ */
+ struct ieee80211_ht_capabilities htcaps;
+ struct ieee80211_ht_capabilities htcaps_mask;
};
enum hide_ssid {
@@ -5567,6 +5567,14 @@ skip_auth_type:
NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
}
+ if (params->disable_ht)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sizeof(params->htcaps),
+ ¶ms->htcaps);
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sizeof(params->htcaps_mask),
+ ¶ms->htcaps_mask);
+
ret = nl80211_set_conn_keys(params, msg);
if (ret)
goto nla_put_failure;
@@ -5714,6 +5722,14 @@ static int wpa_driver_nl80211_associate(
params->prev_bssid);
}
+ if (params->disable_ht)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sizeof(params->htcaps),
+ ¶ms->htcaps);
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sizeof(params->htcaps_mask),
+ ¶ms->htcaps_mask);
+
if (params->p2p)
wpa_printf(MSG_DEBUG, " * P2P group");
@@ -1337,6 +1337,19 @@ enum nl80211_attrs {
NL80211_ATTR_TDLS_SUPPORT,
NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+ NL80211_ATTR_DEVICE_AP_SME,
+
+ NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+ NL80211_ATTR_FEATURE_FLAGS,
+
+ NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+ NL80211_ATTR_PROBE_RESP,
+
+ NL80211_ATTR_DISABLE_HT,
+ NL80211_ATTR_HT_CAPABILITY_MASK,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1732,6 +1732,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->home_ca_cert);
os_free(config->home_imsi);
os_free(config->home_milenage);
+ os_free(config->ht_mcs);
os_free(config);
}
@@ -2201,6 +2202,11 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
config->max_num_sta = DEFAULT_MAX_NUM_STA;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+ config->disable_ht = DEFAULT_DISABLE_HT;
+ config->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
+ config->ampdu_factor = DEFAULT_AMPDU_FACTOR;
+ config->ampdu_density = DEFAULT_AMPDU_DENSITY;
+ config->ht_mcs = strdup("");
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2495,6 +2501,12 @@ static const struct global_parse_data global_fields[] = {
{ STR(home_imsi), 0 },
{ STR(home_milenage), 0 },
{ INT_RANGE(interworking, 0, 1), 0 },
+ { INT(disable_ht), 0 },
+ { INT(disable_ht40), 0 },
+ { INT(disable_max_amsdu), 0 },
+ { INT(ampdu_factor), 0 },
+ { INT(ampdu_density), 0 },
+ { STR(ht_mcs), 0 },
{ FUNC(hessid), 0 },
{ INT_RANGE(access_network_type, 0, 15), 0 }
};
@@ -15,6 +15,11 @@
#ifndef CONFIG_H
#define CONFIG_H
+#define DEFAULT_DISABLE_HT 0
+#define DEFAULT_DISABLE_HT40 0
+#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
+#define DEFAULT_AMPDU_FACTOR -1 /* no change */
+#define DEFAULT_AMPDU_DENSITY -1 /* no change */
#define DEFAULT_EAPOL_VERSION 1
#ifdef CONFIG_NO_SCAN_PROCESSING
#define DEFAULT_AP_SCAN 2
@@ -192,6 +197,52 @@ struct wpa_config {
int fast_reauth;
/**
+ * disable_ht - Disable HT (802.11n) for this interface
+ *
+ * By default, use it if it is available, but this can be configured
+ * to a non-zero value 1 to have it disabled.
+ */
+ int disable_ht;
+
+ /**
+ * disable_ht40 - Disable HT-40 for this interface
+ *
+ * By default, use it if it is available, but this can be configured
+ * to a non-zero value 1 to have it disabled.
+ */
+ int disable_ht40;
+
+ /**
+ * disable_max_amsdu - Disable MAX AMSDU
+ *
+ * AMDSU will be 3839 bytes when disabled, or 7935
+ * when enabled (assuming it is otherwise supported)
+ * -1 (default) means do not apply any settings to the kernel.
+ */
+ int disable_max_amsdu;
+
+ /**
+ * ampdu_factor - Maximum A-MPDU Length Exponent
+ *
+ * Value: 0-3, see section 7.3.2.56.3 of the 802.11n-2009 spec.
+ */
+ int ampdu_factor;
+
+ /**
+ * ampdu_density - Minum A-MPDU Start Spacing
+ *
+ * Value: 0-7, see section 7.3.2.56.3 of the 802.11n-2009 spec.
+ */
+ int ampdu_density;
+
+ /**
+ * ht_mcs - Allowed HT-MCS rates, in ascii hex: ffff0000...
+ *
+ * By default: use whatever the OS has configured.
+ */
+ char *ht_mcs;
+
+ /**
* opensc_engine_path - Path to the OpenSSL engine for opensc
*
* This is an OpenSSL specific configuration option for loading OpenSC
@@ -386,6 +386,19 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+ params.disable_ht = wpa_s->conf->disable_ht;
+ params.disable_ht40 = wpa_s->conf->disable_ht40;
+
+ wpa_set_htcap_mcs(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask, wpa_s->conf->ht_mcs);
+ wpa_disable_max_amsdu(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->disable_max_amsdu);
+ wpa_set_ampdu_factor(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->ampdu_factor);
+ wpa_set_ampdu_density(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->ampdu_density);
+ wpa_set_disable_ht40(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->disable_ht40);
+
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
params.wpa_ie = wpa_s->sme.ft_ies;
@@ -742,7 +742,13 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
}
eapol_sm_invalidate_cached_session(wpa_s->eapol);
- if (wpa_s->current_ssid) {
+ if (wpa_s->current_ssid ||
+ (conf->disable_ht40 != wpa_s->conf->disable_ht40) ||
+ (conf->disable_max_amsdu != wpa_s->conf->disable_max_amsdu) ||
+ (conf->ampdu_factor != wpa_s->conf->ampdu_factor) ||
+ (conf->ampdu_density != wpa_s->conf->ampdu_density) ||
+ (conf->disable_ht != wpa_s->conf->disable_ht) ||
+ (strcmp(conf->ht_mcs, wpa_s->conf->ht_mcs) != 0)) {
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
@@ -1424,6 +1430,18 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.uapsd = wpa_s->parent->sta_uapsd;
else
params.uapsd = -1;
+ params.disable_ht = wpa_s->conf->disable_ht;
+ params.disable_ht40 = wpa_s->conf->disable_ht40;
+
+ wpa_set_htcap_mcs(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask, wpa_s->conf->ht_mcs);
+ wpa_disable_max_amsdu(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->disable_max_amsdu);
+ wpa_set_ampdu_factor(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->ampdu_factor);
+ wpa_set_ampdu_density(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->ampdu_density);
+ wpa_set_disable_ht40(wpa_s, ¶ms.htcaps, ¶ms.htcaps_mask,
+ wpa_s->conf->disable_ht40);
ret = wpa_drv_associate(wpa_s, ¶ms);
if (ret < 0) {
@@ -2165,6 +2183,140 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
return wpa_s;
}
+int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ const char *ht_mcs)
+{
+ /* parse ht_mcs into hex array */
+ int i;
+ const char* tmp = ht_mcs;
+ char* end = NULL;
+
+ /* This is what we are setting in the kernel.. */
+ os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ wpa_msg(wpa_s, MSG_ERROR, "set_htcap, ht_mcs -:%s:-\n", ht_mcs);
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ errno = 0;
+ long v = strtol(tmp, &end, 16);
+ if (errno == 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "htcap value[%i]: %ld end: %p tmp: %p\n",
+ i, v, end, tmp);
+ if (end == tmp) {
+ break;
+ }
+
+ htcaps->supported_mcs_set[i] = v;
+ tmp = end;
+ }
+ else {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to parse ht-mcs: %s, error: %s\n",
+ ht_mcs, strerror(errno));
+ return -1;
+ }
+ }
+
+ if (i) {
+ os_memset(&htcaps_mask->supported_mcs_set, 0xff, IEEE80211_HT_MCS_MASK_LEN-1);
+ htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN-1] = 0x1f; /* skip the 3 reserved bits */
+ }
+
+ return 0;
+}
+
+
+int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "wpa: set_disable_max_amsdu: %d\n",
+ disabled);
+
+ if (disabled == -1)
+ return 0;
+
+ u16 msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
+ htcaps_mask->ht_capabilities_info |= msk;
+ if (disabled)
+ htcaps->ht_capabilities_info &= msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+ return 0;
+}
+
+int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int factor)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "wpa: set_ampdu_factor: %d\n",
+ factor);
+
+ if (factor == -1)
+ return 0;
+
+ if (factor < 0 || factor > 3) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "wpa: ampdu_factor: %d out of range. Must be 0-3 or -1\n",
+ factor);
+ return -EINVAL;
+ }
+
+ htcaps_mask->a_mpdu_params |= 0x3; // 2 bits for factor
+ htcaps->a_mpdu_params &= ~0x3;
+ htcaps->a_mpdu_params |= factor & 0x3;
+ return 0;
+}
+
+int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int density)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "wpa: set_ampdu_density: %d\n",
+ density);
+
+ if (density == -1)
+ return 0;
+
+ if (density < 0 || density > 7) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "wpa: ampdu_density: %d out of range. Must be 0-7 or -1.\n",
+ density);
+ return -EINVAL;
+ }
+
+ htcaps_mask->a_mpdu_params |= 0x1C;
+ htcaps->a_mpdu_params &= ~(0x1C);
+ htcaps->a_mpdu_params |= (density << 2) & 0x1C;
+ return 0;
+}
+
+int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* Masking these out disables HT-40 */
+ u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "wpa: set_disable_ht40: %d\n",
+ disabled);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ return 0;
+}
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
@@ -36,6 +36,7 @@ struct scan_info;
struct wpa_bss;
struct wpa_scan_results;
struct hostapd_hw_modes;
+struct ieee80211_ht_capabilities;
/*
* Forward declarations of private structures used within the ctrl_iface
@@ -514,6 +515,26 @@ struct wpa_supplicant {
/* wpa_supplicant.c */
+int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ const char *ht_mcs);
+int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled);
+int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int factor);
+int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int density);
+int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
From: Ben Greear <greearb@candelatech.com> This allows ht-capabilities over-rides on kernels that support these features. MCS Rates can be disabled (ie, to force to slower speeds when using /n). Rates cannot be forced higher. HT can be disabled, forcing an /a/b/g/n station to act like an /a/b/g station. HT40 can be disabled. MAX-AMSDU can be disabled AMPDU-Factor and AMPDU Density can be modified. Please note that these are suggestions to the kernel. Only mac80211 drivers will work at all. The AMPDU-Factor can only be decreased and the AMPDU-Density can only be increased currently. Signed-hostap: Ben Greear <greearb@candelatech.com> --- :100644 100644 3014762... 860396f... M src/common/ieee802_11_defs.h :100644 100644 bd0c611... ca9c698... M src/drivers/driver.h :100644 100644 89775d7... 6d60030... M src/drivers/driver_nl80211.c :100644 100644 9d797f2... 688bd3f... M src/drivers/nl80211_copy.h :100644 100644 b446a3f... a457c1e... M wpa_supplicant/config.c :100644 100644 ae496ff... 7586209... M wpa_supplicant/config.h :100644 100644 3416d68... b41b7c2... M wpa_supplicant/sme.c :100644 100644 2b3140e... 704fab1... M wpa_supplicant/wpa_supplicant.c :100644 100644 59fc9a3... ebc4d64... M wpa_supplicant/wpa_supplicant_i.h src/common/ieee802_11_defs.h | 1 + src/drivers/driver.h | 19 +++++ src/drivers/driver_nl80211.c | 16 ++++ src/drivers/nl80211_copy.h | 13 +++ wpa_supplicant/config.c | 12 +++ wpa_supplicant/config.h | 51 ++++++++++++ wpa_supplicant/sme.c | 13 +++ wpa_supplicant/wpa_supplicant.c | 154 ++++++++++++++++++++++++++++++++++++- wpa_supplicant/wpa_supplicant_i.h | 21 +++++ 9 files changed, 299 insertions(+), 1 deletions(-)