Search Linux Wireless

[wireless-next PATCH 3/5] wifi: Allow overriding some HT information.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ben Greear <greearb@xxxxxxxxxxxxxxx>

* Allow configuring the mcs (/n) rates available.
* Allow configuration of MAX-A-MSDU
* Allow configuration of A-MPDU factor & density.

Users can only remove existing rates.  The MSDU and MPDU
values can be set to any value allowed by the 802.11n
specification.

Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
---
:100644 100644 ae50ade... 7f269cd... M	include/linux/nl80211.h
:100644 100644 9d7a5e0... 802ff5f... M	include/net/cfg80211.h
:100644 100644 c63d7f0... dde541f... M	net/mac80211/cfg.c
:100644 100644 f80a35c... 0753c96... M	net/mac80211/ht.c
:100644 100644 f4a7618... f279ee9... M	net/mac80211/ieee80211_i.h
:100644 100644 164cdb1... 681ba4e... M	net/mac80211/mlme.c
:100644 100644 94472eb... 2f546be... M	net/mac80211/work.c
:100644 100644 5696621... 2cbb7c6... M	net/wireless/nl80211.c
 include/linux/nl80211.h    |    3 ++
 include/net/cfg80211.h     |    4 ++
 net/mac80211/cfg.c         |   28 +++++++++++++++++-
 net/mac80211/ht.c          |   70 +++++++++++++++++++++++++++++++++++++++++++-
 net/mac80211/ieee80211_i.h |    9 +++++-
 net/mac80211/mlme.c        |    4 +-
 net/mac80211/work.c        |   34 +++++++++++++++------
 net/wireless/nl80211.c     |   14 +++++++++
 8 files changed, 151 insertions(+), 15 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index ae50ade..7f269cd 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1113,6 +1113,8 @@ enum nl80211_commands {
  *      function as /a/b/g stations.
  * @NL80211_ATTR_DISABLE_HT40:  Disable HT-40 even if AP and hardware
  *      support it.
+ * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the HT_CAPs
+ *      to pay attention to.
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1344,6 +1346,7 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_DISABLE_11N,
 	NL80211_ATTR_DISABLE_HT40,
+	NL80211_ATTR_HT_CAPABILITY_MASK,
 
 	/* add attributes here, update the policy in nl80211.c */
 
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9d7a5e0..802ff5f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -256,11 +256,15 @@ struct ieee80211_supported_band {
  * @use_4addr: use 4-address frames
  * @disable_11n:  Don't use 11n features (HT, etc)
  * @disable_ht40:  Don't use HT40, even if hardware & AP support it.
+ * @ht_capa:  HT Capabilities for this interface.
+ * @ht_capa_mask:  Bits of ht_capa that are to be used.
  */
 struct vif_params {
 	int use_4addr;
 	int disable_11n;
 	int disable_ht40;
+	struct ieee80211_ht_cap *ht_capa;
+	struct ieee80211_ht_cap *ht_capa_mask;
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c63d7f0..dde541f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -105,6 +105,32 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 		}
 	}
 
+	if (params->ht_capa) {
+		u8 *caps = (u8 *)(params->ht_capa);
+		u8 *mask = (u8 *)(params->ht_capa_mask);
+		u8 *scaps = (u8 *)(&sdata->ht_capa);
+		u8 *smask = (u8 *)(&sdata->ht_capa_mask);
+		int i;
+
+		for (i = 0; i < sizeof(sdata->ht_capa); i++) {
+			if (mask[i]) {
+				int q;
+				smask[i] |= mask[i];
+				for (q = 0; q < 8; q++) {
+					if (mask[i] & (1<<q)) {
+						if (caps[i] & (1<<q))
+							scaps[i] |= (1<<q);
+						else
+							scaps[i] &= ~(1<<q);
+					}
+				}
+			}
+		}
+	} else if (params->ht_capa_mask) {
+		memcpy(&sdata->ht_capa_mask, params->ht_capa_mask,
+		       sizeof(sdata->ht_capa_mask));
+	}
+
 	return 0;
 }
 
