From: Johannes Berg It's relatively simple to maintain this pointer back to the interface's link_conf, since it has to exist when the link is added to the station. On the other hand, it's not simple for the driver to look it up indirectly through the vif and it won't be possible to do so during SMD Transition. Add the pointer and keep it pointing to the right place in mac80211. While already touching the function prototype anyway, get rid of the gfp_t argument that's always GFP_KERNEL. Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++++ net/mac80211/cfg.c | 25 ++++++++++++++++++------- net/mac80211/mlme.c | 9 ++++----- net/mac80211/sta_info.c | 41 ++++++++++++++++++++++++++++++++++------- net/mac80211/sta_info.h | 9 ++++----- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2576f9a30b37..e54fa07e2cbf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2619,6 +2619,9 @@ struct ieee80211_sta_aggregates { * or a MLD STA(multiple entries) are stored here. * * @sta: reference to owning STA + * @link_conf: The per-link BSS configuration for the link that the + * station belongs to. During SMD Transition, this link might + * not be in vif->links[]. * @addr: MAC address of the Link STA. For non-MLO STA this is same as the addr * in ieee80211_sta. For MLO Link STA this addr can be same or different * from addr in ieee80211_sta (representing MLD STA addr) @@ -2648,6 +2651,7 @@ struct ieee80211_sta_aggregates { */ struct ieee80211_link_sta { struct ieee80211_sta *sta; + struct ieee80211_bss_conf *link_conf; u8 addr[ETH_ALEN]; u8 link_id; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a4f242a23957..38898fd58692 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2925,13 +2925,19 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct wireless_dev *wdev, * but we need to have a link_mac in that case as well, so use the * STA's MAC address in that case. */ - if (params->link_sta_params.link_id >= 0) - sta = sta_info_alloc_with_link(sdata, mac, - params->link_sta_params.link_id, - params->link_sta_params.link_mac ?: mac, - GFP_KERNEL); - else + if (params->link_sta_params.link_id >= 0) { + struct ieee80211_link_data *link; + + link = wiphy_dereference(wiphy, + sdata->link[params->link_sta_params.link_id]); + if (!link) + return -ENOLINK; + + sta = sta_info_alloc_with_link(link, mac, + params->link_sta_params.link_mac ?: mac); + } else { sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + } if (!sta) return -ENOMEM; @@ -6090,6 +6096,7 @@ ieee80211_add_link_station(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_link_data *link; struct sta_info *sta; int ret; @@ -6105,6 +6112,10 @@ ieee80211_add_link_station(struct wiphy *wiphy, struct net_device *dev, if (sta->sta.valid_links & BIT(params->link_id)) return -EALREADY; + link = wiphy_dereference(wiphy, sdata->link[params->link_id]); + if (!link) + return -ENOLINK; + ret = ieee80211_sta_allocate_link(sta, params->link_id); if (ret) return ret; @@ -6123,7 +6134,7 @@ ieee80211_add_link_station(struct wiphy *wiphy, struct net_device *dev, } /* ieee80211_sta_set_link_valid frees the link upon failure */ - return ieee80211_sta_set_link_valid(sta, params->link_id); + return ieee80211_sta_set_link_valid(sta, link); } static int diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2625103f6307..8b95a3277066 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7223,7 +7223,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, } if (link_id != assoc_data->assoc_link_id) { - err = ieee80211_sta_set_link_valid(sta, link_id); + err = ieee80211_sta_set_link_valid(sta, link); if (err) goto out_err; } @@ -9764,9 +9764,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (!have_sta) { if (mlo) - new_sta = sta_info_alloc_with_link(sdata, ap_mld_addr, - link_id, cbss->bssid, - GFP_KERNEL); + new_sta = sta_info_alloc_with_link(link, ap_mld_addr, + cbss->bssid); else new_sta = sta_info_alloc(sdata, ap_mld_addr, GFP_KERNEL); @@ -11218,7 +11217,7 @@ ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata, if (add_links_data->link[link_id].status != WLAN_STATUS_SUCCESS) goto disconnect; - if (ieee80211_sta_set_link_valid(sta, link_id)) + if (ieee80211_sta_set_link_valid(sta, link)) goto disconnect; changed |= ieee80211_link_set_associated(link, cbss); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 61aadc3c695d..3c2e08808e99 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -629,8 +629,25 @@ static void sta_info_add_link(struct sta_info *sta, link_sta->agg.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA; } +static struct ieee80211_bss_conf * +link_data_pub_link_conf(struct ieee80211_link_data *link) +{ + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_sub_if_data *bss_sdata = get_bss_sdata(sdata); + + if (sdata == bss_sdata) + return link->conf; + + if (link == &sdata->deflink) + return bss_sdata->deflink.conf; + + return sdata_dereference(bss_sdata->vif.link_conf[link->link_id], + bss_sdata); +} + static struct sta_info * __sta_info_alloc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, const u8 *addr, int link_id, const u8 *link_addr, gfp_t gfp) { @@ -660,6 +677,9 @@ __sta_info_alloc(struct ieee80211_sub_if_data *sdata, } sta->sta.cur = &sta->sta.deflink.agg; + sta->sta.deflink.link_conf = link_data_pub_link_conf(link); + if (WARN_ON(!sta->sta.deflink.link_conf)) + goto free; spin_lock_init(&sta->lock); spin_lock_init(&sta->ps_lock); @@ -803,16 +823,15 @@ __sta_info_alloc(struct ieee80211_sub_if_data *sdata, struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, const u8 *addr, gfp_t gfp) { - return __sta_info_alloc(sdata, addr, -1, addr, gfp); + return __sta_info_alloc(sdata, &sdata->deflink, addr, -1, addr, gfp); } -struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata, +struct sta_info *sta_info_alloc_with_link(struct ieee80211_link_data *link, const u8 *mld_addr, - unsigned int link_id, - const u8 *link_addr, - gfp_t gfp) + const u8 *link_addr) { - return __sta_info_alloc(sdata, mld_addr, link_id, link_addr, gfp); + return __sta_info_alloc(link->sdata, link, mld_addr, link->link_id, + link_addr, GFP_KERNEL); } static int sta_info_insert_check(struct sta_info *sta) @@ -3473,12 +3492,15 @@ void ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id) sta_remove_link(sta, link_id, false); } -int ieee80211_sta_set_link_valid(struct sta_info *sta, unsigned int link_id) +int ieee80211_sta_set_link_valid(struct sta_info *sta, + struct ieee80211_link_data *link) { struct ieee80211_sub_if_data *sdata = sta->sdata; struct link_sta_info *link_sta; u16 old_links = sta->sta.valid_links; + int link_id = link->link_id; u16 new_links = old_links | BIT(link_id); + struct ieee80211_bss_conf *link_conf; int ret; link_sta = rcu_dereference_protected(sta->link[link_id], @@ -3495,6 +3517,11 @@ int ieee80211_sta_set_link_valid(struct sta_info *sta, unsigned int link_id) /* we only modify under the mutex so this is fine */ rcu_read_unlock(); + link_conf = link_data_pub_link_conf(link); + if (WARN_ON(!link_conf)) + return -EINVAL; + + link_sta->pub->link_conf = link_conf; sta->sta.valid_links = new_links; if (WARN_ON(!test_sta_flag(sta, WLAN_STA_INSERTED))) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 0a286185125d..5187e3eadf30 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -925,11 +925,9 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, */ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, const u8 *addr, gfp_t gfp); -struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata, +struct sta_info *sta_info_alloc_with_link(struct ieee80211_link_data *link, const u8 *mld_addr, - unsigned int link_id, - const u8 *link_addr, - gfp_t gfp); + const u8 *link_addr); void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); @@ -1008,7 +1006,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id); void ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id); -int ieee80211_sta_set_link_valid(struct sta_info *sta, unsigned int link_id); +int ieee80211_sta_set_link_valid(struct sta_info *sta, + struct ieee80211_link_data *link); void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id); void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); -- 2.56.0