diff mbox

[RFC,3/4] mac80211: Apply per-peer NoAck tid bitmap configuration

Message ID 1522140171-10926-4-git-send-email-vthiagar@codeaurora.org (mailing list archive)
State RFC
Delegated to: Johannes Berg
Headers show

Commit Message

Vasanthakumar Thiagarajan March 27, 2018, 8:42 a.m. UTC
Use per-peer noack tid bitmap, if it is configured,
when setting up the qos header. If no per-peer configuration
is set, use the existing nedev wide noack policy configuration.
Also modifies callback set_noack_tid_bitmap() with the provision
to send per-peer NoAck policy configuration to the drivers supporting
the NoAck offload functionality (IEEE80211_HW_SUPPORTS_NOACK_POLICY).

Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@codeaurora.org>
---
 include/net/mac80211.h    |  7 +++++--
 net/mac80211/cfg.c        | 42 +++++++++++++++++++++++++++++++++++++-----
 net/mac80211/driver-ops.h |  5 +++--
 net/mac80211/iface.c      |  2 +-
 net/mac80211/sta_info.h   |  3 +++
 net/mac80211/trace.h      |  9 ++++++---
 net/mac80211/tx.c         |  2 +-
 net/mac80211/wme.c        | 34 +++++++++++++++++++++++++++++++++-
 8 files changed, 89 insertions(+), 15 deletions(-)

Comments

