1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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 #include "osif_vdev_sync.h" 19 #include "wlan_hdd_hostapd.h" 20 #include "wlan_hdd_pre_cac.h" 21 #include <qdf_types.h> 22 #include "osif_pre_cac.h" 23 #include "wlan_pre_cac_ucfg_api.h" 24 #include "wlan_ipa_ucfg_api.h" 25 #include "wlan_hdd_son.h" 26 #include "wlan_dp_ucfg_api.h" 27 28 /** 29 * wlan_hdd_pre_cac_failure() - Process the pre cac failure 30 * @adapter: AP adapter 31 * 32 * Deletes the pre cac adapter 33 * 34 * Return: None 35 */ 36 static void wlan_hdd_pre_cac_failure(struct hdd_adapter *adapter) 37 { 38 struct hdd_context *hdd_ctx; 39 40 hdd_enter(); 41 42 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 43 if (wlan_hdd_validate_context(hdd_ctx)) 44 return; 45 46 wlan_hdd_stop_sap(adapter); 47 hdd_stop_adapter(hdd_ctx, adapter); 48 49 hdd_exit(); 50 } 51 52 /** 53 * wlan_hdd_pre_cac_success() - Process the pre cac result 54 * @adapter: AP adapter 55 * 56 * Stops the pre cac adapter and moves the existing SAP to the pre cac 57 * channel 58 * 59 * Return: None 60 */ 61 static void wlan_hdd_pre_cac_success(struct hdd_adapter *adapter) 62 { 63 struct hdd_adapter *ap_adapter; 64 int i; 65 struct hdd_context *hdd_ctx; 66 enum phy_ch_width pre_cac_ch_width; 67 qdf_freq_t chan_freq; 68 69 hdd_enter(); 70 71 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 72 if (!hdd_ctx) { 73 hdd_err("HDD context is null"); 74 return; 75 } 76 77 pre_cac_ch_width = wlansap_get_chan_width( 78 WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink)); 79 80 hdd_stop_adapter(hdd_ctx, adapter); 81 82 /* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */ 83 ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); 84 if (!ap_adapter) { 85 hdd_err("failed to get SAP adapter, no restart on pre CAC channel"); 86 return; 87 } 88 89 /* 90 * Setting of the pre cac complete status will ensure that on channel 91 * switch to the pre CAC DFS channel, there is no CAC again. 92 */ 93 ucfg_pre_cac_complete_set(ap_adapter->deflink->vdev, true); 94 95 wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->deflink->vdev_id, 96 CSA_REASON_PRE_CAC_SUCCESS); 97 chan_freq = ucfg_pre_cac_get_freq(ap_adapter->deflink->vdev); 98 i = hdd_softap_set_channel_change(ap_adapter->dev, 99 chan_freq, 100 pre_cac_ch_width, false); 101 if (i) { 102 hdd_err("failed to change channel"); 103 ucfg_pre_cac_complete_set(ap_adapter->deflink->vdev, false); 104 } 105 106 hdd_exit(); 107 } 108 109 void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx) 110 { 111 struct hdd_adapter *pre_cac_adapter; 112 struct osif_vdev_sync *vdev_sync; 113 int errno; 114 115 pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx, 116 SAP_PRE_CAC_IFNAME); 117 if (!pre_cac_adapter) 118 return; 119 120 ucfg_pre_cac_clear_work(hdd_ctx->psoc); 121 errno = osif_vdev_sync_trans_start_wait(pre_cac_adapter->dev, 122 &vdev_sync); 123 if (errno) 124 return; 125 126 osif_vdev_sync_unregister(pre_cac_adapter->dev); 127 osif_vdev_sync_wait_for_ops(vdev_sync); 128 129 wlan_hdd_release_intf_addr(hdd_ctx, pre_cac_adapter->mac_addr.bytes); 130 pre_cac_adapter->is_virtual_iface = true; 131 hdd_close_adapter(hdd_ctx, pre_cac_adapter, true); 132 133 osif_vdev_sync_trans_stop(vdev_sync); 134 osif_vdev_sync_destroy(vdev_sync); 135 } 136 137 static int wlan_set_def_pre_cac_chan(struct hdd_context *hdd_ctx, 138 uint32_t pre_cac_ch_freq, 139 struct cfg80211_chan_def *chandef, 140 enum nl80211_channel_type *chantype, 141 enum phy_ch_width *ch_width) 142 { 143 enum nl80211_channel_type channel_type; 144 struct ieee80211_channel *ieee_chan; 145 struct ch_params ch_params = {0}; 146 147 ieee_chan = ieee80211_get_channel(hdd_ctx->wiphy, 148 pre_cac_ch_freq); 149 if (!ieee_chan) { 150 hdd_err("channel conversion failed %d", pre_cac_ch_freq); 151 return -EINVAL; 152 } 153 ch_params.ch_width = *ch_width; 154 wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, 155 pre_cac_ch_freq, 0, 156 &ch_params, 157 REG_CURRENT_PWR_MODE); 158 switch (ch_params.sec_ch_offset) { 159 case HIGH_PRIMARY_CH: 160 channel_type = NL80211_CHAN_HT40MINUS; 161 break; 162 case LOW_PRIMARY_CH: 163 channel_type = NL80211_CHAN_HT40PLUS; 164 break; 165 default: 166 channel_type = NL80211_CHAN_HT20; 167 break; 168 } 169 cfg80211_chandef_create(chandef, ieee_chan, channel_type); 170 switch (ch_params.ch_width) { 171 case CH_WIDTH_80MHZ: 172 chandef->width = NL80211_CHAN_WIDTH_80; 173 break; 174 case CH_WIDTH_80P80MHZ: 175 chandef->width = NL80211_CHAN_WIDTH_80P80; 176 if (ch_params.mhz_freq_seg1) 177 chandef->center_freq2 = ch_params.mhz_freq_seg1; 178 break; 179 case CH_WIDTH_160MHZ: 180 chandef->width = NL80211_CHAN_WIDTH_160; 181 break; 182 default: 183 break; 184 } 185 if (ch_params.ch_width == CH_WIDTH_80MHZ || 186 ch_params.ch_width == CH_WIDTH_80P80MHZ || 187 ch_params.ch_width == CH_WIDTH_160MHZ) { 188 if (ch_params.mhz_freq_seg0) 189 chandef->center_freq1 = ch_params.mhz_freq_seg0; 190 } 191 *chantype = channel_type; 192 *ch_width = ch_params.ch_width; 193 hdd_debug("pre cac ch def: chan:%d width:%d freq1:%d freq2:%d", 194 chandef->chan->center_freq, chandef->width, 195 chandef->center_freq1, chandef->center_freq2); 196 197 return 0; 198 } 199 200 /** 201 * __wlan_hdd_request_pre_cac() - Start pre CAC in the driver 202 * @hdd_ctx: the HDD context to operate against 203 * @chan_freq: Channel frequency option provided by userspace 204 * @out_adapter: out parameter for the newly created pre-cac adapter 205 * 206 * Sets the driver to the required hardware mode and start an adapter for 207 * pre CAC which will mimic an AP. 208 * 209 * Return: Zero on success, non-zero value on error 210 */ 211 static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, 212 uint32_t chan_freq, 213 struct hdd_adapter **out_adapter) 214 { 215 uint8_t *mac_addr = NULL; 216 uint32_t pre_cac_chan_freq = 0; 217 int ret; 218 struct hdd_adapter *ap_adapter, *pre_cac_adapter = NULL; 219 struct hdd_ap_ctx *hdd_ap_ctx, *pre_cac_ap_ctx; 220 QDF_STATUS status; 221 struct wiphy *wiphy; 222 struct net_device *dev; 223 struct cfg80211_chan_def chandef; 224 enum nl80211_channel_type channel_type; 225 mac_handle_t mac_handle; 226 enum phy_ch_width cac_ch_width; 227 struct hdd_adapter_create_param params = {0}; 228 struct wlan_hdd_link_info *pre_cac_link_info, *link_info; 229 bool is_rtnl_locked = false; 230 231 if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc)) { 232 hdd_debug("Pre CAC is not supported on non-dbs platforms"); 233 return -EINVAL; 234 } 235 236 if (policy_mgr_get_connection_count(hdd_ctx->psoc) > 1) { 237 hdd_err("pre cac not allowed in concurrency"); 238 return -EINVAL; 239 } 240 241 ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); 242 if (!ap_adapter) { 243 hdd_err("unable to get SAP adapter"); 244 return -EINVAL; 245 } 246 247 link_info = ap_adapter->deflink; 248 hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); 249 250 if (qdf_atomic_read(&hdd_ap_ctx->ch_switch_in_progress)) { 251 hdd_err("pre cac not allowed during CSA"); 252 return -EINVAL; 253 } 254 255 mac_handle = hdd_ctx->mac_handle; 256 257 if (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, 258 hdd_ap_ctx->operating_chan_freq)) { 259 hdd_err("SAP is already on DFS channel:%d", 260 hdd_ap_ctx->operating_chan_freq); 261 return -EINVAL; 262 } 263 264 if (!WLAN_REG_IS_24GHZ_CH_FREQ(hdd_ap_ctx->operating_chan_freq)) { 265 hdd_err("pre CAC allowed only when SAP is in 2.4GHz:%d", 266 hdd_ap_ctx->operating_chan_freq); 267 return -EINVAL; 268 } 269 270 cac_ch_width = wlansap_get_max_bw_by_phymode(hdd_ap_ctx->sap_context); 271 if (cac_ch_width > DEFAULT_PRE_CAC_BANDWIDTH) 272 cac_ch_width = DEFAULT_PRE_CAC_BANDWIDTH; 273 if (chan_freq) { 274 qdf_mem_zero(&chandef, sizeof(struct cfg80211_chan_def)); 275 if (wlan_set_def_pre_cac_chan(hdd_ctx, chan_freq, &chandef, 276 &channel_type, &cac_ch_width)) { 277 hdd_err("failed to set pre_cac channel %d", chan_freq); 278 return -EINVAL; 279 } 280 } 281 hdd_debug("channel: %d bw: %d", chan_freq, cac_ch_width); 282 283 ret = ucfg_pre_cac_validate_and_get_freq(hdd_ctx->pdev, chan_freq, 284 &pre_cac_chan_freq, 285 cac_ch_width); 286 if (ret != 0) { 287 hdd_err("can't validate pre-cac channel"); 288 goto release_intf_addr_and_return_failure; 289 } 290 291 hdd_debug("starting pre cac SAP adapter"); 292 293 mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE); 294 if (!mac_addr) { 295 hdd_err("can't add virtual intf: Not getting valid mac addr"); 296 return -EINVAL; 297 } 298 299 /** 300 * Starting a SAP adapter: 301 * Instead of opening an adapter, we could just do a SME open 302 * session for AP type. But, start BSS would still need an 303 * adapter. So, this option is not taken. 304 * 305 * hdd open adapter is going to register this precac interface 306 * with user space. This interface though exposed to user space 307 * will be in DOWN state. Consideration was done to avoid this 308 * registration to the user space. But, as part of SAP 309 * operations multiple events are sent to user space. Some of 310 * these events received from unregistered interface was 311 * causing crashes. So, retaining the registration. 312 * 313 * So, this interface would remain registered and will remain 314 * in DOWN state for the CAC duration. We will add notes in the 315 * feature announcement to not use this temporary interface for 316 * any activity from user space. 317 */ 318 319 params.is_add_virtual_iface = 1; 320 params.is_pre_cac_adapter = 1; 321 if (rtnl_trylock()) { 322 pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, 323 SAP_PRE_CAC_IFNAME, 324 mac_addr, NET_NAME_UNKNOWN, 325 true, ¶ms); 326 rtnl_unlock(); 327 } 328 329 if (!pre_cac_adapter) { 330 hdd_err("error opening the pre cac adapter"); 331 goto release_intf_addr_and_return_failure; 332 } 333 334 pre_cac_link_info = pre_cac_adapter->deflink; 335 pre_cac_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(pre_cac_link_info); 336 sap_clear_global_dfs_param(mac_handle, pre_cac_ap_ctx->sap_context); 337 338 /* 339 * This interface is internally created by the driver. So, no interface 340 * up comes for this interface from user space and hence starting 341 * the adapter internally. 342 */ 343 if (hdd_start_adapter(pre_cac_adapter, false)) { 344 hdd_err("error starting the pre cac adapter"); 345 goto close_pre_cac_adapter; 346 } 347 348 hdd_debug("preparing for start ap/bss on the pre cac adapter"); 349 350 wiphy = hdd_ctx->wiphy; 351 dev = pre_cac_adapter->dev; 352 353 /* Since this is only a dummy interface lets us use the IEs from the 354 * other active SAP interface. In regular scenarios, these IEs would 355 * come from the user space entity 356 */ 357 pre_cac_ap_ctx->beacon = qdf_mem_malloc(sizeof(*hdd_ap_ctx->beacon)); 358 if (!pre_cac_ap_ctx->beacon) 359 goto stop_close_pre_cac_adapter; 360 361 qdf_mem_copy(pre_cac_ap_ctx->beacon, hdd_ap_ctx->beacon, 362 sizeof(*pre_cac_ap_ctx->beacon)); 363 pre_cac_ap_ctx->sap_config.authType = hdd_ap_ctx->sap_config.authType; 364 pre_cac_ap_ctx->sap_config.ch_width_orig = 365 hdd_ap_ctx->sap_config.ch_width_orig; 366 367 /* The original premise is that on moving from 2.4GHz to 5GHz, the SAP 368 * will continue to operate on the same bandwidth as that of the 2.4GHz 369 * operations. Only bandwidths 20MHz/40MHz are possible on 2.4GHz band. 370 * Now some customer request to start AP on higher BW such as 80Mhz. 371 * Hence use max possible supported BW based on phymode configurated 372 * on SAP. 373 */ 374 cac_ch_width = wlansap_get_max_bw_by_phymode(hdd_ap_ctx->sap_context); 375 if (cac_ch_width > DEFAULT_PRE_CAC_BANDWIDTH) 376 cac_ch_width = DEFAULT_PRE_CAC_BANDWIDTH; 377 378 qdf_mem_zero(&chandef, sizeof(struct cfg80211_chan_def)); 379 if (wlan_set_def_pre_cac_chan(hdd_ctx, pre_cac_chan_freq, &chandef, 380 &channel_type, &cac_ch_width)) { 381 hdd_err("error set pre_cac channel %d", pre_cac_chan_freq); 382 goto close_pre_cac_adapter; 383 } 384 pre_cac_ap_ctx->sap_config.ch_width_orig = 385 hdd_map_nl_chan_width(chandef.width); 386 387 hdd_debug("existing ap phymode:%d pre cac ch_width:%d freq:%d", 388 hdd_ap_ctx->sap_config.SapHw_mode, 389 cac_ch_width, pre_cac_chan_freq); 390 /* 391 * Doing update after opening and starting pre-cac adapter will make 392 * sure that driver won't do hardware mode change if there are any 393 * initial hick-ups or issues in pre-cac adapter's configuration. 394 * Since current SAP is in 2.4GHz and pre CAC channel is in 5GHz, this 395 * connection update should result in DBS mode 396 */ 397 status = policy_mgr_update_and_wait_for_connection_update( 398 hdd_ctx->psoc, 399 link_info->vdev_id, 400 pre_cac_chan_freq, 401 POLICY_MGR_UPDATE_REASON_PRE_CAC); 402 if (QDF_IS_STATUS_ERROR(status)) { 403 hdd_err("error in moving to DBS mode"); 404 goto stop_close_pre_cac_adapter; 405 } 406 407 ret = wlan_hdd_set_channel(wiphy, dev, &chandef, channel_type); 408 if (ret != 0) { 409 hdd_err("failed to set channel"); 410 goto stop_close_pre_cac_adapter; 411 } 412 413 status = wlan_hdd_cfg80211_start_bss(pre_cac_link_info, 414 NULL, PRE_CAC_SSID, 415 qdf_str_len(PRE_CAC_SSID), 416 NL80211_HIDDEN_SSID_NOT_IN_USE, 417 false); 418 if (QDF_IS_STATUS_ERROR(status)) { 419 hdd_err("start bss failed"); 420 goto stop_close_pre_cac_adapter; 421 } 422 423 /* 424 * The pre cac status is set here. But, it would not be reset explicitly 425 * anywhere, since after the pre cac success/failure, the pre cac 426 * adapter itself would be removed. 427 */ 428 ret = ucfg_pre_cac_set_status(pre_cac_link_info->vdev, true); 429 if (ret != 0) { 430 hdd_err("failed to set pre cac status"); 431 goto stop_close_pre_cac_adapter; 432 } 433 434 ucfg_pre_cac_set_freq_before_pre_cac(link_info->vdev, 435 hdd_ap_ctx->operating_chan_freq); 436 ucfg_pre_cac_set_freq(link_info->vdev, pre_cac_chan_freq); 437 ucfg_pre_cac_adapter_set(pre_cac_link_info->vdev, true); 438 *out_adapter = pre_cac_adapter; 439 440 return 0; 441 442 stop_close_pre_cac_adapter: 443 pre_cac_adapter->is_virtual_iface = true; 444 hdd_stop_adapter(hdd_ctx, pre_cac_adapter); 445 qdf_mem_free(pre_cac_ap_ctx->beacon); 446 pre_cac_ap_ctx->beacon = NULL; 447 close_pre_cac_adapter: 448 if (rtnl_trylock()) 449 is_rtnl_locked = true; 450 451 hdd_close_adapter(hdd_ctx, pre_cac_adapter, true); 452 453 if (is_rtnl_locked) 454 rtnl_unlock(); 455 release_intf_addr_and_return_failure: 456 /* 457 * Release the interface address as the adapter 458 * failed to start, if you don't release then next 459 * adapter which is trying to come wouldn't get valid 460 * mac address. Remember we have limited pool of mac addresses 461 */ 462 if (mac_addr) 463 wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); 464 return -EINVAL; 465 } 466 467 static int 468 wlan_hdd_start_pre_cac_trans(struct hdd_context *hdd_ctx, 469 struct osif_vdev_sync **out_vdev_sync, 470 bool *is_vdev_sync_created) 471 { 472 struct hdd_adapter *adapter, *next_adapter = NULL; 473 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_START_PRE_CAC_TRANS; 474 int errno; 475 476 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 477 dbgid) { 478 if (!qdf_str_cmp(adapter->dev->name, SAP_PRE_CAC_IFNAME)) { 479 errno = osif_vdev_sync_trans_start(adapter->dev, 480 out_vdev_sync); 481 482 hdd_adapter_dev_put_debug(adapter, dbgid); 483 if (next_adapter) 484 hdd_adapter_dev_put_debug(next_adapter, 485 dbgid); 486 return errno; 487 } 488 hdd_adapter_dev_put_debug(adapter, dbgid); 489 } 490 491 errno = osif_vdev_sync_create_and_trans(hdd_ctx->parent_dev, 492 out_vdev_sync); 493 if (errno) 494 return errno; 495 496 *is_vdev_sync_created = true; 497 return 0; 498 } 499 500 int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq) 501 { 502 struct hdd_adapter *adapter; 503 struct osif_vdev_sync *vdev_sync; 504 int errno; 505 bool is_vdev_sync_created = false; 506 507 errno = wlan_hdd_start_pre_cac_trans(hdd_ctx, &vdev_sync, 508 &is_vdev_sync_created); 509 if (errno) 510 return errno; 511 512 errno = __wlan_hdd_request_pre_cac(hdd_ctx, chan_freq, &adapter); 513 if (errno) 514 goto destroy_sync; 515 516 if (is_vdev_sync_created) 517 osif_vdev_sync_register(adapter->dev, vdev_sync); 518 osif_vdev_sync_trans_stop(vdev_sync); 519 520 return 0; 521 522 destroy_sync: 523 osif_vdev_sync_trans_stop(vdev_sync); 524 if (is_vdev_sync_created) 525 osif_vdev_sync_destroy(vdev_sync); 526 527 return errno; 528 } 529 530 static void 531 wlan_hdd_pre_cac_conditional_freq_switch_ind(struct wlan_objmgr_vdev *vdev, 532 bool completed) 533 { 534 struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); 535 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; 536 struct hdd_adapter *adapter; 537 struct wlan_hdd_link_info *link_info; 538 struct hdd_ap_ctx *ap_ctx; 539 540 link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); 541 if (!link_info) { 542 hdd_err("Invalid vdev"); 543 return; 544 } 545 546 adapter = link_info->adapter; 547 if (completed) { 548 ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); 549 ap_ctx->dfs_cac_block_tx = false; 550 ucfg_ipa_set_dfs_cac_tx(adapter->hdd_ctx->pdev, 551 ap_ctx->dfs_cac_block_tx); 552 ucfg_dp_set_dfs_cac_tx(vdev, ap_ctx->dfs_cac_block_tx); 553 adapter->hdd_ctx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; 554 } else { 555 adapter->hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; 556 hdd_son_deliver_cac_status_event(adapter, 557 ucfg_pre_cac_get_freq(vdev), 558 true); 559 } 560 } 561 562 static void 563 wlan_hdd_pre_cac_complete(struct wlan_objmgr_psoc *psoc, 564 uint8_t vdev_id, 565 QDF_STATUS status) 566 { 567 struct wlan_hdd_link_info *link_info; 568 569 link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); 570 if (!link_info) { 571 hdd_err("Invalid vdev %d", vdev_id); 572 return; 573 } 574 575 if (QDF_IS_STATUS_SUCCESS(status)) 576 wlan_hdd_pre_cac_success(link_info->adapter); 577 else 578 wlan_hdd_pre_cac_failure(link_info->adapter); 579 } 580 581 struct osif_pre_cac_legacy_ops pre_cac_legacy_ops = { 582 .conditional_csa_ind_legacy_cb = 583 wlan_hdd_pre_cac_conditional_freq_switch_ind, 584 .pre_cac_complete_legacy_cb = wlan_hdd_pre_cac_complete, 585 }; 586 587 QDF_STATUS hdd_pre_cac_register_cb(void) 588 { 589 osif_pre_cac_set_legacy_cb(&pre_cac_legacy_ops); 590 591 return osif_pre_cac_register_cb(); 592 } 593 594 void hdd_pre_cac_unregister_cb(void) 595 { 596 osif_pre_cac_reset_legacy_cb(); 597 } 598