* @bssid: BSSID to be matched; may be all-zero BSSID in case of SSID match
  *     or no match (RSSI only)
  * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
+ * @per_band_rssi_thold: Minimum rssi threshold for each band to be applied
+ *     for filtering out scan results received. Drivers advertize this support
+ *     of band specific rssi based filtering through the feature capability
+ *     %NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD. These band
+ *     specific rssi thresholds take precedence over rssi_thold, if specified.
+ *     If not specified for any band, it will be assigned with rssi_thold of
+ *     corresponding matchset.
  */
 struct cfg80211_match_set {
        struct cfg80211_ssid ssid;
        u8 bssid[ETH_ALEN];
        s32 rssi_thold;
+       s32 per_band_rssi_thold[NUM_NL80211_BANDS];
 };
 
 /**
 
  *     value as specified by &struct nl80211_bss_select_rssi_adjust.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching
  *     (this cannot be used together with SSID).
+ * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Nested attribute that carries the
+ *     band specific minimum rssi thresholds for the bands defined in
+ *     enum nl80211_band. The minimum rssi threshold value(s32) specific to a
+ *     band shall be encapsulated in attribute with type value equals to one
+ *     of the NL80211_BAND_* defined in enum nl80211_band. For example, the
+ *     minimum rssi threshold value for 2.4GHZ band shall be encapsulated
+ *     within an attribute of type NL80211_BAND_2GHZ. And one or more of such
+ *     attributes will be nested within this attribute.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *     attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
        NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
        NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
        NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
+       NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI,
 
        /* keep last */
        __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
  * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching
  *     (set/del PMKSA operations) in AP mode.
  *
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports
+ *     filtering of sched scan results using band specific RSSI thresholds.
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
        NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
        NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
        NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
+       NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
 
        [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
 };
 
+static const struct nla_policy
+nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
+       [NL80211_BAND_2GHZ] = { .type = NLA_S32 },
+       [NL80211_BAND_5GHZ] = { .type = NLA_S32 },
+       [NL80211_BAND_60GHZ] = { .type = NLA_S32 },
+};
+
 static const struct nla_policy
 nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
        [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
                                                 .len = IEEE80211_MAX_SSID_LEN },
        [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN },
        [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
+       [NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
+               NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
 };
 
 static const struct nla_policy
        return 0;
 }
 
+static int
+nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy,
+                                      struct cfg80211_match_set *match_sets,
+                                      struct nlattr *tb_band_rssi,
+                                      s32 rssi_thold)
+{
+       struct nlattr *attr;
+       int i, tmp, ret = 0;
+
+       if (!wiphy_ext_feature_isset(wiphy,
+                   NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) {
+               if (tb_band_rssi)
+                       ret = -EOPNOTSUPP;
+               else
+                       for (i = 0; i < NUM_NL80211_BANDS; i++)
+                               match_sets->per_band_rssi_thold[i] =
+                                       NL80211_SCAN_RSSI_THOLD_OFF;
+               return ret;
+       }
+
+       for (i = 0; i < NUM_NL80211_BANDS; i++)
+               match_sets->per_band_rssi_thold[i] = rssi_thold;
+
+       nla_for_each_nested(attr, tb_band_rssi, tmp) {
+               enum nl80211_band band = nla_type(attr);
+
+               if (band < 0 || band >= NUM_NL80211_BANDS)
+                       return -EINVAL;
+
+               match_sets->per_band_rssi_thold[band] = nla_get_s32(attr);
+       }
+
+       return 0;
+}
+
 static struct cfg80211_sched_scan_request *
 nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                         struct nlattr **attrs, int max_match_sets)
                        if (rssi)
                                request->match_sets[i].rssi_thold =
                                        nla_get_s32(rssi);
+
+                       /* Parse per band RSSI attribute */
+                       err = nl80211_parse_sched_scan_per_band_rssi(wiphy,
+                               &request->match_sets[i],
+                               tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI],
+                               request->match_sets[i].rssi_thold);
+                       if (err)
+                               goto out_free;
+
                        i++;
                }