|
@@ -552,9 +552,16 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
|
|
|
if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
|
|
|
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
|
|
|
goto nla_put_failure;
|
|
|
- if ((chan->flags & IEEE80211_CHAN_RADAR) &&
|
|
|
- nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
|
|
|
- goto nla_put_failure;
|
|
|
+ if (chan->flags & IEEE80211_CHAN_RADAR) {
|
|
|
+ u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
|
|
|
+ if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
|
|
|
+ goto nla_put_failure;
|
|
|
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
|
|
|
+ chan->dfs_state))
|
|
|
+ goto nla_put_failure;
|
|
|
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
|
|
|
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
|
|
|
DBM_TO_MBM(chan->max_power)))
|
|
@@ -2775,6 +2782,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
struct cfg80211_ap_settings params;
|
|
|
int err;
|
|
|
+ u8 radar_detect_width = 0;
|
|
|
|
|
|
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
|
|
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
|
@@ -2893,9 +2901,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef))
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ if (err) {
|
|
|
+ radar_detect_width = BIT(params.chandef.width);
|
|
|
+ params.radar_required = true;
|
|
|
+ }
|
|
|
+
|
|
|
mutex_lock(&rdev->devlist_mtx);
|
|
|
- err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan,
|
|
|
- CHAN_MODE_SHARED);
|
|
|
+ err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
|
|
|
+ params.chandef.chan,
|
|
|
+ CHAN_MODE_SHARED,
|
|
|
+ radar_detect_width);
|
|
|
mutex_unlock(&rdev->devlist_mtx);
|
|
|
|
|
|
if (err)
|
|
@@ -5055,6 +5073,54 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int nl80211_start_radar_detection(struct sk_buff *skb,
|
|
|
+ struct genl_info *info)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+ struct net_device *dev = info->user_ptr[1];
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
+ struct cfg80211_chan_def chandef;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = nl80211_parse_chandef(rdev, info, &chandef);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (wdev->cac_started)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (err == 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!rdev->ops->start_radar_detection)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ mutex_lock(&rdev->devlist_mtx);
|
|
|
+ err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
|
|
|
+ chandef.chan, CHAN_MODE_SHARED,
|
|
|
+ BIT(chandef.width));
|
|
|
+ if (err)
|
|
|
+ goto err_locked;
|
|
|
+
|
|
|
+ err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
|
|
|
+ if (!err) {
|
|
|
+ wdev->channel = chandef.chan;
|
|
|
+ wdev->cac_started = true;
|
|
|
+ wdev->cac_start_time = jiffies;
|
|
|
+ }
|
|
|
+err_locked:
|
|
|
+ mutex_unlock(&rdev->devlist_mtx);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
|
|
|
u32 seq, int flags,
|
|
|
struct cfg80211_registered_device *rdev,
|
|
@@ -8305,6 +8371,14 @@ static struct genl_ops nl80211_ops[] = {
|
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
|
|
NL80211_FLAG_NEED_RTNL,
|
|
|
},
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_RADAR_DETECT,
|
|
|
+ .doit = nl80211_start_radar_detection,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
|
@@ -9501,6 +9575,57 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
|
|
|
nlmsg_free(msg);
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
|
|
+ struct cfg80211_chan_def *chandef,
|
|
|
+ enum nl80211_radar_event event,
|
|
|
+ struct net_device *netdev, gfp_t gfp)
|
|
|
+{
|
|
|
+ struct sk_buff *msg;
|
|
|
+ void *hdr;
|
|
|
+
|
|
|
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
|
|
+ if (!msg)
|
|
|
+ return;
|
|
|
+
|
|
|
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
|
|
|
+ if (!hdr) {
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ /* NOP and radar events don't need a netdev parameter */
|
|
|
+ if (netdev) {
|
|
|
+ struct wireless_dev *wdev = netdev->ieee80211_ptr;
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
|
|
+ nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ if (nl80211_send_chandef(msg, chandef))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ if (genlmsg_end(msg, hdr) < 0) {
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
|
|
+ nl80211_mlme_mcgrp.id, gfp);
|
|
|
+ return;
|
|
|
+
|
|
|
+ nla_put_failure:
|
|
|
+ genlmsg_cancel(msg, hdr);
|
|
|
+ nlmsg_free(msg);
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
|
|
struct net_device *netdev, const u8 *peer,
|