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..03b60d987a1b 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_CHANNEL_WIDTH can be passed from the userspace
+ *	to specify the scan channel bandwidth; 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 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_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 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.
@@ -4875,6 +4888,8 @@ enum nl80211_key_mode {
  * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
  * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
  *	attribute must be provided as well
+ * @NUM_NL80211_CHAN_WIDTH: number of values, avoid using this in userspace
+ *	since newer kernel versions may support more channel widths
  */
 enum nl80211_chan_width {
 	NL80211_CHAN_WIDTH_20_NOHT,
@@ -4891,6 +4906,8 @@ enum nl80211_chan_width {
 	NL80211_CHAN_WIDTH_8,
 	NL80211_CHAN_WIDTH_16,
 	NL80211_CHAN_WIDTH_320,
+
+	NUM_NL80211_CHAN_WIDTH
 };
 
 /**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 64cf6110ce9d..2048a98c3273 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -478,7 +478,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 						NL80211_EDMG_BW_CONFIG_MIN,
 						NL80211_EDMG_BW_CONFIG_MAX),
 
-	[NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
+	[NL80211_ATTR_CHANNEL_WIDTH] =
+		NLA_POLICY_MAX(NLA_U32, NUM_NL80211_CHAN_WIDTH),
 	[NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
 	[NL80211_ATTR_CENTER_FREQ1_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
 	[NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
@@ -8924,6 +8925,34 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
 	return 0;
 }
 
+static enum nl80211_bss_scan_width
+chan_width_to_scan_width(enum nl80211_chan_width width)
+{
+	switch (width) {
+	case NL80211_CHAN_WIDTH_5:
+		return NL80211_BSS_CHAN_WIDTH_5;
+	case NL80211_CHAN_WIDTH_10:
+		return NL80211_BSS_CHAN_WIDTH_10;
+	case NL80211_CHAN_WIDTH_1:
+		return NL80211_BSS_CHAN_WIDTH_1;
+	case NL80211_CHAN_WIDTH_2:
+		return NL80211_BSS_CHAN_WIDTH_2;
+	case NL80211_CHAN_WIDTH_4:
+		return NL80211_BSS_CHAN_WIDTH_4;
+	case NL80211_CHAN_WIDTH_8:
+		return NL80211_BSS_CHAN_WIDTH_8;
+	case NL80211_CHAN_WIDTH_16:
+		return NL80211_BSS_CHAN_WIDTH_16;
+	default:
+		/* for the rest of channel bandwidth values (20 MHz or higher),
+		 * scan channel bandwidth can be set to NL80211_BSS_CHAN_WIDTH_20
+		 * as management frames of BSSs using 20 MHz or higher channel
+		 * can be received on the primary 20 MHz channel
+		 */
+		return NL80211_BSS_CHAN_WIDTH_20;
+	}
+}
+
 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -9120,6 +9149,14 @@ 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_CHANNEL_WIDTH]) {
+		enum nl80211_chan_width chan_width;
+
+		chan_width = nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
+		request->scan_width = chan_width_to_scan_width(chan_width);
+		request->scan_width_set = true;
+	}
+
 	err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
 				       false);
 	if (err)
@@ -9611,6 +9648,14 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
 		       request->ie_len);
 	}
 
+	if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
+		enum nl80211_chan_width chan_width;
+
+		chan_width = nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH]);
+		request->scan_width = chan_width_to_scan_width(chan_width);
+		request->scan_width_set = true;
+	}
+
 	err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
 	if (err)
 		goto out_free;
