wifi: cfg80211/mac80211: validate radio frequency range for monitor mode

In multi-radio devices, it is possible to have an MLD AP and a monitor
interface active at the same time. In such cases, monitor mode may not
be able to specify a fixed channel and could end up capturing frames
from all radios, including those outside the intended frequency bands.

This patch adds frequency validation for monitor mode. Received frames
are now only processed if their frequency fall within the allowed ranges
of the radios specified by the interface's radio_mask.

This prevents monitor mode from capturing frames outside the supported radio.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Link: https://patch.msgid.link/700b8284e845d96654eb98431f8eeb5a81503862.1758647858.git.ryder.lee@mediatek.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Ryder Lee
2025-09-23 17:23:22 +00:00
committed by Johannes Berg
parent 428ea708b7
commit a392cde88d
3 changed files with 66 additions and 3 deletions

View File

@@ -1015,6 +1015,7 @@ const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2);
/**
* nl80211_chan_width_to_mhz - get the channel width in MHz
* @chan_width: the channel width from &enum nl80211_chan_width
@@ -6882,6 +6883,19 @@ static inline bool cfg80211_channel_is_psc(struct ieee80211_channel *chan)
return ieee80211_frequency_to_channel(chan->center_freq) % 16 == 5;
}
/**
* ieee80211_radio_freq_range_valid - Check if the radio supports the
* specified frequency range
*
* @radio: wiphy radio
* @freq: the frequency (in KHz) to be queried
* @width: the bandwidth (in KHz) to be queried
*
* Return: whether or not the given frequency range is valid for the given radio
*/
bool ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
u32 freq, u32 width);
/**
* cfg80211_radio_chandef_valid - Check if the radio supports the chandef
*

View File

@@ -763,6 +763,51 @@ ieee80211_make_monitor_skb(struct ieee80211_local *local,
return skb;
}
static bool
ieee80211_validate_monitor_radio(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local,
struct ieee80211_rx_status *status)
{
struct wiphy *wiphy = local->hw.wiphy;
int i, freq, bw;
if (!wiphy->n_radio)
return true;
switch (status->bw) {
case RATE_INFO_BW_20:
bw = 20000;
break;
case RATE_INFO_BW_40:
bw = 40000;
break;
case RATE_INFO_BW_80:
bw = 80000;
break;
case RATE_INFO_BW_160:
bw = 160000;
break;
case RATE_INFO_BW_320:
bw = 320000;
break;
default:
return false;
}
freq = MHZ_TO_KHZ(status->freq);
for (i = 0; i < wiphy->n_radio; i++) {
if (!(sdata->wdev.radio_mask & BIT(i)))
continue;
if (!ieee80211_radio_freq_range_valid(&wiphy->radio[i], freq, bw))
continue;
return true;
}
return false;
}
/*
* This function copies a received frame to all monitor interfaces and
* returns a cleaned-up SKB that no longer includes the FCS nor the
@@ -855,6 +900,10 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
chandef->chan->center_freq != status->freq)
continue;
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
!ieee80211_validate_monitor_radio(sdata, local, status))
continue;
if (!prev_sdata) {
prev_sdata = sdata;
continue;

View File

@@ -2942,9 +2942,8 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type)
}
EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa);
static bool
ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
u32 freq, u32 width)
bool ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
u32 freq, u32 width)
{
const struct wiphy_radio_freq_range *r;
int i;
@@ -2958,6 +2957,7 @@ ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
return false;
}
EXPORT_SYMBOL(ieee80211_radio_freq_range_valid);
bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
const struct cfg80211_chan_def *chandef)