Commit c71420db authored by Johannes Berg's avatar Johannes Berg
Browse files

wifi: mac80211: RCU-ify link STA pointers



We need to be able to access these in a race-free way under
traffic while adding/removing them, so RCU-ify the pointers.
This requires passing a link_sta to a lot of functions so
we don't have to do the RCU handling everywhere.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ce6893e9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2201,7 +2201,7 @@ struct ieee80211_sta {

	u16 valid_links;
	struct ieee80211_link_sta deflink;
	struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS];
	struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];

	/* must be last */
	u8 drv_priv[] __aligned(sizeof(void *));
+7 −5
Original line number Diff line number Diff line
@@ -1771,19 +1771,21 @@ static int sta_apply_parameters(struct ieee80211_local *local,

	if (params->ht_capa)
		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
						  params->ht_capa, sta, 0);
						  params->ht_capa,
						  &sta->deflink);

	/* VHT can override some HT caps such as the A-MSDU max length */
	if (params->vht_capa)
		ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
						    params->vht_capa, sta, 0);
						    params->vht_capa,
						    &sta->deflink);

	if (params->he_capa)
		ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
						  (void *)params->he_capa,
						  params->he_capa_len,
						  (void *)params->he_6ghz_capa,
						  sta, 0);
						  &sta->deflink);

	if (params->eht_capa)
		ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
@@ -1791,13 +1793,13 @@ static int sta_apply_parameters(struct ieee80211_local *local,
						    params->he_capa_len,
						    params->eht_capa,
						    params->eht_capa_len,
						    sta, 0);
						    &sta->deflink);

	if (params->opmode_notif_used) {
		/* returned value is only needed for rc update, but the
		 * rc isn't initialized here yet, so ignore it
		 */
		__ieee80211_vht_handle_opmode(sdata, sta, 0,
		__ieee80211_vht_handle_opmode(sdata, &sta->deflink,
					      params->opmode_notif,
					      sband->band);
	}
+17 −8
Original line number Diff line number Diff line
@@ -207,16 +207,20 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
						    unsigned int link_id)
{
	enum ieee80211_sta_rx_bandwidth width =
		ieee80211_sta_cap_rx_bw(sta, link_id);
	enum ieee80211_sta_rx_bandwidth width;
	struct link_sta_info *link_sta;

	link_sta = rcu_dereference(sta->link[link_id]);

	/* no effect if this STA has no presence on this link */
	if (!sta->sta.link[link_id])
	if (!link_sta)
		return NL80211_CHAN_WIDTH_20_NOHT;

	width = ieee80211_sta_cap_rx_bw(link_sta);

	switch (width) {
	case IEEE80211_STA_RX_BW_20:
		if (sta->sta.link[link_id]->ht_cap.ht_supported)
		if (link_sta->pub->ht_cap.ht_supported)
			return NL80211_CHAN_WIDTH_20;
		else
			return NL80211_CHAN_WIDTH_20_NOHT;
@@ -416,6 +420,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];
			struct link_sta_info *link_sta;

			if (!link_conf)
				continue;
@@ -423,18 +428,22 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
			if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
				continue;

			new_sta_bw = ieee80211_sta_cur_vht_bw(sta, link_id);
			link_sta = rcu_dereference(sta->link[link_id]);
			if (!link_sta)
				continue;

			new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta);

			/* nothing change */
			if (new_sta_bw == sta->sta.link[link_id]->bandwidth)
			if (new_sta_bw == link_sta->pub->bandwidth)
				continue;

			/* vif changed to narrow BW and narrow BW for station wasn't
			 * requested or vise versa */
			if ((new_sta_bw < sta->sta.link[link_id]->bandwidth) == !narrowed)
			if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
				continue;

			sta->sta.link[link_id]->bandwidth = new_sta_bw;
			link_sta->pub->bandwidth = new_sta_bw;
			rate_control_rate_update(local, sband, sta, link_id,
						 IEEE80211_RC_BW_CHANGED);
		}
+5 −8
Original line number Diff line number Diff line
@@ -12,11 +12,10 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
				    struct ieee80211_supported_band *sband,
				    const u8 *he_cap_ie, u8 he_cap_len,
				    const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
				    u8 eht_cap_len, struct sta_info *sta,
				    unsigned int link_id)
				    u8 eht_cap_len,
				    struct link_sta_info *link_sta)
{
	struct ieee80211_sta_eht_cap *eht_cap =
		&sta->sta.link[link_id]->eht_cap;
	struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap;
	struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
	u8 eht_ppe_size = 0;
	u8 mcs_nss_size;
@@ -73,8 +72,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,

	eht_cap->has_eht = true;

	sta->link[link_id]->cur_max_bandwidth =
		ieee80211_sta_cap_rx_bw(sta, link_id);
	sta->sta.link[link_id]->bandwidth =
		ieee80211_sta_cur_vht_bw(sta, link_id);
	link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
	link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
}
+8 −9
Original line number Diff line number Diff line
@@ -10,8 +10,9 @@

static void
ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
				   struct sta_info *sta, unsigned int link_id)
				   struct link_sta_info *link_sta)
{
	struct sta_info *sta = link_sta->sta;
	enum ieee80211_smps_mode smps_mode;

	if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -49,7 +50,7 @@ ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_
		break;
	}

	sta->sta.link[link_id]->he_6ghz_capa = *he_6ghz_capa;
	link_sta->pub->he_6ghz_capa = *he_6ghz_capa;
}

static void ieee80211_he_mcs_disable(__le16 *he_mcs)
@@ -108,9 +109,9 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
				  struct ieee80211_supported_band *sband,
				  const u8 *he_cap_ie, u8 he_cap_len,
				  const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
				  struct sta_info *sta, unsigned int link_id)
				  struct link_sta_info *link_sta)
{
	struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap;
	struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
	struct ieee80211_sta_he_cap own_he_cap;
	struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
	u8 he_ppe_size;
@@ -153,13 +154,11 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,

	he_cap->has_he = true;

	sta->link[link_id]->cur_max_bandwidth =
		ieee80211_sta_cap_rx_bw(sta, link_id);
	sta->sta.link[link_id]->bandwidth =
		ieee80211_sta_cur_vht_bw(sta, link_id);
	link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
	link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);

	if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa)
		ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, sta, link_id);
		ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta);

	ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80,
				      &he_cap->he_mcs_nss_supp.rx_mcs_80,
Loading