On Tue, 2011-11-08 at 11:36 -0800, greearb@xxxxxxxxxxxxxxx wrote: > From: Ben Greear <greearb@xxxxxxxxxxxxxxx> > > 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 now. > Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx> > --- > > v8: Fix compile bugs from v7. Must have compiled the > wrong tree while testing that. > > :100644 100644 8049bf7... 34c3973... M include/linux/nl80211.h > :100644 100644 92cf1c2... 5598b91... M include/net/cfg80211.h > :100644 100644 b9ec306... 8357ed6... M net/wireless/core.h > :100644 100644 21fc970... bf538e1... M net/wireless/mlme.c > :100644 100644 b3a476f... 31f17c8... M net/wireless/nl80211.c > :100644 100644 6e86d5a... ed9d0e6... M net/wireless/sme.c > include/linux/nl80211.h | 15 +++++++++++++++ > include/net/cfg80211.h | 28 ++++++++++++++++++++++++++++ > net/wireless/core.h | 10 ++++++++-- > net/wireless/mlme.c | 37 ++++++++++++++++++++++++++++++++++--- > net/wireless/nl80211.c | 44 +++++++++++++++++++++++++++++++++++++++++++- > net/wireless/sme.c | 7 ++++++- > 6 files changed, 134 insertions(+), 7 deletions(-) > > diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h > index 8049bf7..34c3973 100644 > --- a/include/linux/nl80211.h > +++ b/include/linux/nl80211.h > @@ -1109,6 +1109,18 @@ enum nl80211_commands { > * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be > * used for asking the driver to perform a TDLS operation. > * > + * @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 > */ > @@ -1337,6 +1349,9 @@ enum nl80211_attrs { > NL80211_ATTR_TDLS_SUPPORT, > NL80211_ATTR_TDLS_EXTERNAL_SETUP, > > + 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 92cf1c2..5598b91 100644 > --- a/include/net/cfg80211.h > +++ b/include/net/cfg80211.h > @@ -1036,6 +1036,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 > @@ -1046,6 +1055,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; > @@ -1053,6 +1066,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; > }; > > /** > @@ -1151,6 +1167,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; > @@ -1164,6 +1184,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; > }; > > /** > @@ -1903,6 +1926,9 @@ struct wiphy_wowlan_support { > * may request, if implemented. > * > * @wowlan: WoWLAN support information > + * > + * @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 */ > @@ -1983,6 +2009,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 b9ec306..8357ed6 100644 > --- a/net/wireless/core.h > +++ b/net/wireless/core.h > @@ -339,13 +339,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, > @@ -377,6 +381,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, > 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 21fc970..bf538e1 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 b3a476f..31f17c8 100644 > --- a/net/wireless/nl80211.c > +++ b/net/wireless/nl80211.c > @@ -196,6 +196,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { > [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, > [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, > [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, > + [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG }, > + [NL80211_ATTR_HT_CAPABILITY_MASK] = { > + .len = NL80211_HT_CAPABILITY_LEN > + }, > }; > > /* policy for the key attributes */ > @@ -1007,6 +1011,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, > if (nl80211_put_iface_combinations(&dev->wiphy, msg)) > goto nla_put_failure; > > + 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: > @@ -4359,6 +4368,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; > @@ -4402,11 +4414,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; > } > @@ -4896,6 +4922,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 6e86d5a..ed9d0e6 100644 > --- a/net/wireless/sme.c > +++ b/net/wireless/sme.c > @@ -189,7 +189,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, > @@ -773,6 +775,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; -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html