From patchwork Sat Nov 19 00:49:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Greear X-Patchwork-Id: 126515 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from maxx.maxx.shmoo.com (maxx.shmoo.com [205.134.188.171]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "maxx.shmoo.com", Issuer "CA Cert Signing Authority" (not verified)) by ozlabs.org (Postfix) with ESMTPS id E02BCB723B for ; Sat, 19 Nov 2011 11:50:16 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 914C517C040; Fri, 18 Nov 2011 19:50:12 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MZb3kNsVwwUE; Fri, 18 Nov 2011 19:50:12 -0500 (EST) Received: from maxx.shmoo.com (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 0D05417C004; Fri, 18 Nov 2011 19:50:08 -0500 (EST) X-Original-To: mailman-post+hostap@maxx.shmoo.com Delivered-To: mailman-post+hostap@maxx.shmoo.com Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 897669C251 for ; Fri, 18 Nov 2011 19:50:06 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ANY+PWvg+Iw6 for ; Fri, 18 Nov 2011 19:50:01 -0500 (EST) Received: from ns3.lanforge.com (mail.candelatech.com [208.74.158.172]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by maxx.maxx.shmoo.com (Postfix) with ESMTPS id 1A3429C24C for ; Fri, 18 Nov 2011 19:50:00 -0500 (EST) Received: from localhost.localdomain (firewall.candelatech.com [70.89.124.249]) by ns3.lanforge.com (8.14.2/8.14.2) with ESMTP id pAJ0ntQN023293 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 18 Nov 2011 16:49:56 -0800 From: greearb@candelatech.com To: hostap@lists.shmoo.com Subject: [PATCH v2] hostap: Support ht-cap over-rides. Date: Fri, 18 Nov 2011 16:49:49 -0800 Message-Id: <1321663789-7989-1-git-send-email-greearb@candelatech.com> X-Mailer: git-send-email 1.7.3.4 Cc: Ben Greear X-BeenThere: hostap@lists.shmoo.com X-Mailman-Version: 2.1.9 Precedence: list List-Id: HostAP Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: hostap-bounces@lists.shmoo.com Errors-To: hostap-bounces@lists.shmoo.com From: Ben Greear 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 --- :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(-) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 3014762..860396f 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -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; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index bd0c611..ca9c698 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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 { diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 89775d7..6d60030 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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"); diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 9d797f2..688bd3f 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -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, diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b446a3f..a457c1e 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -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 } }; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index ae496ff..7586209 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -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 diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 3416d68..b41b7c2 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -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; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 2b3140e..704fab1 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 59fc9a3..ebc4d64 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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);