diff mbox series

[59/76] wifi: mac80211: fix link manipulation

Message ID 20220713114426.d26055298480.Id13d50b4dd1ea6298282e4414611822996bba284@changeid (mailing list archive)
State Accepted
Delegated to: Johannes Berg
Headers show
Series wifi: more MLO work | expand

Commit Message

Johannes Berg July 13, 2022, 9:44 a.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

When we add non-deflink pointers, we need to remove the
link[0] pointer to deflink in case link[0] is not valid
afterwards. Also, we need to add that back when there
are no more valid links. Reorg the code to fix that.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/iface.c | 44 ++++++++++++++++++++++++++------------------
 1 file changed, 26 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index fc5869f40279..271fc81a5ea4 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -463,6 +463,10 @@  static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
 	if (old_links == new_links)
 		return 0;
 
+	/* if there were no old links, need to clear the pointers to deflink */
+	if (!old_links)
+		rem |= BIT(0);
+
 	/* allocate new link structures first */
 	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
 		link = kzalloc(sizeof(*link), GFP_KERNEL);
@@ -480,6 +484,22 @@  static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
 	BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
 	memcpy(old_data, sdata->link, sizeof(old_data));
 
+	/* grab old links to free later */
+	for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+		RCU_INIT_POINTER(sdata->link[link_id], NULL);
+		RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
+
+		if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
+			continue;
+		/*
+		 * we must have allocated the data through this path so
+		 * we know we can free both at the same time
+		 */
+		to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
+						typeof(*links[link_id]),
+						data);
+	}
+
 	/* link them into data structures */
 	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
 		WARN_ON(!use_deflink &&
@@ -490,10 +510,9 @@  static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
 		ieee80211_link_setup(&link->data);
 	}
 
-	for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
-		RCU_INIT_POINTER(sdata->link[link_id], NULL);
-		RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
-	}
+	if (new_links == 0)
+		ieee80211_link_init(sdata, -1, &sdata->deflink,
+				    &sdata->vif.bss_conf);
 
 	sdata->vif.valid_links = new_links;
 
@@ -506,25 +525,14 @@  static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
 		memcpy(sdata->link, old_data, sizeof(old_data));
 		memcpy(sdata->vif.link_conf, old, sizeof(old));
 		sdata->vif.valid_links = old_links;
-		/* and free the newly allocated links */
-		goto deinit;
+		/* and free (only) the newly allocated links */
+		memset(to_free, 0, sizeof(links));
+		goto free;
 	}
 
 	/* use deflink/bss_conf again if and only if there are no more links */
 	use_deflink = new_links == 0;
 
-	for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
-		if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
-			continue;
-		/*
-		 * we must have allocated the data through this path so
-		 * we know we can free both at the same time
-		 */
-		to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
-						typeof(*links[link_id]),
-						data);
-	}
-
 	goto deinit;
 free:
 	/* if we failed during allocation, only free all */