From: Vasanthakumar Thiagarajan <[email protected]>

Use per-peer NoAck tid bitmap, if it is configured,
when setting up the qos header. If the NoAck tid bitmap is
default (-1) for a peer, use the netdev wide noack policy
configuration. The NoAck tid bitmap for newly connected stations
is set to default (-1). Also modifies callback set_noack_tid_bitmap()
with the provision to send per-peer NoAck policy configuration to the
drivers.

Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
Signed-off-by: Tamizh chelvam <[email protected]>
---
 include/net/mac80211.h    |   14 ++++++++++----
 net/mac80211/cfg.c        |   43 ++++++++++++++++++++++++++++++++++++++-----
 net/mac80211/driver-ops.h |    3 ++-
 net/mac80211/iface.c      |    2 +-
 net/mac80211/sta_info.c   |    2 ++
 net/mac80211/sta_info.h   |    3 +++
 net/mac80211/tx.c         |    4 +++-
 net/mac80211/wme.c        |   34 +++++++++++++++++++++++++++++++++-
 8 files changed, 92 insertions(+), 13 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5ce7ce7..b6cc3e33 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3624,9 +3624,14 @@ enum ieee80211_reconfig_type {
  * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available.
  *     Statistics should be cumulative, currently no way to reset is provided.
  *
- * @set_noack_tid_bitmap: Set NoAck policy TID bitmap for a virtual interface.
- *     Drivers mplementing this callback must take care of setting NoAck policy
- *     in QOS control field based on the configured TID bitmap.
+ * @set_noack_tid_bitmap: Set NoAck policy TID bitmap. Apply the TID NoAck
+ *     configuration for a particular station when @sta is non-NULL. NoAck
+ *     policy is set to default for a peer when noack_map is -1 for the peer.
+ *     The default NoAck policy for a peer is using netdev NoAck policy.
+ *     When @sta is NULL, apply TID NoAck configuration at virtual interface
+ *     level. Drivers mplementing this callback must take care of setting NoAck
+ *     policy in QOS control field based on the configured TID bitmap.
+ *     This callback may sleep.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -3917,7 +3922,8 @@ struct ieee80211_ops {
                                       struct cfg80211_ftm_responder_stats 
*ftm_stats);
 
        int (*set_noack_tid_bitmap)(struct ieee80211_hw *hw,
-                                   struct ieee80211_vif *vif, int noack_map);
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_sta *sta, int noack_map);
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7a7e423..02e6d49 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -344,18 +344,51 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
                                  int 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 (!sdata->local->ops->set_noack_tid_bitmap) {
-               ieee80211_check_fast_xmit_iface(sdata);
-               return 0;
+               if (!sdata->local->ops->set_noack_tid_bitmap) {
+                       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 (!sdata->local->ops->set_noack_tid_bitmap) {
+               ieee80211_check_fast_xmit(sta);
+               mutex_unlock(&sdata->local->sta_mtx);
                return 0;
+       }
+
+       ret = drv_set_noack_tid_bitmap(sdata->local, sdata,
+                                      &sta->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 d705938..ed9bd59 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1280,6 +1280,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 ieee80211_sta *sta,
                                           int noack_map)
 {
        int ret;
@@ -1293,7 +1294,7 @@ static inline int drv_set_noack_tid_bitmap(struct 
ieee80211_local *local,
 
        trace_drv_set_noack_tid_bitmap(local, sdata, noack_map);
        ret = local->ops->set_noack_tid_bitmap(&local->hw, &sdata->vif,
-                                              noack_map);
+                                              sta, noack_map);
        trace_drv_return_int(local, ret);
 
        return ret;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 06106f2..4999977 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -635,7 +635,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.c b/net/mac80211/sta_info.c
index fb8c225..d2ea8ee 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -606,6 +606,8 @@ static int sta_info_insert_finish(struct sta_info *sta) 
__acquires(RCU)
        cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
        kfree(sinfo);
 
+       sta->noack_map = -1;
+
        sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
 
        /* move reference to rcu-protected */
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9a04327..863601a 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -583,6 +583,9 @@ struct sta_info {
 
        struct cfg80211_chan_def tdls_chandef;
 
+       /* TID bitmap for station's NoAck policy */
+       int noack_map;
+
        /* keep last! */
        struct ieee80211_sta sta;
 };
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d744c4b..b57cd1f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2872,7 +2872,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
            test_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT))
                goto out;
 
-       if (sdata->noack_map && !local->ops->set_noack_tid_bitmap)
+       if (((sta->noack_map == -1 && sdata->noack_map) ||
+            (sta->noack_map != -1 && sta->noack_map)) &&
+           !local->ops->set_noack_tid_bitmap)
                goto out;
 
        /* fast-xmit doesn't handle fragmentation at all */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 11c14b9..b1722b8 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
+ */
+int ieee80211_get_noack_map(struct ieee80211_sub_if_data *sdata, const u8 *mac)
+{
+       struct sta_info *sta;
+       int 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 == -1)
+               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) ||
            (!sdata->local->ops->set_noack_tid_bitmap &&
-           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;
        }
-- 
1.7.9.5

Reply via email to