@@ -3086,7 +3086,15 @@ struct cfg80211_ftm_responder_stats {
* @probe_client: probe an associated client, must return a cookie that it
* later passes to cfg80211_probe_status().
*
- * @set_noack_map: Set the NoAck Map for the TIDs.
+ * @set_noack_map: Set the NoAck Map for the TIDs. When peer is not %NULL NoAck
+ * map will be applied for that particular peer. A NoAck map value of -1
+ * for non-%NULL peer would indicate that the peer's current NoAck
+ * configuration should be reset to the default one. The default NoAck
+ * configuration for a peer uses the currently configured NoAck setting of
+ * netdev. When peer is %NULL NoAck map will be applied for all the
+ * connected stations on the netdev which have default NoAck policy
+ * configuration. Default NoAck configuration should be used for newly
+ * connected stations.
*
* @get_channel: Get the current operating channel for the virtual interface.
* For monitor interfaces, it should return %NULL unless there's a single
@@ -3403,7 +3411,7 @@ struct cfg80211_ops {
int (*set_noack_map)(struct wiphy *wiphy,
struct net_device *dev,
- u16 noack_map);
+ const u8 *peer, int noack_map);
int (*get_channel)(struct wiphy *wiphy,
struct wireless_dev *wdev,
@@ -3917,7 +3917,7 @@ struct ieee80211_ops {
struct cfg80211_ftm_responder_stats *ftm_stats);
int (*set_noack_tid_bitmap)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 noack_map);
+ struct ieee80211_vif *vif, int noack_map);
};
/**
@@ -788,7 +788,18 @@
* messages. Note that per PHY only one application may register.
*
* @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
- * No Acknowledgement Policy should be applied.
+ * No Acknowledgement Policy should be applied. %NL80211_ATTR_MAC is used
+ * to apply No Acknowledgement policy for a particular connected station.
+ * When the command is received without %NL80211_ATTR_NOACK_MAP for a
+ * connected station (%NL80211_ATTR_MAC), the station's current NoAck
+ * policy configuration should be reset to default. The default
+ * configuration for a peer should use the current ndev level NoAck
+ * policy configuration. Station specific NoAck policy configuration is
+ * valid only for STA's current connection, i.e. the configuration will
+ * be reset to default when the station connects back after disconnection/
+ * roaming. When user-space does not include %NL80211_ATTR_MAC, the No
+ * Acknowledgement Policy setting should be treated as per-netdev
+ * configuration.
*
* @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
* independently of the userspace SME, send this event indicating
@@ -5257,6 +5268,8 @@ enum nl80211_feature_flags {
* able to rekey an in-use key correctly. Userspace must not rekey PTK keys
* if this flag is not set. Ignoring this can leak clear text packets and/or
* freeze the connection.
+ * @NL80211_EXT_FEATURE_PER_STA_NOACK_MAP: Driver supports STA specific NoAck
+ * policy functionality.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5297,6 +5310,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
+ NL80211_EXT_FEATURE_PER_STA_NOACK_MAP,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -340,7 +340,8 @@ static void ieee80211_del_nan_func(struct wiphy *wiphy,
static int ieee80211_set_noack_map(struct wiphy *wiphy,
struct net_device *dev,
- u16 noack_map)
+ const u8 *peer,
+ int noack_map)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1280,7 +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,
- u16 noack_map)
+ int noack_map)
{
int ret;
@@ -891,7 +891,7 @@ struct ieee80211_sub_if_data {
unsigned int fragment_next;
/* TID bitmap for NoAck policy */
- u16 noack_map;
+ int noack_map;
/* bit field of ACM bits (BIT(802.1D tag)) */
u8 wmm_acm;
@@ -1885,13 +1885,13 @@ struct trace_switch_entry {
TRACE_EVENT(drv_set_noack_tid_bitmap,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- u16 noack_map),
+ int noack_map),
TP_ARGS(local, sdata, noack_map),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
- __field(u16, noack_map)
+ __field(int, noack_map)
),
TP_fast_assign(
@@ -1902,7 +1902,7 @@ struct trace_switch_entry {
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT
- ", noack_map: %u",
+ ", noack_map: %d",
LOCAL_PR_ARG, VIF_PR_ARG, __entry->noack_map
)
);
@@ -3331,17 +3331,29 @@ static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
- u16 noack_map;
+ int noack_map = -1;
+ const u8 *peer = NULL;
- if (!info->attrs[NL80211_ATTR_NOACK_MAP])
+ if (!(info->attrs[NL80211_ATTR_NOACK_MAP] ||
+ info->attrs[NL80211_ATTR_MAC]))
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_NOACK_MAP])
+ noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
+
+ if (info->attrs[NL80211_ATTR_MAC]) {
+ if (!wiphy_ext_feature_isset(
+ &rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_NOACK_MAP))
+ return -EOPNOTSUPP;
+
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ }
+
if (!rdev->ops->set_noack_map)
return -EOPNOTSUPP;
- noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
-
- return rdev_set_noack_map(rdev, dev, noack_map);
+ return rdev_set_noack_map(rdev, dev, peer, noack_map);
}
struct get_key_cookie {
@@ -908,11 +908,12 @@ static inline int rdev_probe_client(struct cfg80211_registered_device *rdev,
}
static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev,
- struct net_device *dev, u16 noack_map)
+ struct net_device *dev, const u8 *peer,
+ int noack_map)
{
int ret;
- trace_rdev_set_noack_map(&rdev->wiphy, dev, noack_map);
- ret = rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
+ trace_rdev_set_noack_map(&rdev->wiphy, dev, peer, noack_map);
+ ret = rdev->ops->set_noack_map(&rdev->wiphy, dev, peer, noack_map);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
@@ -1909,21 +1909,24 @@
);
TRACE_EVENT(rdev_set_noack_map,
- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
- u16 noack_map),
- TP_ARGS(wiphy, netdev, noack_map),
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *peer,
+ int noack_map),
+ TP_ARGS(wiphy, netdev, peer, noack_map),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
- __field(u16, noack_map)
+ MAC_ENTRY(peer)
+ __field(int, noack_map)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
+ MAC_ASSIGN(peer, peer);
__entry->noack_map = noack_map;
),
- TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", noack_map: %u",
- WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map)
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT
+ ", noack_map: %d", WIPHY_PR_ARG, NETDEV_PR_ARG,
+ MAC_PR_ARG(peer), __entry->noack_map)
);
DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel,