/* * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /** * DOC: wlan_hdd_assoc.c * * WLAN Host Device Driver implementation * */ #include "wlan_hdd_includes.h" #include #include "dot11f.h" #include "wlan_hdd_power.h" #include "wlan_hdd_trace.h" #include #include #include #include #include "wlan_hdd_cfg80211.h" #include "csr_inside_api.h" #include "wlan_hdd_p2p.h" #include "wlan_hdd_tdls.h" #include "sme_api.h" #include "wlan_hdd_hostapd.h" #include #include #include "wlan_hdd_lpass.h" #include #include #include "wlan_policy_mgr_api.h" #include #include "sme_power_save_api.h" #include "wlan_hdd_napi.h" #include #include #include #include #include #include "ol_txrx.h" #include #include #include #include "wlan_pmo_ucfg_api.h" #include "wlan_hdd_tsf.h" #include "wlan_utility.h" #include "wlan_p2p_ucfg_api.h" #include "wlan_ipa_ucfg_api.h" #include "wlan_hdd_stats.h" #include "wlan_hdd_scan.h" #include "wlan_crypto_global_api.h" #include "wlan_hdd_bcn_recv.h" #include "wlan_mlme_twt_ucfg_api.h" #include #include #include "wlan_dlm_ucfg_api.h" #include "wlan_hdd_sta_info.h" #include "wlan_hdd_ftm_time_sync.h" #include "wlan_cm_roam_api.h" #include #include "wlan_pkt_capture_ucfg_api.h" #include "wlan_if_mgr_ucfg_api.h" #include "wlan_if_mgr_public_struct.h" #include "wlan_cm_public_struct.h" #include "osif_cm_util.h" #include "wlan_hdd_cm_api.h" #include "cm_utf.h" #include "wlan_hdd_bootup_marker.h" #include "wlan_roam_debug.h" #include "wlan_hdd_twt.h" #include "wlan_cm_roam_ucfg_api.h" #include "wlan_hdd_son.h" #include "wlan_dp_ucfg_api.h" #include "wlan_cm_ucfg_api.h" /* These are needed to recognize WPA and RSN suite types */ #define HDD_WPA_OUI_SIZE 4 #define HDD_RSN_OUI_SIZE 4 uint8_t ccp_wpa_oui00[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x00 }; uint8_t ccp_wpa_oui01[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x01 }; uint8_t ccp_wpa_oui02[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; uint8_t ccp_wpa_oui03[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x03 }; uint8_t ccp_wpa_oui04[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x04 }; uint8_t ccp_wpa_oui05[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x05 }; #ifdef FEATURE_WLAN_ESE /* CCKM */ uint8_t ccp_wpa_oui06[HDD_WPA_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; /* CCKM */ uint8_t ccp_rsn_oui06[HDD_RSN_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; #endif /* FEATURE_WLAN_ESE */ /* group cipher */ uint8_t ccp_rsn_oui00[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x00 }; /* WEP-40 or RSN */ uint8_t ccp_rsn_oui01[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x01 }; /* TKIP or RSN-PSK */ uint8_t ccp_rsn_oui02[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x02 }; /* Reserved */ uint8_t ccp_rsn_oui03[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x03 }; /* AES-CCMP */ uint8_t ccp_rsn_oui04[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x04 }; /* WEP-104 */ uint8_t ccp_rsn_oui05[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; /* RSN-PSK-SHA256 */ uint8_t ccp_rsn_oui07[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x06 }; /* RSN-8021X-SHA256 */ uint8_t ccp_rsn_oui08[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; /* AES-GCMP-128 */ uint8_t ccp_rsn_oui09[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x08 }; /* AES-GCMP-256 */ uint8_t ccp_rsn_oui0a[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x09 }; #ifdef WLAN_FEATURE_FILS_SK uint8_t ccp_rsn_oui_0e[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0E}; uint8_t ccp_rsn_oui_0f[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0F}; uint8_t ccp_rsn_oui_10[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x10}; uint8_t ccp_rsn_oui_11[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x11}; #endif uint8_t ccp_rsn_oui_12[HDD_RSN_OUI_SIZE] = {0x50, 0x6F, 0x9A, 0x02}; uint8_t ccp_rsn_oui_0b[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0B}; uint8_t ccp_rsn_oui_0c[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0C}; /* FT-SUITE-B AKM */ uint8_t ccp_rsn_oui_0d[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0D}; /* OWE https://tools.ietf.org/html/rfc8110 */ uint8_t ccp_rsn_oui_18[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x12}; #ifdef WLAN_FEATURE_SAE /* SAE AKM */ uint8_t ccp_rsn_oui_80[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x08}; /* FT SAE AKM */ uint8_t ccp_rsn_oui_90[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x09}; #endif static const u8 ccp_rsn_oui_13[HDD_RSN_OUI_SIZE] = {0x50, 0x6F, 0x9A, 0x01}; #ifdef FEATURE_WLAN_WAPI #define HDD_WAPI_OUI_SIZE 4 /* WPI-SMS4 */ uint8_t ccp_wapi_oui01[HDD_WAPI_OUI_SIZE] = { 0x00, 0x14, 0x72, 0x01 }; /* WAI-PSK */ uint8_t ccp_wapi_oui02[HDD_WAPI_OUI_SIZE] = { 0x00, 0x14, 0x72, 0x02 }; #endif /* FEATURE_WLAN_WAPI */ /* Offset where the EID-Len-IE, start. */ #define ASSOC_RSP_IES_OFFSET 6 /* Capability(2) + AID(2) + Status Code(2) */ #define ASSOC_REQ_IES_OFFSET 4 /* Capability(2) + LI(2) */ /* * beacon_filter_table - table of IEs used for beacon filtering */ static const int beacon_filter_table[] = { WLAN_ELEMID_DSPARMS, WLAN_ELEMID_ERP, WLAN_ELEMID_EDCAPARMS, WLAN_ELEMID_QOS_CAPABILITY, WLAN_ELEMID_HTINFO_ANA, WLAN_ELEMID_OP_MODE_NOTIFY, WLAN_ELEMID_VHTOP, WLAN_ELEMID_QUIET_CHANNEL, WLAN_ELEMID_TWT, #ifdef WLAN_FEATURE_11AX_BSS_COLOR /* * EID: 221 vendor IE is being used temporarily by 11AX * bss-color-change IE till it gets any fixed number. This * vendor EID needs to be replaced with bss-color-change IE * number. */ WLAN_ELEMID_VENDOR, #endif }; /* * beacon_filter_extn_table - table of extn IEs used for beacon filtering */ static const int beacon_filter_extn_table[] = { WLAN_EXTN_ELEMID_HEOP, WLAN_EXTN_ELEMID_UORA, WLAN_EXTN_ELEMID_MUEDCA, #ifdef WLAN_FEATURE_11BE WLAN_EXTN_ELEMID_EHTOP, #endif }; /* HE operation BIT positins */ #if defined(WLAN_FEATURE_11AX) #define HE_OPERATION_DFLT_PE_DURATION_POS 0 #define HE_OPERATION_TWT_REQUIRED_POS 3 #define HE_OPERATION_RTS_THRESHOLD_POS 4 #define HE_OPERATION_VHT_OPER_POS 14 #define HE_OPERATION_CO_LOCATED_BSS_POS 15 #define HE_OPERATION_ER_SU_DISABLE_POS 16 #define HE_OPERATION_OPER_INFO_6G_POS 17 #define HE_OPERATION_RESERVED_POS 18 #define HE_OPERATION_BSS_COLOR_POS 24 #define HE_OPERATION_PARTIAL_BSS_COLOR_POS 30 #define HE_OPERATION_BSS_COL_DISABLED_POS 31 #endif /* EHT operation BIT positins */ #if defined(WLAN_FEATURE_11BE) #define EHT_OPER_BASIC_RX_NSS_MCS_0_TO_7_POS 0 #define EHT_OPER_BASIC_TX_NSS_MCS_0_TO_7_POS 4 #define EHT_OPER_BASIC_RX_NSS_MCS_8_AND_9_POS 8 #define EHT_OPER_BASIC_TX_NSS_MCS_8_AND_9_POS 12 #define EHT_OPER_BASIC_RX_NSS_MCS_10_AND_11_POS 16 #define EHT_OPER_BASIC_TX_NSS_MCS_10_AND_11_POS 20 #define EHT_OPER_BASIC_RX_NSS_MCS_12_AND_13_POS 24 #define EHT_OPER_BASIC_TX_NSS_MCS_12_AND_13_POS 28 #endif #if defined(WLAN_FEATURE_SAE) && \ (defined(CFG80211_EXTERNAL_AUTH_SUPPORT) || \ LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) #if defined (CFG80211_SAE_AUTH_TA_ADDR_SUPPORT) /** * wlan_hdd_sae_copy_ta_addr() - Send TA address to supplicant * @params: pointer to external auth params * @link_info: Link info pointer in HDD adapter * * This API is used to copy TA address info in supplicant structure. * * Return: None */ static inline void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params, struct wlan_hdd_link_info *link_info) { struct qdf_mac_addr ta = QDF_MAC_ADDR_ZERO_INIT; QDF_STATUS status = QDF_STATUS_SUCCESS; uint8_t *link_addr; status = ucfg_cm_get_sae_auth_ta(link_info->adapter->hdd_ctx->pdev, link_info->vdev_id, &ta); if (QDF_IS_STATUS_SUCCESS(status)) qdf_ether_addr_copy(params->tx_addr, ta.bytes); else if (wlan_vdev_mlme_is_mlo_vdev(link_info->vdev)) { link_addr = wlan_vdev_mlme_get_linkaddr(link_info->vdev); qdf_ether_addr_copy(params->tx_addr, link_addr); } hdd_debug("status:%d ta:" QDF_MAC_ADDR_FMT, status, QDF_MAC_ADDR_REF(params->tx_addr)); } #else static inline void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params, struct wlan_hdd_link_info *link_info) { } #endif #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_EXTERNAL_AUTH_MLO_SUPPORT) /** * wlan_hdd_sae_update_mld_addr() - Send mld address to supplicant * @params: pointer to external auth params * @link_info: Link info pointer in HDD adapter * * This API is used to copy MLD address info in supplicant structure. * * Return: QDF_STATUS */ static inline QDF_STATUS wlan_hdd_sae_update_mld_addr(struct cfg80211_external_auth_params *params, struct wlan_hdd_link_info *link_info) { struct qdf_mac_addr mld_addr; struct qdf_mac_addr *mld_roaming_addr; QDF_STATUS status = QDF_STATUS_SUCCESS; struct wlan_objmgr_vdev *vdev; if (!link_info->vdev) return QDF_STATUS_E_INVAL; vdev = link_info->vdev; wlan_objmgr_vdev_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR); if (!ucfg_cm_is_sae_auth_addr_conversion_required(vdev)) goto end; if (ucfg_cm_is_vdev_roaming(vdev)) { /* * while roaming, peer is not created yet till authentication * So retrieving the MLD address which is cached from the * scan entry. */ mld_roaming_addr = ucfg_cm_roaming_get_peer_mld_addr(vdev); if (!mld_roaming_addr) { status = QDF_STATUS_E_INVAL; goto end; } mld_addr = *mld_roaming_addr; } else { status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr); if (QDF_IS_STATUS_ERROR(status)) { status = QDF_STATUS_E_INVAL; goto end; } } qdf_mem_copy(params->mld_addr, mld_addr.bytes, QDF_MAC_ADDR_SIZE); hdd_debug("Sending MLD:" QDF_MAC_ADDR_FMT" to userspace", QDF_MAC_ADDR_REF(mld_addr.bytes)); end: wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); return status; } #else static inline QDF_STATUS wlan_hdd_sae_update_mld_addr(struct cfg80211_external_auth_params *params, struct wlan_hdd_link_info *link_info) { return QDF_STATUS_SUCCESS; } #endif /** * wlan_hdd_get_keymgmt_for_sae_akm() - Get the keymgmt OUI * corresponding to the SAE AKM type * @akm: AKM type * * This API is used to get the keymgmt OUI for the SAE AKM type. * Return: keymgmt OUI */ static uint32_t wlan_hdd_get_keymgmt_for_sae_akm(uint32_t akm) { if (akm == WLAN_AKM_SAE) return WLAN_AKM_SUITE_SAE; else if (akm == WLAN_AKM_FT_SAE) return WLAN_AKM_SUITE_FT_OVER_SAE; else if (akm == WLAN_AKM_SAE_EXT_KEY) return WLAN_AKM_SUITE_SAE_EXT_KEY; else if (akm == WLAN_AKM_FT_SAE_EXT_KEY) return WLAN_AKM_SUITE_FT_SAE_EXT_KEY; /** * Legacy FW doesn't support SAE-EXK-KEY or * Cross-SAE_AKM roaming. In such cases, send * SAE for both SAE and FT-SAE AKMs. The supplicant * has backward compatibility to handle this case. */ else return WLAN_AKM_SUITE_SAE; } /** * wlan_hdd_sae_callback() - Sends SAE info to supplicant * @link_info: Link info pointer in HDD adapter * @roam_info: pointer to roam info * * This API is used to send required SAE info to trigger SAE in supplicant. * * Return: None */ static void wlan_hdd_sae_callback(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roam_info) { struct hdd_adapter *adapter = link_info->adapter; struct hdd_context *hdd_ctx = adapter->hdd_ctx; int flags; struct sir_sae_info *sae_info = roam_info->sae_info; struct cfg80211_external_auth_params params = {0}; QDF_STATUS status; if (wlan_hdd_validate_context(hdd_ctx)) return; if (!sae_info) { hdd_err("SAE info in NULL"); return; } flags = cds_get_gfp_flags(); params.key_mgmt_suite = wlan_hdd_get_keymgmt_for_sae_akm(sae_info->akm); params.action = NL80211_EXTERNAL_AUTH_START; qdf_ether_addr_copy(params.bssid, sae_info->peer_mac_addr.bytes); wlan_hdd_sae_copy_ta_addr(¶ms, link_info); status = wlan_hdd_sae_update_mld_addr(¶ms, link_info); if (QDF_IS_STATUS_ERROR(status)) return; qdf_mem_copy(params.ssid.ssid, sae_info->ssid.ssId, sae_info->ssid.length); params.ssid.ssid_len = sae_info->ssid.length; cfg80211_external_auth_request(adapter->dev, ¶ms, flags); hdd_debug("SAE: sent cmd"); } #else static inline void wlan_hdd_sae_callback(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roam_info) { } #endif /** * hdd_start_powersave_timer_on_associated() - Start auto powersave timer * after associated * @link_info: Link info pointer in HDD adapter * * This function will start auto powersave timer for STA/P2P Client. * * Return: none */ static void hdd_start_powersave_timer_on_associated(struct wlan_hdd_link_info *link_info) { uint32_t timeout; uint32_t auto_bmps_timer_val; struct hdd_adapter *adapter = link_info->adapter; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); if (adapter->device_mode != QDF_STA_MODE && adapter->device_mode != QDF_P2P_CLIENT_MODE) return; ucfg_mlme_get_auto_bmps_timer_value(hdd_ctx->psoc, &auto_bmps_timer_val); timeout = hdd_cm_is_vdev_roaming(link_info) ? AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE : (auto_bmps_timer_val * 1000); sme_ps_enable_auto_ps_timer(hdd_ctx->mac_handle, link_info->vdev_id, timeout); } void hdd_conn_set_authenticated(struct wlan_hdd_link_info *link_info, uint8_t auth_state) { struct hdd_station_ctx *sta_ctx; struct wlan_objmgr_vdev *vdev; char *auth_time; uint32_t time_buffer_size; sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); /* save the new connection state */ hdd_debug("Authenticated state Changed from oldState:%d to State:%d", sta_ctx->conn_info.is_authenticated, auth_state); sta_ctx->conn_info.is_authenticated = auth_state; vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); if (vdev) { ucfg_dp_conn_info_set_peer_authenticate(vdev, auth_state); hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); } auth_time = sta_ctx->conn_info.auth_time; time_buffer_size = sizeof(sta_ctx->conn_info.auth_time); if (auth_state) qdf_get_time_of_the_day_in_hr_min_sec_usec(auth_time, time_buffer_size); else qdf_mem_zero(auth_time, time_buffer_size); if (auth_state && (sta_ctx->conn_info.ptk_installed || sta_ctx->conn_info.uc_encrypt_type == eCSR_ENCRYPT_TYPE_NONE)) hdd_start_powersave_timer_on_associated(link_info); } void hdd_conn_set_connection_state(struct hdd_adapter *adapter, eConnectionState conn_state) { struct hdd_station_ctx *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); /* save the new connection state */ if (conn_state == hdd_sta_ctx->conn_info.conn_state) return; hdd_nofl_debug("connection state changed %d --> %d for dev %s (vdev %d)", hdd_sta_ctx->conn_info.conn_state, conn_state, adapter->dev->name, adapter->deflink->vdev_id); hdd_sta_ctx->conn_info.conn_state = conn_state; } enum band_info hdd_conn_get_connected_band(struct wlan_hdd_link_info *link_info) { struct hdd_station_ctx *sta_ctx; uint32_t sta_freq = 0; sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); if (hdd_cm_is_vdev_associated(link_info)) sta_freq = sta_ctx->conn_info.chan_freq; if (wlan_reg_is_24ghz_ch_freq(sta_freq)) return BAND_2G; else if (wlan_reg_is_5ghz_ch_freq(sta_freq) || wlan_reg_is_6ghz_chan_freq(sta_freq)) return BAND_5G; else /* If station is not connected return as BAND_ALL */ return BAND_ALL; } /** * hdd_conn_get_connected_cipher_algo() - get current connection cipher type * @link_info: Link info pointer in HDD adapter. * @sta_ctx: pointer to global HDD Station context * @pConnectedCipherAlgo: pointer to connected cipher algo * * Return: false if any errors encountered, true otherwise */ static inline bool hdd_conn_get_connected_cipher_algo(struct wlan_hdd_link_info *link_info, struct hdd_station_ctx *sta_ctx, eCsrEncryptionType *pConnectedCipherAlgo) { bool connected; connected = hdd_cm_is_vdev_associated(link_info); if (pConnectedCipherAlgo) *pConnectedCipherAlgo = sta_ctx->conn_info.uc_encrypt_type; return connected; } struct wlan_hdd_link_info * hdd_get_sta_connection_in_progress(struct hdd_context *hdd_ctx) { struct hdd_adapter *adapter = NULL, *next_adapter = NULL; wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_STA_CONNECTION_IN_PROGRESS; struct wlan_hdd_link_info *link_info; if (!hdd_ctx) { hdd_err("HDD context is NULL"); return NULL; } hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, dbgid) { if ((QDF_STA_MODE == adapter->device_mode) || (QDF_P2P_CLIENT_MODE == adapter->device_mode) || (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { hdd_adapter_for_each_active_link_info(adapter, link_info) { if (!hdd_cm_is_connecting(link_info)) continue; hdd_debug("vdev_id %d: Connection is in progress", link_info->vdev_id); hdd_adapter_dev_put_debug(adapter, dbgid); if (next_adapter) hdd_adapter_dev_put_debug(next_adapter, dbgid); return link_info; } } hdd_adapter_dev_put_debug(adapter, dbgid); } return NULL; } void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx) { struct wlan_hdd_link_info *link_info; link_info = hdd_get_sta_connection_in_progress(hdd_ctx); if (link_info && !wlan_vdev_mlme_is_mlo_link_switch_in_progress(link_info->vdev)) wlan_hdd_cm_issue_disconnect(link_info, REASON_UNSPEC_FAILURE, false); } void hdd_abort_ongoing_sta_sae_connection(struct hdd_context *hdd_ctx) { struct wlan_hdd_link_info *link_info; struct wlan_objmgr_vdev *vdev; int32_t key_mgmt; link_info = hdd_get_sta_connection_in_progress(hdd_ctx); if (!link_info || wlan_vdev_mlme_is_mlo_link_switch_in_progress(link_info->vdev)) return; vdev = hdd_objmgr_get_vdev_by_user(link_info->adapter->deflink, WLAN_OSIF_ID); if (!vdev) return; key_mgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); if (key_mgmt < 0) { hdd_debug_rl("Invalid key_mgmt: %d", key_mgmt); return; } if (QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY) || QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) wlan_hdd_cm_issue_disconnect(link_info->adapter->deflink, REASON_DISASSOC_NETWORK_LEAVING, false); } QDF_STATUS hdd_get_first_connected_sta_vdev_id(struct hdd_context *hdd_ctx, uint32_t *vdev_id) { struct hdd_adapter *adapter = NULL, *next_adapter = NULL; wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_ANY_STA_CONNECTED; struct wlan_hdd_link_info *link_info; if (!hdd_ctx) { hdd_err("HDD context is NULL"); return QDF_STATUS_E_INVAL; } hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, dbgid) { if (adapter->device_mode == QDF_STA_MODE || adapter->device_mode == QDF_P2P_CLIENT_MODE) { hdd_adapter_for_each_active_link_info(adapter, link_info) { if (!hdd_cm_is_vdev_connected(link_info)) continue; *vdev_id = link_info->vdev_id; hdd_adapter_dev_put_debug(adapter, dbgid); if (next_adapter) hdd_adapter_dev_put_debug(next_adapter, dbgid); return QDF_STATUS_SUCCESS; } } hdd_adapter_dev_put_debug(adapter, dbgid); } return QDF_STATUS_E_FAILURE; } bool hdd_is_any_sta_connected(struct hdd_context *hdd_ctx) { QDF_STATUS status; uint32_t vdev_id; status = hdd_get_first_connected_sta_vdev_id(hdd_ctx, &vdev_id); return QDF_IS_STATUS_ERROR(status) ? false : true; } /** * hdd_remove_beacon_filter() - remove beacon filter * @adapter: Pointer to the hdd adapter * * Return: 0 on success and errno on failure */ int hdd_remove_beacon_filter(struct hdd_adapter *adapter) { QDF_STATUS status; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); status = sme_remove_beacon_filter(hdd_ctx->mac_handle, adapter->deflink->vdev_id); if (!QDF_IS_STATUS_SUCCESS(status)) { hdd_err("sme_remove_beacon_filter() failed"); return -EFAULT; } return 0; } int hdd_add_beacon_filter(struct hdd_adapter *adapter) { int i; uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST] = {0}; QDF_STATUS status; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); for (i = 0; i < ARRAY_SIZE(beacon_filter_table); i++) qdf_set_bit(beacon_filter_table[i], (unsigned long *)ie_map); for (i = 0; i < ARRAY_SIZE(beacon_filter_extn_table); i++) qdf_set_bit(beacon_filter_extn_table[i] + WLAN_ELEMID_EXTN_ELEM, (unsigned long *)ie_map); status = sme_add_beacon_filter(hdd_ctx->mac_handle, adapter->deflink->vdev_id, ie_map); if (!QDF_IS_STATUS_SUCCESS(status)) { hdd_err("sme_add_beacon_filter() failed"); return -EFAULT; } return 0; } void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, tDot11fIEHTCaps *roam_ht_cap) { uint32_t i, temp_ht_cap; qdf_mem_zero(hdd_ht_cap, sizeof(struct ieee80211_ht_cap)); if (roam_ht_cap->advCodingCap) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LDPC_CODING; if (roam_ht_cap->supportedChannelWidthSet) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; temp_ht_cap = roam_ht_cap->mimoPowerSave & (IEEE80211_HT_CAP_SM_PS >> IEEE80211_HT_CAP_SM_PS_SHIFT); if (temp_ht_cap) hdd_ht_cap->cap_info |= temp_ht_cap << IEEE80211_HT_CAP_SM_PS_SHIFT; if (roam_ht_cap->greenField) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_GRN_FLD; if (roam_ht_cap->shortGI20MHz) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_20; if (roam_ht_cap->shortGI40MHz) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_40; if (roam_ht_cap->txSTBC) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_TX_STBC; temp_ht_cap = roam_ht_cap->rxSTBC & (IEEE80211_HT_CAP_RX_STBC >> IEEE80211_HT_CAP_RX_STBC_SHIFT); if (temp_ht_cap) hdd_ht_cap->cap_info |= temp_ht_cap << IEEE80211_HT_CAP_RX_STBC_SHIFT; if (roam_ht_cap->delayedBA) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DELAY_BA; if (roam_ht_cap->maximalAMSDUsize) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_MAX_AMSDU; if (roam_ht_cap->dsssCckMode40MHz) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DSSSCCK40; if (roam_ht_cap->psmp) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_RESERVED; if (roam_ht_cap->stbcControlFrame) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; if (roam_ht_cap->lsigTXOPProtection) hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LSIG_TXOP_PROT; /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ if (roam_ht_cap->maxRxAMPDUFactor) hdd_ht_cap->ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; temp_ht_cap = roam_ht_cap->mpduDensity & (IEEE80211_HT_AMPDU_PARM_DENSITY >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); if (temp_ht_cap) hdd_ht_cap->ampdu_params_info |= temp_ht_cap << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; /* 802.11n HT extended capabilities masks */ if (roam_ht_cap->pco) hdd_ht_cap->extended_ht_cap_info |= IEEE80211_HT_EXT_CAP_PCO; temp_ht_cap = roam_ht_cap->transitionTime & (IEEE80211_HT_EXT_CAP_PCO_TIME >> IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT); if (temp_ht_cap) hdd_ht_cap->extended_ht_cap_info |= temp_ht_cap << IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT; temp_ht_cap = roam_ht_cap->mcsFeedback & (IEEE80211_HT_EXT_CAP_MCS_FB >> IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT); if (temp_ht_cap) hdd_ht_cap->extended_ht_cap_info |= temp_ht_cap << IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT; /* tx_bf_cap_info capabilities */ if (roam_ht_cap->txBF) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_BF; if (roam_ht_cap->rxStaggeredSounding) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_RX_STAG_RED_SOUNDING; if (roam_ht_cap->txStaggeredSounding) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_STAG_RED_SOUNDING; if (roam_ht_cap->rxZLF) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_RX_ZFL; if (roam_ht_cap->txZLF) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_ZFL; if (roam_ht_cap->implicitTxBF) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_IMP_TX_BF; temp_ht_cap = roam_ht_cap->calibration & (TX_BF_CAP_INFO_CALIBRATION >> TX_BF_CAP_INFO_CALIBRATION_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_CALIBRATION_SHIFT; if (roam_ht_cap->explicitCSITxBF) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_EXP_CSIT_BF; if (roam_ht_cap->explicitUncompressedSteeringMatrix) hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_EXP_UNCOMP_STEER_MAT; temp_ht_cap = roam_ht_cap->explicitBFCSIFeedback & (TX_BF_CAP_INFO_EXP_BF_CSI_FB >> TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT; temp_ht_cap = roam_ht_cap->explicitUncompressedSteeringMatrixFeedback & (TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT >> TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT; temp_ht_cap = roam_ht_cap->explicitCompressedSteeringMatrixFeedback & (TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB >> TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT; temp_ht_cap = roam_ht_cap->csiNumBFAntennae & (TX_BF_CAP_INFO_CSI_NUM_BF_ANT >> TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT; temp_ht_cap = roam_ht_cap->uncompressedSteeringMatrixBFAntennae & (TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT >> TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT; temp_ht_cap = roam_ht_cap->compressedSteeringMatrixBFAntennae & (TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT >> TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT); if (temp_ht_cap) hdd_ht_cap->tx_BF_cap_info |= temp_ht_cap << TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT; /* antenna selection */ if (roam_ht_cap->antennaSelection) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO; if (roam_ht_cap->explicitCSIFeedbackTx) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO_EXP_CSI_FB_TX; if (roam_ht_cap->antennaIndicesFeedbackTx) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO_ANT_ID_FB_TX; if (roam_ht_cap->explicitCSIFeedback) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO_EXP_CSI_FB; if (roam_ht_cap->antennaIndicesFeedback) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO_ANT_ID_FB; if (roam_ht_cap->rxAS) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO_RX_AS; if (roam_ht_cap->txSoundingPPDUs) hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO_TX_SOUNDING_PPDU; /* mcs data rate */ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; ++i) hdd_ht_cap->mcs.rx_mask[i] = roam_ht_cap->supportedMCSSet[i]; hdd_ht_cap->mcs.rx_highest = ((short) (roam_ht_cap->supportedMCSSet[11]) << 8) | ((short) (roam_ht_cap->supportedMCSSet[10])); hdd_ht_cap->mcs.tx_params = roam_ht_cap->supportedMCSSet[12]; } #define VHT_CAP_MAX_MPDU_LENGTH_MASK 0x00000003 #define VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT 2 #define VHT_CAP_RXSTBC_MASK_SHIFT 8 #define VHT_CAP_BEAMFORMEE_STS_SHIFT 13 #define VHT_CAP_BEAMFORMEE_STS_MASK \ (0x0000e000 >> VHT_CAP_BEAMFORMEE_STS_SHIFT) #define VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 #define VHT_CAP_SOUNDING_DIMENSIONS_MASK \ (0x00070000 >> VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) #define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT 23 #define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ (0x03800000 >> VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT) #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT 26 void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap, tDot11fIEVHTCaps *roam_vht_cap) { uint32_t temp_vht_cap; qdf_mem_zero(hdd_vht_cap, sizeof(struct ieee80211_vht_cap)); temp_vht_cap = roam_vht_cap->maxMPDULen & VHT_CAP_MAX_MPDU_LENGTH_MASK; hdd_vht_cap->vht_cap_info |= temp_vht_cap; temp_vht_cap = roam_vht_cap->supportedChannelWidthSet & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK >> VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT); if (temp_vht_cap) { if (roam_vht_cap->supportedChannelWidthSet & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ >> VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT)) hdd_vht_cap->vht_cap_info |= temp_vht_cap << IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; if (roam_vht_cap->supportedChannelWidthSet & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ >> VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT)) hdd_vht_cap->vht_cap_info |= temp_vht_cap << IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; } if (roam_vht_cap->ldpcCodingCap) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_RXLDPC; if (roam_vht_cap->shortGI80MHz) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_80; if (roam_vht_cap->shortGI160and80plus80MHz) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_160; if (roam_vht_cap->txSTBC) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_TXSTBC; temp_vht_cap = roam_vht_cap->rxSTBC & (IEEE80211_VHT_CAP_RXSTBC_MASK >> VHT_CAP_RXSTBC_MASK_SHIFT); if (temp_vht_cap) hdd_vht_cap->vht_cap_info |= temp_vht_cap << VHT_CAP_RXSTBC_MASK_SHIFT; if (roam_vht_cap->suBeamFormerCap) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; if (roam_vht_cap->suBeamformeeCap) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; temp_vht_cap = roam_vht_cap->csnofBeamformerAntSup & (VHT_CAP_BEAMFORMEE_STS_MASK); if (temp_vht_cap) hdd_vht_cap->vht_cap_info |= temp_vht_cap << VHT_CAP_BEAMFORMEE_STS_SHIFT; temp_vht_cap = roam_vht_cap->numSoundingDim & (VHT_CAP_SOUNDING_DIMENSIONS_MASK); if (temp_vht_cap) hdd_vht_cap->vht_cap_info |= temp_vht_cap << VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; if (roam_vht_cap->muBeamformerCap) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; if (roam_vht_cap->muBeamformeeCap) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; if (roam_vht_cap->vhtTXOPPS) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_VHT_TXOP_PS; if (roam_vht_cap->htcVHTCap) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_HTC_VHT; temp_vht_cap = roam_vht_cap->maxAMPDULenExp & (VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); if (temp_vht_cap) hdd_vht_cap->vht_cap_info |= temp_vht_cap << VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT; temp_vht_cap = roam_vht_cap->vhtLinkAdaptCap & (IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB >> VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT); if (temp_vht_cap) hdd_vht_cap->vht_cap_info |= temp_vht_cap << VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT; if (roam_vht_cap->rxAntPattern) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; if (roam_vht_cap->txAntPattern) hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; hdd_vht_cap->supp_mcs.rx_mcs_map = roam_vht_cap->rxMCSMap; hdd_vht_cap->supp_mcs.rx_highest = ((uint16_t)roam_vht_cap->rxHighSupDataRate); hdd_vht_cap->supp_mcs.tx_mcs_map = roam_vht_cap->txMCSMap; hdd_vht_cap->supp_mcs.tx_highest = ((uint16_t)roam_vht_cap->txSupDataRate); } /* ht param */ #define HT_PARAM_CONTROLLED_ACCESS_ONLY 0x10 #define HT_PARAM_SERVICE_INT_GRAN 0xe0 #define HT_PARAM_SERVICE_INT_GRAN_SHIFT 5 /* operatinon mode */ #define HT_OP_MODE_TX_BURST_LIMIT 0x0008 /* stbc_param */ #define HT_STBC_PARAM_MCS 0x007f void hdd_copy_ht_operation(struct hdd_station_ctx *hdd_sta_ctx, tDot11fIEHTInfo *ht_ops) { struct ieee80211_ht_operation *hdd_ht_ops = &hdd_sta_ctx->conn_info.ht_operation; uint32_t i, temp_ht_ops; qdf_mem_zero(hdd_ht_ops, sizeof(struct ieee80211_ht_operation)); hdd_ht_ops->primary_chan = ht_ops->primaryChannel; /* HT_PARAMS */ temp_ht_ops = ht_ops->secondaryChannelOffset & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; if (temp_ht_ops) hdd_ht_ops->ht_param |= temp_ht_ops; else hdd_ht_ops->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; if (ht_ops->recommendedTxWidthSet) hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; if (ht_ops->rifsMode) hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE; if (ht_ops->controlledAccessOnly) hdd_ht_ops->ht_param |= HT_PARAM_CONTROLLED_ACCESS_ONLY; temp_ht_ops = ht_ops->serviceIntervalGranularity & (HT_PARAM_SERVICE_INT_GRAN >> HT_PARAM_SERVICE_INT_GRAN_SHIFT); if (temp_ht_ops) hdd_ht_ops->ht_param |= temp_ht_ops << HT_PARAM_SERVICE_INT_GRAN_SHIFT; /* operation mode */ temp_ht_ops = ht_ops->opMode & IEEE80211_HT_OP_MODE_PROTECTION; switch (temp_ht_ops) { case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: hdd_ht_ops->operation_mode |= IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER; break; case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: hdd_ht_ops->operation_mode |= IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; break; case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: hdd_ht_ops->operation_mode |= IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; break; case IEEE80211_HT_OP_MODE_PROTECTION_NONE: default: hdd_ht_ops->operation_mode |= IEEE80211_HT_OP_MODE_PROTECTION_NONE; } if (ht_ops->nonGFDevicesPresent) hdd_ht_ops->operation_mode |= IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT; if (ht_ops->transmitBurstLimit) hdd_ht_ops->operation_mode |= HT_OP_MODE_TX_BURST_LIMIT; if (ht_ops->obssNonHTStaPresent) hdd_ht_ops->operation_mode |= IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; if (ht_ops->chan_center_freq_seg2) hdd_ht_ops->operation_mode |= (ht_ops->chan_center_freq_seg2 << IEEE80211_HT_OP_MODE_CCFS2_SHIFT); /* stbc_param */ temp_ht_ops = ht_ops->basicSTBCMCS & HT_STBC_PARAM_MCS; if (temp_ht_ops) hdd_ht_ops->stbc_param |= temp_ht_ops; if (ht_ops->dualCTSProtection) hdd_ht_ops->stbc_param |= IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT; if (ht_ops->secondaryBeacon) hdd_ht_ops->stbc_param |= IEEE80211_HT_STBC_PARAM_STBC_BEACON; if (ht_ops->lsigTXOPProtectionFullSupport) hdd_ht_ops->stbc_param |= IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT; if (ht_ops->pcoActive) hdd_ht_ops->stbc_param |= IEEE80211_HT_STBC_PARAM_PCO_ACTIVE; if (ht_ops->pcoPhase) hdd_ht_ops->stbc_param |= IEEE80211_HT_STBC_PARAM_PCO_PHASE; /* basic MCs set */ for (i = 0; i < 16; ++i) hdd_ht_ops->basic_set[i] = ht_ops->basicMCSSet[i]; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) static void hdd_copy_vht_center_freq(struct ieee80211_vht_operation *ieee_ops, tDot11fIEVHTOperation *roam_ops) { ieee_ops->center_freq_seg0_idx = roam_ops->chan_center_freq_seg0; ieee_ops->center_freq_seg1_idx = roam_ops->chan_center_freq_seg1; } #else static void hdd_copy_vht_center_freq(struct ieee80211_vht_operation *ieee_ops, tDot11fIEVHTOperation *roam_ops) { ieee_ops->center_freq_seg1_idx = roam_ops->chan_center_freq_seg0; ieee_ops->center_freq_seg2_idx = roam_ops->chan_center_freq_seg1; } #endif /* KERNEL_VERSION(4, 12, 0) */ void hdd_copy_vht_operation(struct hdd_station_ctx *hdd_sta_ctx, tDot11fIEVHTOperation *vht_ops) { struct ieee80211_vht_operation *hdd_vht_ops = &hdd_sta_ctx->conn_info.vht_operation; qdf_mem_zero(hdd_vht_ops, sizeof(struct ieee80211_vht_operation)); hdd_vht_ops->chan_width = vht_ops->chanWidth; hdd_copy_vht_center_freq(hdd_vht_ops, vht_ops); hdd_vht_ops->basic_mcs_set = vht_ops->basicMCSSet; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) && \ defined(WLAN_FEATURE_11BE) void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, tDot11fIEeht_op *eht_ops) { struct ieee80211_eht_operation *hdd_eht_ops = &hdd_sta_ctx->conn_info.eht_operation; struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_param; uint32_t filled = 0, len = 0; qdf_mem_zero(hdd_eht_ops, sizeof(struct ieee80211_eht_operation)); if (!eht_ops->eht_op_information_present) return; /* Min length if op_info_present */ len += 3; hdd_eht_ops->params |= IEEE80211_EHT_OPER_INFO_PRESENT; if (eht_ops->eht_default_pe_duration) hdd_eht_ops->params |= IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION; if (eht_ops->group_addr_bu_indication_limit) hdd_eht_ops->params |= IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT; if (eht_ops->group_addr_bu_indication_exponent) hdd_eht_ops->params |= IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK; mcs_param.rx_tx_mcs7_max_nss = eht_ops->basic_rx_max_nss_for_mcs_0_to_7 << EHT_OPER_BASIC_RX_NSS_MCS_0_TO_7_POS; mcs_param.rx_tx_mcs7_max_nss |= eht_ops->basic_tx_max_nss_for_mcs_0_to_7 << EHT_OPER_BASIC_TX_NSS_MCS_0_TO_7_POS; mcs_param.rx_tx_mcs9_max_nss = eht_ops->basic_rx_max_nss_for_mcs_8_and_9 << EHT_OPER_BASIC_RX_NSS_MCS_8_AND_9_POS; mcs_param.rx_tx_mcs9_max_nss |= eht_ops->basic_tx_max_nss_for_mcs_8_and_9 << EHT_OPER_BASIC_TX_NSS_MCS_8_AND_9_POS; mcs_param.rx_tx_mcs11_max_nss = eht_ops->basic_rx_max_nss_for_mcs_10_and_11 << EHT_OPER_BASIC_RX_NSS_MCS_10_AND_11_POS; mcs_param.rx_tx_mcs11_max_nss |= eht_ops->basic_tx_max_nss_for_mcs_10_and_11 << EHT_OPER_BASIC_TX_NSS_MCS_10_AND_11_POS; mcs_param.rx_tx_mcs13_max_nss = eht_ops->basic_rx_max_nss_for_mcs_12_and_13 << EHT_OPER_BASIC_RX_NSS_MCS_12_AND_13_POS; mcs_param.rx_tx_mcs13_max_nss |= eht_ops->basic_tx_max_nss_for_mcs_12_and_13 << EHT_OPER_BASIC_TX_NSS_MCS_12_AND_13_POS; hdd_eht_ops->basic_mcs_nss = mcs_param; hdd_eht_ops->optional[filled++] = eht_ops->channel_width; hdd_eht_ops->optional[filled++] = eht_ops->ccfs0; hdd_eht_ops->optional[filled++] = eht_ops->ccfs1; if (eht_ops->disabled_sub_chan_bitmap_present) { hdd_eht_ops->params |= IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT; len += 2; hdd_eht_ops->optional[filled++] = eht_ops->disabled_sub_chan_bitmap[0][0]; hdd_eht_ops->optional[filled++] = eht_ops->disabled_sub_chan_bitmap[0][1]; } hdd_sta_ctx->conn_info.eht_oper_len = sizeof(struct ieee80211_eht_operation) + len; } #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) && \ defined(WLAN_FEATURE_11BE) void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, tDot11fIEeht_op *eht_ops) { struct ieee80211_eht_operation *hdd_eht_ops = &hdd_sta_ctx->conn_info.eht_operation; uint32_t mcs_param = 0, filled = 0, len = 0; qdf_mem_zero(hdd_eht_ops, sizeof(struct ieee80211_eht_operation)); if (!eht_ops->eht_op_information_present) return; /* Min length if op_info_present */ len += 3; hdd_eht_ops->params |= IEEE80211_EHT_OPER_INFO_PRESENT; if (eht_ops->eht_default_pe_duration) hdd_eht_ops->params |= IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION; if (eht_ops->group_addr_bu_indication_limit) hdd_eht_ops->params |= IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT; if (eht_ops->group_addr_bu_indication_exponent) hdd_eht_ops->params |= IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK; mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_0_to_7 << EHT_OPER_BASIC_RX_NSS_MCS_0_TO_7_POS; mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_0_to_7 << EHT_OPER_BASIC_TX_NSS_MCS_0_TO_7_POS; mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_8_and_9 << EHT_OPER_BASIC_RX_NSS_MCS_8_AND_9_POS; mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_8_and_9 << EHT_OPER_BASIC_TX_NSS_MCS_8_AND_9_POS; mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_10_and_11 << EHT_OPER_BASIC_RX_NSS_MCS_10_AND_11_POS; mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_10_and_11 << EHT_OPER_BASIC_TX_NSS_MCS_10_AND_11_POS; mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_12_and_13 << EHT_OPER_BASIC_RX_NSS_MCS_12_AND_13_POS; mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_12_and_13 << EHT_OPER_BASIC_TX_NSS_MCS_12_AND_13_POS; hdd_eht_ops->basic_mcs_nss = mcs_param; hdd_eht_ops->optional[filled++] = eht_ops->channel_width; hdd_eht_ops->optional[filled++] = eht_ops->ccfs0; hdd_eht_ops->optional[filled++] = eht_ops->ccfs1; if (eht_ops->disabled_sub_chan_bitmap_present) { hdd_eht_ops->params |= IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT; len += 2; hdd_eht_ops->optional[filled++] = eht_ops->disabled_sub_chan_bitmap[0][0]; hdd_eht_ops->optional[filled++] = eht_ops->disabled_sub_chan_bitmap[0][1]; } hdd_sta_ctx->conn_info.eht_oper_len = sizeof(struct ieee80211_eht_operation) + len; } #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) && \ defined(WLAN_FEATURE_11BE) void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, tDot11fIEeht_op *eht_ops) { struct ieee80211_eht_operation *hdd_eht_ops = &hdd_sta_ctx->conn_info.eht_operation; uint32_t filled = 0, len = 0; qdf_mem_zero(hdd_eht_ops, sizeof(struct ieee80211_eht_operation)); if (!eht_ops->eht_op_information_present) return; hdd_eht_ops->chan_width = eht_ops->channel_width; hdd_eht_ops->ccfs = eht_ops->ccfs0; hdd_eht_ops->present_bm = eht_ops->disabled_sub_chan_bitmap_present; if (eht_ops->disabled_sub_chan_bitmap_present) { hdd_eht_ops->disable_subchannel_bitmap[filled++] = eht_ops->disabled_sub_chan_bitmap[0][0]; hdd_eht_ops->disable_subchannel_bitmap[filled++] = eht_ops->disabled_sub_chan_bitmap[0][1]; len += 2; } hdd_sta_ctx->conn_info.eht_oper_len = sizeof(struct ieee80211_eht_operation) + len; } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ defined(WLAN_FEATURE_11AX) void hdd_copy_he_operation(struct hdd_station_ctx *hdd_sta_ctx, tDot11fIEhe_op *he_operation) { struct ieee80211_he_operation *hdd_he_operation; uint32_t he_oper_params = 0; uint32_t len = 0, filled = 0; uint8_t he_oper_6g_params = 0; uint32_t he_oper_len; if (!he_operation->present) return; if (he_operation->vht_oper_present) len += 3; if (he_operation->co_located_bss) len += 1; if (he_operation->oper_info_6g_present) len += 5; he_oper_len = sizeof(struct ieee80211_he_operation) + len; hdd_he_operation = qdf_mem_malloc(he_oper_len); if (!hdd_he_operation) return; /* Fill he_oper_params */ he_oper_params |= he_operation->default_pe << HE_OPERATION_DFLT_PE_DURATION_POS; he_oper_params |= he_operation->twt_required << HE_OPERATION_TWT_REQUIRED_POS; he_oper_params |= he_operation->txop_rts_threshold << HE_OPERATION_RTS_THRESHOLD_POS; he_oper_params |= he_operation->vht_oper_present << HE_OPERATION_VHT_OPER_POS; he_oper_params |= he_operation->co_located_bss << HE_OPERATION_CO_LOCATED_BSS_POS; he_oper_params |= he_operation->er_su_disable << HE_OPERATION_ER_SU_DISABLE_POS; he_oper_params |= he_operation->oper_info_6g_present << HE_OPERATION_OPER_INFO_6G_POS; he_oper_params |= he_operation->reserved2 << HE_OPERATION_RESERVED_POS; he_oper_params |= he_operation->bss_color << HE_OPERATION_BSS_COLOR_POS; he_oper_params |= he_operation->partial_bss_col << HE_OPERATION_PARTIAL_BSS_COLOR_POS; he_oper_params |= he_operation->bss_col_disabled << HE_OPERATION_BSS_COL_DISABLED_POS; hdd_he_operation->he_oper_params = he_oper_params; /* Fill he_mcs_nss set */ qdf_mem_copy(&hdd_he_operation->he_mcs_nss_set, he_operation->basic_mcs_nss, sizeof(hdd_he_operation->he_mcs_nss_set)); /* Fill he_params_optional fields */ if (he_operation->vht_oper_present) { hdd_he_operation->optional[filled++] = he_operation->vht_oper.info.chan_width; hdd_he_operation->optional[filled++] = he_operation->vht_oper.info.center_freq_seg0; hdd_he_operation->optional[filled++] = he_operation->vht_oper.info.center_freq_seg1; } if (he_operation->co_located_bss) hdd_he_operation->optional[filled++] = he_operation->maxbssid_ind.info.data; if (he_operation->oper_info_6g_present) { hdd_he_operation->optional[filled++] = he_operation->oper_info_6g.info.primary_ch; he_oper_6g_params |= he_operation->oper_info_6g.info.ch_width << 0; he_oper_6g_params |= he_operation->oper_info_6g.info.dup_bcon << 2; he_oper_6g_params |= he_operation->oper_info_6g.info.reserved << 3; hdd_he_operation->optional[filled++] = he_oper_6g_params; hdd_he_operation->optional[filled++] = he_operation->oper_info_6g.info.center_freq_seg0; hdd_he_operation->optional[filled++] = he_operation->oper_info_6g.info.center_freq_seg1; hdd_he_operation->optional[filled] = he_operation->oper_info_6g.info.min_rate; } if (hdd_sta_ctx->cache_conn_info.he_operation) { qdf_mem_free(hdd_sta_ctx->cache_conn_info.he_operation); hdd_sta_ctx->cache_conn_info.he_operation = NULL; } hdd_sta_ctx->cache_conn_info.he_oper_len = he_oper_len; hdd_sta_ctx->cache_conn_info.he_operation = hdd_he_operation; } #endif bool hdd_is_roam_sync_in_progress(struct hdd_context *hdd_ctx, uint8_t vdev_id) { return wlan_cm_is_roam_sync_in_progress(hdd_ctx->psoc, vdev_id); } void hdd_conn_remove_connect_info(struct hdd_station_ctx *sta_ctx) { /* Remove bssid and peer_macaddr */ qdf_mem_zero(&sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE); qdf_mem_zero(&sta_ctx->conn_info.peer_macaddr[0], QDF_MAC_ADDR_SIZE); /* Clear all security settings */ sta_ctx->conn_info.auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; sta_ctx->conn_info.uc_encrypt_type = eCSR_ENCRYPT_TYPE_NONE; sta_ctx->conn_info.proxy_arp_service = 0; qdf_mem_zero(&sta_ctx->conn_info.ssid, sizeof(tCsrSSIDInfo)); /* * Reset the ptk, gtk status flags to avoid using current connection * status in further connections. */ sta_ctx->conn_info.gtk_installed = false; sta_ctx->conn_info.ptk_installed = false; } void hdd_clear_roam_profile_ie(struct hdd_adapter *adapter) { hdd_enter(); #ifdef FEATURE_WLAN_WAPI adapter->wapi_info.wapi_auth_mode = WAPI_AUTH_MODE_OPEN; adapter->wapi_info.wapi_mode = false; #endif hdd_exit(); } #if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) static inline void hdd_set_unpause_queue(void *soc, uint8_t vdev_id) { cdp_fc_vdev_unpause(soc, vdev_id, OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED, 0); } #else static inline void hdd_set_unpause_queue(void *soc, uint8_t vdev_id) { } #endif #ifdef FEATURE_WDS /** * hdd_config_wds_repeater_mode() - configures vdev for wds repeater mode * @link_info: Link info pointer in HDD adapter * @peer_addr: peer mac address * * Configure dp vdev to detect and drop multicast echo packets and enable * 4 address frame format in fw. * * Return: None */ static void hdd_config_wds_repeater_mode(struct wlan_hdd_link_info *link_info, uint8_t *peer_addr) { cdp_config_param_type vdev_param; ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); vdev_param.cdp_vdev_param_mec = true; if (cdp_txrx_set_vdev_param(soc, link_info->vdev_id, CDP_ENABLE_MEC, vdev_param)) hdd_debug("Failed to set MEC param on DP vdev"); hdd_nofl_info("Turn on 4 address for peer: " QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_addr)); if (sme_set_peer_param(peer_addr, WMI_HOST_PEER_USE_4ADDR, true, link_info->vdev_id)) hdd_err("Failed to enable WDS on vdev"); } #else static inline void hdd_config_wds_repeater_mode(struct wlan_hdd_link_info *link_info, uint8_t *peer_addr) { } #endif QDF_STATUS hdd_change_peer_state(struct wlan_hdd_link_info *link_info, uint8_t *peer_mac, enum ol_txrx_peer_state sta_state) { QDF_STATUS err; struct hdd_adapter *adapter = link_info->adapter; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); void *soc = cds_get_context(QDF_MODULE_ID_SOC); err = cdp_peer_state_update(soc, peer_mac, sta_state); if (err != QDF_STATUS_SUCCESS) { hdd_err("peer state update failed"); return QDF_STATUS_E_FAULT; } if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id)) { if (adapter->device_mode == QDF_STA_MODE && (wlan_mlme_get_wds_mode(hdd_ctx->psoc) == WLAN_WDS_MODE_REPEATER)) hdd_config_wds_repeater_mode(link_info, peer_mac); hdd_son_deliver_peer_authorize_event(link_info, peer_mac); return QDF_STATUS_SUCCESS; } if (sta_state == OL_TXRX_PEER_STATE_AUTH) { /* Reset scan reject params on successful set key */ hdd_debug("Reset scan reject params"); hdd_init_scan_reject_params(hdd_ctx); err = sme_set_peer_authorized(peer_mac, link_info->vdev_id); if (err != QDF_STATUS_SUCCESS) { hdd_err("Failed to set the peer state to authorized"); return QDF_STATUS_E_FAULT; } if (adapter->device_mode == QDF_STA_MODE || adapter->device_mode == QDF_P2P_CLIENT_MODE) { hdd_set_unpause_queue(soc, link_info->vdev_id); } if (adapter->device_mode == QDF_STA_MODE && (wlan_mlme_get_wds_mode(hdd_ctx->psoc) == WLAN_WDS_MODE_REPEATER)) hdd_config_wds_repeater_mode(link_info, peer_mac); hdd_son_deliver_peer_authorize_event(link_info, peer_mac); } return QDF_STATUS_SUCCESS; } QDF_STATUS hdd_update_dp_vdev_flags(void *cbk_data, uint8_t vdev_id, uint32_t vdev_param, bool is_link_up) { QDF_STATUS status = QDF_STATUS_SUCCESS; void *soc = cds_get_context(QDF_MODULE_ID_SOC); struct hdd_context *hdd_ctx; struct wlan_objmgr_psoc **psoc; cdp_config_param_type val; if (!cbk_data) return status; psoc = cbk_data; hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); if (!hdd_ctx) return QDF_STATUS_E_INVAL; if (!hdd_ctx->tdls_nap_active) return status; if (vdev_id == WLAN_INVALID_VDEV_ID) { status = QDF_STATUS_E_FAILURE; return status; } val.cdp_vdev_param_tdls_flags = is_link_up; cdp_txrx_set_vdev_param(soc, vdev_id, vdev_param, val); return status; } QDF_STATUS hdd_roam_register_sta(struct wlan_hdd_link_info *link_info, struct qdf_mac_addr *bssid, bool is_auth_required) { QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; struct ol_txrx_desc_type txrx_desc = {0}; void *soc = cds_get_context(QDF_MODULE_ID_SOC); enum phy_ch_width ch_width; enum wlan_phymode phymode; struct wlan_objmgr_vdev *vdev; struct hdd_adapter *adapter = link_info->adapter; /* Get the Station ID from the one saved during the association */ if (!QDF_IS_ADDR_BROADCAST(bssid->bytes)) WLAN_ADDR_COPY(txrx_desc.peer_addr.bytes, bssid->bytes); else WLAN_ADDR_COPY(txrx_desc.peer_addr.bytes, adapter->mac_addr.bytes); /* set the QoS field appropriately */ if (hdd_wmm_is_active(adapter)) txrx_desc.is_qos_enabled = 1; else txrx_desc.is_qos_enabled = 0; #ifdef FEATURE_WLAN_WAPI hdd_debug("WAPI STA Registered: %d", adapter->wapi_info.is_wapi_sta); if (adapter->wapi_info.is_wapi_sta) txrx_desc.is_wapi_supported = 1; else txrx_desc.is_wapi_supported = 0; #endif /* FEATURE_WLAN_WAPI */ vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); if (!vdev) return QDF_STATUS_E_INVAL; qdf_status = ucfg_dp_sta_register_txrx_ops(vdev); hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { hdd_err("DP tx/rx ops register failed Status: %d", qdf_status); return qdf_status; } if (adapter->device_mode == QDF_NDI_MODE) { phymode = ucfg_mlme_get_vdev_phy_mode( adapter->hdd_ctx->psoc, link_info->vdev_id); ch_width = ucfg_mlme_get_ch_width_from_phymode(phymode); } else { ch_width = ucfg_mlme_get_peer_ch_width(adapter->hdd_ctx->psoc, txrx_desc.peer_addr.bytes); } txrx_desc.bw = hdd_convert_ch_width_to_cdp_peer_bw(ch_width); qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &txrx_desc); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { hdd_err("cdp_peer_register() failed Status: %d [0x%08X]", qdf_status, qdf_status); return qdf_status; } hdd_cm_set_peer_authenticate(link_info, &txrx_desc.peer_addr, is_auth_required); return qdf_status; } /** * hdd_change_sta_state_authenticated()- * This function changes STA state to authenticated * @link_info: Link info pointer in HDD adapter * @roaminfo: pointer to the RoamInfo structure. * * This is called from hdd_RoamSetKeyCompleteHandler * in context to eCSR_ROAM_SET_KEY_COMPLETE event from fw. * * Return: 0 on success and errno on failure */ static int hdd_change_sta_state_authenticated(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roaminfo) { uint8_t *mac_addr; struct hdd_station_ctx *sta_ctx; struct hdd_adapter *adapter = link_info->adapter; struct hdd_context *hdd_ctx; QDF_STATUS status; bool alt_pipe; sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); mac_addr = sta_ctx->conn_info.bssid.bytes; if (ucfg_ipa_is_enabled() && !sta_ctx->conn_info.is_authenticated && adapter->device_mode == QDF_STA_MODE && sta_ctx->conn_info.auth_type != eCSR_AUTH_TYPE_NONE && sta_ctx->conn_info.auth_type != eCSR_AUTH_TYPE_OPEN_SYSTEM && sta_ctx->conn_info.auth_type != eCSR_AUTH_TYPE_SHARED_KEY) { hdd_ctx = WLAN_HDD_GET_CTX(adapter); status = hdd_ipa_get_tx_pipe(hdd_ctx, link_info, &alt_pipe); if (!QDF_IS_STATUS_SUCCESS(status)) { hdd_debug("Failed to get alternate pipe for vdev %d", link_info->vdev_id); alt_pipe = false; } ucfg_ipa_wlan_evt(adapter->hdd_ctx->pdev, adapter->dev, adapter->device_mode, link_info->vdev_id, WLAN_IPA_STA_CONNECT, mac_addr, alt_pipe); } hdd_cm_set_peer_authenticate(link_info, &sta_ctx->conn_info.bssid, false); return 0; } /** * hdd_change_peer_state_after_set_key() - change the peer state on set key * complete * @link_info: Link info pointer in HDD adapter * @roaminfo: pointer to roam info * @roam_result: roam result * * Peer state will be OL_TXRX_PEER_STATE_CONN until set key is complete. * This function checks for the successful set key completion and update * the peer state to OL_TXRX_PEER_STATE_AUTH. * * Return: None */ static void hdd_change_peer_state_after_set_key(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roaminfo, eCsrRoamResult roam_result) { struct hdd_station_ctx *hdd_sta_ctx; eCsrEncryptionType encr_type; struct hdd_adapter *adapter = link_info->adapter; hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); encr_type = hdd_sta_ctx->conn_info.uc_encrypt_type; if (eCSR_ROAM_RESULT_AUTHENTICATED == roam_result) { hdd_sta_ctx->conn_info.gtk_installed = true; /* * PTK exchange happens in preauthentication itself if key_mgmt * is FT-PSK, ptk_installed was false as there is no set PTK * after roaming. STA TL state moves to authenticated only if * ptk_installed is true. So, make ptk_installed to true in * case of 11R roaming. */ if (sme_neighbor_roam_is11r_assoc(adapter->hdd_ctx->mac_handle, link_info->vdev_id)) hdd_sta_ctx->conn_info.ptk_installed = true; } else { hdd_sta_ctx->conn_info.ptk_installed = true; } /* In WPA case move STA to authenticated when ptk is installed. Earlier * in WEP case STA was moved to AUTHENTICATED prior to setting the * unicast key and it was resulting in sending few un-encrypted packet. * Now in WEP case STA state will be moved to AUTHENTICATED after we * set the unicast and broadcast key. */ if ((encr_type == eCSR_ENCRYPT_TYPE_WEP40) || (encr_type == eCSR_ENCRYPT_TYPE_WEP104) || (encr_type == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) || (encr_type == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) { if (hdd_sta_ctx->conn_info.gtk_installed && hdd_sta_ctx->conn_info.ptk_installed) hdd_change_sta_state_authenticated(link_info, roaminfo); } else if (hdd_sta_ctx->conn_info.ptk_installed) { hdd_change_sta_state_authenticated(link_info, roaminfo); } if (hdd_sta_ctx->conn_info.gtk_installed && hdd_sta_ctx->conn_info.ptk_installed) { hdd_sta_ctx->conn_info.gtk_installed = false; hdd_sta_ctx->conn_info.ptk_installed = false; } } /** * hdd_roam_set_key_complete_handler() - Update the security parameters * @link_info: Link info pointer in HDD adapter * @roam_info: pointer to roam info * @roam_status: roam status * @roam_result: roam result * * Return: QDF_STATUS enumeration */ static QDF_STATUS hdd_roam_set_key_complete_handler(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roam_info, eRoamCmdStatus roam_status, eCsrRoamResult roam_result) { eCsrEncryptionType algorithm; bool connected; struct hdd_station_ctx *sta_ctx; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); hdd_enter(); if (!roam_info) { hdd_err("roam_info is NULL"); return QDF_STATUS_E_FAILURE; } if (!hdd_ctx || !hdd_ctx->psoc) { hdd_err("hdd_ctx or psoc is NULL"); return QDF_STATUS_E_FAILURE; } sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); /* * if (WPA), tell TL to go to 'authenticated' after the keys are set. * then go to 'authenticated'. For all other authentication types * (those that do not require upper layer authentication) we can put TL * directly into 'authenticated' state. */ hdd_debug("Set Key completion roam_status =%d roam_result=%d " QDF_MAC_ADDR_FMT, roam_status, roam_result, QDF_MAC_ADDR_REF(roam_info->peerMac.bytes)); sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); connected = hdd_conn_get_connected_cipher_algo(link_info, sta_ctx, &algorithm); if (connected) { hdd_change_peer_state_after_set_key(link_info, roam_info, roam_result); } policy_mgr_restart_opportunistic_timer(hdd_ctx->psoc, false); hdd_exit(); return QDF_STATUS_SUCCESS; } bool hdd_save_peer(struct hdd_station_ctx *sta_ctx, struct qdf_mac_addr *peer_mac_addr) { int idx; struct qdf_mac_addr *mac_addr; for (idx = 0; idx < MAX_PEERS; idx++) { mac_addr = &sta_ctx->conn_info.peer_macaddr[idx]; if (qdf_is_macaddr_zero(mac_addr)) { hdd_debug("adding peer: "QDF_MAC_ADDR_FMT" at idx: %d", QDF_MAC_ADDR_REF(peer_mac_addr->bytes), idx); qdf_copy_macaddr(mac_addr, peer_mac_addr); return true; } } return false; } void hdd_delete_peer(struct hdd_station_ctx *sta_ctx, struct qdf_mac_addr *peer_mac_addr) { int i; struct qdf_mac_addr *mac_addr; for (i = 0; i < MAX_PEERS; i++) { mac_addr = &sta_ctx->conn_info.peer_macaddr[i]; if (qdf_is_macaddr_equal(mac_addr, peer_mac_addr)) { qdf_zero_macaddr(mac_addr); return; } } } bool hdd_any_valid_peer_present(struct wlan_hdd_link_info *link_info) { struct hdd_station_ctx *sta_ctx; int i; struct qdf_mac_addr *mac_addr; sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); for (i = 0; i < MAX_PEERS; i++) { mac_addr = &sta_ctx->conn_info.peer_macaddr[i]; if (!qdf_is_macaddr_zero(mac_addr) && !qdf_is_macaddr_broadcast(mac_addr)) { hdd_debug("peer: index: %u " QDF_MAC_ADDR_FMT, i, QDF_MAC_ADDR_REF(mac_addr->bytes)); return true; } } return false; } /** * hdd_roam_mic_error_indication_handler() - MIC error indication handler * @link_info: Link info pointer in HDD adapter * @roam_info: pointer to roam info * * This function indicates the Mic failure to the supplicant * * Return: None */ static void hdd_roam_mic_error_indication_handler(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roam_info) { struct hdd_adapter *adapter = link_info->adapter; tSirMicFailureInfo *mic_failure_info; if (!hdd_cm_is_vdev_associated(link_info)) return; mic_failure_info = roam_info->u.pMICFailureInfo; cfg80211_michael_mic_failure(adapter->dev, mic_failure_info->taMacAddr, mic_failure_info->multicast ? NL80211_KEYTYPE_GROUP : NL80211_KEYTYPE_PAIRWISE, mic_failure_info->keyId, mic_failure_info->TSC, GFP_KERNEL); } #ifdef FEATURE_WLAN_TDLS QDF_STATUS hdd_roam_register_tdlssta(struct hdd_adapter *adapter, const uint8_t *peerMac, uint8_t qos) { QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; struct ol_txrx_desc_type txrx_desc = { 0 }; void *soc = cds_get_context(QDF_MODULE_ID_SOC); enum phy_ch_width ch_width; struct wlan_objmgr_vdev *vdev; /* * TDLS sta in BSS should be set as STA type TDLS and STA MAC should * be peer MAC, here we are working on direct Link */ WLAN_ADDR_COPY(txrx_desc.peer_addr.bytes, peerMac); /* set the QoS field appropriately .. */ txrx_desc.is_qos_enabled = qos; vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); if (!vdev) return QDF_STATUS_E_INVAL; qdf_status = ucfg_dp_tdlsta_register_txrx_ops(vdev); hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { hdd_err("DP tx/rx ops register failed Status: %d", qdf_status); return qdf_status; } ch_width = ucfg_mlme_get_peer_ch_width(adapter->hdd_ctx->psoc, txrx_desc.peer_addr.bytes); txrx_desc.bw = hdd_convert_ch_width_to_cdp_peer_bw(ch_width); /* Register the Station with TL... */ qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &txrx_desc); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { hdd_err("cdp_peer_register() failed Status: %d [0x%08X]", qdf_status, qdf_status); return qdf_status; } return qdf_status; } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) static void hdd_rx_unprot_disassoc(struct net_device *dev, const u8 *buf, size_t len) { cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); } static void hdd_rx_unprot_deauth(struct net_device *dev, const u8 *buf, size_t len) { cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); } #else static void hdd_rx_unprot_disassoc(struct net_device *dev, const u8 *buf, size_t len) { cfg80211_send_unprot_disassoc(dev, buf, len); } static void hdd_rx_unprot_deauth(struct net_device *dev, const u8 *buf, size_t len) { cfg80211_send_unprot_deauth(dev, buf, len); } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ /** * hdd_indicate_unprot_mgmt_frame() - indicate unprotected management frame * @link_info: Link info pointer in HDD adapter * @frame_length: Length of the unprotected frame being passed * @frame: Pointer to the frame buffer * @frame_type: 802.11 frame type * * This function forwards the unprotected management frame to the supplicant. * * Return: nothing */ static void hdd_indicate_unprot_mgmt_frame(struct wlan_hdd_link_info *link_info, uint32_t frame_length, uint8_t *frame, uint8_t frame_type) { uint8_t type, subtype; struct hdd_stats *hdd_stats; struct hdd_adapter *adapter = link_info->adapter; hdd_debug("Frame Type = %d Frame Length = %d", frame_type, frame_length); if (hdd_validate_adapter(adapter)) return; if (!frame_length) { hdd_err("Frame Length is Invalid ZERO"); return; } if (!frame) { hdd_err("frame is NULL"); return; } type = WLAN_HDD_GET_TYPE_FRM_FC(frame[0]); if (type != SIR_MAC_MGMT_FRAME) { hdd_warn("Unexpected frame type %d", type); return; } hdd_stats = &link_info->hdd_stats; subtype = WLAN_HDD_GET_SUBTYPE_FRM_FC(frame[0]); switch (subtype) { case SIR_MAC_MGMT_DISASSOC: hdd_rx_unprot_disassoc(adapter->dev, frame, frame_length); hdd_stats->hdd_pmf_stats.num_unprot_disassoc_rx++; break; case SIR_MAC_MGMT_DEAUTH: hdd_rx_unprot_deauth(adapter->dev, frame, frame_length); hdd_stats->hdd_pmf_stats.num_unprot_deauth_rx++; break; default: hdd_warn("Unexpected frame subtype %d", subtype); break; } } #ifdef FEATURE_WLAN_ESE /** * hdd_indicate_tsm_ie() - send traffic stream metrics ie * @adapter: pointer to adapter * @tid: traffic identifier * @state: state * @measInterval: measurement interval * * This function sends traffic stream metrics IE information to * the supplicant via wireless event. * * Return: none */ static void hdd_indicate_tsm_ie(struct hdd_adapter *adapter, uint8_t tid, uint8_t state, uint16_t measInterval) { union iwreq_data wrqu; char buf[IW_CUSTOM_MAX + 1]; int nBytes = 0; if (!adapter) return; /* create the event */ memset(&wrqu, '\0', sizeof(wrqu)); memset(buf, '\0', sizeof(buf)); hdd_debug("TSM Ind tid(%d) state(%d) MeasInt(%d)", tid, state, measInterval); nBytes = snprintf(buf, IW_CUSTOM_MAX, "TSMIE=%d:%d:%d", tid, state, measInterval); wrqu.data.pointer = buf; wrqu.data.length = nBytes; /* send the event */ hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); } /** * hdd_indicate_ese_adj_ap_rep_ind() - send adjacent AP report indication * @adapter: pointer to adapter * @roam_info: pointer to roam info * * Return: none */ static void hdd_indicate_ese_adj_ap_rep_ind(struct hdd_adapter *adapter, struct csr_roam_info *roam_info) { union iwreq_data wrqu; char buf[IW_CUSTOM_MAX + 1]; int nBytes = 0; if ((!adapter) || (!roam_info)) return; /* create the event */ memset(&wrqu, '\0', sizeof(wrqu)); memset(buf, '\0', sizeof(buf)); hdd_debug("CCXADJAPREP=%u", roam_info->tsmRoamDelay); nBytes = snprintf(buf, IW_CUSTOM_MAX, "CCXADJAPREP=%u", roam_info->tsmRoamDelay); wrqu.data.pointer = buf; wrqu.data.length = nBytes; /* send the event */ hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); } /** * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results * @adapter: pointer to adapter * @measurementToken: measurement token * @flag: flag * @numBss: number of bss * * If the measurement is none and no scan results found, * indicate the supplicant about measurement done. * * Return: none */ void hdd_indicate_ese_bcn_report_no_results(const struct hdd_adapter *adapter, const uint16_t measurementToken, const bool flag, const uint8_t numBss) { union iwreq_data wrqu; char buf[IW_CUSTOM_MAX]; char *pos = buf; int nBytes = 0, freeBytes = IW_CUSTOM_MAX; memset(&wrqu, '\0', sizeof(wrqu)); memset(buf, '\0', sizeof(buf)); hdd_debug("CCXBCNREP=%d %d %d", measurementToken, flag, numBss); nBytes = snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d", measurementToken, flag, numBss); wrqu.data.pointer = buf; wrqu.data.length = nBytes; /* send the event */ hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); } /** * hdd_indicate_ese_bcn_report_ind() - send beacon report indication * @adapter: pointer to adapter * @roam_info: pointer to roam info * * If the measurement is none and no scan results found, * indicate the supplicant about measurement done. * * Return: none */ static void hdd_indicate_ese_bcn_report_ind(const struct hdd_adapter *adapter, const struct csr_roam_info *roam_info) { union iwreq_data wrqu; char buf[IW_CUSTOM_MAX]; char *pos = buf; int nBytes = 0, freeBytes = IW_CUSTOM_MAX; uint8_t i = 0, len = 0; uint8_t tot_bcn_ieLen = 0; /* total size of the beacon report data */ uint8_t lastSent = 0, sendBss = 0; int bcnRepFieldSize = sizeof(roam_info->pEseBcnReportRsp->bcnRepBssInfo[0]. bcnReportFields); uint8_t ieLenByte = 1; /* * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes */ #define ESEBCNREPHEADER_LEN (18) if ((!adapter) || (!roam_info)) return; /* * Custom event can pass maximum of 256 bytes of data, * based on the IE len we need to identify how many BSS info can * be filled in to custom event data. */ /* * meas_tokflagno_of_bsstot_bcn_ie_len bcn_rep_data * bcn_rep_data will have bcn_rep_fields,ie_len,ie without any spaces * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes */ if ((roam_info->pEseBcnReportRsp->flag >> 1) && (!roam_info->pEseBcnReportRsp->numBss)) { hdd_debug("Measurement Done but no scan results"); /* If the measurement is none and no scan results found, * indicate the supplicant about measurement done */ hdd_indicate_ese_bcn_report_no_results( adapter, roam_info->pEseBcnReportRsp-> measurementToken, roam_info->pEseBcnReportRsp->flag, roam_info->pEseBcnReportRsp->numBss); } else { while (lastSent < roam_info->pEseBcnReportRsp->numBss) { memset(&wrqu, '\0', sizeof(wrqu)); memset(buf, '\0', sizeof(buf)); tot_bcn_ieLen = 0; sendBss = 0; pos = buf; freeBytes = IW_CUSTOM_MAX; for (i = lastSent; i < roam_info->pEseBcnReportRsp->numBss; i++) { len = bcnRepFieldSize + ieLenByte + roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i].ieLen; if ((len + tot_bcn_ieLen) > (IW_CUSTOM_MAX - ESEBCNREPHEADER_LEN)) { break; } tot_bcn_ieLen += len; sendBss++; hdd_debug("i(%d) sizeof bcnReportFields(%d) IeLength(%d) Length of Ie(%d) totLen(%d)", i, bcnRepFieldSize, 1, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i].ieLen, tot_bcn_ieLen); } hdd_debug("Sending %d BSS Info", sendBss); hdd_debug("CCXBCNREP=%d %d %d %d", roam_info->pEseBcnReportRsp->measurementToken, roam_info->pEseBcnReportRsp->flag, sendBss, tot_bcn_ieLen); nBytes = snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d ", roam_info->pEseBcnReportRsp-> measurementToken, roam_info->pEseBcnReportRsp->flag, sendBss); pos += nBytes; freeBytes -= nBytes; /* Copy total Beacon report data length */ qdf_mem_copy(pos, (char *)&tot_bcn_ieLen, sizeof(tot_bcn_ieLen)); pos += sizeof(tot_bcn_ieLen); freeBytes -= sizeof(tot_bcn_ieLen); for (i = 0; i < sendBss; i++) { hdd_debug("ChanNum(%d) Spare(%d) MeasDuration(%d)" " PhyType(%d) RecvSigPower(%d) ParentTSF(%u)" " TargetTSF[0](%u) TargetTSF[1](%u) BeaconInterval(%u)" " CapabilityInfo(%d) BSSID(%02X:%02X:%02X:%02X:%02X:%02X)", roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. ChanNum, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Spare, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. MeasDuration, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. PhyType, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. RecvSigPower, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. ParentTsf, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. TargetTsf[0], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. TargetTsf[1], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. BcnInterval, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. CapabilityInfo, roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Bssid[0], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Bssid[1], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Bssid[2], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Bssid[3], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Bssid[4], roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].bcnReportFields. Bssid[5]); /* bcn report fields are copied */ len = sizeof(roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent]. bcnReportFields); qdf_mem_copy(pos, (char *)&roam_info-> pEseBcnReportRsp->bcnRepBssInfo[i + lastSent]. bcnReportFields, len); pos += len; freeBytes -= len; /* Add 1 byte of ie len */ len = roam_info->pEseBcnReportRsp-> bcnRepBssInfo[i + lastSent].ieLen; qdf_mem_copy(pos, (char *)&len, sizeof(len)); pos += sizeof(len); freeBytes -= sizeof(len); /* copy IE from scan results */ qdf_mem_copy(pos, (char *)roam_info-> pEseBcnReportRsp->bcnRepBssInfo[i + lastSent]. pBuf, len); pos += len; freeBytes -= len; } wrqu.data.pointer = buf; wrqu.data.length = IW_CUSTOM_MAX - freeBytes; /* send the event */ hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); lastSent += sendBss; } } } #endif /* FEATURE_WLAN_ESE */ /* * hdd_roam_channel_switch_handler() - hdd channel switch handler * @link_info: Link info pointer in HDD adapter * @roam_info: Pointer to roam info * * Return: None */ static void hdd_roam_channel_switch_handler(struct wlan_hdd_link_info *link_info, struct csr_roam_info *roam_info) { struct hdd_chan_change_params chan_change = {0}; QDF_STATUS status; struct hdd_adapter *adapter = link_info->adapter; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); mac_handle_t mac_handle; struct hdd_station_ctx *sta_ctx; uint8_t connected_vdev; bool notify = true, is_sap_go_moved_before_sta = false; struct wlan_objmgr_vdev *vdev; mac_handle = hdd_adapter_get_mac_handle(adapter); if (!mac_handle) return; /* Enable Roaming on STA interface which was disabled before CSA */ if (adapter->device_mode == QDF_STA_MODE) sme_start_roaming(mac_handle, link_info->vdev_id, REASON_VDEV_RESTART_FROM_HOST, RSO_CHANNEL_SWITCH); sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); if (sta_ctx) { sta_ctx->conn_info.chan_freq = roam_info->chan_info.mhz; sta_ctx->conn_info.ch_width = roam_info->chan_info.ch_width; } chan_change.chan_freq = roam_info->chan_info.mhz; chan_change.chan_params.ch_width = roam_info->chan_info.ch_width; chan_change.chan_params.sec_ch_offset = roam_info->chan_info.sec_ch_offset; chan_change.chan_params.mhz_freq_seg0 = roam_info->chan_info.band_center_freq1; chan_change.chan_params.mhz_freq_seg1 = roam_info->chan_info.band_center_freq2; vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); if (!vdev) { hdd_err("Invalid vdev"); return; } if ((adapter->device_mode == QDF_STA_MODE || adapter->device_mode == QDF_P2P_CLIENT_MODE)) { if (!wlan_get_connected_vdev_by_bssid( hdd_ctx->pdev, sta_ctx->conn_info.bssid.bytes, &connected_vdev)) notify = false; else if (link_info->vdev_id != connected_vdev || !ucfg_cm_is_vdev_active(vdev)) notify = false; } if (notify) { qdf_sched_work(0, &link_info->chan_change_notify_work); } else { hdd_err("BSS "QDF_MAC_ADDR_FMT" no connected with vdev %d (%d)", QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes), link_info->vdev_id, connected_vdev); } status = policy_mgr_set_hw_mode_on_channel_switch(hdd_ctx->psoc, link_info->vdev_id); if (QDF_IS_STATUS_ERROR(status)) hdd_debug("set hw mode change not done"); is_sap_go_moved_before_sta = wlan_vdev_mlme_is_sap_go_move_before_sta(vdev); hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); if (!is_sap_go_moved_before_sta) policy_mgr_check_concurrent_intf_and_restart_sap( hdd_ctx->psoc, !!link_info->session.ap.sap_config.acs_cfg.acs_mode); wlan_twt_concurrency_update(hdd_ctx); if (adapter->device_mode == QDF_STA_MODE || adapter->device_mode == QDF_P2P_CLIENT_MODE) { vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); if (!vdev) return; status = ucfg_if_mgr_deliver_event( vdev, WLAN_IF_MGR_EV_STA_CSA_COMPLETE, NULL); if (QDF_IS_STATUS_ERROR(status)) hdd_debug("Failed to deliver CSA complete evt"); hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); } } #ifdef WLAN_FEATURE_HOST_ROAM void wlan_hdd_ft_set_key_delay(struct wlan_objmgr_vdev *vdev) { int errno = 0; if (ucfg_cm_ft_key_ready_for_install(vdev)) errno = wlan_cfg80211_crypto_add_key(vdev, WLAN_CRYPTO_KEY_TYPE_UNICAST, 0, false); if (errno) hdd_err("ft set key failed"); } #endif QDF_STATUS hdd_sme_roam_callback(void *context, struct csr_roam_info *roam_info, eRoamCmdStatus roam_status, eCsrRoamResult roam_result) { QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; struct wlan_hdd_link_info *link_info = context; struct hdd_adapter *adapter = link_info->adapter; struct hdd_station_ctx *sta_ctx = NULL; struct hdd_context *hdd_ctx; hdd_debug("CSR Callback: status=%s (%d) result= %s (%d)", get_e_roam_cmd_status_str(roam_status), roam_status, get_e_csr_roam_result_str(roam_result), roam_result); /* Sanity check */ if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { hdd_err("Invalid adapter or adapter has invalid magic"); return QDF_STATUS_E_FAILURE; } sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); hdd_ctx = WLAN_HDD_GET_CTX(adapter); MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_RX_SME_MSG, link_info->vdev_id, roam_status)); switch (roam_status) { case eCSR_ROAM_MIC_ERROR_IND: hdd_roam_mic_error_indication_handler(link_info, roam_info); break; case eCSR_ROAM_SET_KEY_COMPLETE: { qdf_ret_status = hdd_roam_set_key_complete_handler(link_info, roam_info, roam_status, roam_result); if (eCSR_ROAM_RESULT_AUTHENTICATED == roam_result) hdd_debug("set key complete, session: %d", link_info->vdev_id); } break; case eCSR_ROAM_UNPROT_MGMT_FRAME_IND: if (roam_info) hdd_indicate_unprot_mgmt_frame(link_info, roam_info->nFrameLength, roam_info->pbFrames, roam_info->frameType); break; #ifdef FEATURE_WLAN_ESE case eCSR_ROAM_TSM_IE_IND: if (roam_info) hdd_indicate_tsm_ie(adapter, roam_info->tsm_ie.tsid, roam_info->tsm_ie.state, roam_info->tsm_ie.msmt_interval); break; case eCSR_ROAM_ESE_ADJ_AP_REPORT_IND: { hdd_indicate_ese_adj_ap_rep_ind(adapter, roam_info); break; } case eCSR_ROAM_ESE_BCN_REPORT_IND: { hdd_indicate_ese_bcn_report_ind(adapter, roam_info); break; } #endif /* FEATURE_WLAN_ESE */ case eCSR_ROAM_STA_CHANNEL_SWITCH: hdd_roam_channel_switch_handler(link_info, roam_info); break; case eCSR_ROAM_NDP_STATUS_UPDATE: hdd_ndp_event_handler(link_info, roam_info, roam_status, roam_result); break; case eCSR_ROAM_SAE_COMPUTE: if (roam_info) wlan_hdd_sae_callback(link_info, roam_info); break; default: break; } return qdf_ret_status; } #ifdef WLAN_FEATURE_FILS_SK /** * hdd_translate_fils_rsn_to_csr_auth() - Translate FILS RSN to CSR auth type * @auth_suite: auth suite * @auth_type: pointer to enum csr_akm_type * * Return: None */ static void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4], enum csr_akm_type *auth_type) { if (!memcmp(auth_suite, ccp_rsn_oui_0e, 4)) *auth_type = eCSR_AUTH_TYPE_FILS_SHA256; else if (!memcmp(auth_suite, ccp_rsn_oui_0f, 4)) *auth_type = eCSR_AUTH_TYPE_FILS_SHA384; else if (!memcmp(auth_suite, ccp_rsn_oui_10, 4)) *auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA256; else if (!memcmp(auth_suite, ccp_rsn_oui_11, 4)) *auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA384; } #else static inline void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4], enum csr_akm_type *auth_type) { } #endif #ifdef WLAN_FEATURE_SAE /** * hdd_translate_sae_rsn_to_csr_auth() - Translate SAE RSN to CSR auth type * @auth_suite: auth suite * @auth_type: pointer to enum csr_akm_type * * Return: None */ static void hdd_translate_sae_rsn_to_csr_auth(int8_t auth_suite[4], enum csr_akm_type *auth_type) { if (qdf_mem_cmp(auth_suite, ccp_rsn_oui_80, 4) == 0) *auth_type = eCSR_AUTH_TYPE_SAE; else if (qdf_mem_cmp(auth_suite, ccp_rsn_oui_90, 4) == 0) *auth_type = eCSR_AUTH_TYPE_FT_SAE; } #else static inline void hdd_translate_sae_rsn_to_csr_auth(int8_t auth_suite[4], enum csr_akm_type *auth_type) { } #endif void *hdd_filter_ft_info(const uint8_t *frame, size_t len, uint32_t *ft_info_len) { uint32_t ft_ie_len, md_ie_len, rsn_ie_len, ie_len; const uint8_t *rsn_ie, *md_ie, *ft_ie; void *ft_info; ft_ie_len = 0; md_ie_len = 0; rsn_ie_len = 0; ie_len = len - DOT11F_FF_CAPABILITIES_LEN - DOT11F_FF_STATUS_LEN - DOT11F_IE_AID_MAX_LEN - sizeof(tSirMacMgmtHdr); rsn_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_RSN, frame, ie_len); if (rsn_ie) { rsn_ie_len = rsn_ie[1] + 2; QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, (void *)rsn_ie, rsn_ie_len); } md_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_MOBILITYDOMAIN, frame, ie_len); if (md_ie) { md_ie_len = md_ie[1] + 2; QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, (void *)md_ie, md_ie_len); } ft_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_FTINFO, frame, ie_len); if (ft_ie) ft_ie_len = ft_ie[1] + 2; *ft_info_len = rsn_ie_len + md_ie_len + ft_ie_len; ft_info = qdf_mem_malloc(*ft_info_len); if (!ft_info) return NULL; if (rsn_ie_len) qdf_mem_copy(ft_info, rsn_ie, rsn_ie_len); if (md_ie_len) qdf_mem_copy(ft_info + rsn_ie_len, md_ie, md_ie_len); if (ft_ie_len) qdf_mem_copy(ft_info + rsn_ie_len + md_ie_len, ft_ie, ft_ie_len); return ft_info; } /** * hdd_translate_rsn_to_csr_auth_type() - Translate RSN to CSR auth type * @auth_suite: auth suite * * Return: enum csr_akm_type enumeration */ enum csr_akm_type hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]) { enum csr_akm_type auth_type = eCSR_AUTH_TYPE_UNKNOWN; /* is the auth type supported? */ if (memcmp(auth_suite, ccp_rsn_oui01, 4) == 0) { auth_type = eCSR_AUTH_TYPE_RSN; } else if (memcmp(auth_suite, ccp_rsn_oui02, 4) == 0) { auth_type = eCSR_AUTH_TYPE_RSN_PSK; } else if (memcmp(auth_suite, ccp_rsn_oui04, 4) == 0) { /* Check for 11r FT Authentication with PSK */ auth_type = eCSR_AUTH_TYPE_FT_RSN_PSK; } else if (memcmp(auth_suite, ccp_rsn_oui03, 4) == 0) { /* Check for 11R FT Authentication with 802.1X */ auth_type = eCSR_AUTH_TYPE_FT_RSN; } else #ifdef FEATURE_WLAN_ESE if (memcmp(auth_suite, ccp_rsn_oui06, 4) == 0) { auth_type = eCSR_AUTH_TYPE_CCKM_RSN; } else #endif /* FEATURE_WLAN_ESE */ if (memcmp(auth_suite, ccp_rsn_oui07, 4) == 0) { auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256; } else if (memcmp(auth_suite, ccp_rsn_oui08, 4) == 0) { auth_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256; } else if (memcmp(auth_suite, ccp_rsn_oui_18, 4) == 0) { auth_type = eCSR_AUTH_TYPE_OWE; } else if (memcmp(auth_suite, ccp_rsn_oui_12, 4) == 0) { auth_type = eCSR_AUTH_TYPE_DPP_RSN; } else if (memcmp(auth_suite, ccp_rsn_oui_0b, 4) == 0) { /* Check for Suite B EAP 256 */ auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; } else if (memcmp(auth_suite, ccp_rsn_oui_0c, 4) == 0) { /* Check for Suite B EAP 384 */ auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; } else if (memcmp(auth_suite, ccp_rsn_oui_0d, 4) == 0) { /* Check for FT Suite B EAP 384 */ auth_type = eCSR_AUTH_TYPE_FT_SUITEB_EAP_SHA384; } else if (memcmp(auth_suite, ccp_rsn_oui_13, 4) == 0) { auth_type = eCSR_AUTH_TYPE_OSEN; } else { hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type); hdd_translate_sae_rsn_to_csr_auth(auth_suite, &auth_type); } return auth_type; } /** * hdd_translate_wpa_to_csr_auth_type() - Translate WPA to CSR auth type * @auth_suite: auth suite * * Return: enum csr_akm_type enumeration */ enum csr_akm_type hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]) { enum csr_akm_type auth_type = eCSR_AUTH_TYPE_UNKNOWN; /* is the auth type supported? */ if (memcmp(auth_suite, ccp_wpa_oui01, 4) == 0) { auth_type = eCSR_AUTH_TYPE_WPA; } else if (memcmp(auth_suite, ccp_wpa_oui02, 4) == 0) { auth_type = eCSR_AUTH_TYPE_WPA_PSK; } else #ifdef FEATURE_WLAN_ESE if (memcmp(auth_suite, ccp_wpa_oui06, 4) == 0) { auth_type = eCSR_AUTH_TYPE_CCKM_WPA; } else #endif /* FEATURE_WLAN_ESE */ { hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type); } return auth_type; } /** * hdd_translate_rsn_to_csr_encryption_type() - * Translate RSN to CSR encryption type * @cipher_suite: cipher suite * * Return: eCsrEncryptionType enumeration */ eCsrEncryptionType hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]) { eCsrEncryptionType cipher_type; if (memcmp(cipher_suite, ccp_rsn_oui04, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_AES; else if (memcmp(cipher_suite, ccp_rsn_oui09, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP; else if (memcmp(cipher_suite, ccp_rsn_oui0a, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP_256; else if (memcmp(cipher_suite, ccp_rsn_oui02, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_TKIP; else if (memcmp(cipher_suite, ccp_rsn_oui00, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_NONE; else if (memcmp(cipher_suite, ccp_rsn_oui01, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; else if (memcmp(cipher_suite, ccp_rsn_oui05, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; else cipher_type = eCSR_ENCRYPT_TYPE_FAILED; return cipher_type; } /** * hdd_translate_wpa_to_csr_encryption_type() - * Translate WPA to CSR encryption type * @cipher_suite: cipher suite * * Return: eCsrEncryptionType enumeration */ eCsrEncryptionType hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]) { eCsrEncryptionType cipher_type; if (memcmp(cipher_suite, ccp_wpa_oui04, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_AES; else if (memcmp(cipher_suite, ccp_wpa_oui02, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_TKIP; else if (memcmp(cipher_suite, ccp_wpa_oui00, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_NONE; else if (memcmp(cipher_suite, ccp_wpa_oui01, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; else if (memcmp(cipher_suite, ccp_wpa_oui05, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; else cipher_type = eCSR_ENCRYPT_TYPE_FAILED; return cipher_type; } #ifdef FEATURE_WLAN_WAPI enum csr_akm_type hdd_translate_wapi_to_csr_auth_type(uint8_t auth_suite[4]) { enum csr_akm_type auth_type; if (memcmp(auth_suite, ccp_wapi_oui01, 4) == 0) auth_type = eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; else if (memcmp(auth_suite, ccp_wapi_oui02, 4) == 0) auth_type = eCSR_AUTH_TYPE_WAPI_WAI_PSK; else auth_type = eCSR_AUTH_TYPE_UNKNOWN; return auth_type; } eCsrEncryptionType hdd_translate_wapi_to_csr_encryption_type(uint8_t cipher_suite[4]) { eCsrEncryptionType cipher_type; if (memcmp(cipher_suite, ccp_wapi_oui01, 4) == 0 || memcmp(cipher_suite, ccp_wapi_oui02, 4) == 0) cipher_type = eCSR_ENCRYPT_TYPE_WPI; else cipher_type = eCSR_ENCRYPT_TYPE_FAILED; return cipher_type; } #endif /* FEATURE_WLAN_WAPI */ enum cdp_peer_bw hdd_convert_ch_width_to_cdp_peer_bw(enum phy_ch_width ch_width) { switch (ch_width) { case CH_WIDTH_20MHZ: return CDP_20_MHZ; case CH_WIDTH_40MHZ: return CDP_40_MHZ; case CH_WIDTH_80MHZ: return CDP_80_MHZ; case CH_WIDTH_160MHZ: return CDP_160_MHZ; case CH_WIDTH_80P80MHZ: return CDP_80P80_MHZ; case CH_WIDTH_5MHZ: return CDP_5_MHZ; case CH_WIDTH_10MHZ: return CDP_10_MHZ; case CH_WIDTH_320MHZ: return CDP_320_MHZ; default: return CDP_BW_INVALID; } return CDP_BW_INVALID; } #ifdef WLAN_FEATURE_FILS_SK bool hdd_is_fils_connection(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter) { struct wlan_fils_connection_info *fils_info; fils_info = wlan_cm_get_fils_connection_info(hdd_ctx->psoc, adapter->deflink->vdev_id); if (fils_info) return fils_info->is_fils_connection; return false; } #else bool hdd_is_fils_connection(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter) { return false; } #endif void hdd_roam_profile_init(struct wlan_hdd_link_info *link_info) { struct csr_roam_profile *roam_profile; struct hdd_station_ctx *sta_ctx; hdd_enter(); roam_profile = hdd_roam_profile(link_info); qdf_mem_zero(roam_profile, sizeof(*roam_profile)); sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); /* Configure the roaming profile links to SSID and bssid. */ roam_profile->SSIDs.numOfSSIDs = 0; roam_profile->SSIDs.SSIDList = &sta_ctx->conn_info.ssid; roam_profile->BSSIDs.numOfBSSIDs = 0; roam_profile->BSSIDs.bssid = &sta_ctx->conn_info.bssid; /* Set the numOfChannels to zero to scan all the channels */ roam_profile->ChannelInfo.numOfChannels = 0; roam_profile->ChannelInfo.freq_list = NULL; roam_profile->BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; roam_profile->phyMode = eCSR_DOT11_MODE_AUTO; /* Set the default scan mode */ link_info->adapter->scan_info.scan_mode = eSIR_ACTIVE_SCAN; hdd_clear_roam_profile_ie(link_info->adapter); hdd_exit(); } struct osif_cm_ops osif_ops = { .connect_active_notify_cb = hdd_cm_connect_active_notify, .connect_complete_cb = hdd_cm_connect_complete, .disconnect_complete_cb = hdd_cm_disconnect_complete, .netif_queue_control_cb = hdd_cm_netif_queue_control, .napi_serialize_control_cb = hdd_cm_napi_serialize_control, .save_gtk_cb = hdd_cm_save_gtk, #ifdef WLAN_FEATURE_ROAM_OFFLOAD .roam_rt_stats_event_cb = wlan_hdd_cfg80211_roam_events_callback, #endif #ifdef WLAN_FEATURE_FILS_SK .set_hlp_data_cb = hdd_cm_set_hlp_data, #endif #ifdef WLAN_FEATURE_PREAUTH_ENABLE .ft_preauth_complete_cb = hdd_cm_ft_preauth_complete, #ifdef FEATURE_WLAN_ESE .cckm_preauth_complete_cb = hdd_cm_cckm_preauth_complete, #endif #endif #ifdef WLAN_VENDOR_HANDOFF_CONTROL .vendor_handoff_params_cb = hdd_cm_get_vendor_handoff_params, #endif .send_vdev_keys_cb = hdd_cm_send_vdev_keys, .get_scan_ie_params_cb = hdd_cm_get_scan_ie_params, #ifdef WLAN_BOOST_CPU_FREQ_IN_ROAM .perfd_set_cpufreq_cb = hdd_cm_perfd_set_cpufreq, #endif }; QDF_STATUS hdd_cm_register_cb(void) { QDF_STATUS status; osif_cm_set_legacy_cb(&osif_ops); status = osif_cm_register_cb(); if (QDF_IS_STATUS_ERROR(status)) return status; /* Overwrite with UTF cb if UTF enabled */ return cm_utf_register_os_if_cb(); } void hdd_cm_unregister_cb(void) { osif_cm_reset_legacy_cb(); }