[RFC PATCH v2 03/23] nl80211: Add MAC address filter support for remain-on-channel
Peddolla Harshavardhan Reddy
peddolla.reddy at oss.qualcomm.com
Thu Apr 2 05:24:08 PDT 2026
Currently, the remain_on_channel driver interface does not support
filtering received frames by a specific MAC address. This prevents
use cases like Proximity Ranging from listening for frames addressed
to a custom MAC address that differs from the interface address.
Add a filter_addr parameter to the remain_on_channel driver operation
and its wpa_drv_remain_on_channel() wrapper. When provided, the
nl80211 driver adds NL80211_ATTR_MAC to the remain-on-channel command
to configure hardware-level frame filtering. A new driver capability
flag WPA_DRIVER_FLAGS2_ROC_ADDR_FILTER, detected from the kernel's
NL80211_EXT_FEATURE_ROC_ADDR_FILTER, guards this behavior. All
existing callers are updated to pass NULL to maintain backward
compatibility.
Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy at oss.qualcomm.com>
---
src/drivers/driver.h | 10 +++++++++-
src/drivers/driver_nl80211.c | 27 +++++++++++++++++++++++----
src/drivers/driver_nl80211_capa.c | 3 +++
wpa_supplicant/dpp_supplicant.c | 2 +-
wpa_supplicant/driver_i.h | 5 +++--
wpa_supplicant/nan_supplicant.c | 2 +-
wpa_supplicant/offchannel.c | 4 ++--
wpa_supplicant/p2p_supplicant.c | 2 +-
8 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 1e4a3da35..268229edd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2444,6 +2444,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS2_EPPKE 0x0000000400000000ULL
/** Driver supports IEEE 802.1X authentication in Authentication frames */
#define WPA_DRIVER_FLAGS2_802_1X_AUTH 0x0000000800000000ULL
+/** Driver supports MAC address filter for remain-on-channel */
+#define WPA_DRIVER_FLAGS2_ROC_ADDR_FILTER 0x0000001000000000ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -4312,6 +4314,8 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* @freq: Frequency (in MHz) of the channel
* @duration: Duration in milliseconds
+ * @filter_addr: MAC address to filter received frames (NULL for no
+ * filter)
* Returns: 0 on success, -1 on failure
*
* This command is used to request the driver to remain awake on the
@@ -4320,6 +4324,10 @@ struct wpa_driver_ops {
* Probe Request frames may also be requested to be reported by calling
* probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
*
+ * If filter_addr is provided, the driver will configure an additional MAC
+ * address for frame filtering. i.e., this new address would be used in
+ * addition to the interface address.
+ *
* The driver may not be at the requested channel when this function
* returns, i.e., the return code is only indicating whether the
* request was accepted. The caller will need to wait until the
@@ -4330,7 +4338,7 @@ struct wpa_driver_ops {
* executed.
*/
int (*remain_on_channel)(void *priv, unsigned int freq,
- unsigned int duration);
+ unsigned int duration, const u8 *filter_addr);
/**
* cancel_remain_on_channel - Cancel remain-on-channel operation
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 52c561dfc..297f363f4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -9868,7 +9868,8 @@ static int nl80211_put_any_link_id(struct nl_msg *msg,
static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
- unsigned int duration)
+ unsigned int duration,
+ const u8 *filter_addr)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -9884,12 +9885,30 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
return -1;
}
+ /* Add MAC address filter if provided and supported */
+ if (filter_addr) {
+ if (!(drv->capa.flags2 & WPA_DRIVER_FLAGS2_ROC_ADDR_FILTER)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support ROC address filter");
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, filter_addr)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to add MAC address filter");
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
cookie = 0;
ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
if (ret == 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
- "0x%llx for freq=%u MHz duration=%u",
- (long long unsigned int) cookie, freq, duration);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remain-on-channel cookie 0x%llx for freq=%u MHz duration=%u%s",
+ (unsigned long long) cookie, freq, duration,
+ filter_addr ? " (with MAC filter)" : "");
drv->remain_on_chan_cookie = cookie;
drv->pending_remain_on_chan = 1;
return 0;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 1ee021cd9..b8bfb6613 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -586,6 +586,9 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_ROC_ADDR_FILTER))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_ROC_ADDR_FILTER;
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI))
capa->flags |= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI;
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index ab9d81593..a55d0e7ab 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1034,7 +1034,7 @@ static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
wpa_s->dpp_pending_listen_freq = lwork->freq;
if (wpa_drv_remain_on_channel(wpa_s, lwork->freq,
- wpa_s->max_remain_on_chan) < 0) {
+ wpa_s->max_remain_on_chan, NULL) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
lwork->freq);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 60eb31ca1..5a8298288 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -460,11 +460,12 @@ static inline int wpa_drv_if_remove(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_remain_on_channel(struct wpa_supplicant *wpa_s,
unsigned int freq,
- unsigned int duration)
+ unsigned int duration,
+ const u8 *filter_addr)
{
if (wpa_s->driver->remain_on_channel)
return wpa_s->driver->remain_on_channel(wpa_s->drv_priv, freq,
- duration);
+ duration, filter_addr);
return -1;
}
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 1eac1fb78..362dd75e3 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -523,7 +523,7 @@ static void wpas_nan_usd_start_listen_cb(struct wpa_radio_work *work,
duration = wpa_s->max_remain_on_chan;
wpa_printf(MSG_DEBUG, "NAN: Start listen on %u MHz for %u ms",
lwork->freq, duration);
- if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration, NULL) < 0) {
wpa_printf(MSG_DEBUG,
"NAN: Failed to request the driver to remain on channel (%u MHz) for listen",
lwork->freq);
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 9e591d7d6..688718cd7 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -124,7 +124,7 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_drv_remain_on_channel(
wpa_s, wpa_s->pending_action_freq,
- duration) < 0) {
+ duration, NULL) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
"request driver to remain on "
"channel (%u MHz) for Action Frame "
@@ -369,7 +369,7 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
wait_time += wpa_s->extra_roc_dur;
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
+ if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time, NULL) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
"to remain on channel (%u MHz) for Action "
"Frame TX", freq);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 154322f8a..b8a9d60b8 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3253,7 +3253,7 @@ static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit)
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration, NULL) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
"state", lwork->freq);
--
2.34.1
More information about the Hostap
mailing list