mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
wifi: mac80211: protect AP template pointers with a spinlock
The AP's beacon, presp etc. templates are only updated under wiphy mutex right now. Prepare for being able to update them without the wiphy mutex by using a (per-link) spinlock for them. Link: https://patch.msgid.link/20261009201417.f9414c150e5d.Iba8a15c4d37e441642b6df68c33ef8c97340e9a9@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
63892371b2
commit
e70df36f36
|
|
@ -1123,13 +1123,11 @@ ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
const struct ieee80211_color_change_settings *cca,
|
||||
struct ieee80211_link_data *link)
|
||||
{
|
||||
struct probe_resp *new, *old;
|
||||
struct probe_resp *new;
|
||||
|
||||
if (!resp || !resp_len)
|
||||
return 1;
|
||||
|
||||
old = sdata_dereference(link->u.ap.probe_resp, sdata);
|
||||
|
||||
new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
|
@ -1144,9 +1142,7 @@ ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
else if (cca)
|
||||
new->cntdwn_counter_offsets[0] = cca->counter_offset_presp;
|
||||
|
||||
rcu_assign_pointer(link->u.ap.probe_resp, new);
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
ap_tmpl_replace(link, link->u.ap.probe_resp, new);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1157,7 +1153,7 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_bss_conf *link_conf,
|
||||
u64 *changed)
|
||||
{
|
||||
struct fils_discovery_data *new, *old = NULL;
|
||||
struct fils_discovery_data *new = NULL;
|
||||
struct ieee80211_fils_discovery *fd;
|
||||
|
||||
/*
|
||||
|
|
@ -1175,20 +1171,15 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
|
|||
fd->min_interval = params->min_interval;
|
||||
fd->max_interval = params->max_interval;
|
||||
|
||||
old = sdata_dereference(link->u.ap.fils_discovery, sdata);
|
||||
if (params->tmpl && params->tmpl_len) {
|
||||
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
new->len = params->tmpl_len;
|
||||
memcpy(new->data, params->tmpl, params->tmpl_len);
|
||||
rcu_assign_pointer(link->u.ap.fils_discovery, new);
|
||||
} else {
|
||||
RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
|
||||
}
|
||||
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
ap_tmpl_replace(link, link->u.ap.fils_discovery, new);
|
||||
|
||||
*changed |= BSS_CHANGED_FILS_DISCOVERY;
|
||||
return 0;
|
||||
|
|
@ -1201,7 +1192,7 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_bss_conf *link_conf,
|
||||
u64 *changed)
|
||||
{
|
||||
struct unsol_bcast_probe_resp_data *new, *old = NULL;
|
||||
struct unsol_bcast_probe_resp_data *new = NULL;
|
||||
|
||||
/*
|
||||
* This configuration is only applicable to transmitting BSSes.
|
||||
|
|
@ -1216,21 +1207,15 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
link_conf->unsol_bcast_probe_resp_interval = params->interval;
|
||||
|
||||
old = sdata_dereference(link->u.ap.unsol_bcast_probe_resp, sdata);
|
||||
|
||||
if (params->tmpl && params->tmpl_len) {
|
||||
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
new->len = params->tmpl_len;
|
||||
memcpy(new->data, params->tmpl, params->tmpl_len);
|
||||
rcu_assign_pointer(link->u.ap.unsol_bcast_probe_resp, new);
|
||||
} else {
|
||||
RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
|
||||
}
|
||||
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
ap_tmpl_replace(link, link->u.ap.unsol_bcast_probe_resp, new);
|
||||
|
||||
*changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
|
||||
return 0;
|
||||
|
|
@ -1649,12 +1634,9 @@ ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
_changed |= BSS_CHANGED_FTM_RESPONDER;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(link->u.ap.beacon, new);
|
||||
ap_tmpl_replace(link, link->u.ap.beacon, new);
|
||||
sdata->u.ap.active = true;
|
||||
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
|
||||
ieee80211_update_ap_bandwidth(link, params);
|
||||
|
||||
*changed |= _changed;
|
||||
|
|
@ -1956,11 +1938,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
err = drv_start_ap(sdata->local, sdata, link_conf);
|
||||
if (err) {
|
||||
old = sdata_dereference(link->u.ap.beacon, sdata);
|
||||
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
RCU_INIT_POINTER(link->u.ap.beacon, NULL);
|
||||
ap_tmpl_replace(link, link->u.ap.beacon, NULL);
|
||||
|
||||
if (ieee80211_num_beaconing_links(sdata) == 0)
|
||||
sdata->u.ap.active = false;
|
||||
|
|
@ -2088,16 +2066,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
old_beacon = sdata_dereference(link->u.ap.beacon, sdata);
|
||||
if (!old_beacon)
|
||||
if (!sdata_dereference(link->u.ap.beacon, sdata))
|
||||
return -ENOENT;
|
||||
old_probe_resp = sdata_dereference(link->u.ap.probe_resp,
|
||||
sdata);
|
||||
old_fils_discovery = sdata_dereference(link->u.ap.fils_discovery,
|
||||
sdata);
|
||||
old_unsol_bcast_probe_resp =
|
||||
sdata_dereference(link->u.ap.unsol_bcast_probe_resp,
|
||||
sdata);
|
||||
old_s1g_short_beacon =
|
||||
sdata_dereference(link->u.ap.s1g_short_beacon, sdata);
|
||||
|
||||
|
|
@ -2118,10 +2088,20 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
/* remove beacon and probe response */
|
||||
RCU_INIT_POINTER(link->u.ap.beacon, NULL);
|
||||
RCU_INIT_POINTER(link->u.ap.probe_resp, NULL);
|
||||
RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
|
||||
RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
|
||||
scoped_guard(spinlock, &link->ap_tmpl_lock) {
|
||||
old_beacon = ap_tmpl_dereference(link, link->u.ap.beacon);
|
||||
old_probe_resp = ap_tmpl_dereference(link,
|
||||
link->u.ap.probe_resp);
|
||||
old_fils_discovery =
|
||||
ap_tmpl_dereference(link, link->u.ap.fils_discovery);
|
||||
old_unsol_bcast_probe_resp =
|
||||
ap_tmpl_dereference(link,
|
||||
link->u.ap.unsol_bcast_probe_resp);
|
||||
RCU_INIT_POINTER(link->u.ap.beacon, NULL);
|
||||
RCU_INIT_POINTER(link->u.ap.probe_resp, NULL);
|
||||
RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
|
||||
RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
|
||||
}
|
||||
RCU_INIT_POINTER(link->u.ap.s1g_short_beacon, NULL);
|
||||
kfree_rcu(old_beacon, rcu_head);
|
||||
if (old_probe_resp)
|
||||
|
|
|
|||
|
|
@ -1152,6 +1152,9 @@ struct ieee80211_link_data {
|
|||
struct ieee80211_link_data_ap ap;
|
||||
} u;
|
||||
|
||||
/* protects replacing the u.ap template pointers, also without wiphy mutex */
|
||||
spinlock_t ap_tmpl_lock;
|
||||
|
||||
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
|
||||
|
||||
struct ieee80211_bss_conf *conf;
|
||||
|
|
@ -1166,6 +1169,21 @@ struct ieee80211_link_data {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define ap_tmpl_dereference(link, p) \
|
||||
rcu_dereference_protected(p, lockdep_is_held(&(link)->ap_tmpl_lock))
|
||||
|
||||
#define ap_tmpl_replace(link, p, new) \
|
||||
do { \
|
||||
typeof(ap_tmpl_dereference(link, p)) __old; \
|
||||
\
|
||||
spin_lock(&(link)->ap_tmpl_lock); \
|
||||
__old = rcu_replace_pointer(p, new, \
|
||||
lockdep_is_held(&(link)->ap_tmpl_lock));\
|
||||
spin_unlock(&(link)->ap_tmpl_lock); \
|
||||
if (__old) \
|
||||
kfree_rcu(__old, rcu_head); \
|
||||
} while (0)
|
||||
|
||||
struct ieee80211_sub_if_data {
|
||||
struct list_head list;
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
|
|||
link->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||
link->user_power_level = sdata->local->user_power_level;
|
||||
link_conf->txpower = INT_MIN;
|
||||
spin_lock_init(&link->ap_tmpl_lock);
|
||||
|
||||
wiphy_work_init(&link->csa.finalize_work,
|
||||
ieee80211_csa_finalize_work);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user