--- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2191,6 +2191,7 @@ struct cfg80211_scan_6ghz_params { * @channels: channels to scan on. * @n_channels: total number of channels to scan * @scan_width: channel width for scanning + * @chandef: defines the channel to do wide band scan * @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 @@ -2221,6 +2222,7 @@ struct cfg80211_scan_request { int n_ssids; u32 n_channels; enum nl80211_bss_scan_width scan_width; + struct cfg80211_chan_def *chandef; const u8 *ie; size_t ie_len; u16 duration; --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5937,6 +5937,9 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate * configuration (AP/mesh) with HE rates. * + * @NL80211_EXT_FEATURE_WIDE_BAND_SCAN: Driver/device supports wide band scan + * on a frequency along with its corresponding phymode (40Mhz, 80Mhz) + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5998,6 +6001,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_FILS_DISCOVERY, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP, NL80211_EXT_FEATURE_BEACON_RATE_HE, + NL80211_EXT_FEATURE_WIDE_BAND_SCAN, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -6114,6 +6118,8 @@ enum nl80211_timeout_reason { * %NL80211_ATTR_SCAN_FREQUENCIES will not be included. * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by * 2.4/5 GHz APs + * @NL80211_SCAN_FLAG_WIDE_BAND_SCAN: This flag intends the driver to perform + * wide band scan only if the driver supports it. */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, @@ -6131,6 +6137,7 @@ enum nl80211_scan_flags { NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12, NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13, NL80211_SCAN_FLAG_COLOCATED_6GHZ = 1<<14, + NL80211_SCAN_FLAG_WIDE_BAND_SCAN = 1<<15, }; /** --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -703,11 +703,13 @@ static int __ieee80211_start_scan(struct local->hw_scan_req = kmalloc( sizeof(*local->hw_scan_req) + + sizeof(*req->chandef) + req->n_channels * sizeof(req->channels[0]) + local->hw_scan_ies_bufsize, GFP_KERNEL); if (!local->hw_scan_req) return -ENOMEM; + local->hw_scan_req->req.chandef = req->chandef; local->hw_scan_req->req.ssids = req->ssids; local->hw_scan_req->req.n_ssids = req->n_ssids; ies = (u8 *)local->hw_scan_req + --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8234,7 +8234,10 @@ nl80211_check_scan_flags(struct wiphy *w NL80211_EXT_FEATURE_SCAN_RANDOM_SN) || !nl80211_check_scan_feat(wiphy, *flags, NL80211_SCAN_FLAG_MIN_PREQ_CONTENT, - NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT)) + NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT) || + !nl80211_check_scan_feat(wiphy, *flags, + NL80211_SCAN_FLAG_WIDE_BAND_SCAN, + NL80211_EXT_FEATURE_WIDE_BAND_SCAN)) return -EOPNOTSUPP; if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { @@ -8259,10 +8262,12 @@ static int nl80211_trigger_scan(struct s struct cfg80211_scan_request *request; struct nlattr *scan_freqs = NULL; bool scan_freqs_khz = false; + struct cfg80211_chan_def chandef; struct nlattr *attr; struct wiphy *wiphy; - int err, tmp, n_ssids = 0, n_channels, i; + int err, tmp, n_ssids = 0, n_channels = 0, i; size_t ie_len; + bool chandef_found = false; wiphy = &rdev->wiphy; @@ -8275,7 +8280,12 @@ static int nl80211_trigger_scan(struct s if (rdev->scan_req || rdev->scan_msg) return -EBUSY; - if (info->attrs[NL80211_ATTR_SCAN_FREQ_KHZ]) { + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { + if (nl80211_parse_chandef(rdev, info, &chandef)) { + return -EINVAL; + } + chandef_found = true; + } else if (info->attrs[NL80211_ATTR_SCAN_FREQ_KHZ]) { if (!wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_SCAN_FREQ_KHZ)) return -EOPNOTSUPP; @@ -8288,6 +8298,8 @@ static int nl80211_trigger_scan(struct s n_channels = validate_scan_freqs(scan_freqs); if (!n_channels) return -EINVAL; + } else if (chandef_found) { + n_channels = 1; } else { n_channels = ieee80211_get_num_supported_channels(wiphy); } @@ -8308,12 +8320,19 @@ static int nl80211_trigger_scan(struct s return -EINVAL; request = kzalloc(sizeof(*request) + + sizeof(*request->chandef) + sizeof(*request->ssids) * n_ssids + sizeof(*request->channels) * n_channels + ie_len, GFP_KERNEL); if (!request) return -ENOMEM; + if (chandef_found) { + request->chandef = &chandef; + request->channels[0] = chandef.chan; + request->n_channels = n_channels; + } + if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; request->n_ssids = n_ssids; @@ -8347,7 +8366,7 @@ static int nl80211_trigger_scan(struct s request->channels[i] = chan; i++; } - } else { + } else if (!chandef_found) { enum nl80211_band band; /* all channels */ @@ -8370,31 +8389,32 @@ static int nl80211_trigger_scan(struct s } } - if (!i) { - err = -EINVAL; - goto out_free; - } - - request->n_channels = i; - - wdev_lock(wdev); - if (!cfg80211_off_channel_oper_allowed(wdev)) { - struct ieee80211_channel *chan; - - if (request->n_channels != 1) { - wdev_unlock(wdev); - err = -EBUSY; + if (!chandef_found) { + if (!i) { + err = -EINVAL; goto out_free; } + request->n_channels = i; - chan = request->channels[0]; - if (chan->center_freq != wdev->chandef.chan->center_freq) { - wdev_unlock(wdev); - err = -EBUSY; - goto out_free; + wdev_lock(wdev); + if (!cfg80211_off_channel_oper_allowed(wdev)) { + struct ieee80211_channel *chan; + + if (request->n_channels != 1) { + wdev_unlock(wdev); + err = -EBUSY; + goto out_free; + } + + chan = request->channels[0]; + if (chan->center_freq != wdev->chandef.chan->center_freq) { + wdev_unlock(wdev); + err = -EBUSY; + goto out_free; + } } + wdev_unlock(wdev); } - wdev_unlock(wdev); i = 0; if (n_ssids) {