summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h3
-rw-r--r--include/uapi/linux/nl80211.h6
-rw-r--r--net/wireless/chan.c27
-rw-r--r--net/wireless/core.h4
-rw-r--r--net/wireless/mlme.c7
-rw-r--r--net/wireless/nl80211.c7
6 files changed, 54 insertions, 0 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fc01de19c798..e00045c150e7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -190,6 +190,8 @@ enum ieee80211_channel_flags {
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
+ * @cac_start_time: timestamp (CLOCK_BOOTTIME, nanoseconds) when CAC was
+ * started on this channel. Zero when CAC is not in progress.
* @psd: power spectral density (in dBm)
*/
struct ieee80211_channel {
@@ -207,6 +209,7 @@ struct ieee80211_channel {
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
unsigned int dfs_cac_ms;
+ u64 cac_start_time;
s8 psd;
};
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b63f71850906..c75aa039f096 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4480,6 +4480,10 @@ enum nl80211_wmm_rule {
* as a non-primary subchannel. Only applicable to S1G channels.
* @NL80211_FREQUENCY_ATTR_NO_UHR: UHR operation is not allowed on this channel
* in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_CAC_START_TIME: Channel Availability Check (CAC)
+ * start time (CLOCK_BOOTTIME, nanoseconds). Only present when CAC is
+ * currently in progress on this channel.
+ * @NL80211_FREQUENCY_ATTR_PAD: attribute used for padding for 64-bit alignment
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -4530,6 +4534,8 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_16MHZ,
NL80211_FREQUENCY_ATTR_S1G_NO_PRIMARY,
NL80211_FREQUENCY_ATTR_NO_UHR,
+ NL80211_FREQUENCY_ATTR_CAC_START_TIME,
+ NL80211_FREQUENCY_ATTR_PAD,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 68221b1ab45e..dfe319565280 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -642,6 +642,33 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
}
}
+void cfg80211_set_cac_state(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef,
+ bool cac_ongoing)
+{
+ struct ieee80211_channel *c;
+ int width;
+ u64 cac_time;
+
+ if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+ return;
+
+ width = cfg80211_chandef_get_width(chandef);
+ if (width < 0)
+ return;
+
+ /* Get the same timestamp for all subchannels */
+ cac_time = cac_ongoing ? ktime_get_boottime_ns() : 0;
+
+ for_each_subchan(chandef, freq, cf) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
+ if (!c)
+ continue;
+
+ c->cac_start_time = cac_time;
+ }
+}
+
static bool
cfg80211_dfs_permissive_check_wdev(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6ac57b7b2615..6cace846d7a3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -481,6 +481,10 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef,
enum nl80211_dfs_state dfs_state);
+void cfg80211_set_cac_state(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef,
+ bool cac_ongoing);
+
void cfg80211_dfs_channels_update_work(struct work_struct *work);
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 212178d04efa..283ea4c7c61e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -1162,9 +1162,11 @@ void cfg80211_cac_event(struct net_device *netdev,
fallthrough;
case NL80211_RADAR_CAC_ABORTED:
wdev->links[link_id].cac_started = false;
+ cfg80211_set_cac_state(wiphy, chandef, false);
break;
case NL80211_RADAR_CAC_STARTED:
wdev->links[link_id].cac_started = true;
+ cfg80211_set_cac_state(wiphy, chandef, true);
break;
default:
WARN_ON(1);
@@ -1192,15 +1194,18 @@ __cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
switch (event) {
case NL80211_RADAR_CAC_FINISHED:
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
+ cfg80211_set_cac_state(wiphy, chandef, false);
memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef));
queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
cfg80211_sched_dfs_chan_update(rdev);
break;
case NL80211_RADAR_CAC_ABORTED:
+ cfg80211_set_cac_state(wiphy, chandef, false);
if (!cancel_delayed_work(&rdev->background_cac_done_wk))
return;
break;
case NL80211_RADAR_CAC_STARTED:
+ cfg80211_set_cac_state(wiphy, chandef, true);
break;
default:
return;
@@ -1307,6 +1312,8 @@ void cfg80211_stop_radar_detection(struct wireless_dev *wdev)
chandef = *wdev_chandef(wdev, link_id);
rdev_end_cac(rdev, wdev->netdev, link_id);
+ wdev->links[link_id].cac_started = false;
+ cfg80211_set_cac_state(wiphy, &chandef, false);
nl80211_radar_notify(rdev, &chandef, NL80211_RADAR_CAC_ABORTED,
wdev->netdev, GFP_KERNEL);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b94231c8441c..7e288d3ce5ae 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1333,6 +1333,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
if ((chan->flags & IEEE80211_CHAN_NO_UHR) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_UHR))
goto nla_put_failure;
+ if (chan->cac_start_time &&
+ nla_put_u64_64bit(msg,
+ NL80211_FREQUENCY_ATTR_CAC_START_TIME,
+ chan->cac_start_time,
+ NL80211_FREQUENCY_ATTR_PAD))
+ goto nla_put_failure;
}
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
@@ -11353,6 +11359,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
wdev->links[link_id].cac_started = true;
wdev->links[link_id].cac_start_time = jiffies;
wdev->links[link_id].cac_time_ms = cac_time_ms;
+ cfg80211_set_cac_state(wiphy, &chandef, true);
return 0;
}