mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-29 15:44:04 +00:00
mac80211: improve single-wiphy multi-radio support
- add support for configuring allowed radios for a vif - add support for monitor mode on multiple channels Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
b2a2c28617
commit
87033c3a0b
@ -0,0 +1,122 @@
|
||||
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
|
||||
Date: Tue, 17 Sep 2024 19:32:39 +0530
|
||||
Subject: [PATCH] wifi: cfg80211: check radio iface combination for multi radio
|
||||
per wiphy
|
||||
|
||||
Currently, wiphy_verify_combinations() fails for the multi-radio per wiphy
|
||||
due to the condition check on new global interface combination that DFS
|
||||
only works on one channel. In a multi-radio scenario, new global interface
|
||||
combination encompasses the capabilities of all radio combinations, so it
|
||||
supports more than one channel with DFS. For multi-radio per wiphy,
|
||||
interface combination verification needs to be performed for radio specific
|
||||
interface combinations. This is necessary as the new global interface
|
||||
combination combines the capabilities of all radio combinations.
|
||||
|
||||
Fixes: a01b1e9f9955 ("wifi: mac80211: add support for DFS with multiple radios")
|
||||
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/core.c
|
||||
+++ b/net/wireless/core.c
|
||||
@@ -599,16 +599,20 @@ use_default_name:
|
||||
}
|
||||
EXPORT_SYMBOL(wiphy_new_nm);
|
||||
|
||||
-static int wiphy_verify_combinations(struct wiphy *wiphy)
|
||||
+static
|
||||
+int wiphy_verify_iface_combinations(struct wiphy *wiphy,
|
||||
+ const struct ieee80211_iface_combination *iface_comb,
|
||||
+ int n_iface_comb,
|
||||
+ bool combined_radio)
|
||||
{
|
||||
const struct ieee80211_iface_combination *c;
|
||||
int i, j;
|
||||
|
||||
- for (i = 0; i < wiphy->n_iface_combinations; i++) {
|
||||
+ for (i = 0; i < n_iface_comb; i++) {
|
||||
u32 cnt = 0;
|
||||
u16 all_iftypes = 0;
|
||||
|
||||
- c = &wiphy->iface_combinations[i];
|
||||
+ c = &iface_comb[i];
|
||||
|
||||
/*
|
||||
* Combinations with just one interface aren't real,
|
||||
@@ -621,9 +625,13 @@ static int wiphy_verify_combinations(str
|
||||
if (WARN_ON(!c->num_different_channels))
|
||||
return -EINVAL;
|
||||
|
||||
- /* DFS only works on one channel. */
|
||||
- if (WARN_ON(c->radar_detect_widths &&
|
||||
- (c->num_different_channels > 1)))
|
||||
+ /* DFS only works on one channel. Avoid this check
|
||||
+ * for multi-radio global combination, since it hold
|
||||
+ * the capabilities of all radio combinations.
|
||||
+ */
|
||||
+ if (!combined_radio &&
|
||||
+ WARN_ON(c->radar_detect_widths &&
|
||||
+ c->num_different_channels > 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!c->n_limits))
|
||||
@@ -644,13 +652,21 @@ static int wiphy_verify_combinations(str
|
||||
if (WARN_ON(wiphy->software_iftypes & types))
|
||||
return -EINVAL;
|
||||
|
||||
- /* Only a single P2P_DEVICE can be allowed */
|
||||
- if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
|
||||
+ /* Only a single P2P_DEVICE can be allowed, avoid this
|
||||
+ * check for multi-radio global combination, since it
|
||||
+ * hold the capabilities of all radio combinations.
|
||||
+ */
|
||||
+ if (!combined_radio &&
|
||||
+ WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
|
||||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
- /* Only a single NAN can be allowed */
|
||||
- if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
|
||||
+ /* Only a single NAN can be allowed, avoid this
|
||||
+ * check for multi-radio global combination, since it
|
||||
+ * hold the capabilities of all radio combinations.
|
||||
+ */
|
||||
+ if (!combined_radio &&
|
||||
+ WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
|
||||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -674,6 +690,34 @@ static int wiphy_verify_combinations(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int wiphy_verify_combinations(struct wiphy *wiphy)
|
||||
+{
|
||||
+ int i, ret;
|
||||
+ bool combined_radio = false;
|
||||
+
|
||||
+ if (wiphy->n_radio) {
|
||||
+ for (i = 0; i < wiphy->n_radio; i++) {
|
||||
+ const struct wiphy_radio *radio = &wiphy->radio[i];
|
||||
+
|
||||
+ ret = wiphy_verify_iface_combinations(wiphy,
|
||||
+ radio->iface_combinations,
|
||||
+ radio->n_iface_combinations,
|
||||
+ false);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ combined_radio = true;
|
||||
+ }
|
||||
+
|
||||
+ ret = wiphy_verify_iface_combinations(wiphy,
|
||||
+ wiphy->iface_combinations,
|
||||
+ wiphy->n_iface_combinations,
|
||||
+ combined_radio);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int wiphy_register(struct wiphy *wiphy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
@ -0,0 +1,309 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 17 Jul 2024 15:43:52 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: add option for vif allowed radios
|
||||
|
||||
This allows users to prevent a vif from affecting radios other than the
|
||||
configured ones. This can be useful in cases where e.g. an AP is running
|
||||
on one radio, and triggering a scan on another radio should not disturb it.
|
||||
|
||||
Changing the allowed radios list for a vif is supported, but only while
|
||||
it is down.
|
||||
|
||||
While it is possible to achieve the same by always explicitly specifying
|
||||
a frequency list for scan requests and ensuring that the wrong channel/band
|
||||
is never accidentally set on an unrelated interface, this change makes
|
||||
multi-radio wiphy setups a lot easier to deal with for CLI users.
|
||||
|
||||
By itself, this patch only enforces the radio mask for scanning requests
|
||||
and remain-on-channel. Follow-up changes build on this to limit configured
|
||||
frequencies.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -6227,6 +6227,7 @@ enum ieee80211_ap_reg_power {
|
||||
* entered.
|
||||
* @links[].cac_time_ms: CAC time in ms
|
||||
* @valid_links: bitmap describing what elements of @links are valid
|
||||
+ * @radio_mask: Bitmask of radios that this interface is allowed to operate on.
|
||||
*/
|
||||
struct wireless_dev {
|
||||
struct wiphy *wiphy;
|
||||
@@ -6339,6 +6340,8 @@ struct wireless_dev {
|
||||
unsigned int cac_time_ms;
|
||||
} links[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
u16 valid_links;
|
||||
+
|
||||
+ u32 radio_mask;
|
||||
};
|
||||
|
||||
static inline const u8 *wdev_address(struct wireless_dev *wdev)
|
||||
@@ -6525,6 +6528,17 @@ bool cfg80211_radio_chandef_valid(const
|
||||
const struct cfg80211_chan_def *chandef);
|
||||
|
||||
/**
|
||||
+ * cfg80211_wdev_channel_allowed - Check if the wdev may use the channel
|
||||
+ *
|
||||
+ * @wdev: the wireless device
|
||||
+ * @chan: channel to check
|
||||
+ *
|
||||
+ * Return: whether or not the wdev may use the channel
|
||||
+ */
|
||||
+bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
|
||||
+ struct ieee80211_channel *chan);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_get_response_rate - get basic rate for a given rate
|
||||
*
|
||||
* @sband: the band to look for rates in
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -2868,6 +2868,9 @@ enum nl80211_commands {
|
||||
* nested item, it contains attributes defined in
|
||||
* &enum nl80211_if_combination_attrs.
|
||||
*
|
||||
+ * @NL80211_ATTR_VIF_RADIO_MASK: Bitmask of allowed radios (u32).
|
||||
+ * A value of 0 means all radios.
|
||||
+ *
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -3416,6 +3419,8 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_WIPHY_RADIOS,
|
||||
NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
|
||||
|
||||
+ NL80211_ATTR_VIF_RADIO_MASK,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -829,6 +829,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
|
||||
[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
|
||||
[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
|
||||
+ [NL80211_ATTR_VIF_RADIO_MASK] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -3996,7 +3997,8 @@ static int nl80211_send_iface(struct sk_
|
||||
nla_put_u32(msg, NL80211_ATTR_GENERATION,
|
||||
rdev->devlist_generation ^
|
||||
(cfg80211_rdev_list_generation << 2)) ||
|
||||
- nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
|
||||
+ nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr) ||
|
||||
+ nla_put_u32(msg, NL80211_ATTR_VIF_RADIO_MASK, wdev->radio_mask))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (rdev->ops->get_channel && !wdev->valid_links) {
|
||||
@@ -4312,6 +4314,29 @@ static int nl80211_valid_4addr(struct cf
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
+static int nl80211_parse_vif_radio_mask(struct genl_info *info,
|
||||
+ u32 *radio_mask)
|
||||
+{
|
||||
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
+ struct nlattr *attr = info->attrs[NL80211_ATTR_VIF_RADIO_MASK];
|
||||
+ u32 mask, allowed;
|
||||
+
|
||||
+ if (!attr) {
|
||||
+ *radio_mask = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ allowed = BIT(rdev->wiphy.n_radio) - 1;
|
||||
+ mask = nla_get_u32(attr);
|
||||
+ if (mask & ~allowed)
|
||||
+ return -EINVAL;
|
||||
+ if (!mask)
|
||||
+ mask = allowed;
|
||||
+ *radio_mask = mask;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
@@ -4319,6 +4344,8 @@ static int nl80211_set_interface(struct
|
||||
int err;
|
||||
enum nl80211_iftype otype, ntype;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
+ u32 radio_mask = 0;
|
||||
bool change = false;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
@@ -4332,8 +4359,6 @@ static int nl80211_set_interface(struct
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MESH_ID]) {
|
||||
- struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
-
|
||||
if (ntype != NL80211_IFTYPE_MESH_POINT)
|
||||
return -EINVAL;
|
||||
if (otype != NL80211_IFTYPE_MESH_POINT)
|
||||
@@ -4364,6 +4389,12 @@ static int nl80211_set_interface(struct
|
||||
if (err > 0)
|
||||
change = true;
|
||||
|
||||
+ err = nl80211_parse_vif_radio_mask(info, &radio_mask);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ if (err && netif_running(dev))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
if (change)
|
||||
err = cfg80211_change_iface(rdev, dev, ntype, ¶ms);
|
||||
else
|
||||
@@ -4372,11 +4403,11 @@ static int nl80211_set_interface(struct
|
||||
if (!err && params.use_4addr != -1)
|
||||
dev->ieee80211_ptr->use_4addr = params.use_4addr;
|
||||
|
||||
- if (change && !err) {
|
||||
- struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
+ if (radio_mask)
|
||||
+ wdev->radio_mask = radio_mask;
|
||||
|
||||
+ if (change && !err)
|
||||
nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
|
||||
- }
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -4387,6 +4418,7 @@ static int _nl80211_new_interface(struct
|
||||
struct vif_params params;
|
||||
struct wireless_dev *wdev;
|
||||
struct sk_buff *msg;
|
||||
+ u32 radio_mask;
|
||||
int err;
|
||||
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
||||
|
||||
@@ -4424,6 +4456,10 @@ static int _nl80211_new_interface(struct
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
+ err = nl80211_parse_vif_radio_mask(info, &radio_mask);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
@@ -4465,6 +4501,9 @@ static int _nl80211_new_interface(struct
|
||||
break;
|
||||
}
|
||||
|
||||
+ if (radio_mask)
|
||||
+ wdev->radio_mask = radio_mask;
|
||||
+
|
||||
if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
|
||||
rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
|
||||
nlmsg_free(msg);
|
||||
@@ -9180,6 +9219,9 @@ static bool cfg80211_off_channel_oper_al
|
||||
|
||||
lockdep_assert_wiphy(wdev->wiphy);
|
||||
|
||||
+ if (!cfg80211_wdev_channel_allowed(wdev, chan))
|
||||
+ return false;
|
||||
+
|
||||
if (!cfg80211_beaconing_iface_active(wdev))
|
||||
return true;
|
||||
|
||||
@@ -9392,7 +9434,8 @@ static int nl80211_trigger_scan(struct s
|
||||
}
|
||||
|
||||
/* ignore disabled channels */
|
||||
- if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
||||
+ !cfg80211_wdev_channel_allowed(wdev, chan))
|
||||
continue;
|
||||
|
||||
request->channels[i] = chan;
|
||||
@@ -9412,7 +9455,8 @@ static int nl80211_trigger_scan(struct s
|
||||
|
||||
chan = &wiphy->bands[band]->channels[j];
|
||||
|
||||
- if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
||||
+ !cfg80211_wdev_channel_allowed(wdev, chan))
|
||||
continue;
|
||||
|
||||
request->channels[i] = chan;
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -956,7 +956,8 @@ static int cfg80211_scan_6ghz(struct cfg
|
||||
struct ieee80211_channel *chan =
|
||||
ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
|
||||
|
||||
- if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED ||
|
||||
+ !cfg80211_wdev_channel_allowed(rdev_req->wdev, chan))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < rdev_req->n_channels; i++) {
|
||||
@@ -3490,9 +3491,12 @@ int cfg80211_wext_siwscan(struct net_dev
|
||||
continue;
|
||||
|
||||
for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
|
||||
+ struct ieee80211_channel *chan;
|
||||
+
|
||||
/* ignore disabled channels */
|
||||
- if (wiphy->bands[band]->channels[j].flags &
|
||||
- IEEE80211_CHAN_DISABLED)
|
||||
+ chan = &wiphy->bands[band]->channels[j];
|
||||
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
|
||||
+ !cfg80211_wdev_channel_allowed(creq->wdev, chan))
|
||||
continue;
|
||||
|
||||
/* If we have a wireless request structure and the
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -2923,3 +2923,32 @@ bool cfg80211_radio_chandef_valid(const
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_radio_chandef_valid);
|
||||
+
|
||||
+bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
|
||||
+ struct ieee80211_channel *chan)
|
||||
+{
|
||||
+ struct wiphy *wiphy = wdev->wiphy;
|
||||
+ const struct wiphy_radio *radio;
|
||||
+ struct cfg80211_chan_def chandef;
|
||||
+ u32 radio_mask;
|
||||
+ int i;
|
||||
+
|
||||
+ radio_mask = wdev->radio_mask;
|
||||
+ if (!wiphy->n_radio || radio_mask == BIT(wiphy->n_radio) - 1)
|
||||
+ return true;
|
||||
+
|
||||
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
|
||||
+ for (i = 0; i < wiphy->n_radio; i++) {
|
||||
+ if (!(radio_mask & BIT(i)))
|
||||
+ continue;
|
||||
+
|
||||
+ radio = &wiphy->radio[i];
|
||||
+ if (!cfg80211_radio_chandef_valid(radio, &chandef))
|
||||
+ continue;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+EXPORT_SYMBOL(cfg80211_wdev_channel_allowed);
|
||||
--- a/net/wireless/core.c
|
||||
+++ b/net/wireless/core.c
|
||||
@@ -1415,6 +1415,8 @@ void cfg80211_init_wdev(struct wireless_
|
||||
/* allow mac80211 to determine the timeout */
|
||||
wdev->ps_timeout = -1;
|
||||
|
||||
+ wdev->radio_mask = BIT(wdev->wiphy->n_radio) - 1;
|
||||
+
|
||||
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
|
||||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
|
@ -0,0 +1,79 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 26 Sep 2024 14:06:11 +0200
|
||||
Subject: [PATCH] wifi: mac80211: use vif radio mask to limit ibss scan
|
||||
frequencies
|
||||
|
||||
Reject frequencies not supported by any radio that the vif is allowed to use.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -1178,14 +1178,14 @@ int ieee80211_request_ibss_scan(struct i
|
||||
unsigned int n_channels)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
- int ret = -EBUSY, i, n_ch = 0;
|
||||
+ int i, n_ch = 0;
|
||||
enum nl80211_band band;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
/* busy scanning */
|
||||
if (local->scan_req)
|
||||
- goto unlock;
|
||||
+ return -EBUSY;
|
||||
|
||||
/* fill internal scan request */
|
||||
if (!channels) {
|
||||
@@ -1202,7 +1202,9 @@ int ieee80211_request_ibss_scan(struct i
|
||||
&local->hw.wiphy->bands[band]->channels[i];
|
||||
|
||||
if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
|
||||
- IEEE80211_CHAN_DISABLED))
|
||||
+ IEEE80211_CHAN_DISABLED) ||
|
||||
+ !cfg80211_wdev_channel_allowed(&sdata->wdev,
|
||||
+ tmp_ch))
|
||||
continue;
|
||||
|
||||
local->int_scan_req->channels[n_ch] = tmp_ch;
|
||||
@@ -1211,21 +1213,23 @@ int ieee80211_request_ibss_scan(struct i
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(n_ch == 0))
|
||||
- goto unlock;
|
||||
+ return -EINVAL;
|
||||
|
||||
local->int_scan_req->n_channels = n_ch;
|
||||
} else {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
|
||||
- IEEE80211_CHAN_DISABLED))
|
||||
+ IEEE80211_CHAN_DISABLED) ||
|
||||
+ !cfg80211_wdev_channel_allowed(&sdata->wdev,
|
||||
+ channels[i]))
|
||||
continue;
|
||||
|
||||
local->int_scan_req->channels[n_ch] = channels[i];
|
||||
n_ch++;
|
||||
}
|
||||
|
||||
- if (WARN_ON_ONCE(n_ch == 0))
|
||||
- goto unlock;
|
||||
+ if (n_ch == 0)
|
||||
+ return -EINVAL;
|
||||
|
||||
local->int_scan_req->n_channels = n_ch;
|
||||
}
|
||||
@@ -1235,9 +1239,7 @@ int ieee80211_request_ibss_scan(struct i
|
||||
memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
|
||||
local->int_scan_req->ssids[0].ssid_len = ssid_len;
|
||||
|
||||
- ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
|
||||
- unlock:
|
||||
- return ret;
|
||||
+ return __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
|
||||
}
|
||||
|
||||
void ieee80211_scan_cancel(struct ieee80211_local *local)
|
@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 26 Sep 2024 14:07:50 +0200
|
||||
Subject: [PATCH] wifi: mac80211: use vif radio mask to limit creating chanctx
|
||||
|
||||
Reject frequencies not supported by any radio that the vif is allowed to use.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/chan.c
|
||||
+++ b/net/mac80211/chan.c
|
||||
@@ -1167,7 +1167,7 @@ ieee80211_replace_chanctx(struct ieee802
|
||||
static bool
|
||||
ieee80211_find_available_radio(struct ieee80211_local *local,
|
||||
const struct ieee80211_chan_req *chanreq,
|
||||
- int *radio_idx)
|
||||
+ u32 radio_mask, int *radio_idx)
|
||||
{
|
||||
struct wiphy *wiphy = local->hw.wiphy;
|
||||
const struct wiphy_radio *radio;
|
||||
@@ -1178,6 +1178,9 @@ ieee80211_find_available_radio(struct ie
|
||||
return true;
|
||||
|
||||
for (i = 0; i < wiphy->n_radio; i++) {
|
||||
+ if (!(radio_mask & BIT(i)))
|
||||
+ continue;
|
||||
+
|
||||
radio = &wiphy->radio[i];
|
||||
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
|
||||
continue;
|
||||
@@ -1211,7 +1214,9 @@ int ieee80211_link_reserve_chanctx(struc
|
||||
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
|
||||
if (!new_ctx) {
|
||||
if (ieee80211_can_create_new_chanctx(local, -1) &&
|
||||
- ieee80211_find_available_radio(local, chanreq, &radio_idx))
|
||||
+ ieee80211_find_available_radio(local, chanreq,
|
||||
+ sdata->wdev.radio_mask,
|
||||
+ &radio_idx))
|
||||
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
|
||||
false, radio_idx);
|
||||
else
|
||||
@@ -1881,7 +1886,9 @@ int _ieee80211_link_use_channel(struct i
|
||||
/* Note: context is now reserved */
|
||||
if (ctx)
|
||||
reserved = true;
|
||||
- else if (!ieee80211_find_available_radio(local, chanreq, &radio_idx))
|
||||
+ else if (!ieee80211_find_available_radio(local, chanreq,
|
||||
+ sdata->wdev.radio_mask,
|
||||
+ &radio_idx))
|
||||
ctx = ERR_PTR(-EBUSY);
|
||||
else
|
||||
ctx = ieee80211_new_chanctx(local, chanreq, mode,
|
@ -0,0 +1,67 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 17 Jul 2024 22:49:16 +0200
|
||||
Subject: [PATCH] wifi: mac80211: remove status->ampdu_delimiter_crc
|
||||
|
||||
This was never used by any driver, so remove it to free up some space.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1448,8 +1448,6 @@ ieee80211_tx_info_clear_status(struct ie
|
||||
* @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU
|
||||
* @RX_FLAG_AMPDU_DELIM_CRC_ERROR: A delimiter CRC error has been detected
|
||||
* on this subframe
|
||||
- * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
|
||||
- * is stored in the @ampdu_delimiter_crc field)
|
||||
* @RX_FLAG_MIC_STRIPPED: The mic was stripped of this packet. Decryption was
|
||||
* done by the hardware
|
||||
* @RX_FLAG_ONLY_MONITOR: Report frame only to monitor interfaces without
|
||||
@@ -1521,7 +1519,7 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_AMPDU_LAST_KNOWN = BIT(12),
|
||||
RX_FLAG_AMPDU_IS_LAST = BIT(13),
|
||||
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(14),
|
||||
- RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(15),
|
||||
+ /* one free bit at 15 */
|
||||
RX_FLAG_MACTIME = BIT(16) | BIT(17),
|
||||
RX_FLAG_MACTIME_PLCP_START = 1 << 16,
|
||||
RX_FLAG_MACTIME_START = 2 << 16,
|
||||
@@ -1618,7 +1616,6 @@ enum mac80211_rx_encoding {
|
||||
* @rx_flags: internal RX flags for mac80211
|
||||
* @ampdu_reference: A-MPDU reference number, must be a different value for
|
||||
* each A-MPDU but the same for each subframe within one A-MPDU
|
||||
- * @ampdu_delimiter_crc: A-MPDU delimiter CRC
|
||||
* @zero_length_psdu_type: radiotap type of the 0-length PSDU
|
||||
* @link_valid: if the link which is identified by @link_id is valid. This flag
|
||||
* is set only when connection is MLO.
|
||||
@@ -1656,7 +1653,6 @@ struct ieee80211_rx_status {
|
||||
s8 signal;
|
||||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
- u8 ampdu_delimiter_crc;
|
||||
u8 zero_length_psdu_type;
|
||||
u8 link_valid:1, link_id:4;
|
||||
};
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -508,18 +508,13 @@ ieee80211_add_rx_radiotap_header(struct
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
|
||||
if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
|
||||
- if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
|
||||
- flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
|
||||
if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
|
||||
if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
|
||||
flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
|
||||
put_unaligned_le16(flags, pos);
|
||||
pos += 2;
|
||||
- if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
|
||||
- *pos++ = status->ampdu_delimiter_crc;
|
||||
- else
|
||||
- *pos++ = 0;
|
||||
+ *pos++ = 0;
|
||||
*pos++ = 0;
|
||||
}
|
||||
|
@ -0,0 +1,165 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 26 Sep 2024 19:52:30 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: pass net_device to .set_monitor_channel
|
||||
|
||||
Preparation for allowing multiple monitor interfaces with different channels
|
||||
on a multi-radio wiphy.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
|
||||
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
|
||||
@@ -1493,6 +1493,7 @@ out:
|
||||
}
|
||||
|
||||
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
--- a/drivers/net/wireless/marvell/libertas/cfg.c
|
||||
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
|
||||
@@ -486,6 +486,7 @@ static int lbs_add_wps_enrollee_tlv(u8 *
|
||||
*/
|
||||
|
||||
static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
|
||||
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
|
||||
@@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(stru
|
||||
}
|
||||
|
||||
static int set_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wilc *wl = wiphy_priv(wiphy);
|
||||
@@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy,
|
||||
struct wilc_vif *vif = netdev_priv(dev);
|
||||
int ret;
|
||||
|
||||
- ret = set_channel(wiphy, &settings->chandef);
|
||||
+ ret = set_channel(wiphy, dev, &settings->chandef);
|
||||
if (ret != 0)
|
||||
netdev_err(dev, "Error in setting channel\n");
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -4700,6 +4700,7 @@ struct cfg80211_ops {
|
||||
struct ieee80211_channel *chan);
|
||||
|
||||
int (*set_monitor_channel)(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
|
||||
int (*scan)(struct wiphy *wiphy,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -879,6 +879,7 @@ static int ieee80211_get_station(struct
|
||||
}
|
||||
|
||||
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
--- a/net/wireless/chan.c
|
||||
+++ b/net/wireless/chan.c
|
||||
@@ -1673,6 +1673,7 @@ bool cfg80211_reg_check_beaconing(struct
|
||||
EXPORT_SYMBOL(cfg80211_reg_check_beaconing);
|
||||
|
||||
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
if (!rdev->ops->set_monitor_channel)
|
||||
@@ -1680,7 +1681,7 @@ int cfg80211_set_monitor_channel(struct
|
||||
if (!cfg80211_has_monitors_only(rdev))
|
||||
return -EBUSY;
|
||||
|
||||
- return rdev_set_monitor_channel(rdev, chandef);
|
||||
+ return rdev_set_monitor_channel(rdev, dev, chandef);
|
||||
}
|
||||
|
||||
bool cfg80211_any_usable_channels(struct wiphy *wiphy,
|
||||
--- a/net/wireless/core.h
|
||||
+++ b/net/wireless/core.h
|
||||
@@ -510,6 +510,7 @@ static inline unsigned int elapsed_jiffi
|
||||
}
|
||||
|
||||
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
|
||||
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -3562,7 +3562,7 @@ static int __nl80211_set_channel(struct
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return cfg80211_set_mesh_channel(rdev, wdev, &chandef);
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- return cfg80211_set_monitor_channel(rdev, &chandef);
|
||||
+ return cfg80211_set_monitor_channel(rdev, dev, &chandef);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
--- a/net/wireless/rdev-ops.h
|
||||
+++ b/net/wireless/rdev-ops.h
|
||||
@@ -445,11 +445,12 @@ rdev_libertas_set_mesh_channel(struct cf
|
||||
|
||||
static inline int
|
||||
rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
+ struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
int ret;
|
||||
- trace_rdev_set_monitor_channel(&rdev->wiphy, chandef);
|
||||
- ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef);
|
||||
+ trace_rdev_set_monitor_channel(&rdev->wiphy, dev, chandef);
|
||||
+ ret = rdev->ops->set_monitor_channel(&rdev->wiphy, dev, chandef);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
--- a/net/wireless/trace.h
|
||||
+++ b/net/wireless/trace.h
|
||||
@@ -1318,19 +1318,21 @@ TRACE_EVENT(rdev_libertas_set_mesh_chann
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_monitor_channel,
|
||||
- TP_PROTO(struct wiphy *wiphy,
|
||||
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_chan_def *chandef),
|
||||
- TP_ARGS(wiphy, chandef),
|
||||
+ TP_ARGS(wiphy, netdev, chandef),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
+ NETDEV_ENTRY
|
||||
CHAN_DEF_ENTRY
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
+ NETDEV_ASSIGN;
|
||||
CHAN_DEF_ASSIGN(chandef);
|
||||
),
|
||||
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
|
||||
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
|
||||
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT,
|
||||
+ WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_auth,
|
||||
--- a/net/wireless/wext-compat.c
|
||||
+++ b/net/wireless/wext-compat.c
|
||||
@@ -830,7 +830,7 @@ static int cfg80211_wext_siwfreq(struct
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
- ret = cfg80211_set_monitor_channel(rdev, &chandef);
|
||||
+ ret = cfg80211_set_monitor_channel(rdev, dev, &chandef);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
freq = cfg80211_wext_freq(wextfreq);
|
@ -0,0 +1,337 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 30 Sep 2024 15:09:45 +0200
|
||||
Subject: [PATCH] wifi: mac80211: add flag to opt out of virtual monitor
|
||||
support
|
||||
|
||||
This is useful for multi-radio devices that are capable of monitoring on
|
||||
multiple channels simultanenously. When this flag is set, each monitor
|
||||
interface is passed to the driver individually and can have a configured
|
||||
channel.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2679,6 +2679,11 @@ struct ieee80211_txq {
|
||||
* a virtual monitor interface when monitor interfaces are the only
|
||||
* active interfaces.
|
||||
*
|
||||
+ * @IEEE80211_HW_NO_VIRTUAL_MONITOR: The driver would like to be informed
|
||||
+ * of any monitor interface, as well as their configured channel.
|
||||
+ * This is useful for supporting multiple monitor interfaces on different
|
||||
+ * channels.
|
||||
+ *
|
||||
* @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
|
||||
* be created. It is expected user-space will create vifs as
|
||||
* desired (and thus have them named as desired).
|
||||
@@ -2838,6 +2843,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS,
|
||||
IEEE80211_HW_MFP_CAPABLE,
|
||||
IEEE80211_HW_WANT_MONITOR_VIF,
|
||||
+ IEEE80211_HW_NO_VIRTUAL_MONITOR,
|
||||
IEEE80211_HW_NO_AUTO_VIF,
|
||||
IEEE80211_HW_SW_CRYPTO_CONTROL,
|
||||
IEEE80211_HW_SUPPORT_FAST_XMIT,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -105,8 +105,11 @@ static int ieee80211_set_mon_options(str
|
||||
}
|
||||
|
||||
/* also validate MU-MIMO change */
|
||||
- monitor_sdata = wiphy_dereference(local->hw.wiphy,
|
||||
- local->monitor_sdata);
|
||||
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ monitor_sdata = sdata;
|
||||
+ else
|
||||
+ monitor_sdata = wiphy_dereference(local->hw.wiphy,
|
||||
+ local->monitor_sdata);
|
||||
|
||||
if (!monitor_sdata &&
|
||||
(params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
|
||||
@@ -114,7 +117,9 @@ static int ieee80211_set_mon_options(str
|
||||
|
||||
/* apply all changes now - no failures allowed */
|
||||
|
||||
- if (monitor_sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
|
||||
+ if (monitor_sdata &&
|
||||
+ (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
|
||||
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
|
||||
|
||||
if (params->flags) {
|
||||
@@ -889,22 +894,25 @@ static int ieee80211_set_monitor_channel
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
- if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
|
||||
- &chanreq.oper))
|
||||
- return 0;
|
||||
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
+ if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
+ if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
|
||||
+ &chanreq.oper))
|
||||
+ return 0;
|
||||
|
||||
- sdata = wiphy_dereference(local->hw.wiphy,
|
||||
- local->monitor_sdata);
|
||||
- if (!sdata)
|
||||
- goto done;
|
||||
+ sdata = wiphy_dereference(wiphy, local->monitor_sdata);
|
||||
+ if (!sdata)
|
||||
+ goto done;
|
||||
+ }
|
||||
|
||||
- if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
|
||||
+ if (rcu_access_pointer(sdata->deflink.conf->chanctx_conf) &&
|
||||
+ cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
|
||||
&chanreq.oper))
|
||||
return 0;
|
||||
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
ret = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
|
||||
- IEEE80211_CHANCTX_EXCLUSIVE);
|
||||
+ IEEE80211_CHANCTX_SHARED);
|
||||
if (ret)
|
||||
return ret;
|
||||
done:
|
||||
@@ -3049,7 +3057,8 @@ static int ieee80211_set_tx_power(struct
|
||||
if (wdev) {
|
||||
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -3097,7 +3106,8 @@ static int ieee80211_set_tx_power(struct
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
has_monitor = true;
|
||||
continue;
|
||||
}
|
||||
@@ -3107,7 +3117,8 @@ static int ieee80211_set_tx_power(struct
|
||||
sdata->vif.bss_conf.txpower_type = txp_type;
|
||||
}
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
continue;
|
||||
ieee80211_recalc_txpower(sdata, update_txp_type);
|
||||
}
|
||||
@@ -4299,7 +4310,8 @@ static int ieee80211_cfg_get_channel(str
|
||||
if (chanctx_conf) {
|
||||
*chandef = link->conf->chanreq.oper;
|
||||
ret = 0;
|
||||
- } else if (local->open_count > 0 &&
|
||||
+ } else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
|
||||
+ local->open_count > 0 &&
|
||||
local->open_count == local->monitors &&
|
||||
sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
*chandef = local->monitor_chanreq.oper;
|
||||
--- a/net/mac80211/chan.c
|
||||
+++ b/net/mac80211/chan.c
|
||||
@@ -337,6 +337,10 @@ ieee80211_get_chanctx_max_required_bw(st
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
continue;
|
||||
+ case NL80211_IFTYPE_MONITOR:
|
||||
+ WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
|
||||
+ NO_VIRTUAL_MONITOR));
|
||||
+ fallthrough;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_OCB:
|
||||
@@ -345,7 +349,6 @@ ieee80211_get_chanctx_max_required_bw(st
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
- case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
WARN_ON_ONCE(1);
|
||||
@@ -954,6 +957,10 @@ void ieee80211_recalc_smps_chanctx(struc
|
||||
if (!link->sdata->u.mgd.associated)
|
||||
continue;
|
||||
break;
|
||||
+ case NL80211_IFTYPE_MONITOR:
|
||||
+ if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ continue;
|
||||
+ break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
@@ -966,6 +973,11 @@ void ieee80211_recalc_smps_chanctx(struc
|
||||
if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
|
||||
continue;
|
||||
|
||||
+ if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
+ rx_chains_dynamic = rx_chains_static = local->rx_chains;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
switch (link->smps_mode) {
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid SMPS mode %d\n",
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -465,6 +465,7 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(SUPPORTS_DYNAMIC_PS),
|
||||
FLAG(MFP_CAPABLE),
|
||||
FLAG(WANT_MONITOR_VIF),
|
||||
+ FLAG(NO_VIRTUAL_MONITOR),
|
||||
FLAG(NO_AUTO_VIF),
|
||||
FLAG(SW_CRYPTO_CONTROL),
|
||||
FLAG(SUPPORT_FAST_XMIT),
|
||||
--- a/net/mac80211/driver-ops.c
|
||||
+++ b/net/mac80211/driver-ops.c
|
||||
@@ -65,6 +65,7 @@ int drv_add_interface(struct ieee80211_l
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
|
||||
!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
|
||||
return -EINVAL;
|
||||
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -279,8 +279,13 @@ static int _ieee80211_change_mac(struct
|
||||
ret = eth_mac_addr(sdata->dev, sa);
|
||||
|
||||
if (ret == 0) {
|
||||
- memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
- ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
+ if (check_dup) {
|
||||
+ memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
+ ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
+ } else {
|
||||
+ memset(sdata->vif.addr, 0, ETH_ALEN);
|
||||
+ memset(sdata->vif.bss_conf.addr, 0, ETH_ALEN);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Regardless of eth_mac_addr() return we still want to add the
|
||||
@@ -699,9 +704,11 @@ static void ieee80211_do_stop(struct iee
|
||||
ieee80211_recalc_idle(local);
|
||||
ieee80211_recalc_offload(local);
|
||||
|
||||
- if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
|
||||
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
break;
|
||||
|
||||
+ ieee80211_link_release_channel(&sdata->deflink);
|
||||
fallthrough;
|
||||
default:
|
||||
if (!going_down)
|
||||
@@ -1131,7 +1138,8 @@ int ieee80211_add_virtual_monitor(struct
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
- if (local->monitor_sdata)
|
||||
+ if (local->monitor_sdata ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
return 0;
|
||||
|
||||
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
|
||||
@@ -1193,6 +1201,9 @@ void ieee80211_del_virtual_monitor(struc
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ return;
|
||||
+
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
@@ -1328,7 +1339,8 @@ int ieee80211_do_open(struct wireless_de
|
||||
break;
|
||||
}
|
||||
|
||||
- if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -840,6 +840,9 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
bool last_monitor = list_is_last(&sdata->u.mntr.list,
|
||||
&local->mon_list);
|
||||
|
||||
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ ieee80211_handle_mu_mimo_mon(sdata, origskb, rtap_space);
|
||||
+
|
||||
if (!monskb)
|
||||
monskb = ieee80211_make_monitor_skb(local, &origskb,
|
||||
rate, rtap_space,
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1763,7 +1763,8 @@ static bool __ieee80211_tx(struct ieee80
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
vif = &sdata->vif;
|
||||
break;
|
||||
}
|
||||
@@ -3952,7 +3953,8 @@ begin:
|
||||
|
||||
switch (tx.sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||
+ if ((tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
|
||||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
vif = &tx.sdata->vif;
|
||||
break;
|
||||
}
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -754,7 +754,8 @@ static void __iterate_interfaces(struct
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
- if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
|
||||
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
continue;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
@@ -1857,8 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
ieee80211_sdata_running(sdata)) {
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (WARN_ON(res))
|
||||
@@ -1871,11 +1874,14 @@ int ieee80211_reconfig(struct ieee80211_
|
||||
*/
|
||||
if (res) {
|
||||
list_for_each_entry_continue_reverse(sdata, &local->interfaces,
|
||||
- list)
|
||||
+ list) {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
+ continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
ieee80211_sdata_running(sdata))
|
||||
drv_remove_interface(local, sdata);
|
||||
+ }
|
||||
ieee80211_handle_reconfig_failure(local);
|
||||
return res;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 30 Sep 2024 17:04:09 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: add monitor SKIP_TX flag
|
||||
|
||||
This can be used to indicate that the user is not interested in receiving
|
||||
locally sent packets on the monitor interface.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -2272,6 +2272,7 @@ static inline int cfg80211_get_station(s
|
||||
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
|
||||
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing
|
||||
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
|
||||
+ * @MONITOR_FLAG_SKIP_TX: do not pass locally transmitted frames
|
||||
*/
|
||||
enum monitor_flags {
|
||||
MONITOR_FLAG_CHANGED = BIT(__NL80211_MNTR_FLAG_INVALID),
|
||||
@@ -2281,6 +2282,7 @@ enum monitor_flags {
|
||||
MONITOR_FLAG_OTHER_BSS = BIT(NL80211_MNTR_FLAG_OTHER_BSS),
|
||||
MONITOR_FLAG_COOK_FRAMES = BIT(NL80211_MNTR_FLAG_COOK_FRAMES),
|
||||
MONITOR_FLAG_ACTIVE = BIT(NL80211_MNTR_FLAG_ACTIVE),
|
||||
+ MONITOR_FLAG_SKIP_TX = BIT(NL80211_MNTR_FLAG_SKIP_TX),
|
||||
};
|
||||
|
||||
/**
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -4703,6 +4703,7 @@ enum nl80211_survey_info {
|
||||
* overrides all other flags.
|
||||
* @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
|
||||
* and ACK incoming unicast packets.
|
||||
+ * @NL80211_MNTR_FLAG_SKIP_TX: do not pass local tx packets
|
||||
*
|
||||
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
|
||||
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
|
||||
@@ -4715,6 +4716,7 @@ enum nl80211_mntr_flags {
|
||||
NL80211_MNTR_FLAG_OTHER_BSS,
|
||||
NL80211_MNTR_FLAG_COOK_FRAMES,
|
||||
NL80211_MNTR_FLAG_ACTIVE,
|
||||
+ NL80211_MNTR_FLAG_SKIP_TX,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_MNTR_FLAG_AFTER_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -4201,6 +4201,7 @@ static const struct nla_policy mntr_flag
|
||||
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
|
||||
[NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
|
||||
+ [NL80211_MNTR_FLAG_SKIP_TX] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
|
@ -0,0 +1,54 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 30 Sep 2024 17:05:18 +0200
|
||||
Subject: [PATCH] wifi: mac80211: add support for the monitor SKIP_TX flag
|
||||
|
||||
Do not pass locally sent packets to monitor interfaces with this flag set.
|
||||
Skip processing tx packets on the status call entirely if no monitor
|
||||
interfaces without this flag are present.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1374,7 +1374,7 @@ struct ieee80211_local {
|
||||
spinlock_t queue_stop_reason_lock;
|
||||
|
||||
int open_count;
|
||||
- int monitors, cooked_mntrs;
|
||||
+ int monitors, cooked_mntrs, tx_mntrs;
|
||||
/* number of interfaces with corresponding FIF_ flags */
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
|
||||
fif_probe_req;
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1094,6 +1094,8 @@ void ieee80211_adjust_monitor_flags(stru
|
||||
ADJUST(CONTROL, control);
|
||||
ADJUST(CONTROL, pspoll);
|
||||
ADJUST(OTHER_BSS, other_bss);
|
||||
+ if (!(flags & MONITOR_FLAG_SKIP_TX))
|
||||
+ local->tx_mntrs += offset;
|
||||
|
||||
#undef ADJUST
|
||||
}
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -927,6 +927,9 @@ void ieee80211_tx_monitor(struct ieee802
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
+ if (sdata->u.mntr.flags & MONITOR_FLAG_SKIP_TX)
|
||||
+ continue;
|
||||
+
|
||||
if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) &&
|
||||
!send_to_cooked)
|
||||
continue;
|
||||
@@ -1099,7 +1102,7 @@ static void __ieee80211_tx_status(struct
|
||||
* This is a bit racy but we can avoid a lot of work
|
||||
* with this test...
|
||||
*/
|
||||
- if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
|
||||
+ if (!local->tx_mntrs && (!send_to_cooked || !local->cooked_mntrs)) {
|
||||
if (status->free_list)
|
||||
list_add_tail(&skb->list, status->free_list);
|
||||
else
|
@ -0,0 +1,94 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 2 Oct 2024 12:31:22 +0200
|
||||
Subject: [PATCH] wifi: mac80211: refactor ieee80211_rx_monitor
|
||||
|
||||
Rework the monitor mode interface iteration to get rid of the last_monitor
|
||||
condition. Preparation for further filtering received monitor packets.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -762,8 +762,8 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
struct ieee80211_rate *rate)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
|
||||
- struct ieee80211_sub_if_data *sdata;
|
||||
- struct sk_buff *monskb = NULL;
|
||||
+ struct ieee80211_sub_if_data *sdata, *prev_sdata = NULL;
|
||||
+ struct sk_buff *skb, *monskb = NULL;
|
||||
int present_fcs_len = 0;
|
||||
unsigned int rtap_space = 0;
|
||||
struct ieee80211_sub_if_data *monitor_sdata =
|
||||
@@ -837,8 +837,10 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
|
||||
- bool last_monitor = list_is_last(&sdata->u.mntr.list,
|
||||
- &local->mon_list);
|
||||
+ if (!prev_sdata) {
|
||||
+ prev_sdata = sdata;
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
ieee80211_handle_mu_mimo_mon(sdata, origskb, rtap_space);
|
||||
@@ -846,34 +848,34 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
if (!monskb)
|
||||
monskb = ieee80211_make_monitor_skb(local, &origskb,
|
||||
rate, rtap_space,
|
||||
- only_monitor &&
|
||||
- last_monitor);
|
||||
-
|
||||
- if (monskb) {
|
||||
- struct sk_buff *skb;
|
||||
+ false);
|
||||
+ if (!monskb)
|
||||
+ continue;
|
||||
|
||||
- if (last_monitor) {
|
||||
- skb = monskb;
|
||||
- monskb = NULL;
|
||||
- } else {
|
||||
- skb = skb_clone(monskb, GFP_ATOMIC);
|
||||
- }
|
||||
+ skb = skb_clone(monskb, GFP_ATOMIC);
|
||||
+ if (!skb)
|
||||
+ continue;
|
||||
+
|
||||
+ skb->dev = prev_sdata->dev;
|
||||
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
|
||||
+ netif_receive_skb(skb);
|
||||
+ prev_sdata = sdata;
|
||||
+ }
|
||||
|
||||
- if (skb) {
|
||||
- skb->dev = sdata->dev;
|
||||
- dev_sw_netstats_rx_add(skb->dev, skb->len);
|
||||
- netif_receive_skb(skb);
|
||||
- }
|
||||
+ if (prev_sdata) {
|
||||
+ if (monskb)
|
||||
+ skb = monskb;
|
||||
+ else
|
||||
+ skb = ieee80211_make_monitor_skb(local, &origskb,
|
||||
+ rate, rtap_space,
|
||||
+ only_monitor);
|
||||
+ if (skb) {
|
||||
+ skb->dev = prev_sdata->dev;
|
||||
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
|
||||
+ netif_receive_skb(skb);
|
||||
}
|
||||
-
|
||||
- if (last_monitor)
|
||||
- break;
|
||||
}
|
||||
|
||||
- /* this happens if last_monitor was erroneously false */
|
||||
- dev_kfree_skb(monskb);
|
||||
-
|
||||
- /* ditto */
|
||||
if (!origskb)
|
||||
return NULL;
|
||||
|
@ -0,0 +1,29 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 2 Oct 2024 12:35:13 +0200
|
||||
Subject: [PATCH] wifi: mac80211: filter on monitor interfaces based on
|
||||
configured channel
|
||||
|
||||
When a monitor interface has an assigned channel (only happens with the
|
||||
NO_VIRTUAL_MONITOR feature), only pass packets received on that channel.
|
||||
This is useful for monitoring on multiple channels at the same time using
|
||||
multiple monitor interfaces.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -837,6 +837,13 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
||||
ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
|
||||
+ struct cfg80211_chan_def *chandef;
|
||||
+
|
||||
+ chandef = &sdata->vif.bss_conf.chanreq.oper;
|
||||
+ if (chandef->chan &&
|
||||
+ chandef->chan->center_freq != status->freq)
|
||||
+ continue;
|
||||
+
|
||||
if (!prev_sdata) {
|
||||
prev_sdata = sdata;
|
||||
continue;
|
@ -0,0 +1,64 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 7 Aug 2024 13:31:07 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: report per wiphy radio antenna mask
|
||||
|
||||
With multi-radio devices, each radio typically gets a fixed set of antennas.
|
||||
In order to be able to disable specific antennas for some radios, user space
|
||||
needs to know which antenna mask bits are assigned to which radio.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -5443,6 +5443,8 @@ struct wiphy_radio_freq_range {
|
||||
* @iface_combinations: Valid interface combinations array, should not
|
||||
* list single interface types.
|
||||
* @n_iface_combinations: number of entries in @iface_combinations array.
|
||||
+ *
|
||||
+ * @antenna_mask: bitmask of antennas connected to this radio.
|
||||
*/
|
||||
struct wiphy_radio {
|
||||
const struct wiphy_radio_freq_range *freq_range;
|
||||
@@ -5450,6 +5452,8 @@ struct wiphy_radio {
|
||||
|
||||
const struct ieee80211_iface_combination *iface_combinations;
|
||||
int n_iface_combinations;
|
||||
+
|
||||
+ u32 antenna_mask;
|
||||
};
|
||||
|
||||
#define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -8038,6 +8038,8 @@ enum nl80211_ap_settings_flags {
|
||||
* @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
|
||||
* combination for this radio. Attribute may be present multiple times
|
||||
* and contains attributes defined in &enum nl80211_if_combination_attrs.
|
||||
+ * @NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK: bitmask (u32) of antennas
|
||||
+ * connected to this radio.
|
||||
*
|
||||
* @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
|
||||
* @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
|
||||
@@ -8048,6 +8050,7 @@ enum nl80211_wiphy_radio_attrs {
|
||||
NL80211_WIPHY_RADIO_ATTR_INDEX,
|
||||
NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
|
||||
NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
|
||||
+ NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_WIPHY_RADIO_ATTR_LAST,
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -2431,6 +2431,11 @@ static int nl80211_put_radio(struct wiph
|
||||
if (nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_INDEX, idx))
|
||||
goto nla_put_failure;
|
||||
|
||||
+ if (r->antenna_mask &&
|
||||
+ nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
|
||||
+ r->antenna_mask))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
for (i = 0; i < r->n_freq_range; i++) {
|
||||
const struct wiphy_radio_freq_range *range = &r->freq_range[i];
|
||||
|
Loading…
x
Reference in New Issue
Block a user