blob: a083a7f48f3dd4847371ac3ff0488caaca62e798 [file] [log] [blame]
/*
* Copyright (c) 2016-2018 The Linux Foundation. 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_reassoc_utils.c
*
* Host based roaming re-association utilities
*/
#include "cds_api.h"
#include "ani_global.h"
#include "wni_api.h"
#include "sir_common.h"
#include "wni_cfg.h"
#include "cfg_api.h"
#include "sch_api.h"
#include "utils_api.h"
#include "lim_utils.h"
#include "lim_assoc_utils.h"
#include "lim_security_utils.h"
#include "lim_ser_des_utils.h"
#include "lim_sta_hash_api.h"
#include "lim_admit_control.h"
#include "lim_send_messages.h"
#include "lim_ibss_peer_mgmt.h"
#include "lim_ft_defs.h"
#include "lim_session.h"
#include "qdf_types.h"
#include "wma_types.h"
#include "lim_types.h"
/**
* lim_update_re_assoc_globals() - Update reassoc global data
* @mac: Global MAC context
* @pAssocRsp: Reassociation response data
* @pe_session: PE Session
*
* This function is called to Update the Globals (LIM) during ReAssoc.
*
* Return: None
*/
void lim_update_re_assoc_globals(struct mac_context *mac, tpSirAssocRsp pAssocRsp,
struct pe_session *pe_session)
{
/* Update the current Bss Information */
qdf_mem_copy(pe_session->bssId,
pe_session->limReAssocbssId, sizeof(tSirMacAddr));
pe_session->currentOperChannel = pe_session->limReassocChannelId;
pe_session->htSecondaryChannelOffset =
pe_session->reAssocHtSupportedChannelWidthSet;
pe_session->htRecommendedTxWidthSet =
pe_session->reAssocHtRecommendedTxWidthSet;
pe_session->htSecondaryChannelOffset =
pe_session->reAssocHtSecondaryChannelOffset;
pe_session->limCurrentBssCaps = pe_session->limReassocBssCaps;
pe_session->limCurrentBssQosCaps =
pe_session->limReassocBssQosCaps;
pe_session->limCurrentBssPropCap =
pe_session->limReassocBssPropCap;
qdf_mem_copy((uint8_t *) &pe_session->ssId,
(uint8_t *) &pe_session->limReassocSSID,
pe_session->limReassocSSID.length + 1);
/* Store assigned AID for TIM processing */
pe_session->limAID = pAssocRsp->aid & 0x3FFF;
/** Set the State Back to ReAssoc Rsp*/
pe_session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE;
MTRACE(mac_trace
(mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
pe_session->limMlmState));
}
/**
* @lim_handle_del_bss_in_re_assoc_context() - DEL BSS during reassociation
* @mac: Global MAC Context
* @pStaDs: Station Hash entry
* @pe_session: PE Session
*
* While Processing the ReAssociation Response Frame in STA,
* a.immediately after receiving the Reassoc Response the RxCleanUp is
* being issued and the end of DelBSS the new BSS is being added.
*
* b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context
* change, We need to update CSR with ReAssocCNF Response with the
* ReAssoc Fail and the reason Code, that is also being handled in the
* DELBSS context only
*
* Return: None
*/
void lim_handle_del_bss_in_re_assoc_context(struct mac_context *mac,
tpDphHashNode pStaDs, struct pe_session *pe_session)
{
tLimMlmReassocCnf mlmReassocCnf;
tpSirBssDescription bss_desc;
/*
* Skipped the DeleteDPH Hash Entry as we need it for the new BSS
* Set the MlmState to IDLE
*/
pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
/* Update PE session Id */
mlmReassocCnf.sessionId = pe_session->peSessionId;
switch (pe_session->limSmeState) {
case eLIM_SME_WT_REASSOC_STATE:
{
tpSirAssocRsp assocRsp;
tpDphHashNode pStaDs;
QDF_STATUS retStatus = QDF_STATUS_SUCCESS;
tpSchBeaconStruct beacon_struct;
beacon_struct = qdf_mem_malloc(sizeof(tSchBeaconStruct));
if (!beacon_struct) {
mlmReassocCnf.resultCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
mlmReassocCnf.protStatusCode =
eSIR_MAC_UNSPEC_FAILURE_STATUS;
lim_delete_dph_hash_entry(mac, pe_session->bssId,
DPH_STA_HASH_INDEX_PEER, pe_session);
goto error;
}
/* Delete the older STA Table entry */
lim_delete_dph_hash_entry(mac, pe_session->bssId,
DPH_STA_HASH_INDEX_PEER, pe_session);
/*
* Add an entry for AP to hash table
* maintained by DPH module
*/
pStaDs = dph_add_hash_entry(mac,
pe_session->limReAssocbssId,
DPH_STA_HASH_INDEX_PEER,
&pe_session->dph.dphHashTable);
if (pStaDs == NULL) {
/* Could not add hash table entry */
pe_err("could not add hash entry at DPH for");
lim_print_mac_addr(mac,
pe_session->limReAssocbssId, LOGE);
mlmReassocCnf.resultCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS;
qdf_mem_free(beacon_struct);
goto error;
}
/*
* While Processing the ReAssoc Response Frame the Rsp Frame
* is being stored to be used here for sending ADDBSS
*/
assocRsp =
(tpSirAssocRsp) pe_session->limAssocResponseData;
lim_update_assoc_sta_datas(mac, pStaDs, assocRsp,
pe_session);
lim_update_re_assoc_globals(mac, assocRsp, pe_session);
bss_desc = &pe_session->pLimReAssocReq->bssDescription;
lim_extract_ap_capabilities(mac,
(uint8_t *) bss_desc->ieFields,
lim_get_ielen_from_bss_description(bss_desc),
beacon_struct);
if (mac->lim.gLimProtectionControl !=
MLME_FORCE_POLICY_PROTECTION_DISABLE)
lim_decide_sta_protection_on_assoc(mac,
beacon_struct,
pe_session);
if (beacon_struct->erpPresent) {
if (beacon_struct->erpIEInfo.barkerPreambleMode)
pe_session->beaconParams.fShortPreamble = 0;
else
pe_session->beaconParams.fShortPreamble = 1;
}
/*
* updateBss flag is false, as in this case, PE is first
* deleting the existing BSS and then adding a new one
*/
if (QDF_STATUS_SUCCESS !=
lim_sta_send_add_bss(mac, assocRsp, beacon_struct,
bss_desc,
false, pe_session)) {
pe_err("Posting ADDBSS in the ReAssocCtx Failed");
retStatus = QDF_STATUS_E_FAILURE;
}
if (retStatus != QDF_STATUS_SUCCESS) {
mlmReassocCnf.resultCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
mlmReassocCnf.protStatusCode =
eSIR_MAC_UNSPEC_FAILURE_STATUS;
qdf_mem_free(assocRsp);
mac->lim.gLimAssocResponseData = NULL;
qdf_mem_free(beacon_struct);
goto error;
}
qdf_mem_free(assocRsp);
qdf_mem_free(beacon_struct);
pe_session->limAssocResponseData = NULL;
}
break;
default:
pe_err("DelBss in wrong system Role and SME State");
mlmReassocCnf.resultCode = eSIR_SME_REFUSED;
mlmReassocCnf.protStatusCode =
eSIR_SME_UNEXPECTED_REQ_RESULT_CODE;
goto error;
}
return;
error:
lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF,
(uint32_t *) &mlmReassocCnf);
}
/**
* @lim_handle_add_bss_in_re_assoc_context() - ADD BSS during reassociation
* @mac: Global MAC Context
* @pStaDs: Station Hash entry
* @pe_session: PE Session
*
* While Processing the ReAssociation Response Frame in STA,
* a. immediately after receiving the Reassoc Response the RxCleanUp is
* being issued and the end of DelBSS the new BSS is being added.
*
* b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context
* change, We need to update CSR with ReAssocCNF Response with the
* ReAssoc Fail and the reason Code, that is also being handled in the
* DELBSS context only
*
* Return: None
*/
void lim_handle_add_bss_in_re_assoc_context(struct mac_context *mac,
tpDphHashNode pStaDs, struct pe_session *pe_session)
{
tLimMlmReassocCnf mlmReassocCnf;
/** Skipped the DeleteDPH Hash Entry as we need it for the new BSS*/
/** Set the MlmState to IDLE*/
pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
MTRACE(mac_trace
(mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
pe_session->limMlmState));
switch (pe_session->limSmeState) {
case eLIM_SME_WT_REASSOC_STATE: {
tpSirAssocRsp assocRsp;
tpDphHashNode pStaDs;
QDF_STATUS retStatus = QDF_STATUS_SUCCESS;
tSchBeaconStruct *pBeaconStruct;
pBeaconStruct =
qdf_mem_malloc(sizeof(tSchBeaconStruct));
if (!pBeaconStruct) {
mlmReassocCnf.resultCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
mlmReassocCnf.protStatusCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
goto Error;
}
/* Get the AP entry from DPH hash table */
pStaDs =
dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER,
&pe_session->dph.dphHashTable);
if (pStaDs == NULL) {
pe_err("Fail to get STA PEER entry from hash");
mlmReassocCnf.resultCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS;
qdf_mem_free(pBeaconStruct);
goto Error;
}
/*
* While Processing the ReAssoc Response Frame the Rsp Frame
* is being stored to be used here for sending ADDBSS
*/
assocRsp =
(tpSirAssocRsp) pe_session->limAssocResponseData;
lim_update_assoc_sta_datas(mac, pStaDs, assocRsp,
pe_session);
lim_update_re_assoc_globals(mac, assocRsp, pe_session);
lim_extract_ap_capabilities(mac,
(uint8_t *) pe_session->
pLimReAssocReq->bssDescription.
ieFields,
lim_get_ielen_from_bss_description
(&pe_session->
pLimReAssocReq->
bssDescription),
pBeaconStruct);
if (mac->lim.gLimProtectionControl !=
MLME_FORCE_POLICY_PROTECTION_DISABLE)
lim_decide_sta_protection_on_assoc(mac,
pBeaconStruct,
pe_session);
if (pBeaconStruct->erpPresent) {
if (pBeaconStruct->erpIEInfo.barkerPreambleMode)
pe_session->beaconParams.
fShortPreamble = 0;
else
pe_session->beaconParams.
fShortPreamble = 1;
}
pe_session->isNonRoamReassoc = 1;
if (QDF_STATUS_SUCCESS !=
lim_sta_send_add_bss(mac, assocRsp, pBeaconStruct,
&pe_session->pLimReAssocReq->
bssDescription, true,
pe_session)) {
pe_err("Post ADDBSS in the ReAssocCtxt Failed");
retStatus = QDF_STATUS_E_FAILURE;
}
if (retStatus != QDF_STATUS_SUCCESS) {
mlmReassocCnf.resultCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
mlmReassocCnf.protStatusCode =
eSIR_MAC_UNSPEC_FAILURE_STATUS;
qdf_mem_free(assocRsp);
mac->lim.gLimAssocResponseData = NULL;
qdf_mem_free(pBeaconStruct);
goto Error;
}
qdf_mem_free(assocRsp);
pe_session->limAssocResponseData = NULL;
qdf_mem_free(pBeaconStruct);
}
break;
default:
pe_err("DelBss in the wrong system Role and SME State");
mlmReassocCnf.resultCode = eSIR_SME_REFUSED;
mlmReassocCnf.protStatusCode =
eSIR_SME_UNEXPECTED_REQ_RESULT_CODE;
goto Error;
}
return;
Error:
lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF,
(uint32_t *) &mlmReassocCnf);
}
/**
* lim_is_reassoc_in_progress() - Check if reassoiciation is in progress
* @mac: Global MAC Context
* @pe_session: PE Session
*
* Return: true When STA is waiting for Reassoc response from AP
* else false
*/
bool lim_is_reassoc_in_progress(struct mac_context *mac, struct pe_session *pe_session)
{
if (pe_session == NULL)
return false;
if (LIM_IS_STA_ROLE(pe_session) &&
(pe_session->limSmeState == eLIM_SME_WT_REASSOC_STATE))
return true;
return false;
}
/**
* lim_add_ft_sta_self()- function to add STA once we have connected with a
* new AP
* @mac_ctx: pointer to global mac structure
* @assoc_id: association id for the station connection
* @session_entry: pe session entr
*
* This function is called to add a STA once we have connected with a new
* AP, that we have performed an FT to.
*
* The Add STA Response is created and now after the ADD Bss Is Successful
* we add the self sta. We update with the association id from the reassoc
* response from the AP.
*
* Return: QDF_STATUS_SUCCESS on success else QDF_STATUS failure codes
*/
QDF_STATUS lim_add_ft_sta_self(struct mac_context *mac_ctx, uint16_t assoc_id,
struct pe_session *session_entry)
{
tpAddStaParams add_sta_params = NULL;
QDF_STATUS ret_code = QDF_STATUS_SUCCESS;
struct scheduler_msg msg_q = {0};
add_sta_params = session_entry->ftPEContext.pAddStaReq;
add_sta_params->assocId = assoc_id;
add_sta_params->smesessionId = session_entry->smeSessionId;
msg_q.type = WMA_ADD_STA_REQ;
msg_q.reserved = 0;
msg_q.bodyptr = add_sta_params;
msg_q.bodyval = 0;
QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
"Sending WMA_ADD_STA_REQ (aid %d)",
add_sta_params->assocId);
MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId,
msg_q.type));
session_entry->limPrevMlmState = session_entry->limMlmState;
MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE,
session_entry->peSessionId, eLIM_MLM_WT_ADD_STA_RSP_STATE));
session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE;
ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q);
if (QDF_STATUS_SUCCESS != ret_code) {
pe_err("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X",
ret_code);
qdf_mem_free(add_sta_params);
}
session_entry->ftPEContext.pAddStaReq = NULL;
return ret_code;
}
/**
* lim_restore_pre_reassoc_state() - Restore the pre-association context
* @mac: Global MAC Context
* @resultCode: Assoc response result
* @protStatusCode: Internal protocol status code
* @pe_session: PE Session
*
* This function is called on STA role whenever Reasociation
* Response with a reject code is received from AP.
* Reassociation failure timer is stopped, Old (or current) AP's
* context is restored both at Polaris & software
*
* Return: None
*/
void
lim_restore_pre_reassoc_state(struct mac_context *mac,
tSirResultCodes resultCode, uint16_t protStatusCode,
struct pe_session *pe_session)
{
tLimMlmReassocCnf mlmReassocCnf;
pe_debug("sessionid: %d protStatusCode: %d resultCode: %d",
pe_session->smeSessionId, protStatusCode, resultCode);
pe_session->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
MTRACE(mac_trace
(mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
eLIM_MLM_LINK_ESTABLISHED_STATE));
/* 'Change' timer for future activations */
lim_deactivate_and_change_timer(mac, eLIM_REASSOC_FAIL_TIMER);
lim_set_channel(mac, pe_session->currentOperChannel,
pe_session->ch_center_freq_seg0,
pe_session->ch_center_freq_seg1,
pe_session->ch_width,
pe_session->maxTxPower,
pe_session->peSessionId,
0, 0);
/* @ToDo:Need to Integrate the STOP the Dataxfer to AP from 11H code */
mlmReassocCnf.resultCode = resultCode;
mlmReassocCnf.protStatusCode = protStatusCode;
mlmReassocCnf.sessionId = pe_session->peSessionId;
lim_post_sme_message(mac,
LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf);
}
/**
* lim_post_reassoc_failure() - Post failure message to SME
* @mac: Global MAC Context
* @resultCode: Result Code
* @protStatusCode: Protocol Status Code
* @pe_session: PE Session
*
* Return: None
*/
void lim_post_reassoc_failure(struct mac_context *mac,
tSirResultCodes resultCode, uint16_t protStatusCode,
struct pe_session *pe_session)
{
tLimMlmReassocCnf mlmReassocCnf;
pe_session->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
MTRACE(mac_trace
(mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
eLIM_MLM_LINK_ESTABLISHED_STATE));
lim_deactivate_and_change_timer(mac, eLIM_REASSOC_FAIL_TIMER);
mlmReassocCnf.resultCode = resultCode;
mlmReassocCnf.protStatusCode = protStatusCode;
mlmReassocCnf.sessionId = pe_session->peSessionId;
lim_post_sme_message(mac,
LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf);
}