mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-23 18:14:04 +08:00
wifi: cfg80211: remove cfg80211_inform_single_bss_frame_data()
This function pretty much does what cfg80211_inform_single_bss_data() already does, except on a frame data. But we can call the other one, after populating the inform_data more completely, so we don't need to do everything twice. This also uncovered a few bugs: * the 6 GHz power type checks were only done in this function, move (and rename from 'uhb') those; * the chains/chain_signal information wasn't used in the latter, add that Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://msgid.link/20240216135047.f3f864f94c78.I2192adb32ab10713e71f395a9d203386264f6ed5@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
f8599d6340
commit
317bad4c3b
@ -2087,6 +2087,35 @@ struct cfg80211_inform_single_bss_data {
|
||||
u64 cannot_use_reasons;
|
||||
};
|
||||
|
||||
static bool cfg80211_6ghz_power_type_valid(const u8 *ie, size_t ielen,
|
||||
const u32 flags)
|
||||
{
|
||||
const struct element *tmp;
|
||||
struct ieee80211_he_operation *he_oper;
|
||||
|
||||
tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen);
|
||||
if (tmp && tmp->datalen >= sizeof(*he_oper) + 1) {
|
||||
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
|
||||
|
||||
he_oper = (void *)&tmp->data[1];
|
||||
he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper);
|
||||
|
||||
if (!he_6ghz_oper)
|
||||
return false;
|
||||
|
||||
switch (u8_get_bits(he_6ghz_oper->control,
|
||||
IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
|
||||
case IEEE80211_6GHZ_CTRL_REG_LPI_AP:
|
||||
return true;
|
||||
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
|
||||
return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT);
|
||||
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
|
||||
return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
static struct cfg80211_bss *
|
||||
cfg80211_inform_single_bss_data(struct wiphy *wiphy,
|
||||
@ -2119,6 +2148,14 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
if (channel->band == NL80211_BAND_6GHZ &&
|
||||
!cfg80211_6ghz_power_type_valid(data->ie, data->ielen,
|
||||
channel->flags)) {
|
||||
data->use_for = 0;
|
||||
data->cannot_use_reasons =
|
||||
NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH;
|
||||
}
|
||||
|
||||
memcpy(tmp.pub.bssid, data->bssid, ETH_ALEN);
|
||||
tmp.pub.channel = channel;
|
||||
if (data->bss_source != BSS_SOURCE_STA_PROFILE)
|
||||
@ -2130,6 +2167,9 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
|
||||
tmp.ts_boottime = drv_data->boottime_ns;
|
||||
tmp.parent_tsf = drv_data->parent_tsf;
|
||||
ether_addr_copy(tmp.parent_bssid, drv_data->parent_bssid);
|
||||
tmp.pub.chains = drv_data->chains;
|
||||
memcpy(tmp.pub.chain_signal, drv_data->chain_signal,
|
||||
IEEE80211_MAX_CHAINS);
|
||||
tmp.pub.use_for = data->use_for;
|
||||
tmp.pub.cannot_use_reasons = data->cannot_use_reasons;
|
||||
|
||||
@ -3025,59 +3065,23 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss_data);
|
||||
|
||||
static bool cfg80211_uhb_power_type_valid(const u8 *ie,
|
||||
size_t ielen,
|
||||
const u32 flags)
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
const struct element *tmp;
|
||||
struct ieee80211_he_operation *he_oper;
|
||||
|
||||
tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen);
|
||||
if (tmp && tmp->datalen >= sizeof(*he_oper) + 1) {
|
||||
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
|
||||
|
||||
he_oper = (void *)&tmp->data[1];
|
||||
he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper);
|
||||
|
||||
if (!he_6ghz_oper)
|
||||
return false;
|
||||
|
||||
switch (u8_get_bits(he_6ghz_oper->control,
|
||||
IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
|
||||
case IEEE80211_6GHZ_CTRL_REG_LPI_AP:
|
||||
return true;
|
||||
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
|
||||
return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT);
|
||||
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
|
||||
return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* cfg80211_inform_bss_width_frame helper */
|
||||
static struct cfg80211_bss *
|
||||
cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
bool signal_valid;
|
||||
struct cfg80211_inform_single_bss_data inform_data = {
|
||||
.drv_data = data,
|
||||
.use_for = data->restrict_use ?
|
||||
data->use_for :
|
||||
NL80211_BSS_USE_FOR_ALL,
|
||||
.cannot_use_reasons = data->cannot_use_reasons,
|
||||
};
|
||||
size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
struct ieee80211_ext *ext = NULL;
|
||||
u8 *bssid, *variable;
|
||||
u16 capability, beacon_int;
|
||||
size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
int bss_type;
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
|
||||
offsetof(struct ieee80211_mgmt, u.beacon.variable));
|
||||
|
||||
trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len);
|
||||
struct cfg80211_bss *res;
|
||||
|
||||
if (WARN_ON(!mgmt))
|
||||
return NULL;
|
||||
@ -3085,9 +3089,10 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
||||
if (WARN_ON(!wiphy))
|
||||
return NULL;
|
||||
|
||||
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
|
||||
(data->signal < 0 || data->signal > 100)))
|
||||
return NULL;
|
||||
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
|
||||
offsetof(struct ieee80211_mgmt, u.beacon.variable));
|
||||
|
||||
trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len);
|
||||
|
||||
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
|
||||
ext = (void *) mgmt;
|
||||
@ -3100,140 +3105,50 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
||||
if (WARN_ON(len < min_hdr_len))
|
||||
return NULL;
|
||||
|
||||
ielen = len - min_hdr_len;
|
||||
variable = mgmt->u.probe_resp.variable;
|
||||
if (ext) {
|
||||
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
|
||||
variable = ext->u.s1g_short_beacon.variable;
|
||||
else
|
||||
variable = ext->u.s1g_beacon.variable;
|
||||
}
|
||||
|
||||
channel = cfg80211_get_bss_channel(wiphy, variable, ielen, data->chan);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
if (channel->band == NL80211_BAND_6GHZ &&
|
||||
!cfg80211_uhb_power_type_valid(variable, ielen, channel->flags)) {
|
||||
data->restrict_use = 1;
|
||||
data->use_for = 0;
|
||||
data->cannot_use_reasons =
|
||||
NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH;
|
||||
}
|
||||
|
||||
inform_data.ielen = len - min_hdr_len;
|
||||
inform_data.ie = mgmt->u.probe_resp.variable;
|
||||
if (ext) {
|
||||
const struct ieee80211_s1g_bcn_compat_ie *compat;
|
||||
const struct element *elem;
|
||||
|
||||
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
|
||||
inform_data.ie = ext->u.s1g_short_beacon.variable;
|
||||
else
|
||||
inform_data.ie = ext->u.s1g_beacon.variable;
|
||||
|
||||
elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT,
|
||||
variable, ielen);
|
||||
inform_data.ie, inform_data.ielen);
|
||||
if (!elem)
|
||||
return NULL;
|
||||
if (elem->datalen < sizeof(*compat))
|
||||
return NULL;
|
||||
compat = (void *)elem->data;
|
||||
bssid = ext->u.s1g_beacon.sa;
|
||||
capability = le16_to_cpu(compat->compat_info);
|
||||
beacon_int = le16_to_cpu(compat->beacon_int);
|
||||
memcpy(inform_data.bssid, ext->u.s1g_beacon.sa, ETH_ALEN);
|
||||
inform_data.capability = le16_to_cpu(compat->compat_info);
|
||||
inform_data.beacon_interval = le16_to_cpu(compat->beacon_int);
|
||||
} else {
|
||||
bssid = mgmt->bssid;
|
||||
beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN);
|
||||
inform_data.beacon_interval =
|
||||
le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
inform_data.capability =
|
||||
le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
}
|
||||
|
||||
if (channel->band == NL80211_BAND_60GHZ) {
|
||||
bss_type = capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
|
||||
bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
} else {
|
||||
if (capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
ies = kzalloc(sizeof(*ies) + ielen, gfp);
|
||||
if (!ies)
|
||||
return NULL;
|
||||
ies->len = ielen;
|
||||
ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) ||
|
||||
ieee80211_is_s1g_beacon(mgmt->frame_control);
|
||||
memcpy(ies->data, variable, ielen);
|
||||
inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control))
|
||||
rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
|
||||
inform_data.ftype = CFG80211_BSS_FTYPE_PRESP;
|
||||
else
|
||||
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
|
||||
rcu_assign_pointer(tmp.pub.ies, ies);
|
||||
inform_data.ftype = CFG80211_BSS_FTYPE_BEACON;
|
||||
|
||||
memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
|
||||
tmp.pub.beacon_interval = beacon_int;
|
||||
tmp.pub.capability = capability;
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.signal = data->signal;
|
||||
tmp.ts_boottime = data->boottime_ns;
|
||||
tmp.parent_tsf = data->parent_tsf;
|
||||
tmp.pub.chains = data->chains;
|
||||
memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
|
||||
ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
|
||||
tmp.pub.use_for = data->restrict_use ?
|
||||
data->use_for :
|
||||
NL80211_BSS_USE_FOR_ALL;
|
||||
tmp.pub.cannot_use_reasons = data->cannot_use_reasons;
|
||||
|
||||
signal_valid = data->chan == channel;
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
res = __cfg80211_bss_update(rdev, &tmp, signal_valid, jiffies);
|
||||
if (!res)
|
||||
goto drop;
|
||||
|
||||
rdev_inform_bss(rdev, &res->pub, ies, data->drv_data);
|
||||
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* __cfg80211_bss_update gives us a referenced result */
|
||||
return &res->pub;
|
||||
|
||||
drop:
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_inform_single_bss_data inform_data = {
|
||||
.drv_data = data,
|
||||
.ie = mgmt->u.probe_resp.variable,
|
||||
.ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable),
|
||||
.use_for = data->restrict_use ?
|
||||
data->use_for :
|
||||
NL80211_BSS_USE_FOR_ALL,
|
||||
.cannot_use_reasons = data->cannot_use_reasons,
|
||||
};
|
||||
struct cfg80211_bss *res;
|
||||
|
||||
res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
|
||||
len, gfp);
|
||||
res = cfg80211_inform_single_bss_data(wiphy, &inform_data, gfp);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
/* don't do any further MBSSID/ML handling for S1G */
|
||||
if (ieee80211_is_s1g_beacon(mgmt->frame_control))
|
||||
if (ext)
|
||||
return res;
|
||||
|
||||
inform_data.ftype = ieee80211_is_beacon(mgmt->frame_control) ?
|
||||
CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP;
|
||||
memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN);
|
||||
inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
inform_data.beacon_interval =
|
||||
le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
|
||||
/* process each non-transmitting bss */
|
||||
cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user