blob: dda8a94e33315ca824cb2faacc664c7bd326c438 [file] [log] [blame]
/*
* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/**========================================================================
\file wlan_hdd_assoc.c
\brief WLAN Host Device Driver implementation
========================================================================*/
/**=========================================================================
EDIT HISTORY FOR FILE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header:$ $DateTime: $ $Author: $
when who what, where, why
-------- --- --------------------------------------------------------
05/06/09 Shailender Created module.
==========================================================================*/
#include "wlan_hdd_includes.h"
#include <aniGlobal.h>
#include "dot11f.h"
#include "wlan_nlink_common.h"
#include "wlan_hdd_power.h"
#include "wlan_hdd_trace.h"
#include <linux/ieee80211.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include "wlan_hdd_cfg80211.h"
#include "csrInsideApi.h"
#include "wlan_hdd_p2p.h"
#ifdef FEATURE_WLAN_TDLS
#include "wlan_hdd_tdls.h"
#endif
#include "sme_Api.h"
#include "wlan_hdd_hostapd.h"
#ifdef IPA_OFFLOAD
#include <wlan_hdd_ipa.h>
#endif
#include <vos_sched.h>
#include <wlan_logging_sock_svc.h>
#include "tl_shim.h"
#include "wlan_hdd_oemdata.h"
#include "wlan_hdd_tsf.h"
#include "adf_trace.h"
#ifdef WLAN_FEATURE_SAP_TO_FOLLOW_STA_CHAN
#include "wlan_hdd_hostapd.h"
#endif//#ifdef WLAN_FEATURE_SAP_TO_FOLLOW_STA_CHAN
struct ether_addr
{
u_char ether_addr_octet[6];
};
// These are needed to recognize WPA and RSN suite types
#define HDD_WPA_OUI_SIZE 4
v_U8_t ccpWpaOui00[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x50, 0xf2, 0x00 };
v_U8_t ccpWpaOui01[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x50, 0xf2, 0x01 };
v_U8_t ccpWpaOui02[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x50, 0xf2, 0x02 };
v_U8_t ccpWpaOui03[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x50, 0xf2, 0x03 };
v_U8_t ccpWpaOui04[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x50, 0xf2, 0x04 };
v_U8_t ccpWpaOui05[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x50, 0xf2, 0x05 };
#ifdef FEATURE_WLAN_ESE
v_U8_t ccpWpaOui06[ HDD_WPA_OUI_SIZE ] = { 0x00, 0x40, 0x96, 0x00 }; // CCKM
#endif /* FEATURE_WLAN_ESE */
#define HDD_RSN_OUI_SIZE 4
v_U8_t ccpRSNOui00[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x00 }; // group cipher
v_U8_t ccpRSNOui01[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x01 }; // WEP-40 or RSN
v_U8_t ccpRSNOui02[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x02 }; // TKIP or RSN-PSK
v_U8_t ccpRSNOui03[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x03 }; // Reserved
v_U8_t ccpRSNOui04[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x04 }; // AES-CCMP
v_U8_t ccpRSNOui05[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x05 }; // WEP-104
#ifdef FEATURE_WLAN_ESE
v_U8_t ccpRSNOui06[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x40, 0x96, 0x00 }; // CCKM
#endif /* FEATURE_WLAN_ESE */
#ifdef WLAN_FEATURE_11W
v_U8_t ccpRSNOui07[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x06 }; // RSN-PSK-SHA256
/* RSN-8021X-SHA256 */
v_U8_t ccpRSNOui08[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x05 };
#endif
#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
#if defined(WLAN_FEATURE_VOWIFI_11R)
// Offset where the EID-Len-IE, start.
#define FT_ASSOC_RSP_IES_OFFSET 6 /* Capability(2) + AID(2) + Status Code(2)*/
#define FT_ASSOC_REQ_IES_OFFSET 4 /* Capability(2) + LI(2) */
#endif
#define BEACON_FRAME_IES_OFFSET 12
#define NUM_BITS_IN_INT 32
static const int beacon_filter_table[] = {
SIR_MAC_DS_PARAM_SET_EID,
SIR_MAC_ERP_INFO_EID,
SIR_MAC_EDCA_PARAM_SET_EID,
SIR_MAC_QOS_CAPABILITY_EID,
SIR_MAC_HT_INFO_EID,
#ifdef WLAN_FEATURE_11AC
SIR_MAC_VHT_OPMODE_EID,
SIR_MAC_VHT_OPERATION_EID,
#endif
};
static eHalStatus hdd_RoamSetKeyCompleteHandler( hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
tANI_U32 roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult );
static v_VOID_t
hdd_connSetAuthenticated(hdd_adapter_t *pAdapter, v_U8_t authState)
{
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
/* save the new connection state */
hddLog(LOG1, FL("Authenticated state Changed from oldState:%d to State:%d"),
pHddStaCtx->conn_info.uIsAuthenticated, authState);
pHddStaCtx->conn_info.uIsAuthenticated = authState;
/* Check is pending ROC request or not when auth state changed */
schedule_delayed_work(&pHddCtx->rocReqWork, 0);
}
v_VOID_t hdd_connSetConnectionState( hdd_adapter_t *pAdapter,
eConnectionState connState )
{
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
/* save the new connection state */
hddLog(LOG1, FL("%pS Changed connectionState from oldState:%d to State:%d"),
(void *)_RET_IP_,
pHddStaCtx->conn_info.connState, connState);
hdd_tsf_notify_wlan_state_change(pAdapter,
pHddStaCtx->conn_info.connState, connState);
pHddStaCtx->conn_info.connState = connState;
/* Check is pending ROC request or not when connection state changed */
schedule_delayed_work(&pHddCtx->rocReqWork, 0);
}
// returns FALSE if not connected.
// returns TRUE for the two 'connected' states (Infra Associated or IBSS Connected ).
// returns the connection state. Can specify NULL if you dont' want to get the actual state.
static inline v_BOOL_t hdd_connGetConnectionState( hdd_station_ctx_t *pHddStaCtx,
eConnectionState *pConnState )
{
v_BOOL_t fConnected;
eConnectionState connState;
// get the connection state.
connState = pHddStaCtx->conn_info.connState;
// Set the fConnected return variable based on the Connected State.
if ( eConnectionState_Associated == connState ||
eConnectionState_IbssConnected == connState ||
eConnectionState_IbssDisconnected == connState)
{
fConnected = VOS_TRUE;
}
else
{
fConnected = VOS_FALSE;
}
if ( pConnState )
{
*pConnState = connState;
}
return( fConnected );
}
v_BOOL_t hdd_connIsConnected( hdd_station_ctx_t *pHddStaCtx )
{
return( hdd_connGetConnectionState( pHddStaCtx, NULL ) );
}
bool hdd_is_connecting(hdd_station_ctx_t *hdd_sta_ctx)
{
return (hdd_sta_ctx->conn_info.connState ==
eConnectionState_Connecting);
}
eCsrBand hdd_connGetConnectedBand( hdd_station_ctx_t *pHddStaCtx )
{
v_U8_t staChannel = 0;
if ( eConnectionState_Associated == pHddStaCtx->conn_info.connState )
{
staChannel = pHddStaCtx->conn_info.operationChannel;
}
if ( staChannel > 0 && staChannel < 14 )
return eCSR_BAND_24;
else if (staChannel >= 36 && staChannel <= 184 )
return eCSR_BAND_5G;
else /* If station is not connected return as eCSR_BAND_ALL */
return eCSR_BAND_ALL;
}
static inline v_BOOL_t hdd_connGetConnectedCipherAlgo( hdd_station_ctx_t *pHddStaCtx, eCsrEncryptionType *pConnectedCipherAlgo )
{
v_BOOL_t fConnected = VOS_FALSE;
fConnected = hdd_connGetConnectionState( pHddStaCtx, NULL );
if ( pConnectedCipherAlgo )
{
*pConnectedCipherAlgo = pHddStaCtx->conn_info.ucEncryptionType;
}
return( fConnected );
}
inline v_BOOL_t hdd_connGetConnectedBssType( hdd_station_ctx_t *pHddStaCtx, eMib_dot11DesiredBssType *pConnectedBssType )
{
v_BOOL_t fConnected = VOS_FALSE;
fConnected = hdd_connGetConnectionState( pHddStaCtx, NULL );
if ( pConnectedBssType )
{
*pConnectedBssType = pHddStaCtx->conn_info.connDot11DesiredBssType;
}
return( fConnected );
}
static inline void hdd_connSaveConnectedBssType( hdd_station_ctx_t *pHddStaCtx, eCsrRoamBssType csrRoamBssType )
{
switch( csrRoamBssType )
{
case eCSR_BSS_TYPE_INFRASTRUCTURE:
pHddStaCtx->conn_info.connDot11DesiredBssType = eMib_dot11DesiredBssType_infrastructure;
break;
case eCSR_BSS_TYPE_IBSS:
case eCSR_BSS_TYPE_START_IBSS:
pHddStaCtx->conn_info.connDot11DesiredBssType = eMib_dot11DesiredBssType_independent;
break;
/** We will never set the BssType to 'any' when attempting a connection
so CSR should never send this back to us.*/
case eCSR_BSS_TYPE_ANY:
default:
VOS_ASSERT( 0 );
break;
}
}
/**
* hdd_unset_beacon_filter() - remove beacon filter
* @adapter: Pointer to the hdd adapter
*
* Return: 0 on success and errno on failure
*/
static int hdd_unset_beacon_filter(hdd_adapter_t *adapter)
{
VOS_STATUS vos_status = VOS_STATUS_E_FAILURE;
vos_status = sme_unset_beacon_filter(adapter->sessionId);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
return -EFAULT;
return 0;
}
/**
* hdd_set_beacon_filter() - set beacon filter
* @adapter: Pointer to the hdd adapter
*
* Return: 0 on success and errno on failure
*/
static int hdd_set_beacon_filter(hdd_adapter_t *adapter)
{
int i;
uint32_t ie_map[8] = {0};
VOS_STATUS vos_status = VOS_STATUS_E_FAILURE;
tHalHandle hal_ptr = WLAN_HDD_GET_HAL_CTX(adapter);
tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal_ptr);
for (i = 0; i < ARRAY_SIZE(beacon_filter_table); i++)
__set_bit(beacon_filter_table[i],
(unsigned long int *)ie_map);
if (TRUE == mac_ptr->sta_change_cc_via_beacon &&
adapter->device_mode == WLAN_HDD_INFRA_STATION)
__set_bit(SIR_MAC_COUNTRY_EID, (unsigned long int *)ie_map);
vos_status = sme_set_beacon_filter(adapter->sessionId, ie_map);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
hddLog(LOGE, "%s: failed to set beacon filter",
__func__);
return -EFAULT;
}
return 0;
}
/**
* hdd_copy_vht_caps()- copy vht caps info from roam info to
* hdd station context.
* @hdd_sta_ctx: pointer to hdd station context
* @roam_info: pointer to roam info
*
* Return: None
*/
static void hdd_copy_ht_caps(hdd_station_ctx_t *hdd_sta_ctx,
tCsrRoamInfo *roam_info)
{
tDot11fIEHTCaps *roam_ht_cap = &roam_info->ht_caps;
struct ieee80211_ht_cap *hdd_ht_cap = &hdd_sta_ctx->conn_info.ht_caps;
uint32_t i, temp_ht_cap;
adf_os_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
/**
* hdd_copy_ht_caps()- copy ht caps info from roam info to
* hdd station context.
* @hdd_sta_ctx: pointer to hdd station context
* @roam_info: pointer to roam info
*
* Return: None
*/
static void hdd_copy_vht_caps(hdd_station_ctx_t *hdd_sta_ctx,
tCsrRoamInfo *roam_info)
{
tDot11fIEVHTCaps *roam_vht_cap = &roam_info->vht_caps;
struct ieee80211_vht_cap *hdd_vht_cap =
&hdd_sta_ctx->conn_info.vht_caps;
uint32_t temp_vht_cap;
adf_os_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
/**
* hdd_copy_ht_operation()- copy HT operation element from roam info to
* hdd station context.
* @hdd_sta_ctx: pointer to hdd station context
* @roam_info: pointer to roam info
*
* Return: None
*/
static void hdd_copy_ht_operation(hdd_station_ctx_t *hdd_sta_ctx,
tCsrRoamInfo *roam_info)
{
tDot11fIEHTInfo *roam_ht_ops = &roam_info->ht_operation;
struct ieee80211_ht_operation *hdd_ht_ops =
&hdd_sta_ctx->conn_info.ht_operation;
uint32_t i, temp_ht_ops;
adf_os_mem_zero(hdd_ht_ops, sizeof(struct ieee80211_ht_operation));
hdd_ht_ops->primary_chan = roam_ht_ops->primaryChannel;
/* HT_PARAMS */
temp_ht_ops = roam_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 (roam_ht_ops->recommendedTxWidthSet)
hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
if (roam_ht_ops->rifsMode)
hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE;
if (roam_ht_ops->controlledAccessOnly)
hdd_ht_ops->ht_param |= HT_PARAM_CONTROLLED_ACCESS_ONLY;
temp_ht_ops = roam_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 = roam_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 (roam_ht_ops->nonGFDevicesPresent)
hdd_ht_ops->operation_mode |=
IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT;
if (roam_ht_ops->transmitBurstLimit)
hdd_ht_ops->operation_mode |=
HT_OP_MODE_TX_BURST_LIMIT;
if (roam_ht_ops->obssNonHTStaPresent)
hdd_ht_ops->operation_mode |=
IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
/* stbc_param */
temp_ht_ops = roam_ht_ops->basicSTBCMCS &
HT_STBC_PARAM_MCS;
if (temp_ht_ops)
hdd_ht_ops->stbc_param |= temp_ht_ops;
if (roam_ht_ops->dualCTSProtection)
hdd_ht_ops->stbc_param |=
IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT;
if (roam_ht_ops->secondaryBeacon)
hdd_ht_ops->stbc_param |=
IEEE80211_HT_STBC_PARAM_STBC_BEACON;
if (roam_ht_ops->lsigTXOPProtectionFullSupport)
hdd_ht_ops->stbc_param |=
IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT;
if (roam_ht_ops->pcoActive)
hdd_ht_ops->stbc_param |=
IEEE80211_HT_STBC_PARAM_PCO_ACTIVE;
if (roam_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] =
roam_ht_ops->basicMCSSet[i];
}
/**
* hdd_copy_vht_operation()- copy VHT operations element from roam info to
* hdd station context.
* @hdd_sta_ctx: pointer to hdd station context
* @roam_info: pointer to roam info
*
* Return: None
*/
static void hdd_copy_vht_operation(hdd_station_ctx_t *hdd_sta_ctx,
tCsrRoamInfo *roam_info)
{
tDot11fIEVHTOperation *roam_vht_ops = &roam_info->vht_operation;
struct ieee80211_vht_operation *hdd_vht_ops =
&hdd_sta_ctx->conn_info.vht_operation;
adf_os_mem_zero(hdd_vht_ops, sizeof(struct ieee80211_vht_operation));
hdd_vht_ops->chan_width = roam_vht_ops->chanWidth;
hdd_vht_ops->center_freq_seg0_idx = roam_vht_ops->chanCenterFreqSeg1;
hdd_vht_ops->center_freq_seg1_idx = roam_vht_ops->chanCenterFreqSeg2;
hdd_vht_ops->basic_mcs_set = roam_vht_ops->basicMCSSet;
}
/**
* hdd_save_bss_info() - save connection info in hdd sta ctx
* @adapter: Pointer to adapter
* @roam_info: pointer to roam info
*
* Return: None
*/
static void hdd_save_bss_info(hdd_adapter_t *adapter,
tCsrRoamInfo *roam_info)
{
hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
hdd_sta_ctx->conn_info.freq = vos_chan_to_freq(
hdd_sta_ctx->conn_info.operationChannel);
if (roam_info->vht_caps.present) {
hdd_sta_ctx->conn_info.conn_flag.vht_present = true;
hdd_copy_vht_caps(hdd_sta_ctx, roam_info);
} else {
hdd_sta_ctx->conn_info.conn_flag.vht_present = false;
}
if (roam_info->ht_caps.present) {
hdd_sta_ctx->conn_info.conn_flag.ht_present = true;
hdd_copy_ht_caps(hdd_sta_ctx, roam_info);
} else {
hdd_sta_ctx->conn_info.conn_flag.ht_present = false;
}
if (roam_info->reassoc)
hdd_sta_ctx->conn_info.roam_count++;
if (roam_info->hs20vendor_ie.present) {
hdd_sta_ctx->conn_info.conn_flag.hs20_present = true;
adf_os_mem_copy(&hdd_sta_ctx->conn_info.hs20vendor_ie,
&roam_info->hs20vendor_ie,
sizeof(roam_info->hs20vendor_ie));
} else {
hdd_sta_ctx->conn_info.conn_flag.hs20_present = false;
}
if (roam_info->ht_operation.present) {
hdd_sta_ctx->conn_info.conn_flag.ht_op_present = true;
hdd_copy_ht_operation(hdd_sta_ctx, roam_info);
} else {
hdd_sta_ctx->conn_info.conn_flag.ht_op_present = false;
}
if (roam_info->vht_operation.present) {
hdd_sta_ctx->conn_info.conn_flag.vht_op_present = true;
hdd_copy_vht_operation(hdd_sta_ctx, roam_info);
} else {
hdd_sta_ctx->conn_info.conn_flag.vht_op_present = false;
}
}
static void
hdd_connSaveConnectInfo(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo,
eCsrRoamBssType eBssType)
{
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
eCsrEncryptionType encryptType = eCSR_ENCRYPT_TYPE_NONE;
VOS_ASSERT( pRoamInfo );
if ( pRoamInfo )
{
// Save the BSSID for the connection...
if ( eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType )
{
VOS_ASSERT( pRoamInfo->pBssDesc );
vos_mem_copy(pHddStaCtx->conn_info.bssId, pRoamInfo->bssid,6 );
// Save the Station ID for this station from the 'Roam Info'.
//For IBSS mode, staId is assigned in NEW_PEER_IND
//For reassoc, the staID doesn't change and it may be invalid in this structure
//so no change here.
if( !pRoamInfo->fReassocReq )
{
pHddStaCtx->conn_info.staId [0]= pRoamInfo->staId;
}
}
else if ( eCSR_BSS_TYPE_IBSS == eBssType )
{
vos_mem_copy(pHddStaCtx->conn_info.bssId, pRoamInfo->bssid,sizeof(pRoamInfo->bssid) );
}
else
{
// can't happen. We need a valid IBSS or Infra setting in the BSSDescription
// or we can't function.
VOS_ASSERT( 0 );
}
// notify WMM
hdd_wmm_connect(pAdapter, pRoamInfo, eBssType);
if( !pRoamInfo->u.pConnectedProfile )
{
VOS_ASSERT( pRoamInfo->u.pConnectedProfile );
}
else
{
// Get Multicast Encryption Type
encryptType = pRoamInfo->u.pConnectedProfile->mcEncryptionType;
pHddStaCtx->conn_info.mcEncryptionType = encryptType;
/* Get Unicast Encryption Type */
encryptType = pRoamInfo->u.pConnectedProfile->EncryptionType;
pHddStaCtx->conn_info.ucEncryptionType = encryptType;
pHddStaCtx->conn_info.authType = pRoamInfo->u.pConnectedProfile->AuthType;
pHddStaCtx->conn_info.last_auth_type = pHddStaCtx->conn_info.authType;
pHddStaCtx->conn_info.operationChannel = pRoamInfo->u.pConnectedProfile->operationChannel;
// Save the ssid for the connection
vos_mem_copy( &pHddStaCtx->conn_info.SSID.SSID, &pRoamInfo->u.pConnectedProfile->SSID, sizeof( tSirMacSSid ) );
vos_mem_copy(&pHddStaCtx->conn_info.last_ssid.SSID,
&pRoamInfo->u.pConnectedProfile->SSID,
sizeof(tSirMacSSid));
// Save dot11mode in which STA associated to AP
pHddStaCtx->conn_info.dot11Mode = pRoamInfo->u.pConnectedProfile->dot11Mode;
pHddStaCtx->conn_info.proxyARPService = pRoamInfo->u.pConnectedProfile->proxyARPService;
pHddStaCtx->conn_info.nss = pRoamInfo->chan_info.nss;
pHddStaCtx->conn_info.rate_flags = pRoamInfo->chan_info.rate_flags;
}
hdd_save_bss_info(pAdapter, pRoamInfo);
}
// save the connected BssType
hdd_connSaveConnectedBssType( pHddStaCtx, eBssType );
}
#if defined(WLAN_FEATURE_VOWIFI_11R)
/*
* Send the 11R key information to the supplicant.
* Only then can the supplicant generate the PMK-R1.
* (BTW, the ESE supplicant also needs the Assoc Resp IEs
* for the same purpose.)
*
* Mainly the Assoc Rsp IEs are passed here. For the IMDA
* this contains the R1KHID, R0KHID and the MDID.
* For FT, this consists of the Reassoc Rsp FTIEs.
* This is the Assoc Response.
*/
static void hdd_SendFTAssocResponse(struct net_device *dev, hdd_adapter_t *pAdapter,
tCsrRoamInfo *pCsrRoamInfo)
{
union iwreq_data wrqu;
char *buff;
unsigned int len = 0;
u8 *pFTAssocRsp = NULL;
if (pCsrRoamInfo->nAssocRspLength == 0)
{
hddLog(LOGE,
"%s: pCsrRoamInfo->nAssocRspLength=%d",
__func__, (int)pCsrRoamInfo->nAssocRspLength);
return;
}
pFTAssocRsp = (u8 *)(pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength +
pCsrRoamInfo->nAssocReqLength);
if (pFTAssocRsp == NULL)
{
hddLog(LOGE, "%s: AssocReq or AssocRsp is NULL", __func__);
return;
}
// pFTAssocRsp needs to point to the IEs
pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET;
hddLog(LOG1, "%s: AssocRsp is now at %02x%02x", __func__,
(unsigned int)pFTAssocRsp[0],
(unsigned int)pFTAssocRsp[1]);
// We need to send the IEs to the supplicant.
buff = vos_mem_malloc(IW_GENERIC_IE_MAX);
if (buff == NULL)
{
hddLog(LOGE, "%s: kmalloc unable to allocate memory", __func__);
return;
}
// Send the Assoc Resp, the supplicant needs this for initial Auth.
len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET;
wrqu.data.length = len;
memset(buff, 0, IW_GENERIC_IE_MAX);
memcpy(buff, pFTAssocRsp, len);
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, buff);
vos_mem_free(buff);
}
#endif /* WLAN_FEATURE_VOWIFI_11R */
#ifdef WLAN_FEATURE_VOWIFI_11R
/*---------------------------------------------------
*
* Send the FTIEs, RIC IEs during FT. This is eventually
* used to send the FT events to the supplicant
*
* At the reception of Auth2 we send the RIC followed
* by the auth response IEs to the supplicant.
* Once both are received in the supplicant, an FT
* event is generated to the supplicant.
*
*---------------------------------------------------
*/
void hdd_SendFTEvent(hdd_adapter_t *pAdapter)
{
tANI_U16 auth_resp_len = 0;
tANI_U32 ric_ies_length = 0;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
#if defined(KERNEL_SUPPORT_11R_CFG80211)
struct cfg80211_ft_event_params ftEvent;
v_U8_t ftIe[DOT11F_IE_FTINFO_MAX_LEN];
v_U8_t ricIe[DOT11F_IE_RICDESCRIPTOR_MAX_LEN];
struct net_device *dev = pAdapter->dev;
#else
char *buff;
union iwreq_data wrqu;
tANI_U16 str_len;
#endif
#if defined(KERNEL_SUPPORT_11R_CFG80211)
vos_mem_zero(ftIe, DOT11F_IE_FTINFO_MAX_LEN);
vos_mem_zero(ricIe, DOT11F_IE_RICDESCRIPTOR_MAX_LEN);
sme_GetRICIEs( pHddCtx->hHal, pAdapter->sessionId, (u8 *)ricIe,
DOT11F_IE_RICDESCRIPTOR_MAX_LEN, &ric_ies_length );
if (ric_ies_length == 0)
{
hddLog(LOGW,
"%s: RIC IEs is of length 0 not sending RIC Information for now",
__func__);
}
ftEvent.ric_ies = ricIe;
ftEvent.ric_ies_len = ric_ies_length;
hddLog(LOG1, "%s: RIC IEs is of length %d", __func__, (int)ric_ies_length);
sme_GetFTPreAuthResponse(pHddCtx->hHal, pAdapter->sessionId, (u8 *)ftIe,
DOT11F_IE_FTINFO_MAX_LEN, &auth_resp_len);
if (auth_resp_len == 0)
{
hddLog(LOGE, "%s: AuthRsp FTIES is of length 0", __func__);
return;
}
sme_SetFTPreAuthState(pHddCtx->hHal, pAdapter->sessionId, VOS_TRUE);
ftEvent.target_ap = ftIe;
ftEvent.ies = (u8 *)(ftIe + SIR_MAC_ADDR_LENGTH);
ftEvent.ies_len = auth_resp_len - SIR_MAC_ADDR_LENGTH;
hddLog(LOG1, "%s ftEvent.ies_len %zu", __FUNCTION__, ftEvent.ies_len);
hddLog(LOG1, "%s ftEvent.ric_ies_len %zu",
__FUNCTION__, ftEvent.ric_ies_len );
hddLog(LOG1, "%s ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x ",
__FUNCTION__, ftEvent.target_ap[0], ftEvent.target_ap[1],
ftEvent.target_ap[2], ftEvent.target_ap[3], ftEvent.target_ap[4],
ftEvent.target_ap[5]);
(void)cfg80211_ft_event(dev, &ftEvent);
#else
// We need to send the IEs to the supplicant
buff = vos_mem_malloc(IW_CUSTOM_MAX);
if (buff == NULL)
{
hddLog(LOGE, "%s: kmalloc unable to allocate memory", __func__);
return;
}
vos_mem_zero(buff, IW_CUSTOM_MAX);
// Sme needs to send the RIC IEs first
str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX);
sme_GetRICIEs( pHddCtx->hHal, pAdapter->sessionId, (u8 *)&(buff[str_len]),
(IW_CUSTOM_MAX - str_len), &ric_ies_length );
if (ric_ies_length == 0)
{
hddLog(LOGW,
"%s: RIC IEs is of length 0 not sending RIC Information for now",
__func__);
}
else
{
wrqu.data.length = str_len + ric_ies_length;
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff);
}
// Sme needs to provide the Auth Resp
vos_mem_zero(buff, IW_CUSTOM_MAX);
str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX);
sme_GetFTPreAuthResponse(pHddCtx->hHal, pAdapter->sessionId,
(u8 *)&buff[str_len],
(IW_CUSTOM_MAX - str_len),
&auth_resp_len);
if (auth_resp_len == 0)
{
hddLog(LOGE, "%s: AuthRsp FTIES is of length 0", __func__);
vos_mem_free(buff);
return;
}
wrqu.data.length = str_len + auth_resp_len;
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff);
vos_mem_free(buff);
#endif
}
#endif /* WLAN_FEATURE_VOWIFI_11R */
#ifdef FEATURE_WLAN_ESE
/*
* Send the ESE required "new AP Channel info" to the supplicant.
* (This keeps the supplicant "up to date" on the current channel.)
*
* The current (new AP) channel information is passed in.
*/
static void hdd_SendNewAPChannelInfo(struct net_device *dev, hdd_adapter_t *pAdapter,
tCsrRoamInfo *pCsrRoamInfo)
{
union iwreq_data wrqu;
tSirBssDescription *descriptor = pCsrRoamInfo->pBssDesc;
if (descriptor == NULL)
{
hddLog(LOGE,
"%s: pCsrRoamInfo->pBssDesc=%pK",
__func__, descriptor);
return;
}
// Send the Channel event, the supplicant needs this to generate the Adjacent AP report.
hddLog(LOGW, "%s: Sending up an SIOCGIWFREQ, channelId=%d", __func__, descriptor->channelId);
memset(&wrqu, '\0', sizeof(wrqu));
wrqu.freq.m = descriptor->channelId;
wrqu.freq.e = 0;
wrqu.freq.i = 0;
wireless_send_event(pAdapter->dev, SIOCGIWFREQ, &wrqu, NULL);
}
#endif /* FEATURE_WLAN_ESE */
static void
hdd_SendUpdateBeaconIEsEvent(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pCsrRoamInfo)
{
union iwreq_data wrqu;
u8 *pBeaconIes;
u8 currentLen = 0;
char *buff;
int totalIeLen = 0, currentOffset = 0, strLen;
memset(&wrqu, '\0', sizeof(wrqu));
if (0 == pCsrRoamInfo->nBeaconLength)
{
hddLog(LOGW, "%s: pCsrRoamInfo->nBeaconFrameLength = 0", __func__);
return;
}
pBeaconIes = (u8 *)(pCsrRoamInfo->pbFrames + BEACON_FRAME_IES_OFFSET);
if (pBeaconIes == NULL)
{
hddLog(LOGW, "%s: Beacon IEs is NULL", __func__);
return;
}
// pBeaconIes needs to point to the IEs
hddLog(LOG1, "%s: Beacon IEs is now at %02x%02x", __func__,
(unsigned int)pBeaconIes[0],
(unsigned int)pBeaconIes[1]);
hddLog(LOG1, "%s: Beacon IEs length = %d", __func__, pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET);
// We need to send the IEs to the supplicant.
buff = vos_mem_malloc(IW_CUSTOM_MAX);
if (buff == NULL)
{
hddLog(LOGE, "%s: kmalloc unable to allocate memory", __func__);
return;
}
vos_mem_zero(buff, IW_CUSTOM_MAX);
strLen = strlcpy(buff,"BEACONIEs=", IW_CUSTOM_MAX);
currentLen = strLen + 1;
totalIeLen = pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET;
do
{
/* If the beacon size exceeds max CUSTOM event size, break it into chunks of CUSTOM event
* max size and send it to supplicant. Changes are done in supplicant to handle this */
vos_mem_zero(&buff[strLen + 1], IW_CUSTOM_MAX - (strLen + 1));
currentLen = VOS_MIN(totalIeLen, IW_CUSTOM_MAX - (strLen + 1) - 1);
vos_mem_copy(&buff[strLen + 1], pBeaconIes+currentOffset, currentLen);
currentOffset += currentLen;
totalIeLen -= currentLen;
wrqu.data.length = strLen + 1 + currentLen;
if (totalIeLen)
buff[strLen] = 1; // This tells supplicant more chunks are pending
else
buff[strLen] = 0; // For last chunk of beacon IE to supplicant
hddLog(LOG1, "%s: Beacon IEs length to supplicant = %d", __func__, currentLen);
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff);
} while (totalIeLen > 0);
vos_mem_free(buff);
}
static void hdd_SendAssociationEvent(struct net_device *dev,tCsrRoamInfo *pCsrRoamInfo)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
union iwreq_data wrqu;
int we_event;
char *msg;
int type = -1;
v_MACADDR_t peerMacAddr;
hdd_adapter_t *mon_adapter = NULL;
#if defined (WLAN_FEATURE_VOWIFI_11R)
// Added to find the auth type on the fly at run time
// rather than with cfg to see if FT is enabled
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
tCsrRoamProfile* pRoamProfile = &(pWextState->roamProfile);
#endif
memset(&wrqu, '\0', sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
we_event = SIOCGIWAP;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (NULL != pCsrRoamInfo)
if (pCsrRoamInfo->roamSynchInProgress)
/* change logging before release */
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG,
"LFR3:hdd_SendAssociationEvent");
#endif
if(eConnectionState_Associated == pHddStaCtx->conn_info.connState)/* Associated */
{
tSirSmeChanInfo chan_info;
if (!pCsrRoamInfo)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: STA in associated state but pCsrRoamInfo is null",
__func__);
return;
}
wlan_hdd_incr_active_session(pHddCtx, pAdapter->device_mode);
memcpy(wrqu.ap_addr.sa_data, pCsrRoamInfo->pBssDesc->bssId, sizeof(pCsrRoamInfo->pBssDesc->bssId));
type = WLAN_STA_ASSOC_DONE_IND;
#ifdef WLAN_FEATURE_P2P_DEBUG
if(pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)
{
if(globalP2PConnectionStatus == P2P_CLIENT_CONNECTING_STATE_1)
{
globalP2PConnectionStatus = P2P_CLIENT_CONNECTED_STATE_1;
hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P State] Changing state from "
"Connecting state to Connected State for 8-way "
"Handshake");
}
else if(globalP2PConnectionStatus == P2P_CLIENT_CONNECTING_STATE_2)
{
globalP2PConnectionStatus = P2P_CLIENT_COMPLETED_STATE;
hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P State] Changing state from "
"Connecting state to P2P Client Connection Completed");
}
}
#endif
hddLog(VOS_TRACE_LEVEL_ERROR, MAC_ADDRESS_STR " connected to "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes),
MAC_ADDR_ARRAY(wrqu.ap_addr.sa_data));
hdd_SendUpdateBeaconIEsEvent(pAdapter, pCsrRoamInfo);
/* Send IWEVASSOCRESPIE Event if WLAN_FEATURE_CIQ_METRICS is Enabled Or
* Send IWEVASSOCRESPIE Event if WLAN_FEATURE_VOWIFI_11R is Enabled
* and fFTEnable is TRUE */
#ifdef WLAN_FEATURE_VOWIFI_11R
// Send FT Keys to the supplicant when FT is enabled
if ((pRoamProfile->AuthType.authType[0] == eCSR_AUTH_TYPE_FT_RSN_PSK) ||
(pRoamProfile->AuthType.authType[0] == eCSR_AUTH_TYPE_FT_RSN)
#ifdef FEATURE_WLAN_ESE
|| (pRoamProfile->AuthType.authType[0] == eCSR_AUTH_TYPE_CCKM_RSN) ||
(pRoamProfile->AuthType.authType[0] == eCSR_AUTH_TYPE_CCKM_WPA)
#endif
)
{
hdd_SendFTAssocResponse(dev, pAdapter, pCsrRoamInfo);
}
#endif
vos_mem_copy(peerMacAddr.bytes, pHddStaCtx->conn_info.bssId,
VOS_MAC_ADDR_SIZE);
chan_info.chan_id = pCsrRoamInfo->chan_info.chan_id;
chan_info.mhz = pCsrRoamInfo->chan_info.mhz;
chan_info.info = pCsrRoamInfo->chan_info.info;
chan_info.band_center_freq1 =
pCsrRoamInfo->chan_info.band_center_freq1;
chan_info.band_center_freq2 =
pCsrRoamInfo->chan_info.band_center_freq2;
chan_info.reg_info_1 = pCsrRoamInfo->chan_info.reg_info_1;
chan_info.reg_info_2 = pCsrRoamInfo->chan_info.reg_info_2;
/* send peer status indication to oem app */
hdd_SendPeerStatusIndToOemApp(&peerMacAddr, ePeerConnected,
pCsrRoamInfo->timingMeasCap,
pAdapter->sessionId,
&chan_info,
pAdapter->device_mode);
#ifdef FEATURE_WLAN_TDLS
if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION) {
hddLog(LOG1,
FL("tdls_prohibited: %d, tdls_chan_swit_prohibited: %d"),
pCsrRoamInfo->tdls_prohibited,
pCsrRoamInfo->tdls_chan_swit_prohibited);
wlan_hdd_update_tdls_info(pAdapter, pCsrRoamInfo->tdls_prohibited,
pCsrRoamInfo->tdls_chan_swit_prohibited);
}
#endif
#ifdef FEATURE_BUS_BANDWIDTH
/* start timer in sta/p2p_cli */
SPIN_LOCK_BH(&pHddCtx->bus_bw_lock);
pAdapter->prev_tx_packets = pAdapter->stats.tx_packets;
pAdapter->prev_rx_packets = pAdapter->stats.rx_packets;
tlshim_get_intra_bss_fwd_pkts_count(pAdapter->sessionId,
&pAdapter->prev_fwd_tx_packets, &pAdapter->prev_fwd_rx_packets);
pAdapter->prev_tx_bytes = pAdapter->stats.tx_bytes;
SPIN_UNLOCK_BH(&pHddCtx->bus_bw_lock);
hdd_start_bus_bw_compute_timer(pAdapter);
#endif
if (pHddCtx->cfg_ini->mon_on_sta_enable &&
(pAdapter->device_mode == WLAN_HDD_INFRA_STATION)) {
/* monitor mode interface should be ready */
mon_adapter = hdd_get_adapter(pHddCtx, WLAN_HDD_MONITOR);
if (mon_adapter && (WLAN_HDD_ADAPTER_MAGIC == mon_adapter->magic) &&
tlshim_get_rxmon_cbk()) {
wlan_hdd_monitor_mode_enable(pHddCtx, true);
}
}
}
else if (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState) // IBss Associated
{
wlan_hdd_incr_active_session(pHddCtx, pAdapter->device_mode);
memcpy(wrqu.ap_addr.sa_data, pHddStaCtx->conn_info.bssId, ETH_ALEN);
type = WLAN_STA_ASSOC_DONE_IND;
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"wlan: new IBSS connection to " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId));
}
else /* Not Associated */
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"wlan: disconnected");
type = WLAN_STA_DISASSOC_DONE_IND;
memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
wlan_hdd_decr_active_session(pHddCtx, pAdapter->device_mode);
#if defined(FEATURE_WLAN_LFR) && defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD)
wlan_hdd_enable_roaming(pAdapter);
#endif
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(pHddCtx, VOS_TRUE);
#endif
if ((WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
(WLAN_HDD_INFRA_STATION == pAdapter->device_mode)) {
vos_mem_copy(peerMacAddr.bytes, pHddStaCtx->conn_info.bssId,
sizeof(pHddStaCtx->conn_info.bssId));
/* send peer status indication to oem app */
hdd_SendPeerStatusIndToOemApp(&peerMacAddr, ePeerDisconnected,
0, pAdapter->sessionId,
NULL,
pAdapter->device_mode);
}
#ifdef WLAN_FEATURE_LPSS
pAdapter->rssi_send = VOS_FALSE;
if (pHddCtx->isUnloadInProgress != TRUE)
wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 0);
#endif
#ifdef FEATURE_BUS_BANDWIDTH
/* stop timer in sta/p2p_cli */
SPIN_LOCK_BH(&pHddCtx->bus_bw_lock);
pAdapter->prev_tx_packets = 0;
pAdapter->prev_rx_packets = 0;
pAdapter->prev_fwd_tx_packets = 0;
pAdapter->prev_fwd_rx_packets = 0;
pAdapter->prev_tx_bytes = 0;
SPIN_UNLOCK_BH(&pHddCtx->bus_bw_lock);
hdd_stop_bus_bw_compute_timer(pAdapter);
#endif
if (pHddCtx->cfg_ini->mon_on_sta_enable &&
(pAdapter->device_mode == WLAN_HDD_INFRA_STATION) &&
(true == pHddCtx->is_mon_enable)) {
wlan_hdd_monitor_mode_enable(pHddCtx, false);
}
}
hdd_dump_concurrency_info(pHddCtx);
msg = NULL;
/*During the WLAN uninitialization,supplicant is stopped before the
driver so not sending the status of the connection to supplicant*/
if ((pHddCtx->isLoadInProgress != TRUE) &&
(pHddCtx->isUnloadInProgress != TRUE))
{
wireless_send_event(dev, we_event, &wrqu, msg);
#ifdef FEATURE_WLAN_ESE
if(eConnectionState_Associated == pHddStaCtx->conn_info.connState)/* Associated */
{
if ( (pRoamProfile->AuthType.authType[0] == eCSR_AUTH_TYPE_CCKM_RSN) ||
(pRoamProfile->AuthType.authType[0] == eCSR_AUTH_TYPE_CCKM_WPA) )
hdd_SendNewAPChannelInfo(dev, pAdapter, pCsrRoamInfo);
}
#endif
}
}
static void hdd_connRemoveConnectInfo(hdd_station_ctx_t *pHddStaCtx)
{
// Remove staId, bssId and peerMacAddress
pHddStaCtx->conn_info.staId [ 0 ] = 0;
vos_mem_zero( &pHddStaCtx->conn_info.bssId, sizeof( v_MACADDR_t ) );
vos_mem_zero( &pHddStaCtx->conn_info.peerMacAddress[ 0 ], sizeof( v_MACADDR_t ) );
// Clear all security settings
pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
pHddStaCtx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE;
pHddStaCtx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE;
vos_mem_zero( &pHddStaCtx->conn_info.Keys, sizeof( tCsrKeys ) );
vos_mem_zero( &pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey) );
// Set not-connected state
pHddStaCtx->conn_info.connDot11DesiredBssType = eCSR_BSS_TYPE_ANY;
pHddStaCtx->conn_info.proxyARPService = 0;
vos_mem_zero( &pHddStaCtx->conn_info.SSID, sizeof( tCsrSSIDInfo ) );
}
/**
* hdd_roamDeregisterSTA() - Deregister STA from data path
* @pAdapter - HDD context
* @staId - Station ID
*
* Return: 0 or VOS_STATUS error code
*/
VOS_STATUS hdd_roamDeregisterSTA(hdd_adapter_t *pAdapter, tANI_U8 staId)
{
VOS_STATUS vosStatus;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
if (WLAN_HDD_IBSS != pAdapter->device_mode)
{
hdd_disconnect_tx_rx(pAdapter);
}
else
{
// Need to cleanup all queues only if the last peer leaves
if (eConnectionState_IbssDisconnected == pHddStaCtx->conn_info.connState)
{
/* Do not set the carrier off when the last peer leaves.
* We will set the carrier off while stopping the IBSS.
*/
hdd_disconnect_tx_rx(pAdapter);
}
else
{
// There is atleast one more peer, do not cleanup all queues
hdd_flush_ibss_tx_queues(pAdapter, staId);
}
}
vosStatus = WLANTL_ClearSTAClient( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, staId );
if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: WLANTL_ClearSTAClient() failed to for staID %d. "
"Status= %d [0x%08X]",
__func__, staId, vosStatus, vosStatus );
}
return( vosStatus );
}
/**
* hdd_print_bss_info() - print bss info
* @hdd_sta_ctx: pointer to hdd station context
*
* Return: None
*/
static void hdd_print_bss_info(hdd_station_ctx_t *hdd_sta_ctx)
{
uint32_t *cap_info;
hddLog(VOS_TRACE_LEVEL_INFO, "WIFI DATA LOGGER");
hddLog(VOS_TRACE_LEVEL_INFO, "channel: %d",
hdd_sta_ctx->conn_info.freq);
hddLog(VOS_TRACE_LEVEL_INFO, "dot11mode: %d",
hdd_sta_ctx->conn_info.dot11Mode);
hddLog(VOS_TRACE_LEVEL_INFO, "AKM: %d",
hdd_sta_ctx->conn_info.last_auth_type);
hddLog(VOS_TRACE_LEVEL_INFO, "ssid: %.*s",
hdd_sta_ctx->conn_info.last_ssid.SSID.length,
hdd_sta_ctx->conn_info.last_ssid.SSID.ssId);
hddLog(VOS_TRACE_LEVEL_INFO, "roam count: %d",
hdd_sta_ctx->conn_info.roam_count);
hddLog(VOS_TRACE_LEVEL_INFO, "ant_info: %d",
hdd_sta_ctx->conn_info.txrate.nss);
hddLog(VOS_TRACE_LEVEL_INFO, "datarate legacy %d",
hdd_sta_ctx->conn_info.txrate.legacy);
hddLog(VOS_TRACE_LEVEL_INFO, "datarate mcs: %d",
hdd_sta_ctx->conn_info.txrate.mcs);
if (hdd_sta_ctx->conn_info.conn_flag.ht_present) {
cap_info = (uint32_t *)&hdd_sta_ctx->conn_info.ht_caps;
hddLog(VOS_TRACE_LEVEL_INFO, "ht caps: %x", *cap_info);
}
if (hdd_sta_ctx->conn_info.conn_flag.vht_present) {
cap_info = (uint32_t *)&hdd_sta_ctx->conn_info.vht_caps;
hddLog(VOS_TRACE_LEVEL_INFO, "vht caps: %x", *cap_info);
}
if (hdd_sta_ctx->conn_info.conn_flag.hs20_present)
hddLog(VOS_TRACE_LEVEL_INFO, "hs20 info: %x",
hdd_sta_ctx->conn_info.hs20vendor_ie.release_num);
hddLog(VOS_TRACE_LEVEL_INFO, "signal: %d",
hdd_sta_ctx->conn_info.signal);
hddLog(VOS_TRACE_LEVEL_INFO, "noise: %d",
hdd_sta_ctx->conn_info.noise);
hddLog(VOS_TRACE_LEVEL_INFO, "assoc_reject.status: %d",
hdd_sta_ctx->conn_info.assoc_status_code);
}
static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo,
tANI_U32 roamId, eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult )
{
eHalStatus status = eHAL_STATUS_SUCCESS;
VOS_STATUS vstatus;
struct net_device *dev = pAdapter->dev;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
v_U8_t sta_id;
v_BOOL_t sendDisconInd = TRUE;
// Sanity check
if(dev == NULL)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: net_dev is released return", __func__);
return eHAL_STATUS_FAILURE;
}
// notify apps that we can't pass traffic anymore
hddLog(LOG1, FL("Disabling queues"));
wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE_N_CARRIER,
WLAN_CONTROL_PATH);
#ifdef IPA_OFFLOAD
if (hdd_ipa_is_enabled(pHddCtx))
hdd_ipa_wlan_evt(pAdapter, pHddStaCtx->conn_info.staId[0],
WLAN_STA_DISCONNECT, pHddStaCtx->conn_info.bssId);
#endif
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(pHddCtx, VOS_TRUE);
#endif
#ifdef QCA_PKT_PROTO_TRACE
/* STA disconnected, update into trace buffer */
if (pHddCtx->cfg_ini->gEnableDebugLog)
{
vos_pkt_trace_buf_update("ST:DISASC");
}
#endif /* QCA_PKT_PROTO_TRACE */
DPTRACE(adf_dp_trace_mgmt_pkt(ADF_DP_TRACE_MGMT_PACKET_RECORD,
pAdapter->sessionId,
ADF_PROTO_TYPE_MGMT, ADF_PROTO_MGMT_DISASSOC));
/* HDD has initiated disconnect, do not send disconnect indication
* to kernel. Sending disconnected event to kernel for userspace
* initiated disconnect will be handled by diconnect handler call
* to cfg80211_disconnected
*/
if ((eConnectionState_Disconnecting == pHddStaCtx->conn_info.connState) ||
(eConnectionState_NotConnected == pHddStaCtx->conn_info.connState))
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL(" HDD has initiated a disconnect, no need to send"
" disconnect indication to kernel"));
sendDisconInd = FALSE;
}
if(pHddStaCtx->conn_info.connState != eConnectionState_Disconnecting)
{
INIT_COMPLETION(pAdapter->disconnect_comp_var);
hdd_connSetConnectionState(pAdapter,
eConnectionState_Disconnecting);
}
/* If only STA mode is on */
if((pHddCtx->concurrency_mode <= 1) &&
(pHddCtx->no_of_open_sessions[WLAN_HDD_INFRA_STATION] <=1))
{
pHddCtx->isAmpAllowed = VOS_TRUE;
}
hdd_clearRoamProfileIe( pAdapter );
hdd_wmm_init( pAdapter );
hddLog(VOS_TRACE_LEVEL_INFO,
FL("Invoking packetdump deregistration API"));
wlan_deregister_txrx_packetdump();
// indicate 'disconnect' status to wpa_supplicant...
hdd_SendAssociationEvent(dev,pRoamInfo);
/* indicate disconnected event to nl80211 */
if(roamStatus != eCSR_ROAM_IBSS_LEAVE)
{
/* Only send indication to kernel if not initiated by kernel */
if (sendDisconInd) {
/* To avoid wpa_supplicant sending "HANGED" CMD to ICS UI */
if (eCSR_ROAM_LOSTLINK == roamStatus)
{
if (pRoamInfo->reasonCode ==
eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON)
pr_info(
"wlan: disconnected due to poor signal, rssi is %d dB\n",
pRoamInfo->rxRssi);
wlan_hdd_cfg80211_indicate_disconnect(dev, false,
pRoamInfo->reasonCode);
}
else
wlan_hdd_cfg80211_indicate_disconnect(dev, false,
WLAN_REASON_UNSPECIFIED);
hddLog(VOS_TRACE_LEVEL_INFO_HIGH,
FL("sent disconnected event to nl80211, reason code %d"),
(eCSR_ROAM_LOSTLINK == roamStatus) ?
pRoamInfo->reasonCode : WLAN_REASON_UNSPECIFIED);
}
if ((pHddCtx->isLoadInProgress != TRUE) &&
(pHddCtx->isUnloadInProgress != TRUE))
{
#ifdef WLAN_FEATURE_P2P_DEBUG
if(pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)
{
if(globalP2PConnectionStatus == P2P_CLIENT_CONNECTED_STATE_1)
{
globalP2PConnectionStatus = P2P_CLIENT_DISCONNECTED_STATE;
hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P State] 8 way Handshake completed "
"and moved to disconnected state");
}
else if(globalP2PConnectionStatus == P2P_CLIENT_COMPLETED_STATE)
{
globalP2PConnectionStatus = P2P_NOT_ACTIVE;
hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P State] P2P Client is removed "
"and moved to inactive state");
}
}
#endif
#ifdef WLAN_FEATURE_SAP_TO_FOLLOW_STA_CHAN
if((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) &&
vos_is_ch_switch_with_csa_enabled())
{
struct wlan_sap_csa_info csa_info;
hddLog(VOS_TRACE_LEVEL_INFO_HIGH,
"%s: Indicate disconnected event to HostApd",
__func__);
csa_info.sta_channel = 0;
/*Indicate to HostApd about Station interface state change*/
hdd_sta_state_sap_notify(pHddCtx, STA_NOTIFY_DISCONNECTED, csa_info);
}
#endif//#ifdef WLAN_FEATURE_SAP_TO_FOLLOW_STA_CHAN
//If the Device Mode is Station
// and the P2P Client is Connected
//Enable BMPS
/*
* In case of JB, as Change-Iface may or may not be called for p2p0
* Enable BMPS/IMPS in case P2P_CLIENT disconnected
* If power save offload is enabled, Fw will take care
* of power save in case of concurrency.
*/
if((VOS_STATUS_SUCCESS == hdd_issta_p2p_clientconnected(pHddCtx))
&& !pHddCtx->cfg_ini->enablePowersaveOffload)
{
//Enable BMPS only of other Session is P2P Client
hdd_context_t *pHddCtx = NULL;
v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL );
if (NULL != pVosContext)
{
pHddCtx = vos_get_context( VOS_MODULE_ID_HDD, pVosContext);
if(NULL != pHddCtx)
{
//Only P2P Client is there Enable Bmps back
if((0 == pHddCtx->no_of_open_sessions[VOS_STA_SAP_MODE]) &&
(0 == pHddCtx->no_of_open_sessions[VOS_P2P_GO_MODE]))
{
if (pHddCtx->hdd_wlan_suspended)
{
hdd_set_pwrparams(pHddCtx);
}
hdd_enable_bmps_imps(pHddCtx);
}
}
}
}
}
}
hdd_wmm_adapter_clear(pAdapter);
#if defined(WLAN_FEATURE_VOWIFI_11R)
sme_FTReset(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId);
#endif
if (hdd_unset_beacon_filter(pAdapter) != 0)
hddLog(LOGE,
FL("hdd_unset_beacon_filter() failed"));
if (eCSR_ROAM_IBSS_LEAVE == roamStatus) {
v_U8_t i;
sta_id = IBSS_BROADCAST_STAID;
vstatus = hdd_roamDeregisterSTA(pAdapter, sta_id);
if (!VOS_IS_STATUS_SUCCESS(vstatus)) {
hddLog(LOGE,
FL("hdd_roamDeregisterSTA() failed for staID %d Status=%d [0x%x]"),
sta_id, status, status);
status = eHAL_STATUS_FAILURE;
}
pHddCtx->sta_to_adapter[sta_id] = NULL;
/*Clear all the peer sta register with TL.*/
for (i =0; i < HDD_MAX_NUM_IBSS_STA; i++) {
if (0 != pHddStaCtx->conn_info.staId[i]) {
sta_id = pHddStaCtx->conn_info.staId[i];
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL("Deregister StaID %d"),sta_id);
vstatus = hdd_roamDeregisterSTA( pAdapter, sta_id );
if (!VOS_IS_STATUS_SUCCESS(vstatus)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("hdd_roamDeregisterSTA() failed to for staID %d. "
"Status= %d [0x%x]"),
sta_id, status, status);
status = eHAL_STATUS_FAILURE;
}
/*set the staid and peer mac as 0, all other reset are
* done in hdd_connRemoveConnectInfo.
*/
pHddStaCtx->conn_info.staId[i]= 0;
vos_mem_zero(&pHddStaCtx->conn_info.peerMacAddress[i], sizeof(v_MACADDR_t));
if (sta_id < (WLAN_MAX_STA_COUNT + 3))
pHddCtx->sta_to_adapter[sta_id] = NULL;
}
}
} else {
sta_id = pHddStaCtx->conn_info.staId[0];
/* clear scan cache for Link Lost */
if (pRoamInfo && !pRoamInfo->reasonCode &&
(eCSR_ROAM_RESULT_DEAUTH_IND == roamResult)) {
wlan_hdd_cfg80211_update_bss_list(pAdapter,
pHddStaCtx->conn_info.bssId);
sme_remove_bssid_from_scan_list(pHddCtx->hHal,
pHddStaCtx->conn_info.bssId);
}
//We should clear all sta register with TL, for now, only one.
vstatus = hdd_roamDeregisterSTA( pAdapter, sta_id );
if (!VOS_IS_STATUS_SUCCESS(vstatus)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("hdd_roamDeregisterSTA() failed to for staID %d. "
"Status= %d [0x%x]"),
sta_id, status, status);
status = eHAL_STATUS_FAILURE;
}
pHddCtx->sta_to_adapter[sta_id] = NULL;
}
// Clear saved connection information in HDD
hdd_connRemoveConnectInfo( pHddStaCtx );
hdd_connSetConnectionState(pAdapter,
eConnectionState_NotConnected);
#ifdef WLAN_FEATURE_GTK_OFFLOAD
if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
(WLAN_HDD_P2P_CLIENT == pAdapter->device_mode))
{
memset(&pHddStaCtx->gtkOffloadReqParams, 0,
sizeof (tSirGtkOffloadParams));
pHddStaCtx->gtkOffloadReqParams.ulFlags = GTK_OFFLOAD_DISABLE;
}
#endif
#ifdef FEATURE_WLAN_TDLS
if (eCSR_ROAM_IBSS_LEAVE != roamStatus)
{
wlan_hdd_tdls_disconnection_callback(pAdapter);
}
#endif
if (pHddCtx->cfg_ini->enablePowersaveOffload &&
((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
(WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)))
{
sme_PsOffloadDisableDeferredPowerSave(
WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId);
}
wlan_hdd_clear_link_layer_stats(pAdapter);
/* Decide ANTENNA_MODE on STA/CLI disconnect */
if (pHddCtx->cfg_ini->enable_dynamic_sta_chainmask)
hdd_decide_dynamic_chain_mask(pHddCtx,
HDD_ANTENNA_MODE_INVALID);
//Unblock anyone waiting for disconnect to complete
complete(&pAdapter->disconnect_comp_var);
hdd_print_bss_info(pHddStaCtx);
return( status );
}
/**
* hdd_roamRegisterSTA() - Registers new STA to TL module
* @pAdapter: pointer to adapter context
* @pRoamInfo: roam info struct pointer
* @staId: station ID
* @pPeerMacAddress: mac address of new STA
* @pBssDesc: bss descriptor
*
* Return: status of operation
*/
VOS_STATUS hdd_roamRegisterSTA(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo,
uint8_t staId, v_MACADDR_t *pPeerMacAddress,
tSirBssDescription *pBssDesc)
{
VOS_STATUS vosStatus = VOS_STATUS_E_FAILURE;
WLAN_STADescType staDesc = {0};
eCsrEncryptionType connectedCipherAlgo;
v_BOOL_t fConnected;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
if ( NULL == pBssDesc)
{
return VOS_STATUS_E_FAILURE;
}
/* Get the Station ID from the one saved during the association */
staDesc.ucSTAId = staId;
if ( pHddStaCtx->conn_info.connDot11DesiredBssType == eMib_dot11DesiredBssType_infrastructure)
{
staDesc.wSTAType = WLAN_STA_INFRA;
// grab the bssid from the connection info in the adapter structure and hand that
// over to TL when registering.
vos_mem_copy( staDesc.vSTAMACAddress.bytes, pHddStaCtx->conn_info.bssId,sizeof(pHddStaCtx->conn_info.bssId) );
}
else
{
// for an IBSS 'connect', setup the Station Descriptor for TL.
staDesc.wSTAType = WLAN_STA_IBSS;
/*
* Note that for IBSS, the STA MAC address and BSSID are going to be
* different where in infrastructure, they are the same (BSSID is the
* MAC address of the AP). So, for IBSS we have a second field to pass
* to TL in the STA descriptor that we don't pass when making an
* Infrastructure connection.
*/
vos_mem_copy( staDesc.vSTAMACAddress.bytes, pPeerMacAddress->bytes,sizeof(pPeerMacAddress->bytes) );
vos_mem_copy( staDesc.vBSSIDforIBSS.bytes, pHddStaCtx->conn_info.bssId,6 );
}
vos_copy_macaddr( &staDesc.vSelfMACAddress, &pAdapter->macAddressCurrent );
// set the QoS field appropriately
if (hdd_wmm_is_active(pAdapter))
{
staDesc.ucQosEnabled = 1;
}
else
{
staDesc.ucQosEnabled = 0;
}
fConnected = hdd_connGetConnectedCipherAlgo( pHddStaCtx, &connectedCipherAlgo );
if ( connectedCipherAlgo != eCSR_ENCRYPT_TYPE_NONE )
{
staDesc.ucProtectedFrame = 1;
}
else
{
staDesc.ucProtectedFrame = 0;
}
#ifdef FEATURE_WLAN_ESE
staDesc.ucIsEseSta = pRoamInfo->isESEAssoc;
#endif //FEATURE_WLAN_ESE
#ifdef VOLANS_ENABLE_SW_REPLAY_CHECK
/* check whether replay check is valid for the station or not */
if( (eCSR_ENCRYPT_TYPE_TKIP == connectedCipherAlgo) || (eCSR_ENCRYPT_TYPE_AES == connectedCipherAlgo))
{
/* Encryption mode is either TKIP or AES
and replay check is valid for only these
two encryption modes */
staDesc.ucIsReplayCheckValid = VOS_TRUE;
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"HDD register TL ucIsReplayCheckValid %d: Replay check is needed for station", staDesc.ucIsReplayCheckValid);
}
else
{
/* For other encryption modes replay check is
not needed */
staDesc.ucIsReplayCheckValid = VOS_FALSE;
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"HDD register TL ucIsReplayCheckValid %d", staDesc.ucIsReplayCheckValid);
}
#endif
#ifdef FEATURE_WLAN_WAPI
hddLog(LOG1, "%s: WAPI STA Registered: %d", __func__, pAdapter->wapi_info.fIsWapiSta);
if (pAdapter->wapi_info.fIsWapiSta)
{
staDesc.ucIsWapiSta = 1;
}
else
{
staDesc.ucIsWapiSta = 0;
}
#endif /* FEATURE_WLAN_WAPI */
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
"HDD register TL Sec_enabled= %d.", staDesc.ucProtectedFrame );
// UMA is Not ready yet, Xlation will be done by TL
staDesc.ucSwFrameTXXlation = 1;
staDesc.ucSwFrameRXXlation = 1;
staDesc.ucAddRmvLLC = 1;
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "HDD register TL QoS_enabled=%d",
staDesc.ucQosEnabled );
// Initialize signatures and state
staDesc.ucUcastSig = pRoamInfo->ucastSig;
staDesc.ucBcastSig = pRoamInfo->bcastSig;
staDesc.ucInitState = pRoamInfo->fAuthRequired ?
WLANTL_STA_CONNECTED : WLANTL_STA_AUTHENTICATED;
// Register the Station with TL...
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "%s: HDD register TL ucInitState=%d", __func__, staDesc.ucInitState );
/* Incase Micro controller data path offload enabled,
* All the traffic routed to WLAN host driver, do not need to
* route IPA. It should be routed kernel network stack */
#if defined(IPA_OFFLOAD) && !defined(IPA_UC_OFFLOAD)
if (hdd_ipa_is_enabled(pHddCtx))
vosStatus = WLANTL_RegisterSTAClient(pHddCtx->pvosContext,
hdd_ipa_process_rxt,
&staDesc,
pBssDesc->rssi);
else
#endif
vosStatus = WLANTL_RegisterSTAClient(pHddCtx->pvosContext,
hdd_rx_packet_cbk,
&staDesc,
pBssDesc->rssi);
if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
"WLANTL_RegisterSTAClient() failed to register. Status= %d [0x%08X]",
vosStatus, vosStatus );
return vosStatus;
}
// if (WPA), tell TL to go to 'connected' and after keys come to the driver,
// then go to 'authenticated'. For all other authentication types
// (those that donot require upper layer authentication) we can put
// TL directly into 'authenticated' state.
if (staDesc.wSTAType != WLAN_STA_IBSS) {
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
"STA type %d fConnected %d", staDesc.wSTAType, fConnected);
}
if ( !pRoamInfo->fAuthRequired )
{
// Connections that do not need Upper layer auth, transition TL directly
// to 'Authenticated' state.
vosStatus = WLANTL_ChangeSTAState(pHddCtx->pvosContext, staDesc.ucSTAId,
WLANTL_STA_AUTHENTICATED,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
VOS_FALSE
#endif
);
hdd_connSetAuthenticated(pAdapter, VOS_TRUE);
}
else
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
"ULA auth StaId= %d. Changing TL state to CONNECTED"
"at Join time", pHddStaCtx->conn_info.staId[0] );
vosStatus = WLANTL_ChangeSTAState(pHddCtx->pvosContext, staDesc.ucSTAId,
WLANTL_STA_CONNECTED,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
VOS_FALSE
#endif
);
hdd_connSetAuthenticated(pAdapter, VOS_FALSE);
}
return( vosStatus );
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/**
* hdd_send_roam_auth_event() - send roamed and authed event
* @hdd_ctx: pointer to hdd context.
* @bssid: pointer to bssid of roamed AP.
* @req_rsn_ie: pointer to request RSN IE
* @req_rsn_len: length of the request RSN IE
* @rsp_rsn_ie: pointer to response RSN IE
* @rsp_rsn_len: length of the response RSN IE
* @roam_info: pointer to the roaming related information
*
* this routine includes a condition check before call
* wlan_hdd_send_roam_auth_event.
*/
static int hdd_send_roam_auth_event(hdd_context_t *hdd_ctx,
uint8_t *bssid, uint8_t *req_rsn_ie,
uint32_t req_rsn_len, uint8_t *rsp_rsn_ie,
uint32_t rsp_rsn_len,
tCsrRoamInfo *roam_info)
{
if (hdd_ctx->cfg_ini->isRoamOffloadEnabled &&
roam_info->roamSynchInProgress)
wlan_hdd_send_roam_auth_event(hdd_ctx, bssid,
req_rsn_ie, req_rsn_len,
rsp_rsn_ie, rsp_rsn_len,
roam_info);
return 0;
}
/**
* hdd_is_roam_sync_in_progress()- Check if roam offloaded
*
* Return: roam sync status if roaming offloaded else false
*/
static inline bool hdd_is_roam_sync_in_progress(tCsrRoamInfo *roaminfo)
{
return roaminfo->roamSynchInProgress;
}
#else
static inline bool hdd_is_roam_sync_in_progress(tCsrRoamInfo *roaminfo)
{
return false;
}
static inline int hdd_send_roam_auth_event(hdd_context_t *hdd_ctx,
uint8_t *bssid, uint8_t *req_rsn_ie, uint32_t req_rsn_length,
uint8_t *rsp_rsn_ie, uint32_t rsp_rsn_length,
tCsrRoamInfo *roam_info)
{
return 0;
}
#endif
static void hdd_SendReAssocEvent(struct net_device *dev,
hdd_adapter_t *pAdapter,
tCsrRoamInfo *pCsrRoamInfo, v_U8_t *reqRsnIe,
tANI_U32 reqRsnLength)
{
unsigned int len = 0;
u8 *pFTAssocRsp = NULL;
v_U8_t *rspRsnIe = vos_mem_malloc(IW_GENERIC_IE_MAX);
tANI_U32 rspRsnLength = 0;
struct ieee80211_channel *chan;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
uint8_t buf_ssid_ie[2 + SIR_MAC_SSID_EID_MAX]; /* 2 bytes for EID and len */
uint8_t *buf_ptr, ssid_ie_len;
struct cfg80211_bss *bss = NULL;
uint8_t *final_req_ie = NULL;
struct cfg80211_roam_info roam_info;
tCsrRoamConnectedProfile roam_profile;
tHalHandle hal_handle = WLAN_HDD_GET_HAL_CTX(pAdapter);
if (!rspRsnIe) {
hddLog(LOGE, FL("Unable to allocate RSN IE"));
return;
}
if (pCsrRoamInfo == NULL) {
hddLog(LOGE, FL("Invalid CSR roam info"));
goto done;
}
if (pCsrRoamInfo->nAssocRspLength == 0) {
hddLog(LOGE, FL("Invalid assoc response length"));
goto done;
}
pFTAssocRsp = (u8 *)(pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength +
pCsrRoamInfo->nAssocReqLength);
if (pFTAssocRsp == NULL)
goto done;
/* pFTAssocRsp needs to point to the IEs */
pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET;
hddLog(LOG1, FL("AssocRsp is now at %02x%02x"),
(unsigned int)pFTAssocRsp[0], (unsigned int)pFTAssocRsp[1]);
/* Active session count is decremented upon disconnection, but during
* roaming, there is no disconnect indication and hence active session
* count is not decremented.
* After roaming is completed, active session count is incremented
* as a part of connect indication but effectively after roaming the
* active session count should still be the same and hence upon
* successful reassoc decrement the active session count here */
wlan_hdd_decr_active_session(pHddCtx, pAdapter->device_mode);
/* Send the Assoc Resp, the supplicant needs this for initial Auth */
len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET;
rspRsnLength = len;
memcpy(rspRsnIe, pFTAssocRsp, len);
memset(rspRsnIe + len, 0, IW_GENERIC_IE_MAX - len);
chan = ieee80211_get_channel(pAdapter->wdev.wiphy,
(int)pCsrRoamInfo->pBssDesc->channelId);
memset(&roam_profile, 0, sizeof(tCsrRoamConnectedProfile));
sme_RoamGetConnectProfile(hal_handle, pAdapter->sessionId, &roam_profile);
bss = hdd_cfg80211_get_bss(pAdapter->wdev.wiphy,
chan, pCsrRoamInfo->bssid,
&roam_profile.SSID.ssId[0],
roam_profile.SSID.length);
if (bss == NULL)
hddLog(LOGE, FL("Get BSS returned NULL"));
buf_ptr = buf_ssid_ie;
*buf_ptr = SIR_MAC_SSID_EID;
buf_ptr++;
*buf_ptr = roam_profile.SSID.length; /*len of ssid*/
buf_ptr++;
vos_mem_copy(buf_ptr, &roam_profile.SSID.ssId[0],
roam_profile.SSID.length);
ssid_ie_len = 2 + roam_profile.SSID.length;
hddLog(LOG2, FL("SSIDIE:"));
VOS_TRACE_HEX_DUMP(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG,
buf_ssid_ie, ssid_ie_len);
final_req_ie = vos_mem_malloc(IW_GENERIC_IE_MAX);
if (final_req_ie == NULL)
goto done;
buf_ptr = final_req_ie;
vos_mem_copy(buf_ptr, buf_ssid_ie, ssid_ie_len);
buf_ptr += ssid_ie_len;
vos_mem_copy(buf_ptr, reqRsnIe, reqRsnLength);
memcpy(rspRsnIe, pFTAssocRsp, len);
memset(final_req_ie + (ssid_ie_len + reqRsnLength), 0,
IW_GENERIC_IE_MAX - (ssid_ie_len + reqRsnLength));
hddLog(LOG2, FL("Req RSN IE:"));
VOS_TRACE_HEX_DUMP(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_DEBUG,
final_req_ie, (ssid_ie_len +reqRsnLength));
roam_info.bss = bss;
roam_info.req_ie = final_req_ie;
roam_info.req_ie_len = (ssid_ie_len + reqRsnLength);
roam_info.resp_ie = rspRsnIe;
roam_info.resp_ie_len = rspRsnLength;
cfg80211_roamed(dev, &roam_info, GFP_KERNEL);
hdd_send_roam_auth_event(pHddCtx, pCsrRoamInfo->bssid,
reqRsnIe, reqRsnLength, rspRsnIe,
rspRsnLength, pCsrRoamInfo);
done:
sme_RoamFreeConnectProfile(hal_handle, &roam_profile);
if (final_req_ie)
vos_mem_free(final_req_ie);
vos_mem_free(rspRsnIe);
}
/**
* hdd_change_sta_state_authenticated()-
* This function changes STA state to authenticated
* @adapter: pointer to the adapter structure.
* @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(hdd_adapter_t *adapter,
tCsrRoamInfo *roaminfo)
{
int ret;
hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
hddLog(LOG1,
"Changing TL state to AUTHENTICATED for StaId= %d",
hddstactx->conn_info.staId[0]);
/* Connections that do not need Upper layer authentication,
* transition TL to 'Authenticated' state after the keys are set
*/
ret = WLANTL_ChangeSTAState(hddctx->pvosContext,
hddstactx->conn_info.staId[0],
WLANTL_STA_AUTHENTICATED,
hdd_is_roam_sync_in_progress(roaminfo));
hdd_connSetAuthenticated(adapter, VOS_TRUE);
if (hddctx->cfg_ini->enablePowersaveOffload &&
(false == hddctx->is_mon_enable) &&
((WLAN_HDD_INFRA_STATION == adapter->device_mode) ||
(WLAN_HDD_P2P_CLIENT == adapter->device_mode))) {
sme_PsOffloadEnableDeferredPowerSave(
WLAN_HDD_GET_HAL_CTX(adapter),
adapter->sessionId,
hddstactx->hdd_ReassocScenario);
}
return ret;
}
void hdd_PerformRoamSetKeyComplete(hdd_adapter_t *pAdapter)
{
eHalStatus halStatus = eHAL_STATUS_SUCCESS;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
tCsrRoamInfo roamInfo;
roamInfo.fAuthRequired = FALSE;
vos_mem_copy(roamInfo.bssid,
pHddStaCtx->roam_info.bssid,
VOS_MAC_ADDR_SIZE);
vos_mem_copy(roamInfo.peerMac,
pHddStaCtx->roam_info.peerMac,
VOS_MAC_ADDR_SIZE);
halStatus = hdd_RoamSetKeyCompleteHandler(pAdapter,
&roamInfo,
pHddStaCtx->roam_info.roamId,
pHddStaCtx->roam_info.roamStatus,
eCSR_ROAM_RESULT_AUTHENTICATED);
if (halStatus != eHAL_STATUS_SUCCESS)
{
hddLog(LOGE, "%s: Set Key complete failure", __func__);
}
pHddStaCtx->roam_info.deferKeyComplete = FALSE;
}
#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
static void hdd_clear_fils_connection_info(hdd_adapter_t *adapter)
{
hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
if (wext_state->roamProfile.fils_con_info) {
vos_mem_free(wext_state->roamProfile.fils_con_info);
wext_state->roamProfile.fils_con_info = NULL;
}
}
#else
static void hdd_clear_fils_connection_info(hdd_adapter_t *adapter)
{ }
#endif
/**
* hdd_sap_restart_handle() - to handle restarting of SAP
* @work: name of the work
*
* Purpose of this function is to trigger sap start. this function
* will be called from workqueue.
*
* Return: void.
*/
void hdd_sap_restart_handle(struct work_struct *work)
{
hdd_adapter_t *sap_adapter;
hdd_context_t *hdd_ctx = container_of(work,
hdd_context_t,
sap_start_work);
vos_ssr_protect(__func__);
if (0 != wlan_hdd_validate_context(hdd_ctx)) {
vos_ssr_unprotect(__func__);
return;
}
sap_adapter = hdd_get_adapter(hdd_ctx,
WLAN_HDD_SOFTAP);
if (sap_adapter == NULL) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("sap_adapter is NULL"));
vos_ssr_unprotect(__func__);
return;
}
if (hdd_ctx->is_ch_avoid_in_progress) {
sap_adapter->sessionCtx.ap.sapConfig.channel = AUTO_CHANNEL_SELECT;
wlan_hdd_restart_sap(sap_adapter);
hdd_change_ch_avoidance_status(hdd_ctx, false);
} else {
wlan_hdd_start_sap(sap_adapter, false);
hdd_change_sap_restart_required_status(hdd_ctx, false);
}
vos_ssr_unprotect(__func__);
}
static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo,
tANI_U32 roamId, eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult )
{
struct net_device *dev = pAdapter->dev;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
#ifdef FEATURE_WLAN_FORCE_SAP_SCC
hdd_adapter_t *pHostapdAdapter;
#endif /* FEATURE_WLAN_FORCE_SAP_SCC */
VOS_STATUS vosStatus = VOS_STATUS_E_FAILURE;
v_U8_t reqRsnIe[DOT11F_IE_RSN_MAX_LEN];
tANI_U32 reqRsnLength = DOT11F_IE_RSN_MAX_LEN;
#if defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) || defined (WLAN_FEATURE_VOWIFI_11R)
int ft_carrier_on = FALSE;
#endif
v_BOOL_t hddDisconInProgress = FALSE;
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
unsigned long rc;
hdd_adapter_t *sap_adapter;
hdd_ap_ctx_t *hdd_ap_ctx;
uint8_t default_sap_channel = 6;
tSirResultCodes timeout_reason = 0;
struct wireless_dev *wdev = dev->ieee80211_ptr;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (pRoamInfo && pRoamInfo->roamSynchInProgress) {
/* change logging before release */
hddLog(VOS_TRACE_LEVEL_DEBUG, "LFR3:hdd_AssociationCompletionHandler");
}
#endif
/* HDD has initiated disconnect, do not send connect result indication
* to kernel as it will be handled by __cfg80211_disconnect.
*/
if(((eConnectionState_Disconnecting == pHddStaCtx->conn_info.connState) ||
(eConnectionState_NotConnected == pHddStaCtx->conn_info.connState)) &&
((eCSR_ROAM_RESULT_ASSOCIATED == roamResult) ||
(eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus)))
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL(" Disconnect from HDD in progress "));
hddDisconInProgress = TRUE;
}
if ( eCSR_ROAM_RESULT_ASSOCIATED == roamResult )
{
if (NULL == pRoamInfo) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("pRoamInfo is NULL"));
return eHAL_STATUS_FAILURE;
}
if ( !hddDisconInProgress )
{
hdd_connSetConnectionState(pAdapter,
eConnectionState_Associated);
}
// Save the connection info from CSR...
hdd_connSaveConnectInfo( pAdapter, pRoamInfo, eCSR_BSS_TYPE_INFRASTRUCTURE );
if (hdd_set_beacon_filter(pAdapter) != 0)
hddLog(LOGE,
FL("hdd_set_beacon_filter() failed"));
#ifdef FEATURE_WLAN_WAPI
if ( pRoamInfo->u.pConnectedProfile->AuthType == eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE ||
pRoamInfo->u.pConnectedProfile->AuthType == eCSR_AUTH_TYPE_WAPI_WAI_PSK )
{
pAdapter->wapi_info.fIsWapiSta = 1;
}
else
{
pAdapter->wapi_info.fIsWapiSta = 0;
}
#endif /* FEATURE_WLAN_WAPI */
/* Indicate 'connect' status to user space */
hdd_SendAssociationEvent(dev,pRoamInfo);
if (hdd_is_mcc_in_24G(pHddCtx)) {
if ((pMac != NULL) && (pHddCtx->miracast_value)) {
hdd_set_mas(pAdapter, pHddCtx->miracast_value);
}
}
// Initialize the Linkup event completion variable
INIT_COMPLETION(pAdapter->linkup_event_var);
/*
Sometimes Switching ON the Carrier is taking time to activate the device properly. Before allowing any
packet to go up to the application, device activation has to be ensured for proper queue mapping by the
kernel. we have registered net device notifier for device change notification. With this we will come to
know that the device is getting activated properly.
*/
#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
if (pHddStaCtx->ft_carrier_on == FALSE)
{
#endif
// Enable Linkup Event Servicing which allows the net device notifier to set the linkup event variable
pAdapter->isLinkUpSvcNeeded = TRUE;
// Enable Linkup Event Servicing which allows the net device notifier to set the linkup event variable
pAdapter->isLinkUpSvcNeeded = TRUE;
// Switch on the Carrier to activate the device
wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_CARRIER_ON,
WLAN_CONTROL_PATH);
// Wait for the Link to up to ensure all the queues are set properly by the kernel
rc = wait_for_completion_timeout(&pAdapter->linkup_event_var,
msecs_to_jiffies(ASSOC_LINKUP_TIMEOUT));
if (!rc) {
hddLog(VOS_TRACE_LEVEL_WARN, "%s: Warning:ASSOC_LINKUP_TIMEOUT", __func__);
}
// Disable Linkup Event Servicing - no more service required from the net device notifier call
pAdapter->isLinkUpSvcNeeded = FALSE;
#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
}
else {
pHddStaCtx->ft_carrier_on = FALSE;
ft_carrier_on = TRUE;
}
#endif
/* Check for STAID */
if ((WLAN_MAX_STA_COUNT + 3) > pRoamInfo->staId)
pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter;
else
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Wrong Staid: %d", __func__,
pRoamInfo->staId);
#ifdef IPA_OFFLOAD
if (hdd_ipa_is_enabled(pHddCtx))
hdd_ipa_wlan_evt(pAdapter, pRoamInfo->staId, WLAN_STA_CONNECT,
pRoamInfo->bssid);
#endif
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(pHddCtx, VOS_FALSE);
#endif
/* validate cfg_ini */
if (!pHddCtx->cfg_ini) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"cfg_ini is NULL");
return eHAL_STATUS_E_NULL_VALUE;
}
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
if ((pHddCtx->cfg_ini->WlanMccToSccSwitchMode
!= VOS_MCC_TO_SCC_SWITCH_DISABLE) &&
((0 == pHddCtx->cfg_ini->conc_custom_rule1) &&
(0 == pHddCtx->cfg_ini->conc_custom_rule2))
#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE
&& !VOS_IS_DFS_CH(pHddStaCtx->conn_info.operationChannel)
#endif
) {
adf_os_create_work(0, &pHddCtx->sta_ap_intf_check_work,
wlan_hdd_check_sta_ap_concurrent_ch_intf, (void *)pAdapter);
adf_os_sched_work(0, &pHddCtx->sta_ap_intf_check_work);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"Checking for Concurrent Change interference");
}
#endif
#ifdef QCA_PKT_PROTO_TRACE
/* STA Associated, update into trace buffer */
if (pHddCtx->cfg_ini->gEnableDebugLog)
{
vos_pkt_trace_buf_update("ST:ASSOC");
}
#endif /* QCA_PKT_PROTO_TRACE */
DPTRACE(adf_dp_trace_mgmt_pkt(ADF_DP_TRACE_MGMT_PACKET_RECORD,
pAdapter->sessionId,
ADF_PROTO_TYPE_MGMT, ADF_PROTO_MGMT_ASSOC));
//For reassoc, the station is already registered, all we need is to change the state
//of the STA in TL.
//If authentication is required (WPA/WPA2/DWEP), change TL to CONNECTED instead of AUTHENTICATED
if( !pRoamInfo->fReassocReq )
{
struct cfg80211_bss *bss;
#ifdef WLAN_FEATURE_VOWIFI_11R
u8 *pFTAssocRsp = NULL;
unsigned int assocRsplen = 0;
u8 *pFTAssocReq = NULL;
unsigned int assocReqlen = 0;
struct ieee80211_channel *chan;
#endif
v_U8_t rspRsnIe[DOT11F_IE_RSN_MAX_LEN];
tANI_U32 rspRsnLength = DOT11F_IE_RSN_MAX_LEN;
/* add bss_id to cfg80211 data base */
bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, pRoamInfo);
if (NULL == bss) {
hddLog(LOGE,
FL("Not able to add BSS entry"));
wlan_hdd_netif_queue_control(pAdapter,
WLAN_NETIF_CARRIER_OFF,
WLAN_CONTROL_PATH);
if (!hddDisconInProgress) {
/*
* Here driver was not able to add bss in cfg80211 database
* this can happen if connected channel is not valid,
* i.e reg domain was changed during connection.
* Queue disconnect for the session if disconnect is
* not in progress.
*/
hddLog(LOGE, FL("Disconnecting..."));
sme_RoamDisconnect( WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
eCSR_DISCONNECT_REASON_UNSPECIFIED);
}
return eHAL_STATUS_FAILURE;
}
#ifdef WLAN_FEATURE_VOWIFI_11R
if(pRoamInfo->u.pConnectedProfile->AuthType == eCSR_AUTH_TYPE_FT_RSN ||
pRoamInfo->u.pConnectedProfile->AuthType == eCSR_AUTH_TYPE_FT_RSN_PSK )
{
//Association Response
pFTAssocRsp = (u8 *)(pRoamInfo->pbFrames + pRoamInfo->nBeaconLength +
pRoamInfo->nAssocReqLength);
if (pFTAssocRsp != NULL)
{
// pFTAssocRsp needs to point to the IEs
pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET;
hddLog(LOG1, "%s: AssocRsp is now at %02x%02x", __func__,
(unsigned int)pFTAssocRsp[0],
(unsigned int)pFTAssocRsp[1]);
assocRsplen = pRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET;
}
else
{
hddLog(LOGE, "%s:AssocRsp is NULL", __func__);
assocRsplen = 0;
}
//Association Request
pFTAssocReq = (u8 *)(pRoamInfo->pbFrames +
pRoamInfo->nBeaconLength);
if (pFTAssocReq != NULL)
{
if(!ft_carrier_on)
{
// pFTAssocReq needs to point to the IEs
pFTAssocReq += FT_ASSOC_REQ_IES_OFFSET;
hddLog(LOG1, "%s: pFTAssocReq is now at %02x%02x", __func__,
(unsigned int)pFTAssocReq[0],
(unsigned int)pFTAssocReq[1]);
assocReqlen = pRoamInfo->nAssocReqLength - FT_ASSOC_REQ_IES_OFFSET;
}
else
{
/* This should contain only the FTIEs */
assocReqlen = pRoamInfo->nAssocReqLength;
}
}
else
{
hddLog(LOGE, "%s:AssocReq is NULL", __func__);
assocReqlen = 0;
}
if(ft_carrier_on)
{
if ( !hddDisconInProgress )
{
struct cfg80211_bss *roam_bss;
struct cfg80211_roam_info roam_info;
/* After roaming is completed, active session count is
* incremented as a part of connect indication but
* effectively the active session count should still
* be the same and hence upon successful reassoc
* decrement the active session count here */
wlan_hdd_decr_active_session(pHddCtx,
pAdapter->device_mode);
hddLog(LOG1, "%s ft_carrier_on is %d, sending roamed "
"indication", __FUNCTION__, ft_carrier_on);
chan = ieee80211_get_channel(pAdapter->wdev.wiphy,
(int)pRoamInfo->pBssDesc->channelId);
hddLog(LOG1, "assocReqlen %d assocRsplen %d", assocReqlen,
assocRsplen);
roam_bss =
hdd_cfg80211_get_bss(
pAdapter->wdev.wiphy,
chan,
pRoamInfo->bssid,
pRoamInfo->u.
pConnectedProfile->SSID.ssId,
pRoamInfo->u.
pConnectedProfile->SSID.length);
roam_info.bss = roam_bss;
roam_info.req_ie = pFTAssocReq;
roam_info.req_ie_len = assocReqlen;
roam_info.resp_ie = pFTAssocRsp;
roam_info.resp_ie_len = assocRsplen;
cfg80211_roamed(dev, &roam_info, GFP_KERNEL);
}
if (sme_GetFTPTKState(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId))
{
sme_SetFTPTKState(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId, FALSE);
pRoamInfo->fAuthRequired = FALSE;
vos_mem_copy(pHddStaCtx->roam_info.bssid,
pRoamInfo->bssid,
HDD_MAC_ADDR_LEN);
vos_mem_copy(pHddStaCtx->roam_info.peerMac,
pRoamInfo->peerMac,
HDD_MAC_ADDR_LEN);
pHddStaCtx->roam_info.roamId = roamId;
pHddStaCtx->roam_info.roamStatus = roamStatus;
pHddStaCtx->roam_info.deferKeyComplete = TRUE;
}
}
else if ( !hddDisconInProgress )
{
hddLog(LOG1, "%s ft_carrier_on is %d, sending connect "
"indication", __FUNCTION__, ft_carrier_on);
if(wdev->ssid_len != 0)
hdd_connect_result(dev, pRoamInfo->bssid, pRoamInfo,
pFTAssocReq, assocReqlen,
pFTAssocRsp, assocRsplen,
WLAN_STATUS_SUCCESS,
GFP_KERNEL, false,
pRoamInfo->statusCode);
}
}
else
#endif
{
/* wpa supplicant expecting WPA/RSN IE in connect result */
csrRoamGetWpaRsnReqIE(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
&reqRsnLength,
reqRsnIe);
csrRoamGetWpaRsnRspIE(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
&rspRsnLength,
rspRsnIe);
if ( !hddDisconInProgress )
{
#if defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
if(ft_carrier_on)
hdd_SendReAssocEvent(dev, pAdapter, pRoamInfo, reqRsnIe, reqRsnLength);
else
#endif /* FEATURE_WLAN_ESE */
{
hddLog(VOS_TRACE_LEVEL_INFO,
"%s: sending connect indication to nl80211:for bssid " MAC_ADDRESS_STR " result:%d and Status:%d",
__func__, MAC_ADDR_ARRAY(pRoamInfo->bssid),
roamResult, roamStatus);
/* inform connect result to nl80211 */
if(wdev->ssid_len != 0)
hdd_connect_result(dev, pRoamInfo->bssid, pRoamInfo,
reqRsnIe, reqRsnLength,
rspRsnIe, rspRsnLength,
WLAN_STATUS_SUCCESS,
GFP_KERNEL, false, pRoamInfo->statusCode);
}
}
}
if ( !hddDisconInProgress )
{
cfg80211_put_bss(
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)) || defined(WITH_BACKPORTS)
pHddCtx->wiphy,
#endif
bss);
// perform any WMM-related association processing
hdd_wmm_assoc(pAdapter, pRoamInfo, eCSR_BSS_TYPE_INFRASTRUCTURE);
/* Start the Queue - Start tx queues before hdd_roamRegisterSTA,
since hdd_roamRegisterSTA will flush any cached data frames
immediately */
hddLog(LOG1, FL("Enabling queues"));
wlan_hdd_netif_queue_control(pAdapter,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
// Register the Station with TL after associated...
vosStatus = hdd_roamRegisterSTA( pAdapter,
pRoamInfo,
pHddStaCtx->conn_info.staId[ 0 ],
NULL,
pRoamInfo->pBssDesc );
}
#ifdef FEATURE_WLAN_TDLS
wlan_hdd_tdls_connection_callback(pAdapter);
#endif
}
else
{
/* wpa supplicant expecting WPA/RSN IE in connect result */
/* in case of reassociation also need to indicate it to supplicant */
csrRoamGetWpaRsnReqIE(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
&reqRsnLength,
reqRsnIe);
hdd_SendReAssocEvent(dev, pAdapter, pRoamInfo, reqRsnIe, reqRsnLength);
//Reassoc successfully
if( pRoamInfo->fAuthRequired )
{
vosStatus = WLANTL_ChangeSTAState(pHddCtx->pvosContext,
pHddStaCtx->conn_info.staId[0],
WLANTL_STA_CONNECTED,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
VOS_FALSE
#endif
);
hdd_connSetAuthenticated(pAdapter, VOS_FALSE);
}
else
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH,
"%s: staId: %d Changing TL state to AUTHENTICATED",
__func__, pHddStaCtx->conn_info.staId[ 0 ] );
vosStatus = WLANTL_ChangeSTAState(pHddCtx->pvosContext,
pHddStaCtx->conn_info.staId[0],
WLANTL_STA_AUTHENTICATED,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
VOS_FALSE
#endif
);
hdd_connSetAuthenticated(pAdapter, VOS_TRUE);
}
if ( VOS_IS_STATUS_SUCCESS( vosStatus ) )
{
// perform any WMM-related association processing
hdd_wmm_assoc(pAdapter, pRoamInfo, eCSR_BSS_TYPE_INFRASTRUCTURE);
}
/* Start the tx queues */
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (pRoamInfo->roamSynchInProgress) {
hddLog(VOS_TRACE_LEVEL_DEBUG, "LFR3:netif_tx_wake_all_queues");
}
#endif
hddLog(LOG1, FL("Enabling queues"));
wlan_hdd_netif_queue_control(pAdapter,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
}
if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"Cannot register STA with TL. Failed with vosStatus = %d [%08X]",
vosStatus, vosStatus );
}
#ifdef WLAN_FEATURE_11W
vos_mem_zero( &pAdapter->hdd_stats.hddPmfStats,
sizeof(pAdapter->hdd_stats.hddPmfStats) );
#endif
}
else
{
hdd_context_t* pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
bool connect_timeout = false;
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if (pRoamInfo)
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"wlan: connection failed with " MAC_ADDRESS_STR " result:%d and Status:%d",
MAC_ADDR_ARRAY(pRoamInfo->bssid), roamResult, roamStatus);
else
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"wlan: connection failed with " MAC_ADDRESS_STR " result:%d and Status:%d",
MAC_ADDR_ARRAY(pWextState->req_bssId),
roamResult, roamStatus);
/* Set connection state to eConnectionState_NotConnected only when CSR
* has completed operation - with a ASSOCIATION_FAILURE status
*/
if ( eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus && !hddDisconInProgress )
{
hdd_connSetConnectionState(pAdapter,
eConnectionState_NotConnected);
}
if((pHddCtx->concurrency_mode <= 1) &&
(pHddCtx->no_of_open_sessions[WLAN_HDD_INFRA_STATION] <=1))
{
pHddCtx->isAmpAllowed = VOS_TRUE;
}
//If the Device Mode is Station
// and the P2P Client is Connected
//Enable BMPS
/*
* In case of JB, as Change-Iface may or may not be called for p2p0
* Enable BMPS/IMPS in case P2P_CLIENT disconnected
* If ps offload is enabled, fw will take care in case of concurrency.
*/
if(((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
(WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) &&
(vos_concurrent_open_sessions_running()) &&
!pHddCtx->cfg_ini->enablePowersaveOffload)
{
//Enable BMPS only of other Session is P2P Client
hdd_context_t *pHddCtx = NULL;
v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL );
if (NULL != pVosContext)
{
pHddCtx = vos_get_context( VOS_MODULE_ID_HDD, pVosContext);
if(NULL != pHddCtx)
{
//Only P2P Client is there Enable Bmps back
if((0 == pHddCtx->no_of_open_sessions[VOS_STA_SAP_MODE]) &&
(0 == pHddCtx->no_of_open_sessions[VOS_P2P_GO_MODE]))
{
if (pHddCtx->hdd_wlan_suspended)
{
hdd_set_pwrparams(pHddCtx);
}
hdd_enable_bmps_imps(pHddCtx);
}
}
}
}
if ((eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE == roamResult) ||
(pRoamInfo &&
((eSIR_SME_JOIN_TIMEOUT_RESULT_CODE == pRoamInfo->statusCode) ||
(eSIR_SME_AUTH_TIMEOUT_RESULT_CODE == pRoamInfo->statusCode) ||
(eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE == pRoamInfo->statusCode)))) {
wlan_hdd_cfg80211_update_bss_list(pAdapter,
pRoamInfo ? pRoamInfo->bssid : pWextState->req_bssId);
sme_remove_bssid_from_scan_list(hHal,
pRoamInfo ? pRoamInfo->bssid : pWextState->req_bssId);
connect_timeout = true;
}
/* CR465478: Only send up a connection failure result when CSR has
* completed operation - with a ASSOCIATION_FAILURE status.*/
if ( eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus && !hddDisconInProgress )
{
if (pRoamInfo) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: send connect failure to nl80211: for bssid " MAC_ADDRESS_STR" result:%d and Status:%d reasonCode %d" ,
__func__, MAC_ADDR_ARRAY(pRoamInfo->bssid),
roamResult, roamStatus, pRoamInfo->reasonCode);
pHddStaCtx->conn_info.assoc_status_code = pRoamInfo->statusCode;
} else {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: connect failed: for bssid " MAC_ADDRESS_STR " result:%d and Status:%d " ,
__func__, MAC_ADDR_ARRAY(pWextState->req_bssId),
roamResult, roamStatus);
}
hddLog(LOG1, FL("Invoking packetdump deregistration API"));
wlan_deregister_txrx_packetdump();
/* inform association failure event to nl80211 */
if ( eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == roamResult )
{
if (pRoamInfo)
hdd_connect_result(dev, pRoamInfo->bssid,
pRoamInfo,
NULL, 0, NULL, 0,
WLAN_STATUS_ASSOC_DENIED_UNSPEC,
GFP_KERNEL, connect_timeout, pRoamInfo->statusCode);
else
hdd_connect_result(dev, pWextState->req_bssId, NULL,
NULL, 0, NULL, 0,
WLAN_STATUS_ASSOC_DENIED_UNSPEC,
GFP_KERNEL, connect_timeout, timeout_reason);
}
else
{
if (pRoamInfo)
hdd_connect_result(dev, pRoamInfo->bssid,
pRoamInfo,
NULL, 0, NULL, 0,
pRoamInfo->reasonCode ?
pRoamInfo->reasonCode :
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL, connect_timeout, pRoamInfo->statusCode);
else
hdd_connect_result(dev, pWextState->req_bssId, NULL,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL, connect_timeout, timeout_reason);
}
/* Clear the roam profile */
hdd_clearRoamProfileIe(pAdapter);
}
hdd_wmm_init( pAdapter );
hddLog(LOG1, FL("Disabling queues"));
wlan_hdd_netif_queue_control(pAdapter,
WLAN_NETIF_TX_DISABLE_N_CARRIER,
WLAN_CONTROL_PATH);
}
if (pHddCtx->cfg_ini->conc_custom_rule1 &&
(true == hdd_is_sap_restart_required(pHddCtx))) {
sap_adapter = hdd_get_adapter(pHddCtx, WLAN_HDD_SOFTAP);
if (sap_adapter == NULL) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("sap_adapter is NULL"));
return eHAL_STATUS_FAILURE;
}
if (test_bit(SOFTAP_BSS_STARTED, &sap_adapter->event_flags)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("Oops SAP is already in started state"));
return eHAL_STATUS_FAILURE;
}
hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(sap_adapter);
if ((eCSR_ROAM_RESULT_ASSOCIATED == roamResult) &&
pHddStaCtx->conn_info.operationChannel < SIR_11A_CHANNEL_BEGIN) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("Starting SAP on channel [%d] after STA assoc complete"),
pHddStaCtx->conn_info.operationChannel);
hdd_ap_ctx->operatingChannel =
pHddStaCtx->conn_info.operationChannel;
} else {
/* start on default SAP channel */
hdd_ap_ctx->operatingChannel =
default_sap_channel;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("Starting SAP on channel [%d] after STA assoc failed"),
default_sap_channel);
}
hdd_ap_ctx->sapConfig.vht_channel_width =
hdd_ap_ctx->sapConfig.ch_width_orig;
sme_SelectCBMode(WLAN_HDD_GET_HAL_CTX(sap_adapter),
hdd_ap_ctx->sapConfig.SapHw_mode,
hdd_ap_ctx->operatingChannel,
hdd_ap_ctx->sapConfig.sec_ch,
&hdd_ap_ctx->sapConfig.vht_channel_width,
hdd_ap_ctx->sapConfig.ch_width_orig);
/*
* Create a workqueue and let the workqueue handle the restarting
* sap task. if we directly call sap restart function without
* creating workqueue then our main thread might go to sleep which
* is not acceptable.
*/
/*
* If channel avoidance is intiated, don't schedule the work.
* Channel avoidance takes care restarting SAP.
*/
if (true == hdd_is_sap_restart_required(pHddCtx))
schedule_work(&pHddCtx->sap_start_work);
}
hdd_clear_fils_connection_info(pAdapter);
/*
* Call hdd_decide_dynamic_chain_mask only when CSR has
* completed connect with failure or success i.e. with
* ASSOCIATION_FAILURE status or with eCSR_ROAM_RESULT_ASSOCIATED
* result.
*/
if (pHddCtx->cfg_ini->enable_dynamic_sta_chainmask &&
((eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus) ||
(eCSR_ROAM_RESULT_ASSOCIATED == roamResult)))
hdd_decide_dynamic_chain_mask(pHddCtx,
HDD_ANTENNA_MODE_INVALID);
#ifdef FEATURE_WLAN_FORCE_SAP_SCC
if (eCSR_ROAM_RESULT_ASSOCIATED == roamResult &&
pHddCtx->cfg_ini->SapSccChanAvoidance) {
pHostapdAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_SOFTAP);
if (pHostapdAdapter != NULL) {
/* Restart SAP if its operating channel is different
* from AP channel.
*/
if (pHostapdAdapter->sessionCtx.ap.operatingChannel !=
pRoamInfo->pBssDesc->channelId) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"Restart Sap as SAP channel is %d and STA channel is %d",
pHostapdAdapter->sessionCtx.ap.operatingChannel,
pRoamInfo->pBssDesc->channelId);
hdd_restart_softap(pHddCtx, pHostapdAdapter);
}
}
}
#endif /* FEATURE_WLAN_FORCE_SAP_SCC */
return eHAL_STATUS_SUCCESS;
}
/**============================================================================
*
@brief hdd_RoamIbssIndicationHandler() - Here we update the status of the
Ibss when we receive information that we have started/joined an ibss session
===========================================================================*/
static void hdd_RoamIbssIndicationHandler( hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
tANI_U32 roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult )
{
hddLog(VOS_TRACE_LEVEL_INFO, "%s: %s: id %d, status %d, result %d",
__func__, pAdapter->dev->name, roamId, roamStatus, roamResult);
switch( roamResult )
{
// both IBSS Started and IBSS Join should come in here.
case eCSR_ROAM_RESULT_IBSS_STARTED:
case eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS:
case eCSR_ROAM_RESULT_IBSS_COALESCED:
{
hdd_context_t *pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
v_MACADDR_t broadcastMacAddr = VOS_MAC_ADDR_BROADCAST_INITIALIZER;
if (NULL == pRoamInfo)
{
VOS_ASSERT(0);
return;
}
/* When IBSS Started comes from CSR, we need to move
* connection state to IBSS Disconnected (meaning no peers
* are in the IBSS).
*/
hdd_connSetConnectionState(pAdapter,
eConnectionState_IbssDisconnected);
/* Notify wmm */
hdd_wmm_connect(pAdapter, pRoamInfo, eCSR_BSS_TYPE_IBSS);
pHddCtx->sta_to_adapter[IBSS_BROADCAST_STAID] = pAdapter;
hdd_roamRegisterSTA (pAdapter, pRoamInfo,
IBSS_BROADCAST_STAID,
&broadcastMacAddr, pRoamInfo->pBssDesc);
if (pRoamInfo->pBssDesc)
{
struct cfg80211_bss *bss;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0)) || defined(WITH_BACKPORTS)
struct ieee80211_channel *chan;
int chan_no;
unsigned int freq;
#endif
/* we created the IBSS, notify supplicant */
hddLog(VOS_TRACE_LEVEL_INFO, "%s: %s: created ibss "
MAC_ADDRESS_STR,
__func__, pAdapter->dev->name,
MAC_ADDR_ARRAY(pRoamInfo->pBssDesc->bssId));
/* we must first give cfg80211 the BSS information */
bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, pRoamInfo);
if (NULL == bss)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: %s: unable to create IBSS entry",
__func__, pAdapter->dev->name);
return;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0)) || defined(WITH_BACKPORTS)
chan_no = pRoamInfo->pBssDesc->channelId;
if (chan_no <= 14)
freq = ieee80211_channel_to_frequency(chan_no,
IEEE80211_BAND_2GHZ);
else
freq = ieee80211_channel_to_frequency(chan_no,
IEEE80211_BAND_5GHZ);
chan = ieee80211_get_channel(pAdapter->wdev.wiphy, freq);
if (chan)
cfg80211_ibss_joined(pAdapter->