summaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
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 /net/mac80211/ht.c
parent3d1cc7cdf2e848181398837fe158bf0850d29ee6 (diff)
downloadlinux-d8675a63518c6148827838058feb7f18403faed1.tar.bz2
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>
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 2eb3a409b70f..ea7ce87b7ec4 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -140,12 +140,14 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_ht_cap *ht_cap_ie,
struct link_sta_info *link_sta)
{
+ struct ieee80211_bss_conf *link_conf;
struct sta_info *sta = link_sta->sta;
struct ieee80211_sta_ht_cap ht_cap, own_cap;
u8 ampdu_info, tx_mcs_set_cap;
int i, max_tx_streams;
bool changed;
enum ieee80211_sta_rx_bandwidth bw;
+ enum nl80211_chan_width width;
memset(&ht_cap, 0, sizeof(ht_cap));
@@ -248,7 +250,14 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap));
- switch (sdata->vif.link_conf[link_sta->link_id]->chandef.width) {
+ rcu_read_lock();
+ link_conf = rcu_dereference(sdata->vif.link_conf[link_sta->link_id]);
+ if (WARN_ON(!link_conf))
+ width = NL80211_CHAN_WIDTH_20_NOHT;
+ else
+ width = link_conf->chandef.width;
+
+ switch (width) {
default:
WARN_ON_ONCE(1);
fallthrough;
@@ -264,6 +273,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
break;
}
+ rcu_read_unlock();
link_sta->pub->bandwidth = bw;
@@ -547,7 +557,7 @@ void ieee80211_request_smps_mgd_work(struct work_struct *work)
u.mgd.request_smps_work);
sdata_lock(link->sdata);
- __ieee80211_request_smps_mgd(link->sdata, link->link_id,
+ __ieee80211_request_smps_mgd(link->sdata, link,
link->u.mgd.driver_smps_mode);
sdata_unlock(link->sdata);
}
@@ -556,19 +566,23 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id,
enum ieee80211_smps_mode smps_mode)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- struct ieee80211_link_data *link = sdata->link[link_id];
+ struct ieee80211_link_data *link;
if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION))
return;
+ rcu_read_lock();
+ link = rcu_dereference(sdata->link[link_id]);
if (WARN_ON(!link))
- return;
+ goto out;
if (link->u.mgd.driver_smps_mode == smps_mode)
- return;
+ goto out;
link->u.mgd.driver_smps_mode = smps_mode;
ieee80211_queue_work(&sdata->local->hw, &link->u.mgd.request_smps_work);
+out:
+ rcu_read_unlock();
}
/* this might change ... don't want non-open drivers using it */
EXPORT_SYMBOL_GPL(ieee80211_request_smps);