developer | 94abd9f | 2021-12-09 15:21:27 +0800 | [diff] [blame] | 1 | diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh |
| 2 | index 27eecf3..ff3169c 100644 |
| 3 | --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh |
| 4 | +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh |
| 5 | @@ -61,7 +61,8 @@ drv_mac80211_init_device_config() { |
| 6 | rx_stbc \ |
| 7 | tx_stbc \ |
| 8 | he_bss_color \ |
| 9 | - he_spr_non_srg_obss_pd_max_offset |
| 10 | + he_spr_non_srg_obss_pd_max_offset \ |
| 11 | + radar_offchan |
| 12 | config_add_boolean \ |
| 13 | ldpc \ |
| 14 | greenfield \ |
| 15 | @@ -137,12 +138,9 @@ mac80211_hostapd_setup_base() { |
| 16 | [ -n "$acs_exclude_dfs" ] && [ "$acs_exclude_dfs" -gt 0 ] && |
| 17 | append base_cfg "acs_exclude_dfs=1" "$N" |
| 18 | |
| 19 | - json_get_vars noscan ht_coex |
| 20 | + json_get_vars noscan ht_coex radar_offchan:0 |
| 21 | json_get_values ht_capab_list ht_capab tx_burst |
| 22 | - json_get_values channel_list channels |
| 23 | - |
| 24 | - [ "$auto_channel" = 0 ] && [ -z "$channel_list" ] && \ |
| 25 | - channel_list="$channel" |
| 26 | + json_get_values channels |
| 27 | |
| 28 | set_default noscan 0 |
| 29 | |
| 30 | @@ -462,10 +460,11 @@ mac80211_hostapd_setup_base() { |
| 31 | append base_cfg "he_mu_edca_ac_vo_timer=255" "$N" |
| 32 | fi |
| 33 | |
| 34 | + append base_cfg "radar_offchan=$radar_offchan" "$N" |
| 35 | + |
| 36 | hostapd_prepare_device_config "$hostapd_conf_file" nl80211 |
| 37 | cat >> "$hostapd_conf_file" <<EOF |
| 38 | ${channel:+channel=$channel} |
| 39 | -${channel_list:+chanlist=$channel_list} |
| 40 | ${hostapd_noscan:+noscan=1} |
| 41 | ${tx_burst:+tx_queue_data2_burst=$tx_burst} |
| 42 | $base_cfg |
| 43 | diff --git a/package/kernel/mac80211/patches/subsys/900-mac80211-zero-wait-dfs.patch b/package/kernel/mac80211/patches/subsys/900-mac80211-zero-wait-dfs.patch |
| 44 | new file mode 100644 |
| 45 | index 0000000..ba3ac4b |
| 46 | --- /dev/null |
| 47 | +++ b/package/kernel/mac80211/patches/subsys/900-mac80211-zero-wait-dfs.patch |
| 48 | @@ -0,0 +1,667 @@ |
| 49 | +diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h |
| 50 | +index 080d220..6278545 100644 |
| 51 | +--- a/include/net/cfg80211.h |
| 52 | ++++ b/include/net/cfg80211.h |
| 53 | +@@ -4024,6 +4024,15 @@ struct mgmt_frame_regs { |
| 54 | + * @set_sar_specs: Update the SAR (TX power) settings. |
| 55 | + * |
| 56 | + * @color_change: Initiate a color change. |
| 57 | ++ * |
| 58 | ++ * @set_radar_offchan: Configure dedicated offchannel chain available for |
| 59 | ++ * radar/CAC detection on some hw. This chain can't be used to transmit |
| 60 | ++ * or receive frames and it is bounded to a running wdev. |
| 61 | ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime |
| 62 | ++ * switching to a different channel during CAC detection on the selected |
| 63 | ++ * radar channel. |
| 64 | ++ * The caller is expected to set chandef pointer to NULL in order to |
| 65 | ++ * disable offchannel CAC/radar detection. |
| 66 | + */ |
| 67 | + struct cfg80211_ops { |
| 68 | + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
| 69 | +@@ -4355,6 +4364,8 @@ struct cfg80211_ops { |
| 70 | + int (*color_change)(struct wiphy *wiphy, |
| 71 | + struct net_device *dev, |
| 72 | + struct cfg80211_color_change_settings *params); |
| 73 | ++ int (*set_radar_offchan)(struct wiphy *wiphy, |
| 74 | ++ struct cfg80211_chan_def *chandef); |
| 75 | + }; |
| 76 | + |
| 77 | + /* |
| 78 | +@@ -7529,15 +7540,33 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, |
| 79 | + void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); |
| 80 | + |
| 81 | + /** |
| 82 | +- * cfg80211_radar_event - radar detection event |
| 83 | ++ * __cfg80211_radar_event - radar detection event |
| 84 | + * @wiphy: the wiphy |
| 85 | + * @chandef: chandef for the current channel |
| 86 | ++ * @offchan: the radar has been detected on the offchannel chain |
| 87 | + * @gfp: context flags |
| 88 | + * |
| 89 | + * This function is called when a radar is detected on the current chanenl. |
| 90 | + */ |
| 91 | +-void cfg80211_radar_event(struct wiphy *wiphy, |
| 92 | +- struct cfg80211_chan_def *chandef, gfp_t gfp); |
| 93 | ++void __cfg80211_radar_event(struct wiphy *wiphy, |
| 94 | ++ struct cfg80211_chan_def *chandef, |
| 95 | ++ bool offchan, gfp_t gfp); |
| 96 | ++ |
| 97 | ++static inline void |
| 98 | ++cfg80211_radar_event(struct wiphy *wiphy, |
| 99 | ++ struct cfg80211_chan_def *chandef, |
| 100 | ++ gfp_t gfp) |
| 101 | ++{ |
| 102 | ++ __cfg80211_radar_event(wiphy, chandef, false, gfp); |
| 103 | ++} |
| 104 | ++ |
| 105 | ++static inline void |
| 106 | ++cfg80211_offchan_radar_event(struct wiphy *wiphy, |
| 107 | ++ struct cfg80211_chan_def *chandef, |
| 108 | ++ gfp_t gfp) |
| 109 | ++{ |
| 110 | ++ __cfg80211_radar_event(wiphy, chandef, true, gfp); |
| 111 | ++} |
| 112 | + |
| 113 | + /** |
| 114 | + * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event |
| 115 | +@@ -7568,6 +7597,14 @@ void cfg80211_cac_event(struct net_device *netdev, |
| 116 | + const struct cfg80211_chan_def *chandef, |
| 117 | + enum nl80211_radar_event event, gfp_t gfp); |
| 118 | + |
| 119 | ++/** |
| 120 | ++ * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event |
| 121 | ++ * @wiphy: the wiphy |
| 122 | ++ * |
| 123 | ++ * This function is called by the driver when a Channel Availability Check |
| 124 | ++ * (CAC) is aborted by a offchannel dedicated chain. |
| 125 | ++ */ |
| 126 | ++void cfg80211_offchan_cac_abort(struct wiphy *wiphy); |
| 127 | + |
| 128 | + /** |
| 129 | + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying |
| 130 | +diff --git a/include/net/mac80211.h b/include/net/mac80211.h |
| 131 | +index afab7ec..acf637d 100644 |
| 132 | +--- a/include/net/mac80211.h |
| 133 | ++++ b/include/net/mac80211.h |
| 134 | +@@ -3939,6 +3939,14 @@ struct ieee80211_prep_tx_info { |
| 135 | + * twt structure. |
| 136 | + * @twt_teardown_request: Update the hw with TWT teardown request received |
| 137 | + * from the peer. |
| 138 | ++ * @set_radar_offchan: Configure dedicated offchannel chain available for |
| 139 | ++ * radar/CAC detection on some hw. This chain can't be used to transmit |
| 140 | ++ * or receive frames and it is bounded to a running wdev. |
| 141 | ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime |
| 142 | ++ * switching to a different channel during CAC detection on the selected |
| 143 | ++ * radar channel. |
| 144 | ++ * The caller is expected to set chandef pointer to NULL in order to |
| 145 | ++ * disable offchannel CAC/radar detection. |
| 146 | + */ |
| 147 | + struct ieee80211_ops { |
| 148 | + void (*tx)(struct ieee80211_hw *hw, |
| 149 | +@@ -4267,6 +4275,8 @@ struct ieee80211_ops { |
| 150 | + struct ieee80211_twt_setup *twt); |
| 151 | + void (*twt_teardown_request)(struct ieee80211_hw *hw, |
| 152 | + struct ieee80211_sta *sta, u8 flowid); |
| 153 | ++ int (*set_radar_offchan)(struct ieee80211_hw *hw, |
| 154 | ++ struct cfg80211_chan_def *chandef); |
| 155 | + }; |
| 156 | + |
| 157 | + /** |
| 158 | +diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h |
| 159 | +index 5f4a094..7634ba0 100644 |
| 160 | +--- a/include/uapi/linux/nl80211.h |
| 161 | ++++ b/include/uapi/linux/nl80211.h |
| 162 | +@@ -2596,6 +2596,13 @@ enum nl80211_commands { |
| 163 | + * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce |
| 164 | + * transmit power to stay within regulatory limits. u32, dBi. |
| 165 | + * |
| 166 | ++ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for |
| 167 | ++ * radar/CAC detection on some hw. This chain can't be used to transmit |
| 168 | ++ * or receive frames and it is bounded to a running wdev. |
| 169 | ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime |
| 170 | ++ * switching on a different channel during CAC detection on the selected |
| 171 | ++ * radar channel. |
| 172 | ++ * |
| 173 | + * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
| 174 | + * @NL80211_ATTR_MAX: highest attribute number currently defined |
| 175 | + * @__NL80211_ATTR_AFTER_LAST: internal use |
| 176 | +@@ -3101,6 +3108,8 @@ enum nl80211_attrs { |
| 177 | + |
| 178 | + NL80211_ATTR_WIPHY_ANTENNA_GAIN, |
| 179 | + |
| 180 | ++ NL80211_ATTR_RADAR_OFFCHAN, |
| 181 | ++ |
| 182 | + /* add attributes here, update the policy in nl80211.c */ |
| 183 | + |
| 184 | + __NL80211_ATTR_AFTER_LAST, |
| 185 | +@@ -6000,6 +6009,9 @@ enum nl80211_feature_flags { |
| 186 | + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision |
| 187 | + * detection and change announcemnts. |
| 188 | + * |
| 189 | ++ * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC |
| 190 | ++ * detection. |
| 191 | ++ * |
| 192 | + * @NUM_NL80211_EXT_FEATURES: number of extended features. |
| 193 | + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
| 194 | + */ |
| 195 | +@@ -6065,6 +6077,7 @@ enum nl80211_ext_feature_index { |
| 196 | + NL80211_EXT_FEATURE_SECURE_RTT, |
| 197 | + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, |
| 198 | + NL80211_EXT_FEATURE_BSS_COLOR, |
| 199 | ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN, |
| 200 | + |
| 201 | + /* add new features before the definition below */ |
| 202 | + NUM_NL80211_EXT_FEATURES, |
| 203 | +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c |
| 204 | +index 8b7c12a..887af1e 100644 |
| 205 | +--- a/net/mac80211/cfg.c |
| 206 | ++++ b/net/mac80211/cfg.c |
| 207 | +@@ -4353,6 +4353,18 @@ out: |
| 208 | + return err; |
| 209 | + } |
| 210 | + |
| 211 | ++static int |
| 212 | ++ieee80211_set_radar_offchan(struct wiphy *wiphy, |
| 213 | ++ struct cfg80211_chan_def *chandef) |
| 214 | ++{ |
| 215 | ++ struct ieee80211_local *local = wiphy_priv(wiphy); |
| 216 | ++ |
| 217 | ++ if (!local->ops->set_radar_offchan) |
| 218 | ++ return -EOPNOTSUPP; |
| 219 | ++ |
| 220 | ++ return local->ops->set_radar_offchan(&local->hw, chandef); |
| 221 | ++} |
| 222 | ++ |
| 223 | + const struct cfg80211_ops mac80211_config_ops = { |
| 224 | + .add_virtual_intf = ieee80211_add_iface, |
| 225 | + .del_virtual_intf = ieee80211_del_iface, |
| 226 | +@@ -4458,4 +4470,5 @@ const struct cfg80211_ops mac80211_config_ops = { |
| 227 | + .reset_tid_config = ieee80211_reset_tid_config, |
| 228 | + .set_sar_specs = ieee80211_set_sar_specs, |
| 229 | + .color_change = ieee80211_color_change, |
| 230 | ++ .set_radar_offchan = ieee80211_set_radar_offchan, |
| 231 | + }; |
| 232 | +diff --git a/net/wireless/chan.c b/net/wireless/chan.c |
| 233 | +index 1382a5f..75b4151 100644 |
| 234 | +--- a/net/wireless/chan.c |
| 235 | ++++ b/net/wireless/chan.c |
| 236 | +@@ -712,6 +712,20 @@ static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, |
| 237 | + return false; |
| 238 | + } |
| 239 | + |
| 240 | ++static bool |
| 241 | ++cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, |
| 242 | ++ struct ieee80211_channel *channel) |
| 243 | ++{ |
| 244 | ++ |
| 245 | ++ if (!rdev->offchan_radar_wdev) |
| 246 | ++ return false; |
| 247 | ++ |
| 248 | ++ if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) |
| 249 | ++ return false; |
| 250 | ++ |
| 251 | ++ return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); |
| 252 | ++} |
| 253 | ++ |
| 254 | + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, |
| 255 | + struct ieee80211_channel *chan) |
| 256 | + { |
| 257 | +@@ -728,6 +742,9 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, |
| 258 | + |
| 259 | + if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan)) |
| 260 | + return true; |
| 261 | ++ |
| 262 | ++ if (cfg80211_offchan_chain_is_active(rdev, chan)) |
| 263 | ++ return true; |
| 264 | + } |
| 265 | + |
| 266 | + return false; |
| 267 | +diff --git a/net/wireless/core.c b/net/wireless/core.c |
| 268 | +index b181dad..378fb4e 100644 |
| 269 | +--- a/net/wireless/core.c |
| 270 | ++++ b/net/wireless/core.c |
| 271 | +@@ -551,6 +551,9 @@ use_default_name: |
| 272 | + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); |
| 273 | + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); |
| 274 | + INIT_WORK(&rdev->event_work, cfg80211_event_work); |
| 275 | ++ INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); |
| 276 | ++ INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, |
| 277 | ++ cfg80211_offchan_cac_done_wk); |
| 278 | + |
| 279 | + init_waitqueue_head(&rdev->dev_wait); |
| 280 | + |
| 281 | +@@ -1045,11 +1048,13 @@ void wiphy_unregister(struct wiphy *wiphy) |
| 282 | + cancel_work_sync(&rdev->conn_work); |
| 283 | + flush_work(&rdev->event_work); |
| 284 | + cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
| 285 | ++ cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); |
| 286 | + flush_work(&rdev->destroy_work); |
| 287 | + flush_work(&rdev->sched_scan_stop_wk); |
| 288 | + flush_work(&rdev->propagate_radar_detect_wk); |
| 289 | + flush_work(&rdev->propagate_cac_done_wk); |
| 290 | + flush_work(&rdev->mgmt_registrations_update_wk); |
| 291 | ++ flush_work(&rdev->offchan_cac_abort_wk); |
| 292 | + |
| 293 | + #ifdef CONFIG_PM |
| 294 | + if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) |
| 295 | +@@ -1188,6 +1193,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, |
| 296 | + |
| 297 | + cfg80211_pmsr_wdev_down(wdev); |
| 298 | + |
| 299 | ++ cfg80211_stop_offchan_radar_detection(wdev); |
| 300 | ++ |
| 301 | + switch (wdev->iftype) { |
| 302 | + case NL80211_IFTYPE_ADHOC: |
| 303 | + __cfg80211_leave_ibss(rdev, dev, true); |
| 304 | +diff --git a/net/wireless/core.h b/net/wireless/core.h |
| 305 | +index 19fcdd7..7fe31aa 100644 |
| 306 | +--- a/net/wireless/core.h |
| 307 | ++++ b/net/wireless/core.h |
| 308 | +@@ -84,6 +84,11 @@ struct cfg80211_registered_device { |
| 309 | + |
| 310 | + struct delayed_work dfs_update_channels_wk; |
| 311 | + |
| 312 | ++ struct wireless_dev *offchan_radar_wdev; |
| 313 | ++ struct cfg80211_chan_def offchan_radar_chandef; |
| 314 | ++ struct delayed_work offchan_cac_done_wk; |
| 315 | ++ struct work_struct offchan_cac_abort_wk; |
| 316 | ++ |
| 317 | + /* netlink port which started critical protocol (0 means not started) */ |
| 318 | + u32 crit_proto_nlportid; |
| 319 | + |
| 320 | +@@ -489,6 +494,17 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, |
| 321 | + |
| 322 | + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); |
| 323 | + |
| 324 | ++int |
| 325 | ++cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, |
| 326 | ++ struct wireless_dev *wdev, |
| 327 | ++ struct cfg80211_chan_def *chandef); |
| 328 | ++ |
| 329 | ++void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); |
| 330 | ++ |
| 331 | ++void cfg80211_offchan_cac_done_wk(struct work_struct *work); |
| 332 | ++ |
| 333 | ++void cfg80211_offchan_cac_abort_wk(struct work_struct *work); |
| 334 | ++ |
| 335 | + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, |
| 336 | + struct ieee80211_channel *chan); |
| 337 | + |
| 338 | +diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c |
| 339 | +index a8a17b9..8f230d3 100644 |
| 340 | +--- a/net/wireless/mlme.c |
| 341 | ++++ b/net/wireless/mlme.c |
| 342 | +@@ -903,13 +903,13 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) |
| 343 | + } |
| 344 | + |
| 345 | + |
| 346 | +-void cfg80211_radar_event(struct wiphy *wiphy, |
| 347 | +- struct cfg80211_chan_def *chandef, |
| 348 | +- gfp_t gfp) |
| 349 | ++void __cfg80211_radar_event(struct wiphy *wiphy, |
| 350 | ++ struct cfg80211_chan_def *chandef, |
| 351 | ++ bool offchan, gfp_t gfp) |
| 352 | + { |
| 353 | + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 354 | + |
| 355 | +- trace_cfg80211_radar_event(wiphy, chandef); |
| 356 | ++ trace_cfg80211_radar_event(wiphy, chandef, offchan); |
| 357 | + |
| 358 | + /* only set the chandef supplied channel to unavailable, in |
| 359 | + * case the radar is detected on only one of multiple channels |
| 360 | +@@ -917,6 +917,9 @@ void cfg80211_radar_event(struct wiphy *wiphy, |
| 361 | + */ |
| 362 | + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); |
| 363 | + |
| 364 | ++ if (offchan) |
| 365 | ++ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); |
| 366 | ++ |
| 367 | + cfg80211_sched_dfs_chan_update(rdev); |
| 368 | + |
| 369 | + nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); |
| 370 | +@@ -924,7 +927,7 @@ void cfg80211_radar_event(struct wiphy *wiphy, |
| 371 | + memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def)); |
| 372 | + queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); |
| 373 | + } |
| 374 | +-EXPORT_SYMBOL(cfg80211_radar_event); |
| 375 | ++EXPORT_SYMBOL(__cfg80211_radar_event); |
| 376 | + |
| 377 | + void cfg80211_cac_event(struct net_device *netdev, |
| 378 | + const struct cfg80211_chan_def *chandef, |
| 379 | +@@ -968,3 +971,142 @@ void cfg80211_cac_event(struct net_device *netdev, |
| 380 | + nl80211_radar_notify(rdev, chandef, event, netdev, gfp); |
| 381 | + } |
| 382 | + EXPORT_SYMBOL(cfg80211_cac_event); |
| 383 | ++ |
| 384 | ++static void |
| 385 | ++__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, |
| 386 | ++ struct wireless_dev *wdev, |
| 387 | ++ const struct cfg80211_chan_def *chandef, |
| 388 | ++ enum nl80211_radar_event event) |
| 389 | ++{ |
| 390 | ++ struct wiphy *wiphy = &rdev->wiphy; |
| 391 | ++ struct net_device *netdev; |
| 392 | ++ |
| 393 | ++ lockdep_assert_wiphy(&rdev->wiphy); |
| 394 | ++ |
| 395 | ++ if (!cfg80211_chandef_valid(chandef)) |
| 396 | ++ return; |
| 397 | ++ |
| 398 | ++ if (!rdev->offchan_radar_wdev) |
| 399 | ++ return; |
| 400 | ++ |
| 401 | ++ switch (event) { |
| 402 | ++ case NL80211_RADAR_CAC_FINISHED: |
| 403 | ++ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); |
| 404 | ++ memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); |
| 405 | ++ queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); |
| 406 | ++ cfg80211_sched_dfs_chan_update(rdev); |
| 407 | ++ wdev = rdev->offchan_radar_wdev; |
| 408 | ++ break; |
| 409 | ++ case NL80211_RADAR_CAC_ABORTED: |
| 410 | ++ if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) |
| 411 | ++ return; |
| 412 | ++ wdev = rdev->offchan_radar_wdev; |
| 413 | ++ break; |
| 414 | ++ case NL80211_RADAR_CAC_STARTED: |
| 415 | ++ break; |
| 416 | ++ default: |
| 417 | ++ return; |
| 418 | ++ } |
| 419 | ++ |
| 420 | ++ netdev = wdev ? wdev->netdev : NULL; |
| 421 | ++ nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); |
| 422 | ++} |
| 423 | ++ |
| 424 | ++static void |
| 425 | ++cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, |
| 426 | ++ const struct cfg80211_chan_def *chandef, |
| 427 | ++ enum nl80211_radar_event event) |
| 428 | ++{ |
| 429 | ++ wiphy_lock(&rdev->wiphy); |
| 430 | ++ __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, |
| 431 | ++ chandef, event); |
| 432 | ++ wiphy_unlock(&rdev->wiphy); |
| 433 | ++} |
| 434 | ++ |
| 435 | ++void cfg80211_offchan_cac_done_wk(struct work_struct *work) |
| 436 | ++{ |
| 437 | ++ struct delayed_work *delayed_work = to_delayed_work(work); |
| 438 | ++ struct cfg80211_registered_device *rdev; |
| 439 | ++ |
| 440 | ++ rdev = container_of(delayed_work, struct cfg80211_registered_device, |
| 441 | ++ offchan_cac_done_wk); |
| 442 | ++ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, |
| 443 | ++ NL80211_RADAR_CAC_FINISHED); |
| 444 | ++} |
| 445 | ++ |
| 446 | ++void cfg80211_offchan_cac_abort_wk(struct work_struct *work) |
| 447 | ++{ |
| 448 | ++ struct cfg80211_registered_device *rdev; |
| 449 | ++ |
| 450 | ++ rdev = container_of(work, struct cfg80211_registered_device, |
| 451 | ++ offchan_cac_abort_wk); |
| 452 | ++ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, |
| 453 | ++ NL80211_RADAR_CAC_ABORTED); |
| 454 | ++} |
| 455 | ++ |
| 456 | ++void cfg80211_offchan_cac_abort(struct wiphy *wiphy) |
| 457 | ++{ |
| 458 | ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 459 | ++ |
| 460 | ++ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); |
| 461 | ++} |
| 462 | ++EXPORT_SYMBOL(cfg80211_offchan_cac_abort); |
| 463 | ++ |
| 464 | ++int |
| 465 | ++cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, |
| 466 | ++ struct wireless_dev *wdev, |
| 467 | ++ struct cfg80211_chan_def *chandef) |
| 468 | ++{ |
| 469 | ++ unsigned int cac_time_ms; |
| 470 | ++ int err; |
| 471 | ++ |
| 472 | ++ lockdep_assert_wiphy(&rdev->wiphy); |
| 473 | ++ |
| 474 | ++ if (!wiphy_ext_feature_isset(&rdev->wiphy, |
| 475 | ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN)) |
| 476 | ++ return -EOPNOTSUPP; |
| 477 | ++ |
| 478 | ++ /* Offchannel chain already locked by another wdev */ |
| 479 | ++ if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) |
| 480 | ++ return -EBUSY; |
| 481 | ++ |
| 482 | ++ /* CAC already in progress on the offchannel chain */ |
| 483 | ++ if (rdev->offchan_radar_wdev == wdev && |
| 484 | ++ delayed_work_pending(&rdev->offchan_cac_done_wk)) |
| 485 | ++ return -EBUSY; |
| 486 | ++ |
| 487 | ++ err = rdev_set_radar_offchan(rdev, chandef); |
| 488 | ++ if (err) |
| 489 | ++ return err; |
| 490 | ++ |
| 491 | ++ cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef); |
| 492 | ++ if (!cac_time_ms) |
| 493 | ++ cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; |
| 494 | ++ |
| 495 | ++ rdev->offchan_radar_chandef = *chandef; |
| 496 | ++ rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ |
| 497 | ++ |
| 498 | ++ __cfg80211_offchan_cac_event(rdev, wdev, chandef, |
| 499 | ++ NL80211_RADAR_CAC_STARTED); |
| 500 | ++ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, |
| 501 | ++ msecs_to_jiffies(cac_time_ms)); |
| 502 | ++ |
| 503 | ++ return 0; |
| 504 | ++} |
| 505 | ++ |
| 506 | ++void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) |
| 507 | ++{ |
| 508 | ++ struct wiphy *wiphy = wdev->wiphy; |
| 509 | ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 510 | ++ |
| 511 | ++ lockdep_assert_wiphy(wiphy); |
| 512 | ++ |
| 513 | ++ if (wdev != rdev->offchan_radar_wdev) |
| 514 | ++ return; |
| 515 | ++ |
| 516 | ++ rdev_set_radar_offchan(rdev, NULL); |
| 517 | ++ rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ |
| 518 | ++ |
| 519 | ++ __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, |
| 520 | ++ NL80211_RADAR_CAC_ABORTED); |
| 521 | ++} |
| 522 | +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c |
| 523 | +index 4a3de61..0cf9f68 100644 |
| 524 | +--- a/net/wireless/nl80211.c |
| 525 | ++++ b/net/wireless/nl80211.c |
| 526 | +@@ -781,6 +781,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { |
| 527 | + [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, |
| 528 | + [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), |
| 529 | + [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, |
| 530 | ++ [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, |
| 531 | + }; |
| 532 | + |
| 533 | + /* policy for the key attributes */ |
| 534 | +@@ -9106,38 +9107,60 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, |
| 535 | + struct cfg80211_chan_def chandef; |
| 536 | + enum nl80211_dfs_regions dfs_region; |
| 537 | + unsigned int cac_time_ms; |
| 538 | +- int err; |
| 539 | ++ int err = -EINVAL; |
| 540 | ++ |
| 541 | ++ flush_delayed_work(&rdev->dfs_update_channels_wk); |
| 542 | ++ |
| 543 | ++ wiphy_lock(wiphy); |
| 544 | + |
| 545 | + dfs_region = reg_get_dfs_region(wiphy); |
| 546 | + if (dfs_region == NL80211_DFS_UNSET) |
| 547 | +- return -EINVAL; |
| 548 | ++ goto unlock; |
| 549 | + |
| 550 | + err = nl80211_parse_chandef(rdev, info, &chandef); |
| 551 | + if (err) |
| 552 | +- return err; |
| 553 | +- |
| 554 | +- if (netif_carrier_ok(dev)) |
| 555 | +- return -EBUSY; |
| 556 | +- |
| 557 | +- if (wdev->cac_started) |
| 558 | +- return -EBUSY; |
| 559 | ++ goto unlock; |
| 560 | + |
| 561 | + err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); |
| 562 | + if (err < 0) |
| 563 | +- return err; |
| 564 | ++ goto unlock; |
| 565 | + |
| 566 | +- if (err == 0) |
| 567 | +- return -EINVAL; |
| 568 | ++ if (err == 0) { |
| 569 | ++ err = -EINVAL; |
| 570 | ++ goto unlock; |
| 571 | ++ } |
| 572 | + |
| 573 | +- if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) |
| 574 | +- return -EINVAL; |
| 575 | ++ if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) { |
| 576 | ++ err = -EINVAL; |
| 577 | ++ goto unlock; |
| 578 | ++ } |
| 579 | ++ |
| 580 | ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { |
| 581 | ++ err = cfg80211_start_offchan_radar_detection(rdev, wdev, |
| 582 | ++ &chandef); |
| 583 | ++ goto unlock; |
| 584 | ++ } |
| 585 | ++ |
| 586 | ++ if (netif_carrier_ok(dev)) { |
| 587 | ++ err = -EBUSY; |
| 588 | ++ goto unlock; |
| 589 | ++ } |
| 590 | ++ |
| 591 | ++ if (wdev->cac_started) { |
| 592 | ++ err = -EBUSY; |
| 593 | ++ goto unlock; |
| 594 | ++ } |
| 595 | + |
| 596 | + /* CAC start is offloaded to HW and can't be started manually */ |
| 597 | +- if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) |
| 598 | +- return -EOPNOTSUPP; |
| 599 | ++ if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) { |
| 600 | ++ err = -EOPNOTSUPP; |
| 601 | ++ goto unlock; |
| 602 | ++ } |
| 603 | + |
| 604 | +- if (!rdev->ops->start_radar_detection) |
| 605 | +- return -EOPNOTSUPP; |
| 606 | ++ if (!rdev->ops->start_radar_detection) { |
| 607 | ++ err = -EOPNOTSUPP; |
| 608 | ++ goto unlock; |
| 609 | ++ } |
| 610 | + |
| 611 | + cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); |
| 612 | + if (WARN_ON(!cac_time_ms)) |
| 613 | +@@ -9150,6 +9173,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, |
| 614 | + wdev->cac_start_time = jiffies; |
| 615 | + wdev->cac_time_ms = cac_time_ms; |
| 616 | + } |
| 617 | ++unlock: |
| 618 | ++ wiphy_unlock(wiphy); |
| 619 | ++ |
| 620 | + return err; |
| 621 | + } |
| 622 | + |
| 623 | +@@ -15762,7 +15788,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { |
| 624 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
| 625 | + .doit = nl80211_start_radar_detection, |
| 626 | + .flags = GENL_UNS_ADMIN_PERM, |
| 627 | +- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP, |
| 628 | ++ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
| 629 | ++ NL80211_FLAG_NO_WIPHY_MTX, |
| 630 | + }, |
| 631 | + { |
| 632 | + .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, |
| 633 | +diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h |
| 634 | +index 36422cf..c566f47 100644 |
| 635 | +--- a/net/wireless/rdev-ops.h |
| 636 | ++++ b/net/wireless/rdev-ops.h |
| 637 | +@@ -1381,4 +1381,21 @@ static inline int rdev_color_change(struct cfg80211_registered_device *rdev, |
| 638 | + return ret; |
| 639 | + } |
| 640 | + |
| 641 | ++static inline int |
| 642 | ++rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, |
| 643 | ++ struct cfg80211_chan_def *chandef) |
| 644 | ++{ |
| 645 | ++ struct wiphy *wiphy = &rdev->wiphy; |
| 646 | ++ int ret; |
| 647 | ++ |
| 648 | ++ if (!rdev->ops->set_radar_offchan) |
| 649 | ++ return -EOPNOTSUPP; |
| 650 | ++ |
| 651 | ++ trace_rdev_set_radar_offchan(wiphy, chandef); |
| 652 | ++ ret = rdev->ops->set_radar_offchan(wiphy, chandef); |
| 653 | ++ trace_rdev_return_int(wiphy, ret); |
| 654 | ++ |
| 655 | ++ return ret; |
| 656 | ++} |
| 657 | ++ |
| 658 | + #endif /* __CFG80211_RDEV_OPS */ |
| 659 | +diff --git a/net/wireless/trace.h b/net/wireless/trace.h |
| 660 | +index 973ce68..cd60ada 100644 |
| 661 | +--- a/net/wireless/trace.h |
| 662 | ++++ b/net/wireless/trace.h |
| 663 | +@@ -3022,18 +3022,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_notify, |
| 664 | + ); |
| 665 | + |
| 666 | + TRACE_EVENT(cfg80211_radar_event, |
| 667 | +- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), |
| 668 | +- TP_ARGS(wiphy, chandef), |
| 669 | ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, |
| 670 | ++ bool offchan), |
| 671 | ++ TP_ARGS(wiphy, chandef, offchan), |
| 672 | + TP_STRUCT__entry( |
| 673 | + WIPHY_ENTRY |
| 674 | + CHAN_DEF_ENTRY |
| 675 | ++ __field(bool, offchan) |
| 676 | + ), |
| 677 | + TP_fast_assign( |
| 678 | + WIPHY_ASSIGN; |
| 679 | + CHAN_DEF_ASSIGN(chandef); |
| 680 | ++ __entry->offchan = offchan; |
| 681 | + ), |
| 682 | +- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, |
| 683 | +- WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 684 | ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d", |
| 685 | ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan) |
| 686 | + ); |
| 687 | + |
| 688 | + TRACE_EVENT(cfg80211_cac_event, |
| 689 | +@@ -3643,6 +3646,25 @@ TRACE_EVENT(cfg80211_bss_color_notify, |
| 690 | + __entry->color_bitmap) |
| 691 | + ); |
| 692 | + |
| 693 | ++TRACE_EVENT(rdev_set_radar_offchan, |
| 694 | ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), |
| 695 | ++ |
| 696 | ++ TP_ARGS(wiphy, chandef), |
| 697 | ++ |
| 698 | ++ TP_STRUCT__entry( |
| 699 | ++ WIPHY_ENTRY |
| 700 | ++ CHAN_DEF_ENTRY |
| 701 | ++ ), |
| 702 | ++ |
| 703 | ++ TP_fast_assign( |
| 704 | ++ WIPHY_ASSIGN; |
| 705 | ++ CHAN_DEF_ASSIGN(chandef) |
| 706 | ++ ), |
| 707 | ++ |
| 708 | ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, |
| 709 | ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 710 | ++); |
| 711 | ++ |
| 712 | + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
| 713 | + |
| 714 | + #undef TRACE_INCLUDE_PATH |
| 715 | + |