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