summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2022-06-17 22:36:37 +0200
committerJohannes Berg <johannes.berg@intel.com>2022-07-15 11:43:14 +0200
commitd8675a63518c6148827838058feb7f18403faed1 (patch)
treefbdee52aa9f31da2b33ad5804cc4ea76a9a82a24
parent3d1cc7cdf2e848181398837fe158bf0850d29ee6 (diff)
downloadlinux-d8675a63518c6148827838058feb7f18403faed1.tar.gz
linux-d8675a63518c6148827838058feb7f18403faed1.tar.bz2
linux-d8675a63518c6148827838058feb7f18403faed1.zip
wifi: mac80211: RCU-ify link/link_conf pointers
Since links can be added and removed dynamically, we need to somehow protect the sdata->link[] and vif->link_conf[] array pointers from disappearing when accessing them without locks. RCU-ify the pointers to achieve this, which requires quite a bit of rework. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c14
-rw-r--r--include/net/mac80211.h6
-rw-r--r--net/mac80211/cfg.c169
-rw-r--r--net/mac80211/chan.c123
-rw-r--r--net/mac80211/debugfs_netdev.c2
-rw-r--r--net/mac80211/driver-ops.h10
-rw-r--r--net/mac80211/ht.c24
-rw-r--r--net/mac80211/ibss.c8
-rw-r--r--net/mac80211/ieee80211_i.h21
-rw-r--r--net/mac80211/iface.c36
-rw-r--r--net/mac80211/main.c9
-rw-r--r--net/mac80211/mesh.c7
-rw-r--r--net/mac80211/mlme.c30
-rw-r--r--net/mac80211/ocb.c4
-rw-r--r--net/mac80211/offchannel.c15
-rw-r--r--net/mac80211/rx.c8
-rw-r--r--net/mac80211/sta_info.c3
-rw-r--r--net/mac80211/tdls.c3
-rw-r--r--net/mac80211/trace.h19
-rw-r--r--net/mac80211/tx.c88
-rw-r--r--net/mac80211/util.c34
-rw-r--r--net/mac80211/vht.c62
22 files changed, 420 insertions, 275 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 4f22f3df161c..6bad95eeb709 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1477,9 +1477,10 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
int i;
for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
- struct ieee80211_bss_conf *conf = vif->link_conf[i];
+ struct ieee80211_bss_conf *conf;
struct ieee80211_chanctx_conf *chanctx;
+ conf = rcu_dereference(vif->link_conf[i]);
if (!conf)
continue;
@@ -1917,7 +1918,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
{
struct mac80211_hwsim_link_data *link_data = arg;
u32 link_id = link_data->link_id;
- struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf;
struct mac80211_hwsim_data *data =
container_of(link_data, struct mac80211_hwsim_data,
link_data[link_id]);
@@ -1931,6 +1932,10 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
hwsim_check_magic(vif);
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ if (!link_conf)
+ return;
+
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_MESH_POINT &&
vif->type != NL80211_IFTYPE_ADHOC &&
@@ -2155,12 +2160,11 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw,
static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u32 link_id,
- u64 changed)
+ struct ieee80211_bss_conf *info,
+ u32 link_id, u64 changed)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
struct mac80211_hwsim_data *data = hw->priv;
- struct ieee80211_bss_conf *info = vif->link_conf[link_id];
struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id];
hwsim_check_magic(vif);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1c005a30313f..044ed417b06f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1789,7 +1789,7 @@ struct ieee80211_vif {
enum nl80211_iftype type;
struct ieee80211_vif_cfg cfg;
struct ieee80211_bss_conf bss_conf;
- struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
u16 valid_links;
u8 addr[ETH_ALEN] __aligned(2);
bool p2p;
@@ -4082,7 +4082,9 @@ struct ieee80211_ops {
u64 changed);
void (*link_info_changed)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- unsigned int link_id, u64 changed);
+ struct ieee80211_bss_conf *info,
+ unsigned int link_id,
+ u64 changed);
int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
unsigned int link_id);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 85032dcaa595..3d66e40af7a9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -39,7 +39,7 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
memcpy(sdata->vif.bss_conf.mu_group.position,
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
WLAN_USER_POSITION_LEN);
- ieee80211_link_info_change_notify(sdata, 0,
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
BSS_CHANGED_MU_GROUPS);
/* don't care about endianness - just check for 0 */
memcpy(&membership, params->vht_mumimo_groups,
@@ -841,8 +841,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
sdata = wiphy_dereference(local->hw.wiphy,
local->monitor_sdata);
if (sdata) {
- ieee80211_link_release_channel(sdata->link[0]);
- ret = ieee80211_link_use_channel(sdata->link[0],
+ ieee80211_link_release_channel(&sdata->deflink);
+ ret = ieee80211_link_use_channel(&sdata->deflink,
chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
}
@@ -1008,6 +1008,7 @@ ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst,
}
static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link,
struct cfg80211_beacon_data *params,
const struct ieee80211_csa_settings *csa,
const struct ieee80211_color_change_settings *cca)
@@ -1017,9 +1018,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
int new_head_len, new_tail_len;
int size, err;
u32 changed = BSS_CHANGED_BEACON;
- struct ieee80211_link_data *link = sdata->link[params->link_id];
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[params->link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
old = sdata_dereference(link->u.ap.beacon, sdata);
@@ -1153,8 +1152,14 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
int i, err;
int prev_beacon_int;
unsigned int link_id = params->beacon.link_id;
- struct ieee80211_link_data *link = sdata->link[link_id];
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link;
+ struct ieee80211_bss_conf *link_conf;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ link_conf = link->conf;
old = sdata_dereference(link->u.ap.beacon, sdata);
if (old)
@@ -1264,7 +1269,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL))
link_conf->beacon_tx_rate = params->beacon_rate;
- err = ieee80211_assign_beacon(sdata, &params->beacon, NULL, NULL);
+ err = ieee80211_assign_beacon(sdata, link, &params->beacon, NULL, NULL);
if (err < 0)
goto error;
changed |= err;
@@ -1300,7 +1305,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
ieee80211_recalc_dtim(local, sdata);
ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID);
- ieee80211_link_info_change_notify(sdata, link_id, changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);
netif_carrier_on(dev);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
@@ -1320,25 +1325,30 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_beacon_data *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_link_data *link;
struct beacon_data *old;
int err;
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[params->link_id];
+ struct ieee80211_bss_conf *link_conf;
sdata_assert_lock(sdata);
+ link = sdata_dereference(sdata->link[params->link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ link_conf = link->conf;
+
/* don't allow changing the beacon while a countdown is in place - offset
* of channel switch counter may change
*/
if (link_conf->csa_active || link_conf->color_change_active)
return -EBUSY;
- old = sdata_dereference(sdata->link[params->link_id]->u.ap.beacon,
- sdata);
+ old = sdata_dereference(link->u.ap.beacon, sdata);
if (!old)
return -ENOENT;
- err = ieee80211_assign_beacon(sdata, params, NULL, NULL);
+ err = ieee80211_assign_beacon(sdata, link, params, NULL, NULL);
if (err < 0)
return err;
@@ -1348,7 +1358,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
err |= BSS_CHANGED_HE_BSS_COLOR;
}
- ieee80211_link_info_change_notify(sdata, params->link_id, err);
+ ieee80211_link_info_change_notify(sdata, link, err);
return 0;
}
@@ -1373,8 +1383,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
struct fils_discovery_data *old_fils_discovery;
struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp;
struct cfg80211_chan_def chandef;
- struct ieee80211_link_data *link = sdata->link[link_id];
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link =
+ sdata_dereference(sdata->link[link_id], sdata);
+ struct ieee80211_bss_conf *link_conf = link->conf;
sdata_assert_lock(sdata);
@@ -1431,7 +1442,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->beacon_rate_set = false;
sdata->vif.cfg.ssid_len = 0;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
- ieee80211_link_info_change_notify(sdata, link_id,
+ ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_BEACON_ENABLED);
if (sdata->wdev.cac_started) {
@@ -1589,14 +1600,16 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 link_id = params->link_id < 0 ? 0 : params->link_id;
+ struct ieee80211_link_data *link =
+ sdata_dereference(sdata->link[link_id], sdata);
struct link_sta_info *link_sta =
rcu_dereference_protected(sta->link[link_id],
lockdep_is_held(&local->sta_mtx));
- if (!link_sta)
+ if (!link || !link_sta)
return -EINVAL;
- sband = ieee80211_get_link_sband(sdata, link_id);
+ sband = ieee80211_get_link_sband(link);
if (!sband)
return -EINVAL;
@@ -1616,7 +1629,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
if (params->supported_rates &&
params->supported_rates_len) {
- ieee80211_parse_bitrates(&sdata->vif.link_conf[link_id]->chandef,
+ ieee80211_parse_bitrates(&link->conf->chandef,
sband, params->supported_rates,
params->supported_rates_len,
&link_sta->pub->supp_rates[sband->band]);
@@ -1667,9 +1680,14 @@ static int sta_apply_parameters(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 link_id = params->link_sta_params.link_id < 0 ?
0 : params->link_sta_params.link_id;
+ struct ieee80211_link_data *link;
u32 mask, set;
- sband = ieee80211_get_link_sband(sdata, link_id);
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ sband = ieee80211_get_link_sband(link);
if (!sband)
return -EINVAL;
@@ -1987,7 +2005,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
}
- err = sta_apply_parameters(local, sta, params);
+ /* we use sta_info_get_bss() so this might be different */
+ if (sdata != sta->sdata) {
+ mutex_lock_nested(&sta->sdata->wdev.mtx, 1);
+ err = sta_apply_parameters(local, sta, params);
+ mutex_unlock(&sta->sdata->wdev.mtx);
+ } else {
+ err = sta_apply_parameters(local, sta, params);
+ }
if (err)
goto out_err;
@@ -2374,7 +2399,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) {
conf->ht_opmode = nconf->ht_opmode;
sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_HT);
}
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask))
conf->dot11MeshHWMPactivePathToRootTimeout =
@@ -2426,7 +2452,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
sdata->deflink.needed_rx_chains = sdata->local->rx_chains;
mutex_lock(&sdata->local->mtx);
- err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef,
+ err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef,
IEEE80211_CHANCTX_SHARED);
mutex_unlock(&sdata->local->mtx);
if (err)
@@ -2441,7 +2467,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
ieee80211_stop_mesh(sdata);
mutex_lock(&sdata->local->mtx);
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
kfree(sdata->u.mesh.ie);
mutex_unlock(&sdata->local->mtx);
@@ -2529,7 +2555,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
changed |= BSS_CHANGED_P2P_PS;
}
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);
return 0;
}
@@ -2570,7 +2596,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
return -EINVAL;
}
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_QOS);
return 0;
}
@@ -2719,7 +2746,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
memcpy(sdata->vif.bss_conf.mcast_rate, rate,
sizeof(int) * NUM_NL80211_BANDS);
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MCAST_RATE);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_MCAST_RATE);
return 0;
}
@@ -2934,7 +2962,7 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
#endif
int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id,
+ struct ieee80211_link_data *link,
enum ieee80211_smps_mode smps_mode)
{
const u8 *ap;
@@ -2948,8 +2976,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
return -EINVAL;
- old_req = sdata->link[link_id]->u.mgd.req_smps;
- sdata->link[link_id]->u.mgd.req_smps = smps_mode;
+ old_req = link->u.mgd.req_smps;
+ link->u.mgd.req_smps = smps_mode;
if (old_req == smps_mode &&
smps_mode != IEEE80211_SMPS_AUTOMATIC)
@@ -2961,10 +2989,10 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
* the new value until we associate.
*/
if (!sdata->u.mgd.associated ||
- sdata->vif.link_conf[link_id]->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
+ link->conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return 0;
- ap = sdata->link[link_id]->u.mgd.bssid;
+ ap = link->u.mgd.bssid;
rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
@@ -2988,7 +3016,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
err = ieee80211_send_smps_action(sdata, smps_mode,
ap, ap);
if (err)
- sdata->link[link_id]->u.mgd.req_smps = old_req;
+ link->u.mgd.req_smps = old_req;
else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found)
ieee80211_teardown_tdls_peers(sdata);
@@ -3018,10 +3046,14 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
/* no change, but if automatic follow powersave */
sdata_lock(sdata);
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- if (!sdata->link[link_id])
+ struct ieee80211_link_data *link;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+
+ if (!link)
continue;
- __ieee80211_request_smps_mgd(sdata, link_id,
- sdata->link[link_id]->u.mgd.req_smps);
+ __ieee80211_request_smps_mgd(sdata, link,
+ link->u.mgd.req_smps);
}
sdata_unlock(sdata);
@@ -3060,7 +3092,8 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
/* tell the driver upon association, unless already associated */
if (sdata->u.mgd.associated &&
sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_CQM);
return 0;
}
@@ -3085,7 +3118,8 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
/* tell the driver upon association, unless already associated */
if (sdata->u.mgd.associated &&
sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
- ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ BSS_CHANGED_CQM);
return 0;
}
@@ -3177,7 +3211,7 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
sdata->deflink.needed_rx_chains = local->rx_chains;
- err = ieee80211_link_use_channel(sdata->link[0], chandef,
+ err = ieee80211_link_use_channel(&sdata->deflink, chandef,
IEEE80211_CHANCTX_SHARED);
if (err)
goto out_unlock;
@@ -3206,7 +3240,7 @@ static void ieee80211_end_cac(struct wiphy *wiphy,
cancel_delayed_work(&sdata->deflink.dfs_cac_timer_work);
if (sdata->wdev.cac_started) {
- ieee80211_link_release_channel(sdata->link[0]);
+ ieee80211_link_release_channel(&sdata->deflink);
sdata->wdev.cac_started = false;
}
}
@@ -3353,7 +3387,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
if (!sdata->deflink.u.ap.next_beacon)
return -EINVAL;
- err = ieee80211_assign_beacon(sdata,
+ err = ieee80211_assign_beacon(sdata, &sdata->deflink,
sdata->deflink.u.ap.next_beacon,
NULL, NULL);
ieee80211_free_next_beacon(&sdata->deflink);
@@ -3410,7 +3444,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
if (sdata->deflink.reserved_ready)
return 0;
- return ieee80211_link_use_reserved_context(sdata->link[0]);
+ return ieee80211_link_use_reserved_context(&sdata->deflink);
}
if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
@@ -3423,7 +3457,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
if (err)
return err;
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);
if (sdata->deflink.csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
@@ -3522,7 +3556,9 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
csa.count = params->count;
- err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa, NULL);
+ err = ieee80211_assign_beacon(sdata, &sdata->deflink,
+ &params->beacon_csa, &csa,
+ NULL);
if (err < 0) {
ieee80211_free_next_beacon(&sdata->deflink);
return err;
@@ -3675,7 +3711,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if (err)
goto out;
- err = ieee80211_link_reserve_chanctx(sdata->link[0], &params->chandef,
+ err = ieee80211_link_reserve_chanctx(&sdata->deflink, &params->chandef,
chanctx->mode,
params->radar_required);
if (err)
@@ -3684,7 +3720,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
/* if reservation is invalid then this will fail */
err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
if (err) {
- ieee80211_link_unreserve_chanctx(sdata->link[0]);
+ ieee80211_link_unreserve_chanctx(&sdata->deflink);
goto out;
}
@@ -3694,7 +3730,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
err = ieee80211_set_csa_beacon(sdata, params, &changed);
if (err) {
- ieee80211_link_unreserve_chanctx(sdata->link[0]);
+ ieee80211_link_unreserve_chanctx(&sdata->deflink);
goto out;
}
@@ -3711,7 +3747,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
params->count, params->block_tx);
if (changed) {
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ changed);
drv_channel_switch_beacon(sdata, &params->chandef);
} else {
/* if the beacon didn't change, we can finalize immediately */
@@ -3950,12 +3987,19 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_link_data *link;
int ret = -ENODATA;
rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf);
+ link = rcu_dereference(sdata->link[link_id]);
+ if (!link) {
+ ret = -ENOLINK;
+ goto out;
+ }
+
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (chanctx_conf) {
- *chandef = sdata->vif.link_conf[link_id]->chandef;
+ *chandef = link->conf->chandef;
ret = 0;
} else if (local->open_count > 0 &&
local->open_count == local->monitors &&
@@ -3966,6 +4010,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
*chandef = local->_oper_chandef;
ret = 0;
}
+out:
rcu_read_unlock();
return ret;
@@ -4009,13 +4054,15 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_link_data *link;
int ret;
u32 changed = 0;
- ret = ieee80211_link_change_bandwidth(sdata->link[link_id], chandef,
- &changed);
+ link = sdata_dereference(sdata->link[link_id], sdata);
+
+ ret = ieee80211_link_change_bandwidth(link, chandef, &changed);
if (ret == 0)
- ieee80211_link_info_change_notify(sdata, link_id, changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);
return ret;
}
@@ -4358,7 +4405,7 @@ ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata,
if (!sdata->deflink.u.ap.next_beacon)
return -EINVAL;
- ret = ieee80211_assign_beacon(sdata,
+ ret = ieee80211_assign_beacon(sdata, &sdata->deflink,
sdata->deflink.u.ap.next_beacon,
NULL, NULL);
ieee80211_free_next_beacon(&sdata->deflink);
@@ -4401,7 +4448,8 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata,
params->counter_offset_presp;
color_change.count = params->count;
- err = ieee80211_assign_beacon(sdata, &params->beacon_color_change,
+ err = ieee80211_assign_beacon(sdata, &sdata->deflink,
+ &params->beacon_color_change,
NULL, &color_change);
if (err < 0) {
ieee80211_free_next_beacon(&sdata->deflink);
@@ -4424,7 +4472,7 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.he_bss_color.enabled = enable;
changed |= BSS_CHANGED_HE_BSS_COLOR;
- ieee80211_link_info_change_notify(sdata, 0, changed);
+ ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed);
if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) {
struct ieee80211_sub_if_data *child;
@@ -4434,7 +4482,8 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) {
child->vif.bss_conf.he_bss_color.color = color;
child->vif.bss_conf.he_bss_color.enabled = enable;
- ieee80211_link_info_change_notify(child, 0,
+ ieee80211_link_info_change_notify(child,
+ &child->deflink,
BSS_CHANGED_HE_BSS_COLOR);
}
}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 6853b563fb6c..8d384956fde5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -67,14 +67,12 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
}
static struct ieee80211_chanctx *
-ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata,
- unsigned int link_id)
+ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
{
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
- struct ieee80211_local *local __maybe_unused = sdata->local;
+ struct ieee80211_local *local __maybe_unused = link->sdata->local;
struct ieee80211_chanctx_conf *conf;
- conf = rcu_dereference_protected(link_conf->chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf)
return NULL;
@@ -82,12 +80,6 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata,
return container_of(conf, struct ieee80211_chanctx, conf);
}
-static struct ieee80211_chanctx *
-ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
-{
- return ieee80211_vif_get_chanctx(link->sdata, link->link_id);
-}
-
static const struct cfg80211_chan_def *
ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
@@ -122,8 +114,7 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
list_for_each_entry(link, &ctx->assigned_links,
assigned_chanctx_list) {
- struct ieee80211_bss_conf *link_conf =
- link->sdata->vif.link_conf[link->link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
if (link->reserved_chanctx)
continue;
@@ -254,7 +245,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
struct sta_info *sta;
- rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
if (sdata != sta->sdata &&
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
@@ -262,7 +252,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id));
}
- rcu_read_unlock();
return max_bw;
}
@@ -275,10 +264,11 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
struct ieee80211_vif *vif = &sdata->vif;
int link_id;
+ rcu_read_lock();
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ rcu_dereference(sdata->vif.link_conf[link_id]);
if (!link_conf)
continue;
@@ -319,6 +309,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
max_bw = max(max_bw, width);
}
+ rcu_read_unlock();
return max_bw;
}
@@ -345,7 +336,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
/* use the configured bandwidth in case of monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
if (sdata &&
- rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == conf)
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf)
max_bw = max(max_bw, conf->def.width);
rcu_read_unlock();
@@ -419,7 +410,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ rcu_dereference(sdata->vif.link_conf[link_id]);
struct link_sta_info *link_sta;
if (!link_conf)
@@ -572,8 +563,11 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
unsigned int link_id;
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- if (sdata->link[link_id] &&
- sdata->link[link_id]->radar_required) {
+ struct ieee80211_link_data *link;
+
+ link = rcu_dereference(sdata->link[link_id]);
+
+ if (link && link->radar_required) {
rcu_read_unlock();
return true;
}
@@ -602,15 +596,15 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local,
if (!ieee80211_sdata_running(sdata))
continue;
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link;
- if (!link_conf)
+ link = rcu_dereference(sdata->link[link_id]);
+ if (!link)
continue;
- if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
+ if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
continue;
- if (!sdata->link[link_id]->radar_required)
+ if (!link->radar_required)
continue;
required = true;
break;
@@ -774,7 +768,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ rcu_dereference(sdata->vif.link_conf[link_id]);
if (!link_conf)
continue;
@@ -850,7 +844,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
return -ENOTSUPP;
- conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (conf) {
@@ -872,7 +866,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
}
out:
- rcu_assign_pointer(sdata->vif.link_conf[link_id]->chanctx_conf, conf);
+ rcu_assign_pointer(link->conf->chanctx_conf, conf);
sdata->vif.cfg.idle = !conf;
@@ -931,14 +925,14 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
}
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
- struct ieee80211_link_data *link = sdata->link[link_id];
- struct ieee80211_bss_conf *link_conf =
- sdata->vif.link_conf[link_id];
+ struct ieee80211_link_data *link;
- if (!link_conf)
+ link = rcu_dereference(sdata->link[link_id]);
+
+ if (!link)
continue;
- if (rcu_access_pointer(link_conf->chanctx_conf) != &chanctx->conf)
+ if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
continue;
switch (link->smps_mode) {
@@ -968,7 +962,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
/* Disable SMPS for the monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
if (sdata &&
- rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == &chanctx->conf)
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
rx_chains_dynamic = rx_chains_static = local->rx_chains;
rcu_read_unlock();
@@ -998,7 +992,7 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
{
struct ieee80211_sub_if_data *sdata = link->sdata;
unsigned int link_id = link->link_id;
- struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local __maybe_unused = sdata->local;
struct ieee80211_sub_if_data *vlan;