1 /* 2 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: Add host 11d scan utility functions 21 */ 22 23 #include <wlan_cmn.h> 24 #include <reg_services_public_struct.h> 25 #include <wlan_scan_public_structs.h> 26 #include <wlan_scan_ucfg_api.h> 27 #include <wlan_objmgr_psoc_obj.h> 28 #include "reg_priv_objs.h" 29 #include "reg_getset.h" 30 #include "reg_host_11d.h" 31 #include "reg_services_common.h" 32 33 static QDF_STATUS reg_11d_scan_trigger_handler( 34 struct wlan_regulatory_psoc_priv_obj *soc_reg) 35 { 36 struct scan_start_request *req; 37 struct wlan_objmgr_vdev *vdev; 38 QDF_STATUS status; 39 40 req = qdf_mem_malloc(sizeof(*req)); 41 if (!req) 42 return QDF_STATUS_E_NOMEM; 43 44 vdev = wlan_objmgr_get_vdev_by_id_from_psoc( 45 soc_reg->psoc_ptr, 46 soc_reg->vdev_id_for_11d_scan, 47 WLAN_REGULATORY_SB_ID); 48 if (!vdev) { 49 reg_err("vdev object is NULL id %d", 50 soc_reg->vdev_id_for_11d_scan); 51 qdf_mem_free(req); 52 return QDF_STATUS_E_FAILURE; 53 } 54 55 ucfg_scan_init_default_params(vdev, req); 56 57 req->scan_req.scan_id = ucfg_scan_get_scan_id(soc_reg->psoc_ptr); 58 if (!req->scan_req.scan_id) { 59 wlan_objmgr_vdev_release_ref(vdev, WLAN_REGULATORY_SB_ID); 60 qdf_mem_free(req); 61 reg_err("Invalid scan ID"); 62 return QDF_STATUS_E_FAILURE; 63 } 64 soc_reg->scan_id = req->scan_req.scan_id; 65 req->scan_req.vdev_id = soc_reg->vdev_id_for_11d_scan; 66 req->scan_req.scan_req_id = soc_reg->scan_req_id; 67 req->scan_req.scan_priority = SCAN_PRIORITY_LOW; 68 req->scan_req.scan_f_passive = false; 69 70 status = ucfg_scan_start(req); 71 reg_debug("11d scan trigger vdev %d scan_id %d req_id %d status %d", 72 soc_reg->vdev_id_for_11d_scan, soc_reg->scan_id, 73 soc_reg->scan_req_id, status); 74 75 if (status != QDF_STATUS_SUCCESS) 76 /* Don't free req here, ucfg_scan_start will do free */ 77 reg_err("11d scan req failed vdev %d", 78 soc_reg->vdev_id_for_11d_scan); 79 80 wlan_objmgr_vdev_release_ref(vdev, WLAN_REGULATORY_SB_ID); 81 82 return status; 83 } 84 85 static void reg_11d_scan_event_cb( 86 struct wlan_objmgr_vdev *vdev, 87 struct scan_event *event, void *arg) 88 { 89 }; 90 91 QDF_STATUS reg_11d_host_scan( 92 struct wlan_regulatory_psoc_priv_obj *soc_reg) 93 { 94 QDF_STATUS status = QDF_STATUS_SUCCESS; 95 96 reg_debug("host 11d enabled %d, inited: %d", soc_reg->enable_11d_supp, 97 soc_reg->is_host_11d_inited); 98 if (!soc_reg->is_host_11d_inited) 99 return QDF_STATUS_E_FAILURE; 100 101 if (soc_reg->enable_11d_supp) { 102 qdf_mc_timer_stop(&soc_reg->timer); 103 status = reg_11d_scan_trigger_handler(soc_reg); 104 if (status != QDF_STATUS_SUCCESS) { 105 reg_err("11d scan trigger failed!"); 106 return status; 107 } 108 109 qdf_mc_timer_start(&soc_reg->timer, soc_reg->scan_11d_interval); 110 } else { 111 qdf_mc_timer_stop(&soc_reg->timer); 112 } 113 return status; 114 } 115 116 static void reg_11d_scan_timer(void *context) 117 { 118 struct wlan_regulatory_psoc_priv_obj *soc_reg = context; 119 120 reg_debug("11d scan timeout"); 121 122 if (!soc_reg) 123 return; 124 125 reg_11d_host_scan(soc_reg); 126 } 127 128 QDF_STATUS reg_11d_host_scan_init(struct wlan_objmgr_psoc *psoc) 129 { 130 struct wlan_regulatory_psoc_priv_obj *soc_reg; 131 132 soc_reg = reg_get_psoc_obj(psoc); 133 if (!soc_reg) { 134 reg_err("reg psoc private obj is NULL"); 135 return QDF_STATUS_E_FAULT; 136 } 137 138 if (soc_reg->is_host_11d_inited) { 139 reg_debug("host 11d scan are already inited"); 140 return QDF_STATUS_SUCCESS; 141 } 142 soc_reg->scan_req_id = 143 ucfg_scan_register_requester(psoc, "11d", 144 reg_11d_scan_event_cb, 145 soc_reg); 146 qdf_mc_timer_init(&soc_reg->timer, QDF_TIMER_TYPE_SW, 147 reg_11d_scan_timer, soc_reg); 148 149 soc_reg->is_host_11d_inited = true; 150 reg_debug("reg 11d scan inited"); 151 152 return QDF_STATUS_SUCCESS; 153 } 154 155 QDF_STATUS reg_11d_host_scan_deinit(struct wlan_objmgr_psoc *psoc) 156 { 157 struct wlan_regulatory_psoc_priv_obj *soc_reg; 158 159 soc_reg = reg_get_psoc_obj(psoc); 160 if (!soc_reg) { 161 reg_err("reg psoc private obj is NULL"); 162 return QDF_STATUS_E_FAULT; 163 } 164 165 if (!soc_reg->is_host_11d_inited) { 166 reg_debug("host 11d scan are not inited"); 167 return QDF_STATUS_SUCCESS; 168 } 169 qdf_mc_timer_stop(&soc_reg->timer); 170 qdf_mc_timer_destroy(&soc_reg->timer); 171 ucfg_scan_unregister_requester(psoc, soc_reg->scan_req_id); 172 soc_reg->is_host_11d_inited = false; 173 reg_debug("reg 11d scan deinit"); 174 175 return QDF_STATUS_SUCCESS; 176 } 177 178 QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev, 179 uint8_t *country) 180 { 181 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 182 struct set_country country_code; 183 struct wlan_objmgr_psoc *psoc; 184 struct cc_regdmn_s rd; 185 QDF_STATUS status; 186 struct wlan_lmac_if_reg_tx_ops *tx_ops; 187 uint8_t pdev_id; 188 189 if (!country) { 190 reg_err("country code is NULL"); 191 return QDF_STATUS_E_INVAL; 192 } 193 194 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 195 196 psoc = wlan_pdev_get_psoc(pdev); 197 psoc_priv_obj = reg_get_psoc_obj(psoc); 198 if (!psoc_priv_obj) { 199 reg_err("psoc reg component is NULL"); 200 return QDF_STATUS_E_INVAL; 201 } 202 203 if (!qdf_mem_cmp(psoc_priv_obj->cur_country, country, REG_ALPHA2_LEN)) { 204 reg_debug("country is not different"); 205 return QDF_STATUS_SUCCESS; 206 } 207 208 reg_info("programming new 11d country:%c%c to firmware", 209 country[0], country[1]); 210 211 qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1); 212 country_code.pdev_id = pdev_id; 213 214 psoc_priv_obj->new_11d_ctry_pending[pdev_id] = true; 215 216 if (psoc_priv_obj->offload_enabled) { 217 tx_ops = reg_get_psoc_tx_ops(psoc); 218 if (tx_ops->set_country_code) { 219 tx_ops->set_country_code(psoc, &country_code); 220 } else { 221 reg_err("country set fw handler not present"); 222 psoc_priv_obj->new_11d_ctry_pending[pdev_id] = false; 223 return QDF_STATUS_E_FAULT; 224 } 225 status = QDF_STATUS_SUCCESS; 226 } else { 227 qdf_mem_copy(rd.cc.alpha, country, REG_ALPHA2_LEN + 1); 228 rd.flags = ALPHA_IS_SET; 229 reg_program_chan_list(pdev, &rd); 230 status = QDF_STATUS_SUCCESS; 231 } 232 233 return status; 234 } 235 236 /** 237 * reg_send_11d_flush_cbk() - release 11d psoc reference 238 * @msg: Pointer to scheduler message. 239 * 240 * Return: QDF_STATUS 241 */ 242 static QDF_STATUS reg_send_11d_flush_cbk(struct scheduler_msg *msg) 243 { 244 struct wlan_objmgr_psoc *psoc = msg->bodyptr; 245 246 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID); 247 248 return QDF_STATUS_SUCCESS; 249 } 250 251 /** 252 * reg_send_11d_msg_cbk() - Send start/stop 11d scan message. 253 * @msg: Pointer to scheduler message. 254 * 255 * Return: QDF_STATUS 256 */ 257 static QDF_STATUS reg_send_11d_msg_cbk(struct scheduler_msg *msg) 258 { 259 struct wlan_objmgr_psoc *psoc = msg->bodyptr; 260 struct wlan_lmac_if_reg_tx_ops *tx_ops; 261 struct reg_start_11d_scan_req start_req; 262 struct reg_stop_11d_scan_req stop_req; 263 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 264 265 tx_ops = reg_get_psoc_tx_ops(psoc); 266 267 psoc_priv_obj = reg_get_psoc_obj(psoc); 268 if (!psoc_priv_obj) { 269 reg_err("psoc priv obj is NULL"); 270 return QDF_STATUS_E_FAILURE; 271 } 272 273 if (psoc_priv_obj->enable_11d_supp) { 274 start_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan; 275 start_req.scan_period_msec = psoc_priv_obj->scan_11d_interval; 276 start_req.start_interval_msec = 0; 277 reg_debug("sending start msg"); 278 tx_ops->start_11d_scan(psoc, &start_req); 279 } else { 280 stop_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan; 281 reg_debug("sending stop msg"); 282 tx_ops->stop_11d_scan(psoc, &stop_req); 283 } 284 285 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID); 286 return QDF_STATUS_SUCCESS; 287 } 288 289 /** 290 * reg_sched_11d_msg() - Schedules 11d scan message. 291 * @psoc: soc context 292 */ 293 static QDF_STATUS reg_sched_11d_msg(struct wlan_objmgr_psoc *psoc) 294 { 295 struct scheduler_msg msg = {0}; 296 QDF_STATUS status; 297 298 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID); 299 if (QDF_IS_STATUS_ERROR(status)) { 300 reg_err("error taking psoc ref cnt"); 301 return status; 302 } 303 304 msg.bodyptr = psoc; 305 msg.callback = reg_send_11d_msg_cbk; 306 msg.flush_callback = reg_send_11d_flush_cbk; 307 308 status = scheduler_post_message(QDF_MODULE_ID_REGULATORY, 309 QDF_MODULE_ID_REGULATORY, 310 QDF_MODULE_ID_TARGET_IF, &msg); 311 if (QDF_IS_STATUS_ERROR(status)) { 312 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID); 313 reg_err("scheduler msg posting failed"); 314 } 315 316 return status; 317 } 318 319 void reg_run_11d_state_machine(struct wlan_objmgr_psoc *psoc) 320 { 321 bool temp_11d_support; 322 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 323 bool world_mode; 324 325 psoc_priv_obj = reg_get_psoc_obj(psoc); 326 if (!psoc_priv_obj) { 327 reg_err("reg psoc private obj is NULL"); 328 return; 329 } 330 331 world_mode = reg_is_world_alpha2(psoc_priv_obj->cur_country); 332 333 temp_11d_support = psoc_priv_obj->enable_11d_supp; 334 if ((psoc_priv_obj->enable_11d_in_world_mode) && (world_mode)) 335 psoc_priv_obj->enable_11d_supp = true; 336 else if (((psoc_priv_obj->user_ctry_set) && 337 (psoc_priv_obj->user_ctry_priority)) || 338 (psoc_priv_obj->master_vdev_cnt)) 339 psoc_priv_obj->enable_11d_supp = false; 340 else 341 psoc_priv_obj->enable_11d_supp = 342 psoc_priv_obj->enable_11d_supp_original; 343 344 reg_debug("inside 11d state machine:tmp %d 11d_supp %d org %d set %d pri %d cnt %d vdev %d", 345 temp_11d_support, 346 psoc_priv_obj->enable_11d_supp, 347 psoc_priv_obj->enable_11d_supp_original, 348 psoc_priv_obj->user_ctry_set, 349 psoc_priv_obj->user_ctry_priority, 350 psoc_priv_obj->master_vdev_cnt, 351 psoc_priv_obj->vdev_id_for_11d_scan); 352 353 if (temp_11d_support != psoc_priv_obj->enable_11d_supp) { 354 if (psoc_priv_obj->is_11d_offloaded) 355 reg_sched_11d_msg(psoc); 356 else 357 reg_11d_host_scan(psoc_priv_obj); 358 } 359 } 360 361 QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev) 362 { 363 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 364 struct wlan_objmgr_pdev *parent_pdev; 365 struct wlan_objmgr_psoc *parent_psoc; 366 uint32_t vdev_id; 367 enum QDF_OPMODE op_mode; 368 uint8_t i; 369 370 op_mode = wlan_vdev_mlme_get_opmode(vdev); 371 372 parent_pdev = wlan_vdev_get_pdev(vdev); 373 parent_psoc = wlan_pdev_get_psoc(parent_pdev); 374 375 psoc_priv_obj = reg_get_psoc_obj(parent_psoc); 376 if (!psoc_priv_obj) { 377 reg_err("reg psoc private obj is NULL"); 378 return QDF_STATUS_E_FAULT; 379 } 380 381 if ((op_mode == QDF_STA_MODE) || 382 (op_mode == QDF_P2P_DEVICE_MODE) || 383 (op_mode == QDF_P2P_CLIENT_MODE)) { 384 vdev_id = wlan_vdev_get_id(vdev); 385 if (!psoc_priv_obj->vdev_cnt_11d) { 386 psoc_priv_obj->vdev_id_for_11d_scan = vdev_id; 387 reg_debug("running 11d state machine, opmode %d", 388 op_mode); 389 reg_run_11d_state_machine(parent_psoc); 390 } 391 392 for (i = 0; i < MAX_STA_VDEV_CNT; i++) { 393 if (psoc_priv_obj->vdev_ids_11d[i] == INVALID_VDEV_ID) { 394 psoc_priv_obj->vdev_ids_11d[i] = vdev_id; 395 break; 396 } 397 } 398 psoc_priv_obj->vdev_cnt_11d++; 399 } 400 401 if ((op_mode == QDF_P2P_GO_MODE) || (op_mode == QDF_SAP_MODE)) { 402 reg_debug("running 11d state machine, opmode %d", op_mode); 403 psoc_priv_obj->master_vdev_cnt++; 404 reg_run_11d_state_machine(parent_psoc); 405 } 406 407 return QDF_STATUS_SUCCESS; 408 } 409 410 QDF_STATUS reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev) 411 { 412 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 413 struct wlan_objmgr_pdev *parent_pdev; 414 struct wlan_objmgr_psoc *parent_psoc; 415 enum QDF_OPMODE op_mode; 416 uint32_t vdev_id; 417 uint8_t i; 418 419 if (!vdev) { 420 reg_err("vdev is NULL"); 421 return QDF_STATUS_E_INVAL; 422 } 423 op_mode = wlan_vdev_mlme_get_opmode(vdev); 424 425 parent_pdev = wlan_vdev_get_pdev(vdev); 426 parent_psoc = wlan_pdev_get_psoc(parent_pdev); 427 428 psoc_priv_obj = reg_get_psoc_obj(parent_psoc); 429 if (!psoc_priv_obj) { 430 reg_err("reg psoc private obj is NULL"); 431 return QDF_STATUS_E_FAULT; 432 } 433 434 if ((op_mode == QDF_P2P_GO_MODE) || (op_mode == QDF_SAP_MODE)) { 435 psoc_priv_obj->master_vdev_cnt--; 436 reg_debug("run 11d state machine, deleted opmode %d", 437 op_mode); 438 reg_run_11d_state_machine(parent_psoc); 439 return QDF_STATUS_SUCCESS; 440 } 441 442 if ((op_mode == QDF_STA_MODE) || (op_mode == QDF_P2P_DEVICE_MODE) || 443 (op_mode == QDF_P2P_CLIENT_MODE)) { 444 vdev_id = wlan_vdev_get_id(vdev); 445 for (i = 0; i < MAX_STA_VDEV_CNT; i++) { 446 if (psoc_priv_obj->vdev_ids_11d[i] == vdev_id) { 447 psoc_priv_obj->vdev_ids_11d[i] = 448 INVALID_VDEV_ID; 449 psoc_priv_obj->vdev_cnt_11d--; 450 break; 451 } 452 } 453 454 if ((psoc_priv_obj->vdev_id_for_11d_scan != vdev_id) || 455 !psoc_priv_obj->vdev_cnt_11d) 456 return QDF_STATUS_SUCCESS; 457 458 for (i = 0; i < MAX_STA_VDEV_CNT; i++) { 459 if (psoc_priv_obj->vdev_ids_11d[i] == INVALID_VDEV_ID) 460 continue; 461 psoc_priv_obj->vdev_id_for_11d_scan = 462 psoc_priv_obj->vdev_ids_11d[i]; 463 psoc_priv_obj->enable_11d_supp = false; 464 reg_debug("running 11d state machine, vdev %d", 465 psoc_priv_obj->vdev_id_for_11d_scan); 466 reg_run_11d_state_machine(parent_psoc); 467 break; 468 } 469 } 470 471 return QDF_STATUS_SUCCESS; 472 } 473 474 bool reg_is_11d_scan_inprogress(struct wlan_objmgr_psoc *psoc) 475 { 476 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 477 478 psoc_priv_obj = reg_get_psoc_obj(psoc); 479 if (!psoc_priv_obj) { 480 reg_err("reg psoc private obj is NULL"); 481 return false; 482 } 483 484 return psoc_priv_obj->enable_11d_supp; 485 } 486 487 QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc, 488 uint8_t *country) 489 { 490 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 491 struct wlan_lmac_if_reg_tx_ops *tx_ops; 492 struct set_country country_code; 493 uint8_t pdev_id; 494 495 psoc_priv_obj = reg_get_psoc_obj(psoc); 496 if (!psoc_priv_obj) { 497 reg_err("reg psoc private obj is NULL"); 498 499 return QDF_STATUS_E_FAILURE; 500 } 501 502 pdev_id = psoc_priv_obj->def_pdev_id; 503 psoc_priv_obj->new_11d_ctry_pending[pdev_id] = true; 504 qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1); 505 country_code.pdev_id = pdev_id; 506 507 if (psoc_priv_obj->offload_enabled) { 508 tx_ops = reg_get_psoc_tx_ops(psoc); 509 if (tx_ops->set_country_code) { 510 tx_ops->set_country_code(psoc, &country_code); 511 } else { 512 reg_err("country set handler is not present"); 513 psoc_priv_obj->new_11d_ctry_pending[pdev_id] = false; 514 return QDF_STATUS_E_FAULT; 515 } 516 } 517 518 return QDF_STATUS_SUCCESS; 519 } 520 521 bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc) 522 { 523 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 524 525 psoc_priv_obj = reg_get_psoc_obj(psoc); 526 if (!psoc_priv_obj) { 527 reg_err("reg psoc private obj is NULL"); 528 return QDF_STATUS_E_FAILURE; 529 } 530 531 return (psoc_priv_obj->enable_11d_supp && 532 !psoc_priv_obj->is_11d_offloaded); 533 } 534 535 QDF_STATUS reg_set_11d_offloaded(struct wlan_objmgr_psoc *psoc, bool val) 536 { 537 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 538 539 psoc_priv_obj = reg_get_psoc_obj(psoc); 540 if (!psoc_priv_obj) { 541 reg_err("psoc reg component is NULL"); 542 return QDF_STATUS_E_FAILURE; 543 } 544 545 psoc_priv_obj->is_11d_offloaded = val; 546 reg_debug("set is_11d_offloaded %d", val); 547 return QDF_STATUS_SUCCESS; 548 } 549 550 bool reg_is_11d_offloaded(struct wlan_objmgr_psoc *psoc) 551 { 552 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 553 554 psoc_priv_obj = reg_get_psoc_obj(psoc); 555 if (!psoc_priv_obj) { 556 reg_err("reg psoc private obj is NULL"); 557 return false; 558 } 559 560 return psoc_priv_obj->is_11d_offloaded; 561 } 562