1 /* 2 * Copyright (c) 2018-2020 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 11d 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_utils.h" 30 #include "reg_services_common.h" 31 #include "reg_offload_11d_scan.h" 32 #include "reg_host_11d.h" 33 34 #ifdef TARGET_11D_SCAN 35 36 QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev, 37 uint8_t *country) 38 { 39 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 40 struct set_country country_code; 41 struct wlan_objmgr_psoc *psoc; 42 struct cc_regdmn_s rd; 43 QDF_STATUS status; 44 struct wlan_lmac_if_reg_tx_ops *tx_ops; 45 uint8_t pdev_id; 46 uint8_t phy_id; 47 48 if (!country) { 49 reg_err("Null country code"); 50 return QDF_STATUS_E_INVAL; 51 } 52 53 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 54 55 psoc = wlan_pdev_get_psoc(pdev); 56 psoc_priv_obj = reg_get_psoc_obj(psoc); 57 if (!psoc_priv_obj) { 58 reg_err("Null psoc reg component"); 59 return QDF_STATUS_E_INVAL; 60 } 61 62 if (!qdf_mem_cmp(psoc_priv_obj->cur_country, country, REG_ALPHA2_LEN)) { 63 if (psoc_priv_obj->cc_src == SOURCE_11D) { 64 reg_debug("same country"); 65 return QDF_STATUS_SUCCESS; 66 } 67 } 68 69 reg_info("set new 11d country:%c%c to fW", 70 country[0], country[1]); 71 72 qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1); 73 country_code.pdev_id = pdev_id; 74 75 tx_ops = reg_get_psoc_tx_ops(psoc); 76 if (tx_ops->get_phy_id_from_pdev_id) 77 tx_ops->get_phy_id_from_pdev_id(psoc, pdev_id, &phy_id); 78 else 79 phy_id = pdev_id; 80 81 psoc_priv_obj->new_11d_ctry_pending[phy_id] = true; 82 83 if (psoc_priv_obj->offload_enabled) { 84 tx_ops = reg_get_psoc_tx_ops(psoc); 85 if (tx_ops->set_country_code) { 86 tx_ops->set_country_code(psoc, &country_code); 87 } else { 88 reg_err("country set fw handler not present"); 89 psoc_priv_obj->new_11d_ctry_pending[phy_id] = false; 90 return QDF_STATUS_E_FAULT; 91 } 92 status = QDF_STATUS_SUCCESS; 93 } else { 94 qdf_mem_copy(rd.cc.alpha, country, REG_ALPHA2_LEN + 1); 95 rd.flags = ALPHA_IS_SET; 96 reg_program_chan_list(pdev, &rd); 97 status = QDF_STATUS_SUCCESS; 98 } 99 100 return status; 101 } 102 103 /** 104 * reg_send_11d_flush_cbk() - release 11d psoc reference 105 * @msg: Pointer to scheduler message. 106 * 107 * Return: QDF_STATUS 108 */ 109 static QDF_STATUS reg_send_11d_flush_cbk(struct scheduler_msg *msg) 110 { 111 struct reg_11d_scan_msg *scan_msg_11d = msg->bodyptr; 112 struct wlan_objmgr_psoc *psoc = scan_msg_11d->psoc; 113 114 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID); 115 qdf_mem_free(scan_msg_11d); 116 117 return QDF_STATUS_SUCCESS; 118 } 119 120 /** 121 * reg_send_11d_msg_cbk() - Send start/stop 11d scan message. 122 * @msg: Pointer to scheduler message. 123 * 124 * Return: QDF_STATUS 125 */ 126 static QDF_STATUS reg_send_11d_msg_cbk(struct scheduler_msg *msg) 127 { 128 struct reg_11d_scan_msg *scan_msg_11d = msg->bodyptr; 129 struct wlan_objmgr_psoc *psoc = scan_msg_11d->psoc; 130 struct wlan_lmac_if_reg_tx_ops *tx_ops; 131 struct reg_start_11d_scan_req start_req; 132 struct reg_stop_11d_scan_req stop_req; 133 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 134 135 tx_ops = reg_get_psoc_tx_ops(psoc); 136 137 psoc_priv_obj = reg_get_psoc_obj(psoc); 138 if (!psoc_priv_obj) { 139 reg_err("Null psoc priv obj"); 140 goto end; 141 } 142 143 if (psoc_priv_obj->vdev_id_for_11d_scan == INVALID_VDEV_ID) { 144 psoc_priv_obj->enable_11d_supp = false; 145 reg_err("Invalid vdev"); 146 goto end; 147 } 148 149 if (scan_msg_11d->enable_11d_supp) { 150 start_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan; 151 start_req.scan_period_msec = psoc_priv_obj->scan_11d_interval; 152 start_req.start_interval_msec = 0; 153 reg_debug("sending start msg"); 154 tx_ops->start_11d_scan(psoc, &start_req); 155 } else { 156 stop_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan; 157 reg_debug("sending stop msg"); 158 tx_ops->stop_11d_scan(psoc, &stop_req); 159 } 160 161 end: 162 qdf_mem_free(scan_msg_11d); 163 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID); 164 return QDF_STATUS_SUCCESS; 165 } 166 167 /** 168 * reg_sched_11d_msg() - Schedules 11d scan message. 169 * @scan_msg_11d: 11d scan message 170 */ 171 static QDF_STATUS reg_sched_11d_msg(struct reg_11d_scan_msg *scan_msg_11d) 172 { 173 struct scheduler_msg msg = {0}; 174 QDF_STATUS status; 175 176 status = wlan_objmgr_psoc_try_get_ref(scan_msg_11d->psoc, 177 WLAN_REGULATORY_SB_ID); 178 if (QDF_IS_STATUS_ERROR(status)) { 179 reg_err("error taking psoc ref cnt"); 180 return status; 181 } 182 183 msg.bodyptr = scan_msg_11d; 184 msg.callback = reg_send_11d_msg_cbk; 185 msg.flush_callback = reg_send_11d_flush_cbk; 186 187 status = scheduler_post_message(QDF_MODULE_ID_REGULATORY, 188 QDF_MODULE_ID_REGULATORY, 189 QDF_MODULE_ID_TARGET_IF, &msg); 190 if (QDF_IS_STATUS_ERROR(status)) 191 wlan_objmgr_psoc_release_ref(scan_msg_11d->psoc, 192 WLAN_REGULATORY_SB_ID); 193 194 return status; 195 } 196 197 void reg_run_11d_state_machine(struct wlan_objmgr_psoc *psoc) 198 { 199 bool temp_11d_support; 200 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 201 bool world_mode; 202 struct reg_11d_scan_msg *scan_msg_11d; 203 204 psoc_priv_obj = reg_get_psoc_obj(psoc); 205 if (!psoc_priv_obj) { 206 reg_err("Null reg psoc private obj"); 207 return; 208 } 209 210 if (psoc_priv_obj->vdev_id_for_11d_scan == INVALID_VDEV_ID) { 211 psoc_priv_obj->enable_11d_supp = false; 212 reg_err("Invalid vdev"); 213 return; 214 } 215 216 world_mode = reg_is_world_alpha2(psoc_priv_obj->cur_country); 217 218 temp_11d_support = psoc_priv_obj->enable_11d_supp; 219 if ((psoc_priv_obj->enable_11d_in_world_mode) && (world_mode)) 220 psoc_priv_obj->enable_11d_supp = true; 221 else if (((psoc_priv_obj->user_ctry_set) && 222 (psoc_priv_obj->user_ctry_priority)) || 223 (psoc_priv_obj->master_vdev_cnt)) 224 psoc_priv_obj->enable_11d_supp = false; 225 else 226 psoc_priv_obj->enable_11d_supp = 227 psoc_priv_obj->enable_11d_supp_original; 228 229 reg_debug("inside 11d state machine:tmp %d 11d_supp %d org %d set %d pri %d cnt %d vdev %d", 230 temp_11d_support, 231 psoc_priv_obj->enable_11d_supp, 232 psoc_priv_obj->enable_11d_supp_original, 233 psoc_priv_obj->user_ctry_set, 234 psoc_priv_obj->user_ctry_priority, 235 psoc_priv_obj->master_vdev_cnt, 236 psoc_priv_obj->vdev_id_for_11d_scan); 237 238 if (temp_11d_support != psoc_priv_obj->enable_11d_supp) { 239 if (psoc_priv_obj->is_11d_offloaded) { 240 scan_msg_11d = qdf_mem_malloc(sizeof(*scan_msg_11d)); 241 if (!scan_msg_11d) 242 return; 243 scan_msg_11d->psoc = psoc; 244 scan_msg_11d->enable_11d_supp = 245 psoc_priv_obj->enable_11d_supp; 246 reg_sched_11d_msg(scan_msg_11d); 247 } else { 248 reg_11d_host_scan(psoc_priv_obj); 249 } 250 } 251 } 252 253 QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev) 254 { 255 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 256 struct wlan_objmgr_pdev *parent_pdev; 257 struct wlan_objmgr_psoc *parent_psoc; 258 uint32_t vdev_id; 259 enum QDF_OPMODE op_mode; 260 uint8_t i; 261 262 op_mode = wlan_vdev_mlme_get_opmode(vdev); 263 264 parent_pdev = wlan_vdev_get_pdev(vdev); 265 parent_psoc = wlan_pdev_get_psoc(parent_pdev); 266 267 psoc_priv_obj = reg_get_psoc_obj(parent_psoc); 268 if (!psoc_priv_obj) { 269 reg_err("reg psoc private obj is NULL"); 270 return QDF_STATUS_E_FAULT; 271 } 272 273 if ((op_mode == QDF_STA_MODE) || 274 (op_mode == QDF_P2P_DEVICE_MODE) || 275 (op_mode == QDF_P2P_CLIENT_MODE)) { 276 vdev_id = wlan_vdev_get_id(vdev); 277 if (!psoc_priv_obj->vdev_cnt_11d) { 278 psoc_priv_obj->vdev_id_for_11d_scan = vdev_id; 279 reg_debug("running 11d state machine, opmode %d", 280 op_mode); 281 reg_run_11d_state_machine(parent_psoc); 282 } 283 284 for (i = 0; i < MAX_STA_VDEV_CNT; i++) { 285 if (psoc_priv_obj->vdev_ids_11d[i] == INVALID_VDEV_ID) { 286 psoc_priv_obj->vdev_ids_11d[i] = vdev_id; 287 break; 288 } 289 } 290 psoc_priv_obj->vdev_cnt_11d++; 291 } 292 293 if ((op_mode == QDF_P2P_GO_MODE) || (op_mode == QDF_SAP_MODE)) { 294 reg_debug("running 11d state machine, opmode %d", op_mode); 295 psoc_priv_obj->master_vdev_cnt++; 296 reg_run_11d_state_machine(parent_psoc); 297 } 298 299 return QDF_STATUS_SUCCESS; 300 } 301 302 QDF_STATUS reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev) 303 { 304 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 305 struct wlan_objmgr_pdev *parent_pdev; 306 struct wlan_objmgr_psoc *parent_psoc; 307 enum QDF_OPMODE op_mode; 308 uint32_t vdev_id; 309 uint8_t i; 310 311 if (!vdev) { 312 reg_err("NULL vdev"); 313 return QDF_STATUS_E_INVAL; 314 } 315 op_mode = wlan_vdev_mlme_get_opmode(vdev); 316 317 parent_pdev = wlan_vdev_get_pdev(vdev); 318 parent_psoc = wlan_pdev_get_psoc(parent_pdev); 319 320 psoc_priv_obj = reg_get_psoc_obj(parent_psoc); 321 if (!psoc_priv_obj) { 322 reg_err("NULL reg psoc private obj"); 323 return QDF_STATUS_E_FAULT; 324 } 325 326 if ((op_mode == QDF_P2P_GO_MODE) || (op_mode == QDF_SAP_MODE)) { 327 psoc_priv_obj->master_vdev_cnt--; 328 reg_debug("run 11d state machine, deleted opmode %d", 329 op_mode); 330 reg_run_11d_state_machine(parent_psoc); 331 return QDF_STATUS_SUCCESS; 332 } 333 334 if ((op_mode == QDF_STA_MODE) || (op_mode == QDF_P2P_DEVICE_MODE) || 335 (op_mode == QDF_P2P_CLIENT_MODE)) { 336 vdev_id = wlan_vdev_get_id(vdev); 337 for (i = 0; i < MAX_STA_VDEV_CNT; i++) { 338 if (psoc_priv_obj->vdev_ids_11d[i] == vdev_id) { 339 psoc_priv_obj->vdev_ids_11d[i] = 340 INVALID_VDEV_ID; 341 psoc_priv_obj->vdev_cnt_11d--; 342 break; 343 } 344 } 345 346 if (psoc_priv_obj->vdev_id_for_11d_scan != vdev_id) 347 return QDF_STATUS_SUCCESS; 348 349 if (!psoc_priv_obj->vdev_cnt_11d) { 350 psoc_priv_obj->vdev_id_for_11d_scan = INVALID_VDEV_ID; 351 psoc_priv_obj->enable_11d_supp = false; 352 return QDF_STATUS_SUCCESS; 353 } 354 355 for (i = 0; i < MAX_STA_VDEV_CNT; i++) { 356 if (psoc_priv_obj->vdev_ids_11d[i] == INVALID_VDEV_ID) 357 continue; 358 psoc_priv_obj->vdev_id_for_11d_scan = 359 psoc_priv_obj->vdev_ids_11d[i]; 360 psoc_priv_obj->enable_11d_supp = false; 361 reg_debug("running 11d state machine, vdev %d", 362 psoc_priv_obj->vdev_id_for_11d_scan); 363 reg_run_11d_state_machine(parent_psoc); 364 break; 365 } 366 } 367 368 return QDF_STATUS_SUCCESS; 369 } 370 371 bool reg_is_11d_scan_inprogress(struct wlan_objmgr_psoc *psoc) 372 { 373 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 374 375 psoc_priv_obj = reg_get_psoc_obj(psoc); 376 if (!psoc_priv_obj) { 377 reg_err("NULL reg psoc private obj"); 378 return false; 379 } 380 381 return psoc_priv_obj->enable_11d_supp; 382 } 383 384 QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc, 385 uint8_t *country) 386 { 387 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 388 struct wlan_lmac_if_reg_tx_ops *tx_ops; 389 struct set_country country_code; 390 uint8_t pdev_id; 391 uint8_t ctr; 392 393 psoc_priv_obj = reg_get_psoc_obj(psoc); 394 if (!psoc_priv_obj) { 395 reg_err("NULL reg psoc private obj"); 396 397 return QDF_STATUS_E_FAILURE; 398 } 399 400 /* 401 * Need firmware to send channel list event 402 * for all phys. Therefore set pdev_id to 0xFF 403 */ 404 pdev_id = 0xFF; 405 for (ctr = 0; ctr < psoc_priv_obj->num_phy; ctr++) 406 psoc_priv_obj->new_11d_ctry_pending[ctr] = true; 407 408 qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1); 409 country_code.pdev_id = pdev_id; 410 411 if (psoc_priv_obj->offload_enabled) { 412 tx_ops = reg_get_psoc_tx_ops(psoc); 413 if (tx_ops->set_country_code) { 414 tx_ops->set_country_code(psoc, &country_code); 415 } else { 416 reg_err("NULL country set handler"); 417 for (ctr = 0; ctr < psoc_priv_obj->num_phy; ctr++) 418 psoc_priv_obj->new_11d_ctry_pending[ctr] = 419 false; 420 return QDF_STATUS_E_FAULT; 421 } 422 } 423 424 return QDF_STATUS_SUCCESS; 425 } 426 427 bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc) 428 { 429 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 430 431 psoc_priv_obj = reg_get_psoc_obj(psoc); 432 if (!psoc_priv_obj) { 433 reg_err("NULL reg psoc private obj"); 434 return QDF_STATUS_E_FAILURE; 435 } 436 437 return (psoc_priv_obj->enable_11d_supp && 438 !psoc_priv_obj->is_11d_offloaded); 439 } 440 441 QDF_STATUS reg_set_11d_offloaded(struct wlan_objmgr_psoc *psoc, bool val) 442 { 443 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 444 445 psoc_priv_obj = reg_get_psoc_obj(psoc); 446 if (!psoc_priv_obj) { 447 reg_err("NULL psoc reg component"); 448 return QDF_STATUS_E_FAILURE; 449 } 450 451 psoc_priv_obj->is_11d_offloaded = val; 452 reg_debug("set is_11d_offloaded %d", val); 453 return QDF_STATUS_SUCCESS; 454 } 455 456 bool reg_is_11d_offloaded(struct wlan_objmgr_psoc *psoc) 457 { 458 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; 459 460 psoc_priv_obj = reg_get_psoc_obj(psoc); 461 if (!psoc_priv_obj) { 462 reg_err("NULL reg psoc private obj"); 463 return false; 464 } 465 466 return psoc_priv_obj->is_11d_offloaded; 467 } 468 #endif 469