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