xref: /wlan-dirver/qcacld-3.0/core/hdd/src/wlan_hdd_mlo.c (revision dc882e4dd9e61bd77cf492e38eb95e049c61d2a7)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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 800
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
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
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
74 void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter,
75 			       struct hdd_adapter *link_adapter)
76 {
77 }
78 
79 static
80 void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter,
81 				 bool rtnl_held)
82 {
83 }
84 #endif
85 
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
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 
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 
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(&ml_adapter->mld_addr,
181 						  &link_addr[0],
182 						  WLAN_MAX_ML_BSS_LINKS);
183 	if (QDF_IS_STATUS_ERROR(status))
184 		return;
185 
186 	/* if target supports MLO create a new dev */
187 	params.only_wdev_register = true;
188 	params.associate_with_ml_adapter = true;
189 	status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null",
190 					   link_addr[0].bytes, &params);
191 	if (QDF_IS_STATUS_ERROR(status))
192 		hdd_err("Failed to register link adapter:%d", status);
193 
194 	qdf_mem_zero(&params, sizeof(params));
195 	params.only_wdev_register  = true;
196 	params.associate_with_ml_adapter = false;
197 	/* if target supports MLO create a new dev */
198 	status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null",
199 					   link_addr[1].bytes, &params);
200 	if (QDF_IS_STATUS_ERROR(status)) {
201 		hdd_err("Failed to register link adapter:%d", status);
202 	} else {
203 		hdd_adapter_for_each_link_info(ml_adapter, link_info) {
204 			qdf_copy_macaddr(&link_info->link_addr,
205 					 &link_addr[i++]);
206 		}
207 	}
208 }
209 
210 void
211 hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter)
212 {
213 	adapter->mlo_adapter_info.is_single_link_ml = true;
214 }
215 
216 void
217 hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter)
218 {
219 	adapter->mlo_adapter_info.is_single_link_ml = false;
220 }
221 
222 struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx)
223 {
224 	struct hdd_adapter *adapter, *next_adapter = NULL;
225 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_VDEV;
226 
227 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
228 					   dbgid) {
229 		if (hdd_adapter_is_ml_adapter(adapter)) {
230 			hdd_adapter_dev_put_debug(adapter, dbgid);
231 			if (next_adapter)
232 				hdd_adapter_dev_put_debug(next_adapter,
233 							  dbgid);
234 			return adapter;
235 		}
236 		hdd_adapter_dev_put_debug(adapter, dbgid);
237 	}
238 
239 	return NULL;
240 }
241 #endif
242 
243 #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
244 void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
245 {
246 	adapter->mlo_adapter_info.is_ml_adapter = true;
247 	qdf_copy_macaddr(&adapter->mld_addr, &adapter->mac_addr);
248 }
249 #else
250 void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
251 {
252 	adapter->mlo_adapter_info.is_ml_adapter = true;
253 }
254 
255 static struct mlo_osif_ext_ops mlo_osif_ops = {
256 	.mlo_mgr_osif_update_bss_info = hdd_cm_save_connected_links_info,
257 	.mlo_mgr_osif_update_mac_addr = hdd_link_switch_vdev_mac_addr_update,
258 	.mlo_mgr_osif_link_switch_notification =
259 					hdd_adapter_link_switch_notification,
260 };
261 
262 QDF_STATUS hdd_mlo_mgr_register_osif_ops(void)
263 {
264 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
265 
266 	return wlan_mlo_mgr_register_osif_ext_ops(mlo_mgr_ctx, &mlo_osif_ops);
267 }
268 
269 QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void)
270 {
271 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
272 
273 	return wlan_mlo_mgr_unregister_osif_ext_ops(mlo_mgr_ctx);
274 }
275 
276 QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev,
277 						uint8_t non_trans_vdev_id)
278 {
279 	int errno;
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 	struct osif_vdev_sync *vdev_sync;
285 
286 	osif_priv = wlan_vdev_get_ospriv(vdev);
287 	if (!osif_priv) {
288 		hdd_err("Invalid osif priv");
289 		return QDF_STATUS_E_INVAL;
290 	}
291 
292 	link_info = osif_priv->legacy_osif_priv;
293 	adapter = link_info->adapter;
294 
295 	if (link_info->vdev_id != adapter->deflink->vdev_id) {
296 		hdd_err("Default VDEV %d not equal", adapter->deflink->vdev_id);
297 		QDF_ASSERT(0);
298 		return QDF_STATUS_E_INVAL;
299 	}
300 
301 	errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
302 	if (errno)
303 		return QDF_STATUS_E_FAILURE;
304 
305 	osif_vdev_sync_wait_for_ops(vdev_sync);
306 	hdd_adapter_for_each_link_info(adapter, iter_link_info) {
307 		if (non_trans_vdev_id == iter_link_info->vdev_id) {
308 			adapter->deflink = iter_link_info;
309 			found = true;
310 			break;
311 		}
312 	}
313 	osif_vdev_sync_trans_stop(vdev_sync);
314 
315 	if (!found)
316 		return QDF_STATUS_E_FAILURE;
317 
318 	return QDF_STATUS_SUCCESS;
319 }
320 #endif
321 
322 void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev)
323 {
324 	if (!vdev || !vdev->mlo_dev_ctx)
325 		return;
326 
327 	wlan_register_t2lm_link_update_notify_handler(
328 			hdd_mlo_dev_t2lm_notify_link_update,
329 			vdev->mlo_dev_ctx);
330 }
331 
332 void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev)
333 {
334 	if (!vdev || !vdev->mlo_dev_ctx)
335 		return;
336 
337 	wlan_unregister_t2lm_link_update_notify_handler(vdev->mlo_dev_ctx, 0);
338 }
339 
340 QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
341 					    struct qdf_mac_addr *link_addr_list,
342 					    uint8_t max_idx)
343 {
344 	uint8_t last_byte, temp_byte, idx;
345 	struct qdf_mac_addr new_addr;
346 	struct qdf_mac_addr *link_addr;
347 
348 	if (!mld_addr || !link_addr_list || !max_idx ||
349 	    max_idx > WLAN_MAX_ML_BSS_LINKS || qdf_is_macaddr_zero(mld_addr)) {
350 		hdd_err("Invalid values");
351 		return QDF_STATUS_E_INVAL;
352 	}
353 
354 	qdf_copy_macaddr(&new_addr, mld_addr);
355 	/* Set locally administered bit */
356 	new_addr.bytes[0] |= 0x02;
357 
358 	link_addr = link_addr_list;
359 	last_byte = mld_addr->bytes[5];
360 	hdd_debug("MLD addr: " QDF_MAC_ADDR_FMT,
361 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
362 
363 	for (idx = 0; 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
380 static void hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter)
381 {
382 	int i;
383 	unsigned long link_flags;
384 	uint8_t vdev_id, cur_link_idx, temp_link_idx;
385 	struct vdev_osif_priv *osif_priv;
386 	struct wlan_objmgr_vdev *vdev;
387 	struct wlan_hdd_link_info *temp_link_info, *link_info;
388 
389 	hdd_adapter_for_each_link_info(adapter, link_info) {
390 		cur_link_idx = hdd_adapter_get_index_of_link_info(link_info);
391 		/* If the current index matches the current pos in mapping
392 		 * then the link info is in same position
393 		 */
394 		if (adapter->curr_link_info_map[cur_link_idx] == cur_link_idx)
395 			continue;
396 
397 		/* Find the index where current link info is moved to perform
398 		 * VDEV info swap.
399 		 */
400 		for (i = cur_link_idx + 1; i < WLAN_MAX_ML_BSS_LINKS; i++) {
401 			if (adapter->curr_link_info_map[i] == cur_link_idx) {
402 				temp_link_idx = i;
403 				break;
404 			}
405 		}
406 
407 		if (i == WLAN_MAX_ML_BSS_LINKS)
408 			continue;
409 
410 		temp_link_info = &adapter->link_info[temp_link_idx];
411 
412 		/* Move VDEV info from current link info */
413 		qdf_spin_lock_bh(&temp_link_info->vdev_lock);
414 		vdev = temp_link_info->vdev;
415 		vdev_id = temp_link_info->vdev_id;
416 		temp_link_info->vdev = link_info->vdev;
417 		temp_link_info->vdev_id = link_info->vdev_id;
418 		qdf_spin_unlock_bh(&temp_link_info->vdev_lock);
419 
420 		/* Fill current link info's actual VDEV info */
421 		qdf_spin_lock_bh(&link_info->vdev_lock);
422 		link_info->vdev = vdev;
423 		link_info->vdev_id = vdev_id;
424 		qdf_spin_unlock_bh(&link_info->vdev_lock);
425 
426 		/* Swap link flags */
427 		link_flags = temp_link_info->link_flags;
428 		temp_link_info->link_flags = link_info->link_flags;
429 		link_info->link_flags = link_flags;
430 
431 		/* Update VDEV-OSIF priv pointer to new link info. */
432 		if (!vdev)
433 			continue;
434 
435 		osif_priv = wlan_vdev_get_ospriv(vdev);
436 		if (!osif_priv)
437 			continue;
438 		osif_priv->legacy_osif_priv = link_info;
439 
440 		/* Update the mapping, current link info's mapping will be
441 		 * set to be proper.
442 		 */
443 		adapter->curr_link_info_map[temp_link_idx] =
444 				adapter->curr_link_info_map[cur_link_idx];
445 		adapter->curr_link_info_map[cur_link_idx] = cur_link_idx;
446 	}
447 	hdd_adapter_disable_all_links(adapter);
448 }
449 
450 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
451 				struct qdf_mac_addr mac_addr)
452 {
453 	int idx, i, ret = 0;
454 	bool eht_capab, update_self_peer;
455 	QDF_STATUS status;
456 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
457 	struct wlan_hdd_link_info *link_info;
458 	uint8_t *addr_list[WLAN_MAX_ML_BSS_LINKS + 1] = {0};
459 	struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0};
460 
461 	/* This API is only called with is ml adapter set for STA mode adapter.
462 	 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for
463 	 * MAC address update.
464 	 */
465 	ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab);
466 	if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) {
467 		struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
468 
469 		ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
470 						  mld_addr, true);
471 		return ret;
472 	}
473 
474 	status = hdd_derive_link_address_from_mld(&mac_addr, &link_addrs[0],
475 						  WLAN_MAX_ML_BSS_LINKS);
476 
477 	if (QDF_IS_STATUS_ERROR(status))
478 		return qdf_status_to_os_return(status);
479 
480 	hdd_adapter_restore_link_vdev_map(adapter);
481 
482 	i = 0;
483 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
484 		idx = hdd_adapter_get_index_of_link_info(link_info);
485 		addr_list[i++] = &link_addrs[idx].bytes[0];
486 	}
487 
488 	status = sme_check_for_duplicate_session(hdd_ctx->mac_handle,
489 						 &addr_list[0]);
490 	if (QDF_IS_STATUS_ERROR(status))
491 		return qdf_status_to_os_return(status);
492 
493 	i = 0;
494 	hdd_adapter_for_each_link_info(adapter, link_info)
495 		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]);
496 
497 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
498 		idx = hdd_adapter_get_index_of_link_info(link_info);
499 		update_self_peer =
500 			(link_info == adapter->deflink) ? true : false;
501 		ret = hdd_dynamic_mac_address_set(link_info, link_addrs[idx],
502 						  mac_addr, update_self_peer);
503 		if (ret)
504 			return ret;
505 
506 		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[idx]);
507 	}
508 
509 	hdd_adapter_update_mlo_mgr_mac_addr(adapter);
510 	return ret;
511 }
512 #else
513 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
514 				struct qdf_mac_addr mac_addr)
515 {
516 	int i, ret = 0;
517 	QDF_STATUS status;
518 	bool eht_capab, update_self_peer;
519 	struct hdd_adapter *link_adapter;
520 	struct hdd_mlo_adapter_info *mlo_adapter_info;
521 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
522 	uint8_t *addr_list[WLAN_MAX_MLD + 1] = {0};
523 	struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0};
524 
525 	/* This API is only called with is ml adapter set for STA mode adapter.
526 	 * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for
527 	 * MAC address update.
528 	 */
529 	ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab);
530 	if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) {
531 		struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT;
532 
533 		ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr,
534 						  mld_addr, true);
535 		return ret;
536 	}
537 
538 	status = hdd_derive_link_address_from_mld(&mac_addr, &link_addrs[0],
539 						  WLAN_MAX_ML_BSS_LINKS);
540 
541 	if (QDF_IS_STATUS_ERROR(status))
542 		return qdf_status_to_os_return(status);
543 
544 	for (i = 0; i < WLAN_MAX_MLD; i++)
545 		addr_list[i] = &link_addrs[i].bytes[0];
546 
547 	status = sme_check_for_duplicate_session(hdd_ctx->mac_handle,
548 						 &addr_list[0]);
549 	if (QDF_IS_STATUS_ERROR(status))
550 		return qdf_status_to_os_return(status);
551 
552 	mlo_adapter_info = &adapter->mlo_adapter_info;
553 	for (i = 0; i < WLAN_MAX_MLD; i++) {
554 		link_adapter = mlo_adapter_info->link_adapter[i];
555 		if (!link_adapter)
556 			continue;
557 
558 		if (hdd_adapter_is_associated_with_ml_adapter(link_adapter))
559 			update_self_peer = true;
560 		else
561 			update_self_peer = false;
562 
563 		ret = hdd_dynamic_mac_address_set(link_adapter->deflink,
564 						  link_addrs[i], mac_addr,
565 						  update_self_peer);
566 		if (ret)
567 			return ret;
568 
569 		/* Update DP intf and new link address in link adapter
570 		 */
571 		ucfg_dp_update_intf_mac(hdd_ctx->psoc, &link_adapter->mac_addr,
572 					&link_addrs[i],
573 					link_adapter->deflink->vdev);
574 		qdf_copy_macaddr(&link_adapter->mac_addr, &link_addrs[i]);
575 		qdf_copy_macaddr(&adapter->link_info[i].link_addr,
576 				 &link_addrs[i]);
577 	}
578 
579 	qdf_copy_macaddr(&adapter->link_info[i].link_addr, &link_addrs[i]);
580 	hdd_adapter_update_mlo_mgr_mac_addr(adapter);
581 
582 	return ret;
583 }
584 #endif
585 #endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */
586 
587 const struct nla_policy
588 ml_link_state_config_policy [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1] = {
589 	[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID] =  {.type = NLA_U8},
590 	[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE] =    {.type = NLA_U32},
591 };
592 
593 const struct nla_policy
594 ml_link_state_request_policy[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1] = {
595 	[QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE] = {.type = NLA_U32},
596 	[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE] = {.type = NLA_U32},
597 	[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG] = {.type = NLA_NESTED},
598 	[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS] = {
599 							.type = NLA_U8},
600 };
601 
602 static int
603 __wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
604 					  struct wireless_dev *wdev,
605 					  const void *data, int data_len)
606 {
607 	int ret = 0;
608 	struct net_device *dev = wdev->netdev;
609 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
610 	struct wlan_objmgr_vdev *vdev;
611 	struct hdd_context *hdd_ctx = NULL;
612 
613 	hdd_enter_dev(wdev->netdev);
614 
615 	if (hdd_validate_adapter(adapter))
616 		return -EINVAL;
617 
618 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
619 	if (!hdd_ctx)
620 		return -EINVAL;
621 
622 	if (adapter->device_mode != QDF_STA_MODE)
623 		return -EINVAL;
624 
625 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
626 
627 	if (!vdev)
628 		return -EINVAL;
629 
630 	ret = wlan_handle_mlo_link_state_operation(wiphy, vdev, hdd_ctx,
631 						   data, data_len);
632 
633 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
634 
635 	return ret;
636 }
637 
638 int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
639 					    struct wireless_dev *wdev,
640 					    const void *data, int data_len)
641 {
642 	int errno;
643 	struct osif_vdev_sync *vdev_sync;
644 
645 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
646 	if (errno)
647 		return errno;
648 
649 	errno = __wlan_hdd_cfg80211_process_ml_link_state(wiphy, wdev, data,
650 							  data_len);
651 
652 	osif_vdev_sync_op_stop(vdev_sync);
653 
654 	return errno;
655 }
656 
657 static inline void ml_link_state_resp_cb(struct ml_link_state_info_event *ev,
658 					 void *cookie)
659 {
660 	struct ml_link_state_info_event *priv;
661 	struct osif_request *request;
662 
663 	request = osif_request_get(cookie);
664 
665 	if (!request) {
666 		hdd_err("Obsolete request");
667 		return;
668 	}
669 
670 	priv = osif_request_priv(request);
671 
672 	qdf_mem_copy(priv, ev, sizeof(*priv));
673 	osif_request_complete(request);
674 	osif_request_put(request);
675 }
676 
677 static uint32_t
678 hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event)
679 {
680 	uint32_t len = 0;
681 	uint32_t info_len = 0;
682 
683 	len = NLMSG_HDRLEN;
684 	/* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE */
685 	len += NLA_HDRLEN + sizeof(u32);
686 
687 	/* QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE */
688 	len += NLA_HDRLEN + sizeof(u32);
689 
690 	/* nest */
691 	info_len = NLA_HDRLEN;
692 	/* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID */
693 	info_len += NLA_HDRLEN + sizeof(u8);
694 	/* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE */
695 	info_len += NLA_HDRLEN + sizeof(u32);
696 
697 	/* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG */
698 	len += NLA_HDRLEN + (info_len * event->num_mlo_vdev_link_info);
699 
700 	return len;
701 }
702 
703 static int
704 hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb,
705 				      struct ml_link_state_info_event *params,
706 				      uint32_t num_link_info)
707 {
708 	struct nlattr *nla_config_attr, *nla_config_params;
709 	uint32_t i = 0, attr;
710 	int errno;
711 	uint32_t value;
712 
713 	attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE;
714 
715 	/* Default control mode is only supported */
716 	value = QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT;
717 	errno = nla_put_u32(skb, attr, value);
718 	if (errno)
719 		return errno;
720 
721 	attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE;
722 
723 	/* Default link state operation mode is only supported */
724 	value = QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT;
725 	errno = nla_put_u32(skb, attr, value);
726 	if (errno)
727 		return errno;
728 
729 	attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG;
730 	nla_config_attr = nla_nest_start(skb, attr);
731 
732 	if (!nla_config_attr)
733 		return -EINVAL;
734 
735 	for (i = 0; i < num_link_info; i++) {
736 		nla_config_params = nla_nest_start(skb, attr);
737 		if (!nla_config_params)
738 			return -EINVAL;
739 
740 		attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID;
741 		value = params->link_info[i].link_id;
742 		errno = nla_put_u8(skb, attr, value);
743 		if (errno)
744 			return errno;
745 
746 		attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE;
747 		value = params->link_info[i].link_status;
748 		errno = nla_put_u32(skb, attr, value);
749 
750 		if (errno)
751 			return errno;
752 
753 		nla_nest_end(skb, nla_config_params);
754 	}
755 
756 	nla_nest_end(skb, nla_config_attr);
757 
758 	return 0;
759 }
760 
761 static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy,
762 					      struct wlan_objmgr_vdev *vdev)
763 {
764 	int errno;
765 	int skb_len;
766 	struct sk_buff *reply_skb = NULL;
767 	QDF_STATUS status = QDF_STATUS_E_INVAL;
768 	void *cookie;
769 	struct ml_link_state_info_event *link_state_event = NULL;
770 	struct osif_request *request;
771 	struct ml_link_state_cmd_info info = {0};
772 	int num_info = 0;
773 	static const struct osif_request_params params = {
774 		.priv_size = sizeof(*link_state_event),
775 		.timeout_ms = WLAN_WAIT_TIME_LINK_STATE,
776 		.dealloc = NULL,
777 	};
778 
779 	if (!wiphy || !vdev)
780 		return status;
781 
782 	request = osif_request_alloc(&params);
783 	if (!request)
784 		return QDF_STATUS_E_NOMEM;
785 
786 	cookie = osif_request_cookie(request);
787 	link_state_event = osif_request_priv(request);
788 
789 	info.request_cookie = cookie;
790 	info.ml_link_state_resp_cb = ml_link_state_resp_cb;
791 
792 	status = mlo_get_link_state_register_resp_cb(vdev,
793 						     &info);
794 	if (QDF_IS_STATUS_ERROR(status)) {
795 		hdd_err("Failed to register resp callback: %d", status);
796 		status = qdf_status_to_os_return(status);
797 		goto free_event;
798 	}
799 
800 	status = ml_post_get_link_state_msg(vdev);
801 	if (QDF_IS_STATUS_ERROR(status)) {
802 		hdd_err("Failed to post scheduler msg");
803 		goto free_event;
804 		return status;
805 	}
806 
807 	status = osif_request_wait_for_response(request);
808 	if (status) {
809 		hdd_err("wait failed or timed out ret: %d", status);
810 		goto free_event;
811 	}
812 
813 	hdd_debug("ml_link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT,
814 		  link_state_event->vdev_id, link_state_event->status,
815 		  link_state_event->num_mlo_vdev_link_info,
816 		  QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes));
817 
818 	for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info;
819 	     num_info++) {
820 		hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d",
821 			  link_state_event->link_info[num_info].chan_freq,
822 			  link_state_event->link_info[num_info].vdev_id,
823 			  link_state_event->link_info[num_info].link_id,
824 			  link_state_event->link_info[num_info].link_status);
825 	}
826 
827 	skb_len = hdd_get_ml_link_state_response_len(link_state_event);
828 
829 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
830 						wiphy,
831 						skb_len);
832 	if (!reply_skb) {
833 		hdd_err("Get stats - alloc reply_skb failed");
834 		status = QDF_STATUS_E_NOMEM;
835 		goto free_event;
836 	}
837 
838 	status = hdd_ml_generate_link_state_resp_nlmsg(
839 			reply_skb, link_state_event,
840 			link_state_event->num_mlo_vdev_link_info);
841 	if (QDF_IS_STATUS_ERROR(status)) {
842 		hdd_err("Failed to pack nl response");
843 		goto free_skb;
844 	}
845 
846 	osif_request_put(request);
847 
848 	errno = wlan_cfg80211_vendor_cmd_reply(reply_skb);
849 	return qdf_status_from_os_return(errno);
850 
851 free_skb:
852 	wlan_cfg80211_vendor_free_skb(reply_skb);
853 free_event:
854 	osif_request_put(request);
855 
856 	return status;
857 }
858 
859 #define MLD_MAX_SUPPORTED_LINKS 2
860 
861 int wlan_handle_mlo_link_state_operation(struct wiphy *wiphy,
862 					 struct wlan_objmgr_vdev *vdev,
863 					 struct hdd_context *hdd_ctx,
864 					 const void *data, int data_len)
865 {
866 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1];
867 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1];
868 	enum qca_wlan_vendor_link_state_op_types ml_link_op;
869 	struct nlattr *link_oper_attr, *mode_attr, *curr_attr, *num_link_attr;
870 	int rem_len = 0, rc;
871 	uint32_t attr_id, ml_config_state;
872 	uint8_t ml_active_num_links, ml_link_control_mode;
873 	uint8_t ml_config_link_id, num_links = 0;
874 	uint8_t vdev_id = vdev->vdev_objmgr.vdev_id;
875 	uint8_t link_id_list[MLD_MAX_SUPPORTED_LINKS] = {0};
876 	uint32_t config_state_list[MLD_MAX_SUPPORTED_LINKS] = {0};
877 	QDF_STATUS status;
878 
879 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX,
880 				    data, data_len,
881 				    ml_link_state_request_policy)) {
882 		hdd_debug("vdev %d: invalid mlo link state attr", vdev_id);
883 		return -EINVAL;
884 	}
885 
886 	attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE;
887 	link_oper_attr = tb[attr_id];
888 	if (!link_oper_attr) {
889 		hdd_debug("vdev %d: link state op not specified", vdev_id);
890 		return -EINVAL;
891 	}
892 	ml_link_op = nla_get_u8(link_oper_attr);
893 	switch (ml_link_op) {
894 	case QCA_WLAN_VENDOR_LINK_STATE_OP_GET:
895 		return wlan_hdd_link_state_request(wiphy, vdev);
896 	case QCA_WLAN_VENDOR_LINK_STATE_OP_SET:
897 		break;
898 	default:
899 		hdd_debug("vdev %d: Invalid op type:%d", vdev_id, ml_link_op);
900 		return -EINVAL;
901 	}
902 
903 	attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE;
904 	mode_attr = tb[attr_id];
905 	if (!mode_attr) {
906 		hdd_debug("vdev %d: ml links control mode attr not present",
907 			  vdev_id);
908 		return -EINVAL;
909 	}
910 	ml_link_control_mode = nla_get_u8(mode_attr);
911 
912 	switch (ml_link_control_mode) {
913 	case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT:
914 		/* clear mlo link(s) settings in fw as per driver */
915 		status = policy_mgr_clear_ml_links_settings_in_fw(hdd_ctx->psoc,
916 								  vdev_id);
917 		if (QDF_IS_STATUS_ERROR(status))
918 			return -EINVAL;
919 		break;
920 	case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER:
921 		attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG;
922 		if (!tb[attr_id]) {
923 			hdd_debug("vdev %d: state config attr not present",
924 				  vdev_id);
925 			return -EINVAL;
926 		}
927 
928 		nla_for_each_nested(curr_attr, tb[attr_id], rem_len) {
929 			rc = wlan_cfg80211_nla_parse_nested(
930 				tb2, QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX,
931 				curr_attr,
932 				ml_link_state_config_policy);
933 			if (rc) {
934 				hdd_debug("vdev %d: nested attr not present",
935 					     vdev_id);
936 				return -EINVAL;
937 			}
938 
939 			attr_id =
940 				QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID;
941 			if (!tb2[attr_id]) {
942 				hdd_debug("vdev %d: link id attr not present",
943 					  vdev_id);
944 				return -EINVAL;
945 			}
946 
947 			ml_config_link_id = nla_get_u8(tb2[attr_id]);
948 
949 			attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE;
950 			if (!tb2[attr_id]) {
951 				hdd_debug("vdev %d: config attr not present",
952 					  vdev_id);
953 				return -EINVAL;
954 			}
955 
956 			ml_config_state = nla_get_u32(tb2[attr_id]);
957 			hdd_debug("vdev %d: ml_link_id %d, ml_link_state:%d",
958 				  vdev_id, ml_config_link_id, ml_config_state);
959 			link_id_list[num_links] = ml_config_link_id;
960 			config_state_list[num_links] = ml_config_state;
961 			num_links++;
962 
963 			if (num_links >= MLD_MAX_SUPPORTED_LINKS)
964 				break;
965 		}
966 
967 		status = policy_mgr_update_mlo_links_based_on_linkid(
968 						hdd_ctx->psoc,
969 						vdev_id, num_links,
970 						link_id_list,
971 						config_state_list);
972 		if (QDF_IS_STATUS_ERROR(status))
973 			return -EINVAL;
974 		break;
975 	case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED:
976 		attr_id =
977 		   QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS;
978 		num_link_attr = tb[attr_id];
979 		if (!num_link_attr) {
980 			hdd_debug("number of active state links not specified");
981 			return -EINVAL;
982 		}
983 		ml_active_num_links = nla_get_u8(num_link_attr);
984 		hdd_debug("vdev %d: ml_active_num_links: %d", vdev_id,
985 			  ml_active_num_links);
986 		if (ml_active_num_links > MLD_MAX_SUPPORTED_LINKS)
987 			return -EINVAL;
988 		status = policy_mgr_update_active_mlo_num_links(hdd_ctx->psoc,
989 						vdev_id, ml_active_num_links);
990 		if (QDF_IS_STATUS_ERROR(status))
991 			return -EINVAL;
992 		break;
993 	default:
994 		hdd_debug("vdev %d: invalid ml_link_control_mode: %d", vdev_id,
995 			  ml_link_control_mode);
996 		return -EINVAL;
997 	}
998 
999 	hdd_debug("vdev: %d, processed link state command successfully",
1000 		  vdev_id);
1001 	return 0;
1002 }
1003 
1004 static uint32_t
1005 hdd_get_t2lm_setup_event_len(void)
1006 {
1007 	uint32_t len = 0;
1008 	uint32_t info_len = 0;
1009 
1010 	len = NLMSG_HDRLEN;
1011 
1012 	/* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR */
1013 	len += nla_total_size(QDF_MAC_ADDR_SIZE);
1014 
1015 	/* nest */
1016 	info_len = NLA_HDRLEN;
1017 	/* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK */
1018 	info_len += NLA_HDRLEN + sizeof(u16);
1019 	/* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK */
1020 	info_len += NLA_HDRLEN + sizeof(u16);
1021 
1022 	/* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS */
1023 	len += NLA_HDRLEN + (info_len * T2LM_MAX_NUM_TIDS);
1024 
1025 	return len;
1026 }
1027 
1028 static QDF_STATUS
1029 hdd_t2lm_pack_nl_response(struct sk_buff *skb,
1030 			  struct wlan_objmgr_vdev *vdev,
1031 			  struct wlan_t2lm_info *t2lm,
1032 			  struct qdf_mac_addr mld_addr)
1033 {
1034 	struct nlattr *config_attr, *config_params;
1035 	uint32_t i = 0, attr, attr1;
1036 	int errno;
1037 	uint32_t value;
1038 	uint8_t tid_num;
1039 
1040 	attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR;
1041 	if (nla_put(skb, attr, QDF_MAC_ADDR_SIZE, mld_addr.bytes)) {
1042 		hdd_err("Failed to put mac_addr");
1043 		return QDF_STATUS_E_INVAL;
1044 	}
1045 
1046 	if (t2lm->default_link_mapping) {
1047 		hdd_debug("update mld addr for default mapping");
1048 		return QDF_STATUS_SUCCESS;
1049 	}
1050 
1051 	attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS;
1052 	config_attr = nla_nest_start(skb, attr);
1053 	if (!config_attr) {
1054 		hdd_err("nla_nest_start error");
1055 		return QDF_STATUS_E_INVAL;
1056 	}
1057 
1058 	switch (t2lm->direction) {
1059 	case WLAN_T2LM_UL_DIRECTION:
1060 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1061 			config_params = nla_nest_start(skb, tid_num + 1);
1062 			if (!config_params)
1063 				return -EINVAL;
1064 
1065 			attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK;
1066 			value = t2lm->ieee_link_map_tid[i];
1067 			errno = nla_put_u16(skb, attr1, value);
1068 			if (errno)
1069 				return errno;
1070 
1071 			attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK;
1072 			value = 0;
1073 			errno = nla_put_u16(skb, attr1, value);
1074 			if (errno)
1075 				return errno;
1076 			nla_nest_end(skb, config_params);
1077 		}
1078 		break;
1079 	case WLAN_T2LM_DL_DIRECTION:
1080 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1081 			config_params = nla_nest_start(skb, tid_num + 1);
1082 			if (!config_params)
1083 				return -EINVAL;
1084 			attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK;
1085 			value = t2lm->ieee_link_map_tid[i];
1086 			errno = nla_put_u16(skb, attr1, value);
1087 			if (errno)
1088 				return errno;
1089 
1090 			attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK;
1091 			value = 0;
1092 			errno = nla_put_u16(skb, attr1, value);
1093 			if (errno)
1094 				return errno;
1095 			nla_nest_end(skb, config_params);
1096 		}
1097 		break;
1098 	case WLAN_T2LM_BIDI_DIRECTION:
1099 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
1100 			config_params = nla_nest_start(skb, tid_num + 1);
1101 			if (!config_params)
1102 				return -EINVAL;
1103 
1104 			attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK;
1105 			value = t2lm->ieee_link_map_tid[i];
1106 			errno = nla_put_u16(skb, attr1, value);
1107 			if (errno)
1108 				return errno;
1109 
1110 			attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK;
1111 			value = t2lm->ieee_link_map_tid[i];
1112 			errno = nla_put_u16(skb, attr1, value);
1113 			if (errno)
1114 				return errno;
1115 			nla_nest_end(skb, config_params);
1116 		}
1117 		break;
1118 	default:
1119 		return -EINVAL;
1120 	}
1121 	nla_nest_end(skb, config_attr);
1122 	return QDF_STATUS_SUCCESS;
1123 }
1124 
1125 QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev,
1126 				    struct wlan_t2lm_info *t2lm)
1127 {
1128 	struct sk_buff *skb;
1129 	size_t data_len;
1130 	QDF_STATUS status;
1131 	struct qdf_mac_addr mld_addr;
1132 	struct hdd_adapter *adapter;
1133 	struct wlan_hdd_link_info *link_info;
1134 
1135 	enum qca_nl80211_vendor_subcmds_index index =
1136 		QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX;
1137 
1138 	link_info = wlan_hdd_get_link_info_from_objmgr(vdev);
1139 	if (!link_info) {
1140 		hdd_err("Invalid VDEV");
1141 		return QDF_STATUS_E_FAILURE;
1142 	}
1143 
1144 	adapter = link_info->adapter;
1145 	data_len = hdd_get_t2lm_setup_event_len();
1146 	skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy,
1147 					       NULL,
1148 					       data_len,
1149 					       index, GFP_KERNEL);
1150 	if (!skb) {
1151 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
1152 		return -EINVAL;
1153 	}
1154 
1155 	/* get mld addr */
1156 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr);
1157 	if (QDF_IS_STATUS_ERROR(status)) {
1158 		hdd_err("Failed to get mld address");
1159 		goto free_skb;
1160 	}
1161 
1162 	status = hdd_t2lm_pack_nl_response(skb, vdev, t2lm, mld_addr);
1163 	if (QDF_IS_STATUS_ERROR(status)) {
1164 		hdd_err("Failed to pack nl response");
1165 		goto free_skb;
1166 	}
1167 
1168 	wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
1169 
1170 	return status;
1171 free_skb:
1172 	wlan_cfg80211_vendor_free_skb(skb);
1173 
1174 	return status;
1175 }
1176 #endif
1177