1 /*
2 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /**
19 * DOC: wlan_hdd_mlo.c
20 *
21 * WLAN Host Device Driver file for 802.11be (Extremely High Throughput)
22 * support.
23 *
24 */
25 #include "wlan_hdd_main.h"
26 #include "wlan_hdd_mlo.h"
27 #include "osif_vdev_sync.h"
28 #include "wlan_osif_features.h"
29 #include "wlan_dp_ucfg_api.h"
30 #include "wlan_psoc_mlme_ucfg_api.h"
31 #include "wlan_osif_request_manager.h"
32 #include "wlan_hdd_object_manager.h"
33 #include <wlan_osif_priv.h>
34
35 /*max time in ms, caller may wait for link state request get serviced */
36 #define WLAN_WAIT_TIME_LINK_STATE 3000
37
38 #if defined(CFG80211_11BE_BASIC)
39 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
40 #ifdef CFG80211_IFTYPE_MLO_LINK_SUPPORT
41
42 static
wlan_hdd_register_ml_link(struct hdd_adapter * sta_adapter,struct hdd_adapter * link_adapter)43 void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter,
44 struct hdd_adapter *link_adapter)
45 {
46 int ret;
47
48 link_adapter->wdev.iftype = NL80211_IFTYPE_MLO_LINK;
49 mutex_lock(&sta_adapter->wdev.mtx);
50 ret = cfg80211_register_sta_mlo_link(&sta_adapter->wdev,
51 &link_adapter->wdev);
52 mutex_unlock(&sta_adapter->wdev.mtx);
53
54 if (ret) {
55 hdd_err("Failed to register ml link wdev %d", ret);
56 return;
57 }
58 }
59
60 static
wlan_hdd_unregister_ml_link(struct hdd_adapter * link_adapter,bool rtnl_held)61 void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter,
62 bool rtnl_held)
63 {
64 if (rtnl_held)
65 rtnl_unlock();
66
67 cfg80211_unregister_wdev(&link_adapter->wdev);
68
69 if (rtnl_held)
70 rtnl_lock();
71 }
72 #else
73 static
wlan_hdd_register_ml_link(struct hdd_adapter * sta_adapter,struct hdd_adapter * link_adapter)74 void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter,
75 struct hdd_adapter *link_adapter)
76 {
77 }
78
79 static
wlan_hdd_unregister_ml_link(struct hdd_adapter * link_adapter,bool rtnl_held)80 void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter,
81 bool rtnl_held)
82 {
83 }
84 #endif
85
hdd_register_wdev(struct hdd_adapter * sta_adapter,struct hdd_adapter * link_adapter,struct hdd_adapter_create_param * adapter_params)86 void hdd_register_wdev(struct hdd_adapter *sta_adapter,
87 struct hdd_adapter *link_adapter,
88 struct hdd_adapter_create_param *adapter_params)
89 {
90 int i;
91
92 hdd_enter_dev(sta_adapter->dev);
93 /* Set the relation between adapters*/
94 wlan_hdd_register_ml_link(sta_adapter, link_adapter);
95 sta_adapter->mlo_adapter_info.is_ml_adapter = true;
96 sta_adapter->mlo_adapter_info.is_link_adapter = false;
97 link_adapter->mlo_adapter_info.is_link_adapter = true;
98 link_adapter->mlo_adapter_info.is_ml_adapter = false;
99 link_adapter->mlo_adapter_info.ml_adapter = sta_adapter;
100 link_adapter->mlo_adapter_info.associate_with_ml_adapter =
101 adapter_params->associate_with_ml_adapter;
102 qdf_set_bit(WDEV_ONLY_REGISTERED, &link_adapter->event_flags);
103
104 for (i = 0; i < WLAN_MAX_MLD; i++) {
105 if (sta_adapter->mlo_adapter_info.link_adapter[i])
106 continue;
107 sta_adapter->mlo_adapter_info.link_adapter[i] = link_adapter;
108 break;
109 }
110
111 qdf_mem_copy(link_adapter->mld_addr.bytes, sta_adapter->mld_addr.bytes,
112 QDF_MAC_ADDR_SIZE);
113 hdd_exit();
114 }
115
116 static
hdd_mlo_close_adapter(struct hdd_adapter * link_adapter,bool rtnl_held)117 void hdd_mlo_close_adapter(struct hdd_adapter *link_adapter, bool rtnl_held)
118 {
119 struct osif_vdev_sync *vdev_sync;
120
121 vdev_sync = osif_vdev_sync_unregister(link_adapter->dev);
122 if (vdev_sync)
123 osif_vdev_sync_wait_for_ops(vdev_sync);
124
125 hdd_check_for_net_dev_ref_leak(link_adapter);
126 policy_mgr_clear_concurrency_mode(link_adapter->hdd_ctx->psoc,
127 link_adapter->device_mode);
128 link_adapter->wdev.netdev = NULL;
129
130 wlan_hdd_unregister_ml_link(link_adapter, rtnl_held);
131 free_netdev(link_adapter->dev);
132
133 if (vdev_sync)
134 osif_vdev_sync_destroy(vdev_sync);
135 }
136
hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter * adapter,bool rtnl_held)137 QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter,
138 bool rtnl_held)
139 {
140 int i;
141 struct hdd_mlo_adapter_info *mlo_adapter_info;
142 struct hdd_adapter *link_adapter;
143
144 mlo_adapter_info = &adapter->mlo_adapter_info;
145
146 if (mlo_adapter_info->is_link_adapter) {
147 ucfg_dp_destroy_intf(adapter->hdd_ctx->psoc,
148 &adapter->mac_addr);
149 hdd_remove_front_adapter(adapter->hdd_ctx, &adapter);
150 return QDF_STATUS_E_AGAIN;
151 }
152
153 for (i = 0; i < WLAN_MAX_MLD; i++) {
154 link_adapter = mlo_adapter_info->link_adapter[i];
155 if (!link_adapter)
156 continue;
157 hdd_cleanup_conn_info(link_adapter->deflink);
158 ucfg_dp_destroy_intf(link_adapter->hdd_ctx->psoc,
159 &link_adapter->mac_addr);
160 hdd_remove_adapter(link_adapter->hdd_ctx, link_adapter);
161 hdd_mlo_close_adapter(link_adapter, rtnl_held);
162 }
163
164 return QDF_STATUS_SUCCESS;
165 }
166
hdd_wlan_register_mlo_interfaces(struct hdd_context * hdd_ctx)167 void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx)
168 {
169 int i = 0;
170 QDF_STATUS status;
171 struct hdd_adapter *ml_adapter;
172 struct wlan_hdd_link_info *link_info;
173 struct hdd_adapter_create_param params = {0};
174 struct qdf_mac_addr link_addr[WLAN_MAX_ML_BSS_LINKS] = {0};
175
176 ml_adapter = hdd_get_ml_adapter(hdd_ctx);
177 if (!ml_adapter)
178 return;
179
180 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
181 &ml_adapter->mld_addr,
182 &link_addr[0],
183 WLAN_MAX_ML_BSS_LINKS);
184 if (QDF_IS_STATUS_ERROR(status))
185 return;
186
187 /* if target supports MLO create a new dev */
188 params.only_wdev_register = true;
189 params.associate_with_ml_adapter = true;
190 status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null",
191 link_addr[0].bytes, ¶ms);
192 if (QDF_IS_STATUS_ERROR(status))
193 hdd_err("Failed to register link adapter:%d", status);
194
195 qdf_mem_zero(¶ms, sizeof(params));
196 params.only_wdev_register = true;
197 params.associate_with_ml_adapter = false;
198 /* if target supports MLO create a new dev */
199 status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null",
200 link_addr[1].bytes, ¶ms);
201 if (QDF_IS_STATUS_ERROR(status)) {
202 hdd_err("Failed to register link adapter:%d", status);
203 } else {
204 hdd_adapter_for_each_link_info(ml_adapter, link_info) {
205 qdf_copy_macaddr(&link_info->link_addr,
206 &link_addr[i++]);
207 }
208 }
209 }
210
211 void
hdd_adapter_set_sl_ml_adapter(struct hdd_adapter * adapter)212 hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter)
213 {
214 adapter->mlo_adapter_info.is_single_link_ml = true;
215 }
216
217 void
hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter * adapter)218 hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter)
219 {
220 adapter->mlo_adapter_info.is_single_link_ml = false;
221 }
222
hdd_get_ml_adapter(struct hdd_context * hdd_ctx)223 struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx)
224 {
225 struct hdd_adapter *adapter, *next_adapter = NULL;
226 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_VDEV;
227
228 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
229 dbgid) {
230 if (hdd_adapter_is_ml_adapter(adapter)) {
231 hdd_adapter_dev_put_debug(adapter, dbgid);
232 if (next_adapter)
233 hdd_adapter_dev_put_debug(next_adapter,
234 dbgid);
235 return adapter;
236 }
237 hdd_adapter_dev_put_debug(adapter, dbgid);
238 }
239
240 return NULL;
241 }
242 #endif
243
244 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
hdd_adapter_set_ml_adapter(struct hdd_adapter * adapter)245 void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
246 {
247 adapter->mlo_adapter_info.is_ml_adapter = true;
248 qdf_copy_macaddr(&adapter->mld_addr, &adapter->mac_addr);
249 }
250 #else
hdd_adapter_set_ml_adapter(struct hdd_adapter * adapter)251 void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
252 {
253 adapter->mlo_adapter_info.is_ml_adapter = true;
254 }
255
256 static struct mlo_osif_ext_ops mlo_osif_ops = {
257 .mlo_mgr_osif_update_bss_info = hdd_cm_save_connected_links_info,
258 .mlo_mgr_osif_update_mac_addr = hdd_link_switch_vdev_mac_addr_update,
259 .mlo_mgr_osif_link_switch_notification =
260 hdd_adapter_link_switch_notification,
261 };
262
hdd_mlo_mgr_register_osif_ops(void)263 QDF_STATUS hdd_mlo_mgr_register_osif_ops(void)
264 {
265 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
266
267 return wlan_mlo_mgr_register_osif_ext_ops(mlo_mgr_ctx, &mlo_osif_ops);
268 }
269
hdd_mlo_mgr_unregister_osif_ops(void)270 QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void)
271 {
272 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
273
274 return wlan_mlo_mgr_unregister_osif_ext_ops(mlo_mgr_ctx);
275 }
276
hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev * vdev,uint8_t non_trans_vdev_id)277 QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev,
278 uint8_t non_trans_vdev_id)
279 {
280 bool found = false;
281 struct hdd_adapter *adapter;
282 struct vdev_osif_priv *osif_priv;
283 struct wlan_hdd_link_info *link_info, *iter_link_info;
284
285 osif_priv = wlan_vdev_get_ospriv(vdev);
286 if (!osif_priv) {
287 hdd_err("Invalid osif priv");
288 return QDF_STATUS_E_INVAL;
289 }
290
291 link_info = osif_priv->legacy_osif_priv;
292 adapter = link_info->adapter;
293
294 if (link_info->vdev_id != adapter->deflink->vdev_id) {
295 hdd_err("Deflink VDEV %d not equals current VDEV %d",
296 adapter->deflink->vdev_id, link_info->vdev_id);
297 return QDF_STATUS_E_INVAL;
298 }
299
300 hdd_adapter_for_each_link_info(adapter, iter_link_info) {
301 if (non_trans_vdev_id == iter_link_info->vdev_id) {
302 adapter->deflink = iter_link_info;
303 found = true;
304 break;
305 }
306 }
307
308 if (!found)
309 return QDF_STATUS_E_FAILURE;
310
311 return QDF_STATUS_SUCCESS;
312 }
313 #endif
314
hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev * vdev)315 void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev)
316 {
317 if (!vdev || !vdev->mlo_dev_ctx)
318 return;
319
320 wlan_register_t2lm_link_update_notify_handler(
321 hdd_mlo_dev_t2lm_notify_link_update,
322 vdev->mlo_dev_ctx);
323 }
324
hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev * vdev)325 void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev)
326 {
327 if (!vdev || !vdev->mlo_dev_ctx)
328 return;
329
330 wlan_unregister_t2lm_link_update_notify_handler(vdev->mlo_dev_ctx, 0);
331 }
332
hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc * psoc,struct qdf_mac_addr * mld_addr,struct qdf_mac_addr * link_addr_list,uint8_t max_idx)333 QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc,
334 struct qdf_mac_addr *mld_addr,
335 struct qdf_mac_addr *link_addr_list,
336 uint8_t max_idx)
337 {
338 uint8_t last_byte, temp_byte, idx, start_idx = 0;
339 struct qdf_mac_addr new_addr;
340 struct qdf_mac_addr *link_addr;
341
342 if (!psoc || !mld_addr || !link_addr_list || !max_idx ||
343 max_idx > WLAN_MAX_ML_BSS_LINKS || qdf_is_macaddr_zero(mld_addr)) {
344 hdd_err("Invalid values");
345 return QDF_STATUS_E_INVAL;
346 }
347
348 qdf_copy_macaddr(&new_addr, mld_addr);
349 /* Set locally administered bit */
350 new_addr.bytes[0] |= 0x02;
351
352 link_addr = link_addr_list;
353 last_byte = mld_addr->bytes[5];
354 hdd_debug("MLD addr: " QDF_MAC_ADDR_FMT,
355 QDF_MAC_ADDR_REF(mld_addr->bytes));
356
357 if (wlan_mlme_get_sta_same_link_mld_addr(psoc)) {
358 qdf_copy_macaddr(link_addr, mld_addr);
359 link_addr++;
360 start_idx++;
361 }
362
363 for (idx = start_idx; idx < max_idx; idx++) {
364 temp_byte = ((last_byte >> 4 & INTF_MACADDR_MASK) + idx) &
365 INTF_MACADDR_MASK;
366 new_addr.bytes[5] = last_byte + temp_byte;
367 new_addr.bytes[5] ^= (1 << 7);
368
369 qdf_copy_macaddr(link_addr, &new_addr);
370 link_addr++;
371 hdd_debug("Derived link addr: " QDF_MAC_ADDR_FMT ", idx: %d",
372 QDF_MAC_ADDR_REF(new_addr.bytes), idx);
373 }
374
375 return QDF_STATUS_SUCCESS;
376 }
377
378 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
379 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
hdd_adapter_restore_link_vdev_map(struct hdd_adapter * adapter,bool same_vdev_mac_map)380 bool hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter,
381 bool same_vdev_mac_map)
382 {
383 int i;
384 bool mapping_changed = false;
385 unsigned long link_flags;
386 uint8_t vdev_id, cur_link_idx, temp_link_idx;
387 struct vdev_osif_priv *osif_priv;
388 struct wlan_objmgr_vdev *vdev;
389 struct wlan_hdd_link_info *temp_link_info, *link_info;
390 struct qdf_mac_addr temp_mac;
391
392 hdd_adapter_for_each_link_info(adapter, link_info) {
393 cur_link_idx = hdd_adapter_get_index_of_link_info(link_info);
394 /* If the current index matches the current pos in mapping
395 * then the link info is in same position
396 */
397 if (adapter->curr_link_info_map[cur_link_idx] == cur_link_idx)
398 continue;
399
400 /* Find the index where current link info is moved to perform
401 * VDEV info swap.
402 */
403 for (i = cur_link_idx + 1; i < WLAN_MAX_ML_BSS_LINKS; i++) {
404 if (adapter->curr_link_info_map[i] == cur_link_idx) {
405 temp_link_idx = i;
406 break;
407 }
408 }
409
410 if (i == WLAN_MAX_ML_BSS_LINKS)
411 continue;
412
413 temp_link_info = &adapter->link_info[temp_link_idx];
414
415 /* Move VDEV info from current link info */
416 qdf_spin_lock_bh(&temp_link_info->vdev_lock);
417 vdev = temp_link_info->vdev;
418 vdev_id = temp_link_info->vdev_id;
419 temp_link_info->vdev = link_info->vdev;
420 temp_link_info->vdev_id = link_info->vdev_id;
421 qdf_spin_unlock_bh(&temp_link_info->vdev_lock);
422
423 /* Update VDEV-OSIF priv pointer to new link info. */
424 if (temp_link_info->vdev) {
425 osif_priv = wlan_vdev_get_ospriv(temp_link_info->vdev);
426 if (osif_priv)
427 osif_priv->legacy_osif_priv = temp_link_info;
428 }
429
430 /* Fill current link info's actual VDEV info */
431 qdf_spin_lock_bh(&link_info->vdev_lock);
432 link_info->vdev = vdev;
433 link_info->vdev_id = vdev_id;
434 qdf_spin_unlock_bh(&link_info->vdev_lock);
435
436 /* Update VDEV-OSIF priv pointer to new link info. */
437 if (link_info->vdev) {
438 osif_priv = wlan_vdev_get_ospriv(link_info->vdev);
439 if (osif_priv)
440 osif_priv->legacy_osif_priv = link_info;
441 }
442
443 /* Preserve the VDEV-MAC mapping if requested */
444 if (same_vdev_mac_map) {
445 qdf_copy_macaddr(&temp_mac, &temp_link_info->link_addr);
446 qdf_copy_macaddr(&temp_link_info->link_addr,
447 &link_info->link_addr);
448 qdf_copy_macaddr(&link_info->link_addr, &temp_mac);
449 }
450
451 /* Swap link flags */
452 link_flags = temp_link_info->link_flags;
453 temp_link_info->link_flags = link_info->link_flags;
454 link_info->link_flags = link_flags;
455
456 /* Update the mapping, current link info's mapping will be
457 * set to be proper.
458 */
459 adapter->curr_link_info_map[temp_link_idx] =
460 adapter->curr_link_info_map[cur_link_idx];
461 adapter->curr_link_info_map[cur_link_idx] = cur_link_idx;
462
463 if (!mapping_changed)
464 mapping_changed = true;
465 }
466
467 hdd_adapter_disable_all_links(adapter, !same_vdev_mac_map);
468
469 return mapping_changed;
470 }
471
hdd_update_vdev_mac_address(struct hdd_adapter * adapter,struct qdf_mac_addr mac_addr)472 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
473 struct qdf_mac_addr mac_addr)
474 {
475 int idx, i, ret = 0;
476 bool update_self_peer;
477 QDF_STATUS status;
478 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
479 struct wlan_hdd_link_info *link_info;
480 uint8_t *addr_list[WLAN_MAX_ML_BSS_LINKS + 1] = {0};
481 struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0};
482
483 /* This API is only called with is ml adapter set for STA mode adapter.
484 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for
485 * MAC address update.
486 */
487
488 if (!hdd_adapter_is_ml_adapter(adapter)) {
489 struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
490
491 ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
492 mld_addr, true);
493 return ret;
494 }
495
496 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
497 &mac_addr, &link_addrs[0],
498 WLAN_MAX_ML_BSS_LINKS);
499
500 if (QDF_IS_STATUS_ERROR(status))
501 return qdf_status_to_os_return(status);
502
503 hdd_adapter_restore_link_vdev_map(adapter, false);
504
505 i = 0;
506 hdd_adapter_for_each_active_link_info(adapter, link_info) {
507 idx = hdd_adapter_get_index_of_link_info(link_info);
508 addr_list[i++] = &link_addrs[idx].bytes[0];
509 }
510
511 status = sme_check_for_duplicate_session(hdd_ctx->mac_handle,
512 &addr_list[0]);
513 if (QDF_IS_STATUS_ERROR(status))
514 return qdf_status_to_os_return(status);
515
516 i = 0;
517 hdd_adapter_for_each_link_info(adapter, link_info)
518 qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]);
519
520 hdd_adapter_for_each_active_link_info(adapter, link_info) {
521 idx = hdd_adapter_get_index_of_link_info(link_info);
522 update_self_peer =
523 (link_info == adapter->deflink) ? true : false;
524 ret = hdd_dynamic_mac_address_set(link_info, link_addrs[idx],
525 mac_addr, update_self_peer);
526 if (ret)
527 return ret;
528
529 qdf_copy_macaddr(&link_info->link_addr, &link_addrs[idx]);
530 }
531
532 hdd_adapter_update_mlo_mgr_mac_addr(adapter);
533 return ret;
534 }
535 #else
hdd_update_vdev_mac_address(struct hdd_adapter * adapter,struct qdf_mac_addr mac_addr)536 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
537 struct qdf_mac_addr mac_addr)
538 {
539 int i, ret = 0;
540 QDF_STATUS status;
541 bool eht_capab, update_self_peer;
542 struct hdd_adapter *link_adapter;
543 struct hdd_mlo_adapter_info *mlo_adapter_info;
544 struct hdd_context *hdd_ctx = adapter->hdd_ctx;
545 uint8_t *addr_list[WLAN_MAX_MLD + 1] = {0};
546 struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0};
547
548 /* This API is only called with is ml adapter set for STA mode adapter.
549 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for
550 * MAC address update.
551 */
552 ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab);
553 if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) {
554 struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
555
556 ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
557 mld_addr, true);
558 return ret;
559 }
560
561 status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
562 &mac_addr, &link_addrs[0],
563 WLAN_MAX_ML_BSS_LINKS);
564
565 if (QDF_IS_STATUS_ERROR(status))
566 return qdf_status_to_os_return(status);
567
568 for (i = 0; i < WLAN_MAX_MLD; i++)
569 addr_list[i] = &link_addrs[i].bytes[0];
570
571 status = sme_check_for_duplicate_session(hdd_ctx->mac_handle,
572 &addr_list[0]);
573 if (QDF_IS_STATUS_ERROR(status))
574 return qdf_status_to_os_return(status);
575
576 mlo_adapter_info = &adapter->mlo_adapter_info;
577 for (i = 0; i < WLAN_MAX_MLD; i++) {
578 link_adapter = mlo_adapter_info->link_adapter[i];
579 if (!link_adapter)
580 continue;
581
582 if (hdd_adapter_is_associated_with_ml_adapter(link_adapter))
583 update_self_peer = true;
584 else
585 update_self_peer = false;
586
587 ret = hdd_dynamic_mac_address_set(link_adapter->deflink,
588 link_addrs[i], mac_addr,
589 update_self_peer);
590 if (ret)
591 return ret;
592
593 /* Update DP intf and new link address in link adapter
594 */
595 ucfg_dp_update_intf_mac(hdd_ctx->psoc, &link_adapter->mac_addr,
596 &link_addrs[i],
597 link_adapter->deflink->vdev);
598 qdf_copy_macaddr(&link_adapter->mac_addr, &link_addrs[i]);
599 qdf_copy_macaddr(&adapter->link_info[i].link_addr,
600 &link_addrs[i]);
601 }
602
603 qdf_copy_macaddr(&adapter->link_info[i].link_addr, &link_addrs[i]);
604 hdd_adapter_update_mlo_mgr_mac_addr(adapter);
605
606 return ret;
607 }
608 #endif
609 #endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */
610
611 const struct nla_policy
612 ml_link_state_config_policy [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1] = {
613 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID] = {.type = NLA_U8},
614 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE] = {.type = NLA_U32},
615 };
616
617 const struct nla_policy
618 ml_link_state_request_policy[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1] = {
619 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE] = {.type = NLA_U32},
620 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE] = {.type = NLA_U32},
621 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG] = {.type = NLA_NESTED},
622 [QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS] = {
623 .type = NLA_U8},
624 };
625
626 static int
__wlan_hdd_cfg80211_process_ml_link_state(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)627 __wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
628 struct wireless_dev *wdev,
629 const void *data, int data_len)
630 {
631 int ret = 0;
632 struct net_device *dev = wdev->netdev;
633 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
634 struct wlan_objmgr_vdev *vdev;
635 struct hdd_context *hdd_ctx = NULL;
636
637 hdd_enter_dev(wdev->netdev);
638
639 if (hdd_validate_adapter(adapter))
640 return -EINVAL;
641
642 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
643 if (!hdd_ctx)
644 return -EINVAL;
645
646 if (adapter->device_mode != QDF_STA_MODE)
647 return -EINVAL;
648
649 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
650
651 if (!vdev)
652 return -EINVAL;
653
654 if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
655 goto release_ref;
656
657 ret = wlan_handle_mlo_link_state_operation(adapter, wiphy, vdev,
658 hdd_ctx, data, data_len);
659
660 release_ref:
661 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
662
663 return ret;
664 }
665
wlan_hdd_cfg80211_process_ml_link_state(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)666 int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
667 struct wireless_dev *wdev,
668 const void *data, int data_len)
669 {
670 int errno;
671 struct osif_vdev_sync *vdev_sync;
672
673 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
674 if (errno)
675 return errno;
676
677 errno = __wlan_hdd_cfg80211_process_ml_link_state(wiphy, wdev, data,
678 data_len);
679
680 osif_vdev_sync_op_stop(vdev_sync);
681
682 return errno;
683 }
684
ml_link_state_resp_cb(struct ml_link_state_info_event * ev,void * cookie)685 static inline void ml_link_state_resp_cb(struct ml_link_state_info_event *ev,
686 void *cookie)
687 {
688 struct ml_link_state_info_event *priv;
689 struct osif_request *request;
690
691 request = osif_request_get(cookie);
692
693 if (!request) {
694 hdd_err("Obsolete request");
695 return;
696 }
697
698 priv = osif_request_priv(request);
699
700 qdf_mem_copy(priv, ev, sizeof(*priv));
701 osif_request_complete(request);
702 osif_request_put(request);
703 }
704
705 static uint32_t
hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event * event)706 hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event)
707 {
708 uint32_t len = 0;
709 uint32_t info_len = 0;
710
711 len = NLMSG_HDRLEN;
712 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE */
713 len += NLA_HDRLEN + sizeof(u32);
714
715 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE */
716 len += NLA_HDRLEN + sizeof(u32);
717
718 /* nest */
719 info_len = NLA_HDRLEN;
720 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID */
721 info_len += NLA_HDRLEN + sizeof(u8);
722 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE */
723 info_len += NLA_HDRLEN + sizeof(u32);
724
725 /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG */
726 len += NLA_HDRLEN + (info_len * event->num_mlo_vdev_link_info);
727
728 return len;
729 }
730
731 static int
hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff * skb,struct wlan_objmgr_psoc * psoc,struct ml_link_state_info_event * params,uint32_t num_link_info)732 hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb,
733 struct wlan_objmgr_psoc *psoc,
734 struct ml_link_state_info_event *params,
735 uint32_t num_link_info)
736 {
737 struct nlattr *nla_config_attr, *nla_config_params;
738 uint32_t i = 0, attr;
739 int errno;
740 uint32_t value;
741
742 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE;
743 value = ucfg_mlme_get_ml_link_control_mode(psoc, params->vdev_id);
744 errno = nla_put_u32(skb, attr, value);
745 if (errno)
746 return errno;
747
748 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE;
749
750 /* Default link state operation mode is only supported */
751 value = QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT;
752 errno = nla_put_u32(skb, attr, value);
753 if (errno)
754 return errno;
755
756 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG;
757 nla_config_attr = nla_nest_start(skb, attr);
758
759 if (!nla_config_attr)
760 return -EINVAL;
761
762 for (i = 0; i < num_link_info; i++) {
763 nla_config_params = nla_nest_start(skb, attr);
764 if (!nla_config_params)
765 return -EINVAL;
766
767 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID;
768 value = params->link_info[i].link_id;
769 errno = nla_put_u8(skb, attr, value);
770 if (errno)
771 return errno;
772
773 attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE;
774 value = params->link_info[i].link_status;
775 errno = nla_put_u32(skb, attr, value);
776
777 if (errno)
778 return errno;
779
780 nla_nest_end(skb, nla_config_params);
781 }
782
783 nla_nest_end(skb, nla_config_attr);
784
785 return 0;
786 }
787
link_state_status_id_to_str(uint32_t status)788 static char *link_state_status_id_to_str(uint32_t status)
789 {
790 switch (status) {
791 case WLAN_LINK_INFO_EVENT_SUCCESS:
792 return "LINK_INFO_EVENT_SUCCESS";
793 case WLAN_LINK_INFO_EVENT_REJECT_FAILURE:
794 return "LINK_INFO_EVENT_REJECT_FAILURE";
795 case WLAN_LINK_INFO_EVENT_REJECT_VDEV_NOT_UP:
796 return "LINK_INFO_EVENT_REJECT_VDEV_NOT_UP";
797 case WLAN_LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS:
798 return "LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS";
799 case WLAN_LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION:
800 return "LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION";
801 }
802 return "Undefined link state status ID";
803 }
804
805 static bool
wlan_hdd_link_state_request_needed(struct hdd_adapter * adapter)806 wlan_hdd_link_state_request_needed(struct hdd_adapter *adapter)
807 {
808 qdf_time_t link_state_cached_duration = 0;
809
810 link_state_cached_duration =
811 qdf_system_ticks_to_msecs(qdf_system_ticks()) -
812 adapter->link_state_cached_timestamp;
813 if (link_state_cached_duration <=
814 adapter->hdd_ctx->config->link_state_cache_expiry_time)
815 return false;
816
817 return true;
818 }
819
820 #ifdef WLAN_FEATURE_11BE_MLO
821
hdd_update_link_state_cached_timestamp(struct hdd_adapter * adapter)822 void hdd_update_link_state_cached_timestamp(struct hdd_adapter *adapter)
823 {
824 adapter->link_state_cached_timestamp =
825 qdf_system_ticks_to_msecs(qdf_system_ticks());
826 }
827 #endif /* WLAN_FEATURE_11BE_MLO */
828
829 static QDF_STATUS
wlan_hdd_cached_link_state_request(struct hdd_adapter * adapter,struct wiphy * wiphy,struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev)830 wlan_hdd_cached_link_state_request(struct hdd_adapter *adapter,
831 struct wiphy *wiphy,
832 struct wlan_objmgr_psoc *psoc,
833 struct wlan_objmgr_vdev *vdev)
834 {
835 QDF_STATUS status = QDF_STATUS_E_INVAL;
836 struct ml_link_state_info_event link_state_event = {0};
837 struct wlan_hdd_link_info *link_info;
838 struct hdd_station_ctx *sta_ctx;
839 int skb_len;
840 struct sk_buff *reply_skb = NULL;
841 int errno;
842 struct qdf_mac_addr *mld_addr;
843 uint8_t link_iter = 0;
844 struct mlo_link_info *ml_link_info;
845 struct wlan_mlo_dev_context *mlo_ctx;
846
847 mlo_ctx = vdev->mlo_dev_ctx;
848 if (!mlo_ctx) {
849 hdd_err("null mlo_dev_ctx");
850 return -EINVAL;
851 }
852
853 hdd_adapter_for_each_link_info(adapter, link_info) {
854
855 if (link_iter >= WLAN_MAX_ML_BSS_LINKS) {
856 hdd_err("Invalid number of link info");
857 return -EINVAL;
858 }
859
860 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
861 link_state_event.link_info[link_iter].link_id =
862 sta_ctx->conn_info.ieee_link_id;
863 link_state_event.link_info[link_iter].vdev_id =
864 link_info->vdev_id;
865 link_state_event.link_info[link_iter].chan_freq =
866 sta_ctx->ch_info.freq;
867
868 if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID)
869 continue;
870
871 ml_link_info = mlo_mgr_get_ap_link_by_link_id(
872 mlo_ctx,
873 sta_ctx->conn_info.ieee_link_id);
874 if (!ml_link_info) {
875 hdd_debug("link: %d info does not exist",
876 sta_ctx->conn_info.ieee_link_id);
877 return -EINVAL;
878 }
879
880 link_state_event.link_info[link_iter].link_status =
881 ml_link_info->is_link_active;
882
883 link_iter++;
884
885 hdd_debug_rl("vdev id %d sta_ctx->conn_info.ieee_link_id %d is_mlo_vdev_active %d ",
886 link_info->vdev_id, sta_ctx->conn_info.ieee_link_id,
887 ml_link_info->is_link_active);
888 }
889
890 link_state_event.num_mlo_vdev_link_info = link_iter;
891 link_state_event.vdev_id = wlan_vdev_get_id(vdev);
892 link_state_event.status = 0;
893 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
894 link_state_event.mldaddr = *mld_addr;
895
896 hdd_debug_rl("cached link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT,
897 link_state_event.vdev_id, link_state_event.status,
898 link_state_event.num_mlo_vdev_link_info,
899 QDF_MAC_ADDR_REF(link_state_event.mldaddr.bytes));
900
901 skb_len = hdd_get_ml_link_state_response_len(&link_state_event);
902
903 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
904 if (!reply_skb) {
905 hdd_err("Get stats - alloc reply_skb failed");
906 status = QDF_STATUS_E_NOMEM;
907 return status;
908 }
909
910 status = hdd_ml_generate_link_state_resp_nlmsg(
911 reply_skb, psoc, &link_state_event,
912 link_state_event.num_mlo_vdev_link_info);
913 if (QDF_IS_STATUS_ERROR(status)) {
914 hdd_err("Failed to pack nl response");
915 goto free_skb;
916 }
917
918 errno = wlan_cfg80211_vendor_cmd_reply(reply_skb);
919
920 return qdf_status_from_os_return(errno);
921
922 free_skb:
923 wlan_cfg80211_vendor_free_skb(reply_skb);
924 return QDF_STATUS_SUCCESS;
925 }
926
wlan_hdd_link_state_request(struct hdd_adapter * adapter,struct wiphy * wiphy,struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev)927 static QDF_STATUS wlan_hdd_link_state_request(struct hdd_adapter *adapter,
928 struct wiphy *wiphy,
929 struct wlan_objmgr_psoc *psoc,
930 struct wlan_objmgr_vdev *vdev)
931 {
932 int errno;
933 int skb_len;
934 struct sk_buff *reply_skb = NULL;
935 QDF_STATUS status = QDF_STATUS_E_INVAL;
936 void *cookie;
937 struct ml_link_state_info_event *link_state_event = NULL;
938 struct osif_request *request;
939 struct ml_link_state_cmd_info info = {0};
940 int num_info = 0;
941 static const struct osif_request_params params = {
942 .priv_size = sizeof(*link_state_event),
943 .timeout_ms = WLAN_WAIT_TIME_LINK_STATE,
944 .dealloc = NULL,
945 };
946
947 if (!wiphy || !vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev))
948 return status;
949
950 if (adapter->device_mode != QDF_STA_MODE)
951 return QDF_STATUS_SUCCESS;
952
953 if (!wlan_hdd_link_state_request_needed(adapter)) {
954 hdd_debug_rl("sending cached link state request");
955 status = wlan_hdd_cached_link_state_request(adapter, wiphy,
956 psoc, vdev);
957 return status;
958 }
959
960 request = osif_request_alloc(¶ms);
961 if (!request)
962 return QDF_STATUS_E_NOMEM;
963
964 cookie = osif_request_cookie(request);
965 link_state_event = osif_request_priv(request);
966
967 info.request_cookie = cookie;
968 info.ml_link_state_resp_cb = ml_link_state_resp_cb;
969
970 status = mlo_get_link_state_register_resp_cb(vdev,
971 &info);
972 if (QDF_IS_STATUS_ERROR(status)) {
973 hdd_err("Failed to register resp callback: %d", status);
974 status = qdf_status_to_os_return(status);
975 goto free_event;
976 }
977
978 status = ml_post_get_link_state_msg(vdev);
979 if (QDF_IS_STATUS_ERROR(status)) {
980 hdd_err("Failed to post scheduler msg");
981 goto free_event;
982 }
983
984 status = osif_request_wait_for_response(request);
985 if (status) {
986 hdd_err("wait failed or timed out ret: %d", status);
987 goto free_event;
988 }
989
990 hdd_debug("ml_link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT,
991 link_state_event->vdev_id, link_state_event->status,
992 link_state_event->num_mlo_vdev_link_info,
993 QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes));
994
995 if (QDF_IS_STATUS_ERROR(link_state_event->status)) {
996 hdd_debug("ml_link_state_status failed %s",
997 link_state_status_id_to_str(link_state_event->status));
998 goto free_event;
999 }
1000
1001 for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info;
1002 num_info++) {
1003 hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d",
1004 link_state_event->link_info[num_info].chan_freq,
1005 link_state_event->link_info[num_info].vdev_id,
1006 link_state_event->link_info[num_info].link_id,
1007 link_state_event->link_info[num_info].link_status);
1008 }
1009
1010 hdd_update_link_state_cached_timestamp(adapter);
1011
1012 skb_len = hdd_get_ml_link_state_response_len(link_state_event);
1013
1014 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
1015 wiphy,
1016 skb_len);
1017 if (!reply_skb) {
1018 hdd_err("Get stats - alloc reply_skb failed");
1019 status = QDF_STATUS_E_NOMEM;
1020 goto free_event;
1021 }
1022
1023 status = hdd_ml_generate_link_state_resp_nlmsg(
1024 reply_skb, psoc, link_state_event,
1025 link_state_event->num_mlo_vdev_link_info);
1026 if (QDF_IS_STATUS_ERROR(status)) {
1027 hdd_err("Failed to pack nl response");
1028 goto free_skb;
1029 }
1030
1031 osif_request_put(request);
1032
1033 errno = wlan_cfg80211_vendor_cmd_reply(reply_skb);
1034
1035 return qdf_status_from_os_return(errno);
1036
1037 free_skb:
1038 wlan_cfg80211_vendor_free_skb(reply_skb);
1039 free_event:
1040 osif_request_put(request);
1041
1042 return status;
1043 }
1044
1045 #define MLD_MAX_SUPPORTED_LINKS 2
1046
wlan_handle_mlo_link_state_operation(struct hdd_adapter * adapter,struct wiphy * wiphy,struct wlan_objmgr_vdev * vdev,struct hdd_context * hdd_ctx,const void * data,int data_len)1047 int wlan_handle_mlo_link_state_operation(struct hdd_adapter *adapter,
1048 struct wiphy *wiphy,
1049 struct wlan_objmgr_vdev *vdev,
1050 struct hdd_context *hdd_ctx,
1051 const void *data, int data_len)
1052 {
1053 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1];
1054 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1];
1055 enum qca_wlan_vendor_link_state_op_types ml_link_op;
1056 struct nlattr *link_oper_attr, *mode_attr, *curr_attr, *num_link_attr;
1057 int rem_len = 0, rc;
1058 uint32_t attr_id, ml_config_state;
1059 uint8_t ml_active_num_links, ml_link_control_mode;
1060 uint8_t ml_config_link_id, num_links = 0;
1061 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id;
1062 uint8_t link_id_list[MLD_MAX_SUPPORTED_LINKS] = {0};
1063 uint32_t config_state_list[MLD_MAX_SUPPORTED_LINKS] = {0};
1064 QDF_STATUS status;
1065
1066 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX,
1067 data, data_len,
1068 ml_link_state_request_policy)) {
1069 hdd_debug("vdev %d: invalid mlo link state attr", vdev_id);
1070 return -EINVAL;
1071 }
1072
1073 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE;
1074 link_oper_attr = tb[attr_id];
1075 if (!link_oper_attr) {
1076 hdd_debug("vdev %d: link state op not specified", vdev_id);
1077 return -EINVAL;
1078 }
1079 ml_link_op = nla_get_u8(link_oper_attr);
1080 switch (ml_link_op) {
1081 case QCA_WLAN_VENDOR_LINK_STATE_OP_GET:
1082 status = wlan_hdd_link_state_request(adapter, wiphy,
1083 hdd_ctx->psoc, vdev);
1084 return qdf_status_to_os_return(status);
1085 case QCA_WLAN_VENDOR_LINK_STATE_OP_SET:
1086 if (policy_mgr_is_set_link_in_progress(hdd_ctx->psoc)) {
1087 hdd_debug("vdev %d: change link already in progress",
1088 vdev_id);
1089 return -EBUSY;
1090 }
1091
1092 break;
1093 default:
1094 hdd_debug("vdev %d: Invalid op type:%d", vdev_id, ml_link_op);
1095 return -EINVAL;
1096 }
1097
1098 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE;
1099 mode_attr = tb[attr_id];
1100 if (!mode_attr) {
1101 hdd_debug("vdev %d: ml links control mode attr not present",
1102 vdev_id);
1103 return -EINVAL;
1104 }
1105 ml_link_control_mode = nla_get_u8(mode_attr);
1106
1107 switch (ml_link_control_mode) {
1108 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT:
1109 /* clear mlo link(s) settings in fw as per driver */
1110 status = policy_mgr_clear_ml_links_settings_in_fw(hdd_ctx->psoc,
1111 vdev_id);
1112 if (QDF_IS_STATUS_ERROR(status))
1113 return -EINVAL;
1114 break;
1115 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER:
1116 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG;
1117 if (!tb[attr_id]) {
1118 hdd_debug("vdev %d: state config attr not present",
1119 vdev_id);
1120 return -EINVAL;
1121 }
1122
1123 nla_for_each_nested(curr_attr, tb[attr_id], rem_len) {
1124 rc = wlan_cfg80211_nla_parse_nested(
1125 tb2, QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX,
1126 curr_attr,
1127 ml_link_state_config_policy);
1128 if (rc) {
1129 hdd_debug("vdev %d: nested attr not present",
1130 vdev_id);
1131 return -EINVAL;
1132 }
1133
1134 attr_id =
1135 QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID;
1136 if (!tb2[attr_id]) {
1137 hdd_debug("vdev %d: link id attr not present",
1138 vdev_id);
1139 return -EINVAL;
1140 }
1141
1142 ml_config_link_id = nla_get_u8(tb2[attr_id]);
1143
1144 attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE;
1145 if (!tb2[attr_id]) {
1146 hdd_debug("vdev %d: config attr not present",
1147 vdev_id);
1148 return -EINVAL;
1149 }
1150
1151 ml_config_state = nla_get_u32(tb2[attr_id]);
1152 hdd_debug("vdev %d: ml_link_id %d, ml_link_state:%d",
1153 vdev_id, ml_config_link_id, ml_config_state);
1154 link_id_list[num_links] = ml_config_link_id;
1155 config_state_list[num_links] = ml_config_state;
1156 num_links++;
1157
1158 if (num_links >= MLD_MAX_SUPPORTED_LINKS)
1159 break;
1160 }
1161
1162 status = policy_mgr_update_mlo_links_based_on_linkid(
1163 hdd_ctx->psoc,
1164 vdev_id, num_links,
1165 link_id_list,
1166 config_state_list);
1167 if (QDF_IS_STATUS_ERROR(status))
1168 return -EINVAL;
1169 break;
1170 case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED:
1171 attr_id =
1172 QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS;
1173 num_link_attr = tb[attr_id];
1174 if (!num_link_attr) {
1175 hdd_debug("number of active state links not specified");
1176 return -EINVAL;
1177 }
1178 ml_active_num_links = nla_get_u8(num_link_attr);
1179 hdd_debug("vdev %d: ml_active_num_links: %d", vdev_id,
1180 ml_active_num_links);
1181 if (ml_active_num_links > MLD_MAX_SUPPORTED_LINKS)
1182 return -EINVAL;
1183 status = policy_mgr_update_active_mlo_num_links(hdd_ctx->psoc,
1184 vdev_id, ml_active_num_links);
1185 if (QDF_IS_STATUS_ERROR(status))
1186 return -EINVAL;
1187 break;
1188 default:
1189 hdd_debug("vdev %d: invalid ml_link_control_mode: %d", vdev_id,
1190 ml_link_control_mode);
1191 return -EINVAL;
1192 }
1193
1194 ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, vdev_id,
1195 ml_link_control_mode);
1196
1197 hdd_debug("vdev: %d, processed link state command successfully",
1198 vdev_id);
1199 return 0;
1200 }
1201
1202 static uint32_t
hdd_get_t2lm_setup_event_len(void)1203 hdd_get_t2lm_setup_event_len(void)
1204 {
1205 uint32_t len = 0;
1206 uint32_t info_len = 0;
1207
1208 len = NLMSG_HDRLEN;
1209
1210 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR */
1211 len += nla_total_size(QDF_MAC_ADDR_SIZE);
1212
1213 /* nest */
1214 info_len = NLA_HDRLEN;
1215 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK */
1216 info_len += NLA_HDRLEN + sizeof(u16);
1217 /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK */
1218 info_len += NLA_HDRLEN + sizeof(u16);
1219
1220 /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS */
1221 len += NLA_HDRLEN + (info_len * T2LM_MAX_NUM_TIDS);
1222
1223 return len;
1224 }
1225
1226 static QDF_STATUS
hdd_t2lm_pack_nl_response(struct sk_buff * skb,struct wlan_objmgr_vdev * vdev,struct wlan_t2lm_info * t2lm,struct qdf_mac_addr mld_addr)1227 hdd_t2lm_pack_nl_response(struct sk_buff *skb,
1228 struct wlan_objmgr_vdev *vdev,
1229 struct wlan_t2lm_info *t2lm,
1230 struct qdf_mac_addr mld_addr)
1231 {
1232 struct nlattr *config_attr, *config_params;
1233 uint32_t i = 0, attr, attr1;
1234 int errno;
1235 uint32_t value;
1236 uint8_t tid_num;
1237
1238 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR;
1239 if (nla_put(skb, attr, QDF_MAC_ADDR_SIZE, mld_addr.bytes)) {
1240 hdd_err("Failed to put mac_addr");
1241 return QDF_STATUS_E_INVAL;
1242 }
1243
1244 if (t2lm->default_link_mapping) {
1245 hdd_debug("update mld addr for default mapping");
1246 return QDF_STATUS_SUCCESS;
1247 }
1248
1249 attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS;
1250 config_attr = nla_nest_start(skb, attr);
1251 if (!config_attr) {
1252 hdd_err("nla_nest_start error");
1253 return QDF_STATUS_E_INVAL;
1254 }
1255
1256 switch (t2lm->direction) {
1257 case WLAN_T2LM_UL_DIRECTION:
1258 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1259 config_params = nla_nest_start(skb, tid_num + 1);
1260 if (!config_params)
1261 return -EINVAL;
1262
1263 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK;
1264 value = t2lm->ieee_link_map_tid[i];
1265 errno = nla_put_u16(skb, attr1, value);
1266 if (errno)
1267 return errno;
1268
1269 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK;
1270 value = 0;
1271 errno = nla_put_u16(skb, attr1, value);
1272 if (errno)
1273 return errno;
1274 nla_nest_end(skb, config_params);
1275 }
1276 break;
1277 case WLAN_T2LM_DL_DIRECTION:
1278 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1279 config_params = nla_nest_start(skb, tid_num + 1);
1280 if (!config_params)
1281 return -EINVAL;
1282 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK;
1283 value = t2lm->ieee_link_map_tid[i];
1284 errno = nla_put_u16(skb, attr1, value);
1285 if (errno)
1286 return errno;
1287
1288 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK;
1289 value = 0;
1290 errno = nla_put_u16(skb, attr1, value);
1291 if (errno)
1292 return errno;
1293 nla_nest_end(skb, config_params);
1294 }
1295 break;
1296 case WLAN_T2LM_BIDI_DIRECTION:
1297 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1298 config_params = nla_nest_start(skb, tid_num + 1);
1299 if (!config_params)
1300 return -EINVAL;
1301
1302 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK;
1303 value = t2lm->ieee_link_map_tid[i];
1304 errno = nla_put_u16(skb, attr1, value);
1305 if (errno)
1306 return errno;
1307
1308 attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK;
1309 value = t2lm->ieee_link_map_tid[i];
1310 errno = nla_put_u16(skb, attr1, value);
1311 if (errno)
1312 return errno;
1313 nla_nest_end(skb, config_params);
1314 }
1315 break;
1316 default:
1317 return -EINVAL;
1318 }
1319 nla_nest_end(skb, config_attr);
1320 return QDF_STATUS_SUCCESS;
1321 }
1322
wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev * vdev,struct wlan_t2lm_info * t2lm)1323 QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev,
1324 struct wlan_t2lm_info *t2lm)
1325 {
1326 struct sk_buff *skb;
1327 size_t data_len;
1328 QDF_STATUS status;
1329 struct qdf_mac_addr mld_addr;
1330 struct hdd_adapter *adapter;
1331 struct wlan_hdd_link_info *link_info;
1332
1333 enum qca_nl80211_vendor_subcmds_index index =
1334 QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX;
1335
1336 link_info = wlan_hdd_get_link_info_from_objmgr(vdev);
1337 if (!link_info) {
1338 hdd_err("Invalid VDEV");
1339 return QDF_STATUS_E_FAILURE;
1340 }
1341
1342 adapter = link_info->adapter;
1343 data_len = hdd_get_t2lm_setup_event_len();
1344 skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy,
1345 NULL,
1346 data_len,
1347 index, GFP_KERNEL);
1348 if (!skb) {
1349 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
1350 return -EINVAL;
1351 }
1352
1353 /* get mld addr */
1354 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr);
1355 if (QDF_IS_STATUS_ERROR(status)) {
1356 hdd_err("Failed to get mld address");
1357 goto free_skb;
1358 }
1359
1360 status = hdd_t2lm_pack_nl_response(skb, vdev, t2lm, mld_addr);
1361 if (QDF_IS_STATUS_ERROR(status)) {
1362 hdd_err("Failed to pack nl response");
1363 goto free_skb;
1364 }
1365
1366 wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
1367
1368 return status;
1369 free_skb:
1370 wlan_cfg80211_vendor_free_skb(skb);
1371
1372 return status;
1373 }
1374 #endif
1375