xref: /openbmc/linux/net/mac80211/link.c (revision 15b209cd)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * MLO link handling
4  *
5  * Copyright (C) 2022 Intel Corporation
6  */
7 #include <linux/slab.h>
8 #include <linux/kernel.h>
9 #include <net/mac80211.h>
10 #include "ieee80211_i.h"
11 #include "driver-ops.h"
12 
13 void ieee80211_link_setup(struct ieee80211_link_data *link)
14 {
15 	if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
16 		ieee80211_mgd_setup_link(link);
17 }
18 
19 void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
20 			 int link_id,
21 			 struct ieee80211_link_data *link,
22 			 struct ieee80211_bss_conf *link_conf)
23 {
24 	bool deflink = link_id < 0;
25 
26 	if (link_id < 0)
27 		link_id = 0;
28 
29 	rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
30 	rcu_assign_pointer(sdata->link[link_id], link);
31 
32 	link->sdata = sdata;
33 	link->link_id = link_id;
34 	link->conf = link_conf;
35 	link_conf->link_id = link_id;
36 
37 	INIT_WORK(&link->csa_finalize_work,
38 		  ieee80211_csa_finalize_work);
39 	INIT_WORK(&link->color_change_finalize_work,
40 		  ieee80211_color_change_finalize_work);
41 	INIT_LIST_HEAD(&link->assigned_chanctx_list);
42 	INIT_LIST_HEAD(&link->reserved_chanctx_list);
43 	INIT_DELAYED_WORK(&link->dfs_cac_timer_work,
44 			  ieee80211_dfs_cac_timer_work);
45 
46 	if (!deflink) {
47 		switch (sdata->vif.type) {
48 		case NL80211_IFTYPE_AP:
49 			ether_addr_copy(link_conf->addr,
50 					sdata->wdev.links[link_id].addr);
51 			link_conf->bssid = link_conf->addr;
52 			WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
53 			break;
54 		case NL80211_IFTYPE_STATION:
55 			/* station sets the bssid in ieee80211_mgd_setup_link */
56 			break;
57 		default:
58 			WARN_ON(1);
59 		}
60 	}
61 }
62 
63 void ieee80211_link_stop(struct ieee80211_link_data *link)
64 {
65 	if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
66 		ieee80211_mgd_stop_link(link);
67 
68 	ieee80211_link_release_channel(link);
69 }
70 
71 struct link_container {
72 	struct ieee80211_link_data data;
73 	struct ieee80211_bss_conf conf;
74 };
75 
76 static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
77 				 struct link_container **links)
78 {
79 	LIST_HEAD(keys);
80 	unsigned int link_id;
81 
82 	for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
83 		if (!links[link_id])
84 			continue;
85 		ieee80211_remove_link_keys(&links[link_id]->data, &keys);
86 	}
87 
88 	synchronize_rcu();
89 
90 	ieee80211_free_key_list(sdata->local, &keys);
91 
92 	for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
93 		if (!links[link_id])
94 			continue;
95 		ieee80211_link_stop(&links[link_id]->data);
96 		kfree(links[link_id]);
97 	}
98 }
99 
100 static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
101 {
102 	unsigned int i, j;
103 
104 	for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
105 		struct ieee80211_link_data *link1;
106 
107 		link1 = sdata_dereference(sdata->link[i], sdata);
108 		if (!link1)
109 			continue;
110 		for (j = i + 1; j < IEEE80211_MLD_MAX_NUM_LINKS; j++) {
111 			struct ieee80211_link_data *link2;
112 
113 			link2 = sdata_dereference(sdata->link[j], sdata);
114 			if (!link2)
115 				continue;
116 
117 			if (ether_addr_equal(link1->conf->addr,
118 					     link2->conf->addr))
119 				return -EALREADY;
120 		}
121 	}
122 
123 	return 0;
124 }
125 
126 static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
127 				      struct link_container **to_free,
128 				      u16 new_links)
129 {
130 	u16 old_links = sdata->vif.valid_links;
131 	unsigned long add = new_links & ~old_links;
132 	unsigned long rem = old_links & ~new_links;
133 	unsigned int link_id;
134 	int ret;
135 	struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
136 	struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
137 	struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
138 	bool use_deflink = old_links == 0; /* set for error case */
139 
140 	sdata_assert_lock(sdata);
141 
142 	memset(to_free, 0, sizeof(links));
143 
144 	if (old_links == new_links)
145 		return 0;
146 
147 	/* if there were no old links, need to clear the pointers to deflink */
148 	if (!old_links)
149 		rem |= BIT(0);
150 
151 	/* allocate new link structures first */
152 	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
153 		link = kzalloc(sizeof(*link), GFP_KERNEL);
154 		if (!link) {
155 			ret = -ENOMEM;
156 			goto free;
157 		}
158 		links[link_id] = link;
159 	}
160 
161 	/* keep track of the old pointers for the driver */
162 	BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf));
163 	memcpy(old, sdata->vif.link_conf, sizeof(old));
164 	/* and for us in error cases */
165 	BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
166 	memcpy(old_data, sdata->link, sizeof(old_data));
167 
168 	/* grab old links to free later */
169 	for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
170 		if (rcu_access_pointer(sdata->link[link_id]) != &sdata->deflink) {
171 			/*
172 			 * we must have allocated the data through this path so
173 			 * we know we can free both at the same time
174 			 */
175 			to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
176 							typeof(*links[link_id]),
177 							data);
178 		}
179 
180 		RCU_INIT_POINTER(sdata->link[link_id], NULL);
181 		RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
182 	}
183 
184 	/* link them into data structures */
185 	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
186 		WARN_ON(!use_deflink &&
187 			rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);
188 
189 		link = links[link_id];
190 		ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
191 		ieee80211_link_setup(&link->data);
192 	}
193 
194 	if (new_links == 0)
195 		ieee80211_link_init(sdata, -1, &sdata->deflink,
196 				    &sdata->vif.bss_conf);
197 
198 	sdata->vif.valid_links = new_links;
199 
200 	ret = ieee80211_check_dup_link_addrs(sdata);
201 	if (!ret) {
202 		/* tell the driver */
203 		ret = drv_change_vif_links(sdata->local, sdata,
204 					   old_links, new_links,
205 					   old);
206 	}
207 
208 	if (ret) {
209 		/* restore config */
210 		memcpy(sdata->link, old_data, sizeof(old_data));
211 		memcpy(sdata->vif.link_conf, old, sizeof(old));
212 		sdata->vif.valid_links = old_links;
213 		/* and free (only) the newly allocated links */
214 		memset(to_free, 0, sizeof(links));
215 		goto free;
216 	}
217 
218 	/* use deflink/bss_conf again if and only if there are no more links */
219 	use_deflink = new_links == 0;
220 
221 	goto deinit;
222 free:
223 	/* if we failed during allocation, only free all */
224 	for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
225 		kfree(links[link_id]);
226 		links[link_id] = NULL;
227 	}
228 deinit:
229 	if (use_deflink)
230 		ieee80211_link_init(sdata, -1, &sdata->deflink,
231 				    &sdata->vif.bss_conf);
232 	return ret;
233 }
234 
235 int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
236 			    u16 new_links)
237 {
238 	struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
239 	int ret;
240 
241 	ret = ieee80211_vif_update_links(sdata, links, new_links);
242 	ieee80211_free_links(sdata, links);
243 
244 	return ret;
245 }
246 
247 void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata)
248 {
249 	struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
250 
251 	/*
252 	 * The locking here is different because when we free links
253 	 * in the station case we need to be able to cancel_work_sync()
254 	 * something that also takes the lock.
255 	 */
256 
257 	sdata_lock(sdata);
258 	ieee80211_vif_update_links(sdata, links, 0);
259 	sdata_unlock(sdata);
260 
261 	ieee80211_free_links(sdata, links);
262 }
263