Merge "cfg80211: Define macro for report better BSS in sched scan"

This commit is contained in:
Linux Build Service Account 2017-01-30 07:05:05 -08:00 committed by Gerrit - the friendly Code Review server
commit 3f2738720d
4 changed files with 285 additions and 0 deletions

View file

@ -70,6 +70,7 @@ struct wiphy;
#define CFG80211_UPDATE_CONNECT_PARAMS 1
#define CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT 1
#define CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME 1
#define CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN 1
/*
* wireless hardware capability structures
@ -1568,6 +1569,17 @@ struct cfg80211_sched_scan_plan {
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
*
@ -1603,6 +1615,16 @@ struct cfg80211_sched_scan_plan {
* 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;
@ -1622,6 +1644,10 @@ struct cfg80211_sched_scan_request {
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;
@ -1906,6 +1932,22 @@ struct cfg80211_ibss_params {
struct ieee80211_ht_cap ht_capa_mask;
};
/**
* struct cfg80211_bss_selection - connection parameters for BSS selection.
*
* @behaviour: requested BSS selection behaviour.
* @param: parameters for requestion behaviour.
* @band_pref: preferred band for %NL80211_BSS_SELECT_ATTR_BAND_PREF.
* @adjust: parameters for %NL80211_BSS_SELECT_ATTR_RSSI_ADJUST.
*/
struct cfg80211_bss_selection {
enum nl80211_bss_select_attr behaviour;
union {
enum ieee80211_band band_pref;
struct cfg80211_bss_select_adjust adjust;
} param;
};
/**
* struct cfg80211_connect_params - Connection parameters
*
@ -1943,6 +1985,7 @@ struct cfg80211_ibss_params {
* @vht_capa_mask: The bits of vht_capa which are to be used.
* @pbss: if set, connect to a PCP instead of AP. Valid for DMG
* networks.
* @bss_select: criteria to be used for BSS selection.
* @prev_bssid: previous BSSID, if not %NULL use reassociate frame
*/
struct cfg80211_connect_params {
@ -1967,6 +2010,7 @@ struct cfg80211_connect_params {
struct ieee80211_vht_cap vht_capa;
struct ieee80211_vht_cap vht_capa_mask;
bool pbss;
struct cfg80211_bss_selection bss_select;
const u8 *prev_bssid;
};
@ -3284,6 +3328,9 @@ struct wiphy_iftype_ext_capab {
* low rssi when a frame is heard on different channel, then it should set
* this variable to the maximal offset for which it can compensate.
* This value should be set in MHz.
* @bss_select_support: bitmask indicating the BSS selection criteria supported
* by the driver in the .connect() callback. The bit position maps to the
* attribute indices defined in &enum nl80211_bss_select_attr.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@ -3411,6 +3458,8 @@ struct wiphy {
u8 max_num_csa_counters;
u8 max_adj_channel_rssi_comp;
u32 bss_select_support;
char priv[0] __aligned(NETDEV_ALIGN);
};

View file

@ -1934,6 +1934,20 @@ enum nl80211_commands {
* @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
@ -2340,6 +2354,9 @@ enum nl80211_attrs {
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,
@ -3008,6 +3025,13 @@ enum nl80211_reg_rule_attr {
* 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
@ -3017,6 +3041,8 @@ enum nl80211_sched_scan_match_attr {
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,
@ -4609,6 +4635,9 @@ enum nl80211_feature_flags {
* 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.
@ -4626,6 +4655,7 @@ enum nl80211_ext_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,
@ -4875,4 +4905,48 @@ enum nl80211_sched_scan_plan {
__NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1
};
/**
* struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters.
*
* @band: band of BSS that must match for RSSI value adjustment.
* @delta: value used to adjust the RSSI value of matching BSS.
*/
struct nl80211_bss_select_rssi_adjust {
__u8 band;
__s8 delta;
} __attribute__((packed));
/**
* enum nl80211_bss_select_attr - attributes for bss selection.
*
* @__NL80211_BSS_SELECT_ATTR_INVALID: reserved.
* @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection
* is requested.
* @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS
* selection should be done such that the specified band is preferred.
* When there are multiple BSS-es in the preferred band, the driver
* shall use RSSI-based BSS selection as a second step. The value of
* this attribute is according to &enum nl80211_band (u32).
* @NL80211_BSS_SELECT_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_BSS_SELECT_ATTR_MAX: highest bss select attribute number.
* @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use.
*
* One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT
* for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour
* which the driver shall use.
*/
enum nl80211_bss_select_attr {
__NL80211_BSS_SELECT_ATTR_INVALID,
NL80211_BSS_SELECT_ATTR_RSSI,
NL80211_BSS_SELECT_ATTR_BAND_PREF,
NL80211_BSS_SELECT_ATTR_RSSI_ADJUST,
/* keep last */
__NL80211_BSS_SELECT_ATTR_AFTER_LAST,
NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1
};
#endif /* __LINUX_NL80211_H */

View file

@ -619,6 +619,13 @@ int wiphy_register(struct wiphy *wiphy)
!rdev->ops->set_mac_acl)))
return -EINVAL;
/* assure only valid behaviours are flagged by driver
* hence subtract 2 as bit 0 is invalid.
*/
if (WARN_ON(wiphy->bss_select_support &&
(wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2))))
return -EINVAL;
if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);

View file

@ -402,7 +402,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
[NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
[NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
[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 */
@ -487,6 +492,15 @@ nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
[NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
};
static const struct nla_policy
nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
[NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
[NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
},
};
static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct cfg80211_registered_device **rdev,
@ -1778,6 +1792,25 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
}
}
if (rdev->wiphy.bss_select_support) {
struct nlattr *nested;
u32 bss_select_support = rdev->wiphy.bss_select_support;
nested = nla_nest_start(msg, NL80211_ATTR_BSS_SELECT);
if (!nested)
goto nla_put_failure;
i = 0;
while (bss_select_support) {
if ((bss_select_support & 1) &&
nla_put_flag(msg, i))
goto nla_put_failure;
i++;
bss_select_support >>= 1;
}
nla_nest_end(msg, nested);
}
/* done */
state->split_start = 0;
break;
@ -6087,6 +6120,73 @@ static int validate_scan_freqs(struct nlattr *freqs)
return n_channels;
}
static bool is_band_valid(struct wiphy *wiphy, enum ieee80211_band b)
{
return b < IEEE80211_NUM_BANDS && wiphy->bands[b];
}
static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
struct cfg80211_bss_selection *bss_select)
{
struct nlattr *attr[NL80211_BSS_SELECT_ATTR_MAX + 1];
struct nlattr *nest;
int err;
bool found = false;
int i;
/* only process one nested attribute */
nest = nla_data(nla);
if (!nla_ok(nest, nla_len(nest)))
return -EINVAL;
err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest),
nla_len(nest), nl80211_bss_select_policy);
if (err)
return err;
/* only one attribute may be given */
for (i = 0; i <= NL80211_BSS_SELECT_ATTR_MAX; i++) {
if (attr[i]) {
if (found)
return -EINVAL;
found = true;
}
}
bss_select->behaviour = __NL80211_BSS_SELECT_ATTR_INVALID;
if (attr[NL80211_BSS_SELECT_ATTR_RSSI])
bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI;
if (attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]) {
bss_select->behaviour = NL80211_BSS_SELECT_ATTR_BAND_PREF;
bss_select->param.band_pref =
nla_get_u32(attr[NL80211_BSS_SELECT_ATTR_BAND_PREF]);
if (!is_band_valid(wiphy, bss_select->param.band_pref))
return -EINVAL;
}
if (attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]) {
struct nl80211_bss_select_rssi_adjust *adj_param;
adj_param = nla_data(attr[NL80211_BSS_SELECT_ATTR_RSSI_ADJUST]);
bss_select->behaviour = NL80211_BSS_SELECT_ATTR_RSSI_ADJUST;
bss_select->param.adjust.band = adj_param->band;
bss_select->param.adjust.delta = adj_param->delta;
if (!is_band_valid(wiphy, bss_select->param.adjust.band))
return -EINVAL;
}
/* user-space did not provide behaviour attribute */
if (bss_select->behaviour == __NL80211_BSS_SELECT_ATTR_INVALID)
return -EINVAL;
if (!(wiphy->bss_select_support & BIT(bss_select->behaviour)))
return -EINVAL;
return 0;
}
static int nl80211_parse_random_mac(struct nlattr **attrs,
u8 *mac_addr, u8 *mac_addr_mask)
{
@ -6557,6 +6657,12 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
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
@ -6762,6 +6868,26 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
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;
@ -8349,6 +8475,21 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
}
if (info->attrs[NL80211_ATTR_BSS_SELECT]) {
/* bss selection makes no sense if bssid is set */
if (connect.bssid) {
kzfree(connkeys);
return -EINVAL;
}
err = parse_bss_select(info->attrs[NL80211_ATTR_BSS_SELECT],
wiphy, &connect.bss_select);
if (err) {
kzfree(connkeys);
return err;
}
}
wdev_lock(dev->ieee80211_ptr);
err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
wdev_unlock(dev->ieee80211_ptr);
@ -9245,6 +9386,20 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
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;