@@ -2639,6 +2639,13 @@ enum nl80211_commands {
* Mandatory parameter for the transmitting interface to enable MBSSID.
* Optional for the non-transmitting interfaces.
*
+ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for
+ * radar/CAC detection on some hw. This chain can't be used to transmit
+ * or receive frames and it is bounded to a running wdev.
+ * Offchannel radar/CAC detection allows to avoid the CAC downtime
+ * switching on a different channel during CAC detection on the selected
+ * radar channel.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3145,6 +3152,8 @@ enum nl80211_attrs {
NL80211_ATTR_MBSSID_CONFIG,
NL80211_ATTR_MBSSID_ELEMS,
+ NL80211_ATTR_RADAR_OFFCHAN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -25,6 +25,8 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
if (!wdev->beacon_interval)
return -ENOENT;
+ cfg80211_stop_offchan_radar_detection(rdev);
+
err = rdev_stop_ap(rdev, dev);
if (!err) {
wdev->conn_owner_nlportid = 0;
@@ -498,6 +498,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
}
mutex_init(&rdev->wiphy.mtx);
+ mutex_init(&rdev->offchan_mutex);
INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations);
spin_lock_init(&rdev->beacon_registrations_lock);
@@ -84,6 +84,9 @@ struct cfg80211_registered_device {
struct delayed_work dfs_update_channels_wk;
+ struct mutex offchan_mutex; /* protect offchan_radar_wdev */
+ struct wireless_dev *offchan_radar_wdev;
+
/* netlink port which started critical protocol (0 means not started) */
u32 crit_proto_nlportid;
@@ -489,6 +492,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
+int
+cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef);
+
+int
+cfg80211_stop_offchan_radar_detection(struct cfg80211_registered_device *rdev);
+
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan);
@@ -968,3 +968,43 @@ void cfg80211_cac_event(struct net_device *netdev,
nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
}
EXPORT_SYMBOL(cfg80211_cac_event);
+
+int
+cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
+{
+ int err = -EBUSY;
+
+ mutex_lock(&rdev->offchan_mutex);
+ if (rdev->offchan_radar_wdev)
+ goto out;
+
+ err = rdev_set_radar_offchan(rdev, chandef);
+ if (err)
+ goto out;
+
+ rdev->offchan_radar_wdev = wdev;
+out:
+ mutex_unlock(&rdev->offchan_mutex);
+ return err;
+}
+
+int
+cfg80211_stop_offchan_radar_detection(struct cfg80211_registered_device *rdev)
+{
+ int err = 0;
+
+ mutex_lock(&rdev->offchan_mutex);
+ if (!rdev->offchan_radar_wdev)
+ goto out;
+
+ err = rdev_set_radar_offchan(rdev, NULL);
+ if (err)
+ goto out;
+
+ rdev->offchan_radar_wdev = NULL;
+out:
+ mutex_unlock(&rdev->offchan_mutex);
+ return err;
+}
@@ -776,6 +776,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MBSSID_CONFIG] =
NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -9280,12 +9281,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (err)
return err;
- if (netif_carrier_ok(dev))
- return -EBUSY;
-
- if (wdev->cac_started)
- return -EBUSY;
-
err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
if (err < 0)
return err;
@@ -9296,6 +9291,16 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
return -EINVAL;
+ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN]))
+ return cfg80211_start_offchan_radar_detection(rdev, wdev,
+ &chandef);
+
+ if (netif_carrier_ok(dev))
+ return -EBUSY;
+
+ if (wdev->cac_started)
+ return -EBUSY;
+
/* CAC start is offloaded to HW and can't be started manually */
if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
return -EOPNOTSUPP;
Introduce NL80211_ATTR_RADAR_OFFCHAN netlink attribute in order to configure a offchannel radar chain if supported by the underlay driver. Since the offchannel chain is commonly shared between multiple wireless devices, offchan_radar_wdev pointer refers to the current owner of the chain. Offchannel can't be used by multiple wdev at the same time. Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> --- include/uapi/linux/nl80211.h | 9 ++++++++ net/wireless/ap.c | 2 ++ net/wireless/core.c | 1 + net/wireless/core.h | 11 ++++++++++ net/wireless/mlme.c | 40 ++++++++++++++++++++++++++++++++++++ net/wireless/nl80211.c | 17 +++++++++------ 6 files changed, 74 insertions(+), 6 deletions(-)