1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * MLO link handling
4 *
5 * Copyright (C) 2022-2024 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#include "key.h"
13#include "debugfs_netdev.h"
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;
38 link_conf->vif = &sdata->vif;
39
40 wiphy_work_init(work: &link->csa_finalize_work,
41 func: ieee80211_csa_finalize_work);
42 wiphy_work_init(work: &link->color_change_finalize_work,
43 func: ieee80211_color_change_finalize_work);
44 INIT_DELAYED_WORK(&link->color_collision_detect_work,
45 ieee80211_color_collision_detection_work);
46 INIT_LIST_HEAD(list: &link->assigned_chanctx_list);
47 INIT_LIST_HEAD(list: &link->reserved_chanctx_list);
48 wiphy_delayed_work_init(dwork: &link->dfs_cac_timer_work,
49 func: ieee80211_dfs_cac_timer_work);
50
51 if (!deflink) {
52 switch (sdata->vif.type) {
53 case NL80211_IFTYPE_AP:
54 ether_addr_copy(dst: link_conf->addr,
55 src: 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 }
65
66 ieee80211_link_debugfs_add(link);
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
75 cancel_delayed_work_sync(dwork: &link->color_collision_detect_work);
76 wiphy_work_cancel(wiphy: link->sdata->local->hw.wiphy,
77 work: &link->csa_finalize_work);
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
86static void ieee80211_tear_down_links(struct ieee80211_sub_if_data *sdata,
87 struct link_container **links, u16 mask)
88{
89 struct ieee80211_link_data *link;
90 LIST_HEAD(keys);
91 unsigned int link_id;
92
93 for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
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))
100 continue;
101 ieee80211_remove_link_keys(link, keys: &keys);
102 ieee80211_link_debugfs_remove(link);
103 ieee80211_link_stop(link);
104 }
105
106 synchronize_rcu();
107
108 ieee80211_free_key_list(local: sdata->local, keys: &keys);
109}
110
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++)
117 kfree(objp: links[link_id]);
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(addr1: link1->conf->addr,
138 addr2: link2->conf->addr))
139 return -EALREADY;
140 }
141 }
142
143 return 0;
144}
145
146static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
147 u16 valid_links, u16 dormant_links)
148{
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)) {
157 sdata->vif.active_links = 0;
158 sdata->vif.dormant_links = 0;
159 return;
160 }
161
162 switch (sdata->vif.type) {
163 case NL80211_IFTYPE_AP:
164 /* in an AP all links are always active */
165 sdata->vif.active_links = valid_links;
166
167 /* AP links are not expected to be disabled */
168 WARN_ON(dormant_links);
169 break;
170 case NL80211_IFTYPE_STATION:
171 if (sdata->vif.active_links)
172 break;
173 sdata->vif.active_links = valid_links & ~dormant_links;
174 WARN_ON(hweight16(sdata->vif.active_links) > 1);
175 break;
176 default:
177 WARN_ON(1);
178 }
179}
180
181static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
182 struct link_container **to_free,
183 u16 new_links, u16 dormant_links)
184{
185 u16 old_links = sdata->vif.valid_links;
186 u16 old_active = sdata->vif.active_links;
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
196 lockdep_assert_wiphy(sdata->local->hw.wiphy);
197
198 memset(to_free, 0, sizeof(links));
199
200 if (old_links == new_links && dormant_links == sdata->vif.dormant_links)
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(size: 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
240 if (!old_links)
241 ieee80211_debugfs_recreate_netdev(sdata, mld_vif: true);
242
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: &link->data, link_conf: &link->conf);
250 ieee80211_link_setup(link: &link->data);
251 }
252
253 if (new_links == 0)
254 ieee80211_link_init(sdata, link_id: -1, link: &sdata->deflink,
255 link_conf: &sdata->vif.bss_conf);
256
257 ret = ieee80211_check_dup_link_addrs(sdata);
258 if (!ret) {
259 /* for keys we will not be able to undo this */
260 ieee80211_tear_down_links(sdata, links: to_free, mask: rem);
261
262 ieee80211_set_vif_links_bitmaps(sdata, valid_links: new_links, dormant_links);
263
264 /* tell the driver */
265 ret = drv_change_vif_links(local: sdata->local, sdata,
266 old_links: old_links & old_active,
267 new_links: new_links & sdata->vif.active_links,
268 old);
269 if (!new_links)
270 ieee80211_debugfs_recreate_netdev(sdata, mld_vif: false);
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));
277 ieee80211_set_vif_links_bitmaps(sdata, valid_links: old_links, dormant_links);
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(objp: links[link_id]);
291 links[link_id] = NULL;
292 }
293deinit:
294 if (use_deflink)
295 ieee80211_link_init(sdata, link_id: -1, link: &sdata->deflink,
296 link_conf: &sdata->vif.bss_conf);
297 return ret;
298}
299
300int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
301 u16 new_links, u16 dormant_links)
302{
303 struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
304 int ret;
305
306 ret = ieee80211_vif_update_links(sdata, to_free: links, new_links,
307 dormant_links);
308 ieee80211_free_links(sdata, links);
309
310 return ret;
311}
312
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
331 if (active_links & ~ieee80211_vif_usable_links(vif: &sdata->vif))
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_links: old_active,
346 new_links: sdata->vif.active_links,
347 old: 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
359 ieee80211_teardown_tdls_peers(link);
360
361 ieee80211_link_release_channel(link);
362 }
363
364 list_for_each_entry(sta, &local->sta_list, list) {
365 if (sdata != sta->sdata)
366 continue;
367
368 /* this is very temporary, but do it anyway */
369 __ieee80211_sta_recalc_aggregates(sta,
370 active_links: old_active | active_links);
371
372 ret = drv_change_sta_links(local, sdata, sta: &sta->sta,
373 old_links: old_active,
374 new_links: old_active | active_links);
375 WARN_ON_ONCE(ret);
376 }
377
378 ret = ieee80211_key_switch_links(sdata, del_links_mask: rem, add_links_mask: add);
379 WARN_ON_ONCE(ret);
380
381 list_for_each_entry(sta, &local->sta_list, list) {
382 if (sdata != sta->sdata)
383 continue;
384
385 __ieee80211_sta_recalc_aggregates(sta, active_links);
386
387 ret = drv_change_sta_links(local, sdata, sta: &sta->sta,
388 old_links: old_active | active_links,
389 new_links: active_links);
390 WARN_ON_ONCE(ret);
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);
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
407 ret = ieee80211_link_use_channel(link,
408 req: &link->conf->chanreq,
409 mode: IEEE80211_CHANCTX_SHARED);
410 WARN_ON_ONCE(ret);
411
412 ieee80211_mgd_set_link_qos_params(link);
413 ieee80211_link_info_change_notify(sdata, link,
414 changed: BSS_CHANGED_ERP_CTS_PROT |
415 BSS_CHANGED_ERP_PREAMBLE |
416 BSS_CHANGED_ERP_SLOT |
417 BSS_CHANGED_HT |
418 BSS_CHANGED_BASIC_RATES |
419 BSS_CHANGED_BSSID |
420 BSS_CHANGED_CQM |
421 BSS_CHANGED_QOS |
422 BSS_CHANGED_TXPOWER |
423 BSS_CHANGED_BANDWIDTH |
424 BSS_CHANGED_TWT |
425 BSS_CHANGED_HE_OBSS_PD |
426 BSS_CHANGED_HE_BSS_COLOR);
427 }
428
429 old_active = sdata->vif.active_links;
430 sdata->vif.active_links = active_links;
431
432 if (rem) {
433 ret = drv_change_vif_links(local, sdata, old_links: old_active,
434 new_links: active_links, old: link_confs);
435 WARN_ON_ONCE(ret);
436 }
437
438 return 0;
439}
440
441int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links)
442{
443 struct ieee80211_sub_if_data *sdata = vif_to_sdata(p: vif);
444 struct ieee80211_local *local = sdata->local;
445 u16 old_active;
446 int ret;
447
448 lockdep_assert_wiphy(local->hw.wiphy);
449
450 if (WARN_ON(!active_links))
451 return -EINVAL;
452
453 if (!drv_can_activate_links(local, sdata, active_links))
454 return -EINVAL;
455
456 old_active = sdata->vif.active_links;
457 if (old_active & active_links) {
458 /*
459 * if there's at least one link that stays active across
460 * the change then switch to it (to those) first, and
461 * then enable the additional links
462 */
463 ret = _ieee80211_set_active_links(sdata,
464 active_links: old_active & active_links);
465 if (!ret)
466 ret = _ieee80211_set_active_links(sdata, active_links);
467 } else {
468 /* otherwise switch directly */
469 ret = _ieee80211_set_active_links(sdata, active_links);
470 }
471
472 return ret;
473}
474EXPORT_SYMBOL_GPL(ieee80211_set_active_links);
475
476void ieee80211_set_active_links_async(struct ieee80211_vif *vif,
477 u16 active_links)
478{
479 struct ieee80211_sub_if_data *sdata = vif_to_sdata(p: vif);
480
481 if (WARN_ON(!active_links))
482 return;
483
484 if (!ieee80211_sdata_running(sdata))
485 return;
486
487 if (sdata->vif.type != NL80211_IFTYPE_STATION)
488 return;
489
490 if (active_links & ~ieee80211_vif_usable_links(vif: &sdata->vif))
491 return;
492
493 /* nothing to do */
494 if (sdata->vif.active_links == active_links)
495 return;
496
497 sdata->desired_active_links = active_links;
498 wiphy_work_queue(wiphy: sdata->local->hw.wiphy, work: &sdata->activate_links_work);
499}
500EXPORT_SYMBOL_GPL(ieee80211_set_active_links_async);
501

source code of linux/net/mac80211/link.c