From: Vasanthakumar Thiagarajan <vthiagar@xxxxxxxxxxxxxx> 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 <vthiagar@xxxxxxxxxxxxxx> Signed-off-by: Tamizh chelvam <tamizhr@xxxxxxxxxxxxxx> --- 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