* [PATCH wireless-next v4 1/4] wifi: nl80211/cfg80211: rename probe_client to probe_peer
2026-06-08 9:07 [PATCH wireless-next v4 0/4] wifi: nl80211: introduce PROBE_PEER for AP and STA Priyansha Tiwari
@ 2026-06-08 9:07 ` Priyansha Tiwari
2026-06-08 9:07 ` [PATCH wireless-next v4 2/4] wifi: cfg80211/nl80211: add STA-mode peer probing Priyansha Tiwari
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Priyansha Tiwari @ 2026-06-08 9:07 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, quic_drohan, veerendranath.jakkam
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
Rename NL80211_CMD_PROBE_CLIENT to NL80211_CMD_PROBE_PEER in the UAPI
enum and retain NL80211_CMD_PROBE_CLIENT as a compatibility alias.
Rename the .probe_client cfg80211_ops callback to .probe_peer and
update all in-tree users (wil6210, mwifiex) and mac80211 so the
tree continues to build after this change.
Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 8 ++++----
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 8 ++++----
include/net/cfg80211.h | 6 +++---
include/uapi/linux/nl80211.h | 5 +++--
net/mac80211/cfg.c | 6 +++---
net/wireless/nl80211.c | 17 ++++++++---------
net/wireless/rdev-ops.h | 10 +++++-----
net/wireless/trace.h | 2 +-
8 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index d6ef92cfcbaf..a85ff2a4316b 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -2379,9 +2379,9 @@ void wil_probe_client_flush(struct wil6210_vif *vif)
mutex_unlock(&vif->probe_client_mutex);
}
-static int wil_cfg80211_probe_client(struct wiphy *wiphy,
- struct net_device *dev,
- const u8 *peer, u64 *cookie)
+static int wil_cfg80211_probe_peer(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *peer, u64 *cookie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = ndev_to_vif(dev);
@@ -2660,7 +2660,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
.add_station = wil_cfg80211_add_station,
.del_station = wil_cfg80211_del_station,
.change_station = wil_cfg80211_change_station,
- .probe_client = wil_cfg80211_probe_client,
+ .probe_peer = wil_cfg80211_probe_peer,
.change_bss = wil_cfg80211_change_bss,
/* P2P device */
.start_p2p_device = wil_cfg80211_start_p2p_device,
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index c9daf893472f..99d96088e364 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4558,9 +4558,9 @@ mwifiex_cfg80211_disassociate(struct wiphy *wiphy,
}
static int
-mwifiex_cfg80211_probe_client(struct wiphy *wiphy,
- struct net_device *dev, const u8 *peer,
- u64 *cookie)
+mwifiex_cfg80211_probe_peer(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *peer,
+ u64 *cookie)
{
/* hostapd looks for NL80211_CMD_PROBE_CLIENT support; otherwise,
* it requires monitor-mode support (which mwifiex doesn't support).
@@ -4726,7 +4726,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
ops->disassoc = mwifiex_cfg80211_disassociate;
ops->disconnect = NULL;
ops->connect = NULL;
- ops->probe_client = mwifiex_cfg80211_probe_client;
+ ops->probe_peer = mwifiex_cfg80211_probe_peer;
}
wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ddcf559430dd..7f30588ff52a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5076,7 +5076,7 @@ struct mgmt_frame_regs {
* @tdls_mgmt: Transmit a TDLS management frame.
* @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
*
- * @probe_client: probe an associated client, must return a cookie that it
+ * @probe_peer: 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.
@@ -5478,8 +5478,8 @@ struct cfg80211_ops {
int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, enum nl80211_tdls_operation oper);
- int (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
- const u8 *peer, u64 *cookie);
+ int (*probe_peer)(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u64 *cookie);
int (*set_noack_map)(struct wiphy *wiphy,
struct net_device *dev,
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9998f6c0a665..d1907dd12a80 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -922,7 +922,7 @@
* and wasn't already in a 4-addr VLAN. The event will be sent similarly
* to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
*
- * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ * @NL80211_CMD_PROBE_PEER: Probe an associated station on an AP interface
* by sending a null data frame to it and reporting when the frame is
* acknowledged. This is used to allow timing out inactive clients. Uses
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
@@ -1558,7 +1558,7 @@ enum nl80211_commands {
NL80211_CMD_UNEXPECTED_FRAME,
- NL80211_CMD_PROBE_CLIENT,
+ NL80211_CMD_PROBE_PEER,
NL80211_CMD_REGISTER_BEACONS,
@@ -1729,6 +1729,7 @@ enum nl80211_commands {
#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
+#define NL80211_CMD_PROBE_CLIENT NL80211_CMD_PROBE_PEER
/**
* enum nl80211_attrs - nl80211 netlink attributes
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 0b1291ff7a2c..f948b1331e3e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4915,8 +4915,8 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
return 0;
}
-static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
- const u8 *peer, u64 *cookie)
+static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@@ -6026,7 +6026,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.tdls_mgmt = ieee80211_tdls_mgmt,
.tdls_channel_switch = ieee80211_tdls_channel_switch,
.tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
- .probe_client = ieee80211_probe_client,
+ .probe_peer = ieee80211_probe_peer,
.set_noack_map = ieee80211_set_noack_map,
#ifdef CONFIG_PM
.set_wakeup = ieee80211_set_wakeup,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cd72f187a606..5d51dc8c09a2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2432,7 +2432,7 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
}
if (rdev->wiphy.max_sched_scan_reqs)
CMD(sched_scan_start, START_SCHED_SCAN);
- CMD(probe_client, PROBE_CLIENT);
+ CMD(probe_peer, PROBE_PEER);
CMD(set_noack_map, SET_NOACK_MAP);
if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
i++;
@@ -16114,8 +16114,7 @@ static int nl80211_register_unexpected_frame(struct sk_buff *skb,
return 0;
}
-static int nl80211_probe_client(struct sk_buff *skb,
- struct genl_info *info)
+static int nl80211_probe_peer(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];
@@ -16133,7 +16132,7 @@ static int nl80211_probe_client(struct sk_buff *skb,
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
- if (!rdev->ops->probe_client)
+ if (!rdev->ops->probe_peer)
return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -16141,7 +16140,7 @@ static int nl80211_probe_client(struct sk_buff *skb,
return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
- NL80211_CMD_PROBE_CLIENT);
+ NL80211_CMD_PROBE_PEER);
if (!hdr) {
err = -ENOBUFS;
goto free_msg;
@@ -16149,7 +16148,7 @@ static int nl80211_probe_client(struct sk_buff *skb,
addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- err = rdev_probe_client(rdev, dev, addr, &cookie);
+ err = rdev_probe_peer(rdev, dev, addr, &cookie);
if (err)
goto free_msg;
@@ -19997,9 +19996,9 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV),
},
{
- .cmd = NL80211_CMD_PROBE_CLIENT,
+ .cmd = NL80211_CMD_PROBE_PEER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .doit = nl80211_probe_client,
+ .doit = nl80211_probe_peer,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
},
@@ -22567,7 +22566,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
if (!msg)
return;
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_PEER);
if (!hdr) {
nlmsg_free(msg);
return;
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 63c26e8b1139..6c3bad8b2d6f 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -948,13 +948,13 @@ static inline int rdev_tdls_oper(struct cfg80211_registered_device *rdev,
return ret;
}
-static inline int rdev_probe_client(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *peer,
- u64 *cookie)
+static inline int rdev_probe_peer(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *peer,
+ u64 *cookie)
{
int ret;
- trace_rdev_probe_client(&rdev->wiphy, dev, peer);
- ret = rdev->ops->probe_client(&rdev->wiphy, dev, peer, cookie);
+ trace_rdev_probe_peer(&rdev->wiphy, dev, peer);
+ ret = rdev->ops->probe_peer(&rdev->wiphy, dev, peer, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 94944f2a39a4..8c2a91b85c39 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2132,7 +2132,7 @@ DECLARE_EVENT_CLASS(rdev_pmksa,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->bssid)
);
-TRACE_EVENT(rdev_probe_client,
+TRACE_EVENT(rdev_probe_peer,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const u8 *peer),
TP_ARGS(wiphy, netdev, peer),
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH wireless-next v4 2/4] wifi: cfg80211/nl80211: add STA-mode peer probing
2026-06-08 9:07 [PATCH wireless-next v4 0/4] wifi: nl80211: introduce PROBE_PEER for AP and STA Priyansha Tiwari
2026-06-08 9:07 ` [PATCH wireless-next v4 1/4] wifi: nl80211/cfg80211: rename probe_client to probe_peer Priyansha Tiwari
@ 2026-06-08 9:07 ` Priyansha Tiwari
2026-06-08 9:07 ` [PATCH wireless-next v4 3/4] wifi: mac80211: implement " Priyansha Tiwari
2026-06-08 9:07 ` [PATCH wireless-next v4 4/4] wifi: mac80211_hwsim: report TX status link_id Priyansha Tiwari
3 siblings, 0 replies; 6+ messages in thread
From: Priyansha Tiwari @ 2026-06-08 9:07 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, quic_drohan, veerendranath.jakkam
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
Add NL80211_EXT_FEATURE_PROBE_AP to allow drivers to advertise
support for probing the associated AP from STA/P2P-client mode.
Extend nl80211_probe_peer() to accept STA/P2P-client interfaces
when the driver advertises NL80211_EXT_FEATURE_PROBE_AP; in that
case the MAC attribute must be omitted (the peer is implied by
the association).
Update cfg80211_probe_status() to accept an optional peer address
and a link_id parameter (-1 for non-MLO), and include
NL80211_ATTR_MLO_LINK_ID in the event when link_id >= 0.
Update all callers.
Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 2 +-
include/net/cfg80211.h | 14 +++---
include/uapi/linux/nl80211.h | 20 +++++---
net/mac80211/status.c | 2 +-
net/wireless/nl80211.c | 52 ++++++++++++++-------
5 files changed, 59 insertions(+), 31 deletions(-)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index a85ff2a4316b..5f2bd9a31faf 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -2326,7 +2326,7 @@ static void wil_probe_client_handle(struct wil6210_priv *wil,
*/
bool alive = (sta->status == wil_sta_connected);
- cfg80211_probe_status(ndev, sta->addr, req->cookie, alive,
+ cfg80211_probe_status(ndev, sta->addr, req->cookie, -1, alive,
0, false, GFP_KERNEL);
}
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7f30588ff52a..73cdedfdb9ad 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5076,8 +5076,8 @@ struct mgmt_frame_regs {
* @tdls_mgmt: Transmit a TDLS management frame.
* @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
*
- * @probe_peer: probe an associated client, must return a cookie that it
- * later passes to cfg80211_probe_status().
+ * @probe_peer: probe a connected peer (AP: STA MAC required; STA: no MAC),
+ * must return a cookie that is later passed to cfg80211_probe_status().
*
* @set_noack_map: Set the NoAck Map for the TIDs.
*
@@ -9838,15 +9838,17 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, const u8 *addr,
/**
* cfg80211_probe_status - notify userspace about probe status
* @dev: the device the probe was sent on
- * @addr: the address of the peer
- * @cookie: the cookie filled in @probe_client previously
+ * @peer: The peer MAC address (or MLD address for MLO) or %NULL if not
+ * applicable (e.g. for STA/P2P-client)
+ * @cookie: the cookie filled in @probe_peer previously
+ * @link_id: The link ID on which the probe was sent (or -1 for non-MLO)
* @acked: indicates whether probe was acked or not
* @ack_signal: signal strength (in dBm) of the ACK frame.
* @is_valid_ack_signal: indicates the ack_signal is valid or not.
* @gfp: allocation flags
*/
-void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
- u64 cookie, bool acked, s32 ack_signal,
+void cfg80211_probe_status(struct net_device *dev, const u8 *peer, u64 cookie,
+ int link_id, bool acked, s32 ack_signal,
bool is_valid_ack_signal, gfp_t gfp);
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d1907dd12a80..6b8071606e6f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -922,13 +922,15 @@
* and wasn't already in a 4-addr VLAN. The event will be sent similarly
* to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
*
- * @NL80211_CMD_PROBE_PEER: Probe an associated station on an AP interface
- * by sending a null data frame to it and reporting when the frame is
- * acknowledged. This is used to allow timing out inactive clients. Uses
- * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
- * direct reply with an %NL80211_ATTR_COOKIE that is later used to match
- * up the event with the request. The event includes the same data and
- * has %NL80211_ATTR_ACK set if the frame was ACKed.
+ * @NL80211_CMD_PROBE_PEER: Probe a connected peer by sending a null data
+ * frame and reporting when the frame is acknowledged.
+ * In AP/GO mode, %NL80211_ATTR_MAC is required to identify the client.
+ * In STA/P2P-client mode, %NL80211_ATTR_MAC must be omitted (the AP is
+ * implied); the driver must advertise %NL80211_EXT_FEATURE_PROBE_AP.
+ * The command returns a direct reply with an %NL80211_ATTR_COOKIE that
+ * is later used to match up the event with the request. The event
+ * includes the same data and has %NL80211_ATTR_ACK set if the frame
+ * was ACKed.
*
* @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
* other BSSes when any interfaces are in AP mode. This helps implement
@@ -7086,6 +7088,9 @@ enum nl80211_feature_flags {
* LTF key seed via %NL80211_KEY_LTF_SEED. The seed is used to generate
* secure LTF keys for secure LTF measurement sessions.
*
+ * @NL80211_EXT_FEATURE_PROBE_AP: Driver supports probing the associated AP
+ * in STA mode using @NL80211_CMD_PROBE_PEER.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -7167,6 +7172,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_IEEE8021X_AUTH,
NL80211_EXT_FEATURE_ROC_ADDR_FILTER,
NL80211_EXT_FEATURE_SET_KEY_LTF_SEED,
+ NL80211_EXT_FEATURE_PROBE_AP,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 8716eda8317d..1bb622d06acf 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -655,7 +655,7 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
GFP_ATOMIC);
else if (ieee80211_is_any_nullfunc(hdr->frame_control))
cfg80211_probe_status(sdata->dev, hdr->addr1,
- cookie, acked,
+ cookie, -1, acked,
info->status.ack_signal,
is_valid_ack_signal,
GFP_ATOMIC);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5d51dc8c09a2..bb03ecace4a8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -16121,16 +16121,32 @@ static int nl80211_probe_peer(struct sk_buff *skb, struct genl_info *info)
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct sk_buff *msg;
void *hdr;
- const u8 *addr;
+ const u8 *addr = NULL;
u64 cookie;
int err;
- if (wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO)
+ /* Allow in AP, STA, and their P2P counterparts */
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+ addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PROBE_AP))
+ return -EOPNOTSUPP;
+ if (!wdev->connected)
+ return -ENOLINK;
+ /* STA/P2P-client probes the currently associated AP/GO. */
+ if (info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+ break;
+ default:
return -EOPNOTSUPP;
-
- if (!info->attrs[NL80211_ATTR_MAC])
- return -EINVAL;
+ }
if (!rdev->ops->probe_peer)
return -EOPNOTSUPP;
@@ -16146,8 +16162,6 @@ static int nl80211_probe_peer(struct sk_buff *skb, struct genl_info *info)
goto free_msg;
}
- addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-
err = rdev_probe_peer(rdev, dev, addr, &cookie);
if (err)
goto free_msg;
@@ -22550,8 +22564,8 @@ void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
}
EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify);
-void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
- u64 cookie, bool acked, s32 ack_signal,
+void cfg80211_probe_status(struct net_device *dev, const u8 *peer, u64 cookie,
+ int link_id, bool acked, s32 ack_signal,
bool is_valid_ack_signal, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -22559,7 +22573,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
struct sk_buff *msg;
void *hdr;
- trace_cfg80211_probe_status(dev, addr, cookie, acked);
+ trace_cfg80211_probe_status(dev, peer, cookie, acked);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
@@ -22574,12 +22588,18 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ (peer && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) ||
nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
- NL80211_ATTR_PAD) ||
- (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
- (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL,
- ack_signal)))
+ NL80211_ATTR_PAD))
+ goto nla_put_failure;
+
+ if (link_id >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
+ goto nla_put_failure;
+
+ if ((acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
+ (is_valid_ack_signal &&
+ nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL, ack_signal)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH wireless-next v4 3/4] wifi: mac80211: implement STA-mode peer probing
2026-06-08 9:07 [PATCH wireless-next v4 0/4] wifi: nl80211: introduce PROBE_PEER for AP and STA Priyansha Tiwari
2026-06-08 9:07 ` [PATCH wireless-next v4 1/4] wifi: nl80211/cfg80211: rename probe_client to probe_peer Priyansha Tiwari
2026-06-08 9:07 ` [PATCH wireless-next v4 2/4] wifi: cfg80211/nl80211: add STA-mode peer probing Priyansha Tiwari
@ 2026-06-08 9:07 ` Priyansha Tiwari
2026-06-10 6:57 ` Johannes Berg
2026-06-08 9:07 ` [PATCH wireless-next v4 4/4] wifi: mac80211_hwsim: report TX status link_id Priyansha Tiwari
3 siblings, 1 reply; 6+ messages in thread
From: Priyansha Tiwari @ 2026-06-08 9:07 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, quic_drohan, veerendranath.jakkam
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
Add STA/P2P-client support to ieee80211_probe_peer(): when called
for a station interface, send a null-data frame (TODS) to the
associated AP and report the ACK via cfg80211_probe_status().
For MLO connections the driver/firmware selects the link
(IEEE80211_LINK_UNSPECIFIED); for non-MLO the single link is used.
Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
---
include/net/mac80211.h | 2 +-
net/mac80211/cfg.c | 152 +++++++++++++++++++++++------------------
net/mac80211/status.c | 5 +-
3 files changed, 89 insertions(+), 70 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4fb579805e0f..6df439ef9807 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1396,7 +1396,7 @@ struct ieee80211_tx_info {
u8 pad;
u16 tx_time;
u8 flags;
- u8 pad2;
+ u8 link_valid:1, link_id:4;
void *status_driver_data[16 / sizeof(void *)];
} status;
struct {
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f948b1331e3e..977e2c75b575 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4922,101 +4922,121 @@ static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct ieee80211_qos_hdr *nullfunc;
struct sk_buff *skb;
- int size = sizeof(*nullfunc);
__le16 fc;
- bool qos;
+ bool qos, fromds;
+ struct ieee80211_bss_conf *conf;
struct ieee80211_tx_info *info;
struct sta_info *sta;
struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_bss_conf *conf;
enum nl80211_band band;
- u8 link_id;
+ const u8 *peer_addr;
+ const u8 *src_addr;
+ int link_id;
+ int size;
int ret;
/* the lock is needed to assign the cookie later */
lockdep_assert_wiphy(local->hw.wiphy);
- rcu_read_lock();
- sta = sta_info_get_bss(sdata, peer);
- if (!sta) {
- ret = -ENOLINK;
- goto unlock;
- }
-
- qos = sta->sta.wme;
-
- if (ieee80211_vif_is_mld(&sdata->vif)) {
- if (sta->sta.mlo) {
- link_id = IEEE80211_LINK_UNSPECIFIED;
- } else {
- /*
- * For non-MLO clients connected to an AP MLD, band
- * information is not used; instead, sta->deflink is
- * used to send packets.
- */
- link_id = sta->deflink.link_id;
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ sta = sta_info_get_bss(sdata, peer);
+ if (!sta)
+ return -ENOLINK;
- conf = rcu_dereference(sdata->vif.link_conf[link_id]);
+ qos = sta->sta.wme;
+ peer_addr = sta->sta.addr;
- if (unlikely(!conf)) {
- ret = -ENOLINK;
- goto unlock;
+ if (ieee80211_vif_is_mld(&sdata->vif)) {
+ if (sta->sta.mlo) {
+ link_id = IEEE80211_LINK_UNSPECIFIED;
+ src_addr = sdata->vif.addr;
+ } else {
+ /*
+ * For non-MLO clients connected to an AP MLD,
+ * use the link address for the client's link.
+ */
+ link_id = sta->deflink.link_id;
+ conf = wiphy_dereference(local->hw.wiphy,
+ sdata->vif.link_conf[link_id]);
+ if (unlikely(!conf))
+ return -ENOLINK;
+ src_addr = conf->addr;
}
+ /* MLD transmissions must not rely on the band */
+ band = 0;
+ } else {
+ chanctx_conf = wiphy_dereference(local->hw.wiphy,
+ sdata->vif.bss_conf.chanctx_conf);
+ if (WARN_ON(!chanctx_conf))
+ return -EINVAL;
+ band = chanctx_conf->def.chan->band;
+ link_id = 0;
+ src_addr = sdata->vif.addr;
}
- /* MLD transmissions must not rely on the band */
- band = 0;
- } else {
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
- if (WARN_ON(!chanctx_conf)) {
- ret = -EINVAL;
- goto unlock;
+ fromds = true;
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ link_id = IEEE80211_LINK_UNSPECIFIED;
+ peer_addr = sdata->vif.cfg.ap_addr;
+ src_addr = sdata->vif.addr;
+ if (!ieee80211_vif_is_mld(&sdata->vif)) {
+ chanctx_conf = wiphy_dereference(local->hw.wiphy,
+ sdata->vif.bss_conf.chanctx_conf);
+ if (WARN_ON(!chanctx_conf))
+ return -EINVAL;
+ band = chanctx_conf->def.chan->band;
+ } else {
+ band = 0;
}
- band = chanctx_conf->def.chan->band;
- link_id = 0;
+ sta = sta_info_get(sdata, peer_addr);
+ if (!sta)
+ return -ENOLINK;
+ qos = sta->sta.wme;
+ fromds = false;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
}
- if (qos) {
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_QOS_NULLFUNC |
- IEEE80211_FCTL_FROMDS);
- } else {
+ size = sizeof(*nullfunc);
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ (qos ? IEEE80211_STYPE_QOS_NULLFUNC
+ : IEEE80211_STYPE_NULLFUNC) |
+ (fromds ? IEEE80211_FCTL_FROMDS : IEEE80211_FCTL_TODS));
+ if (!qos)
size -= 2;
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_NULLFUNC |
- IEEE80211_FCTL_FROMDS);
- }
skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
- if (!skb) {
- ret = -ENOMEM;
- goto unlock;
- }
+ if (!skb)
+ return -ENOMEM;
skb->dev = dev;
-
skb_reserve(skb, local->hw.extra_tx_headroom);
nullfunc = skb_put(skb, size);
+ memset(nullfunc, 0, size);
nullfunc->frame_control = fc;
- nullfunc->duration_id = 0;
- memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
- if (ieee80211_vif_is_mld(&sdata->vif) && !sta->sta.mlo) {
- memcpy(nullfunc->addr2, conf->addr, ETH_ALEN);
- memcpy(nullfunc->addr3, conf->addr, ETH_ALEN);
- } else {
- memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
- memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
- }
- nullfunc->seq_ctrl = 0;
- info = IEEE80211_SKB_CB(skb);
+ memcpy(nullfunc->addr1, peer_addr, ETH_ALEN);
+ memcpy(nullfunc->addr2, src_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, fromds ? src_addr : peer_addr, ETH_ALEN);
+ info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_NL80211_FRAME_TX;
info->band = band;
-
info->control.flags |= u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK);
+ if (link_id != IEEE80211_LINK_UNSPECIFIED) {
+ info->status.link_valid = 1;
+ info->status.link_id = link_id;
+ }
+
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
skb->priority = 7;
if (qos)
@@ -5025,18 +5045,14 @@ static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
ret = ieee80211_attach_ack_skb(local, skb, cookie, GFP_ATOMIC);
if (ret) {
kfree_skb(skb);
- goto unlock;
+ return ret;
}
local_bh_disable();
ieee80211_xmit(sdata, sta, skb);
local_bh_enable();
- ret = 0;
-unlock:
- rcu_read_unlock();
-
- return ret;
+ return 0;
}
static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 1bb622d06acf..f80496445f94 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -655,7 +655,10 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
GFP_ATOMIC);
else if (ieee80211_is_any_nullfunc(hdr->frame_control))
cfg80211_probe_status(sdata->dev, hdr->addr1,
- cookie, -1, acked,
+ cookie,
+ info->status.link_valid ?
+ info->status.link_id : -1,
+ acked,
info->status.ack_signal,
is_valid_ack_signal,
GFP_ATOMIC);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH wireless-next v4 3/4] wifi: mac80211: implement STA-mode peer probing
2026-06-08 9:07 ` [PATCH wireless-next v4 3/4] wifi: mac80211: implement " Priyansha Tiwari
@ 2026-06-10 6:57 ` Johannes Berg
0 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2026-06-10 6:57 UTC (permalink / raw)
To: Priyansha Tiwari; +Cc: linux-wireless, quic_drohan, veerendranath.jakkam
Hi,
> + const u8 *peer_addr;
That seems vaguely confusing when we already have "peer", maybe you
should call this dst_addr to go with src_addr.
> /* the lock is needed to assign the cookie later */
> lockdep_assert_wiphy(local->hw.wiphy);
>
> - rcu_read_lock();
> - sta = sta_info_get_bss(sdata, peer);
> - if (!sta) {
> - ret = -ENOLINK;
> - goto unlock;
> - }
> -
> - qos = sta->sta.wme;
> -
> - if (ieee80211_vif_is_mld(&sdata->vif)) {
> - if (sta->sta.mlo) {
> - link_id = IEEE80211_LINK_UNSPECIFIED;
> - } else {
> - /*
> - * For non-MLO clients connected to an AP MLD, band
> - * information is not used; instead, sta->deflink is
> - * used to send packets.
> - */
> - link_id = sta->deflink.link_id;
> + switch (sdata->vif.type) {
> + case NL80211_IFTYPE_AP:
> + case NL80211_IFTYPE_P2P_GO:
> + sta = sta_info_get_bss(sdata, peer);
> + if (!sta)
> + return -ENOLINK;
I don't really understand why you move a bunch of the per-STA handling
into the switch?
> + qos = sta->sta.wme;
This is definitely in all the branches, and must be there. Why not pull
it out?
> + fromds = true;
> + break;
> +
> + case NL80211_IFTYPE_STATION:
(nit: spurious blank line)
> + case NL80211_IFTYPE_P2P_CLIENT:
Both of the P2P cases aren't needed here and are just confusing.
> + link_id = IEEE80211_LINK_UNSPECIFIED;
> + peer_addr = sdata->vif.cfg.ap_addr;
> + src_addr = sdata->vif.addr;
> + if (!ieee80211_vif_is_mld(&sdata->vif)) {
> + chanctx_conf = wiphy_dereference(local->hw.wiphy,
> + sdata->vif.bss_conf.chanctx_conf);
> + if (WARN_ON(!chanctx_conf))
> + return -EINVAL;
(that WARN_ON could perhaps be triggered since you didn't check for the
STA first?)
> + band = chanctx_conf->def.chan->band;
> + } else {
> + band = 0;
> }
> - band = chanctx_conf->def.chan->band;
> - link_id = 0;
> + sta = sta_info_get(sdata, peer_addr);
> + if (!sta)
> + return -ENOLINK;
> + qos = sta->sta.wme;
At the very least you could pull out 'qos = sta->sta.wme', but I wonder
if you could pull out more of the sta lookup too by just saying
if (vif.type == NL80211_IFTYPE_STATION)
peer = sdata->vif.cfg.ap_addr;
and then leaving more of the current behaviour intact. Even the MLO link
thing could be left since it won't actually be able to be used since the
AP will be MLO/non-MLO with the vif, unlike in AP mode.
IOW, it feels like with that you should get away with far less
difference between AP and client, perhaps no other than this and the DS
bits.
johannes
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH wireless-next v4 4/4] wifi: mac80211_hwsim: report TX status link_id
2026-06-08 9:07 [PATCH wireless-next v4 0/4] wifi: nl80211: introduce PROBE_PEER for AP and STA Priyansha Tiwari
` (2 preceding siblings ...)
2026-06-08 9:07 ` [PATCH wireless-next v4 3/4] wifi: mac80211: implement " Priyansha Tiwari
@ 2026-06-08 9:07 ` Priyansha Tiwari
3 siblings, 0 replies; 6+ messages in thread
From: Priyansha Tiwari @ 2026-06-08 9:07 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, quic_drohan, veerendranath.jakkam
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
Populate link_valid/link_id in mac80211_hwsim TX status so the
transmitted link is reported to mac80211.
Set the link information in both the direct TX status path and the
wmediumd/netlink TX status path.
Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
---
.../wireless/virtual/mac80211_hwsim_main.c | 43 +++++++++++++++++--
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index dc9775cd9f54..4ad39cdfb7a7 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -2077,6 +2077,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
bool ack, unicast_data;
enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
u32 _portid, i;
+ int tx_link_id = -1;
if (WARN_ON(skb->len < 10)) {
/* Should not happen; just a sanity check for addr1 use */
@@ -2134,6 +2135,9 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
hdr, &link_sta);
}
+ if (bss_conf)
+ tx_link_id = bss_conf->link_id;
+
if (unlikely(!bss_conf)) {
/* if it's an MLO STA, it might have deactivated all
* links temporarily - but we don't handle real PS in
@@ -2245,6 +2249,12 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
txi->flags |= IEEE80211_TX_STAT_ACK;
+
+ if (tx_link_id >= 0) {
+ txi->status.link_valid = 1;
+ txi->status.link_id = tx_link_id;
+ }
+
ieee80211_tx_status_irqsafe(hw, skb);
}
@@ -6037,6 +6047,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PROBE_AP);
for (i = 0; i < ARRAY_SIZE(data->link_data); i++) {
hrtimer_setup(&data->link_data[i].beacon_timer, mac80211_hwsim_beacon,
@@ -6262,6 +6273,27 @@ static void hwsim_register_wmediumd(struct net *net, u32 portid)
spin_unlock_bh(&hwsim_radio_lock);
}
+static int mac80211_hwsim_get_link_id(struct ieee80211_vif *vif,
+ struct ieee80211_hdr *hdr)
+{
+ int i;
+
+ if (!vif || !ieee80211_vif_is_mld(vif))
+ return -1;
+
+ for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
+ struct ieee80211_bss_conf *link_conf;
+
+ link_conf = rcu_dereference(vif->link_conf[i]);
+ if (!link_conf)
+ continue;
+ if (ether_addr_equal(link_conf->addr, hdr->addr2))
+ return i;
+ }
+
+ return -1;
+}
+
static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
struct genl_info *info)
{
@@ -6342,13 +6374,18 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ i = mac80211_hwsim_get_link_id(txi->control.vif, hdr);
+ if (i >= 0) {
+ txi->status.link_valid = 1;
+ txi->status.link_id = i;
+ }
+
if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) &&
(hwsim_flags & HWSIM_TX_STAT_ACK)) {
- if (skb->len >= 16) {
- hdr = (struct ieee80211_hdr *) skb->data;
+ if (skb->len >= 16)
mac80211_hwsim_monitor_ack(data2->channel,
hdr->addr2);
- }
txi->flags |= IEEE80211_TX_STAT_ACK;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread