]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: cfg80211: Add MAC address filter to remain_on_channel
authorPeddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
Mon, 20 Apr 2026 09:08:45 +0000 (14:38 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 5 May 2026 11:25:27 +0000 (13:25 +0200)
Currently the remain_on_channel operation does not support
filtering incoming frames by destination MAC address. This
prevents use cases such as PASN authentication in the
responder side that need to receive frames addressed to a
specific MAC during the off-channel period.

Add an rx_addr parameter to the remain_on_channel operation
callback and propagate it through the call chain from nl80211
to driver implementations. Introduce the extended feature
NL80211_EXT_FEATURE_ROC_ADDR_FILTER as a capability gate so
that cfg80211 rejects the request if the driver does not
advertise support for address filtering. Extract the address
from the NL80211_ATTR_MAC attribute when provided in the
netlink message and update the tracing infrastructure to
include the address in remain_on_channel trace events. The
rx_addr parameter is optional and can be NULL, maintaining
backward compatibility with existing drivers.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
Link: https://patch.msgid.link/20260420090856.2152905-3-peddolla.reddy@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
13 files changed:
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/microchip/wilc1000/cfg80211.c
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/mac80211/ieee80211_i.h
net/mac80211/offchannel.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/trace.h

index 739a24a6ad6761c8d571ec76a07f4e348ba9c424..cc0f2c45fc3a30d725a4d0e7d2e5632c93f8ae7d 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -3033,7 +3034,7 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy,
                                    struct wireless_dev *wdev,
                                    struct ieee80211_channel *chan,
                                    unsigned int duration,
-                                   u64 *cookie)
+                                   u64 *cookie, const u8 *rx_addr)
 {
        struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
        struct ath6kl *ar = ath6kl_priv(vif->ndev);
index 3d6e5aad48b1af02ef34e0108017467c68e5422d..d6ef92cfcbaffdc1a1c199660d90269867aa8c48 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  */
 
 #include <linux/etherdevice.h>
@@ -1734,7 +1735,7 @@ static int wil_remain_on_channel(struct wiphy *wiphy,
                                 struct wireless_dev *wdev,
                                 struct ieee80211_channel *chan,
                                 unsigned int duration,
-                                u64 *cookie)
+                                u64 *cookie, const u8 *rx_addr)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
        int rc;
index e1752a513c733d2d268f593ae143abce79ccaa44..92c16a3173288b23fb1c71e2a686f3b9fe309643 100644 (file)
@@ -970,10 +970,12 @@ exit:
  * @channel: channel to stay on.
  * @duration: time in ms to remain on channel.
  * @cookie: cookie.
+ * @rx_addr: Address to match against the destination of received frames
  */
 int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
                                struct ieee80211_channel *channel,
-                               unsigned int duration, u64 *cookie)
+                               unsigned int duration, u64 *cookie,
+                               const u8 *rx_addr)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_p2p_info *p2p = &cfg->p2p;
index d3137ebd7158251993787319ae80311427828bfc..9f3f01ade2b77063d5d33b15482cbd1f9d071eec 100644 (file)
@@ -157,7 +157,8 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
                        struct brcmf_cfg80211_vif *vif);
 int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
                                struct ieee80211_channel *channel,
-                               unsigned int duration, u64 *cookie);
+                               unsigned int duration, u64 *cookie,
+                               const u8 *rx_addr);
 int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
                                     const struct brcmf_event_msg *e,
                                     void *data);
index c9a651bdf8822a8b7c0535b6a51a5b82115241fa..c9daf893472fe28dcf176222630d6d6cb963d7a5 100644 (file)
@@ -304,7 +304,8 @@ static int
 mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
                                   struct wireless_dev *wdev,
                                   struct ieee80211_channel *chan,
-                                  unsigned int duration, u64 *cookie)
+                                  unsigned int duration, u64 *cookie,
+                                  const u8 *rx_addr)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
        int ret;
index 3a774cc44b263d92070c5c8829f3f4ce95dcfdfe..6654fce4ded84869b37983b0249d8609b1518c4a 100644 (file)
@@ -1100,7 +1100,8 @@ static void wilc_wfi_remain_on_channel_expired(struct wilc_vif *vif, u64 cookie)
 static int remain_on_channel(struct wiphy *wiphy,
                             struct wireless_dev *wdev,
                             struct ieee80211_channel *chan,
-                            unsigned int duration, u64 *cookie)
+                            unsigned int duration, u64 *cookie,
+                            const u8 *rx_addr)
 {
        int ret = 0;
        struct wilc_vif *vif = netdev_priv(wdev->netdev);
index b0a908b2ba734210abe43793a3e3e07f343dc877..897dbe325b7e5a65a650e4ee19e5389ec204da34 100644 (file)
@@ -5270,7 +5270,7 @@ struct cfg80211_ops {
                                     struct wireless_dev *wdev,
                                     struct ieee80211_channel *chan,
                                     unsigned int duration,
-                                    u64 *cookie);
+                                    u64 *cookie, const u8 *rx_addr);
        int     (*cancel_remain_on_channel)(struct wiphy *wiphy,
                                            struct wireless_dev *wdev,
                                            u64 cookie);
index e26d65c1b73795361b7814a7bc5248548aaed172..8103f2912abc50d7124afc93908499d9df01b6f7 100644 (file)
  *     to remain on the channel. This command is also used as an event to
  *     notify when the requested duration starts (it may take a while for the
  *     driver to schedule this time due to other concurrent needs for the
- *     radio).
+ *     radio). An optional attribute %NL80211_ATTR_MAC can be used to filter
+ *     incoming frames during remain-on-channel, such that frames
+ *     addressed to the specified destination MAC are reported.
  *     When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
  *     that will be included with any events pertaining to this request;
  *     the cookie is also used to cancel the request.
@@ -7040,6 +7042,12 @@ enum nl80211_feature_flags {
  *     (NL80211_CMD_AUTHENTICATE) in non-AP STA mode, as specified in
  *     "IEEE P802.11bi/D4.0, 12.16.5".
  *
+ * @NL80211_EXT_FEATURE_ROC_ADDR_FILTER: Driver supports MAC address
+ *     filtering during remain-on-channel. When %NL80211_ATTR_MAC is
+ *     provided with %NL80211_CMD_REMAIN_ON_CHANNEL, the driver will
+ *     forward frames with a matching MAC address to userspace during
+ *     the off-channel period.
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
@@ -7119,6 +7127,7 @@ enum nl80211_ext_feature_index {
        NL80211_EXT_FEATURE_EPPKE,
        NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION,
        NL80211_EXT_FEATURE_IEEE8021X_AUTH,
+       NL80211_EXT_FEATURE_ROC_ADDR_FILTER,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
index e23e347f870d0416f6b2ff29a717b3dc75f0195b..76ed7aa7d8cd535975d7df015e6af300558c6f7c 100644 (file)
@@ -2097,7 +2097,8 @@ void ieee80211_roc_purge(struct ieee80211_local *local,
                         struct ieee80211_sub_if_data *sdata);
 int ieee80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
                                struct ieee80211_channel *chan,
-                               unsigned int duration, u64 *cookie);
+                               unsigned int duration, u64 *cookie,
+                               const u8 *rx_addr);
 int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
                                       struct wireless_dev *wdev, u64 cookie);
 int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
index 10c962d2803734c27554716c274a449ff9507de3..83e4be06039e30ee2a0acd5492733babe523ef99 100644 (file)
@@ -706,7 +706,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
 int ieee80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
                                struct ieee80211_channel *chan,
-                               unsigned int duration, u64 *cookie)
+                               unsigned int duration, u64 *cookie,
+                               const u8 *rx_addr)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
        struct ieee80211_local *local = sdata->local;
index b96f2f7f67d2492b6240c1d73cc2186054a446cc..c5879056e6940e77e957f5557ffe58a5eadf6d1d 100644 (file)
@@ -14133,6 +14133,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
        unsigned int link_id = nl80211_link_id(info->attrs);
        struct wireless_dev *wdev = info->user_ptr[1];
        struct cfg80211_chan_def chandef;
+       const u8 *rx_addr = NULL;
        struct sk_buff *msg;
        void *hdr;
        u64 cookie;
@@ -14145,6 +14146,14 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
 
        duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
 
+       if (info->attrs[NL80211_ATTR_MAC])
+               rx_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       if (rx_addr &&
+           !wiphy_ext_feature_isset(wdev->wiphy,
+                                    NL80211_EXT_FEATURE_ROC_ADDR_FILTER))
+               return -EOPNOTSUPP;
+
        if (!rdev->ops->remain_on_channel ||
            !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
                return -EOPNOTSUPP;
@@ -14192,7 +14201,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
        }
 
        err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
-                                    duration, &cookie);
+                                    duration, &cookie, rx_addr);
 
        if (err)
                goto free_msg;
index bba239a068f636bc06481e70f6c848d4bf929575..d97d5c08d1359af07935f0bdf70240db1c679d1b 100644 (file)
@@ -736,12 +736,13 @@ static inline int
 rdev_remain_on_channel(struct cfg80211_registered_device *rdev,
                       struct wireless_dev *wdev,
                       struct ieee80211_channel *chan,
-                      unsigned int duration, u64 *cookie)
+                      unsigned int duration, u64 *cookie, const u8 *rx_addr)
 {
        int ret;
-       trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, duration);
+       trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, duration,
+                                    rx_addr);
        ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
-                                          duration, cookie);
+                                          duration, cookie, rx_addr);
        trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
        return ret;
 }
index eb5bedf9c92a4366414df2a25a4e175883be3f98..938fea1fe9d802dd7bd56d40bd1373720a83a8ca 100644 (file)
@@ -2155,22 +2155,26 @@ DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa,
 TRACE_EVENT(rdev_remain_on_channel,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
                 struct ieee80211_channel *chan,
-                unsigned int duration),
-       TP_ARGS(wiphy, wdev, chan, duration),
+                unsigned int duration, const u8 *rx_addr),
+       TP_ARGS(wiphy, wdev, chan, duration, rx_addr),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                WDEV_ENTRY
                CHAN_ENTRY
                __field(unsigned int, duration)
+               MAC_ENTRY(rx_addr)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                WDEV_ASSIGN;
                CHAN_ASSIGN(chan);
                __entry->duration = duration;
+               MAC_ASSIGN(rx_addr, rx_addr);
        ),
-       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", duration: %u",
-                 WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->duration)
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT
+                 ", duration: %u, %pM",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->duration,
+                 __entry->rx_addr)
 );
 
 TRACE_EVENT(rdev_return_int_cookie,