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