Introduce a new NL80211_ATTR_SCAN_CHANNEL_WIDTH attribute with enum nl80211_bss_scan_width semantics and add support to parse it for nl80211_commands NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN. Also add a new scan_width_set flag in the scan request sent to the driver to indicate whether the scan channel width is passed from the userspace. If channel width lower than 20 MHz is specified, it is expected that only BSSs using this channel width can be found. If 20 MHz or higher channel width is specified, it is expected that all the BSSs using 20 MHz or higher channel width can be found as their management frames can be received on the primary 20 MHz channel. If this attribute is not passed from the userspace, the scan channel width will be decided by the driver. One example for such use case is connection between drone and drone controller, userspace may need to specify the scan channel width, which needs to be passed to the driver to trigger the scan on this specified channel width. Signed-off-by: Xinyue Ling <quic_xinyling@xxxxxxxxxxx> --- include/net/cfg80211.h | 6 ++++++ include/uapi/linux/nl80211.h | 28 ++++++++++++++++++++++++++-- net/wireless/nl80211.c | 14 ++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 54a77d906b2d..bbf566190a87 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2400,6 +2400,8 @@ struct cfg80211_scan_6ghz_params { * @channels: channels to scan on. * @n_channels: total number of channels to scan * @scan_width: channel width for scanning + * @scan_width_set: channel width for scanning is specified from the + * userspace * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets * @duration: how long to listen on each channel, in TUs. If @@ -2430,6 +2432,7 @@ struct cfg80211_scan_request { int n_ssids; u32 n_channels; enum nl80211_bss_scan_width scan_width; + bool scan_width_set; const u8 *ie; size_t ie_len; u16 duration; @@ -2525,6 +2528,8 @@ struct cfg80211_bss_select_adjust { * @n_ssids: number of SSIDs * @n_channels: total number of channels to scan * @scan_width: channel width for scanning + * @scan_width_set: channel width for scanning is specified from the + * userspace * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets * @flags: bit field of flags controlling operation @@ -2573,6 +2578,7 @@ struct cfg80211_sched_scan_request { int n_ssids; u32 n_channels; enum nl80211_bss_scan_width scan_width; + bool scan_width_set; const u8 *ie; size_t ie_len; u32 flags; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3f15ac05f581..6d78185bb728 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -501,7 +501,13 @@ * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the * probe requests at CCK rate or not. %NL80211_ATTR_BSSID can be used to * specify a BSSID to scan for; if not included, the wildcard BSSID will - * be used. + * be used. %NL80211_ATTR_SCAN_CHANNEL_WIDTH can be passed from the + * userspace to specify the scan channel width; if channel bandwidth lower + * than 20 MHz is specified, it is expected that only BSSs using this channel + * bandwidth can be found; if 20 MHz or higher channel bandwidth channel + * bandwidth is specified, it is expected that all the BSSs using 20 MHz or + * higher channel bandwidth can be found; if not included, the scan channel + * bandwidth will be decided by the driver. * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to * NL80211_CMD_GET_SCAN and on the "scan" multicast group) * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, @@ -530,6 +536,13 @@ * is supplied. If the device supports multiple concurrent scheduled * scans, it will allow such when the caller provides the flag attribute * %NL80211_ATTR_SCHED_SCAN_MULTI to indicate user-space support for it. + * %NL80211_ATTR_SCAN_CHANNEL_WIDTH can be passed from the userspace to + * specify the scan channel width; if channel bandwidth lower than 20 MHz + * is specified, it is expected that only BSSs using this channel bandwidth + * can be found; if 20 MHz or higher channel bandwidth channel bandwidth is + * specified, it is expected that all the BSSs using 20 MHz or higher channel + * bandwidth can be found; if not included, the scan channel bandwidth will + * be decided by the driver. * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if * scheduled scan is not running. The caller may assume that as soon * as the call returns, it is safe to start a new scheduled scan again. @@ -2752,6 +2765,9 @@ enum nl80211_commands { * the incoming frame RX timestamp. * @NL80211_ATTR_TD_BITMAP: Transition Disable bitmap, for subsequent * (re)associations. + * @NL80211_ATTR_SCAN_CHANNEL_WIDTH: u32 attribute containing one of the + * values of &enum nl80211_bss_scan_width, describing the scan channel + * width. See the documentation of the enum for more information. * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3281,6 +3297,8 @@ enum nl80211_attrs { NL80211_ATTR_RX_HW_TIMESTAMP, NL80211_ATTR_TD_BITMAP, + NL80211_ATTR_SCAN_CHANNEL_WIDTH, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -4896,7 +4914,8 @@ enum nl80211_chan_width { /** * enum nl80211_bss_scan_width - control channel width for a BSS * - * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute. + * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute + * and the %NL80211_ATTR_SCAN_CHANNEL_WIDTH attribute. * * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide @@ -4906,6 +4925,9 @@ enum nl80211_chan_width { * @NL80211_BSS_CHAN_WIDTH_4: control channel is 4 MHz wide * @NL80211_BSS_CHAN_WIDTH_8: control channel is 8 MHz wide * @NL80211_BSS_CHAN_WIDTH_16: control channel is 16 MHz wide + * @NUM_NL80211_BSS_CHAN_WIDTH: number of values, avoid using this in + * userspace since newer kernel versions may support more channel + * widths */ enum nl80211_bss_scan_width { NL80211_BSS_CHAN_WIDTH_20, @@ -4916,6 +4938,8 @@ enum nl80211_bss_scan_width { NL80211_BSS_CHAN_WIDTH_4, NL80211_BSS_CHAN_WIDTH_8, NL80211_BSS_CHAN_WIDTH_16, + + NUM_NL80211_BSS_CHAN_WIDTH }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 64cf6110ce9d..bcafeb0691d0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -805,6 +805,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, + [NL80211_ATTR_SCAN_CHANNEL_WIDTH] = + NLA_POLICY_MAX(NLA_U32, NUM_NL80211_BSS_CHAN_WIDTH), }; /* policy for the key attributes */ @@ -9120,6 +9122,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]); } + if (info->attrs[NL80211_ATTR_SCAN_CHANNEL_WIDTH]) { + request->scan_width = + nla_get_u32(info->attrs[NL80211_ATTR_SCAN_CHANNEL_WIDTH]); + request->scan_width_set = true; + } + err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs, false); if (err) @@ -9611,6 +9619,12 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, request->ie_len); } + if (attrs[NL80211_ATTR_SCAN_CHANNEL_WIDTH]) { + request->scan_width = + nla_get_u32(attrs[NL80211_ATTR_SCAN_CHANNEL_WIDTH]); + request->scan_width_set = true; + } + err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true); if (err) goto out_free; -- 2.25.1