Search Linux Wireless

[RFC 3/4] cfg80211: allow driver to implement HT capabilities per netdev

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

 



Add a callback allowing drivers to return custom HT capabilities per
interface (netdev). This callback is used when per-band HT capabilities
are marked as invalid.

Use the new callback to return per-netdev HT capabilities where
need by NL80211 commands - namely, GET_WIPHY and SET_TX_BITRATE_MASK.

Signed-off-by: Arik Nemtsov <arik@xxxxxxxxxx>
---
 include/net/cfg80211.h |    7 +++++++
 net/wireless/nl80211.c |   49 +++++++++++++++++++++++++++++++++++-------------
 2 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7b24d88..b27ffe1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1619,6 +1619,10 @@ struct cfg80211_gtk_rekey_data {
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  *	and perhaps other supported types of ethtool data-sets.
  *	See @ethtool_ops.get_strings
+ *
+ * @get_ht_cap: Get the HT capabilities of the given interface on the given
+ *	band. If not implemented, the per-band HT capabilities from struct
+ *	wiphy are used.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1827,6 +1831,9 @@ struct cfg80211_ops {
 				  u32 sset, u8 *data);
 
 	void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled);
+	struct ieee80211_sta_ht_cap *(*get_ht_cap)(struct wiphy *wiphy,
+						   struct net_device *dev,
+						   enum ieee80211_band band);
 };
 
 /*
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 010ff47..e737d8c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -790,6 +790,19 @@ nla_put_failure:
 	return -ENOBUFS;
 }
 
+static const struct ieee80211_sta_ht_cap *
+nl80211_get_ht_cap(struct cfg80211_registered_device *dev,
+		   struct net_device *netdev, enum ieee80211_band band)
+{
+	WARN_ON(!dev->wiphy.bands[band]);
+
+	if (netdev && dev->ops->get_ht_cap &&
+	    dev->wiphy.bands[band]->ht_cap_invalid)
+		return dev->ops->get_ht_cap(&dev->wiphy, netdev, band);
+
+	return &dev->wiphy.bands[band]->ht_cap;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev,
 			      struct net_device *netdev)
@@ -902,6 +915,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 		goto nla_put_failure;
 
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		const struct ieee80211_sta_ht_cap *local_ht_cap;
 		if (!dev->wiphy.bands[band])
 			continue;
 
@@ -909,17 +923,19 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 		if (!nl_band)
 			goto nla_put_failure;
 
+		local_ht_cap = nl80211_get_ht_cap(dev, netdev, band);
+
 		/* add HT info */
-		if (dev->wiphy.bands[band]->ht_cap.ht_supported &&
+		if (local_ht_cap->ht_supported &&
 		    (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
-			     sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
-			     &dev->wiphy.bands[band]->ht_cap.mcs) ||
+			     sizeof(local_ht_cap->mcs),
+			     &local_ht_cap->mcs) ||
 		     nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
-				 dev->wiphy.bands[band]->ht_cap.cap) ||
+				 local_ht_cap->cap) ||
 		     nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
-				dev->wiphy.bands[band]->ht_cap.ampdu_factor) ||
+				local_ht_cap->ampdu_factor) ||
 		     nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
-				dev->wiphy.bands[band]->ht_cap.ampdu_density)))
+				local_ht_cap->ampdu_density)))
 			goto nla_put_failure;
 
 		/* add VHT info */
@@ -5793,7 +5809,7 @@ static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
 	return mask;
 }
 
-static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
+static bool ht_rateset_to_mask(const struct ieee80211_sta_ht_cap *ht_cap,
 			       u8 *rates, u8 rates_len,
 			       u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
 {
@@ -5812,7 +5828,7 @@ static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
 			return false;
 
 		/* check availability */
-		if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
+		if (ht_cap->mcs.rx_mask[ridx] & rbit)
 			mcs[ridx] |= rbit;
 		else
 			return false;
@@ -5838,6 +5854,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
 	struct net_device *dev = info->user_ptr[1];
 	struct nlattr *tx_rates;
 	struct ieee80211_supported_band *sband;
+	const struct ieee80211_sta_ht_cap *ht_cap;
 
 	if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
 		return -EINVAL;
@@ -5851,13 +5868,15 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
 		sband = rdev->wiphy.bands[i];
 		mask.control[i].legacy =
 			sband ? (1 << sband->n_bitrates) - 1 : 0;
-		if (sband)
+		if (sband) {
+			ht_cap = nl80211_get_ht_cap(rdev, dev, i);
 			memcpy(mask.control[i].mcs,
-			       sband->ht_cap.mcs.rx_mask,
+			       ht_cap->mcs.rx_mask,
 			       sizeof(mask.control[i].mcs));
-		else
+		} else {
 			memset(mask.control[i].mcs, 0,
 			       sizeof(mask.control[i].mcs));
+		}
 	}
 
 	/*
@@ -5884,9 +5903,10 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
 			    nla_len(tb[NL80211_TXRATE_LEGACY]))
 				return -EINVAL;
 		}
+		ht_cap = nl80211_get_ht_cap(rdev, dev, band);
 		if (tb[NL80211_TXRATE_MCS]) {
 			if (!ht_rateset_to_mask(
-					sband,
+					ht_cap,
 					nla_data(tb[NL80211_TXRATE_MCS]),
 					nla_len(tb[NL80211_TXRATE_MCS]),
 					mask.control[band].mcs))
@@ -5894,9 +5914,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
 		}
 
 		if (mask.control[band].legacy == 0) {
+			const struct ieee80211_sta_ht_cap *ht_cap;
+			ht_cap = nl80211_get_ht_cap(rdev, dev, band);
+
 			/* don't allow empty legacy rates if HT
 			 * is not even supported. */
-			if (!rdev->wiphy.bands[band]->ht_cap.ht_supported)
+			if (!ht_cap->ht_supported)
 				return -EINVAL;
 
 			for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
-- 
1.7.9.5

--
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 Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux