[PATCH wireless-next 5/5] wifi: cfg80211: support MAC address filtering in station dump for link stats

P Praneesh praneesh.p at oss.qualcomm.com
Sun Jun 7 10:59:12 PDT 2026


Currently, when userspace requests station information with
link statistics using NL80211_CMD_GET_STATION with the
NL80211_ATTR_STA_DUMP_LINK_STATS flag, the kernel uses the .doit callback
(nl80211_get_station) which sends a single netlink message. For MLO
stations with multiple links, the link statistics can be large and may
exceed the maximum netlink message size, causing the operation to fail
with -EMSGSIZE.

The .dumpit callback (nl80211_dump_station) already supports
fragmentation across multiple netlink messages, making it suitable
for handling large link statistics. However, it currently iterates over
all stations on the interface, which is inefficient when userspace only
wants information about a specific station.

Add support for MAC address filtering in nl80211_dump_station to allow
userspace to request fragmented link statistics for a specific station.
When NL80211_ATTR_MAC is present in a dump request, cache the MAC address
in the dump context and use rdev_get_station() to retrieve information for
only that station, instead of iterating over all stations with
rdev_dump_station().

This allows userspace tools (like iw) to use NL80211_CMD_GET_STATION with
NLM_F_DUMP flag to retrieve complete link statistics for a specific
station across multiple netlink messages, avoiding the message size
limitation.

Signed-off-by: P Praneesh <praneesh.p at oss.qualcomm.com>
---
 net/wireless/nl80211.c | 44 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3dba329c7eb2..209df747e53e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -56,6 +56,8 @@ struct nl80211_dump_station_ctx {
 	enum nl80211_dump_station_phase phase;
 	int link_idx;
 	bool dump_link_stats;
+	bool filter_mac;
+	u8 filter_mac_addr[ETH_ALEN];
 	u8 mac_addr[ETH_ALEN];
 	struct station_info sinfo;
 };
@@ -8618,6 +8620,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
 	struct nl80211_dump_station_ctx *ctx = cb_data->ctx;
 	struct nlattr **attrbuf = NULL;
 	int err, ret;
+	const u8 *mac_addr;
 
 	NL_ASSERT_CTX_FITS(struct nl80211_dump_station_cb);
 
@@ -8650,6 +8653,19 @@ static int nl80211_dump_station(struct sk_buff *skb,
 		ctx->link_idx = 0;
 		ctx->dump_link_stats =
 			!!attrbuf[NL80211_ATTR_STA_DUMP_LINK_STATS];
+		if (attrbuf[NL80211_ATTR_MAC]) {
+			mac_addr = nla_data(attrbuf[NL80211_ATTR_MAC]);
+			if (!is_valid_ether_addr(mac_addr)) {
+				kfree(attrbuf);
+				kfree(ctx);
+				err = -EINVAL;
+				goto out_err;
+			}
+
+			ctx->filter_mac = true;
+			memcpy(ctx->filter_mac_addr, mac_addr, ETH_ALEN);
+		}
+
 		cb_data->ctx = ctx;
 	}
 
@@ -8661,7 +8677,12 @@ static int nl80211_dump_station(struct sk_buff *skb,
 		goto out_err;
 	}
 
-	if (!rdev->ops->dump_station) {
+	if (ctx->filter_mac) {
+		if (!rdev->ops->get_station) {
+			err = -EOPNOTSUPP;
+			goto out_err;
+		}
+	} else if (!rdev->ops->dump_station) {
 		err = -EOPNOTSUPP;
 		goto out_err;
 	}
@@ -8679,8 +8700,25 @@ static int nl80211_dump_station(struct sk_buff *skb,
 				}
 			}
 
-			err = rdev_dump_station(rdev, wdev, ctx->sta_idx,
-						ctx->mac_addr, &ctx->sinfo);
+			if (ctx->filter_mac) {
+				if (ctx->sta_idx > 0) {
+					err = skb->len;
+					goto out_err_release;
+				}
+
+				err = rdev_get_station(rdev, wdev,
+						       ctx->filter_mac_addr,
+						       &ctx->sinfo);
+				if (!err)
+					memcpy(ctx->mac_addr,
+					       ctx->filter_mac_addr, ETH_ALEN);
+			} else {
+				err = rdev_dump_station(rdev, wdev,
+							ctx->sta_idx,
+							ctx->mac_addr,
+							&ctx->sinfo);
+			}
+
 			if (err == -ENOENT) {
 				err = skb->len;
 				goto out_err_release;
-- 
2.43.0




More information about the ath12k mailing list