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 --- include/net/cfg80211.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 423f97b982ff..db8866d42a4b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4072,6 +4072,15 @@ struct mgmt_frame_regs { * @set_fils_aad: Set FILS AAD data to the AP driver so that the driver can use * those to decrypt (Re)Association Request and encrypt (Re)Association * Response frame. + * + * @set_radar_offchan: Configure dedicated offchannel chain available for + * radar/CAC detection on some hw. This chain can't be used to transmit + * or receive frames and it is bounded to a running wdev. + * Offchannel radar/CAC detection allows to avoid the CAC downtime + * switching to a different channel during CAC detection on the selected + * radar channel. + * The caller is expected to set chandef pointer to NULL in order to + * disable offchannel CAC/radar detection. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -4404,6 +4413,8 @@ struct cfg80211_ops { struct cfg80211_color_change_settings *params); int (*set_fils_aad)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_fils_aad *fils_aad); + int (*set_radar_offchan)(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef); }; /* @@ -7633,6 +7644,20 @@ void cfg80211_cac_event(struct net_device *netdev, const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, gfp_t gfp); +/** + * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event + * @wiphy: the wiphy + * @chandef: chandef for the current channel + * @event: type of event + * + * This function is called when a Channel Availability Check (CAC) is finished, + * started or aborted by a offchannel dedicated chain. + * + * Note that this acquires the wiphy lock. + */ +void cfg80211_offchan_cac_event(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event); /** * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying -- cgit v1.2.3 From 237337c230b94e78a5a0f88d1705259ab543fc40 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 23 Oct 2021 11:10:51 +0200 Subject: mac80211: introduce set_radar_offchan callback Similar to cfg80211, introduce set_radar_offchan callback in mac80211_ops in order to configure a dedicated offchannel chain available on some hw (e.g. mt7915) to perform offchannel CAC detection and avoid tx/rx downtime. Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/201110606d4f3a7dfdf31440e351f2e2c375d4f0.1634979655.git.lorenzo@kernel.org Signed-off-by: Johannes Berg --- include/net/mac80211.h | 10 ++++++++++ net/mac80211/cfg.c | 13 +++++++++++++ 2 files changed, 23 insertions(+) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index dd757f0987b0..775dbb982654 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3944,6 +3944,14 @@ struct ieee80211_prep_tx_info { * twt structure. * @twt_teardown_request: Update the hw with TWT teardown request received * from the peer. + * @set_radar_offchan: Configure dedicated offchannel chain available for + * radar/CAC detection on some hw. This chain can't be used to transmit + * or receive frames and it is bounded to a running wdev. + * Offchannel radar/CAC detection allows to avoid the CAC downtime + * switching to a different channel during CAC detection on the selected + * radar channel. + * The caller is expected to set chandef pointer to NULL in order to + * disable offchannel CAC/radar detection. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4272,6 +4280,8 @@ struct ieee80211_ops { struct ieee80211_twt_setup *twt); void (*twt_teardown_request)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 flowid); + int (*set_radar_offchan)(struct ieee80211_hw *hw, + struct cfg80211_chan_def *chandef); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bd3d3195097f..45334d59fe06 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4383,6 +4383,18 @@ out: return err; } +static int +ieee80211_set_radar_offchan(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (!local->ops->set_radar_offchan) + return -EOPNOTSUPP; + + return local->ops->set_radar_offchan(&local->hw, chandef); +} + const struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -4487,4 +4499,5 @@ const struct cfg80211_ops mac80211_config_ops = { .reset_tid_config = ieee80211_reset_tid_config, .set_sar_specs = ieee80211_set_sar_specs, .color_change = ieee80211_color_change, + .set_radar_offchan = ieee80211_set_radar_offchan, }; -- 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 --- include/net/cfg80211.h | 14 ++++--------- net/wireless/core.c | 6 +++++- net/wireless/core.h | 7 +++++-- net/wireless/mlme.c | 56 ++++++++++++++++++++++++++++++++------------------ 4 files changed, 50 insertions(+), 33 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index db8866d42a4b..362da9f6bf39 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7645,19 +7645,13 @@ void cfg80211_cac_event(struct net_device *netdev, enum nl80211_radar_event event, gfp_t gfp); /** - * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event + * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event * @wiphy: the wiphy - * @chandef: chandef for the current channel - * @event: type of event - * - * This function is called when a Channel Availability Check (CAC) is finished, - * started or aborted by a offchannel dedicated chain. * - * Note that this acquires the wiphy lock. + * This function is called by the driver when a Channel Availability Check + * (CAC) is aborted by a offchannel dedicated chain. */ -void cfg80211_offchan_cac_event(struct wiphy *wiphy, - const struct cfg80211_chan_def *chandef, - enum nl80211_radar_event event); +void cfg80211_offchan_cac_abort(struct wiphy *wiphy); /** * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying 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 d787a3e38f01bfc4566df4e85d432a29d192e637 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 12 Nov 2021 12:22:23 +0100 Subject: mac80211: add support for .ndo_fill_forward_path This allows drivers to provide a destination device + info for flow offload Only supported in combination with 802.3 encap offload Signed-off-by: Felix Fietkau Tested-by: Lorenzo Bianconi Link: https://lore.kernel.org/r/20211112112223.1209-1-nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 ++++++ net/mac80211/driver-ops.h | 22 +++++++++++++++++ net/mac80211/ieee80211_i.h | 2 +- net/mac80211/iface.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/trace.h | 7 ++++++ 5 files changed, 96 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 775dbb982654..10e6fe215f0f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3952,6 +3952,8 @@ struct ieee80211_prep_tx_info { * radar channel. * The caller is expected to set chandef pointer to NULL in order to * disable offchannel CAC/radar detection. + * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to + * resolve a path for hardware flow offloading */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4282,6 +4284,11 @@ struct ieee80211_ops { struct ieee80211_sta *sta, u8 flowid); int (*set_radar_offchan)(struct ieee80211_hw *hw, struct cfg80211_chan_def *chandef); + int (*net_fill_forward_path)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct net_device_path_ctx *ctx, + struct net_device_path *path); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index cd3731cbf6c6..50a0cdadceec 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1483,4 +1483,26 @@ static inline void drv_twt_teardown_request(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline int drv_net_fill_forward_path(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + int ret = -EOPNOTSUPP; + + sdata = get_bss_sdata(sdata); + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_net_fill_forward_path(local, sdata, sta); + if (local->ops->net_fill_forward_path) + ret = local->ops->net_fill_forward_path(&local->hw, + &sdata->vif, sta, + ctx, path); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5666bbb8860b..08c0542c93a3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1463,7 +1463,7 @@ struct ieee80211_local { }; static inline struct ieee80211_sub_if_data * -IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) +IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev) { return netdev_priv(dev); } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 20aa5cc31f77..41531478437c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -789,6 +789,64 @@ static const struct net_device_ops ieee80211_monitorif_ops = { .ndo_get_stats64 = ieee80211_get_stats64, }; +static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; + struct sta_info *sta; + int ret = -ENOENT; + + sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev); + local = sdata->local; + + if (!local->ops->net_fill_forward_path) + return -EOPNOTSUPP; + + rcu_read_lock(); + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP_VLAN: + sta = rcu_dereference(sdata->u.vlan.sta); + if (sta) + break; + if (sdata->wdev.use_4addr) + goto out; + if (is_multicast_ether_addr(ctx->daddr)) + goto out; + sta = sta_info_get_bss(sdata, ctx->daddr); + break; + case NL80211_IFTYPE_AP: + if (is_multicast_ether_addr(ctx->daddr)) + goto out; + sta = sta_info_get(sdata, ctx->daddr); + break; + case NL80211_IFTYPE_STATION: + if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { + sta = sta_info_get(sdata, ctx->daddr); + if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { + if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) + goto out; + + break; + } + } + + sta = sta_info_get(sdata, sdata->u.mgd.bssid); + break; + default: + goto out; + } + + if (!sta) + goto out; + + ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path); +out: + rcu_read_unlock(); + + return ret; +} + static const struct net_device_ops ieee80211_dataif_8023_ops = { .ndo_open = ieee80211_open, .ndo_stop = ieee80211_stop, @@ -798,6 +856,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = { .ndo_set_mac_address = ieee80211_change_mac, .ndo_select_queue = ieee80211_netdev_select_queue, .ndo_get_stats64 = ieee80211_get_stats64, + .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path, }; static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 9e8381bef7ed..d91498f77796 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2892,6 +2892,13 @@ TRACE_EVENT(drv_twt_teardown_request, ) ); +DEFINE_EVENT(sta_event, drv_net_fill_forward_path, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta), + TP_ARGS(local, sdata, sta) +); + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- 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 --- include/net/cfg80211.h | 24 +++++++++++++++++++++--- net/wireless/mlme.c | 16 ++++++++++------ net/wireless/trace.h | 11 +++++++---- 3 files changed, 38 insertions(+), 13 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 362da9f6bf39..a887086cb103 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7605,15 +7605,33 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); /** - * cfg80211_radar_event - radar detection event + * __cfg80211_radar_event - radar detection event * @wiphy: the wiphy * @chandef: chandef for the current channel + * @offchan: the radar has been detected on the offchannel chain * @gfp: context flags * * This function is called when a radar is detected on the current chanenl. */ -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); + +static inline void +cfg80211_radar_event(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + gfp_t gfp) +{ + __cfg80211_radar_event(wiphy, chandef, false, gfp); +} + +static inline void +cfg80211_offchan_radar_event(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + gfp_t gfp) +{ + __cfg80211_radar_event(wiphy, chandef, true, gfp); +} /** * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event 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 fb5f6a0e8063b7a84d6d44ef353846ccd7708d2e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 18 Nov 2021 12:38:39 -0800 Subject: mac80211: Use memset_after() to clear tx status In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields. Use memset_after() so memset() doesn't get confused about writing beyond the destination member that is intended to be the starting point of zeroing through the end of the struct. Additionally fix the common helper, ieee80211_tx_info_clear_status(), which was not clearing ack_signal, but the open-coded versions did. Johannes Berg points out this bug was introduced by commit e3e1a0bcb3f1 ("mac80211: reduce IEEE80211_TX_MAX_RATES") but was harmless. Also drops the associated unneeded BUILD_BUG_ON()s, and adds a note to carl9170 about usage. Signed-off-by: Kees Cook Tested-by: Christian Lamparter [both CARL9170+P54USB on real HW] Link: https://lore.kernel.org/r/20211118203839.1289276-1-keescook@chromium.org Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/carl9170/tx.c | 12 ++++++------ drivers/net/wireless/intersil/p54/txrx.c | 6 +----- include/net/mac80211.h | 7 +------ 3 files changed, 8 insertions(+), 17 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 88444fe6d1c6..1b76f4434c06 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -275,12 +275,12 @@ static void carl9170_tx_release(struct kref *ref) if (WARN_ON_ONCE(!ar)) return; - BUILD_BUG_ON( - offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); - - memset(&txinfo->status.ack_signal, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); + /* + * This does not call ieee80211_tx_info_clear_status() because + * carl9170_tx_fill_rateinfo() has filled the rate information + * before we get to this point. + */ + memset_after(&txinfo->status, 0, rates); if (atomic_read(&ar->tx_total_queued)) ar->tx_schedule = true; diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 873fea59894f..8414aa208655 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -431,11 +431,7 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) * Clear manually, ieee80211_tx_info_clear_status would * clear the counts too and we need them. */ - memset(&info->status.ack_signal, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ack_signal)); - BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, - status.ack_signal) != 20); + memset_after(&info->status, 0, rates); if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) pad = entry_data->align[0]; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 10e6fe215f0f..e349f57d19ae 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1205,12 +1205,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) /* clear the rate counts */ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) info->status.rates[i].count = 0; - - BUILD_BUG_ON( - offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); - memset(&info->status.ampdu_ack_len, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + memset_after(&info->status, 0, rates); } -- cgit v1.2.3 From 6d501764288cf7869c7f54f1fcabd77bcd91b90e Mon Sep 17 00:00:00 2001 From: Nathan Errera Date: Mon, 29 Nov 2021 15:32:38 +0200 Subject: mac80211: introduce channel switch disconnect function Introduce a disconnect function that can be used when a channel switch error occurs. The channel switch can request to block the tx, and so, we need to make sure we do not send a deauth frame in this case. Signed-off-by: Nathan Errera Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20211129152938.cd2a615a0702.I9edb14785586344af17644b610ab5be109dcef00@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 12 ++++++++++++ net/mac80211/cfg.c | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e349f57d19ae..28e66cdae3ec 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6075,6 +6075,18 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw); */ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success); +/** + * ieee80211_channel_switch_disconnect - disconnect due to channel switch error + * @vif &struct ieee80211_vif pointer from the add_interface callback. + * @block_tx: if %true, do not send deauth frame. + * + * Instruct mac80211 to disconnect due to a channel switch error. The channel + * switch can request to block the tx and so, we need to make sure we do not send + * a deauth frame in this case. + */ +void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, + bool block_tx); + /** * ieee80211_request_smps - request SM PS transition * @vif: &struct ieee80211_vif pointer from the add_interface callback. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 26cc762835f7..8f15d9f30aac 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -5,7 +5,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include @@ -3198,6 +3198,18 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif) } EXPORT_SYMBOL(ieee80211_csa_finish); +void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_tx) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + + sdata->csa_block_tx = block_tx; + sdata_info(sdata, "channel switch failed, disconnecting\n"); + ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); +} +EXPORT_SYMBOL(ieee80211_channel_switch_disconnect); + static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, u32 *changed) { -- 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 --- include/net/cfg80211.h | 12 ++++++++++++ include/uapi/linux/nl80211.h | 7 +++++++ net/wireless/nl80211.c | 38 ++++++++++++++++++++++++++++++++++++++ net/wireless/trace.h | 17 +++++++++++++++++ 4 files changed, 74 insertions(+) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a887086cb103..c9a9073d4c2a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -8287,6 +8287,18 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype, bool is_4addr, u8 check_swif); +/** + * cfg80211_assoc_comeback - notification of association that was + * temporarly rejected with a comeback + * @netdev: network device + * @bss: the bss entry with which association is in progress. + * @timeout: timeout interval value TUs. + * + * this function may sleep. the caller must hold the corresponding wdev's mutex. + */ +void cfg80211_assoc_comeback(struct net_device *netdev, + struct cfg80211_bss *bss, u32 timeout); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index bf69ecbc1c24..a8e20d25252b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1232,6 +1232,11 @@ * &NL80211_ATTR_FILS_NONCES - for FILS Nonces * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) * + * @NL80211_CMD_ASSOC_COMEBACK: notification about an association + * temporal rejection with comeback. The event includes %NL80211_ATTR_MAC + * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to + * specify the timeout value. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1474,6 +1479,8 @@ enum nl80211_commands { NL80211_CMD_SET_FILS_AAD, + NL80211_CMD_ASSOC_COMEBACK, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ 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 --- include/net/cfg80211.h | 20 +++++----- include/net/mac80211.h | 10 ++--- include/uapi/linux/nl80211.h | 14 +++---- net/mac80211/cfg.c | 10 ++--- 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 +- 11 files changed, 102 insertions(+), 100 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c9a9073d4c2a..e29d904eccff 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4073,14 +4073,14 @@ struct mgmt_frame_regs { * those to decrypt (Re)Association Request and encrypt (Re)Association * Response frame. * - * @set_radar_offchan: Configure dedicated offchannel chain available for + * @set_radar_background: Configure dedicated offchannel chain available for * radar/CAC detection on some hw. This chain can't be used to transmit * or receive frames and it is bounded to a running wdev. - * Offchannel radar/CAC detection allows to avoid the CAC downtime + * Background radar/CAC detection allows to avoid the CAC downtime * switching to a different channel during CAC detection on the selected * radar channel. * The caller is expected to set chandef pointer to NULL in order to - * disable offchannel CAC/radar detection. + * disable background CAC/radar detection. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -4413,8 +4413,8 @@ struct cfg80211_ops { struct cfg80211_color_change_settings *params); int (*set_fils_aad)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_fils_aad *fils_aad); - int (*set_radar_offchan)(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef); + int (*set_radar_background)(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef); }; /* @@ -7626,9 +7626,9 @@ cfg80211_radar_event(struct wiphy *wiphy, } static inline void -cfg80211_offchan_radar_event(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef, - gfp_t gfp) +cfg80211_background_radar_event(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + gfp_t gfp) { __cfg80211_radar_event(wiphy, chandef, true, gfp); } @@ -7663,13 +7663,13 @@ void cfg80211_cac_event(struct net_device *netdev, enum nl80211_radar_event event, gfp_t gfp); /** - * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event + * cfg80211_background_cac_abort - Channel Availability Check offchan abort event * @wiphy: the wiphy * * This function is called by the driver when a Channel Availability Check * (CAC) is aborted by a offchannel dedicated chain. */ -void cfg80211_offchan_cac_abort(struct wiphy *wiphy); +void cfg80211_background_cac_abort(struct wiphy *wiphy); /** * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 28e66cdae3ec..8907338d52b5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3939,14 +3939,14 @@ struct ieee80211_prep_tx_info { * twt structure. * @twt_teardown_request: Update the hw with TWT teardown request received * from the peer. - * @set_radar_offchan: Configure dedicated offchannel chain available for + * @set_radar_background: Configure dedicated offchannel chain available for * radar/CAC detection on some hw. This chain can't be used to transmit * or receive frames and it is bounded to a running wdev. - * Offchannel radar/CAC detection allows to avoid the CAC downtime + * Background radar/CAC detection allows to avoid the CAC downtime * switching to a different channel during CAC detection on the selected * radar channel. * The caller is expected to set chandef pointer to NULL in order to - * disable offchannel CAC/radar detection. + * disable background CAC/radar detection. * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to * resolve a path for hardware flow offloading */ @@ -4277,8 +4277,8 @@ struct ieee80211_ops { struct ieee80211_twt_setup *twt); void (*twt_teardown_request)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 flowid); - int (*set_radar_offchan)(struct ieee80211_hw *hw, - struct cfg80211_chan_def *chandef); + int (*set_radar_background)(struct ieee80211_hw *hw, + struct cfg80211_chan_def *chandef); int (*net_fill_forward_path)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a8e20d25252b..5ce20fb44f24 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2646,10 +2646,10 @@ enum nl80211_commands { * Mandatory parameter for the transmitting interface to enable MBSSID. * Optional for the non-transmitting interfaces. * - * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for - * radar/CAC detection on some hw. This chain can't be used to transmit - * or receive frames and it is bounded to a running wdev. - * Offchannel radar/CAC detection allows to avoid the CAC downtime + * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain + * available for radar/CAC detection on some hw. This chain can't be used + * to transmit or receive frames and it is bounded to a running wdev. + * Background radar/CAC detection allows to avoid the CAC downtime * switching on a different channel during CAC detection on the selected * radar channel. * @@ -3159,7 +3159,7 @@ enum nl80211_attrs { NL80211_ATTR_MBSSID_CONFIG, NL80211_ATTR_MBSSID_ELEMS, - NL80211_ATTR_RADAR_OFFCHAN, + NL80211_ATTR_RADAR_BACKGROUND, /* add attributes here, update the policy in nl80211.c */ @@ -6066,7 +6066,7 @@ enum nl80211_feature_flags { * frames. Userspace has to share FILS AAD details to the driver by using * @NL80211_CMD_SET_FILS_AAD. * - * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC + * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC * detection. * * @NUM_NL80211_EXT_FEATURES: number of extended features. @@ -6135,7 +6135,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, NL80211_EXT_FEATURE_BSS_COLOR, NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD, - NL80211_EXT_FEATURE_RADAR_OFFCHAN, + NL80211_EXT_FEATURE_RADAR_BACKGROUND, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8f15d9f30aac..dc3746d5cdc1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4414,15 +4414,15 @@ out: } static int -ieee80211_set_radar_offchan(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef) +ieee80211_set_radar_background(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) { struct ieee80211_local *local = wiphy_priv(wiphy); - if (!local->ops->set_radar_offchan) + if (!local->ops->set_radar_background) return -EOPNOTSUPP; - return local->ops->set_radar_offchan(&local->hw, chandef); + return local->ops->set_radar_background(&local->hw, chandef); } const struct cfg80211_ops mac80211_config_ops = { @@ -4529,5 +4529,5 @@ const struct cfg80211_ops mac80211_config_ops = { .reset_tid_config = ieee80211_reset_tid_config, .set_sar_specs = ieee80211_set_sar_specs, .color_change = ieee80211_color_change, - .set_radar_offchan = ieee80211_set_radar_offchan, + .set_radar_background = ieee80211_set_radar_background, }; 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 --- include/net/cfg80211.h | 24 ++++++++++++---------- net/wireless/scan.c | 56 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 18 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e29d904eccff..b59baf9dfd67 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6385,17 +6385,6 @@ static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid, u64_to_ether_addr(new_bssid_u64, new_bssid); } -/** - * cfg80211_get_ies_channel_number - returns the channel number from ies - * @ie: IEs - * @ielen: length of IEs - * @band: enum nl80211_band of the channel - * - * Returns the channel number, or -1 if none could be determined. - */ -int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen, - enum nl80211_band band); - /** * cfg80211_is_element_inherited - returns if element ID should be inherited * @element: element to check @@ -6431,6 +6420,19 @@ enum cfg80211_bss_frame_type { CFG80211_BSS_FTYPE_PRESP, }; +/** + * cfg80211_get_ies_channel_number - returns the channel number from ies + * @ie: IEs + * @ielen: length of IEs + * @band: enum nl80211_band of the channel + * @ftype: frame type + * + * Returns the channel number, or -1 if none could be determined. + */ +int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen, + enum nl80211_band band, + enum cfg80211_bss_frame_type ftype); + /** * cfg80211_inform_bss_data - inform cfg80211 of a new BSS * 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 --- include/net/cfg80211.h | 11 ----------- include/uapi/linux/nl80211.h | 20 +++++++++++++++++++- net/wireless/nl80211.c | 8 ++++++-- 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b59baf9dfd67..d19e48f9fdc6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1187,17 +1187,6 @@ struct cfg80211_unsol_bcast_probe_resp { const u8 *tmpl; }; -/** - * enum cfg80211_ap_settings_flags - AP settings flags - * - * Used by cfg80211_ap_settings - * - * @AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external authentication - */ -enum cfg80211_ap_settings_flags { - AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = BIT(0), -}; - /** * struct cfg80211_ap_settings - AP configuration * diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5ce20fb44f24..ab461b2be157 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2477,7 +2477,9 @@ enum nl80211_commands { * space supports external authentication. This attribute shall be used * with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver * may offload authentication processing to user space if this capability - * is indicated in the respective requests from the user space. + * is indicated in the respective requests from the user space. (This flag + * attribute deprecated for %NL80211_CMD_START_AP, use + * %NL80211_ATTR_AP_SETTINGS_FLAGS) * * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. @@ -2653,6 +2655,10 @@ enum nl80211_commands { * switching on a different channel during CAC detection on the selected * radar channel. * + * @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags, + * enumerated in &enum nl80211_ap_settings_flags. This attribute shall be + * used with %NL80211_CMD_START_AP request. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3161,6 +3167,8 @@ enum nl80211_attrs { NL80211_ATTR_RADAR_BACKGROUND, + NL80211_ATTR_AP_SETTINGS_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -7481,4 +7489,14 @@ enum nl80211_mbssid_config_attributes { NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, }; +/** + * enum nl80211_ap_settings_flags - AP settings flags + * + * @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external + * authentication. + */ +enum nl80211_ap_settings_flags { + NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0, +}; + #endif /* __LINUX_NL80211_H */ 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