Johannes Berg March 27, 2018, 12:54 p.m. UTC | #1
On Tue, 2018-03-27 at 14:12 +0530, Vasanthakumar Thiagarajan wrote:
> 
> +u16 ieee80211_get_noack_map(struct ieee80211_sub_if_data *sdata, const u8 *mac)
> +{
> +	struct sta_info *sta;
> +	u16 noack_map = 0;
> +
> +	/* Retrieve per-station noack_map config for the receiver, if any */
> +
> +	rcu_read_lock();
> +
> +	sta = sta_info_get(sdata, mac);
> +	if (!sta) {
> +		rcu_read_unlock();
> +		return noack_map;
> +	}
> +
> +	noack_map = sta->noack_map;
> +
> +	rcu_read_unlock();
> +
> +	if (!noack_map)
> +		noack_map = sdata->noack_map;

So this has an interesting corner case - should it be possible to have a
default noack_map that's non-zero, but override it with 0 for a specific
peer? It seems that it should be, which makes this code wrong.

johannes
Vasanthakumar Thiagarajan March 28, 2018, 5:43 a.m. UTC | #2
On 2018-03-27 18:24, Johannes Berg wrote:
> On Tue, 2018-03-27 at 14:12 +0530, Vasanthakumar Thiagarajan wrote:
>> 
>> +u16 ieee80211_get_noack_map(struct ieee80211_sub_if_data *sdata, 
>> const u8 *mac)
>> +{
>> +	struct sta_info *sta;
>> +	u16 noack_map = 0;
>> +
>> +	/* Retrieve per-station noack_map config for the receiver, if any */
>> +
>> +	rcu_read_lock();
>> +
>> +	sta = sta_info_get(sdata, mac);
>> +	if (!sta) {
>> +		rcu_read_unlock();
>> +		return noack_map;
>> +	}
>> +
>> +	noack_map = sta->noack_map;
>> +
>> +	rcu_read_unlock();
>> +
>> +	if (!noack_map)
>> +		noack_map = sdata->noack_map;
> 
> So this has an interesting corner case - should it be possible to have 
> a
> default noack_map that's non-zero, but override it with 0 for a 
> specific
> peer? It seems that it should be, which makes this code wrong.

I think 0 as the Noack configuration from user can also be a valid one 
in the case
where user does not want any NoAck policy to be used for a particular 
station even
when a non-zero NoAck configuration is set for ndev level. In this case, 
the logic
may need to be modified so that the default non-zero configuration 
(something like -1)
could be used to determine that the station has been never configured 
with any NoAck
policy and use ndev level configuration. Does this sound reasonable?

Vasanth
Johannes Berg March 28, 2018, 8:04 a.m. UTC | #3
> I think 0 as the Noack configuration from user can also be a valid one 
> in the case
> where user does not want any NoAck policy to be used for a particular 
> station even
> when a non-zero NoAck configuration is set for ndev level. In this case, 
> the logic
> may need to be modified so that the default non-zero configuration 
> (something like -1)
> could be used to determine that the station has been never configured 
> with any NoAck
> policy and use ndev level configuration. Does this sound reasonable?

Yes. You'll have to use int instead of u16 I guess, but that's
completely doable.

johannes
Vasanthakumar Thiagarajan March 29, 2018, 5:31 a.m. UTC | #4
On 2018-03-27 14:12, Vasanthakumar Thiagarajan wrote:
> Use per-peer noack tid bitmap, if it is configured,
> when setting up the qos header. If no per-peer configuration
> is set, use the existing nedev wide noack policy configuration.
> Also modifies callback set_noack_tid_bitmap() with the provision
> to send per-peer NoAck policy configuration to the drivers supporting
> the NoAck offload functionality (IEEE80211_HW_SUPPORTS_NOACK_POLICY).
> 
> Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@codeaurora.org>
> ---
>  include/net/mac80211.h    |  7 +++++--
>  net/mac80211/cfg.c        | 42 
> +++++++++++++++++++++++++++++++++++++-----
>  net/mac80211/driver-ops.h |  5 +++--
>  net/mac80211/iface.c      |  2 +-
>  net/mac80211/sta_info.h   |  3 +++
>  net/mac80211/trace.h      |  9 ++++++---
>  net/mac80211/tx.c         |  2 +-
>  net/mac80211/wme.c        | 34 +++++++++++++++++++++++++++++++++-
>  8 files changed, 89 insertions(+), 15 deletions(-)
> 

<snip>

> diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
> index a0a2d3c..8a2154a 100644
> --- a/net/mac80211/driver-ops.h
> +++ b/net/mac80211/driver-ops.h
> @@ -1252,6 +1252,7 @@ static inline void drv_del_nan_func(struct
> ieee80211_local *local,
> 
>  static inline int drv_set_noack_tid_bitmap(struct ieee80211_local 
> *local,
>  					   struct ieee80211_sub_if_data *sdata,
> +					   struct sta_info *sta,
>  					   u16 noack_map)
>  {
>  	int ret;
> @@ -1263,9 +1264,9 @@ static inline int
> drv_set_noack_tid_bitmap(struct ieee80211_local *local,
>  	if (!local->ops->set_noack_tid_bitmap)
>  		return -EOPNOTSUPP;
> 
> -	trace_drv_set_noack_tid_bitmap(local, sdata, noack_map);
> +	trace_drv_set_noack_tid_bitmap(local, sdata, &sta->sta, noack_map);
>  	ret = local->ops->set_noack_tid_bitmap(&local->hw, &sdata->vif,
> -					       noack_map);
> +					       &sta->sta, noack_map);

Oops, we'll endup in NULL pointer dereference in accessing sta object 
when ndev level
configuration is sent. Ill address this in the next version.

Vasanth
diff mbox

Patch

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5a49c90..a5ed552 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3499,7 +3499,9 @@  enum ieee80211_reconfig_type {
  *	ieee80211_nan_func_terminated() with
  *	NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal.
  *
- * @set_noack_tid_bitmap: Set NoAck policy TID bitmap for a virtual interface.
+ * @set_noack_tid_bitmap: Set NoAck policy TID bitmap. Apply the TID NoAck
+ *	configuration for a particular station when @sta is non-NULL. When @sta
+ *	is NULL, apply TID NoAck configuration at virtual interface level.
  *	Drivers advertising NoAck policy handing support
  *	(%IEEE80211_HW_SUPPORTS_NOACK_POLICY) must implement this callback.
  */
@@ -3785,7 +3787,8 @@  struct ieee80211_ops {
 			    u8 instance_id);
 
 	int (*set_noack_tid_bitmap)(struct ieee80211_hw *hw,
-				    struct ieee80211_vif *vif, u8 noack_map);
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_sta *sta, u8 noack_map);
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 621ef38..1efc9cf 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -345,18 +345,50 @@  static int ieee80211_set_noack_map(struct wiphy *wiphy,
 				  u16 noack_map)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+	int ret;
 
-	sdata->noack_map = noack_map;
+	if (!peer) {
+		sdata->noack_map = noack_map;
 
-	if (!ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NOACK_POLICY)) {
-		ieee80211_check_fast_xmit_iface(sdata);
-		return 0;
+		if (!ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NOACK_POLICY)) {
+			ieee80211_check_fast_xmit_iface(sdata);
+			return 0;
+		}
+
+		if (!ieee80211_sdata_running(sdata))
+			return 0;
+
+		return drv_set_noack_tid_bitmap(sdata->local, sdata, NULL,
+						noack_map);
 	}
 
+	/* NoAck policy is for a connected client on the dev */
+
 	if (!ieee80211_sdata_running(sdata))
+		return -ENETDOWN;
+
+	mutex_lock(&sdata->local->sta_mtx);
+
+	sta = sta_info_get_bss(sdata, peer);
+	if (!sta) {
+		mutex_unlock(&sdata->local->sta_mtx);
+		return -ENOENT;
+	}
+
+	sta->noack_map = noack_map;
+
+	if (!ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NOACK_POLICY)) {
+		ieee80211_check_fast_xmit(sta);
+		mutex_unlock(&sdata->local->sta_mtx);
 		return 0;
+	}
+
+	ret = drv_set_noack_tid_bitmap(sdata->local, sdata, sta, noack_map);
 
-	return drv_set_noack_tid_bitmap(sdata->local, sdata, noack_map);
+	mutex_unlock(&sdata->local->sta_mtx);
+
+	return ret;
 }
 
 static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index a0a2d3c..8a2154a 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1252,6 +1252,7 @@  static inline void drv_del_nan_func(struct ieee80211_local *local,
 
 static inline int drv_set_noack_tid_bitmap(struct ieee80211_local *local,
 					   struct ieee80211_sub_if_data *sdata,
+					   struct sta_info *sta,
 					   u16 noack_map)
 {
 	int ret;
@@ -1263,9 +1264,9 @@  static inline int drv_set_noack_tid_bitmap(struct ieee80211_local *local,
 	if (!local->ops->set_noack_tid_bitmap)
 		return -EOPNOTSUPP;
 
-	trace_drv_set_noack_tid_bitmap(local, sdata, noack_map);
+	trace_drv_set_noack_tid_bitmap(local, sdata, &sta->sta, noack_map);
 	ret = local->ops->set_noack_tid_bitmap(&local->hw, &sdata->vif,
-					       noack_map);
+					       &sta->sta, noack_map);
 	trace_drv_return_int(local, ret);
 
 	return ret;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 4e120b9..1172bed 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -633,7 +633,7 @@  int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 				goto err_del_interface;
 
 			if (sdata->noack_map)
-				drv_set_noack_tid_bitmap(local, sdata,
+				drv_set_noack_tid_bitmap(local, sdata, NULL,
 							 sdata->noack_map);
 		}
 
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f64eb86..01bee75 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -581,6 +581,9 @@  struct sta_info {
 
 	struct cfg80211_chan_def tdls_chandef;
 
+	/* TID bitmap for station's NoAck policy */
+	u16 noack_map;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 3b55569..84089f7 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1866,25 +1866,28 @@  struct trace_switch_entry {
 TRACE_EVENT(drv_set_noack_tid_bitmap,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta,
 		 u16 noack_map),
 
-	TP_ARGS(local, sdata, noack_map),
+	TP_ARGS(local, sdata, sta, noack_map),
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		VIF_ENTRY
+		STA_ENTRY
 		__field(u16, noack_map)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		VIF_ASSIGN;
+		STA_ASSIGN;
 		__entry->noack_map = noack_map;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT
+		LOCAL_PR_FMT  VIF_PR_FMT STA_PR_FMT
 		", noack_map: %u",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->noack_map
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->noack_map
 	)
 );
 
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 27fcef3..5abe73b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2817,7 +2817,7 @@  void ieee80211_check_fast_xmit(struct sta_info *sta)
 	    test_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT))
 		goto out;
 
-	if (sdata->noack_map &&
+	if ((sdata->noack_map || sta->noack_map) &&
 	    !ieee80211_hw_check(&local->hw, SUPPORTS_NOACK_POLICY))
 		goto out;
 
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 6512a47..645c50b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -227,6 +227,38 @@  u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
 }
 
 /**
+ * ieee80211_get_noack_map - Get TID bitmap of NoAck policy. NoAck policy
+ * could be device wide or per-station.
+ *
+ * @sdata: local subif
+ * @mac: MAC address of the receiver
+ */
+u16 ieee80211_get_noack_map(struct ieee80211_sub_if_data *sdata, const u8 *mac)
+{
+	struct sta_info *sta;
+	u16 noack_map = 0;
+
+	/* Retrieve per-station noack_map config for the receiver, if any */
+
+	rcu_read_lock();
+
+	sta = sta_info_get(sdata, mac);
+	if (!sta) {
+		rcu_read_unlock();
+		return noack_map;
+	}
+
+	noack_map = sta->noack_map;
+
+	rcu_read_unlock();
+
+	if (!noack_map)
+		noack_map = sdata->noack_map;
+
+	return noack_map;
+}
+
+/**
  * ieee80211_set_qos_hdr - Fill in the QoS header if there is one.
  *
  * @sdata: local subif
@@ -257,7 +289,7 @@  void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
 
 	if (is_multicast_ether_addr(hdr->addr1) ||
 	    (!ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NOACK_POLICY) &&
-	    sdata->noack_map & BIT(tid))) {
+	    ieee80211_get_noack_map(sdata, hdr->addr1) & BIT(tid))) {
 		flags |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
 		info->flags |= IEEE80211_TX_CTL_NO_ACK;
 	}