1 /* 2 * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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: hdd_cm_disconnect.c 20 * 21 * WLAN Host Device Driver disconnect APIs implementation 22 * 23 */ 24 25 #include "wlan_hdd_main.h" 26 #include "wlan_hdd_object_manager.h" 27 #include "wlan_hdd_trace.h" 28 #include <osif_cm_req.h> 29 #include "wlan_hdd_cm_api.h" 30 #include "wlan_ipa_ucfg_api.h" 31 #include "wlan_hdd_stats.h" 32 #include "wlan_hdd_scan.h" 33 #include "sme_power_save_api.h" 34 #include <wlan_logging_sock_svc.h> 35 #include "wlan_hdd_ftm_time_sync.h" 36 #include "wlan_hdd_bcn_recv.h" 37 #include "wlan_hdd_assoc.h" 38 #include "wlan_hdd_ipa.h" 39 #include "wlan_hdd_green_ap.h" 40 #include "wlan_hdd_lpass.h" 41 #include "wlan_hdd_bootup_marker.h" 42 #include "wlan_p2p_ucfg_api.h" 43 #include "wlan_crypto_global_api.h" 44 #include "wlan_mlme_vdev_mgr_interface.h" 45 #include "hif.h" 46 #include "wlan_hdd_power.h" 47 #include "wlan_hdd_napi.h" 48 #include "wlan_hdd_cfr.h" 49 #include "wlan_roam_debug.h" 50 #include "wma_api.h" 51 #include "wlan_hdd_hostapd.h" 52 #include "wlan_dp_ucfg_api.h" 53 #include "wma.h" 54 55 void hdd_handle_disassociation_event(struct wlan_hdd_link_info *link_info, 56 struct qdf_mac_addr *peer_macaddr) 57 { 58 struct hdd_adapter *adapter = link_info->adapter; 59 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 60 struct hdd_station_ctx *sta_ctx; 61 ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); 62 struct wlan_objmgr_vdev *vdev; 63 64 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); 65 hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, false); 66 67 wlan_hdd_auto_shutdown_enable(hdd_ctx, true); 68 69 if ((adapter->device_mode == QDF_STA_MODE) || 70 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) 71 /* send peer status indication to oem app */ 72 hdd_send_peer_status_ind_to_app(peer_macaddr, 73 ePeerDisconnected, 0, 74 link_info->vdev_id, NULL, 75 adapter->device_mode); 76 77 hdd_lpass_notify_disconnect(link_info); 78 79 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); 80 if (vdev) { 81 ucfg_dp_del_latency_critical_client(vdev, 82 hdd_convert_cfgdot11mode_to_80211mode( 83 sta_ctx->conn_info.dot11mode)); 84 /* stop timer in sta/p2p_cli */ 85 ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(vdev); 86 hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); 87 } 88 89 ucfg_dp_bus_bw_compute_timer_try_stop(hdd_ctx->psoc); 90 cdp_display_txrx_hw_info(soc); 91 } 92 93 /** 94 * hdd_cm_print_bss_info() - print bss info 95 * @hdd_sta_ctx: pointer to hdd station context 96 * 97 * Return: None 98 */ 99 static void hdd_cm_print_bss_info(struct hdd_station_ctx *hdd_sta_ctx) 100 { 101 uint32_t *ht_cap_info; 102 uint32_t *vht_cap_info; 103 struct hdd_connection_info *conn_info; 104 105 conn_info = &hdd_sta_ctx->conn_info; 106 107 hdd_nofl_debug("*********** WIFI DATA LOGGER **************"); 108 hdd_nofl_debug("freq: %d dot11mode %d AKM %d ssid: \"" QDF_SSID_FMT "\" ,roam_count %d nss %d legacy %d mcs %d signal %d noise: %d", 109 conn_info->chan_freq, conn_info->dot11mode, 110 conn_info->last_auth_type, 111 QDF_SSID_REF(conn_info->last_ssid.SSID.length, 112 conn_info->last_ssid.SSID.ssId), 113 conn_info->roam_count, 114 conn_info->txrate.nss, conn_info->txrate.legacy, 115 conn_info->txrate.mcs, conn_info->signal, 116 conn_info->noise); 117 ht_cap_info = (uint32_t *)&conn_info->ht_caps; 118 vht_cap_info = (uint32_t *)&conn_info->vht_caps; 119 hdd_nofl_debug("HT 0x%x VHT 0x%x ht20 info 0x%x", 120 conn_info->conn_flag.ht_present ? *ht_cap_info : 0, 121 conn_info->conn_flag.vht_present ? *vht_cap_info : 0, 122 conn_info->conn_flag.hs20_present ? 123 conn_info->hs20vendor_ie.release_num : 0); 124 } 125 126 void 127 __hdd_cm_disconnect_handler_pre_user_update(struct wlan_hdd_link_info *link_info) 128 { 129 struct hdd_adapter *adapter = link_info->adapter; 130 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 131 struct hdd_station_ctx *sta_ctx; 132 uint32_t time_buffer_size; 133 struct wlan_objmgr_vdev *vdev; 134 135 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); 136 hdd_stop_tsf_sync(adapter); 137 time_buffer_size = sizeof(sta_ctx->conn_info.connect_time); 138 qdf_mem_zero(sta_ctx->conn_info.connect_time, time_buffer_size); 139 if (ucfg_ipa_is_enabled() && 140 QDF_IS_STATUS_SUCCESS(wlan_hdd_validate_mac_address( 141 &sta_ctx->conn_info.bssid))) 142 ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, 143 adapter->device_mode, 144 link_info->vdev_id, 145 WLAN_IPA_STA_DISCONNECT, 146 sta_ctx->conn_info.bssid.bytes, 147 false); 148 149 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); 150 if (vdev) { 151 ucfg_dp_periodic_sta_stats_stop(vdev); 152 hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); 153 } 154 155 wlan_hdd_auto_shutdown_enable(hdd_ctx, true); 156 157 DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, 158 link_info->vdev_id, 159 QDF_TRACE_DEFAULT_PDEV_ID, 160 QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); 161 162 hdd_wmm_dscp_initial_state(adapter); 163 wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID); 164 165 hdd_place_marker(adapter, "DISCONNECTED", NULL); 166 } 167 168 void 169 __hdd_cm_disconnect_handler_post_user_update(struct wlan_hdd_link_info *link_info, 170 struct wlan_objmgr_vdev *vdev, 171 enum wlan_cm_source source) 172 { 173 struct hdd_adapter *adapter = link_info->adapter; 174 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 175 struct hdd_station_ctx *sta_ctx; 176 mac_handle_t mac_handle; 177 struct hdd_adapter *link_adapter; 178 struct hdd_station_ctx *link_sta_ctx; 179 bool is_link_switch = 180 wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev); 181 182 mac_handle = hdd_ctx->mac_handle; 183 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); 184 185 /* update P2P connection status */ 186 ucfg_p2p_status_disconnect(vdev); 187 hdd_cfr_disconnect(vdev); 188 189 hdd_wmm_adapter_clear(adapter); 190 ucfg_cm_ft_reset(vdev); 191 ucfg_cm_reset_key(hdd_ctx->pdev, link_info->vdev_id); 192 hdd_clear_roam_profile_ie(adapter); 193 194 if (adapter->device_mode == QDF_STA_MODE) 195 wlan_crypto_reset_vdev_params(vdev); 196 197 hdd_remove_beacon_filter(adapter); 198 if (sme_is_beacon_report_started(mac_handle, link_info->vdev_id)) { 199 hdd_debug("Sending beacon pause indication to userspace"); 200 hdd_beacon_recv_pause_indication((hdd_handle_t)hdd_ctx, 201 link_info->vdev_id, 202 SCAN_EVENT_TYPE_MAX, true); 203 } 204 205 if (adapter->device_mode == QDF_STA_MODE && 206 hdd_adapter_is_ml_adapter(adapter)) { 207 /* Clear connection info in assoc link adapter as well */ 208 link_adapter = hdd_get_assoc_link_adapter(adapter); 209 if (link_adapter) { 210 link_sta_ctx = 211 WLAN_HDD_GET_STATION_CTX_PTR(link_adapter->deflink); 212 hdd_conn_remove_connect_info(link_sta_ctx); 213 } 214 } 215 216 if (!is_link_switch && source != CM_MLO_ROAM_INTERNAL_DISCONNECT) { 217 /* Clear saved connection information in HDD */ 218 hdd_conn_remove_connect_info(sta_ctx); 219 220 /* 221 * Reset the IEEE link ID to invalid when disconnect is not 222 * due to link switch. This API resets link id for all the 223 * valid link_info for the given adapter. So avoid this reset 224 * for Link Switch disconnect/internal disconnect 225 */ 226 hdd_adapter_reset_station_ctx(adapter); 227 } 228 229 ucfg_dp_remove_conn_info(vdev); 230 231 /* Setting the RTS profile to original value */ 232 if (sme_cli_set_command(link_info->vdev_id, 233 wmi_vdev_param_enable_rtscts, 234 cfg_get(hdd_ctx->psoc, 235 CFG_ENABLE_FW_RTS_PROFILE), 236 VDEV_CMD)) 237 hdd_debug("Failed to set RTS_PROFILE"); 238 239 hdd_init_scan_reject_params(hdd_ctx); 240 ucfg_pmo_flush_gtk_offload_req(vdev); 241 242 if ((QDF_STA_MODE == adapter->device_mode) || 243 (QDF_P2P_CLIENT_MODE == adapter->device_mode)) { 244 sme_ps_disable_auto_ps_timer(mac_handle, link_info->vdev_id); 245 adapter->send_mode_change = true; 246 } 247 wlan_hdd_clear_link_layer_stats(adapter); 248 249 ucfg_dp_reset_cont_txtimeout_cnt(vdev); 250 251 ucfg_dp_nud_reset_tracking(vdev); 252 hdd_reset_limit_off_chan(adapter); 253 254 hdd_cm_print_bss_info(sta_ctx); 255 } 256 257 #ifdef WLAN_FEATURE_MSCS 258 void reset_mscs_params(struct wlan_hdd_link_info *link_info) 259 { 260 mlme_set_is_mscs_req_sent(link_info->vdev, false); 261 link_info->mscs_counter = 0; 262 } 263 #endif 264 265 QDF_STATUS 266 wlan_hdd_cm_issue_disconnect(struct wlan_hdd_link_info *link_info, 267 enum wlan_reason_code reason, bool sync) 268 { 269 QDF_STATUS status; 270 struct wlan_objmgr_vdev *vdev; 271 struct hdd_station_ctx *sta_ctx; 272 struct hdd_adapter *adapter = link_info->adapter; 273 274 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); 275 if (!vdev) 276 return QDF_STATUS_E_INVAL; 277 278 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); 279 hdd_place_marker(adapter, "TRY TO DISCONNECT", NULL); 280 reset_mscs_params(link_info); 281 hdd_conn_set_authenticated(link_info, false); 282 wlan_hdd_netif_queue_control(adapter, 283 WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, 284 WLAN_CONTROL_PATH); 285 286 qdf_rtpm_sync_resume(); 287 288 wlan_rec_conn_info(link_info->vdev_id, DEBUG_CONN_DISCONNECT, 289 sta_ctx->conn_info.bssid.bytes, 0, reason); 290 291 if (sync) 292 status = osif_cm_disconnect_sync(vdev, reason); 293 else 294 status = osif_cm_disconnect(adapter->dev, vdev, reason); 295 296 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); 297 298 return status; 299 } 300 301 int wlan_hdd_cm_disconnect(struct wiphy *wiphy, 302 struct net_device *dev, u16 reason) 303 { 304 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 305 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 306 QDF_STATUS status; 307 int ret; 308 struct wlan_hdd_link_info *link_info = adapter->deflink; 309 310 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 311 hdd_err("Command not allowed in FTM mode"); 312 return -EINVAL; 313 } 314 315 ret = wlan_hdd_validate_context(hdd_ctx); 316 if (ret) 317 return ret; 318 319 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 320 return -EINVAL; 321 322 if (hdd_ctx->is_wiphy_suspended) { 323 hdd_info_rl("wiphy is suspended retry disconnect"); 324 return -EAGAIN; 325 } 326 327 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, 328 TRACE_CODE_HDD_CFG80211_DISCONNECT, 329 link_info->vdev_id, reason); 330 331 hdd_print_netdev_txq_status(dev); 332 333 if (reason == WLAN_REASON_DEAUTH_LEAVING) 334 qdf_dp_trace_dump_all( 335 WLAN_DEAUTH_DPTRACE_DUMP_COUNT, 336 QDF_TRACE_DEFAULT_PDEV_ID); 337 /* 338 * for Supplicant initiated disconnect always wait for complete, 339 * as for WPS connection or back to back connect, supplicant initiate a 340 * disconnect which is followed by connect and if kernel is not yet 341 * disconnected, this new connect will be rejected by kernel with status 342 * EALREADY. In case connect is rejected with EALREADY, supplicant will 343 * queue one more disconnect followed by connect immediately, Now if 344 * driver is not disconnected by this time, the kernel will again reject 345 * connect and thus the failing the connect req in supplicant. 346 * Thus we need to wait for disconnect to complete in this case, 347 * and thus use sync API here. 348 */ 349 status = wlan_hdd_cm_issue_disconnect(link_info, reason, true); 350 351 return qdf_status_to_os_return(status); 352 } 353 354 static QDF_STATUS 355 hdd_cm_disconnect_complete_pre_user_update(struct wlan_objmgr_vdev *vdev, 356 struct wlan_cm_discon_rsp *rsp) 357 { 358 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 359 struct hdd_adapter *adapter; 360 struct wlan_hdd_link_info *link_info; 361 362 if (!hdd_ctx) { 363 hdd_err("hdd_ctx is NULL"); 364 return QDF_STATUS_E_INVAL; 365 } 366 367 link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); 368 if (!link_info) { 369 hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); 370 return QDF_STATUS_E_INVAL; 371 } 372 373 adapter = link_info->adapter; 374 hdd_conn_set_authenticated(link_info, false); 375 hdd_napi_serialize(0); 376 hdd_disable_and_flush_mc_addr_list(adapter, pmo_peer_disconnect); 377 __hdd_cm_disconnect_handler_pre_user_update(link_info); 378 379 hdd_handle_disassociation_event(link_info, &rsp->req.req.bssid); 380 381 wlan_rec_conn_info(link_info->vdev_id, 382 DEBUG_CONN_DISCONNECT_HANDLER, 383 rsp->req.req.bssid.bytes, 384 rsp->req.cm_id, 385 rsp->req.req.reason_code << 16 | 386 rsp->req.req.source); 387 wlan_hdd_set_tx_flow_info(); 388 /* 389 * Convert and cache internal reason code in adapter. This can be 390 * sent to userspace with a vendor event. 391 */ 392 adapter->last_disconnect_reason = 393 osif_cm_mac_to_qca_reason(rsp->req.req.reason_code); 394 395 return QDF_STATUS_SUCCESS; 396 } 397 398 /** 399 * hdd_cm_set_default_wlm_mode - reset the default wlm mode if 400 * wlm_latency_reset_on_disconnect is set. 401 *@adapter: adapter pointer 402 * 403 * return: None. 404 */ 405 static void hdd_cm_set_default_wlm_mode(struct hdd_adapter *adapter) 406 { 407 QDF_STATUS status; 408 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 409 bool reset; 410 uint8_t def_level; 411 uint32_t client_id_bitmap; 412 413 if (!hdd_ctx) { 414 hdd_err("hdd_ctx is NULL"); 415 return; 416 } 417 418 status = ucfg_mlme_cfg_get_wlm_reset(hdd_ctx->psoc, &reset); 419 if (QDF_IS_STATUS_ERROR(status)) { 420 hdd_err("could not get wlm reset flag"); 421 return; 422 } 423 if (!reset) 424 return; 425 426 status = ucfg_mlme_cfg_get_wlm_level(hdd_ctx->psoc, &def_level); 427 if (QDF_IS_STATUS_ERROR(status)) 428 def_level = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL; 429 430 if (hdd_get_multi_client_ll_support(adapter)) { 431 client_id_bitmap = wlan_hdd_get_client_id_bitmap(adapter); 432 hdd_debug("client_id_bitmap: 0x%x", client_id_bitmap); 433 status = wlan_hdd_set_wlm_latency_level(adapter, def_level, 434 client_id_bitmap, true); 435 wlan_hdd_deinit_multi_client_info_table(adapter); 436 } else { 437 status = 438 sme_set_wlm_latency_level(hdd_ctx->mac_handle, 439 adapter->deflink->vdev_id, 440 def_level, 0, false); 441 if (QDF_IS_STATUS_SUCCESS(status)) { 442 hdd_debug("reset wlm mode %x on disconnection", 443 def_level); 444 adapter->latency_level = def_level; 445 } else { 446 hdd_err("reset wlm mode failed: %d", status); 447 } 448 } 449 } 450 451 /** 452 * hdd_cm_reset_udp_qos_upgrade_config() - Reset the threshold for UDP packet 453 * QoS upgrade. 454 * @adapter: adapter for which this configuration is to be applied 455 * 456 * Return: None 457 */ 458 static void hdd_cm_reset_udp_qos_upgrade_config(struct hdd_adapter *adapter) 459 { 460 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 461 bool reset; 462 QDF_STATUS status; 463 464 if (!hdd_ctx) { 465 hdd_err("hdd_ctx is NULL"); 466 return; 467 } 468 469 status = ucfg_mlme_cfg_get_wlm_reset(hdd_ctx->psoc, &reset); 470 if (QDF_IS_STATUS_ERROR(status)) { 471 hdd_err("could not get the wlm reset flag"); 472 return; 473 } 474 475 if (reset) { 476 adapter->upgrade_udp_qos_threshold = QCA_WLAN_AC_BK; 477 hdd_debug("UDP packets qos upgrade to: %d", 478 adapter->upgrade_udp_qos_threshold); 479 } 480 } 481 482 #ifdef WLAN_FEATURE_11BE 483 static inline enum eSirMacHTChannelWidth get_max_bw(void) 484 { 485 uint32_t max_bw = wma_get_eht_ch_width(); 486 487 if (max_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) 488 return eHT_CHANNEL_WIDTH_320MHZ; 489 else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) 490 return eHT_CHANNEL_WIDTH_160MHZ; 491 else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) 492 return eHT_CHANNEL_WIDTH_80P80MHZ; 493 else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) 494 return eHT_CHANNEL_WIDTH_80MHZ; 495 else 496 return eHT_CHANNEL_WIDTH_40MHZ; 497 } 498 #else 499 static inline enum eSirMacHTChannelWidth get_max_bw(void) 500 { 501 uint32_t max_bw = wma_get_vht_ch_width(); 502 503 if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) 504 return eHT_CHANNEL_WIDTH_160MHZ; 505 else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) 506 return eHT_CHANNEL_WIDTH_80P80MHZ; 507 else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) 508 return eHT_CHANNEL_WIDTH_80MHZ; 509 else 510 return eHT_CHANNEL_WIDTH_40MHZ; 511 } 512 #endif 513 514 static void hdd_cm_restore_ch_width(struct wlan_objmgr_vdev *vdev, 515 struct hdd_adapter *adapter) 516 { 517 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 518 struct mlme_legacy_priv *mlme_priv; 519 enum eSirMacHTChannelWidth max_bw; 520 struct wlan_channel *des_chan; 521 uint8_t link_id = 0xFF; 522 int ret; 523 uint8_t vdev_id = wlan_vdev_get_id(vdev); 524 enum phy_ch_width assoc_ch_width; 525 526 mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); 527 if (!mlme_priv) 528 return; 529 530 des_chan = wlan_vdev_mlme_get_des_chan(vdev); 531 if (!des_chan) 532 return; 533 534 assoc_ch_width = mlme_priv->connect_info.assoc_chan_info.assoc_ch_width; 535 if (!ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc) || 536 assoc_ch_width == CH_WIDTH_INVALID) 537 return; 538 539 cm_update_associated_ch_info(vdev, false); 540 541 max_bw = get_max_bw(); 542 ret = hdd_set_mac_chan_width(adapter, max_bw, link_id, true); 543 if (ret) { 544 hdd_err("vdev %d : fail to set max ch width", vdev_id); 545 return; 546 } 547 548 hdd_debug("vdev %d : updated ch width to: %d on disconnection", vdev_id, 549 max_bw); 550 } 551 552 static QDF_STATUS 553 hdd_cm_disconnect_complete_post_user_update(struct wlan_objmgr_vdev *vdev, 554 struct wlan_cm_discon_rsp *rsp) 555 { 556 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 557 struct hdd_adapter *adapter; 558 struct wlan_hdd_link_info *link_info; 559 560 if (!hdd_ctx) { 561 hdd_err("hdd_ctx is NULL"); 562 return QDF_STATUS_E_INVAL; 563 } 564 565 link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); 566 if (!link_info) { 567 hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); 568 return QDF_STATUS_E_INVAL; 569 } 570 571 adapter = link_info->adapter; 572 if (adapter->device_mode == QDF_STA_MODE) { 573 /* Inform FTM TIME SYNC about the disconnection with the AP */ 574 hdd_ftm_time_sync_sta_state_notify( 575 adapter, FTM_TIME_SYNC_STA_DISCONNECTED); 576 } 577 578 /* 579 * via the SET_MAX_BANDWIDTH command, the upper layer can update channel 580 * width. The host should update channel bandwidth to the max supported 581 * bandwidth on disconnection so that post disconnection DUT can 582 * connect in max BW. 583 */ 584 hdd_cm_restore_ch_width(vdev, adapter); 585 hdd_cm_set_default_wlm_mode(adapter); 586 __hdd_cm_disconnect_handler_post_user_update(link_info, vdev, 587 rsp->req.req.source); 588 wlan_twt_concurrency_update(hdd_ctx); 589 hdd_cm_reset_udp_qos_upgrade_config(adapter); 590 ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, 591 vdev->vdev_objmgr.vdev_id, 0); 592 593 return QDF_STATUS_SUCCESS; 594 } 595 596 #ifdef FEATURE_RUNTIME_PM 597 static void 598 wlan_hdd_runtime_pm_wow_disconnect_handler(struct hdd_context *hdd_ctx) 599 { 600 struct hif_opaque_softc *hif_ctx; 601 602 if (!hdd_ctx) { 603 hdd_err("hdd_ctx is NULL"); 604 return; 605 } 606 607 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 608 if (!hif_ctx) { 609 hdd_err("hif_ctx is NULL"); 610 return; 611 } 612 613 if (hdd_is_any_sta_connected(hdd_ctx)) { 614 hdd_debug("active connections: runtime pm prevented: %d", 615 hdd_ctx->runtime_pm_prevented); 616 return; 617 } 618 619 hdd_debug("Runtime allowed : %d", hdd_ctx->runtime_pm_prevented); 620 qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock); 621 if (hdd_ctx->runtime_pm_prevented) { 622 qdf_rtpm_put(QDF_RTPM_PUT, QDF_RTPM_ID_PM_QOS_NOTIFY); 623 hdd_ctx->runtime_pm_prevented = false; 624 } 625 qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock); 626 } 627 #else 628 static void 629 wlan_hdd_runtime_pm_wow_disconnect_handler(struct hdd_context *hdd_ctx) 630 { 631 } 632 #endif 633 634 QDF_STATUS hdd_cm_disconnect_complete(struct wlan_objmgr_vdev *vdev, 635 struct wlan_cm_discon_rsp *rsp, 636 enum osif_cb_type type) 637 { 638 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 639 640 switch (type) { 641 case OSIF_PRE_USERSPACE_UPDATE: 642 return hdd_cm_disconnect_complete_pre_user_update(vdev, rsp); 643 case OSIF_POST_USERSPACE_UPDATE: 644 hdd_debug("Wifi disconnected: vdev id %d", 645 vdev->vdev_objmgr.vdev_id); 646 wlan_hdd_runtime_pm_wow_disconnect_handler(hdd_ctx); 647 648 return hdd_cm_disconnect_complete_post_user_update(vdev, rsp); 649 default: 650 hdd_cm_disconnect_complete_pre_user_update(vdev, rsp); 651 hdd_cm_disconnect_complete_post_user_update(vdev, rsp); 652 return QDF_STATUS_SUCCESS; 653 } 654 } 655 656 QDF_STATUS hdd_cm_netif_queue_control(struct wlan_objmgr_vdev *vdev, 657 enum netif_action_type action, 658 enum netif_reason_type reason) 659 { 660 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 661 struct wlan_hdd_link_info *link_info; 662 663 if (!hdd_ctx) { 664 hdd_err("hdd_ctx is NULL"); 665 return QDF_STATUS_E_INVAL; 666 } 667 668 link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); 669 if (!link_info) { 670 hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); 671 return QDF_STATUS_E_INVAL; 672 } 673 674 wlan_hdd_netif_queue_control(link_info->adapter, action, reason); 675 676 return QDF_STATUS_SUCCESS; 677 } 678 679 QDF_STATUS hdd_cm_napi_serialize_control(bool action) 680 { 681 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 682 683 if (!hdd_ctx) { 684 hdd_err("hdd_ctx is NULL"); 685 return QDF_STATUS_E_INVAL; 686 } 687 688 hdd_napi_serialize(action); 689 690 /* reinit scan reject params for napi off (roam abort/ho fail) */ 691 if (!action) 692 hdd_init_scan_reject_params(hdd_ctx); 693 694 return QDF_STATUS_SUCCESS; 695 } 696 697 #ifdef WLAN_BOOST_CPU_FREQ_IN_ROAM 698 QDF_STATUS hdd_cm_perfd_set_cpufreq(bool action) 699 { 700 struct wlan_core_minfreq req; 701 struct hdd_context *hdd_ctx; 702 703 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 704 if (unlikely(!hdd_ctx)) { 705 hdd_err("cannot get hdd_context"); 706 return QDF_STATUS_E_INVAL; 707 } 708 709 if (action) { 710 req.magic = WLAN_CORE_MINFREQ_MAGIC; 711 req.reserved = 0; /* unused */ 712 req.coremask = 0x00ff;/* big and little cluster */ 713 req.freq = 0xfff;/* set to max freq */ 714 } else { 715 req.magic = WLAN_CORE_MINFREQ_MAGIC; 716 req.reserved = 0; /* unused */ 717 req.coremask = 0; /* not valid */ 718 req.freq = 0; /* reset */ 719 } 720 721 hdd_debug("CPU min freq to 0x%x coremask 0x%x", req.freq, req.coremask); 722 /* the following service function returns void */ 723 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, 724 WLAN_SVC_CORE_MINFREQ, 725 &req, sizeof(struct wlan_core_minfreq)); 726 return QDF_STATUS_SUCCESS; 727 } 728 #endif 729