xref: /wlan-driver/qcacld-3.0/components/son/dispatcher/src/son_api.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2021-2023 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: contains interface prototypes for son api
20*5113495bSYour Name  */
21*5113495bSYour Name 
22*5113495bSYour Name #include <son_api.h>
23*5113495bSYour Name #include <wlan_reg_services_api.h>
24*5113495bSYour Name #include <wlan_mlme_api.h>
25*5113495bSYour Name #include <ieee80211_external.h>
26*5113495bSYour Name #include <wlan_cfg80211_scan.h>
27*5113495bSYour Name #include <wlan_mlme_main.h>
28*5113495bSYour Name 
29*5113495bSYour Name /**
30*5113495bSYour Name  * struct son_mlme_deliver_cbs - son mlme deliver callbacks
31*5113495bSYour Name  * @deliver_opmode: cb to deliver opmode
32*5113495bSYour Name  * @deliver_smps: cb to deliver smps
33*5113495bSYour Name  */
34*5113495bSYour Name struct son_mlme_deliver_cbs {
35*5113495bSYour Name 	mlme_deliver_cb deliver_opmode;
36*5113495bSYour Name 	mlme_deliver_cb deliver_smps;
37*5113495bSYour Name };
38*5113495bSYour Name 
39*5113495bSYour Name static struct son_mlme_deliver_cbs g_son_mlme_deliver_cbs;
40*5113495bSYour Name 
41*5113495bSYour Name static struct son_cbs *g_son_cbs[WLAN_MAX_VDEVS];
42*5113495bSYour Name static qdf_spinlock_t g_cbs_lock;
43*5113495bSYour Name 
44*5113495bSYour Name QDF_STATUS
wlan_son_register_mlme_deliver_cb(struct wlan_objmgr_psoc * psoc,mlme_deliver_cb cb,enum SON_MLME_DELIVER_CB_TYPE type)45*5113495bSYour Name wlan_son_register_mlme_deliver_cb(struct wlan_objmgr_psoc *psoc,
46*5113495bSYour Name 				  mlme_deliver_cb cb,
47*5113495bSYour Name 				  enum SON_MLME_DELIVER_CB_TYPE type)
48*5113495bSYour Name {
49*5113495bSYour Name 	if (!psoc) {
50*5113495bSYour Name 		son_err("invalid psoc");
51*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
52*5113495bSYour Name 	}
53*5113495bSYour Name 
54*5113495bSYour Name 	switch (type) {
55*5113495bSYour Name 	case SON_MLME_DELIVER_CB_TYPE_OPMODE:
56*5113495bSYour Name 		g_son_mlme_deliver_cbs.deliver_opmode = cb;
57*5113495bSYour Name 		break;
58*5113495bSYour Name 	case SON_MLME_DELIVER_CB_TYPE_SMPS:
59*5113495bSYour Name 		g_son_mlme_deliver_cbs.deliver_smps = cb;
60*5113495bSYour Name 		break;
61*5113495bSYour Name 	default:
62*5113495bSYour Name 		son_err("invalid type");
63*5113495bSYour Name 		break;
64*5113495bSYour Name 	}
65*5113495bSYour Name 
66*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
67*5113495bSYour Name }
68*5113495bSYour Name 
69*5113495bSYour Name /**
70*5113495bSYour Name  * wlan_son_is_he_supported() - is he supported or not
71*5113495bSYour Name  * @psoc: pointer to psoc
72*5113495bSYour Name  *
73*5113495bSYour Name  * Return: true if supports, false otherwise
74*5113495bSYour Name  */
75*5113495bSYour Name #ifdef WLAN_FEATURE_11AX
wlan_son_is_he_supported(struct wlan_objmgr_psoc * psoc)76*5113495bSYour Name static bool wlan_son_is_he_supported(struct wlan_objmgr_psoc *psoc)
77*5113495bSYour Name {
78*5113495bSYour Name 	tDot11fIEhe_cap he_cap = {0};
79*5113495bSYour Name 
80*5113495bSYour Name 	mlme_cfg_get_he_caps(psoc, &he_cap);
81*5113495bSYour Name 	return !!he_cap.present;
82*5113495bSYour Name }
83*5113495bSYour Name #else
wlan_son_is_he_supported(struct wlan_objmgr_psoc * psoc)84*5113495bSYour Name static bool wlan_son_is_he_supported(struct wlan_objmgr_psoc *psoc)
85*5113495bSYour Name {
86*5113495bSYour Name 	return false;
87*5113495bSYour Name }
88*5113495bSYour Name #endif /*WLAN_FEATURE_11AX*/
89*5113495bSYour Name 
wlan_son_peer_ext_stat_enable(struct wlan_objmgr_pdev * pdev,uint8_t * mac_addr,struct wlan_objmgr_vdev * vdev,uint32_t stats_count,uint32_t enable)90*5113495bSYour Name QDF_STATUS wlan_son_peer_ext_stat_enable(struct wlan_objmgr_pdev *pdev,
91*5113495bSYour Name 					 uint8_t *mac_addr,
92*5113495bSYour Name 					 struct wlan_objmgr_vdev *vdev,
93*5113495bSYour Name 					 uint32_t stats_count,
94*5113495bSYour Name 					 uint32_t enable)
95*5113495bSYour Name {
96*5113495bSYour Name 	struct wlan_lmac_if_tx_ops *tx_ops;
97*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
98*5113495bSYour Name 
99*5113495bSYour Name 	if (!pdev) {
100*5113495bSYour Name 		son_err("invalid pdev");
101*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
102*5113495bSYour Name 	}
103*5113495bSYour Name 	psoc = wlan_pdev_get_psoc(pdev);
104*5113495bSYour Name 	if (!psoc) {
105*5113495bSYour Name 		son_err("invalid psoc");
106*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
107*5113495bSYour Name 	}
108*5113495bSYour Name 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
109*5113495bSYour Name 	if (!tx_ops) {
110*5113495bSYour Name 		son_err("invalid tx_ops");
111*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
112*5113495bSYour Name 	}
113*5113495bSYour Name 	if (tx_ops->son_tx_ops.peer_ext_stats_enable)
114*5113495bSYour Name 		return tx_ops->son_tx_ops.peer_ext_stats_enable(pdev,
115*5113495bSYour Name 								mac_addr, vdev,
116*5113495bSYour Name 								stats_count,
117*5113495bSYour Name 								enable);
118*5113495bSYour Name 
119*5113495bSYour Name 	return QDF_STATUS_E_NULL_VALUE;
120*5113495bSYour Name }
121*5113495bSYour Name 
wlan_son_peer_req_inst_stats(struct wlan_objmgr_pdev * pdev,uint8_t * mac_addr,struct wlan_objmgr_vdev * vdev)122*5113495bSYour Name QDF_STATUS wlan_son_peer_req_inst_stats(struct wlan_objmgr_pdev *pdev,
123*5113495bSYour Name 					uint8_t *mac_addr,
124*5113495bSYour Name 					struct wlan_objmgr_vdev *vdev)
125*5113495bSYour Name {
126*5113495bSYour Name 	struct wlan_lmac_if_tx_ops *tx_ops;
127*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
128*5113495bSYour Name 
129*5113495bSYour Name 	if (!pdev) {
130*5113495bSYour Name 		son_err("invalid pdev");
131*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
132*5113495bSYour Name 	}
133*5113495bSYour Name 	psoc = wlan_pdev_get_psoc(pdev);
134*5113495bSYour Name 	if (!psoc) {
135*5113495bSYour Name 		son_err("invalid psoc");
136*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
137*5113495bSYour Name 	}
138*5113495bSYour Name 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
139*5113495bSYour Name 	if (!tx_ops) {
140*5113495bSYour Name 		son_err("invalid tx_ops");
141*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
142*5113495bSYour Name 	}
143*5113495bSYour Name 	if (tx_ops->son_tx_ops.son_send_null)
144*5113495bSYour Name 		return tx_ops->son_tx_ops.son_send_null(pdev, mac_addr, vdev);
145*5113495bSYour Name 
146*5113495bSYour Name 	return QDF_STATUS_E_NULL_VALUE;
147*5113495bSYour Name }
148*5113495bSYour Name 
wlan_son_get_chan_flag(struct wlan_objmgr_pdev * pdev,qdf_freq_t freq,bool flag_160,struct ch_params * chan_params)149*5113495bSYour Name uint32_t wlan_son_get_chan_flag(struct wlan_objmgr_pdev *pdev,
150*5113495bSYour Name 				qdf_freq_t freq, bool flag_160,
151*5113495bSYour Name 				struct ch_params *chan_params)
152*5113495bSYour Name {
153*5113495bSYour Name 	uint32_t flags = 0;
154*5113495bSYour Name 	qdf_freq_t sec_freq;
155*5113495bSYour Name 	struct ch_params ch_width40_ch_params;
156*5113495bSYour Name 	uint8_t sub_20_channel_width = 0;
157*5113495bSYour Name 	enum phy_ch_width bandwidth = mlme_get_vht_ch_width();
158*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
159*5113495bSYour Name 	bool is_he_enabled;
160*5113495bSYour Name 	struct ch_params ch_params;
161*5113495bSYour Name 
162*5113495bSYour Name 	if (!pdev) {
163*5113495bSYour Name 		son_err("invalid pdev");
164*5113495bSYour Name 		return flags;
165*5113495bSYour Name 	}
166*5113495bSYour Name 	psoc = wlan_pdev_get_psoc(pdev);
167*5113495bSYour Name 	if (!psoc) {
168*5113495bSYour Name 		son_err("invalid psoc");
169*5113495bSYour Name 		return flags;
170*5113495bSYour Name 	}
171*5113495bSYour Name 
172*5113495bSYour Name 	is_he_enabled = wlan_son_is_he_supported(psoc);
173*5113495bSYour Name 	wlan_mlme_get_sub_20_chan_width(wlan_pdev_get_psoc(pdev),
174*5113495bSYour Name 					&sub_20_channel_width);
175*5113495bSYour Name 
176*5113495bSYour Name 	qdf_mem_zero(chan_params, sizeof(*chan_params));
177*5113495bSYour Name 	qdf_mem_zero(&ch_params, sizeof(ch_params));
178*5113495bSYour Name 	qdf_mem_zero(&ch_width40_ch_params, sizeof(ch_width40_ch_params));
179*5113495bSYour Name 	if (wlan_reg_is_24ghz_ch_freq(freq)) {
180*5113495bSYour Name 		if (bandwidth == CH_WIDTH_80P80MHZ ||
181*5113495bSYour Name 		    bandwidth == CH_WIDTH_160MHZ ||
182*5113495bSYour Name 		    bandwidth == CH_WIDTH_80MHZ)
183*5113495bSYour Name 			bandwidth = CH_WIDTH_40MHZ;
184*5113495bSYour Name 	}
185*5113495bSYour Name 
186*5113495bSYour Name 	ch_params.ch_width = bandwidth;
187*5113495bSYour Name 	switch (bandwidth) {
188*5113495bSYour Name 	case CH_WIDTH_80P80MHZ:
189*5113495bSYour Name 		ch_params.ch_width = CH_WIDTH_80P80MHZ;
190*5113495bSYour Name 		if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
191*5113495bSYour Name 					pdev, freq,
192*5113495bSYour Name 					&ch_params, REG_CURRENT_PWR_MODE) !=
193*5113495bSYour Name 		    CHANNEL_STATE_INVALID) {
194*5113495bSYour Name 			if (!flag_160) {
195*5113495bSYour Name 				chan_params->ch_width = CH_WIDTH_80P80MHZ;
196*5113495bSYour Name 				wlan_reg_set_channel_params_for_pwrmode(
197*5113495bSYour Name 					pdev, freq, 0, chan_params,
198*5113495bSYour Name 					REG_CURRENT_PWR_MODE);
199*5113495bSYour Name 			}
200*5113495bSYour Name 			if (is_he_enabled)
201*5113495bSYour Name 				flags |= VENDOR_CHAN_FLAG2(
202*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80_80);
203*5113495bSYour Name 			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80_80;
204*5113495bSYour Name 		}
205*5113495bSYour Name 		bandwidth = CH_WIDTH_160MHZ;
206*5113495bSYour Name 		fallthrough;
207*5113495bSYour Name 	case CH_WIDTH_160MHZ:
208*5113495bSYour Name 		ch_params.ch_width = CH_WIDTH_160MHZ;
209*5113495bSYour Name 		if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
210*5113495bSYour Name 					pdev, freq,
211*5113495bSYour Name 					&ch_params, REG_CURRENT_PWR_MODE) !=
212*5113495bSYour Name 		    CHANNEL_STATE_INVALID) {
213*5113495bSYour Name 			if (flag_160) {
214*5113495bSYour Name 				chan_params->ch_width = CH_WIDTH_160MHZ;
215*5113495bSYour Name 				wlan_reg_set_channel_params_for_pwrmode(
216*5113495bSYour Name 					pdev, freq, 0, chan_params,
217*5113495bSYour Name 					REG_CURRENT_PWR_MODE);
218*5113495bSYour Name 			}
219*5113495bSYour Name 			if (is_he_enabled)
220*5113495bSYour Name 				flags |= VENDOR_CHAN_FLAG2(
221*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE160);
222*5113495bSYour Name 			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT160;
223*5113495bSYour Name 		}
224*5113495bSYour Name 		bandwidth = CH_WIDTH_80MHZ;
225*5113495bSYour Name 		fallthrough;
226*5113495bSYour Name 	case CH_WIDTH_80MHZ:
227*5113495bSYour Name 		ch_params.ch_width = CH_WIDTH_80MHZ;
228*5113495bSYour Name 		if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
229*5113495bSYour Name 					pdev, freq,
230*5113495bSYour Name 					&ch_params, REG_CURRENT_PWR_MODE) !=
231*5113495bSYour Name 		    CHANNEL_STATE_INVALID) {
232*5113495bSYour Name 			if (!flag_160 &&
233*5113495bSYour Name 			    chan_params->ch_width != CH_WIDTH_80P80MHZ) {
234*5113495bSYour Name 				chan_params->ch_width = CH_WIDTH_80MHZ;
235*5113495bSYour Name 				wlan_reg_set_channel_params_for_pwrmode(
236*5113495bSYour Name 					pdev, freq, 0, chan_params,
237*5113495bSYour Name 					REG_CURRENT_PWR_MODE);
238*5113495bSYour Name 			}
239*5113495bSYour Name 			if (is_he_enabled)
240*5113495bSYour Name 				flags |= VENDOR_CHAN_FLAG2(
241*5113495bSYour Name 					QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80);
242*5113495bSYour Name 			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80;
243*5113495bSYour Name 		}
244*5113495bSYour Name 		bandwidth = CH_WIDTH_40MHZ;
245*5113495bSYour Name 		fallthrough;
246*5113495bSYour Name 	case CH_WIDTH_40MHZ:
247*5113495bSYour Name 		ch_width40_ch_params.ch_width = bandwidth;
248*5113495bSYour Name 		wlan_reg_set_channel_params_for_pwrmode(pdev, freq, 0,
249*5113495bSYour Name 							&ch_width40_ch_params,
250*5113495bSYour Name 							REG_CURRENT_PWR_MODE);
251*5113495bSYour Name 
252*5113495bSYour Name 		if (ch_width40_ch_params.sec_ch_offset == LOW_PRIMARY_CH)
253*5113495bSYour Name 			sec_freq = freq + 20;
254*5113495bSYour Name 		else if (ch_width40_ch_params.sec_ch_offset == HIGH_PRIMARY_CH)
255*5113495bSYour Name 			sec_freq = freq - 20;
256*5113495bSYour Name 		else
257*5113495bSYour Name 			sec_freq = 0;
258*5113495bSYour Name 
259*5113495bSYour Name 		if (wlan_reg_get_bonded_channel_state_for_pwrmode(
260*5113495bSYour Name 							pdev, freq,
261*5113495bSYour Name 							bandwidth, sec_freq,
262*5113495bSYour Name 							REG_CURRENT_PWR_MODE) !=
263*5113495bSYour Name 		    CHANNEL_STATE_INVALID) {
264*5113495bSYour Name 			if (ch_width40_ch_params.sec_ch_offset ==
265*5113495bSYour Name 			    LOW_PRIMARY_CH) {
266*5113495bSYour Name 				if (is_he_enabled)
267*5113495bSYour Name 				  flags |=
268*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40PLUS;
269*5113495bSYour Name 				flags |=
270*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40PLUS;
271*5113495bSYour Name 				flags |=
272*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS;
273*5113495bSYour Name 			} else if (ch_width40_ch_params.sec_ch_offset ==
274*5113495bSYour Name 				   HIGH_PRIMARY_CH) {
275*5113495bSYour Name 				if (is_he_enabled)
276*5113495bSYour Name 				  flags |=
277*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40MINUS;
278*5113495bSYour Name 				flags |=
279*5113495bSYour Name 				   QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40MINUS;
280*5113495bSYour Name 				flags |=
281*5113495bSYour Name 				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS;
282*5113495bSYour Name 			}
283*5113495bSYour Name 		}
284*5113495bSYour Name 		bandwidth = CH_WIDTH_20MHZ;
285*5113495bSYour Name 		fallthrough;
286*5113495bSYour Name 	case CH_WIDTH_20MHZ:
287*5113495bSYour Name 		flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT20;
288*5113495bSYour Name 		flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT20;
289*5113495bSYour Name 		if (is_he_enabled)
290*5113495bSYour Name 			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE20;
291*5113495bSYour Name 		bandwidth = CH_WIDTH_10MHZ;
292*5113495bSYour Name 		fallthrough;
293*5113495bSYour Name 	case CH_WIDTH_10MHZ:
294*5113495bSYour Name 		if (wlan_reg_get_bonded_channel_state_for_pwrmode(
295*5113495bSYour Name 							pdev, freq,
296*5113495bSYour Name 							bandwidth, 0,
297*5113495bSYour Name 							REG_CURRENT_PWR_MODE) !=
298*5113495bSYour Name 		     CHANNEL_STATE_INVALID &&
299*5113495bSYour Name 		     sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_10)
300*5113495bSYour Name 			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF;
301*5113495bSYour Name 		bandwidth = CH_WIDTH_5MHZ;
302*5113495bSYour Name 		fallthrough;
303*5113495bSYour Name 	case CH_WIDTH_5MHZ:
304*5113495bSYour Name 		if (wlan_reg_get_bonded_channel_state_for_pwrmode(
305*5113495bSYour Name 							pdev, freq,
306*5113495bSYour Name 							bandwidth, 0,
307*5113495bSYour Name 							REG_CURRENT_PWR_MODE) !=
308*5113495bSYour Name 		    CHANNEL_STATE_INVALID &&
309*5113495bSYour Name 		    sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_5)
310*5113495bSYour Name 			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER;
311*5113495bSYour Name 		break;
312*5113495bSYour Name 	default:
313*5113495bSYour Name 		son_info("invalid channel width value %d", bandwidth);
314*5113495bSYour Name 	}
315*5113495bSYour Name 
316*5113495bSYour Name 	return flags;
317*5113495bSYour Name }
318*5113495bSYour Name 
wlan_son_peer_set_kickout_allow(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,bool kickout_allow)319*5113495bSYour Name QDF_STATUS wlan_son_peer_set_kickout_allow(struct wlan_objmgr_vdev *vdev,
320*5113495bSYour Name 					   struct wlan_objmgr_peer *peer,
321*5113495bSYour Name 					   bool kickout_allow)
322*5113495bSYour Name {
323*5113495bSYour Name 	struct peer_mlme_priv_obj *peer_priv;
324*5113495bSYour Name 
325*5113495bSYour Name 	if (!peer) {
326*5113495bSYour Name 		son_err("invalid peer");
327*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
328*5113495bSYour Name 	}
329*5113495bSYour Name 	if (!vdev) {
330*5113495bSYour Name 		son_err("invalid vdev");
331*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
332*5113495bSYour Name 	}
333*5113495bSYour Name 
334*5113495bSYour Name 	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
335*5113495bSYour Name 							  WLAN_UMAC_COMP_MLME);
336*5113495bSYour Name 	if (!peer_priv) {
337*5113495bSYour Name 		son_err("invalid vdev");
338*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
339*5113495bSYour Name 	}
340*5113495bSYour Name 
341*5113495bSYour Name 	peer_priv->allow_kickout = kickout_allow;
342*5113495bSYour Name 
343*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
344*5113495bSYour Name }
345*5113495bSYour Name 
wlan_son_peer_is_kickout_allow(struct wlan_objmgr_vdev * vdev,uint8_t * macaddr)346*5113495bSYour Name bool wlan_son_peer_is_kickout_allow(struct wlan_objmgr_vdev *vdev,
347*5113495bSYour Name 				    uint8_t *macaddr)
348*5113495bSYour Name {
349*5113495bSYour Name 	bool kickout_allow = true;
350*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
351*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
352*5113495bSYour Name 	struct peer_mlme_priv_obj *peer_priv;
353*5113495bSYour Name 
354*5113495bSYour Name 	if (!vdev) {
355*5113495bSYour Name 		son_err("invalid vdev");
356*5113495bSYour Name 		return kickout_allow;
357*5113495bSYour Name 	}
358*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
359*5113495bSYour Name 	if (!psoc) {
360*5113495bSYour Name 		son_err("invalid psoc");
361*5113495bSYour Name 		return kickout_allow;
362*5113495bSYour Name 	}
363*5113495bSYour Name 	peer = wlan_objmgr_get_peer_by_mac(psoc, macaddr,
364*5113495bSYour Name 					   WLAN_SON_ID);
365*5113495bSYour Name 
366*5113495bSYour Name 	if (!peer) {
367*5113495bSYour Name 		son_err("peer is null");
368*5113495bSYour Name 		return kickout_allow;
369*5113495bSYour Name 	}
370*5113495bSYour Name 
371*5113495bSYour Name 	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
372*5113495bSYour Name 							  WLAN_UMAC_COMP_MLME);
373*5113495bSYour Name 	if (!peer_priv) {
374*5113495bSYour Name 		son_err("invalid vdev");
375*5113495bSYour Name 		wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
376*5113495bSYour Name 		return kickout_allow;
377*5113495bSYour Name 	}
378*5113495bSYour Name 	kickout_allow = peer_priv->allow_kickout;
379*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
380*5113495bSYour Name 
381*5113495bSYour Name 	return kickout_allow;
382*5113495bSYour Name }
383*5113495bSYour Name 
wlan_son_ind_assoc_req_frm(struct wlan_objmgr_vdev * vdev,uint8_t * macaddr,bool is_reassoc,uint8_t * frame,uint16_t frame_len,QDF_STATUS status)384*5113495bSYour Name void wlan_son_ind_assoc_req_frm(struct wlan_objmgr_vdev *vdev,
385*5113495bSYour Name 				uint8_t *macaddr, bool is_reassoc,
386*5113495bSYour Name 				uint8_t *frame, uint16_t frame_len,
387*5113495bSYour Name 				QDF_STATUS status)
388*5113495bSYour Name {
389*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
390*5113495bSYour Name 	struct wlan_lmac_if_rx_ops *rx_ops;
391*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
392*5113495bSYour Name 	uint16_t assocstatus = STATUS_UNSPECIFIED_FAILURE;
393*5113495bSYour Name 	uint16_t sub_type = IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
394*5113495bSYour Name 
395*5113495bSYour Name 	if (!vdev) {
396*5113495bSYour Name 		son_err("invalid vdev");
397*5113495bSYour Name 		return;
398*5113495bSYour Name 	}
399*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
400*5113495bSYour Name 	if (!psoc) {
401*5113495bSYour Name 		son_err("invalid psoc");
402*5113495bSYour Name 		return;
403*5113495bSYour Name 	}
404*5113495bSYour Name 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
405*5113495bSYour Name 	if (!rx_ops || !rx_ops->son_rx_ops.process_mgmt_frame) {
406*5113495bSYour Name 		son_err("invalid rx ops");
407*5113495bSYour Name 		return;
408*5113495bSYour Name 	}
409*5113495bSYour Name 	peer = wlan_objmgr_get_peer_by_mac(psoc, macaddr,
410*5113495bSYour Name 					   WLAN_SON_ID);
411*5113495bSYour Name 	if (!peer) {
412*5113495bSYour Name 		son_err("peer is null");
413*5113495bSYour Name 		return;
414*5113495bSYour Name 	}
415*5113495bSYour Name 
416*5113495bSYour Name 	if (is_reassoc)
417*5113495bSYour Name 		sub_type = IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
418*5113495bSYour Name 	if (QDF_IS_STATUS_SUCCESS(status))
419*5113495bSYour Name 		assocstatus = STATUS_SUCCESS;
420*5113495bSYour Name 	son_debug("subtype %u frame_len %u assocstatus %u",
421*5113495bSYour Name 		  sub_type, frame_len, assocstatus);
422*5113495bSYour Name 	rx_ops->son_rx_ops.process_mgmt_frame(vdev, peer, sub_type,
423*5113495bSYour Name 					      frame, frame_len,
424*5113495bSYour Name 					      &assocstatus);
425*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
426*5113495bSYour Name }
427*5113495bSYour Name 
wlan_son_deliver_mlme_event(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,uint32_t event,void * event_data)428*5113495bSYour Name static int wlan_son_deliver_mlme_event(struct wlan_objmgr_vdev *vdev,
429*5113495bSYour Name 				       struct wlan_objmgr_peer *peer,
430*5113495bSYour Name 				       uint32_t event,
431*5113495bSYour Name 				       void *event_data)
432*5113495bSYour Name {
433*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
434*5113495bSYour Name 	struct wlan_lmac_if_rx_ops *rx_ops;
435*5113495bSYour Name 	int ret;
436*5113495bSYour Name 
437*5113495bSYour Name 	if (!vdev)
438*5113495bSYour Name 		return -EINVAL;
439*5113495bSYour Name 
440*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
441*5113495bSYour Name 	if (!psoc)
442*5113495bSYour Name 		return -EINVAL;
443*5113495bSYour Name 
444*5113495bSYour Name 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
445*5113495bSYour Name 	if (rx_ops && rx_ops->son_rx_ops.deliver_event) {
446*5113495bSYour Name 		son_debug("deliver mlme event %d", event);
447*5113495bSYour Name 		ret = rx_ops->son_rx_ops.deliver_event(vdev,
448*5113495bSYour Name 						       peer,
449*5113495bSYour Name 						       event,
450*5113495bSYour Name 						       event_data);
451*5113495bSYour Name 	} else {
452*5113495bSYour Name 		return -EINVAL;
453*5113495bSYour Name 	}
454*5113495bSYour Name 
455*5113495bSYour Name 	return ret;
456*5113495bSYour Name }
457*5113495bSYour Name 
wlan_son_deliver_tx_power(struct wlan_objmgr_vdev * vdev,int32_t max_pwr)458*5113495bSYour Name int wlan_son_deliver_tx_power(struct wlan_objmgr_vdev *vdev,
459*5113495bSYour Name 			      int32_t max_pwr)
460*5113495bSYour Name {
461*5113495bSYour Name 	int ret;
462*5113495bSYour Name 
463*5113495bSYour Name 	son_debug("tx power %d", max_pwr);
464*5113495bSYour Name 	ret = wlan_son_deliver_mlme_event(vdev,
465*5113495bSYour Name 					  NULL,
466*5113495bSYour Name 					  MLME_EVENT_TX_PWR_CHANGE,
467*5113495bSYour Name 					  &max_pwr);
468*5113495bSYour Name 
469*5113495bSYour Name 	return ret;
470*5113495bSYour Name }
471*5113495bSYour Name 
wlan_son_deliver_vdev_stop(struct wlan_objmgr_vdev * vdev)472*5113495bSYour Name int wlan_son_deliver_vdev_stop(struct wlan_objmgr_vdev *vdev)
473*5113495bSYour Name {
474*5113495bSYour Name 	int ret;
475*5113495bSYour Name 
476*5113495bSYour Name 	struct wlan_vdev_state_event event;
477*5113495bSYour Name 
478*5113495bSYour Name 	event.state = VDEV_STATE_STOPPED;
479*5113495bSYour Name 	son_debug("state %d", event.state);
480*5113495bSYour Name 	ret = wlan_son_deliver_mlme_event(vdev,
481*5113495bSYour Name 					  NULL,
482*5113495bSYour Name 					  MLME_EVENT_VDEV_STATE,
483*5113495bSYour Name 					  &event);
484*5113495bSYour Name 
485*5113495bSYour Name 	return ret;
486*5113495bSYour Name }
487*5113495bSYour Name 
wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,uint32_t irssi)488*5113495bSYour Name int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev,
489*5113495bSYour Name 			       struct wlan_objmgr_peer *peer,
490*5113495bSYour Name 			       uint32_t irssi)
491*5113495bSYour Name {
492*5113495bSYour Name 	struct wlan_peer_inst_rssi event;
493*5113495bSYour Name 	int ret;
494*5113495bSYour Name 
495*5113495bSYour Name 	if (irssi > 0 && irssi <= 127) {
496*5113495bSYour Name 		event.iRSSI = irssi;
497*5113495bSYour Name 		event.valid = true;
498*5113495bSYour Name 		son_debug("irssi %d", event.iRSSI);
499*5113495bSYour Name 	} else {
500*5113495bSYour Name 		event.valid = false;
501*5113495bSYour Name 		son_debug("irssi invalid");
502*5113495bSYour Name 	}
503*5113495bSYour Name 
504*5113495bSYour Name 	ret = wlan_son_deliver_mlme_event(vdev,
505*5113495bSYour Name 					  peer,
506*5113495bSYour Name 					  MLME_EVENT_INST_RSSI,
507*5113495bSYour Name 					  &event);
508*5113495bSYour Name 
509*5113495bSYour Name 	return ret;
510*5113495bSYour Name }
511*5113495bSYour Name 
wlan_son_deliver_opmode(struct wlan_objmgr_vdev * vdev,uint8_t bw,uint8_t nss,uint8_t * addr)512*5113495bSYour Name int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev,
513*5113495bSYour Name 			    uint8_t bw,
514*5113495bSYour Name 			    uint8_t nss,
515*5113495bSYour Name 			    uint8_t *addr)
516*5113495bSYour Name {
517*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
518*5113495bSYour Name 	struct ieee80211_opmode_update_data opmode;
519*5113495bSYour Name 
520*5113495bSYour Name 	if (!vdev)
521*5113495bSYour Name 		return -EINVAL;
522*5113495bSYour Name 
523*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
524*5113495bSYour Name 	if (!psoc)
525*5113495bSYour Name 		return -EINVAL;
526*5113495bSYour Name 
527*5113495bSYour Name 	opmode.max_chwidth = bw;
528*5113495bSYour Name 	opmode.num_streams = nss;
529*5113495bSYour Name 	qdf_mem_copy(opmode.macaddr, addr, QDF_MAC_ADDR_SIZE);
530*5113495bSYour Name 
531*5113495bSYour Name 	son_debug("bw %d, nss %d, addr " QDF_MAC_ADDR_FMT,
532*5113495bSYour Name 		  bw, nss, QDF_MAC_ADDR_REF(addr));
533*5113495bSYour Name 
534*5113495bSYour Name 	if (!g_son_mlme_deliver_cbs.deliver_opmode) {
535*5113495bSYour Name 		son_err("invalid deliver opmode cb");
536*5113495bSYour Name 		return -EINVAL;
537*5113495bSYour Name 	}
538*5113495bSYour Name 
539*5113495bSYour Name 	g_son_mlme_deliver_cbs.deliver_opmode(vdev,
540*5113495bSYour Name 					      sizeof(opmode),
541*5113495bSYour Name 					      (uint8_t *)&opmode);
542*5113495bSYour Name 
543*5113495bSYour Name 	return 0;
544*5113495bSYour Name }
545*5113495bSYour Name 
wlan_son_deliver_smps(struct wlan_objmgr_vdev * vdev,uint8_t is_static,uint8_t * addr)546*5113495bSYour Name int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev,
547*5113495bSYour Name 			  uint8_t is_static,
548*5113495bSYour Name 			  uint8_t *addr)
549*5113495bSYour Name {
550*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
551*5113495bSYour Name 	struct ieee80211_smps_update_data smps;
552*5113495bSYour Name 
553*5113495bSYour Name 	if (!vdev)
554*5113495bSYour Name 		return -EINVAL;
555*5113495bSYour Name 
556*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
557*5113495bSYour Name 	if (!psoc)
558*5113495bSYour Name 		return -EINVAL;
559*5113495bSYour Name 
560*5113495bSYour Name 	smps.is_static = is_static;
561*5113495bSYour Name 	qdf_mem_copy(smps.macaddr, addr, QDF_MAC_ADDR_SIZE);
562*5113495bSYour Name 
563*5113495bSYour Name 	son_debug("is_static %d, addr" QDF_MAC_ADDR_FMT,
564*5113495bSYour Name 		  is_static, QDF_MAC_ADDR_REF(addr));
565*5113495bSYour Name 
566*5113495bSYour Name 	if (!g_son_mlme_deliver_cbs.deliver_smps) {
567*5113495bSYour Name 		son_err("invalid deliver smps cb");
568*5113495bSYour Name 		return -EINVAL;
569*5113495bSYour Name 	}
570*5113495bSYour Name 
571*5113495bSYour Name 	g_son_mlme_deliver_cbs.deliver_smps(vdev,
572*5113495bSYour Name 					    sizeof(smps),
573*5113495bSYour Name 					    (uint8_t *)&smps);
574*5113495bSYour Name 
575*5113495bSYour Name 	return 0;
576*5113495bSYour Name }
577*5113495bSYour Name 
wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev * vdev,uint8_t * mac_addr,uint8_t * frm,uint32_t flen)578*5113495bSYour Name int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev,
579*5113495bSYour Name 			     uint8_t *mac_addr,
580*5113495bSYour Name 			     uint8_t *frm,
581*5113495bSYour Name 			     uint32_t flen)
582*5113495bSYour Name {
583*5113495bSYour Name 	struct wlan_act_frm_info rrm_info;
584*5113495bSYour Name 	struct wlan_lmac_if_rx_ops *rx_ops;
585*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
586*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
587*5113495bSYour Name 	uint8_t sub_type = IEEE80211_FC0_SUBTYPE_ACTION;
588*5113495bSYour Name 	struct ieee80211_action ia;
589*5113495bSYour Name 	const uint8_t *ie, *pos, *end;
590*5113495bSYour Name 	uint8_t total_bcnrpt_count = 0;
591*5113495bSYour Name 
592*5113495bSYour Name 	if (!vdev) {
593*5113495bSYour Name 		son_err("invalid vdev");
594*5113495bSYour Name 		return -EINVAL;
595*5113495bSYour Name 	}
596*5113495bSYour Name 
597*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
598*5113495bSYour Name 	if (!psoc) {
599*5113495bSYour Name 		son_err("invalid psoc");
600*5113495bSYour Name 		return -EINVAL;
601*5113495bSYour Name 	}
602*5113495bSYour Name 
603*5113495bSYour Name 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
604*5113495bSYour Name 	if (!rx_ops || !rx_ops->son_rx_ops.process_mgmt_frame) {
605*5113495bSYour Name 		son_err("invalid rx ops");
606*5113495bSYour Name 		return -EINVAL;
607*5113495bSYour Name 	}
608*5113495bSYour Name 
609*5113495bSYour Name 	peer = wlan_objmgr_get_peer_by_mac(psoc, mac_addr, WLAN_SON_ID);
610*5113495bSYour Name 	if (!peer) {
611*5113495bSYour Name 		son_err("peer is null");
612*5113495bSYour Name 		return -EINVAL;
613*5113495bSYour Name 	}
614*5113495bSYour Name 
615*5113495bSYour Name 	ia.ia_category = ACTION_CATEGORY_RRM;
616*5113495bSYour Name 	ia.ia_action = RRM_RADIO_MEASURE_RPT;
617*5113495bSYour Name 	qdf_mem_zero(&rrm_info, sizeof(rrm_info));
618*5113495bSYour Name 	rrm_info.ia = &ia;
619*5113495bSYour Name 	rrm_info.ald_info = 0;
620*5113495bSYour Name 	qdf_mem_copy(rrm_info.data.rrm_data.macaddr,
621*5113495bSYour Name 		     mac_addr,
622*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
623*5113495bSYour Name 	/* IEEE80211_ACTION_RM_TOKEN */
624*5113495bSYour Name 	rrm_info.data.rrm_data.dialog_token = *frm;
625*5113495bSYour Name 
626*5113495bSYour Name 	/* Points to Measurement Report Element */
627*5113495bSYour Name 	++frm;
628*5113495bSYour Name 	--flen;
629*5113495bSYour Name 	pos = frm;
630*5113495bSYour Name 	end = pos + flen;
631*5113495bSYour Name 
632*5113495bSYour Name 	while ((ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_MEASREP,
633*5113495bSYour Name 					      pos, end - pos))) {
634*5113495bSYour Name 		if (ie[1] < 3) {
635*5113495bSYour Name 			son_err("Bad Measurement Report element");
636*5113495bSYour Name 			wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
637*5113495bSYour Name 			return -EINVAL;
638*5113495bSYour Name 		}
639*5113495bSYour Name 		if (ie[4] == SIR_MAC_RRM_BEACON_TYPE)
640*5113495bSYour Name 			++total_bcnrpt_count;
641*5113495bSYour Name 		pos = ie + ie[1] + 2;
642*5113495bSYour Name 	}
643*5113495bSYour Name 
644*5113495bSYour Name 	rrm_info.data.rrm_data.num_meas_rpts = total_bcnrpt_count;
645*5113495bSYour Name 
646*5113495bSYour Name 	son_debug("Sta: " QDF_MAC_ADDR_FMT
647*5113495bSYour Name 		  "Category %d Action %d Num_Report %d Rptlen %d",
648*5113495bSYour Name 		  QDF_MAC_ADDR_REF(mac_addr),
649*5113495bSYour Name 		  ACTION_CATEGORY_RRM,
650*5113495bSYour Name 		  RRM_RADIO_MEASURE_RPT,
651*5113495bSYour Name 		  total_bcnrpt_count,
652*5113495bSYour Name 		  flen);
653*5113495bSYour Name 
654*5113495bSYour Name 	rx_ops->son_rx_ops.process_mgmt_frame(vdev, peer, sub_type,
655*5113495bSYour Name 					      frm, flen, &rrm_info);
656*5113495bSYour Name 
657*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
658*5113495bSYour Name 
659*5113495bSYour Name 	return 0;
660*5113495bSYour Name }
661*5113495bSYour Name 
wlan_son_anqp_frame(struct wlan_objmgr_vdev * vdev,int subtype,uint8_t * frame,uint16_t frame_len,void * action_hdr,uint8_t * macaddr)662*5113495bSYour Name int wlan_son_anqp_frame(struct wlan_objmgr_vdev *vdev, int subtype,
663*5113495bSYour Name 			uint8_t *frame, uint16_t frame_len, void *action_hdr,
664*5113495bSYour Name 			uint8_t *macaddr)
665*5113495bSYour Name {
666*5113495bSYour Name 	struct son_act_frm_info info;
667*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
668*5113495bSYour Name 	struct wlan_lmac_if_rx_ops *rx_ops;
669*5113495bSYour Name 	int ret;
670*5113495bSYour Name 
671*5113495bSYour Name 	if (!vdev)
672*5113495bSYour Name 		return -EINVAL;
673*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
674*5113495bSYour Name 	if (!psoc)
675*5113495bSYour Name 		return -EINVAL;
676*5113495bSYour Name 
677*5113495bSYour Name 	qdf_mem_zero(&info, sizeof(info));
678*5113495bSYour Name 	info.ia = (struct ieee80211_action *)action_hdr;
679*5113495bSYour Name 	info.ald_info = 1;
680*5113495bSYour Name 	qdf_mem_copy(info.data.macaddr, macaddr, sizeof(tSirMacAddr));
681*5113495bSYour Name 
682*5113495bSYour Name 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
683*5113495bSYour Name 	if (rx_ops && rx_ops->son_rx_ops.process_mgmt_frame)
684*5113495bSYour Name 		ret = rx_ops->son_rx_ops.process_mgmt_frame(vdev, NULL,
685*5113495bSYour Name 							    subtype, frame,
686*5113495bSYour Name 							    frame_len, &info);
687*5113495bSYour Name 	else
688*5113495bSYour Name 		return -EINVAL;
689*5113495bSYour Name 	return ret;
690*5113495bSYour Name }
691*5113495bSYour Name 
wlan_son_deliver_cbs(struct wlan_objmgr_vdev * vdev,wlan_cbs_event_type type)692*5113495bSYour Name static int wlan_son_deliver_cbs(struct wlan_objmgr_vdev *vdev,
693*5113495bSYour Name 				wlan_cbs_event_type type)
694*5113495bSYour Name {
695*5113495bSYour Name 	int ret;
696*5113495bSYour Name 
697*5113495bSYour Name 	ret = wlan_son_deliver_mlme_event(vdev,
698*5113495bSYour Name 					  NULL,
699*5113495bSYour Name 					  MLME_EVENT_CBS_STATUS,
700*5113495bSYour Name 					  &type);
701*5113495bSYour Name 
702*5113495bSYour Name 	return ret;
703*5113495bSYour Name }
704*5113495bSYour Name 
wlan_son_deliver_cbs_completed(struct wlan_objmgr_vdev * vdev)705*5113495bSYour Name static int wlan_son_deliver_cbs_completed(struct wlan_objmgr_vdev *vdev)
706*5113495bSYour Name {
707*5113495bSYour Name 	return wlan_son_deliver_cbs(vdev, CBS_COMPLETE);
708*5113495bSYour Name }
709*5113495bSYour Name 
wlan_son_deliver_cbs_cancelled(struct wlan_objmgr_vdev * vdev)710*5113495bSYour Name static int wlan_son_deliver_cbs_cancelled(struct wlan_objmgr_vdev *vdev)
711*5113495bSYour Name {
712*5113495bSYour Name 	return wlan_son_deliver_cbs(vdev, CBS_CANCELLED);
713*5113495bSYour Name }
714*5113495bSYour Name 
715*5113495bSYour Name static void
wlan_son_cbs_set_state(struct son_cbs * cbs,enum son_cbs_state state)716*5113495bSYour Name wlan_son_cbs_set_state(struct son_cbs *cbs, enum son_cbs_state state)
717*5113495bSYour Name {
718*5113495bSYour Name 	son_debug("Change State CBS OLD[%d] --> NEW[%d]",
719*5113495bSYour Name 		  cbs->cbs_state, state);
720*5113495bSYour Name 	cbs->cbs_state = state;
721*5113495bSYour Name }
722*5113495bSYour Name 
723*5113495bSYour Name static enum
wlan_son_cbs_get_state(struct son_cbs * cbs)724*5113495bSYour Name son_cbs_state wlan_son_cbs_get_state(struct son_cbs *cbs)
725*5113495bSYour Name {
726*5113495bSYour Name 	return cbs->cbs_state;
727*5113495bSYour Name }
728*5113495bSYour Name 
729*5113495bSYour Name static void
wlan_son_cbs_init_dwell_params(struct son_cbs * cbs,int dwell_split_time,int dwell_rest_time)730*5113495bSYour Name wlan_son_cbs_init_dwell_params(struct son_cbs *cbs,
731*5113495bSYour Name 			       int dwell_split_time,
732*5113495bSYour Name 			       int dwell_rest_time)
733*5113495bSYour Name {
734*5113495bSYour Name 	int i;
735*5113495bSYour Name 
736*5113495bSYour Name 	if (!cbs || !cbs->vdev)
737*5113495bSYour Name 		return;
738*5113495bSYour Name 	son_debug("dwell_split_time %d, dwell_rest_time %d",
739*5113495bSYour Name 		  dwell_split_time, dwell_rest_time);
740*5113495bSYour Name 	son_debug("vdev_id: %d\n", wlan_vdev_get_id(cbs->vdev));
741*5113495bSYour Name 
742*5113495bSYour Name 	switch (dwell_split_time) {
743*5113495bSYour Name 	case CBS_DWELL_TIME_10MS:
744*5113495bSYour Name 		cbs->max_arr_size_used = 10;
745*5113495bSYour Name 		cbs->dwell_split_cnt = cbs->max_arr_size_used - 1;
746*5113495bSYour Name 		cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1;
747*5113495bSYour Name 		for (i = 0; i < cbs->max_arr_size_used; i++)
748*5113495bSYour Name 			cbs->scan_dwell_rest[i] = dwell_rest_time;
749*5113495bSYour Name 		for (i = 0; i < cbs->max_arr_size_used; i++)
750*5113495bSYour Name 			cbs->scan_offset[i] = i * dwell_split_time;
751*5113495bSYour Name 		break;
752*5113495bSYour Name 	case CBS_DWELL_TIME_25MS:
753*5113495bSYour Name 		cbs->max_arr_size_used = 8;
754*5113495bSYour Name 		cbs->dwell_split_cnt = cbs->max_arr_size_used - 1;
755*5113495bSYour Name 		cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1;
756*5113495bSYour Name 		if (dwell_rest_time % TOTAL_DWELL_TIME == 0) {
757*5113495bSYour Name 			cbs->scan_dwell_rest[0] = dwell_rest_time;
758*5113495bSYour Name 			cbs->scan_dwell_rest[1] = dwell_rest_time;
759*5113495bSYour Name 			cbs->scan_dwell_rest[2] = dwell_rest_time;
760*5113495bSYour Name 			cbs->scan_dwell_rest[3] = dwell_rest_time;
761*5113495bSYour Name 			cbs->scan_dwell_rest[4] = dwell_rest_time +
762*5113495bSYour Name 							TOTAL_DWELL_TIME -
763*5113495bSYour Name 							DEFAULT_BEACON_INTERVAL;
764*5113495bSYour Name 			cbs->scan_dwell_rest[5] = dwell_rest_time +
765*5113495bSYour Name 							TOTAL_DWELL_TIME -
766*5113495bSYour Name 							DEFAULT_BEACON_INTERVAL;
767*5113495bSYour Name 			cbs->scan_dwell_rest[6] = dwell_rest_time;
768*5113495bSYour Name 			cbs->scan_dwell_rest[7] = dwell_rest_time;
769*5113495bSYour Name 			cbs->scan_dwell_rest[8] = 0;
770*5113495bSYour Name 			cbs->scan_dwell_rest[9] = 0;
771*5113495bSYour Name 			cbs->scan_offset[0] = 0;
772*5113495bSYour Name 			cbs->scan_offset[1] = 0;
773*5113495bSYour Name 			cbs->scan_offset[2] = dwell_split_time;
774*5113495bSYour Name 			cbs->scan_offset[3] = dwell_split_time;
775*5113495bSYour Name 			cbs->scan_offset[4] = 2 * dwell_split_time;
776*5113495bSYour Name 			cbs->scan_offset[5] = 2 * dwell_split_time;
777*5113495bSYour Name 			cbs->scan_offset[6] = 3 * dwell_split_time;
778*5113495bSYour Name 			cbs->scan_offset[7] = 3 * dwell_split_time;
779*5113495bSYour Name 			cbs->scan_offset[8] = 0;
780*5113495bSYour Name 			cbs->scan_offset[9] = 0;
781*5113495bSYour Name 		} else {
782*5113495bSYour Name 			for (i = 0; i < cbs->max_arr_size_used - 1; i++)
783*5113495bSYour Name 				cbs->scan_dwell_rest[i] = dwell_rest_time;
784*5113495bSYour Name 
785*5113495bSYour Name 			cbs->scan_dwell_rest[8] = 0;
786*5113495bSYour Name 			cbs->scan_dwell_rest[9] = 0;
787*5113495bSYour Name 			cbs->scan_offset[0] = 0;
788*5113495bSYour Name 			cbs->scan_offset[1] = dwell_split_time;
789*5113495bSYour Name 			cbs->scan_offset[2] = 2 * dwell_split_time;
790*5113495bSYour Name 			cbs->scan_offset[3] = 3 * dwell_split_time;
791*5113495bSYour Name 			cbs->scan_offset[4] = 0;
792*5113495bSYour Name 			cbs->scan_offset[5] = dwell_split_time;
793*5113495bSYour Name 			cbs->scan_offset[6] = 2 * dwell_split_time;
794*5113495bSYour Name 			cbs->scan_offset[7] = 3 * dwell_split_time;
795*5113495bSYour Name 			cbs->scan_offset[8] = 0;
796*5113495bSYour Name 			cbs->scan_offset[9] = 0;
797*5113495bSYour Name 		}
798*5113495bSYour Name 		break;
799*5113495bSYour Name 	case CBS_DWELL_TIME_50MS:
800*5113495bSYour Name 		cbs->max_arr_size_used = 4;
801*5113495bSYour Name 		cbs->dwell_split_cnt = cbs->max_arr_size_used - 1;
802*5113495bSYour Name 		cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1;
803*5113495bSYour Name 		if (dwell_rest_time % TOTAL_DWELL_TIME == 0) {
804*5113495bSYour Name 			cbs->scan_dwell_rest[0] = dwell_rest_time;
805*5113495bSYour Name 			cbs->scan_dwell_rest[1] = dwell_rest_time;
806*5113495bSYour Name 			cbs->scan_dwell_rest[2] = dwell_rest_time +
807*5113495bSYour Name 							TOTAL_DWELL_TIME -
808*5113495bSYour Name 							DEFAULT_BEACON_INTERVAL;
809*5113495bSYour Name 			cbs->scan_dwell_rest[3] = dwell_rest_time +
810*5113495bSYour Name 							TOTAL_DWELL_TIME -
811*5113495bSYour Name 							DEFAULT_BEACON_INTERVAL;
812*5113495bSYour Name 			cbs->scan_dwell_rest[4] = 0;
813*5113495bSYour Name 			cbs->scan_dwell_rest[5] = 0;
814*5113495bSYour Name 			cbs->scan_dwell_rest[6] = 0;
815*5113495bSYour Name 			cbs->scan_dwell_rest[7] = 0;
816*5113495bSYour Name 			cbs->scan_dwell_rest[8] = 0;
817*5113495bSYour Name 			cbs->scan_dwell_rest[9] = 0;
818*5113495bSYour Name 			cbs->scan_offset[0] = 0;
819*5113495bSYour Name 			cbs->scan_offset[1] = 0;
820*5113495bSYour Name 			cbs->scan_offset[2] = dwell_split_time;
821*5113495bSYour Name 			cbs->scan_offset[3] = dwell_split_time;
822*5113495bSYour Name 			cbs->scan_offset[4] = 0;
823*5113495bSYour Name 			cbs->scan_offset[5] = 0;
824*5113495bSYour Name 			cbs->scan_offset[6] = 0;
825*5113495bSYour Name 			cbs->scan_offset[7] = 0;
826*5113495bSYour Name 			cbs->scan_offset[8] = 0;
827*5113495bSYour Name 			cbs->scan_offset[9] = 0;
828*5113495bSYour Name 		} else {
829*5113495bSYour Name 			cbs->scan_dwell_rest[0] = dwell_rest_time;
830*5113495bSYour Name 			cbs->scan_dwell_rest[1] = dwell_rest_time;
831*5113495bSYour Name 			cbs->scan_dwell_rest[2] = dwell_rest_time;
832*5113495bSYour Name 			cbs->scan_dwell_rest[3] = dwell_rest_time;
833*5113495bSYour Name 			cbs->scan_dwell_rest[4] = 0;
834*5113495bSYour Name 			cbs->scan_dwell_rest[5] = 0;
835*5113495bSYour Name 			cbs->scan_dwell_rest[6] = 0;
836*5113495bSYour Name 			cbs->scan_dwell_rest[7] = 0;
837*5113495bSYour Name 			cbs->scan_dwell_rest[8] = 0;
838*5113495bSYour Name 			cbs->scan_dwell_rest[9] = 0;
839*5113495bSYour Name 			cbs->scan_offset[0] = 0;
840*5113495bSYour Name 			cbs->scan_offset[1] = dwell_split_time;
841*5113495bSYour Name 			cbs->scan_offset[2] = 0;
842*5113495bSYour Name 			cbs->scan_offset[3] = dwell_split_time;
843*5113495bSYour Name 			cbs->scan_offset[4] = 0;
844*5113495bSYour Name 			cbs->scan_offset[5] = 0;
845*5113495bSYour Name 			cbs->scan_offset[6] = 0;
846*5113495bSYour Name 			cbs->scan_offset[7] = 0;
847*5113495bSYour Name 			cbs->scan_offset[8] = 0;
848*5113495bSYour Name 			cbs->scan_offset[9] = 0;
849*5113495bSYour Name 		}
850*5113495bSYour Name 		break;
851*5113495bSYour Name 	case CBS_DWELL_TIME_75MS:
852*5113495bSYour Name 		cbs->max_arr_size_used = 4;
853*5113495bSYour Name 		cbs->dwell_split_cnt = cbs->max_arr_size_used - 1;
854*5113495bSYour Name 		cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1;
855*5113495bSYour Name 		if (dwell_rest_time % TOTAL_DWELL_TIME == 0) {
856*5113495bSYour Name 			cbs->scan_dwell_rest[0] = dwell_rest_time;
857*5113495bSYour Name 			cbs->scan_dwell_rest[1] = dwell_rest_time;
858*5113495bSYour Name 			cbs->scan_dwell_rest[2] = dwell_rest_time +
859*5113495bSYour Name 							TOTAL_DWELL_TIME -
860*5113495bSYour Name 							DEFAULT_BEACON_INTERVAL;
861*5113495bSYour Name 			cbs->scan_dwell_rest[3] = dwell_rest_time +
862*5113495bSYour Name 							TOTAL_DWELL_TIME -
863*5113495bSYour Name 							DEFAULT_BEACON_INTERVAL;
864*5113495bSYour Name 			cbs->scan_dwell_rest[4] = 0;
865*5113495bSYour Name 			cbs->scan_dwell_rest[5] = 0;
866*5113495bSYour Name 			cbs->scan_dwell_rest[6] = 0;
867*5113495bSYour Name 			cbs->scan_dwell_rest[7] = 0;
868*5113495bSYour Name 			cbs->scan_dwell_rest[8] = 0;
869*5113495bSYour Name 			cbs->scan_dwell_rest[9] = 0;
870*5113495bSYour Name 			cbs->scan_offset[0] = 0;
871*5113495bSYour Name 			cbs->scan_offset[1] = 0;
872*5113495bSYour Name 			cbs->scan_offset[2] = DEFAULT_BEACON_INTERVAL -
873*5113495bSYour Name 							dwell_split_time;
874*5113495bSYour Name 			cbs->scan_offset[3] = DEFAULT_BEACON_INTERVAL -
875*5113495bSYour Name 							dwell_split_time;
876*5113495bSYour Name 			cbs->scan_offset[4] = 0;
877*5113495bSYour Name 			cbs->scan_offset[5] = 0;
878*5113495bSYour Name 			cbs->scan_offset[6] = 0;
879*5113495bSYour Name 			cbs->scan_offset[7] = 0;
880*5113495bSYour Name 			cbs->scan_offset[8] = 0;
881*5113495bSYour Name 			cbs->scan_offset[9] = 0;
882*5113495bSYour Name 		} else {
883*5113495bSYour Name 			cbs->scan_dwell_rest[0] = dwell_rest_time;
884*5113495bSYour Name 			cbs->scan_dwell_rest[1] = dwell_rest_time;
885*5113495bSYour Name 			cbs->scan_dwell_rest[2] = dwell_rest_time;
886*5113495bSYour Name 			cbs->scan_dwell_rest[3] = dwell_rest_time;
887*5113495bSYour Name 			cbs->scan_dwell_rest[4] = 0;
888*5113495bSYour Name 			cbs->scan_dwell_rest[5] = 0;
889*5113495bSYour Name 			cbs->scan_dwell_rest[6] = 0;
890*5113495bSYour Name 			cbs->scan_dwell_rest[7] = 0;
891*5113495bSYour Name 			cbs->scan_dwell_rest[8] = 0;
892*5113495bSYour Name 			cbs->scan_dwell_rest[9] = 0;
893*5113495bSYour Name 			cbs->scan_offset[0] = 0;
894*5113495bSYour Name 			cbs->scan_offset[1] = DEFAULT_BEACON_INTERVAL -
895*5113495bSYour Name 							dwell_split_time;
896*5113495bSYour Name 			cbs->scan_offset[2] = 0;
897*5113495bSYour Name 			cbs->scan_offset[3] = DEFAULT_BEACON_INTERVAL -
898*5113495bSYour Name 							dwell_split_time;
899*5113495bSYour Name 			cbs->scan_offset[4] = 0;
900*5113495bSYour Name 			cbs->scan_offset[5] = 0;
901*5113495bSYour Name 			cbs->scan_offset[6] = 0;
902*5113495bSYour Name 			cbs->scan_offset[7] = 0;
903*5113495bSYour Name 			cbs->scan_offset[8] = 0;
904*5113495bSYour Name 			cbs->scan_offset[9] = 0;
905*5113495bSYour Name 		}
906*5113495bSYour Name 		break;
907*5113495bSYour Name 	default:
908*5113495bSYour Name 		son_err("Dwell time not supported\n");
909*5113495bSYour Name 		break;
910*5113495bSYour Name 	}
911*5113495bSYour Name }
912*5113495bSYour Name 
wlan_son_cbs_start(struct son_cbs * cbs)913*5113495bSYour Name static int wlan_son_cbs_start(struct son_cbs *cbs)
914*5113495bSYour Name {
915*5113495bSYour Name 	struct scan_start_request *req;
916*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
917*5113495bSYour Name 	QDF_STATUS status;
918*5113495bSYour Name 
919*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(cbs->vdev);
920*5113495bSYour Name 	if (!psoc) {
921*5113495bSYour Name 		son_err("invalid psoc");
922*5113495bSYour Name 		return -EINVAL;
923*5113495bSYour Name 	}
924*5113495bSYour Name 
925*5113495bSYour Name 	req = qdf_mem_malloc(sizeof(*req));
926*5113495bSYour Name 	if (!req) {
927*5113495bSYour Name 		son_err("failed to malloc");
928*5113495bSYour Name 		return -ENOMEM;
929*5113495bSYour Name 	}
930*5113495bSYour Name 	qdf_mem_copy(req, &cbs->scan_params, sizeof(*req));
931*5113495bSYour Name 
932*5113495bSYour Name 	cbs->cbs_scan_id = ucfg_scan_get_scan_id(psoc);
933*5113495bSYour Name 	req->scan_req.scan_id = cbs->cbs_scan_id;
934*5113495bSYour Name 	son_debug("vdev_id: %d req->scan_req.scan_id: %u",
935*5113495bSYour Name 		  wlan_vdev_get_id(cbs->vdev), req->scan_req.scan_id);
936*5113495bSYour Name 
937*5113495bSYour Name 	status = ucfg_scan_start(req);
938*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
939*5113495bSYour Name 		son_err("failed to start cbs");
940*5113495bSYour Name 		wlan_son_deliver_cbs_cancelled(cbs->vdev);
941*5113495bSYour Name 		return -EINVAL;
942*5113495bSYour Name 	}
943*5113495bSYour Name 
944*5113495bSYour Name 	son_debug("cbs start");
945*5113495bSYour Name 
946*5113495bSYour Name 	return 0;
947*5113495bSYour Name }
948*5113495bSYour Name 
wlan_son_cbs_stop(struct son_cbs * cbs)949*5113495bSYour Name static int wlan_son_cbs_stop(struct son_cbs *cbs)
950*5113495bSYour Name {
951*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev;
952*5113495bSYour Name 	QDF_STATUS status;
953*5113495bSYour Name 
954*5113495bSYour Name 	pdev = wlan_vdev_get_pdev(cbs->vdev);
955*5113495bSYour Name 	if (!pdev) {
956*5113495bSYour Name 		son_err("invalid pdev");
957*5113495bSYour Name 		return -EINVAL;
958*5113495bSYour Name 	}
959*5113495bSYour Name 	son_debug("vdev_id: %d", wlan_vdev_get_id(cbs->vdev));
960*5113495bSYour Name 
961*5113495bSYour Name 	if (ucfg_scan_get_pdev_status(pdev) != SCAN_NOT_IN_PROGRESS) {
962*5113495bSYour Name 		son_info("cbs_scan_id: %u abort scan", cbs->cbs_scan_id);
963*5113495bSYour Name 		status = wlan_abort_scan(pdev,
964*5113495bSYour Name 					 wlan_objmgr_pdev_get_pdev_id(pdev),
965*5113495bSYour Name 					 cbs->vdev->vdev_objmgr.vdev_id,
966*5113495bSYour Name 					 cbs->cbs_scan_id,
967*5113495bSYour Name 					 true);
968*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
969*5113495bSYour Name 			son_err("failed to abort cbs");
970*5113495bSYour Name 			return -EBUSY;
971*5113495bSYour Name 		}
972*5113495bSYour Name 	}
973*5113495bSYour Name 
974*5113495bSYour Name 	return 0;
975*5113495bSYour Name }
976*5113495bSYour Name 
wlan_cbs_timer_handler(void * arg)977*5113495bSYour Name static void wlan_cbs_timer_handler(void *arg)
978*5113495bSYour Name {
979*5113495bSYour Name 	struct son_cbs *cbs = (struct son_cbs *)arg;
980*5113495bSYour Name 	enum son_cbs_state state;
981*5113495bSYour Name 
982*5113495bSYour Name 	state = wlan_son_cbs_get_state(cbs);
983*5113495bSYour Name 	son_debug("state: %d", state);
984*5113495bSYour Name 	if (state == CBS_REST) {
985*5113495bSYour Name 		son_debug("vdev_id: %d dwell_split_cnt: %d",
986*5113495bSYour Name 			  wlan_vdev_get_id(cbs->vdev),
987*5113495bSYour Name 			  cbs->dwell_split_cnt);
988*5113495bSYour Name 		qdf_spin_lock_bh(&g_cbs_lock);
989*5113495bSYour Name 		wlan_son_cbs_set_state(cbs, CBS_SCAN);
990*5113495bSYour Name 		cbs->dwell_split_cnt--;
991*5113495bSYour Name 		wlan_son_cbs_start(cbs);
992*5113495bSYour Name 		qdf_spin_unlock_bh(&g_cbs_lock);
993*5113495bSYour Name 	} else if (state == CBS_WAIT) {
994*5113495bSYour Name 		wlan_son_cbs_enable(cbs->vdev);
995*5113495bSYour Name 	}
996*5113495bSYour Name }
997*5113495bSYour Name 
wlan_cbs_iterate(struct son_cbs * cbs)998*5113495bSYour Name static int wlan_cbs_iterate(struct son_cbs *cbs)
999*5113495bSYour Name {
1000*5113495bSYour Name 	int offset_array_idx;
1001*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1002*5113495bSYour Name 
1003*5113495bSYour Name 	qdf_spin_lock_bh(&g_cbs_lock);
1004*5113495bSYour Name 	if (!cbs || !cbs->vdev) {
1005*5113495bSYour Name 		qdf_spin_unlock_bh(&g_cbs_lock);
1006*5113495bSYour Name 		return -EINVAL;
1007*5113495bSYour Name 	}
1008*5113495bSYour Name 	son_debug("dwell_split_cnt: %d", cbs->dwell_split_cnt);
1009*5113495bSYour Name 	if (cbs->dwell_split_cnt < 0) {
1010*5113495bSYour Name 		psoc = wlan_vdev_get_psoc(cbs->vdev);
1011*5113495bSYour Name 		if (!psoc) {
1012*5113495bSYour Name 			qdf_spin_unlock_bh(&g_cbs_lock);
1013*5113495bSYour Name 			return -EINVAL;
1014*5113495bSYour Name 		}
1015*5113495bSYour Name 		wlan_son_deliver_cbs_completed(cbs->vdev);
1016*5113495bSYour Name 
1017*5113495bSYour Name 		ucfg_scan_unregister_requester(psoc,
1018*5113495bSYour Name 					       cbs->cbs_scan_requestor);
1019*5113495bSYour Name 		son_debug("Unregister cbs_scan_requestor: %u",
1020*5113495bSYour Name 			  cbs->cbs_scan_requestor);
1021*5113495bSYour Name 
1022*5113495bSYour Name 		if (cbs->wait_time) {
1023*5113495bSYour Name 			wlan_son_cbs_set_state(cbs, CBS_WAIT);
1024*5113495bSYour Name 			qdf_timer_mod(&cbs->cbs_timer,
1025*5113495bSYour Name 				      cbs->wait_time);
1026*5113495bSYour Name 		} else {
1027*5113495bSYour Name 			wlan_son_cbs_set_state(cbs, CBS_INIT);
1028*5113495bSYour Name 		}
1029*5113495bSYour Name 	} else {
1030*5113495bSYour Name 		offset_array_idx = cbs->max_arr_size_used -
1031*5113495bSYour Name 				   cbs->dwell_split_cnt - 1;
1032*5113495bSYour Name 		if (offset_array_idx < MIN_SCAN_OFFSET_ARRAY_SIZE ||
1033*5113495bSYour Name 		    offset_array_idx > MAX_SCAN_OFFSET_ARRAY_SIZE) {
1034*5113495bSYour Name 			qdf_spin_unlock_bh(&g_cbs_lock);
1035*5113495bSYour Name 			return -EINVAL;
1036*5113495bSYour Name 		}
1037*5113495bSYour Name 		if (cbs->scan_dwell_rest[offset_array_idx] == 0) {
1038*5113495bSYour Name 			cbs->dwell_split_cnt--;
1039*5113495bSYour Name 			wlan_son_cbs_start(cbs);
1040*5113495bSYour Name 		} else {
1041*5113495bSYour Name 			wlan_son_cbs_set_state(cbs, CBS_REST);
1042*5113495bSYour Name 			qdf_timer_mod(&cbs->cbs_timer,
1043*5113495bSYour Name 				      cbs->scan_dwell_rest[offset_array_idx]);
1044*5113495bSYour Name 		}
1045*5113495bSYour Name 	}
1046*5113495bSYour Name 	qdf_spin_unlock_bh(&g_cbs_lock);
1047*5113495bSYour Name 
1048*5113495bSYour Name 	return 0;
1049*5113495bSYour Name }
1050*5113495bSYour Name 
wlan_cbs_scan_event_cb(struct wlan_objmgr_vdev * vdev,struct scan_event * event,void * arg)1051*5113495bSYour Name static void wlan_cbs_scan_event_cb(struct wlan_objmgr_vdev *vdev,
1052*5113495bSYour Name 				   struct scan_event *event,
1053*5113495bSYour Name 				   void *arg)
1054*5113495bSYour Name {
1055*5113495bSYour Name 	son_debug("event type: %d", event->type);
1056*5113495bSYour Name 	switch (event->type) {
1057*5113495bSYour Name 	case SCAN_EVENT_TYPE_FOREIGN_CHANNEL:
1058*5113495bSYour Name 	case SCAN_EVENT_TYPE_FOREIGN_CHANNEL_GET_NF:
1059*5113495bSYour Name 		break;
1060*5113495bSYour Name 	case SCAN_EVENT_TYPE_COMPLETED:
1061*5113495bSYour Name 		wlan_cbs_iterate(arg);
1062*5113495bSYour Name 		break;
1063*5113495bSYour Name 	default:
1064*5113495bSYour Name 		break;
1065*5113495bSYour Name 	}
1066*5113495bSYour Name }
1067*5113495bSYour Name 
wlan_son_cbs_init(void)1068*5113495bSYour Name int wlan_son_cbs_init(void)
1069*5113495bSYour Name {
1070*5113495bSYour Name 	int i, j;
1071*5113495bSYour Name 
1072*5113495bSYour Name 	for (i = 0; i < WLAN_MAX_VDEVS; i++) {
1073*5113495bSYour Name 		if (g_son_cbs[i]) {
1074*5113495bSYour Name 			qdf_mem_free(g_son_cbs[i]);
1075*5113495bSYour Name 			g_son_cbs[i] = NULL;
1076*5113495bSYour Name 		}
1077*5113495bSYour Name 		g_son_cbs[i] = qdf_mem_malloc(sizeof(*g_son_cbs[i]));
1078*5113495bSYour Name 		if (!g_son_cbs[i]) {
1079*5113495bSYour Name 			for (j = i - 1; j >= 0; j--) {
1080*5113495bSYour Name 				qdf_mem_free(g_son_cbs[j]);
1081*5113495bSYour Name 				g_son_cbs[i] = NULL;
1082*5113495bSYour Name 			}
1083*5113495bSYour Name 			return -ENOMEM;
1084*5113495bSYour Name 		}
1085*5113495bSYour Name 		qdf_timer_init(NULL,
1086*5113495bSYour Name 			       &g_son_cbs[i]->cbs_timer,
1087*5113495bSYour Name 			       wlan_cbs_timer_handler,
1088*5113495bSYour Name 			       g_son_cbs[i],
1089*5113495bSYour Name 			       QDF_TIMER_TYPE_WAKE_APPS);
1090*5113495bSYour Name 
1091*5113495bSYour Name 		g_son_cbs[i]->rest_time  = CBS_DEFAULT_RESTTIME;
1092*5113495bSYour Name 		g_son_cbs[i]->dwell_time = CBS_DEFAULT_DWELL_TIME;
1093*5113495bSYour Name 		g_son_cbs[i]->wait_time  = CBS_DEFAULT_WAIT_TIME;
1094*5113495bSYour Name 		g_son_cbs[i]->dwell_split_time = CBS_DEFAULT_DWELL_SPLIT_TIME;
1095*5113495bSYour Name 		g_son_cbs[i]->min_dwell_rest_time = CBS_DEFAULT_DWELL_REST_TIME;
1096*5113495bSYour Name 
1097*5113495bSYour Name 		wlan_son_cbs_set_state(g_son_cbs[i], CBS_INIT);
1098*5113495bSYour Name 	}
1099*5113495bSYour Name 	qdf_spinlock_create(&g_cbs_lock);
1100*5113495bSYour Name 	son_debug("cbs init");
1101*5113495bSYour Name 
1102*5113495bSYour Name 	return 0;
1103*5113495bSYour Name }
1104*5113495bSYour Name 
wlan_son_cbs_deinit(void)1105*5113495bSYour Name int wlan_son_cbs_deinit(void)
1106*5113495bSYour Name {
1107*5113495bSYour Name 	int i;
1108*5113495bSYour Name 
1109*5113495bSYour Name 	qdf_spinlock_destroy(&g_cbs_lock);
1110*5113495bSYour Name 	for (i = 0; i < WLAN_MAX_VDEVS; i++) {
1111*5113495bSYour Name 		if (!g_son_cbs[i])
1112*5113495bSYour Name 			return -EINVAL;
1113*5113495bSYour Name 		if (g_son_cbs[i]->vdev) {
1114*5113495bSYour Name 			wlan_objmgr_vdev_release_ref(g_son_cbs[i]->vdev,
1115*5113495bSYour Name 						     WLAN_SON_ID);
1116*5113495bSYour Name 			son_debug("vdev_id: %d dereferenced",
1117*5113495bSYour Name 				  wlan_vdev_get_id(g_son_cbs[i]->vdev));
1118*5113495bSYour Name 		}
1119*5113495bSYour Name 		qdf_timer_free(&g_son_cbs[i]->cbs_timer);
1120*5113495bSYour Name 		qdf_mem_free(g_son_cbs[i]);
1121*5113495bSYour Name 		g_son_cbs[i] = NULL;
1122*5113495bSYour Name 	}
1123*5113495bSYour Name 
1124*5113495bSYour Name 	son_debug("cbs deinit");
1125*5113495bSYour Name 
1126*5113495bSYour Name 	return 0;
1127*5113495bSYour Name }
1128*5113495bSYour Name 
wlan_son_cbs_enable(struct wlan_objmgr_vdev * vdev)1129*5113495bSYour Name int wlan_son_cbs_enable(struct wlan_objmgr_vdev *vdev)
1130*5113495bSYour Name {
1131*5113495bSYour Name 	struct scan_start_request *req;
1132*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1133*5113495bSYour Name 	enum son_cbs_state state;
1134*5113495bSYour Name 	struct son_cbs *cbs;
1135*5113495bSYour Name 	QDF_STATUS status;
1136*5113495bSYour Name 
1137*5113495bSYour Name 	cbs = g_son_cbs[wlan_vdev_get_id(vdev)];
1138*5113495bSYour Name 	if (!cbs) {
1139*5113495bSYour Name 		son_err("invalid cbs");
1140*5113495bSYour Name 		return -EINVAL;
1141*5113495bSYour Name 	}
1142*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1143*5113495bSYour Name 	if (!psoc) {
1144*5113495bSYour Name 		son_err("invalid psoc");
1145*5113495bSYour Name 		return -EINVAL;
1146*5113495bSYour Name 	}
1147*5113495bSYour Name 
1148*5113495bSYour Name 	state = wlan_son_cbs_get_state(cbs);
1149*5113495bSYour Name 	if (state != CBS_INIT &&
1150*5113495bSYour Name 	    state != CBS_WAIT) {
1151*5113495bSYour Name 		son_err("can't start scan in state %d", state);
1152*5113495bSYour Name 		return -EINVAL;
1153*5113495bSYour Name 	}
1154*5113495bSYour Name 	son_debug("State: %d", state);
1155*5113495bSYour Name 
1156*5113495bSYour Name 	qdf_spin_lock_bh(&g_cbs_lock);
1157*5113495bSYour Name 	if (!cbs->vdev) {
1158*5113495bSYour Name 		cbs->vdev = vdev;
1159*5113495bSYour Name 		status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_SON_ID);
1160*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS) {
1161*5113495bSYour Name 			qdf_spin_unlock_bh(&g_cbs_lock);
1162*5113495bSYour Name 			son_err("Failed to get VDEV reference");
1163*5113495bSYour Name 			return -EAGAIN;
1164*5113495bSYour Name 		}
1165*5113495bSYour Name 		son_debug("vdev_id: %d referenced",
1166*5113495bSYour Name 			  wlan_vdev_get_id(vdev));
1167*5113495bSYour Name 	}
1168*5113495bSYour Name 	cbs->cbs_scan_requestor =
1169*5113495bSYour Name 		ucfg_scan_register_requester(psoc,
1170*5113495bSYour Name 					     (uint8_t *)"cbs",
1171*5113495bSYour Name 					     wlan_cbs_scan_event_cb,
1172*5113495bSYour Name 					     (void *)cbs);
1173*5113495bSYour Name 	son_debug("cbs_scan_requestor: %u vdev_id: %d",
1174*5113495bSYour Name 		  cbs->cbs_scan_requestor, wlan_vdev_get_id(vdev));
1175*5113495bSYour Name 
1176*5113495bSYour Name 	if (!cbs->cbs_scan_requestor) {
1177*5113495bSYour Name 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SON_ID);
1178*5113495bSYour Name 		qdf_spin_unlock_bh(&g_cbs_lock);
1179*5113495bSYour Name 		son_err("ucfg_scan_register_requestor failed");
1180*5113495bSYour Name 		return -EINVAL;
1181*5113495bSYour Name 	}
1182*5113495bSYour Name 
1183*5113495bSYour Name 	req = &cbs->scan_params;
1184*5113495bSYour Name 	ucfg_scan_init_default_params(vdev, req);
1185*5113495bSYour Name 	req->scan_req.scan_req_id = cbs->cbs_scan_requestor;
1186*5113495bSYour Name 
1187*5113495bSYour Name 	req->scan_req.vdev_id = wlan_vdev_get_id(vdev);
1188*5113495bSYour Name 	req->scan_req.scan_priority = SCAN_PRIORITY_HIGH;
1189*5113495bSYour Name 	req->scan_req.scan_f_bcast_probe = true;
1190*5113495bSYour Name 
1191*5113495bSYour Name 	req->scan_req.scan_f_passive = true;
1192*5113495bSYour Name 	req->scan_req.max_rest_time = DEFAULT_SCAN_MAX_REST_TIME;
1193*5113495bSYour Name 	req->scan_req.scan_f_forced = true;
1194*5113495bSYour Name 
1195*5113495bSYour Name 	req->scan_req.scan_flags = 0;
1196*5113495bSYour Name 	req->scan_req.dwell_time_active = cbs->dwell_split_time;
1197*5113495bSYour Name 	req->scan_req.dwell_time_passive = cbs->dwell_split_time + 5;
1198*5113495bSYour Name 	req->scan_req.min_rest_time = CBS_DEFAULT_MIN_REST_TIME;
1199*5113495bSYour Name 	req->scan_req.max_rest_time = CBS_DEFAULT_DWELL_REST_TIME;
1200*5113495bSYour Name 	req->scan_req.scan_f_passive = false;
1201*5113495bSYour Name 	req->scan_req.scan_f_2ghz = true;
1202*5113495bSYour Name 	req->scan_req.scan_f_5ghz = true;
1203*5113495bSYour Name 	req->scan_req.scan_f_offchan_mgmt_tx = true;
1204*5113495bSYour Name 	req->scan_req.scan_f_offchan_data_tx = true;
1205*5113495bSYour Name 	req->scan_req.scan_f_chan_stat_evnt = true;
1206*5113495bSYour Name 
1207*5113495bSYour Name 	if (cbs->min_dwell_rest_time % DEFAULT_BEACON_INTERVAL) {
1208*5113495bSYour Name 		cbs->min_dwell_rest_time =
1209*5113495bSYour Name 			(cbs->min_dwell_rest_time /
1210*5113495bSYour Name 			(2 * DEFAULT_BEACON_INTERVAL)) *
1211*5113495bSYour Name 			(2 * DEFAULT_BEACON_INTERVAL) +
1212*5113495bSYour Name 			(cbs->min_dwell_rest_time % 200 < 100) ? 100 : 200;
1213*5113495bSYour Name 	}
1214*5113495bSYour Name 
1215*5113495bSYour Name 	wlan_son_cbs_init_dwell_params(cbs,
1216*5113495bSYour Name 				       cbs->dwell_split_time,
1217*5113495bSYour Name 				       cbs->min_dwell_rest_time);
1218*5113495bSYour Name 
1219*5113495bSYour Name 	cbs->dwell_split_cnt--;
1220*5113495bSYour Name 	wlan_son_cbs_set_state(cbs, CBS_SCAN);
1221*5113495bSYour Name 
1222*5113495bSYour Name 	wlan_son_cbs_start(cbs);
1223*5113495bSYour Name 	qdf_spin_unlock_bh(&g_cbs_lock);
1224*5113495bSYour Name 
1225*5113495bSYour Name 	son_debug("cbs enable");
1226*5113495bSYour Name 
1227*5113495bSYour Name 	return 0;
1228*5113495bSYour Name }
1229*5113495bSYour Name 
wlan_son_cbs_disable(struct wlan_objmgr_vdev * vdev)1230*5113495bSYour Name int wlan_son_cbs_disable(struct wlan_objmgr_vdev *vdev)
1231*5113495bSYour Name {
1232*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1233*5113495bSYour Name 	struct son_cbs *cbs;
1234*5113495bSYour Name 
1235*5113495bSYour Name 	if (!vdev) {
1236*5113495bSYour Name 		son_err("invalid vdev");
1237*5113495bSYour Name 		return -EINVAL;
1238*5113495bSYour Name 	}
1239*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1240*5113495bSYour Name 	if (!psoc) {
1241*5113495bSYour Name 		son_err("invalid psoc");
1242*5113495bSYour Name 		return -EINVAL;
1243*5113495bSYour Name 	}
1244*5113495bSYour Name 	cbs = g_son_cbs[wlan_vdev_get_id(vdev)];
1245*5113495bSYour Name 	if (!cbs || !cbs->vdev) {
1246*5113495bSYour Name 		son_err("vdev null");
1247*5113495bSYour Name 		return -EINVAL;
1248*5113495bSYour Name 	}
1249*5113495bSYour Name 	wlan_son_deliver_cbs_cancelled(vdev);
1250*5113495bSYour Name 
1251*5113495bSYour Name 	qdf_timer_sync_cancel(&cbs->cbs_timer);
1252*5113495bSYour Name 
1253*5113495bSYour Name 	wlan_son_cbs_stop(cbs);
1254*5113495bSYour Name 
1255*5113495bSYour Name 	son_debug("cbs_scan_requestor: %d vdev_id: %d",
1256*5113495bSYour Name 		  cbs->cbs_scan_requestor, wlan_vdev_get_id(vdev));
1257*5113495bSYour Name 	ucfg_scan_unregister_requester(psoc, cbs->cbs_scan_requestor);
1258*5113495bSYour Name 
1259*5113495bSYour Name 	qdf_spin_lock_bh(&g_cbs_lock);
1260*5113495bSYour Name 	wlan_son_cbs_set_state(cbs, CBS_INIT);
1261*5113495bSYour Name 	if (vdev == cbs->vdev) {
1262*5113495bSYour Name 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SON_ID);
1263*5113495bSYour Name 		son_debug("vdev_id: %d dereferenced",
1264*5113495bSYour Name 			  vdev->vdev_objmgr.vdev_id);
1265*5113495bSYour Name 	}
1266*5113495bSYour Name 	cbs->vdev = NULL;
1267*5113495bSYour Name 	qdf_spin_unlock_bh(&g_cbs_lock);
1268*5113495bSYour Name 
1269*5113495bSYour Name 	son_debug("cbs disable");
1270*5113495bSYour Name 
1271*5113495bSYour Name 	return 0;
1272*5113495bSYour Name }
1273*5113495bSYour Name 
wlan_son_set_cbs(struct wlan_objmgr_vdev * vdev,bool enable)1274*5113495bSYour Name int wlan_son_set_cbs(struct wlan_objmgr_vdev *vdev,
1275*5113495bSYour Name 		     bool enable)
1276*5113495bSYour Name {
1277*5113495bSYour Name 	son_debug("Enable: %u", enable);
1278*5113495bSYour Name 
1279*5113495bSYour Name 	if (!vdev || !g_son_cbs[wlan_vdev_get_id(vdev)])
1280*5113495bSYour Name 		return -EINVAL;
1281*5113495bSYour Name 
1282*5113495bSYour Name 	if (enable)
1283*5113495bSYour Name 		wlan_son_cbs_enable(vdev);
1284*5113495bSYour Name 	else
1285*5113495bSYour Name 		wlan_son_cbs_disable(vdev);
1286*5113495bSYour Name 
1287*5113495bSYour Name 	return 0;
1288*5113495bSYour Name }
1289*5113495bSYour Name 
wlan_son_set_cbs_wait_time(struct wlan_objmgr_vdev * vdev,uint32_t val)1290*5113495bSYour Name int wlan_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev,
1291*5113495bSYour Name 			       uint32_t val)
1292*5113495bSYour Name {
1293*5113495bSYour Name 	if (!g_son_cbs[wlan_vdev_get_id(vdev)])
1294*5113495bSYour Name 		return -EINVAL;
1295*5113495bSYour Name 
1296*5113495bSYour Name 	son_debug("vdev_id: %d wait time %d", wlan_vdev_get_id(vdev), val);
1297*5113495bSYour Name 	wlan_son_set_cbs(vdev, false);
1298*5113495bSYour Name 
1299*5113495bSYour Name 	if (val % DEFAULT_BEACON_INTERVAL != 0) {
1300*5113495bSYour Name 		val = (val / (2 * DEFAULT_BEACON_INTERVAL)) *
1301*5113495bSYour Name 			(2 * DEFAULT_BEACON_INTERVAL) +
1302*5113495bSYour Name 			(val % (2 * DEFAULT_BEACON_INTERVAL) <
1303*5113495bSYour Name 				DEFAULT_BEACON_INTERVAL) ?
1304*5113495bSYour Name 				DEFAULT_BEACON_INTERVAL :
1305*5113495bSYour Name 				2 * DEFAULT_BEACON_INTERVAL;
1306*5113495bSYour Name 	}
1307*5113495bSYour Name 	qdf_spin_lock_bh(&g_cbs_lock);
1308*5113495bSYour Name 	g_son_cbs[wlan_vdev_get_id(vdev)]->wait_time = val;
1309*5113495bSYour Name 	qdf_spin_unlock_bh(&g_cbs_lock);
1310*5113495bSYour Name 
1311*5113495bSYour Name 	wlan_son_set_cbs(vdev, true);
1312*5113495bSYour Name 
1313*5113495bSYour Name 	return 0;
1314*5113495bSYour Name }
1315*5113495bSYour Name 
wlan_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev * vdev,uint32_t val)1316*5113495bSYour Name int wlan_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev,
1317*5113495bSYour Name 				      uint32_t val)
1318*5113495bSYour Name {
1319*5113495bSYour Name 	if (!g_son_cbs[wlan_vdev_get_id(vdev)])
1320*5113495bSYour Name 		return -EINVAL;
1321*5113495bSYour Name 
1322*5113495bSYour Name 	son_debug("vdev_id: %d dwell split time %d",
1323*5113495bSYour Name 		  wlan_vdev_get_id(vdev), val);
1324*5113495bSYour Name 	if (val != CBS_DWELL_TIME_10MS &&
1325*5113495bSYour Name 	    val != CBS_DWELL_TIME_25MS &&
1326*5113495bSYour Name 	    val != CBS_DWELL_TIME_50MS &&
1327*5113495bSYour Name 	    val != CBS_DWELL_TIME_75MS) {
1328*5113495bSYour Name 		son_err("dwell time not supported ");
1329*5113495bSYour Name 		return -EINVAL;
1330*5113495bSYour Name 	}
1331*5113495bSYour Name 
1332*5113495bSYour Name 	wlan_son_set_cbs(vdev, false);
1333*5113495bSYour Name 
1334*5113495bSYour Name 	qdf_spin_lock_bh(&g_cbs_lock);
1335*5113495bSYour Name 	g_son_cbs[wlan_vdev_get_id(vdev)]->dwell_split_time = val;
1336*5113495bSYour Name 	qdf_spin_unlock_bh(&g_cbs_lock);
1337*5113495bSYour Name 
1338*5113495bSYour Name 	wlan_son_set_cbs(vdev, true);
1339*5113495bSYour Name 
1340*5113495bSYour Name 	return 0;
1341*5113495bSYour Name }
1342*5113495bSYour Name 
wlan_son_get_node_tx_power(struct element_info assoc_req_ies)1343*5113495bSYour Name uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies)
1344*5113495bSYour Name {
1345*5113495bSYour Name 	const uint8_t *power_cap_ie_data;
1346*5113495bSYour Name 
1347*5113495bSYour Name 	power_cap_ie_data = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_PWRCAP,
1348*5113495bSYour Name 						     assoc_req_ies.ptr,
1349*5113495bSYour Name 						     assoc_req_ies.len);
1350*5113495bSYour Name 	if (power_cap_ie_data)
1351*5113495bSYour Name 		return *(power_cap_ie_data + 3);
1352*5113495bSYour Name 	else
1353*5113495bSYour Name 		return 0;
1354*5113495bSYour Name }
1355*5113495bSYour Name 
wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies,uint8_t * rrmcaps,bool * is_beacon_meas_supported)1356*5113495bSYour Name QDF_STATUS wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies,
1357*5113495bSYour Name 				      uint8_t *rrmcaps,
1358*5113495bSYour Name 				      bool *is_beacon_meas_supported)
1359*5113495bSYour Name {
1360*5113495bSYour Name 	const uint8_t *eid;
1361*5113495bSYour Name 
1362*5113495bSYour Name 	eid = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RRM,
1363*5113495bSYour Name 				       assoc_req_ies.ptr,
1364*5113495bSYour Name 				       assoc_req_ies.len);
1365*5113495bSYour Name 	if (eid) {
1366*5113495bSYour Name 		qdf_mem_copy(rrmcaps, &eid[2], eid[1]);
1367*5113495bSYour Name 		if ((rrmcaps[0] &
1368*5113495bSYour Name 		    IEEE80211_RRM_CAPS_BEACON_REPORT_PASSIVE) ||
1369*5113495bSYour Name 		    (rrmcaps[0] &
1370*5113495bSYour Name 		    IEEE80211_RRM_CAPS_BEACON_REPORT_ACTIVE))
1371*5113495bSYour Name 			*is_beacon_meas_supported = true;
1372*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
1373*5113495bSYour Name 	}
1374*5113495bSYour Name 	return QDF_STATUS_E_RESOURCES;
1375*5113495bSYour Name }
1376*5113495bSYour Name 
1377*5113495bSYour Name QDF_STATUS
wlan_son_vdev_get_supported_txrx_streams(struct wlan_objmgr_vdev * vdev,uint32_t * num_tx_streams,uint32_t * num_rx_streams)1378*5113495bSYour Name wlan_son_vdev_get_supported_txrx_streams(struct wlan_objmgr_vdev *vdev,
1379*5113495bSYour Name 					 uint32_t *num_tx_streams,
1380*5113495bSYour Name 					 uint32_t *num_rx_streams)
1381*5113495bSYour Name {
1382*5113495bSYour Name 	struct wlan_mlme_nss_chains *nss_cfg;
1383*5113495bSYour Name 	enum nss_chains_band_info band = NSS_CHAINS_BAND_MAX;
1384*5113495bSYour Name 	struct wlan_channel *chan;
1385*5113495bSYour Name 	qdf_freq_t chan_freq = 0;
1386*5113495bSYour Name 
1387*5113495bSYour Name 	nss_cfg = mlme_get_dynamic_vdev_config(vdev);
1388*5113495bSYour Name 	if (!nss_cfg)
1389*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
1390*5113495bSYour Name 
1391*5113495bSYour Name 	chan = wlan_vdev_get_active_channel(vdev);
1392*5113495bSYour Name 	if (chan)
1393*5113495bSYour Name 		chan_freq = chan->ch_freq;
1394*5113495bSYour Name 
1395*5113495bSYour Name 	if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq))
1396*5113495bSYour Name 		band = NSS_CHAINS_BAND_2GHZ;
1397*5113495bSYour Name 
1398*5113495bSYour Name 	if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq))
1399*5113495bSYour Name 		band = NSS_CHAINS_BAND_5GHZ;
1400*5113495bSYour Name 
1401*5113495bSYour Name 	if (band == NSS_CHAINS_BAND_MAX)
1402*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
1403*5113495bSYour Name 
1404*5113495bSYour Name 	*num_tx_streams = nss_cfg->tx_nss[band];
1405*5113495bSYour Name 	*num_rx_streams = nss_cfg->rx_nss[band];
1406*5113495bSYour Name 
1407*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1408*5113495bSYour Name }
1409