/* * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 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: lim_ft_preauth.c * * Pre-Authentication implementation for host based roaming */ #include #include #include #include #include #include #include #include #include #include #include #include "wma.h" #include "wlan_crypto_global_api.h" /** * lim_ft_cleanup_pre_auth_info() - Cleanup preauth related information * @mac: Global MAC Context * @pe_session: PE Session * * This routine is called to free the FT context, session and other * information used during preauth operation. * * Return: None */ void lim_ft_cleanup_pre_auth_info(struct mac_context *mac, struct pe_session *pe_session) { struct pe_session *pReAssocSessionEntry = NULL; uint8_t sessionId = 0; if (!pe_session) { pe_err("pe_session is NULL"); return; } /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(pe_session)) { pe_err("pe_session is not in STA mode"); return; } if (pe_session->ftPEContext.pFTPreAuthReq) { pReAssocSessionEntry = pe_find_session_by_bssid(mac, pe_session->ftPEContext. pFTPreAuthReq->preAuthbssId, &sessionId); if (pe_session->ftPEContext.pFTPreAuthReq-> pbssDescription) { qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq-> pbssDescription); pe_session->ftPEContext.pFTPreAuthReq-> pbssDescription = NULL; } qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq); pe_session->ftPEContext.pFTPreAuthReq = NULL; } if (pe_session->ftPEContext.pAddBssReq) { qdf_mem_free(pe_session->ftPEContext.pAddBssReq); pe_session->ftPEContext.pAddBssReq = NULL; } if (pe_session->ftPEContext.pAddStaReq) { qdf_mem_free(pe_session->ftPEContext.pAddStaReq); pe_session->ftPEContext.pAddStaReq = NULL; } /* The session is being deleted, cleanup the contents */ qdf_mem_zero(&pe_session->ftPEContext, sizeof(tftPEContext)); /* Delete the session created while handling pre-auth response */ if (pReAssocSessionEntry) { /* If we have successful pre-auth response, then we would have * created a session on which reassoc request will be sent */ if (pReAssocSessionEntry->valid && pReAssocSessionEntry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { pe_debug("Deleting Preauth session(%d)", pReAssocSessionEntry->peSessionId); pe_delete_session(mac, pReAssocSessionEntry); } } } /* * lim_process_ft_pre_auth_req() - process ft pre auth req * * @mac_ctx: global mac ctx * @ft_pre_auth_req: ft preauth request * * In this function, we process the FT Pre Auth Req: * We receive Pre-Auth, suspend link, register a call back. In the call back, * we will need to accept frames from the new bssid. Send out the auth req to * new AP. Start timer and when the timer is done or if we receive the Auth * response. We change channel. Resume link * * Return: value to indicate if buffer was consumed */ bool lim_process_ft_pre_auth_req(struct mac_context *mac_ctx, tpSirFTPreAuthReq ft_pre_auth_req) { bool buf_consumed = false; struct pe_session *session; uint8_t session_id; if (!ft_pre_auth_req) { pe_err("tSirFTPreAuthReq is NULL"); return buf_consumed; } /* Get the current session entry */ session = pe_find_session_by_bssid(mac_ctx, ft_pre_auth_req->currbssId, &session_id); if (!session) { pe_err("Unable to find session for the bssid " QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(ft_pre_auth_req->currbssId)); /* Post the FT Pre Auth Response to SME */ lim_post_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, session); buf_consumed = true; return buf_consumed; } /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(session)) { pe_err("session is not in STA mode"); buf_consumed = true; return buf_consumed; } /* Can set it only after sending auth */ session->ftPEContext.ftPreAuthStatus = QDF_STATUS_E_FAILURE; session->ftPEContext.ftPreAuthSession = true; /* Indicate that this is the session on which preauth is being done */ if (session->ftPEContext.pFTPreAuthReq) { if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { qdf_mem_free( session->ftPEContext.pFTPreAuthReq->pbssDescription); session->ftPEContext.pFTPreAuthReq->pbssDescription = NULL; } qdf_mem_free(session->ftPEContext.pFTPreAuthReq); session->ftPEContext.pFTPreAuthReq = NULL; } /* We need information from the Pre-Auth Req. Lets save that */ session->ftPEContext.pFTPreAuthReq = ft_pre_auth_req; pe_debug("PRE Auth ft_ies_length=%02x%02x%02x", session->ftPEContext.pFTPreAuthReq->ft_ies[0], session->ftPEContext.pFTPreAuthReq->ft_ies[1], session->ftPEContext.pFTPreAuthReq->ft_ies[2]); #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, session, 0, 0); #endif /* * Dont need to suspend if APs are in same channel and DUT * is not in MCC state */ if ((session->curr_op_freq != session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq) || lim_is_in_mcc(mac_ctx)) { /* Need to suspend link only if the channels are different */ pe_debug("Performing pre-auth on diff channel(session %pK)", session); lim_send_preauth_scan_offload(mac_ctx, session, session->ftPEContext.pFTPreAuthReq); } else { pe_debug("Performing pre-auth on same channel (session %pK)", session); /* We are in the same channel. Perform pre-auth */ lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL, session); } return buf_consumed; } /** * lim_perform_ft_pre_auth() - Perform preauthentication * @mac: Global MAC Context * @status: Status Code * @data: pre-auth data * @pe_session: PE Session * * This routine will trigger the sending of authentication frame * to the peer. * * Return: None */ void lim_perform_ft_pre_auth(struct mac_context *mac, QDF_STATUS status, uint32_t *data, struct pe_session *pe_session) { tSirMacAuthFrameBody authFrame; bool is_open = false; if (!pe_session) { pe_err("pe_session is NULL"); return; } if (cm_is_open_mode(pe_session->vdev)) is_open = true; if (pe_session->is11Rconnection && pe_session->ftPEContext.pFTPreAuthReq) { /* Only 11r assoc has FT IEs */ if ((!is_open) && (pe_session->ftPEContext.pFTPreAuthReq->ft_ies_length == 0)) { pe_err("FTIEs for Auth Req Seq 1 is absent"); goto preauth_fail; } } if (status != QDF_STATUS_SUCCESS) { pe_err("Change channel not successful for FT pre-auth"); goto preauth_fail; } /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(pe_session)) { pe_err("pe_session is not in STA mode"); return; } if (cm_is_auth_type_sae(pe_session->vdev)) { struct qdf_mac_addr *pre_auth_bssid = (struct qdf_mac_addr *) pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId; lim_trigger_auth_req_sae(mac, pe_session, pre_auth_bssid); return; } pe_debug("Entered wait auth2 state for FT (old session %pK)", pe_session); if (pe_session->is11Rconnection) { /* Now we are on the right channel and need to send out Auth1 * and receive Auth2 */ authFrame.authAlgoNumber = eSIR_FT_AUTH; } else { /* Will need to make isESEconnection a enum may be for further * improvements to this to match this algorithm number */ authFrame.authAlgoNumber = eSIR_OPEN_SYSTEM; } authFrame.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; authFrame.authStatusCode = 0; mac->lim.lim_timers.g_lim_periodic_auth_retry_timer.sessionId = pe_session->peSessionId; /* Start timer here to come back to operating channel */ mac->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId = pe_session->peSessionId; if (TX_SUCCESS != tx_timer_activate(&mac->lim.lim_timers.gLimFTPreAuthRspTimer)) { pe_err("FT Auth Rsp Timer Start Failed"); goto preauth_fail; } MTRACE(mac_trace(mac, TRACE_CODE_TIMER_ACTIVATE, pe_session->peSessionId, eLIM_FT_PREAUTH_RSP_TIMER)); pe_debug("FT Auth Rsp Timer Started"); #ifdef FEATURE_WLAN_DIAG_SUPPORT lim_diag_event_report(mac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, mac->lim.pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); #endif if (pe_session->ftPEContext.pFTPreAuthReq) lim_send_auth_mgmt_frame(mac, &authFrame, pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId, LIM_NO_WEP_IN_FC, pe_session); return; preauth_fail: lim_handle_ft_pre_auth_rsp(mac, QDF_STATUS_E_FAILURE, NULL, 0, pe_session); return; } /** * lim_ft_setup_auth_session() - Fill the FT Session * @mac: Global MAC Context * @pe_session: PE Session * * Setup the session and the add bss req for the pre-auth AP. * * Return: Success or Failure Status */ QDF_STATUS lim_ft_setup_auth_session(struct mac_context *mac, struct pe_session *pe_session) { struct pe_session *ft_session = NULL; uint8_t sessionId = 0; struct sSirFTPreAuthReq *req; QDF_STATUS status; ft_session = pe_find_session_by_bssid(mac, pe_session->limReAssocbssId, &sessionId); if (!ft_session) { pe_err("No session found for bssid: "QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); return QDF_STATUS_E_FAILURE; } /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(pe_session)) { pe_err("pe_session is not in STA mode"); return QDF_STATUS_E_FAILURE; } req = pe_session->ftPEContext.pFTPreAuthReq; if (req && req->pbssDescription) { status = lim_fill_ft_session(mac, req->pbssDescription, ft_session, pe_session, WLAN_PHYMODE_AUTO); if (QDF_IS_STATUS_ERROR(status)) pe_err("Failed to fill ft session for vdev id %d", ft_session->vdev_id); lim_ft_prepare_add_bss_req(mac, ft_session, req->pbssDescription); } return QDF_STATUS_SUCCESS; } /** * lim_ft_process_pre_auth_result() - Process the Auth frame * @mac: Global MAC context * @pe_session: PE Session * * Return: None */ static void lim_ft_process_pre_auth_result(struct mac_context *mac, struct pe_session *pe_session) { if (!pe_session || !pe_session->ftPEContext.pFTPreAuthReq) return; /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(pe_session)) { pe_err("pe_session is not in STA mode"); return; } if (pe_session->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) { pe_session->ftPEContext.ftPreAuthStatus = lim_ft_setup_auth_session(mac, pe_session); } /* Post the FT Pre Auth Response to SME */ lim_post_ft_pre_auth_rsp(mac, pe_session->ftPEContext.ftPreAuthStatus, pe_session->ftPEContext.saved_auth_rsp, pe_session->ftPEContext.saved_auth_rsp_length, pe_session); } /** * lim_handle_ft_pre_auth_rsp() - Handle the Auth response * @mac: Global MAC Context * @status: Status Code * @auth_rsp: Auth Response * @auth_rsp_length: Auth response length * @pe_session: PE Session * * Send the FT Pre Auth Response to SME whenever we have a status * ready to be sent to SME * * SME will be the one to send it up to the supplicant to receive * FTIEs which will be required for Reassoc Req. * * @Return: None */ void lim_handle_ft_pre_auth_rsp(struct mac_context *mac, QDF_STATUS status, uint8_t *auth_rsp, uint16_t auth_rsp_length, struct pe_session *pe_session) { struct pe_session *ft_session = NULL; uint8_t sessionId = 0; struct bss_description *pbssDescription = NULL; #ifdef FEATURE_WLAN_DIAG_SUPPORT lim_diag_event_report(mac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, pe_session, (uint16_t) status, 0); #endif /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(pe_session)) { pe_err("pe_session is not in STA mode"); return; } /* Save the status of pre-auth */ pe_session->ftPEContext.ftPreAuthStatus = status; /* Save the auth rsp, so we can send it to * SME once we resume link */ pe_session->ftPEContext.saved_auth_rsp_length = 0; if ((auth_rsp) && (auth_rsp_length < MAX_FTIE_SIZE)) { qdf_mem_copy(pe_session->ftPEContext.saved_auth_rsp, auth_rsp, auth_rsp_length); pe_session->ftPEContext.saved_auth_rsp_length = auth_rsp_length; } if (!pe_session->ftPEContext.pFTPreAuthReq || !pe_session->ftPEContext.pFTPreAuthReq->pbssDescription) { pe_err("pFTPreAuthReq or pbssDescription is NULL"); return; } /* Create FT session for the re-association at this point */ if (pe_session->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) { pbssDescription = pe_session->ftPEContext.pFTPreAuthReq->pbssDescription; ft_session = pe_create_session(mac, pbssDescription->bssId, &sessionId, mac->lim.max_sta_of_pe_session, pe_session->bssType, pe_session->vdev_id); if (!ft_session) { pe_err("Session not created for pre-auth 11R AP"); status = QDF_STATUS_E_FAILURE; pe_session->ftPEContext.ftPreAuthStatus = status; goto send_rsp; } sir_copy_mac_addr(ft_session->self_mac_addr, pe_session->self_mac_addr); sir_copy_mac_addr(ft_session->limReAssocbssId, pbssDescription->bssId); /* Update the beacon/probe filter in mac_ctx */ lim_set_bcn_probe_filter(mac, ft_session, 0); if (ft_session->bssType == eSIR_INFRASTRUCTURE_MODE) ft_session->limSystemRole = eLIM_STA_ROLE; else pe_err("Invalid bss type"); ft_session->limPrevSmeState = ft_session->limSmeState; ft_session->ht_config = pe_session->ht_config; ft_session->limSmeState = eLIM_SME_WT_REASSOC_STATE; if (wlan_reg_is_24ghz_ch_freq(pe_session->ftPEContext. pFTPreAuthReq->pre_auth_channel_freq)) ft_session->vdev_nss = mac->vdev_type_nss_2g.sta; else ft_session->vdev_nss = mac->vdev_type_nss_5g.sta; /* Update the ReAssoc BSSID of the current session */ sir_copy_mac_addr(pe_session->limReAssocbssId, pbssDescription->bssId); pe_debug("created session (%pK) with id = %d BSSID = "QDF_MAC_ADDR_FMT, ft_session, ft_session->peSessionId, QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); } send_rsp: if ((pe_session->curr_op_freq != pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq) || lim_is_in_mcc(mac)) { pe_debug("Pre auth on diff freq as connected AP freq %d or mcc pe sessions exist, so abort scan", pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq); /* Need to move to the original AP channel */ lim_process_abort_scan_ind(mac, pe_session->smeSessionId, pe_session->ftPEContext.pFTPreAuthReq->scan_id, mac->lim.req_id | PREAUTH_REQUESTOR_ID); } /* * Send resp to connection manager, even in case scan needs abort, * scan complete will be no-op. */ lim_ft_process_pre_auth_result(mac, pe_session); } /* * lim_process_ft_preauth_rsp_timeout() - process ft preauth rsp timeout * * @mac_ctx: global mac ctx * * This function is called if preauth response is not received from the AP * within this timeout while FT in progress * * Return: void */ void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac_ctx) { struct pe_session *session; /* * We have failed pre auth. We need to resume link and get back on * home channel */ pe_err("FT Pre-Auth Time Out!!!!"); session = pe_find_session_by_session_id(mac_ctx, mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId); if (!session) { pe_err("Session Does not exist for given sessionID"); return; } /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(session)) { pe_err("session is not in STA mode"); return; } /* Reset the flag to indicate preauth request session */ session->ftPEContext.ftPreAuthSession = false; if (!session->ftPEContext.pFTPreAuthReq) { /* Auth Rsp might already be posted to SME and ftcleanup done */ pe_err("pFTPreAuthReq is NULL sessionId: %d", mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId); return; } /* * To handle the race condition where we receive preauth rsp after * timer has expired. */ if (true == session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { pe_err("Auth rsp already posted to SME (session %pK)", session); return; } else { /* * Here we are sending preauth rsp with failure state * and which is forwarded to SME. Now, if we receive an preauth * resp from AP with success it would create a FT pesession, but * will be dropped in SME leaving behind the pesession. Mark * Preauth rsp processed so that any rsp from AP is dropped in * lim_process_auth_frame_no_session. */ pe_debug("Auth rsp not yet posted to SME (session %pK)", session); session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = true; } /* * Attempted at Pre-Auth and failed. If we are off channel. We need * to get back to home channel */ lim_handle_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, session); } /* * lim_cm_post_preauth_rsp() - post preauth response to osif. * * @mac_ctx: global mac ctx * @status: status code to post in auth rsp * @auth_rsp: pointer to auth rsp FT ie * @auth_rsp_length: len of the IE field * @session: pe session * * post preauth response to osif. * * Return: void */ static void lim_cm_post_preauth_rsp(struct mac_context *mac_ctx, QDF_STATUS status, uint8_t *auth_rsp, uint16_t auth_rsp_length, struct pe_session *session) { QDF_STATUS qdf_status; struct scheduler_msg rsp_msg = {0}; struct wlan_preauth_rsp *rsp; rsp = qdf_mem_malloc(sizeof(*rsp)); if (!rsp) return; rsp->psoc = mac_ctx->psoc; if (session) { /* Nothing to be done if the session is not in STA mode */ if (!LIM_IS_STA_ROLE(session)) { pe_err("session is not in STA mode"); qdf_mem_free(rsp); return; } rsp->vdev_id = session->vdev_id; /* The bssid of the AP we are sending Auth1 to. */ if (session->ftPEContext.pFTPreAuthReq) qdf_mem_copy(rsp->pre_auth_bssid.bytes, session->ftPEContext. pFTPreAuthReq->preAuthbssId, QDF_MAC_ADDR_SIZE); } rsp->status = status; /* Attach the auth response now back to osif */ rsp->ft_ie_length = 0; if (auth_rsp && (auth_rsp_length < MAX_FTIE_SIZE)) { /* Only 11r assoc has FT IEs */ qdf_mem_copy(rsp->ft_ie, auth_rsp, auth_rsp_length); rsp->ft_ie_length = auth_rsp_length; } rsp_msg.bodyptr = rsp; rsp_msg.callback = cm_handle_preauth_rsp; qdf_status = scheduler_post_message( QDF_MODULE_ID_PE, QDF_MODULE_ID_OS_IF, QDF_MODULE_ID_OS_IF, &rsp_msg); if (QDF_IS_STATUS_ERROR(qdf_status)) { pe_err("Failed to post preauth rsp to sme vdev_id %d", rsp->vdev_id); qdf_mem_free(rsp); } } /* * lim_post_ft_pre_auth_rsp() - post ft pre auth response to SME. * * @mac_ctx: global mac ctx * @status: status code to post in auth rsp * @auth_rsp: pointer to auth rsp FT ie * @auth_rsp_length: len of the IE field * @session: pe session * * post pre auth response to SME. * * Return: void */ void lim_post_ft_pre_auth_rsp(struct mac_context *mac_ctx, QDF_STATUS status, uint8_t *auth_rsp, uint16_t auth_rsp_length, struct pe_session *session) { #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ if (status == QDF_STATUS_SUCCESS) lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PREAUTH_DONE, session, status, 0); #endif lim_cm_post_preauth_rsp(mac_ctx, status, auth_rsp, auth_rsp_length, session); } /** * lim_send_preauth_scan_offload() - Send scan command to handle preauth. * * @mac_ctx: Pointer to Global MAC structure * @session_entry: pe session * @ft_preauth_req: Preauth request with parameters * * Builds a single channel scan request and sends it to scan module. * Scan dwell time is the time allocated to go to preauth candidate * channel for auth frame exchange. * * Return: Status of sending message to scan module. */ QDF_STATUS lim_send_preauth_scan_offload(struct mac_context *mac_ctx, struct pe_session *session_entry, tSirFTPreAuthReq *ft_preauth_req) { struct scan_start_request *req; struct wlan_objmgr_vdev *vdev; uint8_t vdev_id; QDF_STATUS status = QDF_STATUS_SUCCESS; if (!session_entry) { pe_err("Session entry is NULL"); return QDF_STATUS_E_FAILURE; } vdev_id = session_entry->smeSessionId; req = qdf_mem_malloc(sizeof(*req)); if (!req) return QDF_STATUS_E_NOMEM; qdf_mem_zero(req, sizeof(*req)); vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, vdev_id, WLAN_LEGACY_MAC_ID); if (!vdev) { pe_err("vdev_id %d: vdev is NULL", vdev_id); qdf_mem_free(req); return QDF_STATUS_E_FAILURE; } wlan_scan_init_default_params(vdev, req); qdf_mem_copy(req->scan_req.bssid_list, (uint8_t *)ft_preauth_req->currbssId, QDF_MAC_ADDR_SIZE); req->scan_req.scan_id = wlan_scan_get_scan_id(mac_ctx->psoc); if (!req->scan_req.scan_id) { wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); qdf_mem_free(req); pe_err("Invalid scan ID"); return QDF_STATUS_E_FAILURE; } ft_preauth_req->scan_id = req->scan_req.scan_id; req->scan_req.vdev_id = vdev_id; req->scan_req.scan_req_id = mac_ctx->lim.req_id | PREAUTH_REQUESTOR_ID; req->scan_req.scan_priority = SCAN_PRIORITY_VERY_HIGH; req->scan_req.scan_f_passive = true; req->scan_req.chan_list.num_chan = 1; req->scan_req.chan_list.chan[0].freq = ft_preauth_req->pre_auth_channel_freq; req->scan_req.dwell_time_active = LIM_FT_PREAUTH_ACTIVE_SCAN_TIME; req->scan_req.dwell_time_passive = LIM_FT_PREAUTH_PASSIVE_SCAN_TIME; status = wlan_scan_start(req); if (QDF_IS_STATUS_ERROR(status)) /* Don't free req here, ucfg_scan_start will do free */ pe_info("Issue scan req failed"); wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); return status; } void lim_preauth_scan_event_handler(struct mac_context *mac_ctx, enum sir_scan_event_type event, uint8_t vdev_id, uint32_t scan_id) { struct pe_session *session_entry; session_entry = pe_find_session_by_scan_id(mac_ctx, scan_id); /* Pre-auth request is sent */ if (session_entry) { if ((event == SIR_SCAN_EVENT_FOREIGN_CHANNEL) && (session_entry->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS)) { pe_err("Pre-auth is done, skip sending pre-auth req"); return; } } else { /* For the first pre-auth request * need to get it by sme session id (vdev id) */ session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); } if (!session_entry) { pe_err("vdev_id :%d PeSessionId:%d does not exist", vdev_id, mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId); return; } switch (event) { case SIR_SCAN_EVENT_START_FAILED: /* Scan command is rejected by firmware */ pe_err("Failed to start preauth scan"); lim_post_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, session_entry); return; case SIR_SCAN_EVENT_COMPLETED: /* * Scan either completed successfully or or got terminated * after successful auth, or timed out. Either way, STA * is back to home channel. Data traffic can continue. * Don't do anything as preauth timer/auth resp will take care * of the sending resp to the connection manager. */ break; case SIR_SCAN_EVENT_FOREIGN_CHANNEL: /* Sta is on candidate channel. Send auth */ lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL, session_entry); break; default: /* Don't print message for scan events that are ignored */ break; } }