u32 iterations;
 };
 
+/**
+ * struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment.
+ *
+ * @band: band of BSS which should match for RSSI level adjustment.
+ * @delta: value of RSSI level adjustment.
+ */
+struct cfg80211_bss_select_adjust {
+       enum nl80211_band band;
+       s8 delta;
+};
+
 /**
  * struct cfg80211_sched_scan_request - scheduled scan request description
  *
  *     cycle.  The driver may ignore this parameter and start
  *     immediately (or at any other time), if this feature is not
  *     supported.
+ * @relative_rssi_set: Indicates whether @relative_rssi is set or not.
+ * @relative_rssi: Relative RSSI threshold in dB to restrict scan result
+ *     reporting in connected state to cases where a matching BSS is determined
+ *     to have better or slightly worse RSSI than the current connected BSS.
+ *     The relative RSSI threshold values are ignored in disconnected state.
+ * @rssi_adjust: delta dB of RSSI preference to be given to the BSSs that belong
+ *     to the specified band while deciding whether a better BSS is reported
+ *     using @relative_rssi. If delta is a negative number, the BSSs that
+ *     belong to the specified band will be penalized by delta dB in relative
+ *     comparisions.
  */
 struct cfg80211_sched_scan_request {
        struct cfg80211_ssid *ssids;
        u8 mac_addr[ETH_ALEN] __aligned(2);
        u8 mac_addr_mask[ETH_ALEN] __aligned(2);
 
+       bool relative_rssi_set;
+       s8 relative_rssi;
+       struct cfg80211_bss_select_adjust rssi_adjust;
+
        /* internal */
        struct wiphy *wiphy;
        struct net_device *dev;
        struct ieee80211_ht_cap ht_capa_mask;
 };
 
-/**
- * struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment.
- *
- * @band: band of BSS which should match for RSSI level adjustment.
- * @delta: value of RSSI level adjustment.
- */
-struct cfg80211_bss_select_adjust {
-       enum nl80211_band band;
-       s8 delta;
-};
-
 /**
  * struct cfg80211_bss_selection - connection parameters for BSS selection.
  *
 
  * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
  *     used in various commands/events for specifying the BSSID.
  *
+ * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which
+ *     other BSSs has to be better or slightly worse than the current
+ *     connected BSS so that they get reported to user space.
+ *     This will give an opportunity to userspace to consider connecting to
+ *     other matching BSSs which have better or slightly worse RSSI than
+ *     the current connected BSS by using an offloaded operation to avoid
+ *     unnecessary wakeups.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
+ *     the specified band is to be adjusted before doing
+ *     %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
+ *     better BSSs. The attribute value is a packed structure
+ *     value as specified by &struct nl80211_bss_select_rssi_adjust.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
 
        NL80211_ATTR_BSSID,
 
+       NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+       NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
  *     how this API was implemented in the past. Also, due to the same problem,
  *     the only way to create a matchset with only an RSSI filter (with this
  *     attribute) is if there's only a single matchset with the RSSI attribute.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether
+ *     %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or
+ *     relative to current bss's RSSI.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for
+ *     BSS-es in the specified band is to be adjusted before doing
+ *     RSSI-based BSS selection. The attribute value is a packed structure
+ *     value as specified by &struct nl80211_bss_select_rssi_adjust.
  * @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_SSID,
        NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+       NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
+       NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
 
        /* keep last */
        __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
  *     in @NL80211_CMD_FRAME while not associated.
  * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports
  *     randomized TA in @NL80211_CMD_FRAME while associated.
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
+ *     for reporting BSSs with better RSSI than the current connected BSS
+ *     (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
        NL80211_EXT_FEATURE_FILS_STA,
        NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
        NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
+       NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
 
        [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
        [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
        [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
+       [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
+       [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
+               .len = sizeof(struct nl80211_bss_select_rssi_adjust)
+       },
 };
 
 /* policy for the key attributes */
        if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
                return ERR_PTR(-EINVAL);
 
+       if (!wiphy_ext_feature_isset(
+                   wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
+           (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
+            attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
+               return ERR_PTR(-EINVAL);
+
        request = kzalloc(sizeof(*request)
                        + sizeof(*request->ssids) * n_ssids
                        + sizeof(*request->match_sets) * n_match_sets
                request->delay =
                        nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
 
+       if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
+               request->relative_rssi = nla_get_s8(
+                       attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
+               request->relative_rssi_set = true;
+       }
+
+       if (request->relative_rssi_set &&
+           attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
+               struct nl80211_bss_select_rssi_adjust *rssi_adjust;
+
+               rssi_adjust = nla_data(
+                       attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
+               request->rssi_adjust.band = rssi_adjust->band;
+               request->rssi_adjust.delta = rssi_adjust->delta;
+               if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
+                       err = -EINVAL;
+                       goto out_free;
+               }
+       }
+
        err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
        if (err)
                goto out_free;
        if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
                return -ENOBUFS;
 
+       if (req->relative_rssi_set) {
+               struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+               if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+                              req->relative_rssi))
+                       return -ENOBUFS;
+
+               rssi_adjust.band = req->rssi_adjust.band;
+               rssi_adjust.delta = req->rssi_adjust.delta;
+               if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+                           sizeof(rssi_adjust), &rssi_adjust))
+                       return -ENOBUFS;
+       }
+
        freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
        if (!freqs)
                return -ENOBUFS;