@@ -784,7 +810,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..0753c96 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -18,7 +18,70 @@
 #include "ieee80211_i.h"
 #include "rate.h"
 
-void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_sta_ht_cap *ht_cap,
+				     int min_rates)
+{
+	u8 *scaps = (u8 *)(&sdata->ht_capa.mcs.rx_mask);
+	u8 *smask = (u8 *)(&sdata->ht_capa_mask.mcs.rx_mask);
+	int i;
+
+	/* check for HT over-rides, mcs rates only at this time,
+	 * and can only disable them, not force new ones to be
+	 * made available.
+	 */
+	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+		int q;
+		for (q = 0; q < 8; q++) {
+			/*
+			 * We always need to advert at least MCS0-7, to
+			 * be a compliant HT station, for instance
+			 */
+			if (((i * 8 + q) >= min_rates) &&
+			    (smask[i] & (1<<q))) {
+				if (!(scaps[i] & (1<<q))) {
+					/*
+					 * Can only disable rates, not force
+					 * new ones
+					 */
+					ht_cap->mcs.rx_mask[i] &= ~(1<<q);
+				}
+			}
+		}
+	}
+
+	/* Force removal of HT-40 capabilities? */
+	if (sdata->cfg_disable_ht40) {
+		ht_cap->cap &= ~(IEEE80211_HT_CAP_SUP_WIDTH_20_40
+				 | IEEE80211_HT_CAP_SGI_40);
+	}
+
+	/* Allow user to set max AMDSU bit. */
+	if (sdata->ht_capa_mask.cap_info & IEEE80211_HT_CAP_MAX_AMSDU) {
+		if (sdata->ht_capa.cap_info & IEEE80211_HT_CAP_MAX_AMSDU)
+			ht_cap->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+		else
+			ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+	}
+
+	/* Set the AMPDU factor */
+	if (sdata->ht_capa_mask.ampdu_params_info &
+	    IEEE80211_HT_AMPDU_PARM_FACTOR)
+		ht_cap->ampdu_factor = sdata->ht_capa.ampdu_params_info &
+			IEEE80211_HT_AMPDU_PARM_FACTOR;
+
+	/* Set the AMPDU density */
+	if (sdata->ht_capa_mask.ampdu_params_info &
+	    IEEE80211_HT_AMPDU_PARM_DENSITY)
+		ht_cap->ampdu_density =
+			(sdata->ht_capa.ampdu_params_info &
+			 IEEE80211_HT_AMPDU_PARM_DENSITY)
+			>> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
+}
+
+
+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 +165,11 @@ 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, 0);
 }
 
 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 f4a7618..f279ee9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -598,6 +598,9 @@ struct ieee80211_sub_if_data {
 	bool cfg_disable_11n; /* configured to disable 11n? */
 	bool cfg_disable_ht40; /* configured to not use HT-40 */
 
+	struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
+	struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
+
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
@@ -1181,7 +1184,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,
+void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_sta_ht_cap *ht_cap,
+				     int min_rates);
+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/mlme.c b/net/mac80211/mlme.c
index 164cdb1..681ba4e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1571,7 +1571,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;
@@ -1940,7 +1940,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;
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 94472eb..2f546be 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,19 @@ 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));
+	/*
+	 * This is for an association attempt, and we must
+	 * advert at least the first 8 rates, even if we
+	 * will later force the rate control to a lower rate.
+	 */
+	ieee80211_apply_htcap_overrides(sdata, &ht_cap, 8);
+
+	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 +180,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 +370,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 */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5696621..2cbb7c6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1655,6 +1655,20 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 		params.disable_ht40 = -1;
 	}
 
+	if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
+		params.ht_capa_mask =
+			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]);
+		change = true;
+	}
+
+	if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
+		if (!params.ht_capa_mask)
+			return -EINVAL;
+		params.ht_capa =
+			nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+		change = true;
+	}
+
 	if (change)
 		err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
 	else
-- 
1.7.3.4

--
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


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux