Linux 6.10-rc3
[linux-block.git] / net / mac80211 / link.c
CommitLineData
e73b5e51
JB
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * MLO link handling
4 *
b82730bf 5 * Copyright (C) 2022-2024 Intel Corporation
e73b5e51
JB
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"
3d901102 12#include "key.h"
170cd6a6 13#include "debugfs_netdev.h"
e73b5e51
JB
14
15void ieee80211_link_setup(struct ieee80211_link_data *link)
16{
17 if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
18 ieee80211_mgd_setup_link(link);
19}
20
21void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
22 int link_id,
23 struct ieee80211_link_data *link,
24 struct ieee80211_bss_conf *link_conf)
25{
26 bool deflink = link_id < 0;
27
28 if (link_id < 0)
29 link_id = 0;
30
31 rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
32 rcu_assign_pointer(sdata->link[link_id], link);
33
34 link->sdata = sdata;
35 link->link_id = link_id;
36 link->conf = link_conf;
37 link_conf->link_id = link_id;
e1f113cc 38 link_conf->vif = &sdata->vif;
e73b5e51 39
d7074be6
JB
40 wiphy_work_init(&link->csa_finalize_work,
41 ieee80211_csa_finalize_work);
b38579ae
JB
42 wiphy_work_init(&link->color_change_finalize_work,
43 ieee80211_color_change_finalize_work);
92881884
LB
44 INIT_DELAYED_WORK(&link->color_collision_detect_work,
45 ieee80211_color_collision_detection_work);
e73b5e51
JB
46 INIT_LIST_HEAD(&link->assigned_chanctx_list);
47 INIT_LIST_HEAD(&link->reserved_chanctx_list);
766d2601
JB
48 wiphy_delayed_work_init(&link->dfs_cac_timer_work,
49 ieee80211_dfs_cac_timer_work);
e73b5e51
JB
50
51 if (!deflink) {
52 switch (sdata->vif.type) {
53 case NL80211_IFTYPE_AP:
54 ether_addr_copy(link_conf->addr,
55 sdata->wdev.links[link_id].addr);
56 link_conf->bssid = link_conf->addr;
57 WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
58 break;
59 case NL80211_IFTYPE_STATION:
60 /* station sets the bssid in ieee80211_mgd_setup_link */
61 break;
62 default:
63 WARN_ON(1);
64 }
170cd6a6
BB
65
66 ieee80211_link_debugfs_add(link);
e73b5e51
JB
67 }
68}
69
70void ieee80211_link_stop(struct ieee80211_link_data *link)
71{
72 if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
73 ieee80211_mgd_stop_link(link);
74
92881884 75 cancel_delayed_work_sync(&link->color_collision_detect_work);
1a96bb4e
AKS
76 wiphy_work_cancel(link->sdata->local->hw.wiphy,
77 &link->csa_finalize_work);
e73b5e51
JB
78 ieee80211_link_release_channel(link);
79}
80
81struct link_container {
82 struct ieee80211_link_data data;
83 struct ieee80211_bss_conf conf;
84};
85
efe9c2bf
JB
86static void ieee80211_tear_down_links(struct ieee80211_sub_if_data *sdata,
87 struct link_container **links, u16 mask)
e73b5e51 88{
efe9c2bf 89 struct ieee80211_link_data *link;
e73b5e51
JB
90 LIST_HEAD(keys);
91 unsigned int link_id;
92
93 for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
efe9c2bf
JB
94 if (!(mask & BIT(link_id)))
95 continue;
96 link = &links[link_id]->data;
97 if (link_id == 0 && !link)
98 link = &sdata->deflink;
99 if (WARN_ON(!link))
e73b5e51 100 continue;
efe9c2bf 101 ieee80211_remove_link_keys(link, &keys);
170cd6a6 102 ieee80211_link_debugfs_remove(link);
efe9c2bf 103 ieee80211_link_stop(link);
e73b5e51
JB
104 }
105
106 synchronize_rcu();
107
108 ieee80211_free_key_list(sdata->local, &keys);
efe9c2bf 109}
e73b5e51 110
efe9c2bf
JB
111static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
112 struct link_container **links)
113{
114 unsigned int link_id;
115
116 for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
e73b5e51 117 kfree(links[link_id]);
e73b5e51
JB
118}
119
120static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
121{
122 unsigned int i, j;
123
124 for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
125 struct ieee80211_link_data *link1;
126
127 link1 = sdata_dereference(sdata->link[i], sdata);
128 if (!link1)
129 continue;
130 for (j = i + 1; j < IEEE80211_MLD_MAX_NUM_LINKS; j++) {
131 struct ieee80211_link_data *link2;
132
133 link2 = sdata_dereference(sdata->link[j], sdata);
134 if (!link2)
135 continue;
136
137 if (ether_addr_equal(link1->conf->addr,
138 link2->conf->addr))
139 return -EALREADY;
140 }
141 }
142
143 return 0;
144}
145
efe9c2bf 146static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
6d543b34 147 u16 valid_links, u16 dormant_links)
efe9c2bf 148{
6d543b34
IP
149 sdata->vif.valid_links = valid_links;
150 sdata->vif.dormant_links = dormant_links;
151
152 if (!valid_links ||
153 WARN((~valid_links & dormant_links) ||
154 !(valid_links & ~dormant_links),
155 "Invalid links: valid=0x%x, dormant=0x%x",
156 valid_links, dormant_links)) {
efe9c2bf 157 sdata->vif.active_links = 0;
6d543b34 158 sdata->vif.dormant_links = 0;
efe9c2bf
JB
159 return;
160 }
161
162 switch (sdata->vif.type) {
163 case NL80211_IFTYPE_AP:
164 /* in an AP all links are always active */
6d543b34
IP
165 sdata->vif.active_links = valid_links;
166
167 /* AP links are not expected to be disabled */
168 WARN_ON(dormant_links);
efe9c2bf
JB
169 break;
170 case NL80211_IFTYPE_STATION:
171 if (sdata->vif.active_links)
172 break;
6d543b34
IP
173 sdata->vif.active_links = valid_links & ~dormant_links;
174 WARN_ON(hweight16(sdata->vif.active_links) > 1);
efe9c2bf
JB
175 break;
176 default:
177 WARN_ON(1);
178 }
179}
180
e73b5e51
JB
181static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
182 struct link_container **to_free,
6d543b34 183 u16 new_links, u16 dormant_links)
e73b5e51
JB
184{
185 u16 old_links = sdata->vif.valid_links;
efe9c2bf 186 u16 old_active = sdata->vif.active_links;
e73b5e51
JB
187 unsigned long add = new_links & ~old_links;
188 unsigned long rem = old_links & ~new_links;
189 unsigned int link_id;
190 int ret;
191 struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
192 struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
193 struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
194 bool use_deflink = old_links == 0; /* set for error case */
195
076fc877 196 lockdep_assert_wiphy(sdata->local->hw.wiphy);
e73b5e51
JB
197
198 memset(to_free, 0, sizeof(links));
199
e7182c4e 200 if (old_links == new_links && dormant_links == sdata->vif.dormant_links)
e73b5e51
JB
201 return 0;
202
203 /* if there were no old links, need to clear the pointers to deflink */
204 if (!old_links)
205 rem |= BIT(0);
206
207 /* allocate new link structures first */
208 for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
209 link = kzalloc(sizeof(*link), GFP_KERNEL);
210 if (!link) {
211 ret = -ENOMEM;
212 goto free;
213 }
214 links[link_id] = link;
215 }
216
217 /* keep track of the old pointers for the driver */
218 BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf));
219 memcpy(old, sdata->vif.link_conf, sizeof(old));
220 /* and for us in error cases */
221 BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
222 memcpy(old_data, sdata->link, sizeof(old_data));
223
224 /* grab old links to free later */
225 for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
226 if (rcu_access_pointer(sdata->link[link_id]) != &sdata->deflink) {
227 /*
228 * we must have allocated the data through this path so
229 * we know we can free both at the same time
230 */
231 to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
232 typeof(*links[link_id]),
233 data);
234 }
235
236 RCU_INIT_POINTER(sdata->link[link_id], NULL);
237 RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
238 }
239
c942398f
MK
240 if (!old_links)
241 ieee80211_debugfs_recreate_netdev(sdata, true);
242
e73b5e51
JB
243 /* link them into data structures */
244 for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
245 WARN_ON(!use_deflink &&
246 rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);
247
248 link = links[link_id];
249 ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
250 ieee80211_link_setup(&link->data);
251 }
252
253 if (new_links == 0)
254 ieee80211_link_init(sdata, -1, &sdata->deflink,
255 &sdata->vif.bss_conf);
256
e73b5e51
JB
257 ret = ieee80211_check_dup_link_addrs(sdata);
258 if (!ret) {
efe9c2bf
JB
259 /* for keys we will not be able to undo this */
260 ieee80211_tear_down_links(sdata, to_free, rem);
261
6d543b34 262 ieee80211_set_vif_links_bitmaps(sdata, new_links, dormant_links);
efe9c2bf 263
e73b5e51
JB
264 /* tell the driver */
265 ret = drv_change_vif_links(sdata->local, sdata,
efe9c2bf
JB
266 old_links & old_active,
267 new_links & sdata->vif.active_links,
e73b5e51 268 old);
c942398f
MK
269 if (!new_links)
270 ieee80211_debugfs_recreate_netdev(sdata, false);
e73b5e51
JB
271 }
272
273 if (ret) {
274 /* restore config */
275 memcpy(sdata->link, old_data, sizeof(old_data));
276 memcpy(sdata->vif.link_conf, old, sizeof(old));
6d543b34 277 ieee80211_set_vif_links_bitmaps(sdata, old_links, dormant_links);
e73b5e51
JB
278 /* and free (only) the newly allocated links */
279 memset(to_free, 0, sizeof(links));
280 goto free;
281 }
282
283 /* use deflink/bss_conf again if and only if there are no more links */
284 use_deflink = new_links == 0;
285
286 goto deinit;
287free:
288 /* if we failed during allocation, only free all */
289 for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
290 kfree(links[link_id]);
291 links[link_id] = NULL;
292 }
293deinit:
294 if (use_deflink)
295 ieee80211_link_init(sdata, -1, &sdata->deflink,
296 &sdata->vif.bss_conf);
297 return ret;
298}
299
300int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
6d543b34 301 u16 new_links, u16 dormant_links)
e73b5e51
JB
302{
303 struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
304 int ret;
305
6d543b34
IP
306 ret = ieee80211_vif_update_links(sdata, links, new_links,
307 dormant_links);
e73b5e51
JB
308 ieee80211_free_links(sdata, links);
309
310 return ret;
311}
312
3d901102
JB
313static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
314 u16 active_links)
315{
316 struct ieee80211_bss_conf *link_confs[IEEE80211_MLD_MAX_NUM_LINKS];
317 struct ieee80211_local *local = sdata->local;
318 u16 old_active = sdata->vif.active_links;
319 unsigned long rem = old_active & ~active_links;
320 unsigned long add = active_links & ~old_active;
321 struct sta_info *sta;
322 unsigned int link_id;
323 int ret, i;
324
325 if (!ieee80211_sdata_running(sdata))
326 return -ENETDOWN;
327
328 if (sdata->vif.type != NL80211_IFTYPE_STATION)
329 return -EINVAL;
330
f1871abd 331 if (active_links & ~ieee80211_vif_usable_links(&sdata->vif))
3d901102
JB
332 return -EINVAL;
333
334 /* nothing to do */
335 if (old_active == active_links)
336 return 0;
337
338 for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
339 link_confs[i] = sdata_dereference(sdata->vif.link_conf[i],
340 sdata);
341
342 if (add) {
343 sdata->vif.active_links |= active_links;
344 ret = drv_change_vif_links(local, sdata,
345 old_active,
346 sdata->vif.active_links,
347 link_confs);
348 if (ret) {
349 sdata->vif.active_links = old_active;
350 return ret;
351 }
352 }
353
354 for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
355 struct ieee80211_link_data *link;
356
357 link = sdata_dereference(sdata->link[link_id], sdata);
358
07fba227 359 ieee80211_teardown_tdls_peers(link);
3d901102 360
3c9ff1a1 361 __ieee80211_link_release_channel(link, true);
3d901102
JB
362 }
363
364 list_for_each_entry(sta, &local->sta_list, list) {
365 if (sdata != sta->sdata)
366 continue;
9b41a9d7
JB
367
368 /* this is very temporary, but do it anyway */
369 __ieee80211_sta_recalc_aggregates(sta,
370 old_active | active_links);
371
3d901102
JB
372 ret = drv_change_sta_links(local, sdata, &sta->sta,
373 old_active,
374 old_active | active_links);
375 WARN_ON_ONCE(ret);
376 }
377
378 ret = ieee80211_key_switch_links(sdata, rem, add);
379 WARN_ON_ONCE(ret);
380
381 list_for_each_entry(sta, &local->sta_list, list) {
382 if (sdata != sta->sdata)
383 continue;
9b41a9d7
JB
384
385 __ieee80211_sta_recalc_aggregates(sta, active_links);
386
3d901102
JB
387 ret = drv_change_sta_links(local, sdata, &sta->sta,
388 old_active | active_links,
389 active_links);
390 WARN_ON_ONCE(ret);
9b41a9d7
JB
391
392 /*
393 * Do it again, just in case - the driver might very
394 * well have called ieee80211_sta_recalc_aggregates()
395 * from there when filling in the new links, which
396 * would set it wrong since the vif's active links are
397 * not switched yet...
398 */
399 __ieee80211_sta_recalc_aggregates(sta, active_links);
3d901102
JB
400 }
401
402 for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
403 struct ieee80211_link_data *link;
404
405 link = sdata_dereference(sdata->link[link_id], sdata);
406
cc3ea42c
BB
407 /*
408 * This call really should not fail. Unfortunately, it appears
409 * that this may happen occasionally with some drivers. Should
410 * it happen, we are stuck in a bad place as going backwards is
411 * not really feasible.
412 *
413 * So lets just tell link_use_channel that it must not fail to
414 * assign the channel context (from mac80211's perspective) and
415 * assume the driver is going to trigger a recovery flow if it
416 * had a failure.
417 * That really is not great nor guaranteed to work. But at least
418 * the internal mac80211 state remains consistent and there is
419 * a chance that we can recover.
420 */
421 ret = _ieee80211_link_use_channel(link,
422 &link->conf->chanreq,
423 IEEE80211_CHANCTX_SHARED,
424 true);
3d901102
JB
425 WARN_ON_ONCE(ret);
426
01605ad6 427 ieee80211_mgd_set_link_qos_params(link);
3d901102
JB
428 ieee80211_link_info_change_notify(sdata, link,
429 BSS_CHANGED_ERP_CTS_PROT |
430 BSS_CHANGED_ERP_PREAMBLE |
431 BSS_CHANGED_ERP_SLOT |
432 BSS_CHANGED_HT |
433 BSS_CHANGED_BASIC_RATES |
434 BSS_CHANGED_BSSID |
435 BSS_CHANGED_CQM |
436 BSS_CHANGED_QOS |
437 BSS_CHANGED_TXPOWER |
438 BSS_CHANGED_BANDWIDTH |
439 BSS_CHANGED_TWT |
440 BSS_CHANGED_HE_OBSS_PD |
441 BSS_CHANGED_HE_BSS_COLOR);
3d901102
JB
442 }
443
444 old_active = sdata->vif.active_links;
445 sdata->vif.active_links = active_links;
446
447 if (rem) {
448 ret = drv_change_vif_links(local, sdata, old_active,
449 active_links, link_confs);
450 WARN_ON_ONCE(ret);
451 }
452
453 return 0;
454}
455
076fc877 456int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links)
3d901102
JB
457{
458 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
459 struct ieee80211_local *local = sdata->local;
460 u16 old_active;
461 int ret;
462
4d3acf43 463 lockdep_assert_wiphy(local->hw.wiphy);
2a8b665e 464
b341590e
MK
465 if (WARN_ON(!active_links))
466 return -EINVAL;
467
2f51c87a
JB
468 old_active = sdata->vif.active_links;
469 if (old_active == active_links)
470 return 0;
471
e993af2e
MK
472 if (!drv_can_activate_links(local, sdata, active_links))
473 return -EINVAL;
474
3d901102
JB
475 if (old_active & active_links) {
476 /*
477 * if there's at least one link that stays active across
478 * the change then switch to it (to those) first, and
479 * then enable the additional links
480 */
481 ret = _ieee80211_set_active_links(sdata,
482 old_active & active_links);
483 if (!ret)
484 ret = _ieee80211_set_active_links(sdata, active_links);
485 } else {
486 /* otherwise switch directly */
487 ret = _ieee80211_set_active_links(sdata, active_links);
488 }
79973d5c
BB
489
490 return ret;
491}
3d901102
JB
492EXPORT_SYMBOL_GPL(ieee80211_set_active_links);
493
494void ieee80211_set_active_links_async(struct ieee80211_vif *vif,
495 u16 active_links)
496{
497 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
498
b341590e
MK
499 if (WARN_ON(!active_links))
500 return;
501
3d901102
JB
502 if (!ieee80211_sdata_running(sdata))
503 return;
504
505 if (sdata->vif.type != NL80211_IFTYPE_STATION)
506 return;
507
f1871abd 508 if (active_links & ~ieee80211_vif_usable_links(&sdata->vif))
3d901102
JB
509 return;
510
511 /* nothing to do */
512 if (sdata->vif.active_links == active_links)
513 return;
514
515 sdata->desired_active_links = active_links;
7206a948 516 wiphy_work_queue(sdata->local->hw.wiphy, &sdata->activate_links_work);
3d901102
JB
517}
518EXPORT_SYMBOL_GPL(ieee80211_set_active_links_async);