From bc2dfc02836b1133d1bf4d22aa13d48ac98eabef Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 23 Oct 2021 11:10:50 +0200 Subject: 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. Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/7468e291ef5d05d692c1738d25b8f778d8ea5c3f.1634979655.git.lorenzo@kernel.org Link: https://lore.kernel.org/r/1e60e60fef00e14401adae81c3d49f3e5f307537.1634979655.git.lorenzo@kernel.org Link: https://lore.kernel.org/r/85fa50f57fc3adb2934c8d9ca0be30394de6b7e8.1634979655.git.lorenzo@kernel.org Link: https://lore.kernel.org/r/4b6c08671ad59aae0ac46fc94c02f31b1610eb72.1634979655.git.lorenzo@kernel.org Link: https://lore.kernel.org/r/241849ccaf2c228873c6f8495bf87b19159ba458.1634979655.git.lorenzo@kernel.org [remove offchan_mutex, fix cfg80211_stop_offchan_radar_detection(), remove gfp_t argument, fix documentation, fix tracing] Signed-off-by: Johannes Berg --- net/wireless/core.c | 3 ++ net/wireless/core.h | 13 ++++++ net/wireless/mlme.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ net/wireless/nl80211.c | 17 +++++--- net/wireless/rdev-ops.h | 17 ++++++++ net/wireless/trace.h | 19 ++++++++ 6 files changed, 176 insertions(+), 6 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index eb297e1015e0..39b2d4ae581d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -545,6 +545,7 @@ use_default_name: INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); INIT_WORK(&rdev->conn_work, cfg80211_conn_work); INIT_WORK(&rdev->event_work, cfg80211_event_work); + INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); init_waitqueue_head(&rdev->dev_wait); @@ -1207,6 +1208,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, cfg80211_pmsr_wdev_down(wdev); + cfg80211_stop_offchan_radar_detection(wdev); + switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: __cfg80211_leave_ibss(rdev, dev, true); diff --git a/net/wireless/core.h b/net/wireless/core.h index 1720abf36f92..612d460dcde0 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -84,6 +84,10 @@ struct cfg80211_registered_device { struct delayed_work dfs_update_channels_wk; + struct wireless_dev *offchan_radar_wdev; + struct cfg80211_chan_def offchan_radar_chandef; + struct delayed_work offchan_cac_work; + /* netlink port which started critical protocol (0 means not started) */ u32 crit_proto_nlportid; @@ -491,6 +495,15 @@ 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); + +void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); + +void cfg80211_offchan_cac_work(struct work_struct *work); + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, struct ieee80211_channel *chan); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 783acd2c4211..46f2ec4d50d7 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -970,3 +970,116 @@ void cfg80211_cac_event(struct net_device *netdev, nl80211_radar_notify(rdev, chandef, event, netdev, gfp); } EXPORT_SYMBOL(cfg80211_cac_event); + +void cfg80211_offchan_cac_work(struct work_struct *work) +{ + struct delayed_work *delayed_work = to_delayed_work(work); + struct cfg80211_registered_device *rdev; + + rdev = container_of(delayed_work, struct cfg80211_registered_device, + offchan_cac_work); + cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_FINISHED); +} + +static void +__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event) +{ + struct wiphy *wiphy = &rdev->wiphy; + struct net_device *netdev; + + lockdep_assert_wiphy(&rdev->wiphy); + + if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) + return; + + switch (event) { + case NL80211_RADAR_CAC_FINISHED: + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); + memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); + queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); + cfg80211_sched_dfs_chan_update(rdev); + wdev = rdev->offchan_radar_wdev; + rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: + cancel_delayed_work(&rdev->offchan_cac_work); + wdev = rdev->offchan_radar_wdev; + rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_STARTED: + WARN_ON(!wdev); + rdev->offchan_radar_wdev = wdev; + break; + default: + return; + } + + netdev = wdev ? wdev->netdev : NULL; + nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); +} + +void cfg80211_offchan_cac_event(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + wiphy_lock(wiphy); + __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); + wiphy_unlock(wiphy); +} +EXPORT_SYMBOL(cfg80211_offchan_cac_event); + +int +cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +{ + unsigned int cac_time_ms; + int err; + + lockdep_assert_wiphy(&rdev->wiphy); + + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_RADAR_OFFCHAN)) + return -EOPNOTSUPP; + + if (rdev->offchan_radar_wdev) + return -EBUSY; + + err = rdev_set_radar_offchan(rdev, chandef); + if (err) + return err; + + cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef); + if (!cac_time_ms) + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + + rdev->offchan_radar_chandef = *chandef; + __cfg80211_offchan_cac_event(rdev, wdev, chandef, + NL80211_RADAR_CAC_STARTED); + queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, + msecs_to_jiffies(cac_time_ms)); + + return 0; +} + +void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + lockdep_assert_wiphy(wiphy); + + if (wdev != rdev->offchan_radar_wdev) + return; + + rdev_set_radar_offchan(rdev, NULL); + + __cfg80211_offchan_cac_event(rdev, NULL, NULL, + NL80211_RADAR_CAC_ABORTED); +} diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a27b3b5fa210..83a1ba96e172 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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 */ @@ -9284,12 +9285,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; @@ -9300,6 +9295,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; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index cc1efec4b27b..8672b3ef99e4 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1395,4 +1395,21 @@ rdev_set_fils_aad(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, + struct cfg80211_chan_def *chandef) +{ + struct wiphy *wiphy = &rdev->wiphy; + int ret; + + if (!rdev->ops->set_radar_offchan) + return -EOPNOTSUPP; + + trace_rdev_set_radar_offchan(wiphy, chandef); + ret = rdev->ops->set_radar_offchan(wiphy, chandef); + trace_rdev_return_int(wiphy, ret); + + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ad6c16a06bcb..0b27eaa14a18 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3674,6 +3674,25 @@ TRACE_EVENT(cfg80211_bss_color_notify, __entry->color_bitmap) ); +TRACE_EVENT(rdev_set_radar_offchan, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), + + TP_ARGS(wiphy, chandef), + + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_DEF_ENTRY + ), + + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_DEF_ASSIGN(chandef) + ), + + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, + WIPHY_PR_ARG, CHAN_DEF_PR_ARG) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From 1507b153198137dfa9cb4bec7c5dee07089ec3af Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 27 Oct 2021 11:03:42 +0200 Subject: cfg80211: move offchan_cac_event to a dedicated work In order to make cfg80211_offchan_cac_abort() (renamed from cfg80211_offchan_cac_event) callable in other contexts and without so much locking restrictions, make it trigger a new work instead of operating directly. Do some other renames while at it to clarify. Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/6145c3d0f30400a568023f67981981d24c7c6133.1635325205.git.lorenzo@kernel.org [rewrite commit log] Signed-off-by: Johannes Berg --- net/wireless/core.c | 6 +++++- net/wireless/core.h | 7 +++++-- net/wireless/mlme.c | 56 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 46 insertions(+), 23 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index 39b2d4ae581d..c4ea903f8184 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -545,7 +545,9 @@ use_default_name: INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); INIT_WORK(&rdev->conn_work, cfg80211_conn_work); INIT_WORK(&rdev->event_work, cfg80211_event_work); - INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); + INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); + INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, + cfg80211_offchan_cac_done_wk); init_waitqueue_head(&rdev->dev_wait); @@ -1055,11 +1057,13 @@ void wiphy_unregister(struct wiphy *wiphy) cancel_work_sync(&rdev->conn_work); flush_work(&rdev->event_work); cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); + cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); flush_work(&rdev->destroy_work); flush_work(&rdev->sched_scan_stop_wk); flush_work(&rdev->propagate_radar_detect_wk); flush_work(&rdev->propagate_cac_done_wk); flush_work(&rdev->mgmt_registrations_update_wk); + flush_work(&rdev->offchan_cac_abort_wk); #ifdef CONFIG_PM if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) diff --git a/net/wireless/core.h b/net/wireless/core.h index 612d460dcde0..fb8d9006d838 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -86,7 +86,8 @@ struct cfg80211_registered_device { struct wireless_dev *offchan_radar_wdev; struct cfg80211_chan_def offchan_radar_chandef; - struct delayed_work offchan_cac_work; + struct delayed_work offchan_cac_done_wk; + struct work_struct offchan_cac_abort_wk; /* netlink port which started critical protocol (0 means not started) */ u32 crit_proto_nlportid; @@ -502,7 +503,9 @@ cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); -void cfg80211_offchan_cac_work(struct work_struct *work); +void cfg80211_offchan_cac_done_wk(struct work_struct *work); + +void cfg80211_offchan_cac_abort_wk(struct work_struct *work); bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, struct ieee80211_channel *chan); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 46f2ec4d50d7..840795828d4f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -971,17 +971,6 @@ void cfg80211_cac_event(struct net_device *netdev, } EXPORT_SYMBOL(cfg80211_cac_event); -void cfg80211_offchan_cac_work(struct work_struct *work) -{ - struct delayed_work *delayed_work = to_delayed_work(work); - struct cfg80211_registered_device *rdev; - - rdev = container_of(delayed_work, struct cfg80211_registered_device, - offchan_cac_work); - cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, - NL80211_RADAR_CAC_FINISHED); -} - static void __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, @@ -1006,7 +995,7 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, rdev->offchan_radar_wdev = NULL; break; case NL80211_RADAR_CAC_ABORTED: - cancel_delayed_work(&rdev->offchan_cac_work); + cancel_delayed_work(&rdev->offchan_cac_done_wk); wdev = rdev->offchan_radar_wdev; rdev->offchan_radar_wdev = NULL; break; @@ -1022,17 +1011,44 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); } -void cfg80211_offchan_cac_event(struct wiphy *wiphy, - const struct cfg80211_chan_def *chandef, - enum nl80211_radar_event event) +static void +cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event) +{ + wiphy_lock(&rdev->wiphy); + __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); + wiphy_unlock(&rdev->wiphy); +} + +void cfg80211_offchan_cac_done_wk(struct work_struct *work) +{ + struct delayed_work *delayed_work = to_delayed_work(work); + struct cfg80211_registered_device *rdev; + + rdev = container_of(delayed_work, struct cfg80211_registered_device, + offchan_cac_done_wk); + cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_FINISHED); +} + +void cfg80211_offchan_cac_abort_wk(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, + offchan_cac_abort_wk); + cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_ABORTED); +} + +void cfg80211_offchan_cac_abort(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - wiphy_lock(wiphy); - __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); - wiphy_unlock(wiphy); + queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); } -EXPORT_SYMBOL(cfg80211_offchan_cac_event); +EXPORT_SYMBOL(cfg80211_offchan_cac_abort); int cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, @@ -1062,7 +1078,7 @@ cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, rdev->offchan_radar_chandef = *chandef; __cfg80211_offchan_cac_event(rdev, wdev, chandef, NL80211_RADAR_CAC_STARTED); - queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, + queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, msecs_to_jiffies(cac_time_ms)); return 0; -- cgit v1.2.3 From 91e89c77322d2a65ede9f418642942f3c096a63b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 3 Nov 2021 18:02:35 +0100 Subject: cfg80211: fix possible NULL pointer dereference in cfg80211_stop_offchan_radar_detection Fix the following NULL pointer dereference in cfg80211_stop_offchan_radar_detection routine that occurs when hostapd is stopped during the CAC on offchannel chain: Sat Jan 1 0[ 779.567851] ESR = 0x96000005 0:12:50 2000 dae[ 779.572346] EC = 0x25: DABT (current EL), IL = 32 bits mon.debug hostap[ 779.578984] SET = 0, FnV = 0 d: hostapd_inter[ 779.583445] EA = 0, S1PTW = 0 face_deinit_free[ 779.587936] Data abort info: : num_bss=1 conf[ 779.592224] ISV = 0, ISS = 0x00000005 ->num_bss=1 Sat[ 779.597403] CM = 0, WnR = 0 Jan 1 00:12:50[ 779.601749] user pgtable: 4k pages, 39-bit VAs, pgdp=00000000418b2000 2000 daemon.deb[ 779.609601] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 ug hostapd: host[ 779.619657] Internal error: Oops: 96000005 [#1] SMP [ 779.770810] CPU: 0 PID: 2202 Comm: hostapd Not tainted 5.10.75 #0 [ 779.776892] Hardware name: MediaTek MT7622 RFB1 board (DT) [ 779.782370] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO BTYPE=--) [ 779.788384] pc : cfg80211_chandef_valid+0x10/0x490 [cfg80211] [ 779.794128] lr : cfg80211_check_station_change+0x3190/0x3950 [cfg80211] [ 779.800731] sp : ffffffc01204b7e0 [ 779.804036] x29: ffffffc01204b7e0 x28: ffffff80039bdc00 [ 779.809340] x27: 0000000000000000 x26: ffffffc008cb3050 [ 779.814644] x25: 0000000000000000 x24: 0000000000000002 [ 779.819948] x23: ffffff8002630000 x22: ffffff8003e748d0 [ 779.825252] x21: 0000000000000cc0 x20: ffffff8003da4a00 [ 779.830556] x19: 0000000000000000 x18: ffffff8001bf7ce0 [ 779.835860] x17: 00000000ffffffff x16: 0000000000000000 [ 779.841164] x15: 0000000040d59200 x14: 00000000000019c0 [ 779.846467] x13: 00000000000001c8 x12: 000636b9e9dab1c6 [ 779.851771] x11: 0000000000000141 x10: 0000000000000820 [ 779.857076] x9 : 0000000000000000 x8 : ffffff8003d7d038 [ 779.862380] x7 : 0000000000000000 x6 : ffffff8003d7d038 [ 779.867683] x5 : 0000000000000e90 x4 : 0000000000000038 [ 779.872987] x3 : 0000000000000002 x2 : 0000000000000004 [ 779.878291] x1 : 0000000000000000 x0 : 0000000000000000 [ 779.883594] Call trace: [ 779.886039] cfg80211_chandef_valid+0x10/0x490 [cfg80211] [ 779.891434] cfg80211_check_station_change+0x3190/0x3950 [cfg80211] [ 779.897697] nl80211_radar_notify+0x138/0x19c [cfg80211] [ 779.903005] cfg80211_stop_offchan_radar_detection+0x7c/0x8c [cfg80211] [ 779.909616] __cfg80211_leave+0x2c/0x190 [cfg80211] [ 779.914490] cfg80211_register_netdevice+0x1c0/0x6d0 [cfg80211] [ 779.920404] raw_notifier_call_chain+0x50/0x70 [ 779.924841] call_netdevice_notifiers_info+0x54/0xa0 [ 779.929796] __dev_close_many+0x40/0x100 [ 779.933712] __dev_change_flags+0x98/0x190 [ 779.937800] dev_change_flags+0x20/0x60 [ 779.941628] devinet_ioctl+0x534/0x6d0 [ 779.945370] inet_ioctl+0x1bc/0x230 [ 779.948849] sock_do_ioctl+0x44/0x200 [ 779.952502] sock_ioctl+0x268/0x4c0 [ 779.955985] __arm64_sys_ioctl+0xac/0xd0 [ 779.959900] el0_svc_common.constprop.0+0x60/0x110 [ 779.964682] do_el0_svc+0x1c/0x24 [ 779.967990] el0_svc+0x10/0x1c [ 779.971036] el0_sync_handler+0x9c/0x120 [ 779.974950] el0_sync+0x148/0x180 [ 779.978259] Code: a9bc7bfd 910003fd a90153f3 aa0003f3 (f9400000) [ 779.984344] ---[ end trace 0e67b4f5d6cdeec7 ]--- [ 779.996400] Kernel panic - not syncing: Oops: Fatal exception [ 780.002139] SMP: stopping secondary CPUs [ 780.006057] Kernel Offset: disabled [ 780.009537] CPU features: 0x0000002,04002004 [ 780.013796] Memory Limit: none Fixes: b8f5facf286b ("cfg80211: implement APIs for dedicated radar detection HW") Reported-by: Evelyn Tsai Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/c2e34c065bf8839c5ffa45498ae154021a72a520.1635958796.git.lorenzo@kernel.org Signed-off-by: Johannes Berg --- net/wireless/mlme.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 840795828d4f..ac2e5e732d94 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -982,6 +982,9 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, lockdep_assert_wiphy(&rdev->wiphy); + if (!cfg80211_chandef_valid(chandef)) + return; + if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) return; @@ -1096,6 +1099,6 @@ void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) rdev_set_radar_offchan(rdev, NULL); - __cfg80211_offchan_cac_event(rdev, NULL, NULL, + __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, NL80211_RADAR_CAC_ABORTED); } -- cgit v1.2.3 From 3536672bbdc2e7093333be85c945a63aef4c6bb8 Mon Sep 17 00:00:00 2001 From: liuguoqiang Date: Mon, 15 Nov 2021 17:21:39 +0800 Subject: cfg80211: delete redundant free code When kzalloc failed and rdev->sacn_req or rdev->scan_msg is null, pass a null pointer to kfree is redundant, delete it and return directly. Signed-off-by: liuguoqiang Link: https://lore.kernel.org/r/20211115092139.24407-1-liuguoqiang@uniontech.com [remove now unused creq = NULL assigment] Signed-off-by: Johannes Berg --- net/wireless/scan.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 22e92be61938..a960940b6b75 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2687,7 +2687,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, struct cfg80211_registered_device *rdev; struct wiphy *wiphy; struct iw_scan_req *wreq = NULL; - struct cfg80211_scan_request *creq = NULL; + struct cfg80211_scan_request *creq; int i, err, n_channels = 0; enum nl80211_band band; @@ -2702,10 +2702,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (IS_ERR(rdev)) return PTR_ERR(rdev); - if (rdev->scan_req || rdev->scan_msg) { - err = -EBUSY; - goto out; - } + if (rdev->scan_req || rdev->scan_msg) + return -EBUSY; wiphy = &rdev->wiphy; @@ -2718,10 +2716,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + n_channels * sizeof(void *), GFP_ATOMIC); - if (!creq) { - err = -ENOMEM; - goto out; - } + if (!creq) + return -ENOMEM; creq->wiphy = wiphy; creq->wdev = dev->ieee80211_ptr; -- cgit v1.2.3 From c47240cb46a10c40686ce4e25c64aaed676f71c9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Nov 2021 12:41:52 +0100 Subject: cfg80211: schedule offchan_cac_abort_wk in cfg80211_radar_event If necessary schedule offchan_cac_abort_wk work in cfg80211_radar_event routine adding offchan parameter to cfg80211_radar_event signature. Rename cfg80211_radar_event in __cfg80211_radar_event and introduce the two following inline helpers: - cfg80211_radar_event - cfg80211_offchan_radar_event Doing so the drv will not need to run cfg80211_offchan_cac_abort() after radar detection on the offchannel chain. Tested-by: Owen Peng Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/3ff583e021e3343a3ced54a7b09b5e184d1880dc.1637062727.git.lorenzo@kernel.org Signed-off-by: Johannes Berg --- net/wireless/mlme.c | 16 ++++++++++------ net/wireless/trace.h | 11 +++++++---- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ac2e5e732d94..450be1ec70b8 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) } -void cfg80211_radar_event(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef, - gfp_t gfp) +void __cfg80211_radar_event(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + bool offchan, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - trace_cfg80211_radar_event(wiphy, chandef); + trace_cfg80211_radar_event(wiphy, chandef, offchan); /* only set the chandef supplied channel to unavailable, in * case the radar is detected on only one of multiple channels @@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy *wiphy, */ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); + if (offchan) + queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); + cfg80211_sched_dfs_chan_update(rdev); nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); @@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy *wiphy, memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def)); queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); } -EXPORT_SYMBOL(cfg80211_radar_event); +EXPORT_SYMBOL(__cfg80211_radar_event); void cfg80211_cac_event(struct net_device *netdev, const struct cfg80211_chan_def *chandef, @@ -998,7 +1001,8 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, rdev->offchan_radar_wdev = NULL; break; case NL80211_RADAR_CAC_ABORTED: - cancel_delayed_work(&rdev->offchan_cac_done_wk); + if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) + return; wdev = rdev->offchan_radar_wdev; rdev->offchan_radar_wdev = NULL; break; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 0b27eaa14a18..e854d52db1a6 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3053,18 +3053,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_notify, ); TRACE_EVENT(cfg80211_radar_event, - TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), - TP_ARGS(wiphy, chandef), + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, + bool offchan), + TP_ARGS(wiphy, chandef, offchan), TP_STRUCT__entry( WIPHY_ENTRY CHAN_DEF_ENTRY + __field(bool, offchan) ), TP_fast_assign( WIPHY_ASSIGN; CHAN_DEF_ASSIGN(chandef); + __entry->offchan = offchan; ), - TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, - WIPHY_PR_ARG, CHAN_DEF_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d", + WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan) ); TRACE_EVENT(cfg80211_cac_event, -- cgit v1.2.3 From 8415816493b7589e74ff4e1e7eaf3aadc7b73621 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Nov 2021 15:03:36 +0100 Subject: cfg80211: allow continuous radar monitoring on offchannel chain Allow continuous radar detection on the offchannel chain in order to switch to the monitored channel whenever the underlying driver reports a radar pattern on the main channel. Tested-by: Owen Peng Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/d46217310a49b14ff0e9c002f0a6e0547d70fd2c.1637071350.git.lorenzo@kernel.org Signed-off-by: Johannes Berg --- net/wireless/chan.c | 16 +++++++++++++ net/wireless/mlme.c | 20 ++++++++++------ net/wireless/nl80211.c | 62 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 71 insertions(+), 27 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 869c43d4414c..00fc7b78063c 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -712,6 +712,19 @@ static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, return false; } +static bool +cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, + struct ieee80211_channel *channel) +{ + if (!rdev->offchan_radar_wdev) + return false; + + if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) + return false; + + return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); +} + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, struct ieee80211_channel *chan) { @@ -728,6 +741,9 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan)) return true; + + if (cfg80211_offchan_chain_is_active(rdev, chan)) + return true; } return false; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 450be1ec70b8..e970076e1098 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, if (!cfg80211_chandef_valid(chandef)) return; - if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) + if (!rdev->offchan_radar_wdev) return; switch (event) { @@ -998,17 +998,13 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); cfg80211_sched_dfs_chan_update(rdev); wdev = rdev->offchan_radar_wdev; - rdev->offchan_radar_wdev = NULL; break; case NL80211_RADAR_CAC_ABORTED: if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) return; wdev = rdev->offchan_radar_wdev; - rdev->offchan_radar_wdev = NULL; break; case NL80211_RADAR_CAC_STARTED: - WARN_ON(!wdev); - rdev->offchan_radar_wdev = wdev; break; default: return; @@ -1024,7 +1020,8 @@ cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, enum nl80211_radar_event event) { wiphy_lock(&rdev->wiphy); - __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); + __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, + chandef, event); wiphy_unlock(&rdev->wiphy); } @@ -1071,7 +1068,13 @@ cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, NL80211_EXT_FEATURE_RADAR_OFFCHAN)) return -EOPNOTSUPP; - if (rdev->offchan_radar_wdev) + /* Offchannel chain already locked by another wdev */ + if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) + return -EBUSY; + + /* CAC already in progress on the offchannel chain */ + if (rdev->offchan_radar_wdev == wdev && + delayed_work_pending(&rdev->offchan_cac_done_wk)) return -EBUSY; err = rdev_set_radar_offchan(rdev, chandef); @@ -1083,6 +1086,8 @@ cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; rdev->offchan_radar_chandef = *chandef; + rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ + __cfg80211_offchan_cac_event(rdev, wdev, chandef, NL80211_RADAR_CAC_STARTED); queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, @@ -1102,6 +1107,7 @@ void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) return; rdev_set_radar_offchan(rdev, NULL); + rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, NL80211_RADAR_CAC_ABORTED); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 83a1ba96e172..65693c96b407 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9275,42 +9275,60 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, struct cfg80211_chan_def chandef; enum nl80211_dfs_regions dfs_region; unsigned int cac_time_ms; - int err; + int err = -EINVAL; + + flush_delayed_work(&rdev->dfs_update_channels_wk); + + wiphy_lock(wiphy); dfs_region = reg_get_dfs_region(wiphy); if (dfs_region == NL80211_DFS_UNSET) - return -EINVAL; + goto unlock; err = nl80211_parse_chandef(rdev, info, &chandef); if (err) - return err; + goto unlock; err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); if (err < 0) - return err; + goto unlock; - if (err == 0) - return -EINVAL; + if (err == 0) { + err = -EINVAL; + goto unlock; + } - if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) - return -EINVAL; + if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) { + err = -EINVAL; + goto unlock; + } - if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) - return cfg80211_start_offchan_radar_detection(rdev, wdev, - &chandef); + if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { + err = cfg80211_start_offchan_radar_detection(rdev, wdev, + &chandef); + goto unlock; + } - if (netif_carrier_ok(dev)) - return -EBUSY; + if (netif_carrier_ok(dev)) { + err = -EBUSY; + goto unlock; + } - if (wdev->cac_started) - return -EBUSY; + if (wdev->cac_started) { + err = -EBUSY; + goto unlock; + } /* 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; + if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) { + err = -EOPNOTSUPP; + goto unlock; + } - if (!rdev->ops->start_radar_detection) - return -EOPNOTSUPP; + if (!rdev->ops->start_radar_detection) { + err = -EOPNOTSUPP; + goto unlock; + } cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); if (WARN_ON(!cac_time_ms)) @@ -9323,6 +9341,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, wdev->cac_start_time = jiffies; wdev->cac_time_ms = cac_time_ms; } +unlock: + wiphy_unlock(wiphy); + return err; } @@ -15959,7 +15980,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_start_radar_detection, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NO_WIPHY_MTX, }, { .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, -- cgit v1.2.3 From fb8b53acf60bdfcefc5a583ce2946258f8261108 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2021 13:11:32 +0200 Subject: cfg80211: use ieee80211_bss_get_elem() instead of _get_ie() Use the structured helper for finding an element instead of the unstructured ieee80211_bss_get_ie(). Link: https://lore.kernel.org/r/20210930131130.e94709f341c3.I4ddb7fcb40efca27987deda7f9a144a5702ebfae@changeid Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 12 +++++++----- net/wireless/scan.c | 21 ++++++++++----------- net/wireless/sme.c | 22 ++++++++++------------ net/wireless/wext-sme.c | 12 ++++++------ 4 files changed, 33 insertions(+), 34 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 65693c96b407..bfa5d7428a3f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3670,14 +3670,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_ADHOC: { - const u8 *ssid_ie; + const struct element *ssid_elem; + if (!wdev->current_bss) break; rcu_read_lock(); - ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, - WLAN_EID_SSID); - if (ssid_ie && - nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2)) + ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, + WLAN_EID_SSID); + if (ssid_elem && + nla_put(msg, NL80211_ATTR_SSID, ssid_elem->datalen, + ssid_elem->data)) goto nla_put_failure_rcu_locked; rcu_read_unlock(); break; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index a960940b6b75..f7bd6810db97 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -406,22 +406,20 @@ static int cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss, struct cfg80211_bss *nontrans_bss) { - const u8 *ssid; - size_t ssid_len; + const struct element *ssid_elem; struct cfg80211_bss *bss = NULL; rcu_read_lock(); - ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); - if (!ssid) { + ssid_elem = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID); + if (!ssid_elem) { rcu_read_unlock(); return -EINVAL; } - ssid_len = ssid[1]; - ssid = ssid + 2; /* check if nontrans_bss is in the list */ list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) { - if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len)) { + if (is_bss(bss, nontrans_bss->bssid, ssid_elem->data, + ssid_elem->datalen)) { rcu_read_unlock(); return 0; } @@ -2234,7 +2232,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len) { u8 *ie, *new_ie, *pos; - const u8 *nontrans_ssid, *trans_ssid, *mbssid; + const struct element *nontrans_ssid; + const u8 *trans_ssid, *mbssid; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); size_t new_ie_len; @@ -2261,11 +2260,11 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, return; new_ie_len -= mbssid[1]; - nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); + nontrans_ssid = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID); if (!nontrans_ssid) return; - new_ie_len += nontrans_ssid[1]; + new_ie_len += nontrans_ssid->datalen; /* generate new ie for nontrans BSS * 1. replace SSID with nontrans BSS' SSID @@ -2282,7 +2281,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, pos = new_ie; /* copy the nontransmitted SSID */ - cpy_len = nontrans_ssid[1] + 2; + cpy_len = nontrans_ssid->datalen + 2; memcpy(pos, nontrans_ssid, cpy_len); pos += cpy_len; /* copy the IEs between SSID and MBSSID */ diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 08a70b4f090c..ff4d48fcbfb2 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -680,7 +680,9 @@ void __cfg80211_connect_result(struct net_device *dev, bool wextev) { struct wireless_dev *wdev = dev->ieee80211_ptr; - const u8 *country_ie; + const struct element *country_elem; + const u8 *country_data; + u8 country_datalen; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -762,26 +764,22 @@ void __cfg80211_connect_result(struct net_device *dev, cfg80211_upload_connect_keys(wdev); rcu_read_lock(); - country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY); - if (!country_ie) { + country_elem = ieee80211_bss_get_elem(cr->bss, WLAN_EID_COUNTRY); + if (!country_elem) { rcu_read_unlock(); return; } - country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC); + country_datalen = country_elem->datalen; + country_data = kmemdup(country_elem->data, country_datalen, GFP_ATOMIC); rcu_read_unlock(); - if (!country_ie) + if (!country_data) return; - /* - * ieee80211_bss_get_ie() ensures we can access: - * - country_ie + 2, the start of the country ie data, and - * - and country_ie[1] which is the IE length - */ regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band, - country_ie + 2, country_ie[1]); - kfree(country_ie); + country_data, country_datalen); + kfree(country_data); } /* Consumes bss object one way or another */ diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 193a18a53142..cd09a9042261 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -212,18 +212,18 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) { - const u8 *ie; + const struct element *ssid_elem; rcu_read_lock(); - ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, - WLAN_EID_SSID); - if (ie) { + ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, + WLAN_EID_SSID); + if (ssid_elem) { data->flags = 1; - data->length = ie[1]; + data->length = ssid_elem->datalen; if (data->length > IW_ESSID_MAX_SIZE) ret = -EINVAL; else - memcpy(ssid, ie + 2, data->length); + memcpy(ssid, ssid_elem->data, data->length); } rcu_read_unlock(); } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { -- cgit v1.2.3 From 3bb1ccc4ed8fbc2d26a0cce369313e80e412b4f1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Nov 2021 15:32:43 +0200 Subject: cfg80211: simplify cfg80211_chandef_valid() There are a lot of duplicate checks in this function to check the delta between the control channel and CF1. With the addition of 320 MHz, this will become even more. Simplify the code so that the common checks are done only once for multiple bandwidths. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211129152938.2d0240b07f11.I759e8e990f5386ba2b56ffb2488a8d4e16e22c1b@changeid Signed-off-by: Johannes Berg --- net/wireless/chan.c | 62 +++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 30 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 00fc7b78063c..ac2e5677524a 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -245,19 +245,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) oper_freq - MHZ_TO_KHZ(oper_width) / 2) return false; break; - case NL80211_CHAN_WIDTH_40: - if (chandef->center_freq1 != control_freq + 10 && - chandef->center_freq1 != control_freq - 10) - return false; - if (chandef->center_freq2) - return false; - break; case NL80211_CHAN_WIDTH_80P80: - if (chandef->center_freq1 != control_freq + 30 && - chandef->center_freq1 != control_freq + 10 && - chandef->center_freq1 != control_freq - 10 && - chandef->center_freq1 != control_freq - 30) - return false; if (!chandef->center_freq2) return false; /* adjacent is not allowed -- that's a 160 MHz channel */ @@ -265,28 +253,42 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) chandef->center_freq2 - chandef->center_freq1 == 80) return false; break; - case NL80211_CHAN_WIDTH_80: - if (chandef->center_freq1 != control_freq + 30 && - chandef->center_freq1 != control_freq + 10 && - chandef->center_freq1 != control_freq - 10 && - chandef->center_freq1 != control_freq - 30) - return false; + default: if (chandef->center_freq2) return false; break; - case NL80211_CHAN_WIDTH_160: - if (chandef->center_freq1 != control_freq + 70 && - chandef->center_freq1 != control_freq + 50 && - chandef->center_freq1 != control_freq + 30 && - chandef->center_freq1 != control_freq + 10 && - chandef->center_freq1 != control_freq - 10 && - chandef->center_freq1 != control_freq - 30 && - chandef->center_freq1 != control_freq - 50 && - chandef->center_freq1 != control_freq - 70) - return false; - if (chandef->center_freq2) - return false; + } + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_5: + case NL80211_CHAN_WIDTH_10: + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_1: + case NL80211_CHAN_WIDTH_2: + case NL80211_CHAN_WIDTH_4: + case NL80211_CHAN_WIDTH_8: + case NL80211_CHAN_WIDTH_16: + /* all checked above */ break; + case NL80211_CHAN_WIDTH_160: + if (chandef->center_freq1 == control_freq + 70 || + chandef->center_freq1 == control_freq + 50 || + chandef->center_freq1 == control_freq - 50 || + chandef->center_freq1 == control_freq - 70) + break; + fallthrough; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_80: + if (chandef->center_freq1 == control_freq + 30 || + chandef->center_freq1 == control_freq - 30) + break; + fallthrough; + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 == control_freq + 10 || + chandef->center_freq1 == control_freq - 10) + break; + fallthrough; default: return false; } -- cgit v1.2.3 From a083ee8a4e03348fb90a4b24cbe957b3252c7b04 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 29 Nov 2021 15:32:34 +0200 Subject: cfg80211: Add support for notifying association comeback Thought the underline driver MLME can handle association temporal rejection with comeback, it is still useful to notify this to user space, as user space might want to handle the temporal rejection differently. For example, in case the comeback time is too long, user space can deauthenticate immediately and try to associate with a different AP. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211129152938.2467809e8cb3.I45574185b582666bc78eef0c29a4c36b478e5382@changeid Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 38 ++++++++++++++++++++++++++++++++++++++ net/wireless/trace.h | 17 +++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bfa5d7428a3f..71da0d506502 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -17064,6 +17064,44 @@ static void nl80211_send_remain_on_chan_event( nlmsg_free(msg); } +void cfg80211_assoc_comeback(struct net_device *netdev, + struct cfg80211_bss *bss, u32 timeout) +{ + struct wireless_dev *wdev = netdev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct sk_buff *msg; + void *hdr; + + trace_cfg80211_assoc_comeback(wdev, bss->bssid, timeout); + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ASSOC_COMEBACK); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bss->bssid) || + nla_put_u32(msg, NL80211_ATTR_TIMEOUT, timeout)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); + return; + + nla_put_failure: + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_assoc_comeback); + void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, unsigned int duration, gfp_t gfp) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index e854d52db1a6..01710f0c8a03 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3696,6 +3696,23 @@ TRACE_EVENT(rdev_set_radar_offchan, WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); +TRACE_EVENT(cfg80211_assoc_comeback, + TP_PROTO(struct wireless_dev *wdev, const u8 *bssid, u32 timeout), + TP_ARGS(wdev, bssid, timeout), + TP_STRUCT__entry( + WDEV_ENTRY + MAC_ENTRY(bssid) + __field(u32, timeout) + ), + TP_fast_assign( + WDEV_ASSIGN; + MAC_ASSIGN(bssid, bssid); + __entry->timeout = timeout; + ), + TP_printk(WDEV_PR_FMT ", " MAC_PR_FMT ", timeout: %u TUs", + WDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->timeout) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From a95bfb876fa87e2d0fa718ee61a8030ddf162d2b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 29 Nov 2021 14:11:24 +0100 Subject: cfg80211: rename offchannel_chain structs to background_chain to avoid confusion with ETSI standard ETSI standard defines "Offchannel CAC" as: "Off-Channel CAC is performed by a number of non-continuous checks spread over a period in time. This period, which is required to determine the presence of radar signals, is defined as the Off-Channel CAC Time.. Minimum Off-Channel CAC Time 6 minutes and Maximum Off-Channel CAC Time 4 hours..". mac80211 implementation refers to a dedicated hw chain used for continuous radar monitoring. Rename offchannel_* references to background_* in order to avoid confusion with ETSI standard. Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/4204cc1d648d76b44557981713231e030a3bd991.1638190762.git.lorenzo@kernel.org Signed-off-by: Johannes Berg --- net/wireless/chan.c | 6 ++-- net/wireless/core.c | 13 ++++---- net/wireless/core.h | 20 +++++------ net/wireless/mlme.c | 89 +++++++++++++++++++++++++------------------------ net/wireless/nl80211.c | 8 ++--- net/wireless/rdev-ops.h | 10 +++--- net/wireless/trace.h | 2 +- 7 files changed, 75 insertions(+), 73 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/chan.c b/net/wireless/chan.c index ac2e5677524a..eb822052d344 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -718,13 +718,13 @@ static bool cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, struct ieee80211_channel *channel) { - if (!rdev->offchan_radar_wdev) + if (!rdev->background_radar_wdev) return false; - if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) + if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) return false; - return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); + return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel); } bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, diff --git a/net/wireless/core.c b/net/wireless/core.c index c4ea903f8184..132c575c5540 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -545,9 +545,10 @@ use_default_name: INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); INIT_WORK(&rdev->conn_work, cfg80211_conn_work); INIT_WORK(&rdev->event_work, cfg80211_event_work); - INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); - INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, - cfg80211_offchan_cac_done_wk); + INIT_WORK(&rdev->background_cac_abort_wk, + cfg80211_background_cac_abort_wk); + INIT_DELAYED_WORK(&rdev->background_cac_done_wk, + cfg80211_background_cac_done_wk); init_waitqueue_head(&rdev->dev_wait); @@ -1057,13 +1058,13 @@ void wiphy_unregister(struct wiphy *wiphy) cancel_work_sync(&rdev->conn_work); flush_work(&rdev->event_work); cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); - cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); + cancel_delayed_work_sync(&rdev->background_cac_done_wk); flush_work(&rdev->destroy_work); flush_work(&rdev->sched_scan_stop_wk); flush_work(&rdev->propagate_radar_detect_wk); flush_work(&rdev->propagate_cac_done_wk); flush_work(&rdev->mgmt_registrations_update_wk); - flush_work(&rdev->offchan_cac_abort_wk); + flush_work(&rdev->background_cac_abort_wk); #ifdef CONFIG_PM if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) @@ -1212,7 +1213,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, cfg80211_pmsr_wdev_down(wdev); - cfg80211_stop_offchan_radar_detection(wdev); + cfg80211_stop_background_radar_detection(wdev); switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: diff --git a/net/wireless/core.h b/net/wireless/core.h index fb8d9006d838..3a7dbd63d8c6 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -84,10 +84,10 @@ struct cfg80211_registered_device { struct delayed_work dfs_update_channels_wk; - struct wireless_dev *offchan_radar_wdev; - struct cfg80211_chan_def offchan_radar_chandef; - struct delayed_work offchan_cac_done_wk; - struct work_struct offchan_cac_abort_wk; + struct wireless_dev *background_radar_wdev; + struct cfg80211_chan_def background_radar_chandef; + struct delayed_work background_cac_done_wk; + struct work_struct background_cac_abort_wk; /* netlink port which started critical protocol (0 means not started) */ u32 crit_proto_nlportid; @@ -497,15 +497,15 @@ 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); +cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef); -void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); +void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev); -void cfg80211_offchan_cac_done_wk(struct work_struct *work); +void cfg80211_background_cac_done_wk(struct work_struct *work); -void cfg80211_offchan_cac_abort_wk(struct work_struct *work); +void cfg80211_background_cac_abort_wk(struct work_struct *work); bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, struct ieee80211_channel *chan); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index e970076e1098..c8155a483ec2 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -920,7 +920,7 @@ void __cfg80211_radar_event(struct wiphy *wiphy, cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); if (offchan) - queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); + queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); cfg80211_sched_dfs_chan_update(rdev); @@ -975,10 +975,10 @@ void cfg80211_cac_event(struct net_device *netdev, EXPORT_SYMBOL(cfg80211_cac_event); static void -__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - const struct cfg80211_chan_def *chandef, - enum nl80211_radar_event event) +__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event) { struct wiphy *wiphy = &rdev->wiphy; struct net_device *netdev; @@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, if (!cfg80211_chandef_valid(chandef)) return; - if (!rdev->offchan_radar_wdev) + if (!rdev->background_radar_wdev) return; switch (event) { @@ -997,12 +997,12 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); cfg80211_sched_dfs_chan_update(rdev); - wdev = rdev->offchan_radar_wdev; + wdev = rdev->background_radar_wdev; break; case NL80211_RADAR_CAC_ABORTED: - if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) + if (!cancel_delayed_work(&rdev->background_cac_done_wk)) return; - wdev = rdev->offchan_radar_wdev; + wdev = rdev->background_radar_wdev; break; case NL80211_RADAR_CAC_STARTED: break; @@ -1015,49 +1015,49 @@ __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, } static void -cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, - const struct cfg80211_chan_def *chandef, - enum nl80211_radar_event event) +cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event) { wiphy_lock(&rdev->wiphy); - __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, - chandef, event); + __cfg80211_background_cac_event(rdev, rdev->background_radar_wdev, + chandef, event); wiphy_unlock(&rdev->wiphy); } -void cfg80211_offchan_cac_done_wk(struct work_struct *work) +void cfg80211_background_cac_done_wk(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); struct cfg80211_registered_device *rdev; rdev = container_of(delayed_work, struct cfg80211_registered_device, - offchan_cac_done_wk); - cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, - NL80211_RADAR_CAC_FINISHED); + background_cac_done_wk); + cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, + NL80211_RADAR_CAC_FINISHED); } -void cfg80211_offchan_cac_abort_wk(struct work_struct *work) +void cfg80211_background_cac_abort_wk(struct work_struct *work) { struct cfg80211_registered_device *rdev; rdev = container_of(work, struct cfg80211_registered_device, - offchan_cac_abort_wk); - cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, - NL80211_RADAR_CAC_ABORTED); + background_cac_abort_wk); + cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, + NL80211_RADAR_CAC_ABORTED); } -void cfg80211_offchan_cac_abort(struct wiphy *wiphy) +void cfg80211_background_cac_abort(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); + queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); } -EXPORT_SYMBOL(cfg80211_offchan_cac_abort); +EXPORT_SYMBOL(cfg80211_background_cac_abort); int -cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - struct cfg80211_chan_def *chandef) +cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) { unsigned int cac_time_ms; int err; @@ -1065,19 +1065,19 @@ cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, lockdep_assert_wiphy(&rdev->wiphy); if (!wiphy_ext_feature_isset(&rdev->wiphy, - NL80211_EXT_FEATURE_RADAR_OFFCHAN)) + NL80211_EXT_FEATURE_RADAR_BACKGROUND)) return -EOPNOTSUPP; /* Offchannel chain already locked by another wdev */ - if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) + if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev) return -EBUSY; /* CAC already in progress on the offchannel chain */ - if (rdev->offchan_radar_wdev == wdev && - delayed_work_pending(&rdev->offchan_cac_done_wk)) + if (rdev->background_radar_wdev == wdev && + delayed_work_pending(&rdev->background_cac_done_wk)) return -EBUSY; - err = rdev_set_radar_offchan(rdev, chandef); + err = rdev_set_radar_background(rdev, chandef); if (err) return err; @@ -1085,30 +1085,31 @@ cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, if (!cac_time_ms) cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; - rdev->offchan_radar_chandef = *chandef; - rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ + rdev->background_radar_chandef = *chandef; + rdev->background_radar_wdev = wdev; /* Get offchain ownership */ - __cfg80211_offchan_cac_event(rdev, wdev, chandef, - NL80211_RADAR_CAC_STARTED); - queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, + __cfg80211_background_cac_event(rdev, wdev, chandef, + NL80211_RADAR_CAC_STARTED); + queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk, msecs_to_jiffies(cac_time_ms)); return 0; } -void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) +void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); lockdep_assert_wiphy(wiphy); - if (wdev != rdev->offchan_radar_wdev) + if (wdev != rdev->background_radar_wdev) return; - rdev_set_radar_offchan(rdev, NULL); - rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ + rdev_set_radar_background(rdev, NULL); + rdev->background_radar_wdev = NULL; /* Release offchain ownership */ - __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, - NL80211_RADAR_CAC_ABORTED); + __cfg80211_background_cac_event(rdev, wdev, + &rdev->background_radar_chandef, + NL80211_RADAR_CAC_ABORTED); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 71da0d506502..6ee21049b028 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -776,7 +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 }, + [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -9305,9 +9305,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, goto unlock; } - if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { - err = cfg80211_start_offchan_radar_detection(rdev, wdev, - &chandef); + if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) { + err = cfg80211_start_background_radar_detection(rdev, wdev, + &chandef); goto unlock; } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 8672b3ef99e4..439bcf52369c 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1396,17 +1396,17 @@ rdev_set_fils_aad(struct cfg80211_registered_device *rdev, } static inline int -rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, - struct cfg80211_chan_def *chandef) +rdev_set_radar_background(struct cfg80211_registered_device *rdev, + struct cfg80211_chan_def *chandef) { struct wiphy *wiphy = &rdev->wiphy; int ret; - if (!rdev->ops->set_radar_offchan) + if (!rdev->ops->set_radar_background) return -EOPNOTSUPP; - trace_rdev_set_radar_offchan(wiphy, chandef); - ret = rdev->ops->set_radar_offchan(wiphy, chandef); + trace_rdev_set_radar_background(wiphy, chandef); + ret = rdev->ops->set_radar_background(wiphy, chandef); trace_rdev_return_int(wiphy, ret); return ret; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 01710f0c8a03..228079d7690a 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3677,7 +3677,7 @@ TRACE_EVENT(cfg80211_bss_color_notify, __entry->color_bitmap) ); -TRACE_EVENT(rdev_set_radar_offchan, +TRACE_EVENT(rdev_set_radar_background, TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), TP_ARGS(wiphy, chandef), -- cgit v1.2.3 From 7f599aeccbd2bcba800c6c7ecc4586fd8cafc1d8 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 2 Dec 2021 14:36:10 +0200 Subject: cfg80211: Use the HE operation IE to determine a 6GHz BSS channel A non-collocated AP whose primary channel is not a PSC channel may transmit a duplicated beacon on the corresponding PSC channel in which it would indicate its true primary channel. Use this inforamtion contained in the HE operation IE to determine the primary channel of the AP. In case of invalid infomration ignore it and use the channel the frame was received on. Signed-off-by: Ayala Beker Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211202143322.71eb2176e54e.I130f678e4aa390973ab39d838bbfe7b2d54bff8e@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index f7bd6810db97..e502c522965d 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1793,12 +1793,33 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, } int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen, - enum nl80211_band band) + enum nl80211_band band, + enum cfg80211_bss_frame_type ftype) { const u8 *tmp; int channel_number = -1; - if (band == NL80211_BAND_S1GHZ) { + if (band == NL80211_BAND_6GHZ) { + const struct element *elem; + struct ieee80211_he_operation *he_oper; + + elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, + ielen); + if (elem && elem->datalen >= sizeof(*he_oper) && + elem->datalen >= ieee80211_he_oper_size(&elem->data[1])) { + const struct ieee80211_he_6ghz_oper *he_6ghz_oper; + + he_oper = (void *)&elem->data[1]; + + he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); + if (!he_6ghz_oper) + return channel_number; + + if (ftype != CFG80211_BSS_FTYPE_BEACON || + he_6ghz_oper->control & IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON) + channel_number = he_6ghz_oper->primary; + } + } else if (band == NL80211_BAND_S1GHZ) { tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen); if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) { struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2); @@ -1829,18 +1850,20 @@ EXPORT_SYMBOL(cfg80211_get_ies_channel_number); * from neighboring channels and the Beacon frames use the DSSS Parameter Set * element to indicate the current (transmitting) channel, but this might also * be needed on other bands if RX frequency does not match with the actual - * operating channel of a BSS. + * operating channel of a BSS, or if the AP reports a different primary channel. */ static struct ieee80211_channel * cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, struct ieee80211_channel *channel, - enum nl80211_bss_scan_width scan_width) + enum nl80211_bss_scan_width scan_width, + enum cfg80211_bss_frame_type ftype) { u32 freq; int channel_number; struct ieee80211_channel *alt_channel; - channel_number = cfg80211_get_ies_channel_number(ie, ielen, channel->band); + channel_number = cfg80211_get_ies_channel_number(ie, ielen, + channel->band, ftype); if (channel_number < 0) { /* No channel information in frame payload */ @@ -1848,6 +1871,16 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, } freq = ieee80211_channel_to_freq_khz(channel_number, channel->band); + + /* + * In 6GHz, duplicated beacon indication is relevant for + * beacons only. + */ + if (channel->band == NL80211_BAND_6GHZ && + (freq == channel->center_freq || + abs(freq - channel->center_freq) > 80)) + return channel; + alt_channel = ieee80211_get_channel_khz(wiphy, freq); if (!alt_channel) { if (channel->band == NL80211_BAND_2GHZ) { @@ -1909,7 +1942,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, return NULL; channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan, - data->scan_width); + data->scan_width, ftype); if (!channel) return NULL; @@ -2332,6 +2365,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); int bss_type; + enum cfg80211_bss_frame_type ftype; BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != offsetof(struct ieee80211_mgmt, u.beacon.variable)); @@ -2368,8 +2402,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, variable = ext->u.s1g_beacon.variable; } + if (ieee80211_is_beacon(mgmt->frame_control)) + ftype = CFG80211_BSS_FTYPE_BEACON; + else if (ieee80211_is_probe_resp(mgmt->frame_control)) + ftype = CFG80211_BSS_FTYPE_PRESP; + else + ftype = CFG80211_BSS_FTYPE_UNKNOWN; + channel = cfg80211_get_bss_channel(wiphy, variable, - ielen, data->chan, data->scan_width); + ielen, data->chan, data->scan_width, + ftype); if (!channel) return NULL; -- cgit v1.2.3 From 47301a74bbfa80cef876e646a8c5fec03c20fc8d Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Fri, 26 Nov 2021 12:55:18 +0530 Subject: nl80211: Add support to set AP settings flags with single attribute In previous method each AP settings flag is represented by a top-level flag attribute and conversion to enum cfg80211_ap_settings_flags had to be done before sending them to driver. This commit is to make it easier to define new AP settings flags and sending them to driver. This commit also deprecate sending of %NL80211_ATTR_EXTERNAL_AUTH_SUPPORT in %NL80211_CMD_START_AP. But to maintain backwards compatibility checks for %NL80211_ATTR_EXTERNAL_AUTH_SUPPORT in %NL80211_CMD_START_AP when %NL80211_ATTR_AP_SETTINGS_FLAGS not present in %NL80211_CMD_START_AP. Signed-off-by: Veerendranath Jakkam Link: https://lore.kernel.org/r/1637911519-21306-1-git-send-email-vjakkam@codeaurora.org Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6ee21049b028..578bff9c378b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -777,6 +777,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_NESTED(nl80211_mbssid_config_policy), [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, + [NL80211_ATTR_AP_SETTINGS_FLAGS] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -5714,8 +5715,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) nl80211_calculate_ap_params(params); - if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) - params->flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; + if (info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS]) + params->flags = nla_get_u32( + info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS]); + else if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) + params->flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; wdev_lock(wdev); err = rdev_start_ap(rdev, dev, params); -- cgit v1.2.3 From 75cca1fac2e11039fefb4f2118a8af50949345dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Dec 2021 13:09:14 +0100 Subject: cfg80211: refactor cfg80211_get_ies_channel_number() Now that this is no longer part of the bigger function, we can get rid of the channel_num variable. Also change the function to use the struct element helpers, instead of open-coding the element handling. Link: https://lore.kernel.org/r/20211202130913.a0adf67a9319.I6db0340a34fff18d78e9cd512f4abf855da4e43a@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e502c522965d..b888522f133b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1796,51 +1796,49 @@ int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen, enum nl80211_band band, enum cfg80211_bss_frame_type ftype) { - const u8 *tmp; - int channel_number = -1; + const struct element *tmp; if (band == NL80211_BAND_6GHZ) { - const struct element *elem; struct ieee80211_he_operation *he_oper; - elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, - ielen); - if (elem && elem->datalen >= sizeof(*he_oper) && - elem->datalen >= ieee80211_he_oper_size(&elem->data[1])) { + tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, + ielen); + if (tmp && tmp->datalen >= sizeof(*he_oper) && + tmp->datalen >= ieee80211_he_oper_size(&tmp->data[1])) { const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - he_oper = (void *)&elem->data[1]; + he_oper = (void *)&tmp->data[1]; he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); if (!he_6ghz_oper) - return channel_number; + return -1; if (ftype != CFG80211_BSS_FTYPE_BEACON || he_6ghz_oper->control & IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON) - channel_number = he_6ghz_oper->primary; + return he_6ghz_oper->primary; } } else if (band == NL80211_BAND_S1GHZ) { - tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen); - if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) { - struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2); + tmp = cfg80211_find_elem(WLAN_EID_S1G_OPERATION, ie, ielen); + if (tmp && tmp->datalen >= sizeof(struct ieee80211_s1g_oper_ie)) { + struct ieee80211_s1g_oper_ie *s1gop = (void *)tmp->data; - channel_number = s1gop->primary_ch; + return s1gop->primary_ch; } } else { - tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen); - if (tmp && tmp[1] == 1) { - channel_number = tmp[2]; - } else { - tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen); - if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) { - struct ieee80211_ht_operation *htop = (void *)(tmp + 2); + tmp = cfg80211_find_elem(WLAN_EID_DS_PARAMS, ie, ielen); + if (tmp && tmp->datalen == 1) + return tmp->data[0]; - channel_number = htop->primary_chan; - } + tmp = cfg80211_find_elem(WLAN_EID_HT_OPERATION, ie, ielen); + if (tmp && + tmp->datalen >= sizeof(struct ieee80211_ht_operation)) { + struct ieee80211_ht_operation *htop = (void *)tmp->data; + + return htop->primary_chan; } } - return channel_number; + return -1; } EXPORT_SYMBOL(cfg80211_get_ies_channel_number); -- cgit v1.2.3 From 701fdfe348f7e5c9fe71caa3558d63dbb4bc4b81 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Thu, 2 Dec 2021 07:08:40 +0530 Subject: cfg80211: Enable regulatory enforcement checks for drivers supporting mesh iface Currently cfg80211 checks for invalid channels whenever there is a regulatory update and stops the active interfaces if it is operating on an unsupported channel in the new regulatory domain. This is done based on a regulatory flag REGULATORY_IGNORE_STALE_KICKOFF set during wiphy registration which disables this enforcement when unsupported interface modes are supported by driver. Add support to enable this enforcement when Mesh Point interface type is advertised by drivers. Signed-off-by: Sriram R Link: https://lore.kernel.org/r/1638409120-28997-1-git-send-email-quic_srirrama@quicinc.com Signed-off-by: Johannes Berg --- net/wireless/core.c | 1 + net/wireless/reg.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index 132c575c5540..3a54c8e6b6c6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -737,6 +737,7 @@ int wiphy_register(struct wiphy *wiphy) if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_P2P_DEVICE) | diff --git a/net/wireless/reg.c b/net/wireless/reg.c index df87c7f3a049..58e4b33aff04 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2349,6 +2349,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) switch (iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: if (!wdev->beacon_interval) goto wdev_inactive_unlock; chandef = wdev->chandef; @@ -2387,6 +2388,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype); case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: -- cgit v1.2.3