History

cfg80211: implement APIs for dedicated radar detection HW

If a dedicated (off-channel) radar detection hardware (chain) is available in the hardware/driver, allow this to be used by calling the NL80211_CMD_RADAR_DETECT command with a new flag attribute requesting off-channel radar detection is used. Offchannel CAC (channel availability check) avoids the CAC downtime when switching to a radar channel or when turning on the AP. Drivers advertise support for this using the new feature flag NL80211_EXT_FEATURE_RADAR_OFFCHAN.

Lorenzo Bianconi committed 5 years ago

Commit bc2dfc01 parent 3b1abcf8 files · +214 −6Browse files

Unified · Split

8 files
  1. include/net/cfg80211.h +25 −0
  2. include/uapi/linux/nl80211.h +13 −0
  3. net/wireless/core.c +3 −0
  4. net/wireless/core.h +13 −0
  5. net/wireless/mlme.c +113 −0
  6. net/wireless/nl80211.c +11 −6
  7. net/wireless/rdev-ops.h +17 −0
  8. net/wireless/trace.h +19 −0
include/net/cfg80211.h+25−0
@@ -4072,6 +4072,15 @@ struct mgmt_frame_regs { · 4071 unmodified lines
4072 * @set_fils_aad: Set FILS AAD data to the AP driver so that the driver can use4072 * @set_fils_aad: Set FILS AAD data to the AP driver so that the driver can use
4073 * those to decrypt (Re)Association Request and encrypt (Re)Association4073 * those to decrypt (Re)Association Request and encrypt (Re)Association
4074 * Response frame.4074 * Response frame.
4075 *
4076 * @set_radar_offchan: Configure dedicated offchannel chain available for
4077 * radar/CAC detection on some hw. This chain can't be used to transmit
4078 * or receive frames and it is bounded to a running wdev.
4079 * Offchannel radar/CAC detection allows to avoid the CAC downtime
4080 * switching to a different channel during CAC detection on the selected
4081 * radar channel.
4082 * The caller is expected to set chandef pointer to NULL in order to
4083 * disable offchannel CAC/radar detection.
4075 */4084 */
4076struct cfg80211_ops {4085struct cfg80211_ops {
4077 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);4086 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4404,6 +4413,8 @@ struct cfg80211_ops { · 326 unmodified lines
4404 struct cfg80211_color_change_settings *params);4413 struct cfg80211_color_change_settings *params);
4405 int (*set_fils_aad)(struct wiphy *wiphy, struct net_device *dev,4414 int (*set_fils_aad)(struct wiphy *wiphy, struct net_device *dev,
4406 struct cfg80211_fils_aad *fils_aad);4415 struct cfg80211_fils_aad *fils_aad);
4416 int (*set_radar_offchan)(struct wiphy *wiphy,
4417 struct cfg80211_chan_def *chandef);
4407};4418};
4408 4419
4409/*4420/*
@@ -7633,6 +7644,20 @@ void cfg80211_cac_event(struct net_device *netdev, · 3223 unmodified lines
7633 const struct cfg80211_chan_def *chandef,7644 const struct cfg80211_chan_def *chandef,
7634 enum nl80211_radar_event event, gfp_t gfp);7645 enum nl80211_radar_event event, gfp_t gfp);
7635 7646
7647/**
7648 * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event
7649 * @wiphy: the wiphy
7650 * @chandef: chandef for the current channel
7651 * @event: type of event
7652 *
7653 * This function is called when a Channel Availability Check (CAC) is finished,
7654 * started or aborted by a offchannel dedicated chain.
7655 *
7656 * Note that this acquires the wiphy lock.
7657 */
7658void cfg80211_offchan_cac_event(struct wiphy *wiphy,
7659 const struct cfg80211_chan_def *chandef,
7660 enum nl80211_radar_event event);
7636 7661
7637/**7662/**
7638 * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying7663 * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
include/uapi/linux/nl80211.h+13−0
@@ -2639,6 +2639,13 @@ enum nl80211_commands { · 2638 unmodified lines
2639 * Mandatory parameter for the transmitting interface to enable MBSSID.2639 * Mandatory parameter for the transmitting interface to enable MBSSID.
2640 * Optional for the non-transmitting interfaces.2640 * Optional for the non-transmitting interfaces.
2641 *2641 *
2642 * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for
2643 * radar/CAC detection on some hw. This chain can't be used to transmit
2644 * or receive frames and it is bounded to a running wdev.
2645 * Offchannel radar/CAC detection allows to avoid the CAC downtime
2646 * switching on a different channel during CAC detection on the selected
2647 * radar channel.
2648 *
2642 * @NUM_NL80211_ATTR: total number of nl80211_attrs available2649 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
2643 * @NL80211_ATTR_MAX: highest attribute number currently defined2650 * @NL80211_ATTR_MAX: highest attribute number currently defined
2644 * @__NL80211_ATTR_AFTER_LAST: internal use2651 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3145,6 +3152,8 @@ enum nl80211_attrs { · 500 unmodified lines
3145 NL80211_ATTR_MBSSID_CONFIG,3152 NL80211_ATTR_MBSSID_CONFIG,
3146 NL80211_ATTR_MBSSID_ELEMS,3153 NL80211_ATTR_MBSSID_ELEMS,
3147 3154
3155 NL80211_ATTR_RADAR_OFFCHAN,
3156
3148 /* add attributes here, update the policy in nl80211.c */3157 /* add attributes here, update the policy in nl80211.c */
3149 3158
3150 __NL80211_ATTR_AFTER_LAST,3159 __NL80211_ATTR_AFTER_LAST,
@@ -6051,6 +6060,9 @@ enum nl80211_feature_flags { · 2900 unmodified lines
6051 * frames. Userspace has to share FILS AAD details to the driver by using6060 * frames. Userspace has to share FILS AAD details to the driver by using
6052 * @NL80211_CMD_SET_FILS_AAD.6061 * @NL80211_CMD_SET_FILS_AAD.
6053 *6062 *
6063 * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC
6064 * detection.
6065 *
6054 * @NUM_NL80211_EXT_FEATURES: number of extended features.6066 * @NUM_NL80211_EXT_FEATURES: number of extended features.
6055 * @MAX_NL80211_EXT_FEATURES: highest extended feature index.6067 * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
6056 */6068 */
@@ -6117,6 +6129,7 @@ enum nl80211_ext_feature_index { · 60 unmodified lines
6117 NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,6129 NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
6118 NL80211_EXT_FEATURE_BSS_COLOR,6130 NL80211_EXT_FEATURE_BSS_COLOR,
6119 NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,6131 NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
6132 NL80211_EXT_FEATURE_RADAR_OFFCHAN,
6120 6133
6121 /* add new features before the definition below */6134 /* add new features before the definition below */
6122 NUM_NL80211_EXT_FEATURES,6135 NUM_NL80211_EXT_FEATURES,
net/wireless/core.c+3−0
@@ -545,6 +545,7 @@ use_default_name: · 544 unmodified lines
545 INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work);545 INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work);
546 INIT_WORK(&rdev->conn_work, cfg80211_conn_work);546 INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
547 INIT_WORK(&rdev->event_work, cfg80211_event_work);547 INIT_WORK(&rdev->event_work, cfg80211_event_work);
548 INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work);
548 549
549 init_waitqueue_head(&rdev->dev_wait);550 init_waitqueue_head(&rdev->dev_wait);
550 551
@@ -1207,6 +1208,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, · 656 unmodified lines
1207 1208
1208 cfg80211_pmsr_wdev_down(wdev);1209 cfg80211_pmsr_wdev_down(wdev);
1209 1210
1211 cfg80211_stop_offchan_radar_detection(wdev);
1212
1210 switch (wdev->iftype) {1213 switch (wdev->iftype) {
1211 case NL80211_IFTYPE_ADHOC:1214 case NL80211_IFTYPE_ADHOC:
1212 __cfg80211_leave_ibss(rdev, dev, true);1215 __cfg80211_leave_ibss(rdev, dev, true);
net/wireless/core.h+13−0
@@ -84,6 +84,10 @@ struct cfg80211_registered_device { · 83 unmodified lines
84 84
85 struct delayed_work dfs_update_channels_wk;85 struct delayed_work dfs_update_channels_wk;
86 86
87 struct wireless_dev *offchan_radar_wdev;
88 struct cfg80211_chan_def offchan_radar_chandef;
89 struct delayed_work offchan_cac_work;
90
87 /* netlink port which started critical protocol (0 means not started) */91 /* netlink port which started critical protocol (0 means not started) */
88 u32 crit_proto_nlportid;92 u32 crit_proto_nlportid;
89 93
@@ -491,6 +495,15 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, · 401 unmodified lines
491 495
492void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);496void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
493 497
498int
499cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
500 struct wireless_dev *wdev,
501 struct cfg80211_chan_def *chandef);
502
503void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev);
504
505void cfg80211_offchan_cac_work(struct work_struct *work);
506
494bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,507bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
495 struct ieee80211_channel *chan);508 struct ieee80211_channel *chan);
496 509
net/wireless/mlme.c+113−0
@@ -970,3 +970,116 @@ void cfg80211_cac_event(struct net_device *netdev, · 969 unmodified lines
970 nl80211_radar_notify(rdev, chandef, event, netdev, gfp);970 nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
971}971}
972EXPORT_SYMBOL(cfg80211_cac_event);972EXPORT_SYMBOL(cfg80211_cac_event);
973
974void cfg80211_offchan_cac_work(struct work_struct *work)
975{
976 struct delayed_work *delayed_work = to_delayed_work(work);
977 struct cfg80211_registered_device *rdev;
978
979 rdev = container_of(delayed_work, struct cfg80211_registered_device,
980 offchan_cac_work);
981 cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef,
982 NL80211_RADAR_CAC_FINISHED);
983}
984
985static void
986__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev,
987 struct wireless_dev *wdev,
988 const struct cfg80211_chan_def *chandef,
989 enum nl80211_radar_event event)
990{
991 struct wiphy *wiphy = &rdev->wiphy;
992 struct net_device *netdev;
993
994 lockdep_assert_wiphy(&rdev->wiphy);
995
996 if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev)
997 return;
998
999 switch (event) {
1000 case NL80211_RADAR_CAC_FINISHED:
1001 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
1002 memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef));
1003 queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
1004 cfg80211_sched_dfs_chan_update(rdev);
1005 wdev = rdev->offchan_radar_wdev;
1006 rdev->offchan_radar_wdev = NULL;
1007 break;
1008 case NL80211_RADAR_CAC_ABORTED:
1009 cancel_delayed_work(&rdev->offchan_cac_work);
1010 wdev = rdev->offchan_radar_wdev;
1011 rdev->offchan_radar_wdev = NULL;
1012 break;
1013 case NL80211_RADAR_CAC_STARTED:
1014 WARN_ON(!wdev);
1015 rdev->offchan_radar_wdev = wdev;
1016 break;
1017 default:
1018 return;
1019 }
1020
1021 netdev = wdev ? wdev->netdev : NULL;
1022 nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL);
1023}
1024
1025void cfg80211_offchan_cac_event(struct wiphy *wiphy,
1026 const struct cfg80211_chan_def *chandef,
1027 enum nl80211_radar_event event)
1028{
1029 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1030
1031 wiphy_lock(wiphy);
1032 __cfg80211_offchan_cac_event(rdev, NULL, chandef, event);
1033 wiphy_unlock(wiphy);
1034}
1035EXPORT_SYMBOL(cfg80211_offchan_cac_event);
1036
1037int
1038cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
1039 struct wireless_dev *wdev,
1040 struct cfg80211_chan_def *chandef)
1041{
1042 unsigned int cac_time_ms;
1043 int err;
1044
1045 lockdep_assert_wiphy(&rdev->wiphy);
1046
1047 if (!wiphy_ext_feature_isset(&rdev->wiphy,
1048 NL80211_EXT_FEATURE_RADAR_OFFCHAN))
1049 return -EOPNOTSUPP;
1050
1051 if (rdev->offchan_radar_wdev)
1052 return -EBUSY;
1053
1054 err = rdev_set_radar_offchan(rdev, chandef);
1055 if (err)
1056 return err;
1057
1058 cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef);
1059 if (!cac_time_ms)
1060 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
1061
1062 rdev->offchan_radar_chandef = *chandef;
1063 __cfg80211_offchan_cac_event(rdev, wdev, chandef,
1064 NL80211_RADAR_CAC_STARTED);
1065 queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work,
1066 msecs_to_jiffies(cac_time_ms));
1067
1068 return 0;
1069}
1070
1071void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev)
1072{
1073 struct wiphy *wiphy = wdev->wiphy;
1074 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1075
1076 lockdep_assert_wiphy(wiphy);
1077
1078 if (wdev != rdev->offchan_radar_wdev)
1079 return;
1080
1081 rdev_set_radar_offchan(rdev, NULL);
1082
1083 __cfg80211_offchan_cac_event(rdev, NULL, NULL,
1084 NL80211_RADAR_CAC_ABORTED);
1085}
net/wireless/nl80211.c+11−6
@@ -776,6 +776,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { · 775 unmodified lines
776 [NL80211_ATTR_MBSSID_CONFIG] =776 [NL80211_ATTR_MBSSID_CONFIG] =
777 NLA_POLICY_NESTED(nl80211_mbssid_config_policy),777 NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
778 [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },778 [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
779 [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG },
779};780};
780 781
781/* policy for the key attributes */782/* policy for the key attributes */
@@ -9284,12 +9285,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, · 8502 unmodified lines
9284 if (err)9285 if (err)
9285 return err;9286 return err;
9286 9287
9287 if (netif_carrier_ok(dev))
9288 return -EBUSY;
9289
9290 if (wdev->cac_started)
9291 return -EBUSY;
9292
9293 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);9288 err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
9294 if (err < 0)9289 if (err < 0)
9295 return err;9290 return err;
@@ -9300,6 +9295,16 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, · 4 unmodified lines
9300 if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))9295 if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
9301 return -EINVAL;9296 return -EINVAL;
9302 9297
9298 if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN]))
9299 return cfg80211_start_offchan_radar_detection(rdev, wdev,
9300 &chandef);
9301
9302 if (netif_carrier_ok(dev))
9303 return -EBUSY;
9304
9305 if (wdev->cac_started)
9306 return -EBUSY;
9307
9303 /* CAC start is offloaded to HW and can't be started manually */9308 /* CAC start is offloaded to HW and can't be started manually */
9304 if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))9309 if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
9305 return -EOPNOTSUPP;9310 return -EOPNOTSUPP;
net/wireless/rdev-ops.h+17−0
@@ -1395,4 +1395,21 @@ rdev_set_fils_aad(struct cfg80211_registered_device *rdev, · 1394 unmodified lines
1395 return ret;1395 return ret;
1396}1396}
1397 1397
1398static inline int
1399rdev_set_radar_offchan(struct cfg80211_registered_device *rdev,
1400 struct cfg80211_chan_def *chandef)
1401{
1402 struct wiphy *wiphy = &rdev->wiphy;
1403 int ret;
1404
1405 if (!rdev->ops->set_radar_offchan)
1406 return -EOPNOTSUPP;
1407
1408 trace_rdev_set_radar_offchan(wiphy, chandef);
1409 ret = rdev->ops->set_radar_offchan(wiphy, chandef);
1410 trace_rdev_return_int(wiphy, ret);
1411
1412 return ret;
1413}
1414
1398#endif /* __CFG80211_RDEV_OPS */1415#endif /* __CFG80211_RDEV_OPS */
net/wireless/trace.h+19−0
@@ -3674,6 +3674,25 @@ TRACE_EVENT(cfg80211_bss_color_notify, · 3673 unmodified lines
3674 __entry->color_bitmap)3674 __entry->color_bitmap)
3675);3675);
3676 3676
3677TRACE_EVENT(rdev_set_radar_offchan,
3678 TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
3679
3680 TP_ARGS(wiphy, chandef),
3681
3682 TP_STRUCT__entry(
3683 WIPHY_ENTRY
3684 CHAN_DEF_ENTRY
3685 ),
3686
3687 TP_fast_assign(
3688 WIPHY_ASSIGN;
3689 CHAN_DEF_ASSIGN(chandef)
3690 ),
3691
3692 TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
3693 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
3694);
3695
3677#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */3696#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
3678 3697
3679#undef TRACE_INCLUDE_PATH3698#undef TRACE_INCLUDE_PATH