* [PATCH v9 1/2] wireless: Support ht-capabilities over-rides.
@ 2011-11-17 21:54 greearb
2011-11-17 21:54 ` [PATCH v9 2/2] mac80211: Support ht-cap over-rides greearb
2011-11-18 10:04 ` [PATCH v9 1/2] wireless: Support ht-capabilities over-rides Johannes Berg
0 siblings, 2 replies; 9+ messages in thread
From: greearb @ 2011-11-17 21:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
From: Ben Greear <greearb@candelatech.com>
This allows users to disable features such as HT, HT40,
and to modify the MCS, AMPDU, and AMSDU settings for
drivers that support it.
The MCS, AMPDU, and AMSDU features that may be disabled are
are reported in the phy-info netlink message as a mask.
Attemping to disable features that are not supported will
take no affect, but will not return errors. This is to aid
backwards compatibility in user-space apps that may not be
clever enough to deal with parsing the the capabilities mask.
This patch only enables the infrastructure. An additional
patch will enable the feature in mac80211.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
:100644 100644 f9261c2... 0df2062... M include/linux/nl80211.h
:100644 100644 8d7ba09... 4f6d131... M include/net/cfg80211.h
:100644 100644 1c7d4df... fb08c28... M net/wireless/core.h
:100644 100644 6c1bafd... 438dfc1... M net/wireless/mlme.c
:100644 100644 6bc7c4b... aa98ec2... M net/wireless/nl80211.c
:100644 100644 0acfdc9... f0c900c... M net/wireless/sme.c
include/linux/nl80211.h | 14 ++++++++++++++
include/net/cfg80211.h | 27 +++++++++++++++++++++++++++
net/wireless/core.h | 10 ++++++++--
net/wireless/mlme.c | 37 ++++++++++++++++++++++++++++++++++---
net/wireless/nl80211.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
net/wireless/sme.c | 7 ++++++-
6 files changed, 132 insertions(+), 7 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f9261c2..0df2062 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1169,6 +1169,17 @@ enum nl80211_commands {
* @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
* probe-response frame. The DA field in the 802.11 header is zero-ed out,
* to be filled by the FW.
+ * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
+ * this feature. Currently, only supported in mac80211 drivers.
+ * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
+ * ATTR_HT_CAPABILITY to which attention should be paid.
+ * Currently, only mac80211 NICs support this feature.
+ * The values that may be configured are:
+ * MCS rates, MAX-AMSDU, HT-20-40 and HT_CAP_SGI_40
+ * AMPDU density and AMPDU factor.
+ * All values are treated as suggestions and may be ignored
+ * by the driver as required. The actual values may be seen in
+ * the station debugfs ht_caps file.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1408,6 +1419,9 @@ enum nl80211_attrs {
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/include/net/cfg80211.h b/include/net/cfg80211.h
index 8d7ba09..4f6d131 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1044,6 +1044,15 @@ struct cfg80211_auth_request {
};
/**
+ * enum cfg80211_assoc_req_flags - Over-ride default behaviour in association.
+ *
+ * @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n)
+ */
+enum cfg80211_assoc_req_flags {
+ ASSOC_REQ_DISABLE_HT = BIT(0),
+};
+
+/**
* struct cfg80211_assoc_request - (Re)Association request data
*
* This structure provides information needed to complete IEEE 802.11
@@ -1054,6 +1063,10 @@ struct cfg80211_auth_request {
* @use_mfp: Use management frame protection (IEEE 802.11w) in this association
* @crypto: crypto settings
* @prev_bssid: previous BSSID, if not %NULL use reassociate frame
+ * @flags: See &enum cfg80211_assoc_req_flags
+ * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
+ * will be used in ht_capa. Un-supported values will be ignored.
+ * @ht_capa_mask: The bits of ht_capa which are to be used.
*/
struct cfg80211_assoc_request {
struct cfg80211_bss *bss;
@@ -1061,6 +1074,9 @@ struct cfg80211_assoc_request {
size_t ie_len;
struct cfg80211_crypto_settings crypto;
bool use_mfp;
+ u32 flags;
+ struct ieee80211_ht_cap ht_capa;
+ struct ieee80211_ht_cap ht_capa_mask;
};
/**
@@ -1159,6 +1175,10 @@ struct cfg80211_ibss_params {
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
+ * @flags: See &enum cfg80211_assoc_req_flags
+ * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
+ * will be used in ht_capa. Un-supported values will be ignored.
+ * @ht_capa_mask: The bits of ht_capa which are to be used.
*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
@@ -1172,6 +1192,9 @@ struct cfg80211_connect_params {
struct cfg80211_crypto_settings crypto;
const u8 *key;
u8 key_len, key_idx;
+ u32 flags;
+ struct ieee80211_ht_cap ht_capa;
+ struct ieee80211_ht_cap ht_capa_mask;
};
/**
@@ -1934,6 +1957,8 @@ struct wiphy_wowlan_support {
* @wowlan: WoWLAN support information
*
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
+ * @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
+ * If null, then none can be over-ridden.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2023,6 +2048,8 @@ struct wiphy {
/* dir in debugfs: ieee80211/<wiphyname> */
struct dentry *debugfsdir;
+ const struct ieee80211_ht_cap *ht_capa_mod_mask;
+
#ifdef CONFIG_NET_NS
/* the network namespace this phy lives in currently */
struct net *_net;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 1c7d4df..fb08c28 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -341,13 +341,17 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt);
+ struct cfg80211_crypto_settings *crypt,
+ u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
+ struct ieee80211_ht_cap *ht_capa_mask);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct ieee80211_channel *chan,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt);
+ struct cfg80211_crypto_settings *crypt,
+ u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
+ struct ieee80211_ht_cap *ht_capa_mask);
int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *bssid,
const u8 *ie, int ie_len, u16 reason,
@@ -379,6 +383,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie);
+void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
+ const struct ieee80211_ht_cap *ht_capa_mask);
/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 6c1bafd..438dfc1 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -501,13 +501,32 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
return err;
}
+/* Do a logical ht_capa &= ht_capa_mask. */
+void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
+ const struct ieee80211_ht_cap *ht_capa_mask)
+{
+ int i;
+ u8 *p1, *p2;
+ if (!ht_capa_mask) {
+ memset(ht_capa, 0, sizeof(*ht_capa));
+ return;
+ }
+
+ p1 = (u8*)(ht_capa);
+ p2 = (u8*)(ht_capa_mask);
+ for (i = 0; i<sizeof(*ht_capa); i++)
+ p1[i] &= p2[i];
+}
+
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt)
+ struct cfg80211_crypto_settings *crypt,
+ u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
+ struct ieee80211_ht_cap *ht_capa_mask)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_assoc_request req;
@@ -537,6 +556,15 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
memcpy(&req.crypto, crypt, sizeof(req.crypto));
req.use_mfp = use_mfp;
req.prev_bssid = prev_bssid;
+ req.flags = assoc_flags;
+ if (ht_capa)
+ memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa));
+ if (ht_capa_mask)
+ memcpy(&req.ht_capa_mask, ht_capa_mask,
+ sizeof(req.ht_capa_mask));
+ cfg80211_oper_and_ht_capa(&req.ht_capa_mask,
+ rdev->wiphy.ht_capa_mod_mask);
+
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
if (!req.bss) {
@@ -574,14 +602,17 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt)
+ struct cfg80211_crypto_settings *crypt,
+ u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
+ struct ieee80211_ht_cap *ht_capa_mask)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
wdev_lock(wdev);
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
- ssid, ssid_len, ie, ie_len, use_mfp, crypt);
+ ssid, ssid_len, ie, ie_len, use_mfp, crypt,
+ assoc_flags, ht_capa, ht_capa_mask);
wdev_unlock(wdev);
return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6bc7c4b..aa98ec2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -199,6 +199,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
[NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_HT_CAPABILITY_MASK] = {
+ .len = NL80211_HT_CAPABILITY_LEN
+ },
};
/* policy for the key attributes */
@@ -1025,6 +1029,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
+ if (dev->wiphy.ht_capa_mod_mask)
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
+ sizeof(*dev->wiphy.ht_capa_mod_mask),
+ dev->wiphy.ht_capa_mod_mask);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -4384,6 +4393,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
int err, ssid_len, ie_len = 0;
bool use_mfp = false;
+ u32 flags = 0;
+ struct ieee80211_ht_cap *ht_capa = NULL;
+ struct ieee80211_ht_cap *ht_capa_mask = NULL;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
@@ -4427,11 +4439,25 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_PREV_BSSID])
prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
+ if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
+ flags |= ASSOC_REQ_DISABLE_HT;
+
+ if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
+ ht_capa_mask =
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]);
+
+ if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
+ if (!ht_capa_mask)
+ return -EINVAL;
+ ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+ }
+
err = nl80211_crypto_settings(rdev, info, &crypto, 1);
if (!err)
err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
ssid, ssid_len, ie, ie_len, use_mfp,
- &crypto);
+ &crypto, flags, ht_capa,
+ ht_capa_mask);
return err;
}
@@ -4921,6 +4947,22 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
return PTR_ERR(connkeys);
}
+ if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
+ connect.flags |= ASSOC_REQ_DISABLE_HT;
+
+ if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
+ memcpy(&connect.ht_capa_mask,
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
+ sizeof(connect.ht_capa_mask));
+
+ if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
+ if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
+ return -EINVAL;
+ memcpy(&connect.ht_capa,
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
+ sizeof(connect.ht_capa));
+ }
+
err = cfg80211_connect(rdev, dev, &connect, connkeys);
if (err)
kfree(connkeys);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 0acfdc9..f0c900c 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -190,7 +190,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
prev_bssid,
params->ssid, params->ssid_len,
params->ie, params->ie_len,
- false, ¶ms->crypto);
+ false, ¶ms->crypto,
+ params->flags, ¶ms->ht_capa,
+ ¶ms->ht_capa_mask);
if (err)
__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
@@ -774,6 +776,9 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
wdev->connect_keys = NULL;
}
+ cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
+ rdev->wiphy.ht_capa_mod_mask);
+
if (connkeys && connkeys->def >= 0) {
int idx;
u32 cipher;
--
1.7.3.4
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
2011-11-17 21:54 [PATCH v9 1/2] wireless: Support ht-capabilities over-rides greearb
@ 2011-11-17 21:54 ` greearb
2011-11-18 10:15 ` Johannes Berg
2011-11-18 10:04 ` [PATCH v9 1/2] wireless: Support ht-capabilities over-rides Johannes Berg
1 sibling, 1 reply; 9+ messages in thread
From: greearb @ 2011-11-17 21:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
From: Ben Greear <greearb@candelatech.com>
This implements ht-cap over-rides for mac80211 drivers.
HT may be disabled, making an /a/b/g/n station act like an
a/b/g station. HT40 may be disabled forcing the station to
be HT20 even if the AP and local hardware support HT40.
MAX-AMSDU may be disabled.
AMPDU-Density may be increased.
AMPDU-Factor may be decreased.
This has been successfully tested with ath9k using patched
wpa_supplicant and iw.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
:100644 100644 1063a7e... 2577c45... M net/mac80211/cfg.c
:100644 100644 d069750... fbdcec8... M net/mac80211/ht.c
:100644 100644 068cc92... 2ecaf2d... M net/mac80211/ieee80211_i.h
:100644 100644 e323d4e... 176fd07... M net/mac80211/main.c
:100644 100644 b3a125f... ee82d2f... M net/mac80211/mesh.c
:100644 100644 0140e88... fff93bc... M net/mac80211/mesh_plink.c
:100644 100644 f9ec15b... 465ff41... M net/mac80211/mlme.c
:100644 100644 3a00814... 68d0119... M net/mac80211/util.c
:100644 100644 3dd5a89... c5e8be6... M net/mac80211/work.c
net/mac80211/cfg.c | 2 +-
net/mac80211/ht.c | 75 +++++++++++++++++++++++++++++++++++++++++++-
net/mac80211/ieee80211_i.h | 11 +++++-
net/mac80211/main.c | 14 ++++++++
net/mac80211/mesh.c | 2 +-
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/mlme.c | 12 ++++++-
net/mac80211/util.c | 12 +++---
net/mac80211/work.c | 20 ++++++++---
9 files changed, 130 insertions(+), 20 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1063a7e..2577c45 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -832,7 +832,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
}
if (params->ht_capa)
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
params->ht_capa,
&sta->sta.ht_cap);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index d069750..fbdcec8 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -19,7 +19,74 @@
#include "ieee80211_i.h"
#include "rate.h"
-void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
+{
+ const u16 flg = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) &&
+ !(sdata->u.mgd.ht_capa.cap_info & flg))
+ return true;
+ return false;
+}
+
+void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ u16 flag)
+{
+ if (sdata->u.mgd.ht_capa_mask.cap_info & flag) {
+ if (!(sdata->u.mgd.ht_capa.cap_info & flag))
+ ht_cap->cap &= ~flag;
+ }
+}
+
+void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_ht_cap *ht_cap)
+{
+ u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask);
+ u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
+ int i;
+
+ /* NOTE: If you add more over-rides here, update register_hw
+ * ht_capa_mod_msk logic in main.c as well.
+ */
+
+ /* check for HT over-rides, MCS rates first. */
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ u8 m = smask[i];
+ ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */
+ /* Add back rates that are supported */
+ ht_cap->mcs.rx_mask[i] |= (m & scaps[i]);
+ }
+
+ /* Force removal of HT-40 capabilities? */
+ __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+ __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40);
+
+ /* Allow user to disable the max-AMSDU bit. */
+ __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU);
+
+ /* Allow user to decrease AMPDU factor */
+ if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
+ IEEE80211_HT_AMPDU_PARM_FACTOR) {
+ u16 n = sdata->u.mgd.ht_capa.ampdu_params_info
+ & IEEE80211_HT_AMPDU_PARM_FACTOR;
+ if (n < ht_cap->ampdu_factor)
+ ht_cap->ampdu_factor = n;
+ }
+
+ /* Allow the user to increase AMPDU density. */
+ if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
+ IEEE80211_HT_AMPDU_PARM_DENSITY) {
+ u16 n = (sdata->u.mgd.ht_capa.ampdu_params_info &
+ IEEE80211_HT_AMPDU_PARM_DENSITY)
+ >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
+ if (n > ht_cap->ampdu_density)
+ ht_cap->ampdu_density = n;
+ }
+}
+
+
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap)
{
@@ -103,6 +170,12 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
/* handle MCS rate 32 too */
if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
ht_cap->mcs.rx_mask[32/8] |= 1;
+
+ /*
+ * If user has specified capability over-rides, take care
+ * of that here.
+ */
+ ieee80211_apply_htcap_overrides(sdata, ht_cap);
}
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 068cc92..2ecaf2d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -448,6 +448,9 @@ struct ieee80211_if_managed {
*/
int rssi_min_thold, rssi_max_thold;
int last_ave_beacon_signal;
+
+ struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
+ struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
};
struct ieee80211_if_ibss {
@@ -1188,7 +1191,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
/* HT */
-void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata);
+void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_ht_cap *ht_cap);
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap);
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
@@ -1343,7 +1350,7 @@ void ieee80211_recalc_smps(struct ieee80211_local *local);
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset);
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
-u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap);
u8 *ieee80211_ie_build_ht_info(u8 *pos,
struct ieee80211_sta_ht_cap *ht_cap,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index e323d4e..176fd07 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -558,6 +558,19 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
};
+static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
+ .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR |
+ IEEE80211_HT_AMPDU_PARM_DENSITY,
+
+ .cap_info = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_MAX_AMSDU |
+ IEEE80211_HT_CAP_SGI_40,
+ .mcs = {
+ .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, },
+ },
+};
+
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
@@ -629,6 +642,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->user_power_level = -1;
local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
+ wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
INIT_LIST_HEAD(&local->interfaces);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index b3a125f..ee82d2f 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -366,7 +366,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
return -ENOMEM;
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
- ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
+ ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
return 0;
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 0140e88..fff93bc 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -101,7 +101,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
set_sta_flag(sta, WLAN_STA_WME);
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
if (elems->ht_cap_elem)
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem,
&sta->sta.ht_cap);
rate_control_rate_init(sta);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f9ec15b..465ff41 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -209,6 +209,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
channel_type = NL80211_CHAN_HT20;
if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+ !ieee80111_cfg_override_disables_ht40(sdata) &&
(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
@@ -1613,7 +1614,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
ap_ht_cap_flags = sta->sta.ht_cap.cap;
@@ -1982,7 +1983,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
ap_ht_cap_flags = sta->sta.ht_cap.cap;
@@ -2640,6 +2641,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+ if (req->flags & ASSOC_REQ_DISABLE_HT)
+ ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+
+ memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
+ memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
+ sizeof(ifmgd->ht_capa_mask));
+
if (req->ie && req->ie_len) {
memcpy(wk->ie, req->ie, req->ie_len);
wk->ie_len = req->ie_len;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3a00814..68d0119 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -813,7 +813,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
}
if (sband->ht_cap.ht_supported)
- pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
+ pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
/*
* If adding more here, adjust code in main.c
@@ -1356,7 +1356,7 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
}
EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
-u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap)
{
__le16 tmp;
@@ -1371,13 +1371,13 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
pos += sizeof(u16);
/* AMPDU parameters */
- *pos++ = sband->ht_cap.ampdu_factor |
- (sband->ht_cap.ampdu_density <<
+ *pos++ = ht_cap->ampdu_factor |
+ (ht_cap->ampdu_density <<
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
/* MCS set */
- memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
- pos += sizeof(sband->ht_cap.mcs);
+ memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
+ pos += sizeof(ht_cap->mcs);
/* extended capabilities */
pos += sizeof(__le16);
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 3dd5a89..c5e8be6 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
/* frame sending functions */
-static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
+static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, const u8 *ht_info_ie,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
enum ieee80211_smps_mode smps)
@@ -102,10 +103,10 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
struct ieee80211_ht_info *ht_info;
u8 *pos;
u32 flags = channel->flags;
- u16 cap = sband->ht_cap.cap;
+ u16 cap;
+ struct ieee80211_sta_ht_cap ht_cap;
- if (!sband->ht_cap.ht_supported)
- return;
+ BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
if (!ht_info_ie)
return;
@@ -113,9 +114,16 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
return;
+ memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
+ ieee80211_apply_htcap_overrides(sdata, &ht_cap);
+
+ if (!ht_cap.ht_supported)
+ return;
+
ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
/* determine capability flags */
+ cap = ht_cap.cap;
switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
@@ -154,7 +162,7 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
/* reserve and fill IE */
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
- ieee80211_ie_build_ht_cap(pos, sband, cap);
+ ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
}
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
@@ -329,7 +337,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
if (wk->assoc.use_11n && wk->assoc.wmm_used &&
local->hw.queues >= 4)
- ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie,
+ ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,
sband, wk->chan, wk->assoc.smps);
/* if present, add any custom non-vendor IEs that go after HT */
--
1.7.3.4
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
2011-11-17 21:54 ` [PATCH v9 2/2] mac80211: Support ht-cap over-rides greearb
@ 2011-11-18 10:15 ` Johannes Berg
2011-11-18 17:09 ` Ben Greear
0 siblings, 1 reply; 9+ messages in thread
From: Johannes Berg @ 2011-11-18 10:15 UTC (permalink / raw)
To: greearb; +Cc: linux-wireless
On Thu, 2011-11-17 at 13:54 -0800, greearb@candelatech.com wrote:
> -void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
> +bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
> +{
> + const u16 flg = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
> + if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) &&
> + !(sdata->u.mgd.ht_capa.cap_info & flg))
> + return true;
This looks like it has endian bugs. Note that sband->ht_cap is
ieee80211_sta_ht_cap, whereas sdata->u.mgd.ht_capa[_mask] is
ieee80211_ht_cap -- the latter is in IEEE format (LE) while the former
is in a complete different format that's easier to digest for the
CPU :-)
> +void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
> + struct ieee80211_sta_ht_cap *ht_cap,
> + u16 flag)
> +{
> + if (sdata->u.mgd.ht_capa_mask.cap_info & flag) {
> + if (!(sdata->u.mgd.ht_capa.cap_info & flag))
> + ht_cap->cap &= ~flag;
> + }
> +}
Same here.
> + /* Allow user to decrease AMPDU factor */
> + if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
> + IEEE80211_HT_AMPDU_PARM_FACTOR) {
> + u16 n = sdata->u.mgd.ht_capa.ampdu_params_info
> + & IEEE80211_HT_AMPDU_PARM_FACTOR;
That should be a u8.
> + /* Allow the user to increase AMPDU density. */
> + if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
> + IEEE80211_HT_AMPDU_PARM_DENSITY) {
> + u16 n = (sdata->u.mgd.ht_capa.ampdu_params_info &
> + IEEE80211_HT_AMPDU_PARM_DENSITY)
> + >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
> + if (n > ht_cap->ampdu_density)
> + ht_cap->ampdu_density = n;
Ditto here.
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -558,6 +558,19 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
> },
> };
>
> +static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
> + .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR |
> + IEEE80211_HT_AMPDU_PARM_DENSITY,
> +
> + .cap_info = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
> + IEEE80211_HT_CAP_MAX_AMSDU |
> + IEEE80211_HT_CAP_SGI_40,
That also has endian bugs.
> --- a/net/mac80211/mlme.c
> +++ b/net/mac80211/mlme.c
> @@ -209,6 +209,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
> channel_type = NL80211_CHAN_HT20;
>
> if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
> + !ieee80111_cfg_override_disables_ht40(sdata) &&
> (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
> (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
> switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
> @@ -1613,7 +1614,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
> sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
>
> if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
> - ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
> + ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
> elems.ht_cap_elem, &sta->sta.ht_cap);
>
> ap_ht_cap_flags = sta->sta.ht_cap.cap;
> @@ -1982,7 +1983,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
>
> sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
>
> - ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
> + ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
> elems.ht_cap_elem, &sta->sta.ht_cap);
>
> ap_ht_cap_flags = sta->sta.ht_cap.cap;
> @@ -2640,6 +2641,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
> ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
>
>
> + if (req->flags & ASSOC_REQ_DISABLE_HT)
> + ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
> +
> + memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
> + memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
> + sizeof(ifmgd->ht_capa_mask));
> +
You need to reset this on disassoc, at least memset the mask to 0,
otherwise a new association w/o overrides will still have them, and if
you change the iftype to something else things will be completely
confused.
> @@ -113,9 +114,16 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
> if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
> return;
>
> + memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
> + ieee80211_apply_htcap_overrides(sdata, &ht_cap);
> +
> + if (!ht_cap.ht_supported)
> + return;
Can applying the overrides change ht_supported? It didn't seem so, so
maybe this check should stay at the front (where you remove the sband
check that would still be valid)
johannes
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
2011-11-18 10:15 ` Johannes Berg
@ 2011-11-18 17:09 ` Ben Greear
2011-11-18 17:28 ` Johannes Berg
0 siblings, 1 reply; 9+ messages in thread
From: Ben Greear @ 2011-11-18 17:09 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On 11/18/2011 02:15 AM, Johannes Berg wrote:
> On Thu, 2011-11-17 at 13:54 -0800, greearb@candelatech.com wrote:
>
>> -void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
>> +bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
>> +{
>> + const u16 flg = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
>> + if ((sdata->u.mgd.ht_capa_mask.cap_info& flg)&&
>> + !(sdata->u.mgd.ht_capa.cap_info& flg))
>> + return true;
>
> This looks like it has endian bugs. Note that sband->ht_cap is
> ieee80211_sta_ht_cap, whereas sdata->u.mgd.ht_capa[_mask] is
> ieee80211_ht_cap -- the latter is in IEEE format (LE) while the former
> is in a complete different format that's easier to digest for the
> CPU :-)
So, the ht-caps & mask data coming from user-space via netlink
should be in network-byte order?
Or do you want me to flip the bytes around when copying
it into the u.mgd.ht_cap structs?
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
2011-11-18 17:09 ` Ben Greear
@ 2011-11-18 17:28 ` Johannes Berg
2011-11-18 17:31 ` Ben Greear
0 siblings, 1 reply; 9+ messages in thread
From: Johannes Berg @ 2011-11-18 17:28 UTC (permalink / raw)
To: Ben Greear; +Cc: linux-wireless
On Fri, 2011-11-18 at 09:09 -0800, Ben Greear wrote:
> On 11/18/2011 02:15 AM, Johannes Berg wrote:
> > On Thu, 2011-11-17 at 13:54 -0800, greearb@candelatech.com wrote:
> >
> >> -void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
> >> +bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
> >> +{
> >> + const u16 flg = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
> >> + if ((sdata->u.mgd.ht_capa_mask.cap_info& flg)&&
> >> + !(sdata->u.mgd.ht_capa.cap_info& flg))
> >> + return true;
> >
> > This looks like it has endian bugs. Note that sband->ht_cap is
> > ieee80211_sta_ht_cap, whereas sdata->u.mgd.ht_capa[_mask] is
> > ieee80211_ht_cap -- the latter is in IEEE format (LE) while the former
> > is in a complete different format that's easier to digest for the
> > CPU :-)
>
> So, the ht-caps & mask data coming from user-space via netlink
> should be in network-byte order?
It is that way right now, and that makes sense.
> Or do you want me to flip the bytes around when copying
> it into the u.mgd.ht_cap structs?
No. Just use them in little endian ("network byte order" for 802.11)
johannes
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
2011-11-18 17:28 ` Johannes Berg
@ 2011-11-18 17:31 ` Ben Greear
2011-11-18 17:35 ` Johannes Berg
0 siblings, 1 reply; 9+ messages in thread
From: Ben Greear @ 2011-11-18 17:31 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On 11/18/2011 09:28 AM, Johannes Berg wrote:
> On Fri, 2011-11-18 at 09:09 -0800, Ben Greear wrote:
>> On 11/18/2011 02:15 AM, Johannes Berg wrote:
>>> On Thu, 2011-11-17 at 13:54 -0800, greearb@candelatech.com wrote:
>>>
>>>> -void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
>>>> +bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
>>>> +{
>>>> + const u16 flg = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
>>>> + if ((sdata->u.mgd.ht_capa_mask.cap_info& flg)&&
>>>> + !(sdata->u.mgd.ht_capa.cap_info& flg))
>>>> + return true;
>>>
>>> This looks like it has endian bugs. Note that sband->ht_cap is
>>> ieee80211_sta_ht_cap, whereas sdata->u.mgd.ht_capa[_mask] is
>>> ieee80211_ht_cap -- the latter is in IEEE format (LE) while the former
>>> is in a complete different format that's easier to digest for the
>>> CPU :-)
>>
>> So, the ht-caps& mask data coming from user-space via netlink
>> should be in network-byte order?
>
> It is that way right now, and that makes sense.
Ok, I think I am using host-byte-order currently in my iw
and hostap patches, which is why everything works for me.
But, I'll flip that all around....
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
2011-11-18 17:31 ` Ben Greear
@ 2011-11-18 17:35 ` Johannes Berg
0 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2011-11-18 17:35 UTC (permalink / raw)
To: Ben Greear; +Cc: linux-wireless
On Fri, 2011-11-18 at 09:31 -0800, Ben Greear wrote:
> >>> This looks like it has endian bugs. Note that sband->ht_cap is
> >>> ieee80211_sta_ht_cap, whereas sdata->u.mgd.ht_capa[_mask] is
> >>> ieee80211_ht_cap -- the latter is in IEEE format (LE) while the former
> >>> is in a complete different format that's easier to digest for the
> >>> CPU :-)
> >>
> >> So, the ht-caps& mask data coming from user-space via netlink
> >> should be in network-byte order?
> >
> > It is that way right now, and that makes sense.
>
> Ok, I think I am using host-byte-order currently in my iw
> and hostap patches, which is why everything works for me.
>
> But, I'll flip that all around....
You're using x86 so 802.11 byte order == CPU byte order...
Be careful: "network byte order" usually means big endian...
johannes
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v9 1/2] wireless: Support ht-capabilities over-rides.
2011-11-17 21:54 [PATCH v9 1/2] wireless: Support ht-capabilities over-rides greearb
2011-11-17 21:54 ` [PATCH v9 2/2] mac80211: Support ht-cap over-rides greearb
@ 2011-11-18 10:04 ` Johannes Berg
1 sibling, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2011-11-18 10:04 UTC (permalink / raw)
To: greearb; +Cc: linux-wireless
On Thu, 2011-11-17 at 13:54 -0800, greearb@candelatech.com wrote:
> From: Ben Greear <greearb@candelatech.com>
>
> This allows users to disable features such as HT, HT40,
> and to modify the MCS, AMPDU, and AMSDU settings for
> drivers that support it.
>
> The MCS, AMPDU, and AMSDU features that may be disabled are
> are reported in the phy-info netlink message as a mask.
>
> Attemping to disable features that are not supported will
> take no affect, but will not return errors. This is to aid
> backwards compatibility in user-space apps that may not be
> clever enough to deal with parsing the the capabilities mask.
>
> This patch only enables the infrastructure. An additional
> patch will enable the feature in mac80211.
Looks OK to me.
johannes
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v9 2/2] mac80211: Support ht-cap over-rides.
@ 2011-11-08 23:15 greearb
0 siblings, 0 replies; 9+ messages in thread
From: greearb @ 2011-11-08 23:15 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
From: Ben Greear <greearb@candelatech.com>
This implements ht-cap over-rides for mac80211 drivers.
HT may be disabled, making an /a/b/g/n station act like an
a/b/g station. HT40 may be disabled forcing the station to
be HT20 even if the AP and local hardware support HT40.
MAX-AMSDU may be disabled.
AMPDU-Density may be increased.
AMPDU-Factor may be decreased.
This has been successfully tested with ath9k using patched
wpa_supplicant and iw.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
v9: Remove minimum mcs rate advertising. Just let
users advertise as few rates as they desire.
NOTE: Did not make the suggested change of caching the
derived ht-cap struct.
:100644 100644 a9ded52... 7f4389e... M net/mac80211/cfg.c
:100644 100644 f80a35c... e631925... M net/mac80211/ht.c
:100644 100644 ea10a51... cefcbc6... M net/mac80211/ieee80211_i.h
:100644 100644 d4ee6d2... 7be5ad8... M net/mac80211/main.c
:100644 100644 2fbd652... 84d6943... M net/mac80211/mlme.c
:100644 100644 6c53b6d... dd1e00b... M net/mac80211/work.c
net/mac80211/cfg.c | 2 +-
net/mac80211/ht.c | 75 +++++++++++++++++++++++++++++++++++++++++++-
net/mac80211/ieee80211_i.h | 9 +++++-
net/mac80211/main.c | 14 ++++++++
net/mac80211/mlme.c | 12 ++++++-
net/mac80211/work.c | 30 ++++++++++++------
6 files changed, 127 insertions(+), 15 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a9ded52..7f4389e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -778,7 +778,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
}
if (params->ht_capa)
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
params->ht_capa,
&sta->sta.ht_cap);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index f80a35c..e631925 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -18,7 +18,74 @@
#include "ieee80211_i.h"
#include "rate.h"
-void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
+{
+ const u16 flg = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) &&
+ !(sdata->u.mgd.ht_capa.cap_info & flg))
+ return true;
+ return false;
+}
+
+void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ u16 flag)
+{
+ if (sdata->u.mgd.ht_capa_mask.cap_info & flag) {
+ if (!(sdata->u.mgd.ht_capa.cap_info & flag))
+ ht_cap->cap &= ~flag;
+ }
+}
+
+void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_ht_cap *ht_cap)
+{
+ u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask);
+ u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
+ int i;
+
+ /* NOTE: If you add more over-rides here, update register_hw
+ * ht_capa_mod_msk logic in main.c as well.
+ */
+
+ /* check for HT over-rides, MCS rates first. */
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ u8 m = smask[i];
+ ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */
+ /* Add back rates that are supported */
+ ht_cap->mcs.rx_mask[i] |= (m & scaps[i]);
+ }
+
+ /* Force removal of HT-40 capabilities? */
+ __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+ __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40);
+
+ /* Allow user to disable the max-AMSDU bit. */
+ __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU);
+
+ /* Allow user to decrease AMPDU factor */
+ if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
+ IEEE80211_HT_AMPDU_PARM_FACTOR) {
+ u16 n = sdata->u.mgd.ht_capa.ampdu_params_info
+ & IEEE80211_HT_AMPDU_PARM_FACTOR;
+ if (n < ht_cap->ampdu_factor)
+ ht_cap->ampdu_factor = n;
+ }
+
+ /* Allow the user to increase AMPDU density. */
+ if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
+ IEEE80211_HT_AMPDU_PARM_DENSITY) {
+ u16 n = (sdata->u.mgd.ht_capa.ampdu_params_info &
+ IEEE80211_HT_AMPDU_PARM_DENSITY)
+ >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
+ if (n > ht_cap->ampdu_density)
+ ht_cap->ampdu_density = n;
+ }
+}
+
+
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap)
{
@@ -102,6 +169,12 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
/* handle MCS rate 32 too */
if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
ht_cap->mcs.rx_mask[32/8] |= 1;
+
+ /*
+ * If user has specified capability over-rides, take care
+ * of that here.
+ */
+ ieee80211_apply_htcap_overrides(sdata, ht_cap);
}
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ea10a51..cefcbc6 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -443,6 +443,9 @@ struct ieee80211_if_managed {
*/
int rssi_min_thold, rssi_max_thold;
int last_ave_beacon_signal;
+ struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
+ struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
+
};
struct ieee80211_if_ibss {
@@ -1179,7 +1182,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
/* HT */
-void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata);
+void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_ht_cap *ht_cap);
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap);
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d4ee6d2..7be5ad8 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -560,6 +560,19 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
};
+static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
+ .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR |
+ IEEE80211_HT_AMPDU_PARM_DENSITY,
+
+ .cap_info = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_MAX_AMSDU |
+ IEEE80211_HT_CAP_SGI_40,
+ .mcs = {
+ .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, },
+ },
+};
+
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
@@ -628,6 +641,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->user_power_level = -1;
local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
+ wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
INIT_LIST_HEAD(&local->interfaces);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2fbd652..84d6943 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -207,6 +207,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
channel_type = NL80211_CHAN_HT20;
if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+ !ieee80111_cfg_override_disables_ht40(sdata) &&
(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
@@ -1603,7 +1604,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
ap_ht_cap_flags = sta->sta.ht_cap.cap;
@@ -1972,7 +1973,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
ap_ht_cap_flags = sta->sta.ht_cap.cap;
@@ -2630,6 +2631,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+ if (req->flags & ASSOC_REQ_DISABLE_HT)
+ ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+
+ memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
+ memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
+ sizeof(ifmgd->ht_capa_mask));
+
if (req->ie && req->ie_len) {
memcpy(wk->ie, req->ie, req->ie_len);
wk->ie_len = req->ie_len;
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 6c53b6d..dd1e00b 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
/* frame sending functions */
-static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
+static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, const u8 *ht_info_ie,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
enum ieee80211_smps_mode smps)
@@ -102,11 +103,11 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
struct ieee80211_ht_info *ht_info;
u8 *pos;
u32 flags = channel->flags;
- u16 cap = sband->ht_cap.cap;
+ u16 cap;
__le16 tmp;
+ struct ieee80211_sta_ht_cap ht_cap;
- if (!sband->ht_cap.ht_supported)
- return;
+ BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
if (!ht_info_ie)
return;
@@ -114,6 +115,15 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
return;
+ memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
+
+ ieee80211_apply_htcap_overrides(sdata, &ht_cap);
+
+ cap = ht_cap.cap;
+
+ if (!ht_cap.ht_supported)
+ return;
+
ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
/* determine capability flags */
@@ -166,13 +176,13 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
pos += sizeof(u16);
/* AMPDU parameters */
- *pos++ = sband->ht_cap.ampdu_factor |
- (sband->ht_cap.ampdu_density <<
- IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+ *pos++ = ht_cap.ampdu_factor |
+ (ht_cap.ampdu_density <<
+ IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
/* MCS set */
- memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
- pos += sizeof(sband->ht_cap.mcs);
+ memcpy(pos, &ht_cap.mcs, sizeof(ht_cap.mcs));
+ pos += sizeof(ht_cap.mcs);
/* extended capabilities */
pos += sizeof(__le16);
@@ -356,7 +366,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
if (wk->assoc.use_11n && wk->assoc.wmm_used &&
local->hw.queues >= 4)
- ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie,
+ ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,
sband, wk->chan, wk->assoc.smps);
/* if present, add any custom non-vendor IEs that go after HT */
--
1.7.3.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-11-18 17:35 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-17 21:54 [PATCH v9 1/2] wireless: Support ht-capabilities over-rides greearb
2011-11-17 21:54 ` [PATCH v9 2/2] mac80211: Support ht-cap over-rides greearb
2011-11-18 10:15 ` Johannes Berg
2011-11-18 17:09 ` Ben Greear
2011-11-18 17:28 ` Johannes Berg
2011-11-18 17:31 ` Ben Greear
2011-11-18 17:35 ` Johannes Berg
2011-11-18 10:04 ` [PATCH v9 1/2] wireless: Support ht-capabilities over-rides Johannes Berg
-- strict thread matches above, loose matches on Subject: below --
2011-11-08 23:15 [PATCH v9 2/2] mac80211: Support ht-cap over-rides greearb
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.