1 /*
2 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 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 manager roam public api
20 */
21 #include "wlan_objmgr_psoc_obj.h"
22 #include "wlan_objmgr_pdev_obj.h"
23 #include "wlan_objmgr_vdev_obj.h"
24 #include "wlan_policy_mgr_api.h"
25 #include "wlan_policy_mgr_i.h"
26 #include "wlan_if_mgr_roam.h"
27 #include "wlan_if_mgr_public_struct.h"
28 #include "wlan_cm_roam_api.h"
29 #include "wlan_if_mgr_main.h"
30 #include "wlan_p2p_ucfg_api.h"
31 #include "cds_api.h"
32 #include "sme_api.h"
33 #include "wlan_vdev_mgr_utils_api.h"
34 #include "wni_api.h"
35 #include "wlan_mlme_vdev_mgr_interface.h"
36 #include "wlan_cm_api.h"
37 #include "wlan_scan_api.h"
38 #include "wlan_mlo_mgr_roam.h"
39 #include "wlan_mlo_mgr_sta.h"
40 #include "wlan_mlo_mgr_link_switch.h"
41 #include <wlan_action_oui_main.h>
42
43
44 #ifdef WLAN_FEATURE_11BE_MLO
45 static inline bool
if_mgr_is_assoc_link_of_vdev(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,uint8_t cur_vdev_id)46 if_mgr_is_assoc_link_of_vdev(struct wlan_objmgr_pdev *pdev,
47 struct wlan_objmgr_vdev *vdev,
48 uint8_t cur_vdev_id)
49 {
50 struct wlan_objmgr_vdev *cur_vdev, *assoc_vdev;
51
52 cur_vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, cur_vdev_id,
53 WLAN_IF_MGR_ID);
54 if (!cur_vdev)
55 return false;
56
57 assoc_vdev = wlan_mlo_get_assoc_link_vdev(cur_vdev);
58
59 wlan_objmgr_vdev_release_ref(cur_vdev, WLAN_IF_MGR_ID);
60 if (vdev == assoc_vdev)
61 return true;
62
63 return false;
64 }
65 #else
66 static inline bool
if_mgr_is_assoc_link_of_vdev(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,uint8_t cur_vdev_id)67 if_mgr_is_assoc_link_of_vdev(struct wlan_objmgr_pdev *pdev,
68 struct wlan_objmgr_vdev *vdev,
69 uint8_t cur_vdev_id)
70 {
71 return false;
72 }
73 #endif
74
if_mgr_enable_roaming_on_vdev(struct wlan_objmgr_pdev * pdev,void * object,void * arg)75 static void if_mgr_enable_roaming_on_vdev(struct wlan_objmgr_pdev *pdev,
76 void *object, void *arg)
77 {
78 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
79 struct change_roam_state_arg *roam_arg = arg;
80 uint8_t vdev_id, curr_vdev_id;
81
82 vdev_id = wlan_vdev_get_id(vdev);
83 curr_vdev_id = roam_arg->curr_vdev_id;
84
85 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
86 return;
87
88 if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) ||
89 if_mgr_is_assoc_link_of_vdev(pdev, vdev, curr_vdev_id))
90 return;
91
92 if (curr_vdev_id != vdev_id &&
93 vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
94 ifmgr_debug("Enable roaming for vdev_id %d", vdev_id);
95 wlan_cm_enable_rso(pdev, vdev_id,
96 roam_arg->requestor,
97 REASON_DRIVER_ENABLED);
98 }
99 }
100
if_mgr_enable_roaming(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,enum wlan_cm_rso_control_requestor requestor)101 QDF_STATUS if_mgr_enable_roaming(struct wlan_objmgr_pdev *pdev,
102 struct wlan_objmgr_vdev *vdev,
103 enum wlan_cm_rso_control_requestor requestor)
104 {
105 QDF_STATUS status = QDF_STATUS_SUCCESS;
106 struct change_roam_state_arg roam_arg;
107 uint8_t vdev_id;
108
109 vdev_id = wlan_vdev_get_id(vdev);
110
111 roam_arg.requestor = requestor;
112 roam_arg.curr_vdev_id = vdev_id;
113
114 status = wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
115 if_mgr_enable_roaming_on_vdev,
116 &roam_arg, 0,
117 WLAN_IF_MGR_ID);
118
119 return status;
120 }
121
if_mgr_disable_roaming_on_vdev(struct wlan_objmgr_pdev * pdev,void * object,void * arg)122 static void if_mgr_disable_roaming_on_vdev(struct wlan_objmgr_pdev *pdev,
123 void *object, void *arg)
124 {
125 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
126 struct change_roam_state_arg *roam_arg = arg;
127 uint8_t vdev_id, curr_vdev_id;
128
129 vdev_id = wlan_vdev_get_id(vdev);
130 curr_vdev_id = roam_arg->curr_vdev_id;
131
132 if (curr_vdev_id == vdev_id ||
133 wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE ||
134 wlan_cm_is_vdev_roam_sync_inprogress(vdev) ||
135 vdev->vdev_mlme.mlme_state != WLAN_VDEV_S_UP)
136 return;
137
138 /*
139 * Disable roaming only for the STA vdev which is not is roam sync state
140 * and VDEV is in UP state.
141 */
142 ifmgr_debug("Roaming disabled on vdev_id %d", vdev_id);
143 wlan_cm_disable_rso(pdev, vdev_id, roam_arg->requestor,
144 REASON_DRIVER_DISABLED);
145 }
146
if_mgr_disable_roaming(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,enum wlan_cm_rso_control_requestor requestor)147 QDF_STATUS if_mgr_disable_roaming(struct wlan_objmgr_pdev *pdev,
148 struct wlan_objmgr_vdev *vdev,
149 enum wlan_cm_rso_control_requestor requestor)
150 {
151 QDF_STATUS status = QDF_STATUS_SUCCESS;
152 struct change_roam_state_arg roam_arg;
153 uint8_t vdev_id;
154
155 vdev_id = wlan_vdev_get_id(vdev);
156
157 roam_arg.requestor = requestor;
158 roam_arg.curr_vdev_id = vdev_id;
159
160 status = wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
161 if_mgr_disable_roaming_on_vdev,
162 &roam_arg, 0,
163 WLAN_IF_MGR_ID);
164
165 return status;
166 }
167
168 QDF_STATUS
if_mgr_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev)169 if_mgr_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev,
170 struct wlan_objmgr_vdev *vdev)
171 {
172 struct wlan_objmgr_psoc *psoc;
173 uint8_t vdev_id = wlan_vdev_get_id(vdev);
174
175 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
176 return QDF_STATUS_E_FAILURE;
177
178 /*
179 * When link switch is in progress, don't send RSO Enable before vdev
180 * is up. RSO Enable will be sent as part of install keys once
181 * link switch connect sequence is complete.
182 */
183 if (mlo_mgr_is_link_switch_in_progress(vdev))
184 return QDF_STATUS_SUCCESS;
185
186 psoc = wlan_vdev_get_psoc(vdev);
187 if (!psoc)
188 return QDF_STATUS_E_FAILURE;
189
190 if (policy_mgr_is_sta_active_connection_exists(psoc) &&
191 mlo_is_enable_roaming_on_connected_sta_allowed(vdev)) {
192 wlan_cm_enable_roaming_on_connected_sta(pdev, vdev_id);
193 policy_mgr_set_pcl_for_connected_vdev(psoc, vdev_id, true);
194 }
195
196 return QDF_STATUS_SUCCESS;
197 }
198
if_mgr_enable_roaming_after_p2p_disconnect(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,enum wlan_cm_rso_control_requestor requestor)199 QDF_STATUS if_mgr_enable_roaming_after_p2p_disconnect(
200 struct wlan_objmgr_pdev *pdev,
201 struct wlan_objmgr_vdev *vdev,
202 enum wlan_cm_rso_control_requestor requestor)
203 {
204 QDF_STATUS status = QDF_STATUS_SUCCESS;
205 struct wlan_objmgr_psoc *psoc;
206 struct change_roam_state_arg roam_arg;
207 uint8_t vdev_id;
208
209 psoc = wlan_vdev_get_psoc(vdev);
210 if (!psoc)
211 return QDF_STATUS_E_FAILURE;
212
213 vdev_id = wlan_vdev_get_id(vdev);
214
215 roam_arg.requestor = requestor;
216 roam_arg.curr_vdev_id = vdev_id;
217
218 /*
219 * Due to audio share glitch with P2P clients due
220 * to roam scan on concurrent interface, disable
221 * roaming if "p2p_disable_roam" ini is enabled.
222 * Re-enable roaming again once the p2p client
223 * gets disconnected.
224 */
225 if (ucfg_p2p_is_roam_config_disabled(psoc) &&
226 wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE) {
227 ifmgr_debug("P2P client disconnected, enable roam");
228 status = wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
229 if_mgr_enable_roaming_on_vdev,
230 &roam_arg, 0,
231 WLAN_IF_MGR_ID);
232 }
233
234 return status;
235 }
236
237 /**
238 * if_mgr_calculate_mcc_beacon_interval() - Calculates the new beacon interval
239 * @sta_bi: station beacon interval
240 * @go_given_bi: P2P GO's given beacon interval
241 *
242 * This function has 3 stages. First it modifies the input go_given_bi to be
243 * within 100 to 199. Then it checks if the sta_bi and go_given_bi are multiples
244 * of each other. If they are, that means the 2 values are compatible, and just
245 * return as is, otherwise, find new compatible BI for P2P GO
246 *
247 * Return: valid beacon interval value
248 */
if_mgr_calculate_mcc_beacon_interval(uint16_t sta_bi,uint16_t go_given_bi)249 static uint16_t if_mgr_calculate_mcc_beacon_interval(uint16_t sta_bi,
250 uint16_t go_given_bi)
251 {
252 uint8_t num_beacons, is_multiple;
253 uint16_t go_calculated_bi, go_final_bi, sta_calculated_bi;
254
255 /* ensure BI ranges between 100 and 200 */
256 if (go_given_bi < 100)
257 go_calculated_bi = 100;
258 else
259 go_calculated_bi = 100 + (go_given_bi % 100);
260
261 if (sta_bi == 0) {
262 /* There is possibility to receive zero as value.
263 * Which will cause divide by zero. Hence initialise with 100
264 */
265 sta_bi = 100;
266 ifmgr_warn("sta_bi 2nd parameter is zero, initialize to %d",
267 sta_bi);
268 }
269 /* check, if either one is multiple of another */
270 if (sta_bi > go_calculated_bi)
271 is_multiple = !(sta_bi % go_calculated_bi);
272 else
273 is_multiple = !(go_calculated_bi % sta_bi);
274
275 /* if it is multiple, then accept GO's beacon interval
276 * range [100,199] as it is
277 */
278 if (is_multiple)
279 return go_calculated_bi;
280
281 /* else , if it is not multiple, then then check for number of beacons
282 * to be inserted based on sta BI
283 */
284 num_beacons = sta_bi / 100;
285 if (num_beacons) {
286 /* GO's final beacon interval will be aligned to sta beacon
287 * interval, but in the range of [100, 199].
288 */
289 sta_calculated_bi = sta_bi / num_beacons;
290 go_final_bi = sta_calculated_bi;
291 } else {
292 /* if STA beacon interval is less than 100, use GO's change
293 * beacon interval instead of updating to STA's beacon interval.
294 */
295 go_final_bi = go_calculated_bi;
296 }
297
298 return go_final_bi;
299 }
300
301 static QDF_STATUS
if_mgr_send_chng_mcc_beacon_interval(struct wlan_objmgr_vdev * vdev,struct beacon_interval_arg * bss_arg)302 if_mgr_send_chng_mcc_beacon_interval(struct wlan_objmgr_vdev *vdev,
303 struct beacon_interval_arg *bss_arg)
304 {
305 struct scheduler_msg msg = {0};
306 struct wlan_change_bi *p_msg;
307 uint16_t len = 0;
308 QDF_STATUS status;
309 uint8_t *mac_addr;
310
311 if (!bss_arg->update_beacon_interval)
312 return QDF_STATUS_SUCCESS;
313
314 bss_arg->update_beacon_interval = false;
315
316 len = sizeof(*p_msg);
317 p_msg = qdf_mem_malloc(len);
318 if (!p_msg)
319 return QDF_STATUS_E_NOMEM;
320
321 p_msg->message_type = eWNI_SME_CHNG_MCC_BEACON_INTERVAL;
322 p_msg->length = len;
323
324 mac_addr = wlan_vdev_get_hw_macaddr(vdev);
325 qdf_mem_copy(&p_msg->bssid, mac_addr, QDF_MAC_ADDR_SIZE);
326 ifmgr_debug(QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac_addr));
327 p_msg->session_id = wlan_vdev_get_id(vdev);
328 ifmgr_debug("session %d BeaconInterval %d", p_msg->session_id,
329 bss_arg->bss_beacon_interval);
330 p_msg->beacon_interval = bss_arg->bss_beacon_interval;
331
332 msg.type = eWNI_SME_CHNG_MCC_BEACON_INTERVAL;
333 msg.bodyval = 0;
334 msg.bodyptr = p_msg;
335
336 status = scheduler_post_message(QDF_MODULE_ID_PE,
337 QDF_MODULE_ID_PE,
338 QDF_MODULE_ID_PE, &msg);
339
340 if (status != QDF_STATUS_SUCCESS)
341 qdf_mem_free(p_msg);
342
343 return status;
344 }
345
if_mgr_update_beacon_interval(struct wlan_objmgr_pdev * pdev,void * object,void * arg)346 static void if_mgr_update_beacon_interval(struct wlan_objmgr_pdev *pdev,
347 void *object, void *arg)
348 {
349 struct wlan_objmgr_psoc *psoc;
350 uint8_t allow_mcc_go_diff_bi;
351 struct wlan_objmgr_peer *peer;
352 enum wlan_peer_type bss_persona;
353 struct beacon_interval_arg *bss_arg = arg;
354 struct wlan_objmgr_vdev *vdev = object;
355 uint8_t vdev_id = wlan_vdev_get_id(vdev);
356
357 psoc = wlan_pdev_get_psoc(pdev);
358 if (!psoc)
359 return;
360
361 policy_mgr_get_allow_mcc_go_diff_bi(psoc, &allow_mcc_go_diff_bi);
362
363 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID);
364 if (!peer)
365 return;
366
367 bss_persona = wlan_peer_get_peer_type(peer);
368
369 wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID);
370
371 /*
372 * If GO in MCC support different beacon interval,
373 * change the BI of the P2P-GO
374 */
375 if (bss_persona == WLAN_PEER_P2P_GO)
376 return;
377 /*
378 * Handle different BI scenario based on the
379 * configuration set. If Config is not set to 0x04 then
380 * Disconnect all the P2P clients associated. If config
381 * is set to 0x04 then update the BI without
382 * disconnecting all the clients
383 */
384 if (allow_mcc_go_diff_bi == ALLOW_MCC_GO_DIFF_BI_NO_DISCONNECT &&
385 bss_arg->update_beacon_interval) {
386 bss_arg->status =
387 if_mgr_send_chng_mcc_beacon_interval(vdev, bss_arg);
388 return;
389 } else if (bss_arg->update_beacon_interval) {
390 /*
391 * If the configuration of fAllowMCCGODiffBI is set to
392 * other than 0x04
393 */
394 bss_arg->status = wlan_sap_disconnect_all_p2p_client(vdev_id);
395 return;
396 }
397 }
398
399 static QDF_STATUS
if_mgr_update_mcc_p2p_beacon_interval(struct wlan_objmgr_vdev * vdev,struct beacon_interval_arg * bss_arg)400 if_mgr_update_mcc_p2p_beacon_interval(struct wlan_objmgr_vdev *vdev,
401 struct beacon_interval_arg *bss_arg)
402 {
403 struct wlan_objmgr_psoc *psoc;
404 struct wlan_objmgr_pdev *pdev;
405 uint8_t enable_mcc_mode;
406
407 pdev = wlan_vdev_get_pdev(vdev);
408 if (!pdev)
409 return QDF_STATUS_E_FAILURE;
410
411 psoc = wlan_pdev_get_psoc(pdev);
412 if (!psoc)
413 return QDF_STATUS_E_FAILURE;
414
415 /* If MCC is not supported just break and return SUCCESS */
416 wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode);
417 if (!enable_mcc_mode)
418 return QDF_STATUS_E_FAILURE;
419
420 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
421 if_mgr_update_beacon_interval,
422 bss_arg, 0, WLAN_IF_MGR_ID);
423
424 return bss_arg->status;
425 }
426
if_mgr_validate_sta_bcn_intrvl(struct wlan_objmgr_vdev * vdev,struct beacon_interval_arg * bss_arg)427 static bool if_mgr_validate_sta_bcn_intrvl(struct wlan_objmgr_vdev *vdev,
428 struct beacon_interval_arg *bss_arg)
429 {
430 struct wlan_objmgr_psoc *psoc;
431 struct vdev_mlme_obj *vdev_mlme;
432 struct wlan_objmgr_peer *peer;
433 uint16_t new_bcn_interval;
434 uint32_t beacon_interval;
435 struct wlan_channel *chan;
436 enum QDF_OPMODE curr_persona;
437 uint8_t allow_mcc_go_diff_bi;
438 uint8_t conc_rule1 = 0, conc_rule2 = 0;
439 uint8_t vdev_id = wlan_vdev_get_id(vdev);
440
441 psoc = wlan_vdev_get_psoc(vdev);
442 if (!psoc)
443 return false;
444
445 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID);
446 if (!peer)
447 return false;
448
449 curr_persona = wlan_vdev_mlme_get_opmode(vdev);
450
451 wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID);
452
453 if (curr_persona == QDF_STA_MODE ||
454 curr_persona == QDF_P2P_CLIENT_MODE) {
455 ifmgr_debug("Bcn Intrvl validation not require for STA/CLIENT");
456 return false;
457 }
458
459 chan = wlan_vdev_get_active_channel(vdev);
460 if (!chan) {
461 ifmgr_err("failed to get active channel");
462 return false;
463 }
464
465 vdev_mlme =
466 wlan_objmgr_vdev_get_comp_private_obj(vdev,
467 WLAN_UMAC_COMP_MLME);
468 if (!vdev_mlme) {
469 QDF_ASSERT(0);
470 return false;
471 }
472
473 wlan_util_vdev_mlme_get_param(vdev_mlme, WLAN_MLME_CFG_BEACON_INTERVAL,
474 &beacon_interval);
475
476 if (curr_persona == QDF_SAP_MODE &&
477 (chan->ch_cfreq1 != bss_arg->ch_freq ||
478 chan->ch_cfreq2 != bss_arg->ch_freq)) {
479 ifmgr_debug("*** MCC with SAP+STA sessions ****");
480 bss_arg->status = QDF_STATUS_SUCCESS;
481 return true;
482 }
483
484 if (curr_persona == QDF_P2P_GO_MODE &&
485 (chan->ch_cfreq1 != bss_arg->ch_freq ||
486 chan->ch_cfreq2 != bss_arg->ch_freq) &&
487 beacon_interval != bss_arg->bss_beacon_interval) {
488 policy_mgr_get_allow_mcc_go_diff_bi(psoc,
489 &allow_mcc_go_diff_bi);
490
491 switch (allow_mcc_go_diff_bi) {
492 case ALLOW_MCC_GO_DIFF_BI_WFA_CERT:
493 bss_arg->status = QDF_STATUS_SUCCESS;
494 return true;
495 case ALLOW_MCC_GO_DIFF_BI_WORKAROUND:
496 fallthrough;
497 case ALLOW_MCC_GO_DIFF_BI_NO_DISCONNECT:
498 policy_mgr_get_conc_rule1(psoc, &conc_rule1);
499 policy_mgr_get_conc_rule2(psoc, &conc_rule2);
500 if (conc_rule1 || conc_rule2)
501 new_bcn_interval = CUSTOM_CONC_GO_BI;
502 else
503 new_bcn_interval =
504 if_mgr_calculate_mcc_beacon_interval(
505 bss_arg->bss_beacon_interval,
506 beacon_interval);
507
508 ifmgr_debug("Peer AP BI : %d, new Beacon Interval: %d",
509 bss_arg->bss_beacon_interval,
510 new_bcn_interval);
511
512 /* Update the beacon interval */
513 if (new_bcn_interval != beacon_interval) {
514 ifmgr_err("Beacon Interval got changed config used: %d",
515 allow_mcc_go_diff_bi);
516 bss_arg->bss_beacon_interval = new_bcn_interval;
517 bss_arg->update_beacon_interval = true;
518 bss_arg->status =
519 if_mgr_update_mcc_p2p_beacon_interval(
520 vdev,
521 bss_arg);
522 return true;
523 }
524 bss_arg->status = QDF_STATUS_SUCCESS;
525 return true;
526 case ALLOW_MCC_GO_DIFF_BI_TEAR_DOWN:
527 bss_arg->update_beacon_interval = false;
528 bss_arg->status = wlan_sap_stop_bss(vdev_id);
529 return true;
530 default:
531 ifmgr_err("BcnIntrvl is diff can't connect to preferred AP");
532 bss_arg->status = QDF_STATUS_E_FAILURE;
533 return true;
534 }
535 }
536 return false;
537 }
538
if_mgr_validate_p2pcli_bcn_intrvl(struct wlan_objmgr_vdev * vdev,struct beacon_interval_arg * bss_arg)539 static bool if_mgr_validate_p2pcli_bcn_intrvl(struct wlan_objmgr_vdev *vdev,
540 struct beacon_interval_arg *bss_arg)
541 {
542 enum QDF_OPMODE curr_persona;
543 enum wlan_peer_type bss_persona;
544 uint32_t beacon_interval;
545 struct wlan_channel *chan;
546 struct wlan_objmgr_peer *peer;
547 struct vdev_mlme_obj *vdev_mlme;
548
549 curr_persona = wlan_vdev_mlme_get_opmode(vdev);
550
551 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID);
552 if (!peer)
553 return false;
554
555 bss_persona = wlan_peer_get_peer_type(peer);
556
557 wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID);
558
559 chan = wlan_vdev_get_active_channel(vdev);
560 if (!chan) {
561 ifmgr_err("failed to get active channel");
562 return false;
563 }
564
565 vdev_mlme =
566 wlan_objmgr_vdev_get_comp_private_obj(vdev,
567 WLAN_UMAC_COMP_MLME);
568 if (!vdev_mlme) {
569 QDF_ASSERT(0);
570 return false;
571 }
572
573 wlan_util_vdev_mlme_get_param(vdev_mlme, WLAN_MLME_CFG_BEACON_INTERVAL,
574 &beacon_interval);
575
576 if (curr_persona == QDF_STA_MODE) {
577 ifmgr_debug("Ignore Beacon Interval Validation...");
578 } else if (bss_persona == WLAN_PEER_P2P_GO) {
579 if ((chan->ch_cfreq1 != bss_arg->ch_freq ||
580 chan->ch_cfreq2 != bss_arg->ch_freq) &&
581 beacon_interval != bss_arg->bss_beacon_interval) {
582 ifmgr_err("BcnIntrvl is diff can't connect to P2P_GO network");
583 bss_arg->status = QDF_STATUS_E_FAILURE;
584 return true;
585 }
586 }
587
588 return false;
589 }
590
591 static bool
if_mgr_validate_p2pgo_bcn_intrvl(struct wlan_objmgr_vdev * vdev,struct beacon_interval_arg * bss_arg)592 if_mgr_validate_p2pgo_bcn_intrvl(struct wlan_objmgr_vdev *vdev,
593 struct beacon_interval_arg *bss_arg)
594 {
595 struct wlan_objmgr_psoc *psoc;
596 struct vdev_mlme_obj *vdev_mlme;
597 enum QDF_OPMODE curr_persona;
598 uint32_t beacon_interval;
599 struct wlan_channel *chan;
600 uint8_t conc_rule1 = 0, conc_rule2 = 0;
601 uint16_t new_bcn_interval;
602
603 curr_persona = wlan_vdev_mlme_get_opmode(vdev);
604
605 chan = wlan_vdev_get_active_channel(vdev);
606 if (!chan) {
607 ifmgr_err("failed to get active channel");
608 return false;
609 }
610
611 vdev_mlme =
612 wlan_objmgr_vdev_get_comp_private_obj(vdev,
613 WLAN_UMAC_COMP_MLME);
614 if (!vdev_mlme) {
615 QDF_ASSERT(0);
616 return false;
617 }
618
619 psoc = wlan_vdev_get_psoc(vdev);
620 if (!psoc)
621 return false;
622
623 wlan_util_vdev_mlme_get_param(vdev_mlme, WLAN_MLME_CFG_BEACON_INTERVAL,
624 &beacon_interval);
625
626 if ((curr_persona == QDF_P2P_CLIENT_MODE) ||
627 (curr_persona == QDF_STA_MODE)) {
628 /* check for P2P_client scenario */
629 if ((chan->ch_cfreq1 == 0) && (chan->ch_cfreq2 == 0) &&
630 (beacon_interval == 0))
631 return false;
632
633 if (wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP &&
634 (chan->ch_cfreq1 != bss_arg->ch_freq ||
635 chan->ch_cfreq2 != bss_arg->ch_freq) &&
636 beacon_interval != bss_arg->bss_beacon_interval) {
637 /*
638 * Updated beaconInterval should be used only when
639 * we are starting a new BSS not incase of
640 * client or STA case
641 */
642 policy_mgr_get_conc_rule1(psoc, &conc_rule1);
643 policy_mgr_get_conc_rule2(psoc, &conc_rule2);
644
645 /* Calculate beacon Interval for P2P-GO incase of MCC */
646 if (conc_rule1 || conc_rule2) {
647 new_bcn_interval = CUSTOM_CONC_GO_BI;
648 } else {
649 new_bcn_interval =
650 if_mgr_calculate_mcc_beacon_interval(
651 beacon_interval,
652 bss_arg->bss_beacon_interval);
653 }
654 if (new_bcn_interval != bss_arg->bss_beacon_interval)
655 bss_arg->bss_beacon_interval = new_bcn_interval;
656 bss_arg->status = QDF_STATUS_SUCCESS;
657 return true;
658 }
659 }
660 return false;
661 }
662
if_mgr_validate_beacon_interval(struct wlan_objmgr_pdev * pdev,void * object,void * arg)663 static void if_mgr_validate_beacon_interval(struct wlan_objmgr_pdev *pdev,
664 void *object, void *arg)
665 {
666 struct beacon_interval_arg *bss_arg = arg;
667 struct wlan_objmgr_vdev *vdev = object;
668 uint8_t iter_vdev_id = wlan_vdev_get_id(vdev);
669 bool is_done = false;
670
671 if (iter_vdev_id == bss_arg->curr_vdev_id)
672 return;
673
674 if (wlan_vdev_mlme_get_state(vdev) != WLAN_VDEV_S_UP)
675 return;
676
677 if (bss_arg->is_done)
678 return;
679
680 switch (bss_arg->curr_bss_opmode) {
681 case QDF_STA_MODE:
682 is_done = if_mgr_validate_sta_bcn_intrvl(vdev, bss_arg);
683 break;
684 case QDF_P2P_CLIENT_MODE:
685 is_done = if_mgr_validate_p2pcli_bcn_intrvl(vdev, bss_arg);
686 break;
687 case QDF_SAP_MODE:
688 case QDF_IBSS_MODE:
689 break;
690 case QDF_P2P_GO_MODE:
691 is_done = if_mgr_validate_p2pgo_bcn_intrvl(vdev, bss_arg);
692 break;
693 default:
694 ifmgr_err("BSS opmode not supported: %d",
695 bss_arg->curr_bss_opmode);
696 }
697
698 if (is_done)
699 bss_arg->is_done = is_done;
700 }
701
if_mgr_is_beacon_interval_valid(struct wlan_objmgr_pdev * pdev,uint8_t vdev_id,struct validate_bss_data * candidate)702 bool if_mgr_is_beacon_interval_valid(struct wlan_objmgr_pdev *pdev,
703 uint8_t vdev_id,
704 struct validate_bss_data *candidate)
705 {
706 struct wlan_objmgr_psoc *psoc;
707 struct beacon_interval_arg bss_arg;
708 uint8_t enable_mcc_mode;
709 struct wlan_objmgr_vdev *vdev;
710
711 psoc = wlan_pdev_get_psoc(pdev);
712 if (!psoc)
713 return false;
714
715 wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode);
716 if (!enable_mcc_mode)
717 return false;
718
719 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
720 WLAN_IF_MGR_ID);
721 if (!vdev)
722 return false;
723
724 bss_arg.curr_vdev_id = vdev_id;
725 bss_arg.curr_bss_opmode = wlan_vdev_mlme_get_opmode(vdev);
726 bss_arg.ch_freq = candidate->chan_freq;
727 bss_arg.bss_beacon_interval = candidate->beacon_interval;
728 bss_arg.is_done = false;
729
730 wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID);
731
732 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
733 if_mgr_validate_beacon_interval,
734 &bss_arg, 0,
735 WLAN_IF_MGR_ID);
736
737 if (!bss_arg.is_done)
738 return true;
739
740 if (bss_arg.is_done && QDF_IS_STATUS_SUCCESS(bss_arg.status))
741 return true;
742
743 return false;
744 }
745
if_mgr_get_vdev_id_from_bssid(struct wlan_objmgr_pdev * pdev,void * object,void * arg)746 static void if_mgr_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev,
747 void *object, void *arg)
748 {
749 struct bssid_search_arg *bssid_arg = arg;
750 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
751 struct wlan_objmgr_peer *peer;
752
753 if (!(wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE ||
754 wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE))
755 return;
756
757 /* Need to check the connection manager state when that becomes
758 * available
759 */
760 if (wlan_vdev_mlme_get_state(vdev) != WLAN_VDEV_S_UP)
761 return;
762
763 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID);
764 if (!peer)
765 return;
766
767 if (WLAN_ADDR_EQ(bssid_arg->peer_addr.bytes,
768 wlan_peer_get_macaddr(peer)) == QDF_STATUS_SUCCESS)
769 bssid_arg->vdev_id = wlan_vdev_get_id(vdev);
770
771 wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID);
772 }
773
774 #ifdef WLAN_FEATURE_11BE_MLO
775 /**
776 * if_mgr_get_conc_ext_flags() - get extended flags for concurrency check
777 * @vdev: pointer to vdev on which new connection is coming up
778 * @candidate_info: interface manager validate candidate data
779 *
780 * Return: extended flags for concurrency check
781 */
782 static inline uint32_t
if_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev * vdev,struct validate_bss_data * candidate_info)783 if_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev,
784 struct validate_bss_data *candidate_info)
785 {
786 struct qdf_mac_addr *mld_addr;
787
788 /* If connection is happening on non-ML VDEV
789 * force the ML AP candidate as non-MLO to
790 * downgrade connection to 11ax.
791 */
792 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
793 if (qdf_is_macaddr_zero(mld_addr))
794 return policy_mgr_get_conc_ext_flags(vdev, false);
795
796 return policy_mgr_get_conc_ext_flags(vdev, candidate_info->is_mlo);
797 }
798
if_mgr_update_candidate(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct validate_bss_data * candidate_info)799 static void if_mgr_update_candidate(struct wlan_objmgr_psoc *psoc,
800 struct wlan_objmgr_vdev *vdev,
801 struct validate_bss_data *candidate_info)
802 {
803 struct scan_cache_entry *scan_entry = candidate_info->scan_entry;
804 struct action_oui_search_attr attr = {0};
805 int8_t i, allowed_partner_links = 0;
806 uint8_t mlo_support_link_num;
807
808 if (!(scan_entry->ie_list.multi_link_bv || scan_entry->ie_list.ehtcap ||
809 scan_entry->ie_list.ehtop))
810 return;
811
812 attr.ie_data = util_scan_entry_ie_data(scan_entry);
813 attr.ie_length = util_scan_entry_ie_len(scan_entry);
814
815 if (!mlme_get_bss_11be_allowed(psoc, &candidate_info->peer_addr,
816 attr.ie_data, attr.ie_length) ||
817 wlan_vdev_mlme_get_user_dis_eht_flag(vdev) ||
818 !wlan_reg_phybitmap_support_11be(wlan_vdev_get_pdev(vdev))) {
819 scan_entry->ie_list.multi_link_bv = NULL;
820 scan_entry->ie_list.ehtcap = NULL;
821 scan_entry->ie_list.ehtop = NULL;
822 qdf_mem_zero(&scan_entry->ml_info, sizeof(scan_entry->ml_info));
823 candidate_info->is_mlo = false;
824 return;
825 }
826
827 mlo_support_link_num = wlan_mlme_get_sta_mlo_conn_max_num(psoc);
828
829 if (mlo_support_link_num <= WLAN_MAX_ML_DEFAULT_LINK)
830 return;
831
832 if (!wlan_action_oui_search(psoc, &attr,
833 ACTION_OUI_RESTRICT_MAX_MLO_LINKS))
834 return;
835
836 for (i = 0; i < scan_entry->ml_info.num_links; i++) {
837 if (i < WLAN_MAX_ML_DEFAULT_LINK - 1) {
838 allowed_partner_links++;
839 continue;
840 }
841
842 scan_entry->ml_info.link_info[i].is_valid_link = false;
843 }
844
845 if (allowed_partner_links != scan_entry->ml_info.num_links)
846 ifmgr_nofl_debug("Downgrade " QDF_MAC_ADDR_FMT " partner links from %d to %d",
847 QDF_MAC_ADDR_REF(scan_entry->ml_info.mld_mac_addr.bytes),
848 scan_entry->ml_info.num_links,
849 allowed_partner_links);
850 }
851 #else
852 static inline uint32_t
if_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev * vdev,struct validate_bss_data * candidate_info)853 if_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev,
854 struct validate_bss_data *candidate_info)
855 {
856 return 0;
857 }
858
if_mgr_update_candidate(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct validate_bss_data * candidate_info)859 static void if_mgr_update_candidate(struct wlan_objmgr_psoc *psoc,
860 struct wlan_objmgr_vdev *vdev,
861 struct validate_bss_data *candidate_info)
862 {
863 }
864 #endif
865
if_mgr_validate_candidate(struct wlan_objmgr_vdev * vdev,struct if_mgr_event_data * event_data)866 QDF_STATUS if_mgr_validate_candidate(struct wlan_objmgr_vdev *vdev,
867 struct if_mgr_event_data *event_data)
868 {
869 struct wlan_objmgr_psoc *psoc;
870 struct wlan_objmgr_pdev *pdev;
871 enum QDF_OPMODE op_mode;
872 enum policy_mgr_con_mode mode;
873 struct bssid_search_arg bssid_arg;
874 struct validate_bss_data *candidate_info =
875 &event_data->validate_bss_info;
876 uint32_t chan_freq = candidate_info->chan_freq;
877 uint32_t conc_freq = 0, conc_ext_flags;
878
879 op_mode = wlan_vdev_mlme_get_opmode(vdev);
880
881 pdev = wlan_vdev_get_pdev(vdev);
882 if (!pdev)
883 return QDF_STATUS_E_FAILURE;
884
885 psoc = wlan_pdev_get_psoc(pdev);
886 if (!psoc)
887 return QDF_STATUS_E_FAILURE;
888
889 if_mgr_update_candidate(psoc, vdev, candidate_info);
890 /*
891 * Do not allow STA to connect on 6Ghz or indoor channel for non dbs
892 * hardware if SAP and skip_6g_and_indoor_freq_scan ini are present
893 */
894 if (op_mode == QDF_STA_MODE &&
895 !policy_mgr_is_sta_chan_valid_for_connect_and_roam(pdev,
896 chan_freq)) {
897 ifmgr_debug("STA connection not allowed on bssid: "QDF_MAC_ADDR_FMT" with freq: %d (6Ghz or indoor(%d)), as not valid for connection",
898 QDF_MAC_ADDR_REF(candidate_info->peer_addr.bytes),
899 chan_freq,
900 wlan_reg_is_freq_indoor(pdev, chan_freq));
901 return QDF_STATUS_E_INVAL;
902 }
903
904 /*
905 * This is a temporary check and will be removed once ll_lt_sap CSA
906 * support is added.
907 */
908 if (policy_mgr_get_ll_lt_sap_freq(psoc) == chan_freq) {
909 ifmgr_debug("STA connection not allowed on LL_LT_SAP freq %d",
910 chan_freq);
911 return QDF_STATUS_E_INVAL;
912 }
913 /*
914 * Ignore the BSS if any other vdev is already connected to it.
915 */
916 qdf_copy_macaddr(&bssid_arg.peer_addr,
917 &candidate_info->peer_addr);
918 bssid_arg.vdev_id = WLAN_INVALID_VDEV_ID;
919 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
920 if_mgr_get_vdev_id_from_bssid,
921 &bssid_arg, 0,
922 WLAN_IF_MGR_ID);
923
924 if (bssid_arg.vdev_id != WLAN_INVALID_VDEV_ID) {
925 ifmgr_info("vdev_id %d already connected to "QDF_MAC_ADDR_FMT". select next bss for vdev_id %d",
926 bssid_arg.vdev_id,
927 QDF_MAC_ADDR_REF(bssid_arg.peer_addr.bytes),
928 wlan_vdev_get_id(vdev));
929 return QDF_STATUS_E_INVAL;
930 }
931
932 /*
933 * If concurrency enabled take the concurrent connected channel first.
934 * Valid multichannel concurrent sessions exempted
935 */
936 mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode,
937 wlan_vdev_get_id(vdev));
938
939 /* If concurrency is not allowed select next bss */
940 conc_ext_flags = if_mgr_get_conc_ext_flags(vdev, candidate_info);
941 /*
942 * Apply concurrency check only for non ML and ML assoc links only
943 * For non-assoc ML link if concurrency check fails its will be forced
944 * disabled in peer assoc.
945 */
946 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) &&
947 !policy_mgr_is_concurrency_allowed(psoc, mode, chan_freq,
948 HW_MODE_20_MHZ, conc_ext_flags,
949 NULL)) {
950 ifmgr_info("Concurrency not allowed for this channel freq %d bssid "QDF_MAC_ADDR_FMT", selecting next",
951 chan_freq,
952 QDF_MAC_ADDR_REF(bssid_arg.peer_addr.bytes));
953 return QDF_STATUS_E_INVAL;
954 }
955
956 /*
957 * check if channel is allowed for current hw mode, if not fetch
958 * next BSS.
959 */
960 if (!policy_mgr_is_hwmode_set_for_given_chnl(psoc, chan_freq)) {
961 ifmgr_info("HW mode isn't properly set, freq %d BSSID "QDF_MAC_ADDR_FMT,
962 chan_freq,
963 QDF_MAC_ADDR_REF(bssid_arg.peer_addr.bytes));
964 return QDF_STATUS_E_INVAL;
965 }
966
967 /* validate beacon interval */
968 if (policy_mgr_concurrent_open_sessions_running(psoc) &&
969 !if_mgr_is_beacon_interval_valid(pdev, wlan_vdev_get_id(vdev),
970 candidate_info)) {
971 conc_freq = wlan_get_conc_freq();
972 ifmgr_debug("csr Conc Channel freq: %d",
973 conc_freq);
974
975 if (conc_freq) {
976 if ((conc_freq == chan_freq) ||
977 (policy_mgr_is_hw_sbs_capable(psoc) &&
978 policy_mgr_are_sbs_chan(psoc, conc_freq,
979 chan_freq)) ||
980 (policy_mgr_is_hw_dbs_capable(psoc) &&
981 !wlan_reg_is_same_band_freqs(conc_freq,
982 chan_freq))) {
983 /*
984 * make this 0 because we do not want the below
985 * check to pass as we don't want to connect on
986 * other channel
987 */
988 ifmgr_debug("Conc chnl freq match: %d",
989 conc_freq);
990 conc_freq = 0;
991 }
992 }
993 }
994
995 if (conc_freq)
996 return QDF_STATUS_E_INVAL;
997
998 /* Check low latency SAP and STA/GC concurrency are valid or not */
999 if (!policy_mgr_is_ll_sap_concurrency_valid(psoc, chan_freq, mode)) {
1000 ifmgr_debug("STA connection not allowed on bssid: "QDF_MAC_ADDR_FMT" with freq: %d due to LL SAP present",
1001 QDF_MAC_ADDR_REF(candidate_info->peer_addr.bytes),
1002 chan_freq);
1003 return QDF_STATUS_E_INVAL;
1004 }
1005
1006 return QDF_STATUS_SUCCESS;
1007 }
1008