wifi: cfg80211: keep bss_lock held when informing

It is reasonable to hold bss_lock for a little bit longer after
cfg80211_bss_update is done. Right now, this does not make any big
difference, but doing so in preparation for the next patch which adds
a call to the driver.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230616094948.61701884ff0d.I3358228209eb6766202aff04d1bae0b8fdff611f@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Benjamin Berg 2023-06-16 09:53:59 +03:00 committed by Johannes Berg
parent c2edd30132
commit 6b7c93c143

View file

@ -1701,10 +1701,10 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
}
/* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *tmp,
bool signal_valid, unsigned long ts)
static struct cfg80211_internal_bss *
__cfg80211_bss_update(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *tmp,
bool signal_valid, unsigned long ts)
{
struct cfg80211_internal_bss *found = NULL;
@ -1713,10 +1713,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
tmp->ts = ts;
spin_lock_bh(&rdev->bss_lock);
if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) {
spin_unlock_bh(&rdev->bss_lock);
return NULL;
}
@ -1724,7 +1721,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
if (found) {
if (!cfg80211_update_known_bss(rdev, found, tmp, signal_valid))
goto drop;
return NULL;
} else {
struct cfg80211_internal_bss *new;
struct cfg80211_internal_bss *hidden;
@ -1744,7 +1741,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
ies = (void *)rcu_dereference(tmp->pub.proberesp_ies);
if (ies)
kfree_rcu(ies, rcu_head);
goto drop;
return NULL;
}
memcpy(new, tmp, sizeof(*new));
new->refcount = 1;
@ -1775,14 +1772,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
*/
if (!cfg80211_combine_bsses(rdev, new)) {
bss_ref_put(rdev, new);
goto drop;
return NULL;
}
}
if (rdev->bss_entries >= bss_entries_limit &&
!cfg80211_bss_expire_oldest(rdev)) {
bss_ref_put(rdev, new);
goto drop;
return NULL;
}
/* This must be before the call to bss_ref_get */
@ -1799,12 +1796,22 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
rdev->bss_generation++;
bss_ref_get(rdev, found);
spin_unlock_bh(&rdev->bss_lock);
return found;
drop:
}
struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *tmp,
bool signal_valid, unsigned long ts)
{
struct cfg80211_internal_bss *res;
spin_lock_bh(&rdev->bss_lock);
res = __cfg80211_bss_update(rdev, tmp, signal_valid, ts);
spin_unlock_bh(&rdev->bss_lock);
return NULL;
return res;
}
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
@ -2015,15 +2022,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
rcu_assign_pointer(tmp.pub.ies, ies);
signal_valid = data->chan == channel;
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts);
spin_lock_bh(&rdev->bss_lock);
res = __cfg80211_bss_update(rdev, &tmp, signal_valid, ts);
if (!res)
return NULL;
goto drop;
if (non_tx_data) {
/* this is a nontransmitting bss, we need to add it to
* transmitting bss' list if it is not there
*/
spin_lock_bh(&rdev->bss_lock);
if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
&res->pub)) {
if (__cfg80211_unlink_bss(rdev, res)) {
@ -2031,15 +2038,19 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
res = NULL;
}
}
spin_unlock_bh(&rdev->bss_lock);
if (!res)
return NULL;
goto drop;
}
spin_unlock_bh(&rdev->bss_lock);
trace_cfg80211_return_bss(&res->pub);
/* cfg80211_bss_update gives us a referenced result */
/* __cfg80211_bss_update gives us a referenced result */
return &res->pub;
drop:
spin_unlock_bh(&rdev->bss_lock);
return NULL;
}
static const struct element
@ -2376,6 +2387,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
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;
@ -2485,14 +2497,20 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
signal_valid = data->chan == channel;
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid,
jiffies);
spin_lock_bh(&rdev->bss_lock);
res = __cfg80211_bss_update(rdev, &tmp, signal_valid, jiffies);
if (!res)
return NULL;
goto drop;
spin_unlock_bh(&rdev->bss_lock);
trace_cfg80211_return_bss(&res->pub);
/* cfg80211_bss_update gives us a referenced result */
/* __cfg80211_bss_update gives us a referenced result */
return &res->pub;
drop:
spin_unlock_bh(&rdev->bss_lock);
return NULL;
}
struct cfg80211_bss *