blob: b2ba1ae089f06434e57cb8d06f6ee1565e026e6f [file] [log] [blame]
/*
* Copyright (c) 2012-2017 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.
*/
/**
* DOC: wlan_hdd_assoc.c
*
* WLAN Host Device Driver implementation
*
*/
#include "wlan_hdd_includes.h"
#include <ani_global.h>
#include "dot11f.h"
#include "wlan_hdd_power.h"
#include "wlan_hdd_trace.h"
#include <linux/ieee80211.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <net/cfg80211.h>
#include "wlan_hdd_cfg80211.h"
#include "csr_inside_api.h"
#include "wlan_hdd_p2p.h"
#include "wlan_hdd_tdls.h"
#include "sme_api.h"
#include "wlan_hdd_hostapd.h"
#include <wlan_hdd_ipa.h>
#include "wlan_hdd_lpass.h"
#include <wlan_logging_sock_svc.h>
#include <cds_sched.h>
#include "wlan_policy_mgr_api.h"
#include <cds_utils.h>
#include "sme_power_save_api.h"
#include "wlan_hdd_napi.h"
#include <cdp_txrx_cmn.h>
#include <cdp_txrx_flow_ctrl_legacy.h>
#include <cdp_txrx_peer_ops.h>
#include <cdp_txrx_misc.h>
#include <cdp_txrx_ctrl.h>
#include <wlan_logging_sock_svc.h>
#include <wlan_hdd_object_manager.h>
#include <cdp_txrx_handle.h>
#include "wlan_pmo_ucfg_api.h"
#include "wlan_hdd_tsf.h"
/* These are needed to recognize WPA and RSN suite types */
#define HDD_WPA_OUI_SIZE 4
#define HDD_RSN_OUI_SIZE 4
uint8_t ccp_wpa_oui00[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x00 };
uint8_t ccp_wpa_oui01[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x01 };
uint8_t ccp_wpa_oui02[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 };
uint8_t ccp_wpa_oui03[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x03 };
uint8_t ccp_wpa_oui04[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x04 };
uint8_t ccp_wpa_oui05[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x05 };
#ifdef FEATURE_WLAN_ESE
/* CCKM */
uint8_t ccp_wpa_oui06[HDD_WPA_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 };
/* CCKM */
uint8_t ccp_rsn_oui06[HDD_RSN_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 };
#endif /* FEATURE_WLAN_ESE */
/* group cipher */
uint8_t ccp_rsn_oui00[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x00 };
/* WEP-40 or RSN */
uint8_t ccp_rsn_oui01[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x01 };
/* TKIP or RSN-PSK */
uint8_t ccp_rsn_oui02[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x02 };
/* Reserved */
uint8_t ccp_rsn_oui03[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x03 };
/* AES-CCMP */
uint8_t ccp_rsn_oui04[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x04 };
/* WEP-104 */
uint8_t ccp_rsn_oui05[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 };
#ifdef WLAN_FEATURE_11W
/* RSN-PSK-SHA256 */
uint8_t ccp_rsn_oui07[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x06 };
/* RSN-8021X-SHA256 */
uint8_t ccp_rsn_oui08[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 };
#endif
/* AES-GCMP-128 */
uint8_t ccp_rsn_oui09[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x08 };
/* AES-GCMP-256 */
uint8_t ccp_rsn_oui0a[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x09 };
#ifdef WLAN_FEATURE_FILS_SK
uint8_t ccp_rsn_oui_0e[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0E};
uint8_t ccp_rsn_oui_0f[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0F};
uint8_t ccp_rsn_oui_10[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x10};
uint8_t ccp_rsn_oui_11[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x11};
#endif
/* 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) */
#define BEACON_FRAME_IES_OFFSET 12
#define HDD_PEER_AUTHORIZE_WAIT 10
/**
* beacon_filter_table - table of IEs used for beacon filtering
*/
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,
SIR_MAC_VHT_OPMODE_EID,
SIR_MAC_VHT_OPERATION_EID,
#ifdef WLAN_FEATURE_11AX_BSS_COLOR
/*
* EID: 221 vendor IE is being used temporarily by 11AX
* bss-color-change IE till it gets any fixed number. This
* vendor EID needs to be replaced with bss-color-change IE
* number.
*/
SIR_MAC_EID_VENDOR,
#endif
};
/**
* hdd_conn_set_authenticated() - set authentication state
* @pAdapter: pointer to the adapter
* @authState: authentication state
*
* This function updates the global HDD station context
* authentication state.
*
* Return: none
*/
static void
hdd_conn_set_authenticated(hdd_adapter_t *pAdapter, uint8_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 */
hdd_debug("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->roc_req_work, 0);
}
/**
* hdd_conn_set_connection_state() - set connection state
* @adapter: pointer to the adapter
* @conn_state: connection state
*
* This function updates the global HDD station context connection state.
*
* Return: none
*/
void hdd_conn_set_connection_state(hdd_adapter_t *adapter,
eConnectionState conn_state)
{
hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
/* save the new connection state */
hdd_debug("%pS Changed conn state from old:%d to new:%d for dev %s",
(void *)_RET_IP_, hdd_sta_ctx->conn_info.connState,
conn_state, adapter->dev->name);
hdd_tsf_notify_wlan_state_change(adapter,
hdd_sta_ctx->conn_info.connState,
conn_state);
hdd_sta_ctx->conn_info.connState = conn_state;
schedule_delayed_work(&hdd_ctx->roc_req_work, 0);
}
/**
* hdd_conn_get_connection_state() - get connection state
* @pAdapter: pointer to the adapter
* @pConnState: pointer to connection state
*
* This function updates the global HDD station context connection state.
*
* Return: true if (Infra Associated or IBSS Connected)
* and sets output parameter pConnState;
* false otherwise
*/
static inline bool hdd_conn_get_connection_state(hdd_station_ctx_t *pHddStaCtx,
eConnectionState *pConnState)
{
bool fConnected = false;
eConnectionState connState;
/* get the connection state. */
connState = pHddStaCtx->conn_info.connState;
if (eConnectionState_Associated == connState ||
eConnectionState_IbssConnected == connState ||
eConnectionState_IbssDisconnected == connState) {
fConnected = true;
}
if (pConnState)
*pConnState = connState;
return fConnected;
}
/**
* hdd_is_connecting() - Function to check connection progress
* @hdd_sta_ctx: pointer to global HDD Station context
*
* Return: true if connecting, false otherwise
*/
bool hdd_is_connecting(hdd_station_ctx_t *hdd_sta_ctx)
{
return hdd_sta_ctx->conn_info.connState ==
eConnectionState_Connecting;
}
/**
* hdd_conn_is_connected() - Function to check connection status
* @pHddStaCtx: pointer to global HDD Station context
*
* Return: false if any errors encountered, true otherwise
*/
bool hdd_conn_is_connected(hdd_station_ctx_t *pHddStaCtx)
{
return hdd_conn_get_connection_state(pHddStaCtx, NULL);
}
/**
* hdd_conn_get_connected_band() - get current connection radio band
* @pHddStaCtx: pointer to global HDD Station context
*
* Return: eCSR_BAND_24 or eCSR_BAND_5G based on current AP connection
* eCSR_BAND_ALL if not connected
*/
enum band_info hdd_conn_get_connected_band(hdd_station_ctx_t *pHddStaCtx)
{
uint8_t staChannel = 0;
if (eConnectionState_Associated == pHddStaCtx->conn_info.connState)
staChannel = pHddStaCtx->conn_info.operationChannel;
if (staChannel > 0 && staChannel < 14)
return BAND_2G;
else if (staChannel >= 36 && staChannel <= 184)
return BAND_5G;
else /* If station is not connected return as eCSR_BAND_ALL */
return BAND_ALL;
}
/**
* hdd_conn_get_connected_cipher_algo() - get current connection cipher type
* @pHddStaCtx: pointer to global HDD Station context
* @pConnectedCipherAlgo: pointer to connected cipher algo
*
* Return: false if any errors encountered, true otherwise
*/
static inline bool
hdd_conn_get_connected_cipher_algo(hdd_station_ctx_t *pHddStaCtx,
eCsrEncryptionType *pConnectedCipherAlgo)
{
bool fConnected = false;
fConnected = hdd_conn_get_connection_state(pHddStaCtx, NULL);
if (pConnectedCipherAlgo)
*pConnectedCipherAlgo = pHddStaCtx->conn_info.ucEncryptionType;
return fConnected;
}
/**
* hdd_remove_beacon_filter() - remove beacon filter
* @adapter: Pointer to the hdd adapter
*
* Return: 0 on success and errno on failure
*/
static int hdd_remove_beacon_filter(hdd_adapter_t *adapter)
{
QDF_STATUS status;
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
status = sme_remove_beacon_filter(hdd_ctx->hHal,
adapter->sessionId);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("sme_remove_beacon_filter() failed");
return -EFAULT;
}
return 0;
}
/**
* hdd_add_beacon_filter() - add beacon filter
* @adapter: Pointer to the hdd adapter
*
* Return: 0 on success and errno on failure
*/
static int hdd_add_beacon_filter(hdd_adapter_t *adapter)
{
int i;
uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST] = {0};
QDF_STATUS status;
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
for (i = 0; i < ARRAY_SIZE(beacon_filter_table); i++)
qdf_set_bit((beacon_filter_table[i]),
(unsigned long int *)ie_map);
status = sme_add_beacon_filter(hdd_ctx->hHal,
adapter->sessionId, ie_map);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("sme_add_beacon_filter() failed");
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;
qdf_mem_zero(hdd_ht_cap, sizeof(struct ieee80211_ht_cap));
if (roam_ht_cap->advCodingCap)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LDPC_CODING;
if (roam_ht_cap->supportedChannelWidthSet)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
temp_ht_cap = roam_ht_cap->mimoPowerSave &
(IEEE80211_HT_CAP_SM_PS >> IEEE80211_HT_CAP_SM_PS_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->cap_info |=
temp_ht_cap << IEEE80211_HT_CAP_SM_PS_SHIFT;
if (roam_ht_cap->greenField)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_GRN_FLD;
if (roam_ht_cap->shortGI20MHz)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_20;
if (roam_ht_cap->shortGI40MHz)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_40;
if (roam_ht_cap->txSTBC)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_TX_STBC;
temp_ht_cap = roam_ht_cap->rxSTBC & (IEEE80211_HT_CAP_RX_STBC >>
IEEE80211_HT_CAP_RX_STBC_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->cap_info |=
temp_ht_cap << IEEE80211_HT_CAP_RX_STBC_SHIFT;
if (roam_ht_cap->delayedBA)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DELAY_BA;
if (roam_ht_cap->maximalAMSDUsize)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_MAX_AMSDU;
if (roam_ht_cap->dsssCckMode40MHz)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
if (roam_ht_cap->psmp)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_RESERVED;
if (roam_ht_cap->stbcControlFrame)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_40MHZ_INTOLERANT;
if (roam_ht_cap->lsigTXOPProtection)
hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LSIG_TXOP_PROT;
/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
if (roam_ht_cap->maxRxAMPDUFactor)
hdd_ht_cap->ampdu_params_info |=
IEEE80211_HT_AMPDU_PARM_FACTOR;
temp_ht_cap = roam_ht_cap->mpduDensity &
(IEEE80211_HT_AMPDU_PARM_DENSITY >>
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->ampdu_params_info |=
temp_ht_cap << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
/* 802.11n HT extended capabilities masks */
if (roam_ht_cap->pco)
hdd_ht_cap->extended_ht_cap_info |=
IEEE80211_HT_EXT_CAP_PCO;
temp_ht_cap = roam_ht_cap->transitionTime &
(IEEE80211_HT_EXT_CAP_PCO_TIME >>
IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->extended_ht_cap_info |=
temp_ht_cap << IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT;
temp_ht_cap = roam_ht_cap->mcsFeedback &
(IEEE80211_HT_EXT_CAP_MCS_FB >> IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->extended_ht_cap_info |=
temp_ht_cap << IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT;
/* tx_bf_cap_info capabilities */
if (roam_ht_cap->txBF)
hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_BF;
if (roam_ht_cap->rxStaggeredSounding)
hdd_ht_cap->tx_BF_cap_info |=
TX_BF_CAP_INFO_RX_STAG_RED_SOUNDING;
if (roam_ht_cap->txStaggeredSounding)
hdd_ht_cap->tx_BF_cap_info |=
TX_BF_CAP_INFO_TX_STAG_RED_SOUNDING;
if (roam_ht_cap->rxZLF)
hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_RX_ZFL;
if (roam_ht_cap->txZLF)
hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_ZFL;
if (roam_ht_cap->implicitTxBF)
hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_IMP_TX_BF;
temp_ht_cap = roam_ht_cap->calibration &
(TX_BF_CAP_INFO_CALIBRATION >> TX_BF_CAP_INFO_CALIBRATION_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap << TX_BF_CAP_INFO_CALIBRATION_SHIFT;
if (roam_ht_cap->explicitCSITxBF)
hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_EXP_CSIT_BF;
if (roam_ht_cap->explicitUncompressedSteeringMatrix)
hdd_ht_cap->tx_BF_cap_info |=
TX_BF_CAP_INFO_EXP_UNCOMP_STEER_MAT;
temp_ht_cap = roam_ht_cap->explicitBFCSIFeedback &
(TX_BF_CAP_INFO_EXP_BF_CSI_FB >>
TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap << TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT;
temp_ht_cap =
roam_ht_cap->explicitUncompressedSteeringMatrixFeedback &
(TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT >>
TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap <<
TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT;
temp_ht_cap =
roam_ht_cap->explicitCompressedSteeringMatrixFeedback &
(TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB >>
TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap <<
TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT;
temp_ht_cap = roam_ht_cap->csiNumBFAntennae &
(TX_BF_CAP_INFO_CSI_NUM_BF_ANT >>
TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap << TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT;
temp_ht_cap = roam_ht_cap->uncompressedSteeringMatrixBFAntennae &
(TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT >>
TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap <<
TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT;
temp_ht_cap = roam_ht_cap->compressedSteeringMatrixBFAntennae &
(TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT >>
TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT);
if (temp_ht_cap)
hdd_ht_cap->tx_BF_cap_info |=
temp_ht_cap <<
TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT;
/* antenna selection */
if (roam_ht_cap->antennaSelection)
hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO;
if (roam_ht_cap->explicitCSIFeedbackTx)
hdd_ht_cap->antenna_selection_info |=
ANTENNA_SEL_INFO_EXP_CSI_FB_TX;
if (roam_ht_cap->antennaIndicesFeedbackTx)
hdd_ht_cap->antenna_selection_info |=
ANTENNA_SEL_INFO_ANT_ID_FB_TX;
if (roam_ht_cap->explicitCSIFeedback)
hdd_ht_cap->antenna_selection_info |=
ANTENNA_SEL_INFO_EXP_CSI_FB;
if (roam_ht_cap->antennaIndicesFeedback)
hdd_ht_cap->antenna_selection_info |=
ANTENNA_SEL_INFO_ANT_ID_FB;
if (roam_ht_cap->rxAS)
hdd_ht_cap->antenna_selection_info |=
ANTENNA_SEL_INFO_RX_AS;
if (roam_ht_cap->txSoundingPPDUs)
hdd_ht_cap->antenna_selection_info |=
ANTENNA_SEL_INFO_TX_SOUNDING_PPDU;
/* mcs data rate */
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; ++i)
hdd_ht_cap->mcs.rx_mask[i] =
roam_ht_cap->supportedMCSSet[i];
hdd_ht_cap->mcs.rx_highest =
((short) (roam_ht_cap->supportedMCSSet[11]) << 8) |
((short) (roam_ht_cap->supportedMCSSet[10]));
hdd_ht_cap->mcs.tx_params =
roam_ht_cap->supportedMCSSet[12];
}
#define VHT_CAP_MAX_MPDU_LENGTH_MASK 0x00000003
#define VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT 2
#define VHT_CAP_RXSTBC_MASK_SHIFT 8
#define VHT_CAP_BEAMFORMEE_STS_SHIFT 13
#define VHT_CAP_BEAMFORMEE_STS_MASK \
(0x0000e000 >> VHT_CAP_BEAMFORMEE_STS_SHIFT)
#define VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16
#define VHT_CAP_SOUNDING_DIMENSIONS_MASK \
(0x00070000 >> VHT_CAP_SOUNDING_DIMENSIONS_SHIFT)
#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT 23
#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \
(0x03800000 >> VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT)
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT 26
/**
* 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;
qdf_mem_zero(hdd_vht_cap, sizeof(struct ieee80211_vht_cap));
temp_vht_cap = roam_vht_cap->maxMPDULen & VHT_CAP_MAX_MPDU_LENGTH_MASK;
hdd_vht_cap->vht_cap_info |= temp_vht_cap;
temp_vht_cap = roam_vht_cap->supportedChannelWidthSet &
(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK >>
VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT);
if (temp_vht_cap) {
if (roam_vht_cap->supportedChannelWidthSet &
(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ >>
VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT))
hdd_vht_cap->vht_cap_info |=
temp_vht_cap <<
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
if (roam_vht_cap->supportedChannelWidthSet &
(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ >>
VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT))
hdd_vht_cap->vht_cap_info |=
temp_vht_cap <<
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
}
if (roam_vht_cap->ldpcCodingCap)
hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_RXLDPC;
if (roam_vht_cap->shortGI80MHz)
hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_80;
if (roam_vht_cap->shortGI160and80plus80MHz)
hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_160;
if (roam_vht_cap->txSTBC)
hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_TXSTBC;
temp_vht_cap = roam_vht_cap->rxSTBC & (IEEE80211_VHT_CAP_RXSTBC_MASK >>
VHT_CAP_RXSTBC_MASK_SHIFT);
if (temp_vht_cap)
hdd_vht_cap->vht_cap_info |=
temp_vht_cap << VHT_CAP_RXSTBC_MASK_SHIFT;
if (roam_vht_cap->suBeamFormerCap)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
if (roam_vht_cap->suBeamformeeCap)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
temp_vht_cap = roam_vht_cap->csnofBeamformerAntSup &
(VHT_CAP_BEAMFORMEE_STS_MASK);
if (temp_vht_cap)
hdd_vht_cap->vht_cap_info |=
temp_vht_cap << VHT_CAP_BEAMFORMEE_STS_SHIFT;
temp_vht_cap = roam_vht_cap->numSoundingDim &
(VHT_CAP_SOUNDING_DIMENSIONS_MASK);
if (temp_vht_cap)
hdd_vht_cap->vht_cap_info |=
temp_vht_cap << VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
if (roam_vht_cap->muBeamformerCap)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
if (roam_vht_cap->muBeamformeeCap)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
if (roam_vht_cap->vhtTXOPPS)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_VHT_TXOP_PS;
if (roam_vht_cap->htcVHTCap)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_HTC_VHT;
temp_vht_cap = roam_vht_cap->maxAMPDULenExp &
(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
if (temp_vht_cap)
hdd_vht_cap->vht_cap_info |=
temp_vht_cap <<
VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT;
temp_vht_cap = roam_vht_cap->vhtLinkAdaptCap &
(IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB >>
VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT);
if (temp_vht_cap)
hdd_vht_cap->vht_cap_info |= temp_vht_cap <<
VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT;
if (roam_vht_cap->rxAntPattern)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
if (roam_vht_cap->txAntPattern)
hdd_vht_cap->vht_cap_info |=
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
hdd_vht_cap->supp_mcs.rx_mcs_map = roam_vht_cap->rxMCSMap;
hdd_vht_cap->supp_mcs.rx_highest =
((uint16_t)roam_vht_cap->rxHighSupDataRate);
hdd_vht_cap->supp_mcs.tx_mcs_map = roam_vht_cap->txMCSMap;
hdd_vht_cap->supp_mcs.tx_highest =
((uint16_t)roam_vht_cap->txSupDataRate);
}
/* ht param */
#define HT_PARAM_CONTROLLED_ACCESS_ONLY 0x10
#define HT_PARAM_SERVICE_INT_GRAN 0xe0
#define HT_PARAM_SERVICE_INT_GRAN_SHIFT 5
/* operatinon mode */
#define HT_OP_MODE_TX_BURST_LIMIT 0x0008
/* stbc_param */
#define HT_STBC_PARAM_MCS 0x007f
/**
* 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;
qdf_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;
qdf_mem_zero(hdd_vht_ops, sizeof(struct ieee80211_vht_operation));
hdd_vht_ops->chan_width = roam_vht_ops->chanWidth;
hdd_vht_ops->center_freq_seg1_idx = roam_vht_ops->chanCenterFreqSeg1;
hdd_vht_ops->center_freq_seg2_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 = cds_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;
qdf_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;
}
}
/**
* hdd_conn_save_connect_info() - save current connection information
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @eBssType: bss type
*
* Return: none
*/
static void
hdd_conn_save_connect_info(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;
QDF_ASSERT(pRoamInfo);
if (pRoamInfo) {
/* Save the BSSID for the connection */
if (eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) {
QDF_ASSERT(pRoamInfo->pBssDesc);
qdf_copy_macaddr(&pHddStaCtx->conn_info.bssId,
&pRoamInfo->bssid);
/*
* 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) {
qdf_copy_macaddr(&pHddStaCtx->conn_info.bssId,
&pRoamInfo->bssid);
} else {
/*
* can't happen. We need a valid IBSS or Infra setting
* in the BSSDescription or we can't function.
*/
QDF_ASSERT(0);
}
/* notify WMM */
hdd_wmm_connect(pAdapter, pRoamInfo, eBssType);
if (!pRoamInfo->u.pConnectedProfile) {
QDF_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 */
qdf_mem_copy(&pHddStaCtx->conn_info.SSID.SSID,
&pRoamInfo->u.pConnectedProfile->SSID,
sizeof(tSirMacSSid));
qdf_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);
}
}
/**
* hdd_send_ft_assoc_response() - send fast transition assoc response
* @dev: pointer to net device
* @pAdapter: pointer to adapter
* @pCsrRoamInfo: pointer to roam info
*
* 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.
*
* Return: none
*/
static void
hdd_send_ft_assoc_response(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) {
hdd_debug("assoc rsp length is 0");
return;
}
pFTAssocRsp =
(u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength +
pCsrRoamInfo->nAssocReqLength);
if (pFTAssocRsp == NULL) {
hdd_debug("AssocReq or AssocRsp is NULL");
return;
}
/* pFTAssocRsp needs to point to the IEs */
pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET;
hdd_debug("AssocRsp is now at %02x%02x",
(unsigned int)pFTAssocRsp[0],
(unsigned int)pFTAssocRsp[1]);
/* We need to send the IEs to the supplicant. */
buff = qdf_mem_malloc(IW_GENERIC_IE_MAX);
if (buff == NULL) {
hdd_err("unable to allocate memory");
return;
}
/* Send the Assoc Resp, the supplicant needs this for initial Auth. */
len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET;
wrqu.data.length = len;
memcpy(buff, pFTAssocRsp, len);
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, buff);
qdf_mem_free(buff);
}
/**
* hdd_send_ft_event() - send fast transition event
* @pAdapter: pointer to adapter
*
* 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.
*
* Return: none
*/
static void hdd_send_ft_event(hdd_adapter_t *pAdapter)
{
uint16_t auth_resp_len = 0;
uint32_t 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;
uint8_t ftIe[DOT11F_IE_FTINFO_MAX_LEN];
uint8_t ricIe[DOT11F_IE_RICDESCRIPTOR_MAX_LEN];
struct net_device *dev = pAdapter->dev;
#else
char *buff;
union iwreq_data wrqu;
uint16_t str_len;
#endif
#if defined(KERNEL_SUPPORT_11R_CFG80211)
qdf_mem_zero(ftIe, DOT11F_IE_FTINFO_MAX_LEN);
qdf_mem_zero(ricIe, DOT11F_IE_RICDESCRIPTOR_MAX_LEN);
sme_get_rici_es(pHddCtx->hHal, pAdapter->sessionId, (u8 *) ricIe,
DOT11F_IE_RICDESCRIPTOR_MAX_LEN, &ric_ies_length);
if (ric_ies_length == 0)
hdd_warn("Do not send RIC IEs as length is 0");
ftEvent.ric_ies = ricIe;
ftEvent.ric_ies_len = ric_ies_length;
hdd_debug("RIC IEs is of length %d", (int)ric_ies_length);
sme_get_ft_pre_auth_response(pHddCtx->hHal, pAdapter->sessionId,
(u8 *) ftIe, DOT11F_IE_FTINFO_MAX_LEN,
&auth_resp_len);
if (auth_resp_len == 0) {
hdd_debug("AuthRsp FTIES is of length 0");
return;
}
sme_set_ft_pre_auth_state(pHddCtx->hHal, pAdapter->sessionId, true);
ftEvent.target_ap = ftIe;
ftEvent.ies = (u8 *) (ftIe + QDF_MAC_ADDR_SIZE);
ftEvent.ies_len = auth_resp_len - QDF_MAC_ADDR_SIZE;
hdd_debug("ftEvent.ies_len %zu", ftEvent.ies_len);
hdd_debug("ftEvent.ric_ies_len %zu", ftEvent.ric_ies_len);
hdd_debug("ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x",
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 = qdf_mem_malloc(IW_CUSTOM_MAX);
if (buff == NULL) {
hdd_err("unable to allocate memory");
return;
}
/* Sme needs to send the RIC IEs first */
str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX);
sme_get_rici_es(pHddCtx->hHal, pAdapter->sessionId,
(u8 *) &(buff[str_len]), (IW_CUSTOM_MAX - str_len),
&ric_ies_length);
if (ric_ies_length == 0) {
hdd_warn("Do not send RIC IEs as length is 0");
} else {
wrqu.data.length = str_len + ric_ies_length;
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff);
}
/* Sme needs to provide the Auth Resp */
qdf_mem_zero(buff, IW_CUSTOM_MAX);
str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX);
sme_get_ft_pre_auth_response(pHddCtx->hHal, pAdapter->sessionId,
(u8 *) &buff[str_len],
(IW_CUSTOM_MAX - str_len), &auth_resp_len);
if (auth_resp_len == 0) {
qdf_mem_free(buff);
hdd_debug("AuthRsp FTIES is of length 0");
return;
}
wrqu.data.length = str_len + auth_resp_len;
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff);
qdf_mem_free(buff);
#endif
}
#ifdef FEATURE_WLAN_ESE
/**
* hdd_send_new_ap_channel_info() - send new ap channel info
* @dev: pointer to net device
* @pAdapter: pointer to adapter
* @pCsrRoamInfo: pointer to roam info
*
* 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.
*
* Return: none
*/
static void
hdd_send_new_ap_channel_info(struct net_device *dev, hdd_adapter_t *pAdapter,
tCsrRoamInfo *pCsrRoamInfo)
{
union iwreq_data wrqu;
tSirBssDescription *descriptor = pCsrRoamInfo->pBssDesc;
if (descriptor == NULL) {
hdd_err("bss descriptor is null");
return;
}
/*
* Send the Channel event, the supplicant needs this to generate
* the Adjacent AP report.
*/
hdd_debug("Sending up an SIOCGIWFREQ, channelId: %d",
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 */
/**
* hdd_send_update_beacon_ies_event() - send update beacons ie event
* @pAdapter: pointer to adapter
* @pCsrRoamInfo: pointer to roam info
*
* Return: none
*/
static void
hdd_send_update_beacon_ies_event(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) {
hdd_debug("beacon frame length is 0");
return;
}
pBeaconIes = (u8 *) (pCsrRoamInfo->pbFrames + BEACON_FRAME_IES_OFFSET);
if (pBeaconIes == NULL) {
hdd_warn("Beacon IEs is NULL");
return;
}
/* pBeaconIes needs to point to the IEs */
hdd_debug("Beacon IEs is now at %02x%02x",
(unsigned int)pBeaconIes[0],
(unsigned int)pBeaconIes[1]);
hdd_debug("Beacon IEs length = %d",
pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET);
/* We need to send the IEs to the supplicant. */
buff = qdf_mem_malloc(IW_CUSTOM_MAX);
if (buff == NULL) {
hdd_err("unable to allocate memory");
return;
}
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.
*/
qdf_mem_zero(&buff[strLen + 1], IW_CUSTOM_MAX - (strLen + 1));
currentLen =
QDF_MIN(totalIeLen, IW_CUSTOM_MAX - (strLen + 1) - 1);
qdf_mem_copy(&buff[strLen + 1], pBeaconIes + currentOffset,
currentLen);
currentOffset += currentLen;
totalIeLen -= currentLen;
wrqu.data.length = strLen + 1 + currentLen;
if (totalIeLen)
buff[strLen] = 1; /* more chunks pending */
else
buff[strLen] = 0; /* last chunk */
hdd_debug("Beacon IEs length to supplicant = %d",
currentLen);
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff);
} while (totalIeLen > 0);
qdf_mem_free(buff);
}
/**
* hdd_send_association_event() - send association event
* @dev: pointer to net device
* @pCsrRoamInfo: pointer to roam info
*
* Return: none
*/
static void hdd_send_association_event(struct net_device *dev,
tCsrRoamInfo *pCsrRoamInfo)
{
int ret;
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;
struct qdf_mac_addr peerMacAddr;
/* 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);
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 */
hdd_debug("LFR3:hdd_send_association_event");
/* Update tdls module about the disconnection event */
hdd_notify_sta_disconnect(pAdapter->sessionId,
true, pAdapter->hdd_vdev);
wlan_hdd_tdls_notify_disconnect(pAdapter, true);
}
#endif
if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) {
tSirSmeChanInfo chan_info = {0};
if (!pCsrRoamInfo) {
hdd_warn("STA in associated state but pCsrRoamInfo is null");
return;
}
if (!hdd_is_roam_sync_in_progress(pCsrRoamInfo))
policy_mgr_incr_active_session(pHddCtx->hdd_psoc,
pAdapter->device_mode, pAdapter->sessionId);
memcpy(wrqu.ap_addr.sa_data, pCsrRoamInfo->pBssDesc->bssId,
sizeof(pCsrRoamInfo->pBssDesc->bssId));
#ifdef WLAN_FEATURE_P2P_DEBUG
if (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) {
if (global_p2p_connection_status ==
P2P_CLIENT_CONNECTING_STATE_1) {
global_p2p_connection_status =
P2P_CLIENT_CONNECTED_STATE_1;
hdd_debug("[P2P State] Changing state from Connecting state to Connected State for 8-way Handshake");
} else if (global_p2p_connection_status ==
P2P_CLIENT_CONNECTING_STATE_2) {
global_p2p_connection_status =
P2P_CLIENT_COMPLETED_STATE;
hdd_debug("[P2P State] Changing state from Connecting state to P2P Client Connection Completed");
}
}
#endif
pr_info("wlan: " MAC_ADDRESS_STR " connected to "
MAC_ADDRESS_STR "\n",
MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes),
MAC_ADDR_ARRAY(wrqu.ap_addr.sa_data));
hdd_send_update_beacon_ies_event(pAdapter, pCsrRoamInfo);
/*
* Send IWEVASSOCRESPIE Event if WLAN_FEATURE_CIQ_METRICS
* is Enabled Or Send IWEVASSOCRESPIE Event if
* fFTEnable is true.
* 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_send_ft_assoc_response(dev, pAdapter, pCsrRoamInfo);
}
qdf_copy_macaddr(&peerMacAddr,
&pHddStaCtx->conn_info.bssId);
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;
ret = hdd_objmgr_add_peer_object(pAdapter->hdd_vdev,
pAdapter->device_mode,
peerMacAddr.bytes,
false);
if (ret)
hdd_err("Peer object "MAC_ADDRESS_STR" add fails!",
MAC_ADDR_ARRAY(peerMacAddr.bytes));
ret = hdd_objmgr_set_peer_mlme_state(pAdapter->hdd_vdev,
WLAN_ASSOC_STATE);
if (ret)
hdd_err("Peer object %pM fail to set associated state",
peerMacAddr.bytes);
/* send peer status indication to oem app */
hdd_send_peer_status_ind_to_app(&peerMacAddr,
ePeerConnected,
pCsrRoamInfo->timingMeasCap,
pAdapter->sessionId, &chan_info,
pAdapter->device_mode);
/* Update tdls module about connection event */
hdd_notify_sta_connect(pAdapter->sessionId,
pCsrRoamInfo->tdls_chan_swit_prohibited,
pCsrRoamInfo->tdls_prohibited,
pAdapter->hdd_vdev);
wlan_hdd_tdls_notify_connect(pAdapter, pCsrRoamInfo);
#ifdef MSM_PLATFORM
#if defined(CONFIG_ICNSS) || defined(CONFIG_CNSS)
/* 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;
cdp_get_intra_bss_fwd_pkts_count(
cds_get_context(QDF_MODULE_ID_SOC), pAdapter->sessionId,
&pAdapter->prev_fwd_tx_packets,
&pAdapter->prev_fwd_rx_packets);
spin_unlock_bh(&pHddCtx->bus_bw_lock);
hdd_bus_bw_compute_timer_start(pHddCtx);
#endif
#endif
} else if (eConnectionState_IbssConnected == /* IBss Associated */
pHddStaCtx->conn_info.connState) {
policy_mgr_update_connection_info(pHddCtx->hdd_psoc,
pAdapter->sessionId);
memcpy(wrqu.ap_addr.sa_data, pHddStaCtx->conn_info.bssId.bytes,
ETH_ALEN);
hdd_info("wlan: new IBSS connection to " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes));
ret = hdd_objmgr_add_peer_object(pAdapter->hdd_vdev,
QDF_IBSS_MODE,
pCsrRoamInfo->bssid.bytes,
false);
if (ret)
hdd_err("Peer object "MAC_ADDRESS_STR" add fails!",
MAC_ADDR_ARRAY(pCsrRoamInfo->bssid.bytes));
ret = hdd_objmgr_set_peer_mlme_state(pAdapter->hdd_vdev,
WLAN_ASSOC_STATE);
if (ret)
hdd_err("Peer object %pM fail to set associated state",
peerMacAddr.bytes);
} else { /* Not Associated */
hdd_info("wlan: disconnected");
memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
policy_mgr_decr_session_set_pcl(pHddCtx->hdd_psoc,
pAdapter->device_mode, pAdapter->sessionId);
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(pHddCtx, true);
#endif
if ((pAdapter->device_mode == QDF_STA_MODE) ||
(pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) {
qdf_copy_macaddr(&peerMacAddr,
&pHddStaCtx->conn_info.bssId);
/* send peer status indication to oem app */
hdd_send_peer_status_ind_to_app(&peerMacAddr,
ePeerDisconnected, 0,
pAdapter->sessionId,
NULL,
pAdapter->device_mode);
}
ret = hdd_objmgr_remove_peer_object(pAdapter->hdd_vdev,
peerMacAddr.bytes);
if (ret)
hdd_err("Peer obj "MAC_ADDRESS_STR" delete fails",
MAC_ADDR_ARRAY(peerMacAddr.bytes));
hdd_lpass_notify_disconnect(pAdapter);
/* Update tdls module about the disconnection event */
hdd_notify_sta_disconnect(pAdapter->sessionId,
false,
pAdapter->hdd_vdev);
wlan_hdd_tdls_notify_disconnect(pAdapter, false);
#ifdef MSM_PLATFORM
/* 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;
spin_unlock_bh(&pHddCtx->bus_bw_lock);
hdd_bus_bw_compute_timer_try_stop(pHddCtx);
#endif
}
hdd_ipa_set_tx_flow_info();
/* Send SCC/MCC Switching event to IPA */
hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode);
msg = NULL;
/* During the WLAN uninitialization,supplicant is stopped before the
* driver so not sending the status of the connection to supplicant
*/
if (cds_is_load_or_unload_in_progress()) {
wireless_send_event(dev, we_event, &wrqu, msg);
#ifdef FEATURE_WLAN_ESE
if (eConnectionState_Associated ==
pHddStaCtx->conn_info.connState) {
if ((pRoamProfile->AuthType.authType[0] ==
eCSR_AUTH_TYPE_CCKM_RSN) ||
(pRoamProfile->AuthType.authType[0] ==
eCSR_AUTH_TYPE_CCKM_WPA))
hdd_send_new_ap_channel_info(dev, pAdapter,
pCsrRoamInfo);
}
#endif
}
}
/**
* hdd_conn_remove_connect_info() - remove connection info
* @pHddStaCtx: pointer to global HDD station context
* @pCsrRoamInfo: pointer to roam info
*
* Return: none
*/
static void hdd_conn_remove_connect_info(hdd_station_ctx_t *pHddStaCtx)
{
/* Remove staId, bssId and peerMacAddress */
pHddStaCtx->conn_info.staId[0] = HDD_WLAN_INVALID_STA_ID;
qdf_mem_zero(&pHddStaCtx->conn_info.bssId, QDF_MAC_ADDR_SIZE);
qdf_mem_zero(&pHddStaCtx->conn_info.peerMacAddress[0],
QDF_MAC_ADDR_SIZE);
/* 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;
qdf_mem_zero(&pHddStaCtx->conn_info.Keys, sizeof(tCsrKeys));
qdf_mem_zero(&pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey));
pHddStaCtx->conn_info.proxyARPService = 0;
qdf_mem_zero(&pHddStaCtx->conn_info.SSID, sizeof(tCsrSSIDInfo));
}
/**
* hdd_roam_deregister_sta() - deregister station
* @pAdapter: pointer to adapter
* @staId: station identifier
*
* Return: QDF_STATUS enumeration
*/
QDF_STATUS hdd_roam_deregister_sta(hdd_adapter_t *adapter, uint8_t staid)
{
QDF_STATUS qdf_status;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
int ret = 0;
uint8_t *peer_mac = NULL;
struct qdf_mac_addr broadcastMacAddr =
QDF_MAC_ADDR_BROADCAST_INITIALIZER;
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.
*/
}
qdf_status = cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC),
(struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX),
staid);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("cdp_clear_peer() failed for staid %d. Status(%d) [0x%08X]",
staid, qdf_status, qdf_status);
}
if (adapter->device_mode == QDF_STA_MODE) {
peer_mac = pHddStaCtx->conn_info.bssId.bytes;
} else if (adapter->device_mode == QDF_IBSS_MODE) {
if (pHddStaCtx->broadcast_staid == staid)
peer_mac = broadcastMacAddr.bytes;
else
peer_mac = pHddStaCtx->conn_info.
peerMacAddress[staid].bytes;
}
ret = hdd_objmgr_remove_peer_object(adapter->hdd_vdev, peer_mac);
if (ret) {
hdd_err("Peer obj %pM delete fails", peer_mac);
return QDF_STATUS_E_FAILURE;
}
return qdf_status;
}
/**
* 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;
hdd_info("WIFI DATA LOGGER");
hdd_info("channel: %d",
hdd_sta_ctx->conn_info.freq);
hdd_info("dot11mode: %d",
hdd_sta_ctx->conn_info.dot11Mode);
hdd_info("AKM: %d",
hdd_sta_ctx->conn_info.last_auth_type);
hdd_info("ssid: %.*s",
hdd_sta_ctx->conn_info.last_ssid.SSID.length,
hdd_sta_ctx->conn_info.last_ssid.SSID.ssId);
hdd_info("roam count: %d",
hdd_sta_ctx->conn_info.roam_count);
hdd_info("ant_info: %d",
hdd_sta_ctx->conn_info.txrate.nss);
hdd_info("datarate legacy %d",
hdd_sta_ctx->conn_info.txrate.legacy);
hdd_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;
hdd_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;
hdd_info("vht caps: %x", *cap_info);
}
if (hdd_sta_ctx->conn_info.conn_flag.hs20_present)
hdd_info("hs20 info: %x",
hdd_sta_ctx->conn_info.hs20vendor_ie.release_num);
hdd_info("signal: %d",
hdd_sta_ctx->conn_info.signal);
hdd_info("noise: %d",
hdd_sta_ctx->conn_info.noise);
}
/**
* hdd_dis_connect_handler() - disconnect event handler
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam identifier
* @roamStatus: roam status
* @roamResult: roam result
*
* This function handles disconnect event:
* 1. Disable transmit queues;
* 2. Clean up internal connection states and data structures;
* 3. Send disconnect indication to supplicant.
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
QDF_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);
uint8_t sta_id;
bool sendDisconInd = true;
if (dev == NULL) {
hdd_err("net_dev is released return");
return QDF_STATUS_E_FAILURE;
}
/* notify apps that we can't pass traffic anymore */
hdd_debug("Disabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
if (hdd_ipa_is_enabled(pHddCtx))
hdd_ipa_wlan_evt(pAdapter, pHddStaCtx->conn_info.staId[0],
HDD_IPA_STA_DISCONNECT,
pHddStaCtx->conn_info.bssId.bytes);
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(pHddCtx, true);
#endif
DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD,
pAdapter->sessionId,
QDF_TRACE_DEFAULT_PDEV_ID,
QDF_PROTO_TYPE_MGMT, QDF_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 disconnect handler call
* to cfg80211_disconnected.
*/
if ((eConnectionState_Disconnecting ==
pHddStaCtx->conn_info.connState) ||
(eConnectionState_NotConnected ==
pHddStaCtx->conn_info.connState)) {
hdd_debug("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_conn_set_connection_state(pAdapter,
eConnectionState_Disconnecting);
}
hdd_clear_roam_profile_ie(pAdapter);
hdd_wmm_init(pAdapter);
hdd_debug("Invoking packetdump deregistration API");
wlan_deregister_txrx_packetdump();
/* indicate 'disconnect' status to wpa_supplicant... */
hdd_send_association_event(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
);
}
hdd_info("sent disconnected event to nl80211, reason code %d",
(eCSR_ROAM_LOSTLINK == roamStatus) ?
pRoamInfo->reasonCode :
WLAN_REASON_UNSPECIFIED);
}
/*
* During the WLAN uninitialization,supplicant is stopped
* before the driver so not sending the status of the
* connection to supplicant.
*/
if (cds_is_load_or_unload_in_progress()) {
#ifdef WLAN_FEATURE_P2P_DEBUG
if (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) {
if (global_p2p_connection_status ==
P2P_CLIENT_CONNECTED_STATE_1) {
global_p2p_connection_status =
P2P_CLIENT_DISCONNECTED_STATE;
hdd_debug("[P2P State] 8 way Handshake completed and moved to disconnected state");
} else if (global_p2p_connection_status ==
P2P_CLIENT_COMPLETED_STATE) {
global_p2p_connection_status =
P2P_NOT_ACTIVE;
hdd_debug("[P2P State] P2P Client is removed and moved to inactive state");
}
}
#endif
}
}
hdd_wmm_adapter_clear(pAdapter);
sme_ft_reset(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId);
if (hdd_remove_beacon_filter(pAdapter) != 0)
hdd_err("hdd_remove_beacon_filter() failed");
if (eCSR_ROAM_IBSS_LEAVE == roamStatus) {
uint8_t i;
sta_id = pHddStaCtx->broadcast_staid;
vstatus = hdd_roam_deregister_sta(pAdapter, sta_id);
if (!QDF_IS_STATUS_SUCCESS(vstatus)) {
hdd_err("hdd_roam_deregister_sta() failed for staID %d Status: %d [0x%x]",
sta_id, status, status);
status = QDF_STATUS_E_FAILURE;
}
pHddCtx->sta_to_adapter[sta_id] = NULL;
/* Clear all the peer sta register with TL. */
for (i = 0; i < MAX_PEERS; i++) {
if (HDD_WLAN_INVALID_STA_ID ==
pHddStaCtx->conn_info.staId[i])
continue;
sta_id = pHddStaCtx->conn_info.staId[i];
hdd_debug("Deregister StaID %d", sta_id);
vstatus = hdd_roam_deregister_sta(pAdapter, sta_id);
if (!QDF_IS_STATUS_SUCCESS(vstatus)) {
hdd_err("hdd_roam_deregister_sta() failed to for staID %d Status: %d [0x%x]",
sta_id, status, status);
status = QDF_STATUS_E_FAILURE;
}
/* set the staid and peer mac as 0, all other
* reset are done in hdd_connRemoveConnectInfo.
*/
pHddStaCtx->conn_info.staId[i] =
HDD_WLAN_INVALID_STA_ID;
qdf_mem_zero(&pHddStaCtx->conn_info.peerMacAddress[i],
sizeof(struct qdf_mac_addr));
if (sta_id < (WLAN_MAX_STA_COUNT + 3))
pHddCtx->sta_to_adapter[sta_id] = NULL;
}
} else {
sta_id = pHddStaCtx->conn_info.staId[0];
hdd_debug("roamResult: %d", roamResult);
/* clear scan cache for Link Lost */
if (eCSR_ROAM_RESULT_DEAUTH_IND == roamResult ||
eCSR_ROAM_RESULT_DISASSOC_IND == roamResult ||
eCSR_ROAM_LOSTLINK == roamStatus) {
wlan_hdd_cfg80211_update_bss_list(pAdapter,
pHddStaCtx->conn_info.bssId.bytes);
sme_remove_bssid_from_scan_list(pHddCtx->hHal,
pHddStaCtx->conn_info.bssId.bytes);
}
pHddCtx->sta_to_adapter[sta_id] = NULL;
}
/* Clear saved connection information in HDD */
hdd_conn_remove_connect_info(pHddStaCtx);
hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected);
pmo_ucfg_flush_gtk_offload_req(pAdapter->hdd_vdev);
#ifdef FEATURE_WLAN_TDLS
if (eCSR_ROAM_IBSS_LEAVE != roamStatus)
wlan_hdd_tdls_disconnection_callback(pAdapter);
#endif
if ((QDF_STA_MODE == pAdapter->device_mode) ||
(QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) {
sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX
(pAdapter),
pAdapter->sessionId);
}
wlan_hdd_clear_link_layer_stats(pAdapter);
/* Unblock anyone waiting for disconnect to complete */
complete(&pAdapter->disconnect_comp_var);
hdd_print_bss_info(pHddStaCtx);
return status;
}
/**
* hdd_set_peer_authorized_event() - set peer_authorized_event
* @vdev_id: vdevid
*
* Return: None
*/
static void hdd_set_peer_authorized_event(uint32_t vdev_id)
{
hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
hdd_adapter_t *adapter = NULL;
adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
if (adapter == NULL) {
hdd_err("Invalid vdev_id");
return;
}
complete(&adapter->sta_authorized_event);
}
/**
* hdd_change_peer_state() - change peer state
* @pAdapter: HDD adapter
* @sta_state: peer state
* @roam_synch_in_progress: roam synch in progress
*
* Return: QDF status
*/
QDF_STATUS hdd_change_peer_state(hdd_adapter_t *pAdapter,
uint8_t sta_id,
enum ol_txrx_peer_state sta_state,
bool roam_synch_in_progress)
{
QDF_STATUS err;
uint8_t *peer_mac_addr;
void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
void *peer;
if (!pdev) {
hdd_err("Failed to get txrx context");
return QDF_STATUS_E_FAULT;
}
if (sta_id >= WLAN_MAX_STA_COUNT) {
hdd_err("Invalid sta id: %d", sta_id);
return QDF_STATUS_E_INVAL;
}
peer = cdp_peer_find_by_local_id(soc,
(struct cdp_pdev *)pdev, sta_id);
if (!peer)
return QDF_STATUS_E_FAULT;
peer_mac_addr = cdp_peer_get_peer_mac_addr(soc, peer);
if (peer_mac_addr == NULL) {
hdd_err("peer mac addr is NULL");
return QDF_STATUS_E_FAULT;
}
err = cdp_peer_state_update(soc, pdev, peer_mac_addr, sta_state);
if (err != QDF_STATUS_SUCCESS) {
hdd_err("peer state update failed");
return QDF_STATUS_E_FAULT;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (roam_synch_in_progress)
return QDF_STATUS_SUCCESS;
#endif
if (sta_state == OL_TXRX_PEER_STATE_AUTH) {
#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
/* make sure event is reset */
INIT_COMPLETION(pAdapter->sta_authorized_event);
#endif
err = sme_set_peer_authorized(peer_mac_addr,
hdd_set_peer_authorized_event,
pAdapter->sessionId);
if (err != QDF_STATUS_SUCCESS) {
hdd_err("Failed to set the peer state to authorized");
return QDF_STATUS_E_FAULT;
}
if (pAdapter->device_mode == QDF_STA_MODE ||
pAdapter->device_mode == QDF_P2P_CLIENT_MODE) {
#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2)
void *vdev;
unsigned long rc;
/* wait for event from firmware to set the event */
rc = wait_for_completion_timeout(
&pAdapter->sta_authorized_event,
msecs_to_jiffies(HDD_PEER_AUTHORIZE_WAIT));
if (!rc)
hdd_debug("timeout waiting for sta_authorized_event");
vdev = (void *)cdp_peer_get_vdev(soc, peer);
cdp_fc_vdev_unpause(soc, (struct cdp_vdev *)vdev,
OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED);
#endif
}
}
return QDF_STATUS_SUCCESS;
}
/**
* hdd_update_dp_vdev_flags() - update datapath vdev flags
* @cbk_data: callback data
* @sta_id: station id
* @vdev_param: vdev parameter
* @is_link_up: link state up or down
*
* Return: QDF status
*/
QDF_STATUS hdd_update_dp_vdev_flags(void *cbk_data,
uint8_t sta_id,
uint32_t vdev_param,
bool is_link_up)
{
struct cdp_vdev *data_vdev;
QDF_STATUS status = QDF_STATUS_SUCCESS;
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
hdd_context_t *hdd_ctx;
struct wlan_objmgr_psoc **psoc;
if (!cbk_data)
return status;
psoc = cbk_data;
hdd_ctx = container_of(psoc, hdd_context_t, hdd_psoc);
if (!hdd_ctx->tdls_nap_active)
return status;
data_vdev = cdp_peer_get_vdev_by_sta_id(soc, sta_id);
if (NULL == data_vdev) {
status = QDF_STATUS_E_FAILURE;
return status;
}
cdp_txrx_set_vdev_param(soc, data_vdev, vdev_param, is_link_up);
return status;
}
/**
* hdd_roam_register_sta() - register station
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @staId: station identifier
* @pPeerMacAddress: peer MAC address
* @pBssDesc: pointer to BSS description
*
* Return: QDF_STATUS enumeration
*/
QDF_STATUS hdd_roam_register_sta(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint8_t staId,
struct qdf_mac_addr *pPeerMacAddress,
tSirBssDescription *pBssDesc)
{
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
struct ol_txrx_desc_type staDesc = { 0 };
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
struct ol_txrx_ops txrx_ops;
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (NULL == pBssDesc)
return QDF_STATUS_E_FAILURE;
/* Get the Station ID from the one saved during the association */
staDesc.sta_id = staId;
/* set the QoS field appropriately */
if (hdd_wmm_is_active(pAdapter))
staDesc.is_qos_enabled = 1;
else
staDesc.is_qos_enabled = 0;
#ifdef FEATURE_WLAN_WAPI
hdd_debug("WAPI STA Registered: %d",
pAdapter->wapi_info.fIsWapiSta);
if (pAdapter->wapi_info.fIsWapiSta)
staDesc.is_wapi_supported = 1;
else
staDesc.is_wapi_supported = 0;
#endif /* FEATURE_WLAN_WAPI */
/* Register the vdev transmit and receive functions */
qdf_mem_zero(&txrx_ops, sizeof(txrx_ops));
txrx_ops.rx.rx = hdd_rx_packet_cbk;
pAdapter->txrx_vdev = (void *)cdp_get_vdev_from_vdev_id(soc,
(struct cdp_pdev *)pdev,
pAdapter->sessionId);
if (!pAdapter->txrx_vdev) {
hdd_err("%s find vdev fail", __func__);
return QDF_STATUS_E_FAILURE;
}
txrx_ops.tx.tx = NULL;
cdp_vdev_register(soc,
(struct cdp_vdev *)pAdapter->txrx_vdev, pAdapter, &txrx_ops);
if (!txrx_ops.tx.tx) {
hdd_err("%s vdev register fail", __func__);
return QDF_STATUS_E_FAILURE;
}
pAdapter->tx_fn = txrx_ops.tx.tx;
qdf_status = cdp_peer_register(soc,
(struct cdp_pdev *)pdev, &staDesc);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("cdp_peer_register() failed Status: %d [0x%08X]",
qdf_status, qdf_status);
return qdf_status;
}
if (!pRoamInfo->fAuthRequired) {
/*
* Connections that do not need Upper layer auth, transition
* TLSHIM directly to 'Authenticated' state
*/
qdf_status =
hdd_change_peer_state(pAdapter, staDesc.sta_id,
OL_TXRX_PEER_STATE_AUTH,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
false
#endif
);
hdd_conn_set_authenticated(pAdapter, true);
hdd_objmgr_set_peer_mlme_auth_state(pAdapter->hdd_vdev, true);
} else {
hdd_debug("ULA auth StaId= %d. Changing TL state to CONNECTED at Join time",
pHddStaCtx->conn_info.staId[0]);
qdf_status =
hdd_change_peer_state(pAdapter, staDesc.sta_id,
OL_TXRX_PEER_STATE_CONN,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
false
#endif
);
hdd_conn_set_authenticated(pAdapter, false);
hdd_objmgr_set_peer_mlme_auth_state(pAdapter->hdd_vdev, false);
}
return qdf_status;
}
/**
* hdd_send_roamed_ind() - send roamed indication to cfg80211
* @dev: network device
* @bss: cfg80211 roamed bss pointer
* @req_ie: IEs used in reassociation request
* @req_ie_len: Length of the @req_ie
* @resp_ie: IEs received in successful reassociation response
* @resp_ie_len: Length of @resp_ie
*
* Return: none
*/
#if defined CFG80211_ROAMED_API_UNIFIED || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
static void hdd_send_roamed_ind(struct net_device *dev,
struct cfg80211_bss *bss, const uint8_t *req_ie,
size_t req_ie_len, const uint8_t *resp_ie,
size_t resp_ie_len)
{
struct cfg80211_roam_info info = {0};
info.bss = bss;
info.req_ie = req_ie;
info.req_ie_len = req_ie_len;
info.resp_ie = resp_ie;
info.resp_ie_len = resp_ie_len;
cfg80211_roamed(dev, &info, GFP_KERNEL);
}
#else
static inline void hdd_send_roamed_ind(struct net_device *dev,
struct cfg80211_bss *bss,
const uint8_t *req_ie, size_t req_ie_len,
const uint8_t *resp_ie,
size_t resp_ie_len)
{
cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie, resp_ie_len,
GFP_KERNEL);
}
#endif
/**
* hdd_send_re_assoc_event() - send reassoc event
* @dev: pointer to net device
* @pAdapter: pointer to adapter
* @pCsrRoamInfo: pointer to roam info
* @reqRsnIe: pointer to RSN Information element
* @reqRsnLength: length of RSN IE
*
* Return: none
*/
static void hdd_send_re_assoc_event(struct net_device *dev,
hdd_adapter_t *pAdapter, tCsrRoamInfo *pCsrRoamInfo,
uint8_t *reqRsnIe, uint32_t reqRsnLength)
{
unsigned int len = 0;
u8 *pFTAssocRsp = NULL;
uint8_t *rspRsnIe = qdf_mem_malloc(IW_GENERIC_IE_MAX);
uint8_t *assoc_req_ies = qdf_mem_malloc(IW_GENERIC_IE_MAX);
uint32_t rspRsnLength = 0;
struct ieee80211_channel *chan;
uint8_t buf_ssid_ie[2 + SIR_MAC_SSID_EID_MAX]; /* 2 bytes-EID and len */
uint8_t *buf_ptr, ssid_ie_len;
struct cfg80211_bss *bss = NULL;
uint8_t *final_req_ie = NULL;
tCsrRoamConnectedProfile roam_profile;
tHalHandle hal_handle = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
qdf_mem_zero(&roam_profile, sizeof(roam_profile));
if (!rspRsnIe) {
hdd_err("Unable to allocate RSN IE");
goto done;
}
if (!assoc_req_ies) {
hdd_err("Unable to allocate Assoc Req IE");
goto done;
}
if (pCsrRoamInfo == NULL) {
hdd_err("Invalid CSR roam info");
goto done;
}
if (pCsrRoamInfo->nAssocRspLength == 0) {
hdd_err("Assoc rsp length is 0");
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;
hdd_debug("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.
*/
if (!hdd_is_roam_sync_in_progress(pCsrRoamInfo))
policy_mgr_decr_session_set_pcl(hdd_ctx->hdd_psoc,
pAdapter->device_mode, pAdapter->sessionId);
/* Send the Assoc Resp, the supplicant needs this for initial Auth */
len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET;
rspRsnLength = len;
qdf_mem_copy(rspRsnIe, pFTAssocRsp, len);
qdf_mem_zero(rspRsnIe + len, IW_GENERIC_IE_MAX - len);
chan = ieee80211_get_channel(pAdapter->wdev.wiphy,
(int)pCsrRoamInfo->pBssDesc->channelId);
sme_roam_get_connect_profile(hal_handle, pAdapter->sessionId,
&roam_profile);
bss = hdd_cfg80211_get_bss(pAdapter->wdev.wiphy,
chan, pCsrRoamInfo->bssid.bytes,
&roam_profile.SSID.ssId[0],
roam_profile.SSID.length);
if (bss == NULL)
hdd_warn("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++;
qdf_mem_copy(buf_ptr, &roam_profile.SSID.ssId[0],
roam_profile.SSID.length);
ssid_ie_len = 2 + roam_profile.SSID.length;
hdd_debug("SSIDIE:");
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
buf_ssid_ie, ssid_ie_len);
final_req_ie = qdf_mem_malloc(IW_GENERIC_IE_MAX);
if (final_req_ie == NULL) {
if (bss)
cfg80211_put_bss(pAdapter->wdev.wiphy, bss);
goto done;
}
buf_ptr = final_req_ie;
qdf_mem_copy(buf_ptr, buf_ssid_ie, ssid_ie_len);
buf_ptr += ssid_ie_len;
qdf_mem_copy(buf_ptr, reqRsnIe, reqRsnLength);
qdf_mem_copy(rspRsnIe, pFTAssocRsp, len);
qdf_mem_zero(final_req_ie + (ssid_ie_len + reqRsnLength),
IW_GENERIC_IE_MAX - (ssid_ie_len + reqRsnLength));
hdd_debug("Req RSN IE:");
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
final_req_ie, (ssid_ie_len + reqRsnLength));
hdd_send_roamed_ind(dev, bss, final_req_ie,
(ssid_ie_len + reqRsnLength), rspRsnIe,
rspRsnLength);
qdf_mem_copy(assoc_req_ies,
(u8 *)pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength,
pCsrRoamInfo->nAssocReqLength);
hdd_debug("ReAssoc Req IE dump");
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
assoc_req_ies, pCsrRoamInfo->nAssocReqLength);
wlan_hdd_send_roam_auth_event(pAdapter, pCsrRoamInfo->bssid.bytes,
assoc_req_ies, pCsrRoamInfo->nAssocReqLength,
rspRsnIe, rspRsnLength,
pCsrRoamInfo);
done:
sme_roam_free_connect_profile(&roam_profile);
if (final_req_ie)
qdf_mem_free(final_req_ie);
qdf_mem_free(rspRsnIe);
qdf_mem_free(assoc_req_ies);
}
/**
* hdd_is_roam_sync_in_progress()- Check if roam offloaded
* @roaminfo - Roaming Information
*
* Return: roam sync status if roaming offloaded else false
*/
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
bool hdd_is_roam_sync_in_progress(tCsrRoamInfo *roaminfo)
{
if (roaminfo)
return roaminfo->roamSynchInProgress;
else
return false;
}
#endif
/**
* hdd_get_ibss_peer_staid() - get sta id for IBSS peer
* @hddstactx: pointer to HDD sta context
* @roaminfo: pointer to roaminfo structure
*
* This function returns staid for IBSS peer. If peer is broadcast
* MAC address return self staid(0) else find the peer sta id of
* the peer.
*
* Return: sta_id (HDD_WLAN_INVALID_STA_ID if peer not found).
*/
static uint8_t hdd_get_ibss_peer_staid(hdd_station_ctx_t *hddstactx,
tCsrRoamInfo *roaminfo)
{
uint8_t staid = HDD_WLAN_INVALID_STA_ID;
QDF_STATUS status;
if (qdf_is_macaddr_broadcast(&roaminfo->peerMac)) {
staid = 0;
} else {
status = hdd_get_peer_sta_id(hddstactx,
&roaminfo->peerMac, &staid);
if (status != QDF_STATUS_SUCCESS) {
hdd_err("Unable to find staid for " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(roaminfo->peerMac.bytes));
}
}
return staid;
}
/**
* 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)
{
QDF_STATUS status;
uint32_t timeout;
uint8_t staid = HDD_WLAN_INVALID_STA_ID;
hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
timeout = hddstactx->hdd_ReassocScenario ?
AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE :
hdd_ctx->config->auto_bmps_timer_val * 1000;
if (QDF_IBSS_MODE == adapter->device_mode)
staid = hdd_get_ibss_peer_staid(hddstactx, roaminfo);
else
staid = hddstactx->conn_info.staId[0];
hdd_debug("Changing Peer state to AUTHENTICATED for StaId = %d", staid);
/* Connections that do not need Upper layer authentication,
* transition TL to 'Authenticated' state after the keys are set
*/
status = hdd_change_peer_state(adapter, staid, OL_TXRX_PEER_STATE_AUTH,
hdd_is_roam_sync_in_progress(roaminfo));
hdd_conn_set_authenticated(adapter, true);
hdd_objmgr_set_peer_mlme_auth_state(adapter->hdd_vdev, true);
if ((QDF_STA_MODE == adapter->device_mode) ||
(QDF_P2P_CLIENT_MODE == adapter->device_mode)) {
sme_ps_enable_auto_ps_timer(
WLAN_HDD_GET_HAL_CTX(adapter),
adapter->sessionId,
timeout);
}
return qdf_status_to_os_return(status);
}
/**
* hdd_is_key_install_required_for_ibss() - check encryption type to identify
* if key installation is required
* @encr_type: encryption type
*
* Return: true if key installation is required and false otherwise.
*/
static inline bool hdd_is_key_install_required_for_ibss(
eCsrEncryptionType encr_type)
{
if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == encr_type ||
eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == encr_type ||
eCSR_ENCRYPT_TYPE_TKIP == encr_type ||
eCSR_ENCRYPT_TYPE_AES_GCMP == encr_type ||
eCSR_ENCRYPT_TYPE_AES_GCMP_256 == encr_type ||
eCSR_ENCRYPT_TYPE_AES == encr_type)
return true;
else
return false;
}
/**
* hdd_change_peer_state_after_set_key() - change the peer state on set key
* complete
* @adapter: pointer to HDD adapter
* @roaminfo: pointer to roam info
* @roam_result: roam result
*
* Peer state will be OL_TXRX_PEER_STATE_CONN until set key is complete.
* This function checks for the successful set key completion and update
* the peer state to OL_TXRX_PEER_STATE_AUTH.
*
* Return: None
*/
static void hdd_change_peer_state_after_set_key(hdd_adapter_t *adapter,
tCsrRoamInfo *roaminfo, eCsrRoamResult roam_result)
{
hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
eCsrEncryptionType encr_type = hdd_sta_ctx->conn_info.ucEncryptionType;
/*
* If the security mode is one of the following, IBSS peer will be
* waiting in CONN state and we will move the peer state to AUTH
* here. For non-secure connection, no need to wait for set-key complete
* peer will be moved to AUTH in hdd_roam_register_sta.
*/
if (QDF_IBSS_MODE == adapter->device_mode) {
if (hdd_is_key_install_required_for_ibss(encr_type))
hdd_change_sta_state_authenticated(adapter, roaminfo);
return;
}
if (eCSR_ROAM_RESULT_AUTHENTICATED == roam_result) {
hdd_sta_ctx->conn_info.gtk_installed = true;
/*
* PTK exchange happens in preauthentication itself if key_mgmt
* is FT-PSK, ptk_installed was false as there is no set PTK
* after roaming. STA TL state moves to authenticated only if
* ptk_installed is true. So, make ptk_installed to true in
* case of 11R roaming.
*/
if (sme_neighbor_roam_is11r_assoc(WLAN_HDD_GET_HAL_CTX(adapter),
adapter->sessionId))
hdd_sta_ctx->conn_info.ptk_installed = true;
} else {
hdd_sta_ctx->conn_info.ptk_installed = true;
}
/* In WPA case move STA to authenticated when ptk is installed. Earlier
* in WEP case STA was moved to AUTHENTICATED prior to setting the
* unicast key and it was resulting in sending few un-encrypted packet.
* Now in WEP case STA state will be moved to AUTHENTICATED after we
* set the unicast and broadcast key.
*/
if ((encr_type == eCSR_ENCRYPT_TYPE_WEP40) ||
(encr_type == eCSR_ENCRYPT_TYPE_WEP104) ||
(encr_type == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) ||
(encr_type == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) {
if (hdd_sta_ctx->conn_info.gtk_installed &&
hdd_sta_ctx->conn_info.ptk_installed)
hdd_change_sta_state_authenticated(adapter, roaminfo);
} else if (hdd_sta_ctx->conn_info.ptk_installed) {
hdd_change_sta_state_authenticated(adapter, roaminfo);
}
if (hdd_sta_ctx->conn_info.gtk_installed &&
hdd_sta_ctx->conn_info.ptk_installed) {
hdd_sta_ctx->conn_info.gtk_installed = false;
hdd_sta_ctx->conn_info.ptk_installed = false;
}
hdd_sta_ctx->roam_info.roamingState = HDD_ROAM_STATE_NONE;
return;
}
/**
* hdd_roam_set_key_complete_handler() - Update the security parameters
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS hdd_roam_set_key_complete_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
eCsrEncryptionType connectedCipherAlgo;
bool fConnected = false;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
ENTER();
if (NULL == pRoamInfo) {
hdd_err("pRoamInfo is NULL");
return QDF_STATUS_E_FAILURE;
}
/*
* if (WPA), tell TL to go to 'authenticated' after the keys are set.
* then go to 'authenticated'. For all other authentication types
* (those that do not require upper layer authentication) we can put TL
* directly into 'authenticated' state.
*/
hdd_info("Set Key completion roamStatus =%d roamResult=%d "
MAC_ADDRESS_STR, roamStatus, roamResult,
MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes));
fConnected = hdd_conn_get_connected_cipher_algo(pHddStaCtx,
&connectedCipherAlgo);
if (fConnected) {
hdd_change_peer_state_after_set_key(pAdapter, pRoamInfo,
roamResult);
} else {
/*
* possible disassoc after issuing set key and waiting
* set key complete.
*/
pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE;
}
EXIT();
return QDF_STATUS_SUCCESS;
}
/**
* hdd_perform_roam_set_key_complete() - perform set key complete
* @pAdapter: pointer to adapter
*
* Return: none
*/
void hdd_perform_roam_set_key_complete(hdd_adapter_t *pAdapter)
{
QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
tCsrRoamInfo roamInfo;
roamInfo.fAuthRequired = false;
qdf_mem_copy(roamInfo.bssid.bytes,
pHddStaCtx->roam_info.bssid, QDF_MAC_ADDR_SIZE);
qdf_mem_copy(roamInfo.peerMac.bytes,
pHddStaCtx->roam_info.peerMac, QDF_MAC_ADDR_SIZE);
qdf_ret_status =
hdd_roam_set_key_complete_handler(pAdapter,
&roamInfo,
pHddStaCtx->roam_info.roamId,
pHddStaCtx->roam_info.roamStatus,
eCSR_ROAM_RESULT_AUTHENTICATED);
if (qdf_ret_status != QDF_STATUS_SUCCESS)
hdd_err("Set Key complete failure");
pHddStaCtx->roam_info.deferKeyComplete = false;
}
#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
void hdd_clear_fils_connection_info(hdd_adapter_t *adapter)
{
hdd_wext_state_t *wext_state;
if ((adapter->device_mode == QDF_SAP_MODE) ||
(adapter->device_mode == QDF_P2P_GO_MODE))
return;
wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
if (wext_state->roamProfile.fils_con_info) {
qdf_mem_free(wext_state->roamProfile.fils_con_info);
wext_state->roamProfile.fils_con_info = NULL;
}
}
#endif
/**
* hdd_association_completion_handler() - association completion handler
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t 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);
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
uint8_t reqRsnIe[DOT11F_IE_RSN_MAX_LEN];
uint32_t reqRsnLength = DOT11F_IE_RSN_MAX_LEN, ie_len;
int ft_carrier_on = false;
bool hddDisconInProgress = false;
unsigned long rc;
tSirResultCodes timeout_reason = 0;
bool ok;
if (!pHddCtx) {
hdd_err("HDD context is NULL");
return QDF_STATUS_E_FAILURE;
}
/* validate config */
if (!pHddCtx->config) {
hdd_err("config is NULL");
return QDF_STATUS_E_NULL_VALUE;
}
/* 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))) {
hdd_info("hddDisconInProgress state=%d, result=%d, status=%d",
pHddStaCtx->conn_info.connState,
roamResult, roamStatus);
hddDisconInProgress = true;
}
if (eCSR_ROAM_RESULT_ASSOCIATED == roamResult) {
if (NULL == pRoamInfo) {
hdd_err("pRoamInfo is NULL");
return QDF_STATUS_E_FAILURE;
}
if (!hddDisconInProgress) {
hdd_conn_set_connection_state(pAdapter,
eConnectionState_Associated);
}
/* Save the connection info from CSR... */
hdd_conn_save_connect_info(pAdapter, pRoamInfo,
eCSR_BSS_TYPE_INFRASTRUCTURE);
if (hdd_add_beacon_filter(pAdapter) != 0)
hdd_err("hdd_add_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 */
hdd_debug("bss_descr[%d] devicemode[%d]", !!pRoamInfo->pBssDesc,
pAdapter->device_mode);
if ((QDF_STA_MODE == pAdapter->device_mode) &&
pRoamInfo->pBssDesc) {
ie_len = GET_IE_LEN_IN_BSS(pRoamInfo->pBssDesc->length);
pHddStaCtx->ap_supports_immediate_power_save =
wlan_hdd_is_ap_supports_immediate_power_save(
(uint8_t *) pRoamInfo->pBssDesc->ieFields,
ie_len);
hdd_debug("ap_supports_immediate_power_save flag [%d]",
pHddStaCtx->ap_supports_immediate_power_save);
}
/* Indicate 'connect' status to user space */
hdd_send_association_event(dev, pRoamInfo);
if (policy_mgr_is_mcc_in_24G(pHddCtx->hdd_psoc)) {
if (pHddCtx->miracast_value)
wlan_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 (pHddStaCtx->ft_carrier_on == false) {
/*
* 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)
hdd_warn("Warning:ASSOC_LINKUP_TIMEOUT");
/*
* Disable Linkup Event Servicing - no more service
* required from the net device notifier call.
*/
pAdapter->isLinkUpSvcNeeded = false;
} else {
pHddStaCtx->ft_carrier_on = false;
ft_carrier_on = true;
}
if ((WLAN_MAX_STA_COUNT + 3) > pRoamInfo->staId)
pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter;
else
hdd_err("Wrong Staid: %d", pRoamInfo->staId);
pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter;
if (hdd_ipa_is_enabled(pHddCtx))
hdd_ipa_wlan_evt(pAdapter, pRoamInfo->staId,
HDD_IPA_STA_CONNECT,
pRoamInfo->bssid.bytes);
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(pHddCtx, false);
#endif
hdd_debug("check if STA chan ok for DNBS");
if (policy_mgr_is_chan_ok_for_dnbs(pHddCtx->hdd_psoc,
pHddStaCtx->conn_info.operationChannel,
&ok)) {
hdd_err("Unable to check DNBS eligibility for chan:%d",
pHddStaCtx->conn_info.operationChannel);
return QDF_STATUS_E_FAILURE;
}
if (!ok) {
hdd_err("Chan:%d not suitable for DNBS",
pHddStaCtx->conn_info.operationChannel);
wlan_hdd_netif_queue_control(pAdapter,
WLAN_NETIF_CARRIER_OFF,
WLAN_CONTROL_PATH);
if (!hddDisconInProgress) {
hdd_err("Disconnecting...");
sme_roam_disconnect(
WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
eCSR_DISCONNECT_REASON_UNSPECIFIED);
}
return QDF_STATUS_E_FAILURE;
}
hdd_debug("check for SAP restart");
policy_mgr_check_concurrent_intf_and_restart_sap(
pHddCtx->hdd_psoc);
DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD,
pAdapter->sessionId,
QDF_TRACE_DEFAULT_PDEV_ID,
QDF_PROTO_TYPE_MGMT, QDF_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;
u8 *pFTAssocRsp = NULL;
unsigned int assocRsplen = 0;
u8 *pFTAssocReq = NULL;
unsigned int assocReqlen = 0;
struct ieee80211_channel *chan;
uint8_t rspRsnIe[DOT11F_IE_RSN_MAX_LEN];
uint32_t 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) {
hdd_err("wlan: Not able to create 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.
*/
hdd_debug("Disconnecting...");
sme_roam_disconnect(
WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
eCSR_DISCONNECT_REASON_UNSPECIFIED);
}
return QDF_STATUS_E_FAILURE;
}
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;
hdd_debug("AssocRsp is now at %02x%02x",
(unsigned int)pFTAssocRsp[0],
(unsigned int)pFTAssocRsp[1]);
assocRsplen =
pRoamInfo->nAssocRspLength -
FT_ASSOC_RSP_IES_OFFSET;
} else {
hdd_debug("AssocRsp is NULL");
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;
hdd_debug("pFTAssocReq is now at %02x%02x",
(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 {
hdd_debug("AssocReq is NULL");
assocReqlen = 0;
}
if (ft_carrier_on) {
if (!hddDisconInProgress &&
pRoamInfo->pBssDesc) {
struct cfg80211_bss *roam_bss;
/*
* 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.
*/
if (!hdd_is_roam_sync_in_progress
(pRoamInfo))
policy_mgr_decr_session_set_pcl(
pHddCtx->hdd_psoc,
pAdapter->device_mode,
pAdapter->sessionId);
hdd_debug("ft_carrier_on is %d, sending roamed indication",
ft_carrier_on);
chan =
ieee80211_get_channel
(pAdapter->wdev.wiphy,
(int)pRoamInfo->pBssDesc->
channelId);
hdd_debug(
"assocReqlen %d assocRsplen %d",
assocReqlen,
assocRsplen);
hdd_debug(
"Reassoc Req IE dump");
QDF_TRACE_HEX_DUMP(
QDF_MODULE_ID_HDD,
QDF_TRACE_LEVEL_DEBUG,
pFTAssocReq,
assocReqlen);
roam_bss =
hdd_cfg80211_get_bss(
pAdapter->wdev.wiphy,
chan,
pRoamInfo->bssid.bytes,
pRoamInfo->u.
pConnectedProfile->SSID.ssId,
pRoamInfo->u.
pConnectedProfile->SSID.length);
hdd_send_roamed_ind(
dev,
roam_bss,
pFTAssocReq,
assocReqlen,
pFTAssocRsp,
assocRsplen);
wlan_hdd_send_roam_auth_event(
pAdapter,
pRoamInfo->bssid.bytes,
pFTAssocReq,
assocReqlen,
pFTAssocRsp,
assocRsplen,
pRoamInfo);
}
if (sme_get_ftptk_state
(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId)) {
sme_set_ftptk_state
(WLAN_HDD_GET_HAL_CTX
(pAdapter),
pAdapter->sessionId,
false);
pRoamInfo->fAuthRequired =
false;
qdf_mem_copy(pHddStaCtx->
roam_info.bssid,
pRoamInfo->bssid.bytes,
QDF_MAC_ADDR_SIZE);
qdf_mem_copy(pHddStaCtx->
roam_info.peerMac,
pRoamInfo->peerMac.bytes,
QDF_MAC_ADDR_SIZE);
pHddStaCtx->roam_info.roamId =
roamId;
pHddStaCtx->roam_info.
roamStatus = roamStatus;
pHddStaCtx->roam_info.
deferKeyComplete = true;
}
} else if (!hddDisconInProgress) {
hdd_debug("ft_carrier_on is %d, sending connect indication",
ft_carrier_on);
hdd_connect_result(dev,
pRoamInfo->
bssid.bytes,
pRoamInfo,
pFTAssocReq,
assocReqlen,
pFTAssocRsp,
assocRsplen,
WLAN_STATUS_SUCCESS,
GFP_KERNEL,
false,
pRoamInfo->statusCode);
}
} else {
/*
* wpa supplicant expecting WPA/RSN IE in
* connect result.
*/
csr_roam_get_wpa_rsn_req_ie(WLAN_HDD_GET_HAL_CTX
(pAdapter),
pAdapter->sessionId,
&reqRsnLength,
reqRsnIe);
csr_roam_get_wpa_rsn_rsp_ie(WLAN_HDD_GET_HAL_CTX
(pAdapter),
pAdapter->sessionId,
&rspRsnLength,
rspRsnIe);
if (!hddDisconInProgress) {
if (ft_carrier_on)
hdd_send_re_assoc_event(dev,
pAdapter,
pRoamInfo,
reqRsnIe,
reqRsnLength);
else {
hdd_debug("sending connect indication to nl80211:for bssid "
MAC_ADDRESS_STR
" result:%d and Status:%d",
MAC_ADDR_ARRAY
(pRoamInfo->bssid.bytes),
roamResult, roamStatus);
/* inform connect result to nl80211 */
hdd_connect_result(dev,
pRoamInfo->
bssid.bytes,
pRoamInfo,
reqRsnIe,
reqRsnLength,
rspRsnIe,
rspRsnLength,
WLAN_STATUS_SUCCESS,
GFP_KERNEL,
false,
pRoamInfo->statusCode);
}
}
}
if (!hddDisconInProgress) {
cfg80211_put_bss(
pHddCtx->wiphy,
bss);
/*
* Perform any WMM-related association
* processing.
*/
hdd_wmm_assoc(pAdapter, pRoamInfo,
eCSR_BSS_TYPE_INFRASTRUCTURE);
/*
* Register the Station with DP after associated
*/
qdf_status = hdd_roam_register_sta(pAdapter,
pRoamInfo,
pHddStaCtx->conn_info.staId[0],
NULL, pRoamInfo->pBssDesc);
hdd_info("Enabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
}
} else {
/*
* wpa supplicant expecting WPA/RSN IE in connect result
* in case of reassociation also need to indicate it to
* supplicant.
*/
csr_roam_get_wpa_rsn_req_ie(
WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
&reqRsnLength, reqRsnIe);
hdd_send_re_assoc_event(dev, pAdapter, pRoamInfo,
reqRsnIe, reqRsnLength);
/* Reassoc successfully */
if (pRoamInfo->fAuthRequired) {
qdf_status =
hdd_change_peer_state(pAdapter,
pHddStaCtx->conn_info.staId[0],
OL_TXRX_PEER_STATE_CONN,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
false
#endif
);
hdd_conn_set_authenticated(pAdapter, false);
hdd_objmgr_set_peer_mlme_auth_state(
pAdapter->hdd_vdev,
false);
} else {
hdd_debug("staId: %d Changing TL state to AUTHENTICATED",
pHddStaCtx->conn_info.staId[0]);
qdf_status =
hdd_change_peer_state(pAdapter,
pHddStaCtx->conn_info.staId[0],
OL_TXRX_PEER_STATE_AUTH,
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
pRoamInfo->roamSynchInProgress
#else
false
#endif
);
hdd_conn_set_authenticated(pAdapter, true);
hdd_objmgr_set_peer_mlme_auth_state(
pAdapter->hdd_vdev,
true);
}
if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
/*
* 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)
hdd_debug("LFR3:netif_tx_wake_all_queues");
#endif
hdd_info("Enabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
}
#ifdef FEATURE_WLAN_TDLS
wlan_hdd_tdls_connection_callback(pAdapter);
#endif
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("STA register with TL failed status: %d [%08X]",
qdf_status, qdf_status);
}
#ifdef WLAN_FEATURE_11W
qdf_mem_zero(&pAdapter->hdd_stats.hddPmfStats,
sizeof(pAdapter->hdd_stats.hddPmfStats));
#endif
} else {
bool connect_timeout = false;
hdd_wext_state_t *pWextState =
WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if (pRoamInfo)
hdd_err("wlan: connection failed with " MAC_ADDRESS_STR
" result: %d and Status: %d",
MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes),
roamResult, roamStatus);
else
hdd_err("wlan: connection failed with " MAC_ADDRESS_STR
" result: %d and Status: %d",
MAC_ADDR_ARRAY(pWextState->req_bssId.bytes),
roamResult, roamStatus);
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.bytes :
pWextState->req_bssId.bytes);
sme_remove_bssid_from_scan_list(pHddCtx->hHal,
pRoamInfo ?
pRoamInfo->bssid.bytes :
pWextState->req_bssId.bytes);
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) {
hdd_err("send connect failure to nl80211: for bssid "
MAC_ADDRESS_STR
" result: %d and Status: %d reasoncode: %d",
MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes),
roamResult, roamStatus,
pRoamInfo->reasonCode);
pHddStaCtx->conn_info.assoc_status_code =
pRoamInfo->statusCode;
} else {
hdd_err("connect failed: for bssid "
MAC_ADDRESS_STR
" result: %d and status: %d ",
MAC_ADDR_ARRAY(pWextState->req_bssId.bytes),
roamResult, roamStatus);
}
hdd_debug("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.bytes,
NULL, NULL, 0, NULL, 0,
WLAN_STATUS_ASSOC_DENIED_UNSPEC,
GFP_KERNEL,
connect_timeout,
pRoamInfo->statusCode);
else
hdd_connect_result(dev,
pWextState->req_bssId.bytes,
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.bytes,
NULL, 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.bytes,
NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL,
connect_timeout,
timeout_reason);
}
hdd_clear_roam_profile_ie(pAdapter);
} else if ((eCSR_ROAM_CANCELLED == roamStatus
&& !hddDisconInProgress)) {
hdd_connect_result(dev,
pWextState->req_bssId.bytes,
NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL,
connect_timeout,
timeout_reason);
}
/*
* Set connection state to eConnectionState_NotConnected only
* when CSR has completed operation - with a
* ASSOCIATION_FAILURE or eCSR_ROAM_CANCELLED status.
*/
if (((eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus) ||
(eCSR_ROAM_CANCELLED == roamStatus))
&& !hddDisconInProgress) {
hdd_conn_set_connection_state(pAdapter,
eConnectionState_NotConnected);
}
hdd_wmm_init(pAdapter);
hdd_info("Disabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
}
return QDF_STATUS_SUCCESS;
}
/**
* hdd_roam_ibss_indication_handler() - update the status of the IBSS
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* Here we update the status of the Ibss when we receive information that we
* have started/joined an ibss session.
*
* Return: none
*/
static void hdd_roam_ibss_indication_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
hdd_debug("%s: id %d, status %d, result %d",
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;
hdd_station_ctx_t *hdd_sta_ctx =
WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
struct qdf_mac_addr broadcastMacAddr =
QDF_MAC_ADDR_BROADCAST_INITIALIZER;
if (NULL == pRoamInfo) {
QDF_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_conn_set_connection_state(pAdapter,
eConnectionState_IbssDisconnected);
/* notify wmm */
hdd_wmm_connect(pAdapter, pRoamInfo,
eCSR_BSS_TYPE_IBSS);
hdd_sta_ctx->broadcast_staid = pRoamInfo->staId;
pHddCtx->sta_to_adapter[pRoamInfo->staId] =
pAdapter;
hdd_roam_register_sta(pAdapter, pRoamInfo,
pRoamInfo->staId,
&broadcastMacAddr,
pRoamInfo->pBssDesc);
if (pRoamInfo->pBssDesc) {
struct cfg80211_bss *bss;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
struct ieee80211_channel *chan;
int chan_no;
unsigned int freq;
#endif
/* we created the IBSS, notify supplicant */
hdd_info("%s: created ibss " MAC_ADDRESS_STR,
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) {
hdd_err("%s: unable to create IBSS entry",
pAdapter->dev->name);
return;
}
hdd_info("Enabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
chan_no = pRoamInfo->pBssDesc->channelId;
if (chan_no <= 14)
freq = ieee80211_channel_to_frequency(chan_no,
HDD_NL80211_BAND_2GHZ);
else
freq = ieee80211_channel_to_frequency(chan_no,
HDD_NL80211_BAND_5GHZ);
chan = ieee80211_get_channel(pAdapter->wdev.wiphy, freq);
if (chan)
cfg80211_ibss_joined(pAdapter->dev,
bss->bssid, chan,
GFP_KERNEL);
else
hdd_warn("%s: chanId: %d, can't find channel",
pAdapter->dev->name,
(int)pRoamInfo->pBssDesc->channelId);
#else
cfg80211_ibss_joined(pAdapter->dev, bss->bssid,
GFP_KERNEL);
#endif
cfg80211_put_bss(
pHddCtx->wiphy,
bss);
}
if (eCSR_ROAM_RESULT_IBSS_STARTED == roamResult) {
policy_mgr_incr_active_session(hdd_ctx->hdd_psoc,
pAdapter->device_mode, pAdapter->sessionId);
} else if (eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS == roamResult ||
eCSR_ROAM_RESULT_IBSS_COALESCED == roamResult) {
policy_mgr_update_connection_info(hdd_ctx->hdd_psoc,
pAdapter->sessionId);
}
break;
}
case eCSR_ROAM_RESULT_IBSS_START_FAILED:
{
hdd_err("%s: unable to create IBSS", pAdapter->dev->name);
break;
}
default:
hdd_err("%s: unexpected result %d",
pAdapter->dev->name, (int)roamResult);
break;
}
}
/**
* hdd_save_peer() - Save peer MAC address in adapter peer table.
* @sta_ctx: pointer to hdd station context
* @sta_id: station ID
* @peer_mac_addr: mac address of new peer
*
* This information is passed to iwconfig later. The peer that joined
* last is passed as information to iwconfig.
* Return: true if success, false otherwise
*/
bool hdd_save_peer(hdd_station_ctx_t *sta_ctx, uint8_t sta_id,
struct qdf_mac_addr *peer_mac_addr)
{
int idx;
for (idx = 0; idx < SIR_MAX_NUM_STA_IN_IBSS; idx++) {
if (HDD_WLAN_INVALID_STA_ID == sta_ctx->conn_info.staId[idx]) {
hdd_debug("adding peer: %pM, sta_id: %d, at idx: %d",
peer_mac_addr, sta_id, idx);
sta_ctx->conn_info.staId[idx] = sta_id;
qdf_copy_macaddr(
&sta_ctx->conn_info.peerMacAddress[idx],
peer_mac_addr);
return true;
}
}
return false;
}
/**
* hdd_delete_peer() - removes peer from hdd station context peer table
* @sta_ctx: pointer to hdd station context
* @sta_id: station ID
*
* Return: None
*/
void hdd_delete_peer(hdd_station_ctx_t *sta_ctx, uint8_t sta_id)
{
int i;
for (i = 0; i < SIR_MAX_NUM_STA_IN_IBSS; i++) {
if (sta_id == sta_ctx->conn_info.staId[i]) {
sta_ctx->conn_info.staId[i] = HDD_WLAN_INVALID_STA_ID;
return;
}
}
}
/**
* roam_remove_ibss_station() - Remove the IBSS peer MAC address in the adapter
* @pAdapter: pointer to adapter
* @staId: station id
*
* Return:
* true if we remove MAX_PEERS or less STA
* false otherwise.
*/
static bool roam_remove_ibss_station(hdd_adapter_t *pAdapter, uint8_t staId)
{
bool fSuccess = false;
int idx = 0;
uint8_t valid_idx = 0;
uint8_t del_idx = 0;
uint8_t empty_slots = 0;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
for (idx = 0; idx < MAX_PEERS; idx++) {
if (staId == pHddStaCtx->conn_info.staId[idx]) {
pHddStaCtx->conn_info.staId[idx] =
HDD_WLAN_INVALID_STA_ID;
qdf_zero_macaddr(&pHddStaCtx->conn_info.
peerMacAddress[idx]);
fSuccess = true;
/*
* Note the deleted Index, if its 0 we need special
* handling.
*/
del_idx = idx;
empty_slots++;
} else {
if (pHddStaCtx->conn_info.staId[idx] !=
HDD_WLAN_INVALID_STA_ID) {
valid_idx = idx;
} else {
/* Found an empty slot */
empty_slots++;
}
}
}
if (MAX_PEERS == empty_slots) {
/* Last peer departed, set the IBSS state appropriately */
hdd_conn_set_connection_state(pAdapter,
eConnectionState_IbssDisconnected);
hdd_debug("Last IBSS Peer Departed!!!");
}
/* Find next active staId, to have a valid sta trigger for TL. */
if (fSuccess == true) {
if (del_idx == 0) {
if (pHddStaCtx->conn_info.staId[valid_idx] !=
HDD_WLAN_INVALID_STA_ID) {
pHddStaCtx->conn_info.staId[0] =
pHddStaCtx->conn_info.staId[valid_idx];
qdf_copy_macaddr(&pHddStaCtx->conn_info.
peerMacAddress[0],
&pHddStaCtx->conn_info.
peerMacAddress[valid_idx]);
pHddStaCtx->conn_info.staId[valid_idx] =
HDD_WLAN_INVALID_STA_ID;
qdf_zero_macaddr(&pHddStaCtx->conn_info.
peerMacAddress[valid_idx]);
}
}
}
return fSuccess;
}
/**
* roam_ibss_connect_handler() - IBSS connection handler
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
*
* We update the status of the IBSS to connected in this function.
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS roam_ibss_connect_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo)
{
struct cfg80211_bss *bss;
/*
* Set the internal connection state to show 'IBSS Connected' (IBSS with
* a partner stations).
*/
hdd_conn_set_connection_state(pAdapter, eConnectionState_IbssConnected);
/* Save the connection info from CSR... */
hdd_conn_save_connect_info(pAdapter, pRoamInfo, eCSR_BSS_TYPE_IBSS);
/* Send the bssid address to the wext. */
hdd_send_association_event(pAdapter->dev, pRoamInfo);
/* add bss_id to cfg80211 data base */
bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, pRoamInfo);
if (NULL == bss) {
hdd_err("%s: unable to create IBSS entry",
pAdapter->dev->name);
return QDF_STATUS_E_FAILURE;
}
cfg80211_put_bss(
WLAN_HDD_GET_CTX(pAdapter)->wiphy,
bss);
return QDF_STATUS_SUCCESS;
}
/**
* hdd_roam_mic_error_indication_handler() - MIC error indication handler
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* This function indicates the Mic failure to the supplicant
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS
hdd_roam_mic_error_indication_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
if (eConnectionState_Associated == pHddStaCtx->conn_info.connState &&
TKIP_COUNTER_MEASURE_STOPED ==
pHddStaCtx->WextState.mTKIPCounterMeasures) {
struct iw_michaelmicfailure msg;
union iwreq_data wreq;
memset(&msg, '\0', sizeof(msg));
msg.src_addr.sa_family = ARPHRD_ETHER;
memcpy(msg.src_addr.sa_data,
pRoamInfo->u.pMICFailureInfo->taMacAddr,
sizeof(pRoamInfo->u.pMICFailureInfo->taMacAddr));
hdd_debug("MIC MAC " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(msg.src_addr.sa_data));
if (pRoamInfo->u.pMICFailureInfo->multicast == true)
msg.flags = IW_MICFAILURE_GROUP;
else
msg.flags = IW_MICFAILURE_PAIRWISE;
memset(&wreq, 0, sizeof(wreq));
wreq.data.length = sizeof(msg);
wireless_send_event(pAdapter->dev, IWEVMICHAELMICFAILURE, &wreq,
(char *)&msg);
/* inform mic failure to nl80211 */
cfg80211_michael_mic_failure(pAdapter->dev,
pRoamInfo->u.pMICFailureInfo->
taMacAddr,
((pRoamInfo->u.pMICFailureInfo->
multicast ==
true) ?
NL80211_KEYTYPE_GROUP :
NL80211_KEYTYPE_PAIRWISE),
pRoamInfo->u.pMICFailureInfo->
keyId,
pRoamInfo->u.pMICFailureInfo->TSC,
GFP_KERNEL);
}
return QDF_STATUS_SUCCESS;
}
/**
* roam_roam_connect_status_update_handler() - IBSS connect status update
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* The Ibss connection status is updated regularly here in this function.
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS
roam_roam_connect_status_update_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
QDF_STATUS qdf_status;
switch (roamResult) {
case eCSR_ROAM_RESULT_IBSS_NEW_PEER:
{
hdd_station_ctx_t *pHddStaCtx =
WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
struct station_info *stainfo;
eCsrEncryptionType encr_type = pHddStaCtx->ibss_enc_key.encType;
hdd_info("IBSS New Peer indication from SME "
"with peerMac " MAC_ADDRESS_STR " BSSID: "
MAC_ADDRESS_STR " and stationID= %d",
MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes),
MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes),
pRoamInfo->staId);
if (!hdd_save_peer
(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter),
pRoamInfo->staId,
&pRoamInfo->peerMac)) {
hdd_warn("Max reached: Can't register new IBSS peer");
break;
}
pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter;
if (hdd_is_key_install_required_for_ibss(encr_type))
pRoamInfo->fAuthRequired = true;
/* Register the Station with TL for the new peer. */
qdf_status = hdd_roam_register_sta(pAdapter,
pRoamInfo,
pRoamInfo->staId,
&pRoamInfo->peerMac,
pRoamInfo->pBssDesc);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("Cannot register STA with TL for IBSS. qdf_status: %d [%08X]",
qdf_status, qdf_status);
}
pHddStaCtx->ibss_sta_generation++;
stainfo = qdf_mem_malloc(sizeof(*stainfo));
if (stainfo == NULL) {
hdd_err("memory allocation for station_info failed");
return QDF_STATUS_E_NOMEM;
}
stainfo->filled = 0;
stainfo->generation = pHddStaCtx->ibss_sta_generation;
cfg80211_new_sta(pAdapter->dev,
(const u8 *)pRoamInfo->peerMac.bytes,
stainfo, GFP_KERNEL);
qdf_mem_free(stainfo);
if (hdd_is_key_install_required_for_ibss(encr_type)) {
pHddStaCtx->ibss_enc_key.keyDirection =
eSIR_TX_RX;
qdf_copy_macaddr(&pHddStaCtx->ibss_enc_key.peerMac,
&pRoamInfo->peerMac);
hdd_info("New peer joined set PTK encType=%d",
encr_type);
qdf_status =
sme_roam_set_key(WLAN_HDD_GET_HAL_CTX
(pAdapter),
pAdapter->sessionId,
&pHddStaCtx->ibss_enc_key,
&roamId);
if (QDF_STATUS_SUCCESS != qdf_status) {
hdd_err("sme_roam_set_key failed, status: %d",
qdf_status);
return QDF_STATUS_E_FAILURE;
}
}
hdd_info("Enabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
break;
}
case eCSR_ROAM_RESULT_IBSS_CONNECT:
{
roam_ibss_connect_handler(pAdapter, pRoamInfo);
break;
}
case eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED:
{
hdd_station_ctx_t *pHddStaCtx =
WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
if (!roam_remove_ibss_station(pAdapter, pRoamInfo->staId))
hdd_warn("IBSS peer departed by cannot find peer in our registration table with TL");
hdd_info("IBSS Peer Departed from SME "
"with peerMac " MAC_ADDRESS_STR " BSSID: "
MAC_ADDRESS_STR " and stationID= %d",
MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes),
MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes),
pRoamInfo->staId);
hdd_roam_deregister_sta(pAdapter, pRoamInfo->staId);
pHddCtx->sta_to_adapter[pRoamInfo->staId] = NULL;
pHddStaCtx->ibss_sta_generation++;
cfg80211_del_sta(pAdapter->dev,
(const u8 *)&pRoamInfo->peerMac.bytes,
GFP_KERNEL);
break;
}
case eCSR_ROAM_RESULT_IBSS_INACTIVE:
{
hdd_debug("Received eCSR_ROAM_RESULT_IBSS_INACTIVE from SME");
/* Stop only when we are inactive */
hdd_info("Disabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
hdd_conn_set_connection_state(pAdapter,
eConnectionState_NotConnected);
/* Send the bssid address to the wext. */
hdd_send_association_event(pAdapter->dev, pRoamInfo);
break;
}
default:
break;
}
return QDF_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_TDLS
/**
* hdd_roam_register_tdlssta() - register new TDLS station
* @pAdapter: pointer to adapter
* @peerMac: pointer to peer MAC address
* @staId: station identifier
* @ucastSig: unicast signature
* @qos: QOS capability of TDLS station/link
*
* Construct the staDesc and register with TL the new STA.
* This is called as part of ADD_STA in the TDLS setup.
*
* Return: QDF_STATUS enumeration
*/
QDF_STATUS hdd_roam_register_tdlssta(hdd_adapter_t *pAdapter,
const uint8_t *peerMac, uint16_t staId,
uint8_t ucastSig, uint8_t qos)
{
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
struct ol_txrx_desc_type staDesc = { 0 };
struct ol_txrx_ops txrx_ops;
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
/*
* TDLS sta in BSS should be set as STA type TDLS and STA MAC should
* be peer MAC, here we are working on direct Link
*/
staDesc.sta_id = staId;
/* set the QoS field appropriately .. */
staDesc.is_qos_enabled = qos;
/* Register the vdev transmit and receive functions */
qdf_mem_zero(&txrx_ops, sizeof(txrx_ops));
txrx_ops.rx.rx = hdd_rx_packet_cbk;
cdp_vdev_register(soc,
(struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc,
(struct cdp_pdev *)pdev, pAdapter->sessionId),
pAdapter, &txrx_ops);
pAdapter->tx_fn = txrx_ops.tx.tx;
/* Register the Station with TL... */
qdf_status = cdp_peer_register(soc,
(struct cdp_pdev *)pdev, &staDesc);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("cdp_peer_register() failed Status: %d [0x%08X]",
qdf_status, qdf_status);
return qdf_status;
}
return qdf_status;
}
/**
* hdd_roam_deregister_tdlssta() - deregister new TDLS station
* @pAdapter: pointer to adapter
* @staId: station identifier
*
* Return: QDF_STATUS enumeration
*/
QDF_STATUS hdd_roam_deregister_tdlssta(hdd_adapter_t *pAdapter, uint8_t staId)
{
QDF_STATUS qdf_status;
qdf_status = cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC),
(struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX),
staId);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("cdp_clear_peer() failed for staID: %d Status: %d [0x%08X]",
staId, qdf_status, qdf_status);
}
return qdf_status;
}
/**
* hdd_tdls_connection_tracker_update() - update connection tracker state
* @adapter: pointer to adapter
* @roam_info: pointer to roam info
* @hdd_tdls_ctx: tdls context
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS hdd_tdls_connection_tracker_update(hdd_adapter_t *adapter,
tCsrRoamInfo *roam_info,
tdlsCtx_t *hdd_tdls_ctx)
{
hddTdlsPeer_t *curr_peer;
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
curr_peer = wlan_hdd_tdls_find_peer(adapter,
roam_info->peerMac.bytes);
if (!curr_peer) {
hdd_err("curr_peer is null");
return QDF_STATUS_E_FAILURE;
}
if (eTDLS_LINK_CONNECTED ==
curr_peer->link_status) {
hdd_debug("Received CONNECTION_TRACKER_NOTIFICATION "
MAC_ADDRESS_STR
" staId: %d, reason: %d",
MAC_ADDR_ARRAY(roam_info->peerMac.bytes),
roam_info->staId,
roam_info->reasonCode);
if (roam_info->reasonCode ==
eWNI_TDLS_PEER_ENTER_BUF_STA ||
roam_info->reasonCode ==
eWNI_TDLS_ENTER_BT_BUSY_MODE ||
roam_info->reasonCode ==
eWMI_TDLS_SCAN_STARTED_EVENT)
hdd_ctx->enable_tdls_connection_tracker = false;
else if (roam_info->reasonCode ==
eWNI_TDLS_PEER_EXIT_BUF_STA ||
roam_info->reasonCode ==
eWNI_TDLS_EXIT_BT_BUSY_MODE ||
roam_info->reasonCode ==
eWMI_TDLS_SCAN_COMPLETED_EVENT)
hdd_ctx->enable_tdls_connection_tracker = true;
hdd_debug("hdd_ctx->enable_tdls_connection_tracker %d",
hdd_ctx->enable_tdls_connection_tracker);
} else {
hdd_debug("TDLS not connected, ignore notification, reason: %d",
roam_info->reasonCode);
}
return QDF_STATUS_SUCCESS;
}
/**
* hdd_roam_tdls_status_update_handler() - TDLS status update handler
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* HDD interface between SME and TL to ensure TDLS client registration with
* TL in case of new TDLS client is added and deregistration at the time
* TDLS client is deleted.
*
* Return: QDF_STATUS enumeration
*/
static QDF_STATUS
hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
tdlsCtx_t *pHddTdlsCtx;
tSmeTdlsPeerStateParams smeTdlsPeerStateParams;
QDF_STATUS status = QDF_STATUS_E_FAILURE;
uint8_t staIdx;
hddTdlsPeer_t *curr_peer;
uint32_t reason;
hdd_debug("hdd_tdlsStatusUpdate: %s staIdx %d " MAC_ADDRESS_STR,
roamResult ==
eCSR_ROAM_RESULT_ADD_TDLS_PEER ? "ADD_TDLS_PEER" : roamResult
==
eCSR_ROAM_RESULT_DELETE_TDLS_PEER ? "DEL_TDLS_PEER" :
roamResult ==
eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND ? "DEL_TDLS_PEER_IND"
: roamResult ==
eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND ?
"DEL_ALL_TDLS_PEER_IND" : roamResult ==
eCSR_ROAM_RESULT_UPDATE_TDLS_PEER ? "UPDATE_TDLS_PEER" :
roamResult ==
eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP ?
"LINK_ESTABLISH_REQ_RSP" : roamResult ==
eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER ? "TDLS_SHOULD_DISCOVER"
: roamResult ==
eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN ? "TDLS_SHOULD_TEARDOWN"
: roamResult ==
eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED ?
"TDLS_SHOULD_PEER_DISCONNECTED" : "UNKNOWN", pRoamInfo->staId,
MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes));
switch (roamResult) {
case eCSR_ROAM_RESULT_ADD_TDLS_PEER:
{
if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) {
hdd_err("Add Sta failed. status code: %d",
pRoamInfo->statusCode);
pAdapter->tdlsAddStaStatus = QDF_STATUS_E_FAILURE;
} else {
/*
* Check if there is available index for this new TDLS
* STA.
*/
for (staIdx = 0;
staIdx < pHddCtx->max_num_tdls_sta;
staIdx++) {
if (0 ==
pHddCtx->tdlsConnInfo[staIdx].
staId) {
pHddCtx->tdlsConnInfo[staIdx].
sessionId =
pRoamInfo->sessionId;
pHddCtx->tdlsConnInfo[staIdx].
staId = pRoamInfo->staId;
hdd_debug("TDLS: STA IDX at %d is %d "
"of mac "
MAC_ADDRESS_STR,
staIdx,
pHddCtx->
tdlsConnInfo[staIdx].
staId,
MAC_ADDR_ARRAY
(pRoamInfo->peerMac.bytes));
qdf_copy_macaddr(&pHddCtx->
tdlsConnInfo
[staIdx].
peerMac,
&pRoamInfo->
peerMac);
status = QDF_STATUS_SUCCESS;
break;
}
}
if (staIdx < pHddCtx->max_num_tdls_sta) {
if (-1 ==
wlan_hdd_tdls_set_sta_id(pAdapter,
pRoamInfo->
peerMac.bytes,
pRoamInfo->
staId)) {
hdd_err("wlan_hdd_tdls_set_sta_id() failed");
return QDF_STATUS_E_FAILURE;
}
(WLAN_HDD_GET_CTX(pAdapter))->
sta_to_adapter[pRoamInfo->staId] =
pAdapter;
/*
* store the ucast signature,
* if required for further reference.
*/
wlan_hdd_tdls_set_signature(pAdapter,
pRoamInfo->
peerMac.bytes,
pRoamInfo->
ucastSig);
} else {
status = QDF_STATUS_E_FAILURE;
hdd_debug("no available slot in conn_info. staId: %d cannot be stored",
pRoamInfo->staId);
}
pAdapter->tdlsAddStaStatus = status;
}
complete(&pAdapter->tdls_add_station_comp);
break;
}
case eCSR_ROAM_RESULT_UPDATE_TDLS_PEER:
{
if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) {
hdd_err("Add Sta failed. status code: %d",
pRoamInfo->statusCode);
pAdapter->tdlsAddStaStatus = QDF_STATUS_E_FAILURE;
} else {
pAdapter->tdlsAddStaStatus = QDF_STATUS_SUCCESS;
}
complete(&pAdapter->tdls_add_station_comp);
break;
}
case eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP:
{
if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) {
hdd_err("Link Establish Request failed. status: %d",
pRoamInfo->statusCode);
}
complete(&pAdapter->tdls_link_establish_req_comp);
break;
}
case eCSR_ROAM_RESULT_DELETE_TDLS_PEER:
{
for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta;
staIdx++) {
if ((pHddCtx->tdlsConnInfo[staIdx].sessionId ==
pRoamInfo->sessionId)
&& pRoamInfo->staId ==
pHddCtx->tdlsConnInfo[staIdx].staId) {
hdd_debug("HDD: del STA IDX = %x",
pRoamInfo->staId);
mutex_lock(&pHddCtx->tdls_lock);
curr_peer =
wlan_hdd_tdls_find_peer(pAdapter,
pRoamInfo->
peerMac.bytes);
if (NULL != curr_peer) {
hdd_debug("Current status for peer " MAC_ADDRESS_STR " is %d",
MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes),
curr_peer->link_status);
if (TDLS_IS_CONNECTED(curr_peer)) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_roam_deregister_tdlssta
(pAdapter,
pRoamInfo->staId);
wlan_hdd_tdls_decrement_peer_count
(pAdapter);
} else if (eTDLS_LINK_CONNECTING ==
curr_peer->link_status) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_roam_deregister_tdlssta
(pAdapter,
pRoamInfo->staId);
} else
mutex_unlock(&pHddCtx->tdls_lock);
} else
mutex_unlock(&pHddCtx->tdls_lock);
mutex_lock(&pHddCtx->tdls_lock);
wlan_hdd_tdls_reset_peer(pAdapter,
pRoamInfo->
peerMac.bytes);
mutex_unlock(&pHddCtx->tdls_lock);
pHddCtx->tdlsConnInfo[staIdx].staId = 0;
pHddCtx->tdlsConnInfo[staIdx].
sessionId = 255;
qdf_mem_zero(&pHddCtx->
tdlsConnInfo[staIdx].
peerMac,
QDF_MAC_ADDR_SIZE);
status = QDF_STATUS_SUCCESS;
break;
}
}
complete(&pAdapter->tdls_del_station_comp);
}
break;
case eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND:
{
hdd_debug("Sending teardown to supplicant with reason code %u",
pRoamInfo->reasonCode);
mutex_lock(&pHddCtx->tdls_lock);
curr_peer =
wlan_hdd_tdls_find_peer(pAdapter,
pRoamInfo->peerMac.bytes);
if (!curr_peer) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_debug("peer doesn't exists");
status = QDF_STATUS_SUCCESS;
break;
}
wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer,
pRoamInfo->reasonCode);
hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_BSS_DISCONNECT,
curr_peer->peerMac);
mutex_unlock(&pHddCtx->tdls_lock);
status = QDF_STATUS_SUCCESS;
break;
}
case eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND:
{
/* 0 staIdx is assigned to AP we dont want to touch that */
for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta;
staIdx++) {
if ((pHddCtx->tdlsConnInfo[staIdx].sessionId ==
pRoamInfo->sessionId)
&& pHddCtx->tdlsConnInfo[staIdx].staId) {
hdd_debug("hdd_tdlsStatusUpdate: staIdx %d "
MAC_ADDRESS_STR,
pHddCtx->tdlsConnInfo[staIdx].
staId,
MAC_ADDR_ARRAY(pHddCtx->
tdlsConnInfo
[staIdx].
peerMac.
bytes));
mutex_lock(&pHddCtx->tdls_lock);
wlan_hdd_tdls_reset_peer(pAdapter,
pHddCtx->
tdlsConnInfo
[staIdx].
peerMac.bytes);
mutex_unlock(&pHddCtx->tdls_lock);
hdd_roam_deregister_tdlssta(pAdapter,
pHddCtx->
tdlsConnInfo
[staIdx].
staId);
qdf_mem_zero(&smeTdlsPeerStateParams,
sizeof
(smeTdlsPeerStateParams));
smeTdlsPeerStateParams.vdevId =
pHddCtx->tdlsConnInfo[staIdx].
sessionId;
qdf_mem_copy(&smeTdlsPeerStateParams.
peerMacAddr,
&pHddCtx->
tdlsConnInfo[staIdx].
peerMac.bytes,
QDF_MAC_ADDR_SIZE);
smeTdlsPeerStateParams.peerState =
eSME_TDLS_PEER_STATE_TEARDOWN;
hdd_debug("calling sme_update_tdls_peer_state for staIdx %d "
MAC_ADDRESS_STR,
pHddCtx->tdlsConnInfo[staIdx].
staId,
MAC_ADDR_ARRAY(pHddCtx->
tdlsConnInfo
[staIdx].
peerMac.
bytes));
status =
sme_update_tdls_peer_state(
pHddCtx->hHal,
&smeTdlsPeerStateParams);
if (QDF_STATUS_SUCCESS != status) {
hdd_err("sme_update_tdls_peer_state failed for "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY
(pHddCtx->
tdlsConnInfo[staIdx].
peerMac.bytes));
}
wlan_hdd_tdls_decrement_peer_count
(pAdapter);
qdf_mem_zero(&pHddCtx->
tdlsConnInfo[staIdx].
peerMac,
QDF_MAC_ADDR_SIZE);
pHddCtx->tdlsConnInfo[staIdx].staId = 0;
pHddCtx->tdlsConnInfo[staIdx].
sessionId = 255;
status = QDF_STATUS_SUCCESS;
}
}
break;
}
case eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER:
{
/* ignore TDLS_SHOULD_DISCOVER if any concurrency detected */
if (!cds_check_is_tdls_allowed(pAdapter->device_mode)) {
hdd_err("TDLS not allowed, ignore SHOULD_DISCOVER");
status = QDF_STATUS_E_FAILURE;
break;
}
if (pHddCtx->tdls_nss_switch_in_progress) {
hdd_debug("TDLS antenna switch is in progress, ignore SHOULD_DISCOVER");
status = QDF_STATUS_SUCCESS;
break;
}
mutex_lock(&pHddCtx->tdls_lock);
pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
if (!pHddTdlsCtx) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_debug("TDLS ctx is null, ignore roamResult (%d)",
roamResult);
status = QDF_STATUS_E_FAILURE;
break;
}
curr_peer =
wlan_hdd_tdls_get_peer(pAdapter,
pRoamInfo->peerMac.bytes);
if (!curr_peer) {
hdd_debug("curr_peer is null");
status = QDF_STATUS_E_FAILURE;
} else {
if (eTDLS_LINK_CONNECTED ==
curr_peer->link_status) {
hdd_debug("TDLS link status is connected, ignore SHOULD_DISCOVER");
} else {
/*
* If external control is enabled then initiate
* TDLS only if forced peer is set otherwise
* ignore should Discover trigger from fw.
*/
if (pHddCtx->config->
fTDLSExternalControl
&& (false ==
curr_peer->isForcedPeer)) {
hdd_debug("TDLS ExternalControl enabled but curr_peer is not forced, ignore SHOULD_DISCOVER");
status = QDF_STATUS_SUCCESS;
break;
}
hdd_debug("initiate TDLS setup on SHOULD_DISCOVER, fTDLSExternalControl: %d, curr_peer->isForcedPeer: %d, reason: %d",
pHddCtx->config->
fTDLSExternalControl,
curr_peer->isForcedPeer,
pRoamInfo->reasonCode);
pHddTdlsCtx->curr_candidate = curr_peer;
wlan_hdd_tdls_implicit_send_discovery_request(
pHddTdlsCtx);
}
status = QDF_STATUS_SUCCESS;
}
mutex_unlock(&pHddCtx->tdls_lock);
break;
}
case eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN:
{
mutex_lock(&pHddCtx->tdls_lock);
pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
if (!pHddTdlsCtx) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_debug("TDLS ctx is null, ignore roamResult (%d)",
roamResult);
status = QDF_STATUS_E_FAILURE;
break;
}
curr_peer =
wlan_hdd_tdls_find_peer(pAdapter,
pRoamInfo->peerMac.bytes);
if (!curr_peer) {
hdd_debug("curr_peer is null");
status = QDF_STATUS_E_FAILURE;
} else {
if (eTDLS_LINK_CONNECTED ==
curr_peer->link_status) {
hdd_debug("Received SHOULD_TEARDOWN for peer "
MAC_ADDRESS_STR
" staId: %d, reason: %d",
MAC_ADDR_ARRAY(pRoamInfo->
peerMac.bytes),
pRoamInfo->staId,
pRoamInfo->reasonCode);
if (pRoamInfo->reasonCode ==
eWNI_TDLS_TEARDOWN_REASON_RSSI ||
pRoamInfo->reasonCode ==
eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE ||
pRoamInfo->reasonCode ==
eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT ||
pRoamInfo->reasonCode ==
eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE) {
reason =
eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE;
} else
reason =
eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON;
wlan_hdd_tdls_indicate_teardown
(pHddTdlsCtx->pAdapter, curr_peer,
reason);
hdd_send_wlan_tdls_teardown_event(
eTDLS_TEARDOWN_BSS_DISCONNECT,
curr_peer->peerMac);
} else {
hdd_debug("TDLS link is not connected, ignore SHOULD_TEARDOWN, reason: %d",
pRoamInfo->reasonCode);
}
status = QDF_STATUS_SUCCESS;
}
mutex_unlock(&pHddCtx->tdls_lock);
break;
}
case eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED:
{
mutex_lock(&pHddCtx->tdls_lock);
pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
if (!pHddTdlsCtx) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_debug("TDLS ctx is null, ignore roamResult (%d)",
roamResult);
status = QDF_STATUS_E_FAILURE;
break;
}
curr_peer =
wlan_hdd_tdls_find_peer(pAdapter,
pRoamInfo->peerMac.bytes);
if (!curr_peer) {
hdd_debug("curr_peer is null");
status = QDF_STATUS_E_FAILURE;
} else {
if (eTDLS_LINK_CONNECTED ==
curr_peer->link_status) {
hdd_debug("Received SHOULD_PEER_DISCONNECTED for peer "
MAC_ADDRESS_STR
" staId: %d reason: %d",
MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes),
pRoamInfo->staId,
pRoamInfo->reasonCode);
if (pRoamInfo->reasonCode ==
eWNI_TDLS_TEARDOWN_REASON_RSSI ||
pRoamInfo->reasonCode ==
eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE ||
pRoamInfo->reasonCode ==
eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT ||
pRoamInfo->reasonCode ==
eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE) {
reason =
eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE;
} else
reason =
eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON;
wlan_hdd_tdls_indicate_teardown
(pHddTdlsCtx->pAdapter, curr_peer,
reason);
hdd_send_wlan_tdls_teardown_event(
eTDLS_TEARDOWN_BSS_DISCONNECT,
curr_peer->peerMac);
} else {
hdd_debug("TDLS link is not connected, ignore SHOULD_PEER_DISCONNECTED, reason: %d",
pRoamInfo->reasonCode);
}
status = QDF_STATUS_SUCCESS;
}
mutex_unlock(&pHddCtx->tdls_lock);
break;
}
case eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION:
mutex_lock(&pHddCtx->tdls_lock);
pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
if (!pHddTdlsCtx) {
mutex_unlock(&pHddCtx->tdls_lock);
hdd_debug("TDLS ctx is null, ignore roamResult (%d)",
roamResult);
status = QDF_STATUS_E_FAILURE;
break;
}
status = hdd_tdls_connection_tracker_update(pAdapter,
pRoamInfo,
pHddTdlsCtx);
mutex_unlock(&pHddCtx->tdls_lock);
break;
default:
{
break;
}
}
return status;
}
#else
inline QDF_STATUS hdd_roam_deregister_tdlssta(hdd_adapter_t *pAdapter,
uint8_t staId)
{
return QDF_STATUS_SUCCESS;
}
static inline QDF_STATUS
hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo,
uint32_t roamId,
eRoamCmdStatus roamStatus,
eCsrRoamResult roamResult)
{
return QDF_STATUS_SUCCESS;
}
#endif
#ifdef WLAN_FEATURE_11W
/**
* hdd_indicate_unprot_mgmt_frame() - indicate unprotected management frame
* @pAdapter: pointer to the adapter
* @nFrameLength: Length of the unprotected frame being passed
* @pbFrames: Pointer to the frame buffer
* @frameType: 802.11 frame type
*
* This function forwards the unprotected management frame to the supplicant.
*
* Return: nothing
*/
static void
hdd_indicate_unprot_mgmt_frame(hdd_adapter_t *pAdapter, uint32_t nFrameLength,
uint8_t *pbFrames, uint8_t frameType)
{
uint8_t type = 0;
uint8_t subType = 0;
hdd_debug("Frame Type = %d Frame Length = %d",
frameType, nFrameLength);
/* Sanity Checks */
if (NULL == pAdapter) {
hdd_err("pAdapter is NULL");
return;
}
if (NULL == pAdapter->dev) {
hdd_err("pAdapter->dev is NULL");
return;
}
if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
hdd_err("pAdapter has invalid magic");
return;
}
if (!nFrameLength) {
hdd_err("Frame Length is Invalid ZERO");
return;
}
if (NULL == pbFrames) {
hdd_err("pbFrames is NULL");
return;
}
type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
/* Get pAdapter from Destination mac address of the frame */
if (type == SIR_MAC_MGMT_FRAME && subType == SIR_MAC_MGMT_DISASSOC) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
cfg80211_rx_unprot_mlme_mgmt(pAdapter->dev, pbFrames,
nFrameLength);
#else
cfg80211_send_unprot_disassoc(pAdapter->dev, pbFrames,
nFrameLength);
#endif
pAdapter->hdd_stats.hddPmfStats.numUnprotDisassocRx++;
} else if (type == SIR_MAC_MGMT_FRAME &&
subType == SIR_MAC_MGMT_DEAUTH) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
cfg80211_rx_unprot_mlme_mgmt(pAdapter->dev, pbFrames,
nFrameLength);
#else
cfg80211_send_unprot_deauth(pAdapter->dev, pbFrames,
nFrameLength);
#endif
pAdapter->hdd_stats.hddPmfStats.numUnprotDeauthRx++;
} else {
hdd_warn("Frame type %d and subtype %d are not valid",
type, subType);
return;
}
}
#endif
#ifdef FEATURE_WLAN_ESE
/**
* hdd_indicate_tsm_ie() - send traffic stream metrics ie
* @pAdapter: pointer to adapter
* @tid: traffic identifier
* @state: state
* @measInterval: measurement interval
*
* This function sends traffic stream metrics IE information to
* the supplicant via wireless event.
*
* Return: none
*/
static void
hdd_indicate_tsm_ie(hdd_adapter_t *pAdapter, uint8_t tid,
uint8_t state, uint16_t measInterval)
{
union iwreq_data wrqu;
char buf[IW_CUSTOM_MAX + 1];
int nBytes = 0;
if (NULL == pAdapter)
return;
/* create the event */
memset(&wrqu, '\0', sizeof(wrqu));
memset(buf, '\0', sizeof(buf));
hdd_debug("TSM Ind tid(%d) state(%d) MeasInt(%d)",
tid, state, measInterval);
nBytes =
snprintf(buf, IW_CUSTOM_MAX, "TSMIE=%d:%d:%d", tid, state,
measInterval);
wrqu.data.pointer = buf;
wrqu.data.length = nBytes;
/* send the event */
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
}
/**
* hdd_indicate_cckm_pre_auth() - send cckm preauth indication
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
*
* This function sends cckm preauth indication to the supplicant
* via wireless custom event.
*
* Return: none
*/
static void
hdd_indicate_cckm_pre_auth(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo)
{
union iwreq_data wrqu;
char buf[IW_CUSTOM_MAX + 1];
char *pos = buf;
int nBytes = 0, freeBytes = IW_CUSTOM_MAX;
if ((NULL == pAdapter) || (NULL == pRoamInfo))
return;
/* create the event */
memset(&wrqu, '\0', sizeof(wrqu));
memset(buf, '\0', sizeof(buf));
/* Timestamp0 is lower 32 bits and Timestamp1 is upper 32 bits */
hdd_debug("CCXPREAUTHNOTIFY=" MAC_ADDRESS_STR " %d:%d",
MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes),
pRoamInfo->timestamp[0], pRoamInfo->timestamp[1]);
nBytes = snprintf(pos, freeBytes, "CCXPREAUTHNOTIFY=");
pos += nBytes;
freeBytes -= nBytes;
qdf_mem_copy(pos, pRoamInfo->bssid.bytes, QDF_MAC_ADDR_SIZE);
pos += QDF_MAC_ADDR_SIZE;
freeBytes -= QDF_MAC_ADDR_SIZE;
nBytes = snprintf(pos, freeBytes, " %u:%u",
pRoamInfo->timestamp[0], pRoamInfo->timestamp[1]);
freeBytes -= nBytes;
wrqu.data.pointer = buf;
wrqu.data.length = (IW_CUSTOM_MAX - freeBytes);
/* send the event */
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
}
/**
* hdd_indicate_ese_adj_ap_rep_ind() - send adjacent AP report indication
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
*
* Return: none
*/
static void
hdd_indicate_ese_adj_ap_rep_ind(hdd_adapter_t *pAdapter,
tCsrRoamInfo *pRoamInfo)
{
union iwreq_data wrqu;
char buf[IW_CUSTOM_MAX + 1];
int nBytes = 0;
if ((NULL == pAdapter) || (NULL == pRoamInfo))
return;
/* create the event */
memset(&wrqu, '\0', sizeof(wrqu));
memset(buf, '\0', sizeof(buf));
hdd_debug("CCXADJAPREP=%u", pRoamInfo->tsmRoamDelay);
nBytes =
snprintf(buf, IW_CUSTOM_MAX, "CCXADJAPREP=%u",
pRoamInfo->tsmRoamDelay);
wrqu.data.pointer = buf;
wrqu.data.length = nBytes;
/* send the event */
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
}
/**
* hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results
* @pAdapter: pointer to adapter
* @measurementToken: measurement token
* @flag: flag
* @numBss: number of bss
*
* If the measurement is none and no scan results found,
* indicate the supplicant about measurement done.
*
* Return: none
*/
void
hdd_indicate_ese_bcn_report_no_results(const hdd_adapter_t *pAdapter,
const uint16_t measurementToken,
const bool flag, const uint8_t numBss)
{
union iwreq_data wrqu;
char buf[IW_CUSTOM_MAX];
char *pos = buf;
int nBytes = 0, freeBytes = IW_CUSTOM_MAX;
memset(&wrqu, '\0', sizeof(wrqu));
memset(buf, '\0', sizeof(buf));
hdd_debug("CCXBCNREP=%d %d %d", measurementToken,
flag, numBss);
nBytes =
snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d", measurementToken,
flag, numBss);
wrqu.data.pointer = buf;
wrqu.data.length = nBytes;
/* send the event */
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
}
/**
* hdd_indicate_ese_bcn_report_ind() - send beacon report indication
* @pAdapter: pointer to adapter
* @pRoamInfo: pointer to roam info
*
* If the measurement is none and no scan results found,
* indicate the supplicant about measurement done.
*
* Return: none
*/
static void
hdd_indicate_ese_bcn_report_ind(const hdd_adapter_t *pAdapter,
const tCsrRoamInfo *pRoamInfo)
{
union iwreq_data wrqu;
char buf[IW_CUSTOM_MAX];
char *pos = buf;
int nBytes = 0, freeBytes = IW_CUSTOM_MAX;
uint8_t i = 0, len = 0;
uint8_t tot_bcn_ieLen = 0; /* total size of the beacon report data */
uint8_t lastSent = 0, sendBss = 0;
int bcnRepFieldSize =
sizeof(pRoamInfo->pEseBcnReportRsp->bcnRepBssInfo[0].
bcnReportFields);
uint8_t ieLenByte = 1;
/*
* CCXBCNREP=meas_tok<sp>flag<sp>no_of_bss<sp>tot_bcn_ie_len = 18 bytes
*/
#define ESEBCNREPHEADER_LEN (18)
if ((NULL == pAdapter) || (NULL == pRoamInfo))
return;
/*
* Custom event can pass maximum of 256 bytes of data,
* based on the IE len we need to identify how many BSS info can
* be filled in to custom event data.
*/
/*
* meas_tok<sp>flag<sp>no_of_bss<sp>tot_bcn_ie_len bcn_rep_data
* bcn_rep_data will have bcn_rep_fields,ie_len,ie without any spaces
* CCXBCNREP=meas_tok<sp>flag<sp>no_of_bss<sp>tot_bcn_ie_len = 18 bytes
*/
if ((pRoamInfo->pEseBcnReportRsp->flag >> 1)
&& (!pRoamInfo->pEseBcnReportRsp->numBss)) {
hdd_debug("Measurement Done but no scan results");
/* If the measurement is none and no scan results found,
* indicate the supplicant about measurement done
*/
hdd_indicate_ese_bcn_report_no_results(
pAdapter,
pRoamInfo->pEseBcnReportRsp->
measurementToken,
pRoamInfo->pEseBcnReportRsp->flag,
pRoamInfo->pEseBcnReportRsp->numBss);
} else {
while (lastSent < pRoamInfo->pEseBcnReportRsp->numBss) {
memset(&wrqu, '\0', sizeof(wrqu));
memset(buf, '\0', sizeof(buf));
tot_bcn_ieLen = 0;
sendBss = 0;
pos = buf;
freeBytes = IW_CUSTOM_MAX;
for (i = lastSent;
i < pRoamInfo->pEseBcnReportRsp->numBss; i++) {
len =
bcnRepFieldSize + ieLenByte +
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i].ieLen;
if ((len + tot_bcn_ieLen) >
(IW_CUSTOM_MAX - ESEBCNREPHEADER_LEN)) {
break;
}
tot_bcn_ieLen += len;
sendBss++;
hdd_debug("i(%d) sizeof bcnReportFields(%d) IeLength(%d) Length of Ie(%d) totLen(%d)",
i, bcnRepFieldSize, 1,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i].ieLen, tot_bcn_ieLen);
}
hdd_debug("Sending %d BSS Info", sendBss);
hdd_debug("CCXBCNREP=%d %d %d %d",
pRoamInfo->pEseBcnReportRsp->measurementToken,
pRoamInfo->pEseBcnReportRsp->flag, sendBss,
tot_bcn_ieLen);
nBytes = snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d ",
pRoamInfo->pEseBcnReportRsp->
measurementToken,
pRoamInfo->pEseBcnReportRsp->flag,
sendBss);
pos += nBytes;
freeBytes -= nBytes;
/* Copy total Beacon report data length */
qdf_mem_copy(pos, (char *)&tot_bcn_ieLen,
sizeof(tot_bcn_ieLen));
pos += sizeof(tot_bcn_ieLen);
freeBytes -= sizeof(tot_bcn_ieLen);
for (i = 0; i < sendBss; i++) {
hdd_debug("ChanNum(%d) Spare(%d) MeasDuration(%d)"
" PhyType(%d) RecvSigPower(%d) ParentTSF(%u)"
" TargetTSF[0](%u) TargetTSF[1](%u) BeaconInterval(%u)"
" CapabilityInfo(%d) BSSID(%02X:%02X:%02X:%02X:%02X:%02X)",
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
ChanNum,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Spare,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
MeasDuration,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
PhyType,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
RecvSigPower,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
ParentTsf,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
TargetTsf[0],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
TargetTsf[1],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
BcnInterval,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
CapabilityInfo,
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Bssid[0],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Bssid[1],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Bssid[2],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Bssid[3],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Bssid[4],
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].bcnReportFields.
Bssid[5]);
/* bcn report fields are copied */
len =
sizeof(pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i +
lastSent].
bcnReportFields);
qdf_mem_copy(pos,
(char *)&pRoamInfo->
pEseBcnReportRsp->bcnRepBssInfo[i +
lastSent].
bcnReportFields, len);
pos += len;
freeBytes -= len;
/* Add 1 byte of ie len */
len =
pRoamInfo->pEseBcnReportRsp->
bcnRepBssInfo[i + lastSent].ieLen;
qdf_mem_copy(pos, (char *)&len, sizeof(len));
pos += sizeof(len);
freeBytes -= sizeof(len);
/* copy IE from scan results */
qdf_mem_copy(pos,
(char *)pRoamInfo->
pEseBcnReportRsp->bcnRepBssInfo[i +
lastSent].
pBuf, len);
pos += len;
freeBytes -= len;
}
wrqu.data.pointer = buf;
wrqu.data.length = IW_CUSTOM_MAX - freeBytes;
/* send the event */
wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu,
buf);
lastSent += sendBss;
}
}
}
#endif /* FEATURE_WLAN_ESE */
/**
* hdd_is_8021x_sha256_auth_type() - check authentication type to 8021x_sha256
* @pHddStaCtx: Station Context
*
* API to check if the connection authentication type is 8021x_sha256.
*
* Return: bool
*/
#ifdef WLAN_FEATURE_11W
static inline bool hdd_is_8021x_sha256_auth_type(hdd_station_ctx_t *pHddStaCtx)
{
return eCSR_AUTH_TYPE_RSN_8021X_SHA256 ==
pHddStaCtx->conn_info.authType;
}
#else
static inline bool hdd_is_8021x_sha256_auth_type(hdd_station_ctx_t *pHddStaCtx)
{
return false;
}
#endif
/*
* hdd_roam_channel_switch_handler() - hdd channel switch handler
* @adapter: Pointer to adapter context
* @roam_info: Pointer to roam info
*
* Return: None
*/
static void hdd_roam_channel_switch_handler(hdd_adapter_t *adapter,
tCsrRoamInfo *roam_info)
{
struct hdd_chan_change_params chan_change;
struct cfg80211_bss *bss;
struct net_device *dev = adapter->dev;
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
QDF_STATUS status;
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
hdd_debug("channel switch for session:%d to channel:%d",
adapter->sessionId, roam_info->chan_info.chan_id);
chan_change.chan = roam_info->chan_info.chan_id;
chan_change.chan_params.ch_width =
roam_info->chan_info.ch_width;
chan_change.chan_params.sec_ch_offset =
roam_info->chan_info.sec_ch_offset;
chan_change.chan_params.center_freq_seg0 =
roam_info->chan_info.band_center_freq1;
chan_change.chan_params.center_freq_seg1 =
roam_info->chan_info.band_center_freq2;
bss = wlan_hdd_cfg80211_update_bss_db(adapter, roam_info);
if (NULL == bss)
hdd_err("%s: unable to create BSS entry", adapter->dev->name);
else
cfg80211_put_bss(wiphy, bss);
status = hdd_chan_change_notify(adapter, adapter->dev, chan_change,
roam_info->mode == SIR_SME_PHY_MODE_LEGACY);
if (QDF_IS_STATUS_ERROR(status))
hdd_err("channel change notification failed");
status = policy_mgr_set_hw_mode_on_channel_switch(hdd_ctx->hdd_psoc,
adapter->sessionId);
if (QDF_IS_STATUS_ERROR(status))
hdd_debug("set hw mode change not done");
}
/**
* hdd_sme_roam_callback() - hdd sme roam callback
* @pContext: pointer to adapter context
* @pRoamInfo: pointer to roam info
* @roamId: roam id
* @roamStatus: roam status
* @roamResult: roam result
*
* Return: QDF_STATUS enumeration
*/
QDF_STATUS
hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId,
eRoamCmdStatus roamStatus, eCsrRoamResult roamResult)
{
QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS;
hdd_adapter_t *pAdapter = (hdd_adapter_t *) pContext;
hdd_wext_state_t *pWextState = NULL;
hdd_station_ctx_t *pHddStaCtx = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct cfg80211_bss *bss_status;
hdd_context_t *hdd_ctx;
hdd_debug("CSR Callback: status= %d result= %d roamID=%d",
roamStatus, roamResult, roamId);
/* Sanity check */
if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
hdd_err("Invalid adapter or adapter has invalid magic");
return QDF_STATUS_E_FAILURE;
}
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
/* Omitting eCSR_ROAM_UPDATE_SCAN_RESULT as this is too frequent */
if (eCSR_ROAM_UPDATE_SCAN_RESULT != roamStatus)
MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_RX_SME_MSG,
pAdapter->sessionId, roamStatus));
switch (roamStatus) {
case eCSR_ROAM_SESSION_OPENED:
set_bit(SME_SESSION_OPENED, &pAdapter->event_flags);
complete(&pAdapter->session_open_comp_var);
hdd_debug("session %d opened", pAdapter->sessionId);
break;
/*
* We did pre-auth,then we attempted a 11r or ese reassoc.
* reassoc failed due to failure, timeout, reject from ap
* in any case tell the OS, our carrier is off and mark
* interface down.
*/
case eCSR_ROAM_FT_REASSOC_FAILED:
hdd_err("Reassoc Failed with roamStatus: %d roamResult: %d SessionID: %d",
roamStatus, roamResult, pAdapter->sessionId);
qdf_ret_status =
hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId,
roamStatus, roamResult);
pHddStaCtx->ft_carrier_on = false;
pHddStaCtx->hdd_ReassocScenario = false;
hdd_debug("hdd_ReassocScenario set to: %d, ReAssoc Failed, session: %d",
pHddStaCtx->hdd_ReassocScenario, pAdapter->sessionId);
break;
case eCSR_ROAM_FT_START:
/*
* When we roam for ESE and 11r, we dont want the OS to be
* informed that the link is down. So mark the link ready for
* ft_start. After this the eCSR_ROAM_SHOULD_ROAM will
* be received. Where in we will not mark the link down
* Also we want to stop tx at this point when we will be
* doing disassoc at this time. This saves 30-60 msec
* after reassoc.
*/
hdd_info("Disabling queues");
hdd_debug("Roam Synch Ind: NAPI Serialize ON");
hdd_napi_serialize(1);
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
status = hdd_roam_deregister_sta(pAdapter,
pHddStaCtx->conn_info.staId[0]);
if (!QDF_IS_STATUS_SUCCESS(status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
pHddStaCtx->ft_carrier_on = true;
pHddStaCtx->hdd_ReassocScenario = true;
hdd_info("hdd_ReassocScenario set to: %d, due to eCSR_ROAM_FT_START, session: %d",
pHddStaCtx->hdd_ReassocScenario, pAdapter->sessionId);
break;
case eCSR_ROAM_NAPI_OFF:
hdd_debug("After Roam Synch Comp: NAPI Serialize OFF");
hdd_napi_serialize(0);
hdd_set_roaming_in_progress(false);
if (roamResult == eCSR_ROAM_RESULT_FAILURE)
pAdapter->roam_ho_fail = true;
else
pAdapter->roam_ho_fail = false;
complete(&pAdapter->roaming_comp_var);
break;
case eCSR_ROAM_SHOULD_ROAM:
/* notify apps that we can't pass traffic anymore */
hdd_info("Disabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
if (pHddStaCtx->ft_carrier_on == false) {
wlan_hdd_netif_queue_control(pAdapter,
WLAN_NETIF_CARRIER_OFF,
WLAN_CONTROL_PATH);
}
break;
case eCSR_ROAM_LOSTLINK:
if (roamResult == eCSR_ROAM_RESULT_LOSTLINK) {
hdd_debug("Roaming started due to connection lost");
hdd_info("Disabling queues");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
WLAN_CONTROL_PATH);
break;
}
case eCSR_ROAM_DISASSOCIATED:
{
hdd_debug("****eCSR_ROAM_DISASSOCIATED****");
hdd_napi_serialize(0);
hdd_set_connection_in_progress(false);
hdd_set_roaming_in_progress(false);
pAdapter->roam_ho_fail = false;
complete(&pAdapter->roaming_comp_var);
/* Call to clear any MC Addr List filter applied after
* successful connection.
*/
hdd_disable_and_flush_mc_addr_list(pAdapter,
pmo_peer_disconnect);
qdf_ret_status =
hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId,
roamStatus, roamResult);
}
break;
case eCSR_ROAM_IBSS_LEAVE:
hdd_debug("****eCSR_ROAM_IBSS_LEAVE****");
qdf_ret_status =
hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId,
roamStatus, roamResult);
break;
case eCSR_ROAM_ASSOCIATION_COMPLETION:
hdd_debug("****eCSR_ROAM_ASSOCIATION_COMPLETION****");
/*
* To Do - address probable memory leak with WEP encryption upon
* successful association.
*/
if (eCSR_ROAM_RESULT_ASSOCIATED != roamResult) {
/* Clear saved connection information in HDD */
hdd_conn_remove_connect_info(
WLAN_HDD_GET_STATION_CTX_PTR(pAdapter));
}
qdf_ret_status =
hdd_association_completion_handler(pAdapter, pRoamInfo,
roamId, roamStatus,
roamResult);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (pRoamInfo)
pRoamInfo->roamSynchInProgress = false;
#endif
break;
case eCSR_ROAM_CANCELLED:
hdd_debug("****eCSR_ROAM_CANCELLED****");
case eCSR_ROAM_ASSOCIATION_FAILURE:
qdf_ret_status = hdd_association_completion_handler(pAdapter,
pRoamInfo,
roamId,
roamStatus,
roamResult);
break;
case eCSR_ROAM_IBSS_IND:
hdd_roam_ibss_indication_handler(pAdapter, pRoamInfo, roamId,
roamStatus, roamResult);
break;
case eCSR_ROAM_CONNECT_STATUS_UPDATE:
qdf_ret_status =
roam_roam_connect_status_update_handler(pAdapter,
pRoamInfo,
roamId,
roamStatus,
roamResult);
break;
case eCSR_ROAM_MIC_ERROR_IND:
qdf_ret_status =
hdd_roam_mic_error_indication_handler(pAdapter,
pRoamInfo,
roamId,
roamStatus,
roamResult);
break;
case eCSR_ROAM_SET_KEY_COMPLETE:
{
qdf_ret_status =
hdd_roam_set_key_complete_handler(pAdapter, pRoamInfo,
roamId, roamStatus,
roamResult);
if (eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) {
pHddStaCtx->hdd_ReassocScenario = false;
hdd_debug("hdd_ReassocScenario set to: %d, set key complete, session: %d",
pHddStaCtx->hdd_ReassocScenario,
pAdapter->sessionId);
}
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (pRoamInfo != NULL)
pRoamInfo->roamSynchInProgress = false;
#endif
break;
case eCSR_ROAM_FT_RESPONSE:
hdd_send_ft_event(pAdapter);
break;
case eCSR_ROAM_PMK_NOTIFY:
if (eCSR_AUTH_TYPE_RSN == pHddStaCtx->conn_info.authType
|| hdd_is_8021x_sha256_auth_type(pHddStaCtx)) {
/* notify the supplicant of a new candidate */
qdf_ret_status =
wlan_hdd_cfg80211_pmksa_candidate_notify(
pAdapter, pRoamInfo, 1, false);
}
break;
#ifdef FEATURE_WLAN_LFR_METRICS
case eCSR_ROAM_PREAUTH_INIT_NOTIFY:
/* This event is to notify pre-auth initiation */
if (QDF_STATUS_SUCCESS !=
wlan_hdd_cfg80211_roam_metrics_preauth(pAdapter,
pRoamInfo)) {
qdf_ret_status = QDF_STATUS_E_FAILURE;
}
break;
case eCSR_ROAM_PREAUTH_STATUS_SUCCESS:
/*
* This event will notify pre-auth completion in case of success
*/
if (QDF_STATUS_SUCCESS !=
wlan_hdd_cfg80211_roam_metrics_preauth_status(pAdapter,
pRoamInfo, 1)) {
qdf_ret_status = QDF_STATUS_E_FAILURE;
}
break;
case eCSR_ROAM_PREAUTH_STATUS_FAILURE:
/*
* This event will notify pre-auth completion incase of failure.
*/
if (QDF_STATUS_SUCCESS !=
wlan_hdd_cfg80211_roam_metrics_preauth_status(pAdapter,
pRoamInfo, 0)) {
qdf_ret_status = QDF_STATUS_E_FAILURE;
}
break;
case eCSR_ROAM_HANDOVER_SUCCESS:
/* This event is to notify handover success.
* It will be only invoked on success
*/
if (QDF_STATUS_SUCCESS !=
wlan_hdd_cfg80211_roam_metrics_handover(pAdapter,
pRoamInfo)) {
qdf_ret_status = QDF_STATUS_E_FAILURE;
}
break;
#endif
case eCSR_ROAM_REMAIN_CHAN_READY:
hdd_remain_chan_ready_handler(pAdapter, pRoamInfo->roc_scan_id);
break;
#ifdef FEATURE_WLAN_TDLS
case eCSR_ROAM_TDLS_STATUS_UPDATE:
qdf_ret_status =
hdd_roam_tdls_status_update_handler(pAdapter, pRoamInfo,
roamId,
roamStatus,
roamResult);
break;
case eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND:
wlan_hdd_tdls_mgmt_completion_callback(pAdapter,
pRoamInfo->reasonCode);
break;
#endif
#ifdef WLAN_FEATURE_11W
case eCSR_ROAM_UNPROT_MGMT_FRAME_IND:
hdd_indicate_unprot_mgmt_frame(pAdapter,
pRoamInfo->nFrameLength,
pRoamInfo->pbFrames,
pRoamInfo->frameType);
break;
#endif
#ifdef FEATURE_WLAN_ESE
case eCSR_ROAM_TSM_IE_IND:
hdd_indicate_tsm_ie(pAdapter, pRoamInfo->tsmIe.tsid,
pRoamInfo->tsmIe.state,
pRoamInfo->tsmIe.msmt_interval);
break;
case eCSR_ROAM_CCKM_PREAUTH_NOTIFY:
{
if (eCSR_AUTH_TYPE_CCKM_WPA ==
pHddStaCtx->conn_info.authType
|| eCSR_AUTH_TYPE_CCKM_RSN ==
pHddStaCtx->conn_info.authType) {
hdd_indicate_cckm_pre_auth(pAdapter, pRoamInfo);
}
break;
}
case eCSR_ROAM_ESE_ADJ_AP_REPORT_IND:
{
hdd_indicate_ese_adj_ap_rep_ind(pAdapter, pRoamInfo);
break;
}
case eCSR_ROAM_ESE_BCN_REPORT_IND:
{
hdd_indicate_ese_bcn_report_ind(pAdapter, pRoamInfo);
break;
}
#endif /* FEATURE_WLAN_ESE */
case eCSR_ROAM_STA_CHANNEL_SWITCH:
hdd_roam_channel_switch_handler(pAdapter, pRoamInfo);
break;
case eCSR_ROAM_UPDATE_SCAN_RESULT:
if ((NULL != pRoamInfo) && (NULL != pRoamInfo->pBssDesc)) {
bss_status = wlan_hdd_cfg80211_inform_bss_frame(
pAdapter, pRoamInfo->pBssDesc);
if (NULL == bss_status)
hdd_debug("UPDATE_SCAN_RESULT returned NULL");
else
cfg80211_put_bss(
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) || defined(WITH_BACKPORTS)
(WLAN_HDD_GET_CTX(pAdapter))->wiphy,
#endif
bss_status);
}
break;
case eCSR_ROAM_NDP_STATUS_UPDATE:
hdd_ndp_event_handler(pAdapter, pRoamInfo, roamId, roamStatus,
roamResult);
break;
case eCSR_ROAM_START:
hdd_debug("Process ROAM_START from firmware");
wlan_hdd_netif_queue_control(pAdapter,
WLAN_STOP_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
hdd_napi_serialize(1);
hdd_set_connection_in_progress(true);
hdd_set_roaming_in_progress(true);
policy_mgr_restart_opportunistic_timer(hdd_ctx->hdd_psoc, true);
break;
case eCSR_ROAM_ABORT:
hdd_debug("Firmware aborted roaming operation, previous connection is still valid");
hdd_napi_serialize(0);
wlan_hdd_netif_queue_control(pAdapter,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
hdd_set_connection_in_progress(false);
hdd_set_roaming_in_progress(false);
pAdapter->roam_ho_fail = false;
complete(&pAdapter->roaming_comp_var);
break;
default:
break;
}
return qdf_ret_status;
}
#ifdef WLAN_FEATURE_FILS_SK
/**
* hdd_translate_fils_rsn_to_csr_auth() - Translate FILS RSN to CSR auth type
* @auth_suite: auth suite
* @auth_type: pointer to eCsrAuthType
*
* Return: None
*/
static void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4],
eCsrAuthType *auth_type)
{
if (!memcmp(auth_suite, ccp_rsn_oui_0e, 4))
*auth_type = eCSR_AUTH_TYPE_FILS_SHA256;
else if (!memcmp(auth_suite, ccp_rsn_oui_0f, 4))
*auth_type = eCSR_AUTH_TYPE_FILS_SHA384;
else if (!memcmp(auth_suite, ccp_rsn_oui_10, 4))
*auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA256;
else if (!memcmp(auth_suite, ccp_rsn_oui_11, 4))
*auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA384;
}
#else
static inline void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4],
eCsrAuthType *auth_type)
{
}
#endif
/**
* hdd_translate_rsn_to_csr_auth_type() - Translate RSN to CSR auth type
* @auth_suite: auth suite
*
* Return: eCsrAuthType enumeration
*/
eCsrAuthType hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4])
{
eCsrAuthType auth_type = eCSR_AUTH_TYPE_UNKNOWN;
/* is the auth type supported? */
if (memcmp(auth_suite, ccp_rsn_oui01, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_RSN;
} else if (memcmp(auth_suite, ccp_rsn_oui02, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_RSN_PSK;
} else if (memcmp(auth_suite, ccp_rsn_oui04, 4) == 0) {
/* Check for 11r FT Authentication with PSK */
auth_type = eCSR_AUTH_TYPE_FT_RSN_PSK;
} else if (memcmp(auth_suite, ccp_rsn_oui03, 4) == 0) {
/* Check for 11R FT Authentication with 802.1X */
auth_type = eCSR_AUTH_TYPE_FT_RSN;
} else
#ifdef FEATURE_WLAN_ESE
if (memcmp(auth_suite, ccp_rsn_oui06, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_CCKM_RSN;
} else
#endif /* FEATURE_WLAN_ESE */
#ifdef WLAN_FEATURE_11W
if (memcmp(auth_suite, ccp_rsn_oui07, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256;
} else if (memcmp(auth_suite, ccp_rsn_oui08, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256;
} else
#endif
{
hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type);
}
hdd_debug("auth_type: %d", auth_type);
return auth_type;
}
/**
* hdd_translate_wpa_to_csr_auth_type() - Translate WPA to CSR auth type
* @auth_suite: auth suite
*
* Return: eCsrAuthType enumeration
*/
eCsrAuthType hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4])
{
eCsrAuthType auth_type = eCSR_AUTH_TYPE_UNKNOWN;
/* is the auth type supported? */
if (memcmp(auth_suite, ccp_wpa_oui01, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_WPA;
} else if (memcmp(auth_suite, ccp_wpa_oui02, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_WPA_PSK;
} else
#ifdef FEATURE_WLAN_ESE
if (memcmp(auth_suite, ccp_wpa_oui06, 4) == 0) {
auth_type = eCSR_AUTH_TYPE_CCKM_WPA;
} else
#endif /* FEATURE_WLAN_ESE */
{
hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type);
}
hdd_debug("auth_type: %d", auth_type);
return auth_type;
}
/**
* hdd_translate_rsn_to_csr_encryption_type() -
* Translate RSN to CSR encryption type
* @cipher_suite: cipher suite
*
* Return: eCsrEncryptionType enumeration
*/
eCsrEncryptionType
hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4])
{
eCsrEncryptionType cipher_type;
if (memcmp(cipher_suite, ccp_rsn_oui04, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_AES;
else if (memcmp(cipher_suite, ccp_rsn_oui09, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP;
else if (memcmp(cipher_suite, ccp_rsn_oui0a, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP_256;
else if (memcmp(cipher_suite, ccp_rsn_oui02, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_TKIP;
else if (memcmp(cipher_suite, ccp_rsn_oui00, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_NONE;
else if (memcmp(cipher_suite, ccp_rsn_oui01, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
else if (memcmp(cipher_suite, ccp_rsn_oui05, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
else
cipher_type = eCSR_ENCRYPT_TYPE_FAILED;
hdd_debug("cipher_type: %d", cipher_type);
return cipher_type;
}
/**
* hdd_translate_wpa_to_csr_encryption_type() -
* Translate WPA to CSR encryption type
* @cipher_suite: cipher suite
*
* Return: eCsrEncryptionType enumeration
*/
eCsrEncryptionType
hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4])
{
eCsrEncryptionType cipher_type;
if (memcmp(cipher_suite, ccp_wpa_oui04, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_AES;
else if (memcmp(cipher_suite, ccp_wpa_oui02, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_TKIP;
else if (memcmp(cipher_suite, ccp_wpa_oui00, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_NONE;
else if (memcmp(cipher_suite, ccp_wpa_oui01, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
else if (memcmp(cipher_suite, ccp_wpa_oui05, 4) == 0)
cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
else
cipher_type = eCSR_ENCRYPT_TYPE_FAILED;
hdd_debug("cipher_type: %d", cipher_type);
return cipher_type;
}
#ifdef WLAN_FEATURE_FILS_SK
/*
* hdd_is_fils_connection: API to determine if connection is FILS
* @adapter: hdd adapter
*
* Return: true if fils connection else false
*/
static inline bool hdd_is_fils_connection(hdd_adapter_t *adapter)
{
hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
if (wext_state->roamProfile.fils_con_info)
return wext_state->roamProfile.
fils_con_info->is_fils_connection;
}
#else
static inline bool hdd_is_fils_connection(hdd_adapter_t *adapter)
{
return false;
}
#endif
/**
* hdd_process_genie() - process gen ie
* @pAdapter: pointer to adapter
* @bssid: pointer to mac address
* @pEncryptType: pointer to encryption type
* @mcEncryptType: pointer to multicast encryption type
* @pAuthType: pointer to auth type
*
* Return: 0 on success, error number otherwise
*/
static int32_t hdd_process_genie(hdd_adapter_t *pAdapter,
u8 *bssid,
eCsrEncryptionType *pEncryptType,
eCsrEncryptionType *mcEncryptType,
eCsrAuthType *pAuthType,
#ifdef WLAN_FEATURE_11W
uint8_t *pMfpRequired, uint8_t *pMfpCapable,
#endif
uint16_t gen_ie_len, uint8_t *gen_ie)
{
tHalHandle halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
tDot11fIERSN dot11RSNIE;
tDot11fIEWPA dot11WPAIE;
uint8_t *pRsnIe;
uint16_t RSNIeLen;
/*
* Clear struct of tDot11fIERSN and tDot11fIEWPA specifically
* setting present flag to 0.
*/
memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA));
memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN));
/* Type check */
if (gen_ie[0] == DOT11F_EID_RSN) {
/* Validity checks */
if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN) ||
(gen_ie_len > DOT11F_IE_RSN_MAX_LEN)) {
hdd_err("Invalid DOT11F RSN IE length: %d",
gen_ie_len);
return -EINVAL;
}
/* Skip past the EID byte and length byte */
pRsnIe = gen_ie + 2;
RSNIeLen = gen_ie_len - 2;
/* Unpack the RSN IE */
dot11f_unpack_ie_rsn((tpAniSirGlobal) halHandle,
pRsnIe, RSNIeLen, &dot11RSNIE, false);
/* Copy out the encryption and authentication types */
hdd_debug("pairwise cipher suite count: %d",
dot11RSNIE.pwise_cipher_suite_count);
hdd_debug("authentication suite count: %d",
dot11RSNIE.akm_suite_count);
/* dot11RSNIE.akm_suite_count */
/* Just translate the FIRST one */
*pAuthType =
hdd_translate_rsn_to_csr_auth_type(
dot11RSNIE.akm_suites[0]);
/* dot11RSNIE.pwise_cipher_suite_count */
*pEncryptType =
hdd_translate_rsn_to_csr_encryption_type(
dot11RSNIE.pwise_cipher_suites[0]);
/* dot11RSNIE.gp_cipher_suite_count */
*mcEncryptType =
hdd_translate_rsn_to_csr_encryption_type(
dot11RSNIE.gp_cipher_suite);
#ifdef WLAN_FEATURE_11W
*pMfpRequired = (dot11RSNIE.RSN_Cap[0] >> 6) & 0x1;
*pMfpCapable = csr_is_mfpc_capable(&dot11RSNIE);
#endif
} else if (gen_ie[0] == DOT11F_EID_WPA) {
/* Validity checks */
if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN) ||
(gen_ie_len > DOT11F_IE_WPA_MAX_LEN)) {
hdd_err("Invalid DOT11F WPA IE length: %d",
gen_ie_len);
return -EINVAL;
}
/* Skip past the EID and length byte - and four byte WiFi OUI */
pRsnIe = gen_ie + 2 + 4;
RSNIeLen = gen_ie_len - (2 + 4);
/* Unpack the WPA IE */
dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle,
pRsnIe, RSNIeLen, &dot11WPAIE, false);
/* Copy out the encryption and authentication types */
hdd_debug("WPA unicast cipher suite count: %d",
dot11WPAIE.unicast_cipher_count);
hdd_debug("WPA authentication suite count: %d",
dot11WPAIE.auth_suite_count);
/* dot11WPAIE.auth_suite_count */
/* Just translate the FIRST one */
*pAuthType =
hdd_translate_wpa_to_csr_auth_type(
dot11WPAIE.auth_suites[0]);
/* dot11WPAIE.unicast_cipher_count */
*pEncryptType =
hdd_translate_wpa_to_csr_encryption_type(
dot11WPAIE.unicast_ciphers[0]);
/* dot11WPAIE.unicast_cipher_count */
*mcEncryptType =
hdd_translate_wpa_to_csr_encryption_type(
dot11WPAIE.multicast_cipher);
} else {
hdd_warn("gen_ie[0]: %d", gen_ie[0]);
return -EINVAL;
}
return 0;
}
/**
* hdd_set_genie_to_csr() - set genie to csr
* @pAdapter: pointer to adapter
* @RSNAuthType: pointer to auth type
*
* Return: 0 on success, error number otherwise
*/
int hdd_set_genie_to_csr(hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType)
{
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
uint32_t status = 0;
eCsrEncryptionType RSNEncryptType;
eCsrEncryptionType mcRSNEncryptType;
#ifdef WLAN_FEATURE_11W
uint8_t RSNMfpRequired = 0;
uint8_t RSNMfpCapable = 0;
#endif
u8 bssid[ETH_ALEN]; /* MAC address of assoc peer */
/* MAC address of assoc peer */
/* But, this routine is only called when we are NOT associated. */
qdf_mem_copy(bssid,
pWextState->roamProfile.BSSIDs.bssid,
sizeof(bssid));
if (pWextState->WPARSNIE[0] == DOT11F_EID_RSN
|| pWextState->WPARSNIE[0] == DOT11F_EID_WPA) {
/* continue */
} else {
return 0;
}
/* The actual processing may eventually be more extensive than this. */
/* Right now, just consume any PMKIDs that are sent in by the app. */
status = hdd_process_genie(pAdapter, bssid,
&RSNEncryptType,
&mcRSNEncryptType, RSNAuthType,
#ifdef WLAN_FEATURE_11W
&RSNMfpRequired, &RSNMfpCapable,
#endif
pWextState->WPARSNIE[1] + 2,
pWextState->WPARSNIE);
if (status == 0) {
/*
* Now copy over all the security attributes
* you have parsed out.
*/
pWextState->roamProfile.EncryptionType.numEntries = 1;
pWextState->roamProfile.mcEncryptionType.numEntries = 1;
pWextState->roamProfile.EncryptionType.encryptionType[0] = RSNEncryptType; /* Use the cipher type in the RSN IE */
pWextState->roamProfile.mcEncryptionType.encryptionType[0] =
mcRSNEncryptType;
if ((QDF_IBSS_MODE == pAdapter->device_mode) &&
((eCSR_ENCRYPT_TYPE_AES == mcRSNEncryptType) ||
(eCSR_ENCRYPT_TYPE_AES_GCMP == mcRSNEncryptType) ||
(eCSR_ENCRYPT_TYPE_AES_GCMP_256 == mcRSNEncryptType) ||
(eCSR_ENCRYPT_TYPE_TKIP == mcRSNEncryptType))) {
/*
* For wpa none supplicant sends the WPA IE with unicast
* cipher as eCSR_ENCRYPT_TYPE_NONE ,where as the
* multicast cipher as either AES/TKIP based on group
* cipher configuration mentioned in the
* wpa_supplicant.conf.
*/
/* Set the unicast cipher same as multicast cipher */
pWextState->roamProfile.EncryptionType.encryptionType[0]
= mcRSNEncryptType;
}
#ifdef WLAN_FEATURE_11W
hdd_debug("RSNMfpRequired = %d, RSNMfpCapable = %d",
RSNMfpRequired, RSNMfpCapable);
pWextState->roamProfile.MFPRequired = RSNMfpRequired;
pWextState->roamProfile.MFPCapable = RSNMfpCapable;
#endif
hdd_debug("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d",
*RSNAuthType, RSNEncryptType, mcRSNEncryptType);
}
return 0;
}
#ifdef WLAN_FEATURE_FILS_SK
/**
* hdd_check_fils_rsn_n_set_auth_type() - This API checks whether a give
* auth type is fils if yes, sets it in profile.
* @rsn_auth_type: auth type
*
* Return: true if FILS auth else false
*/
static bool hdd_check_fils_rsn_n_set_auth_type(tCsrRoamProfile *roam_profile,
eCsrAuthType rsn_auth_type)
{
bool is_fils_rsn = false;
if (!roam_profile->fils_con_info)
return false;
if ((rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA256) ||
(rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA384) ||
(rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA256) ||
(rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA384))
is_fils_rsn = true;
if (is_fils_rsn)
roam_profile->fils_con_info->akm_type = rsn_auth_type;
return is_fils_rsn;
}
#else
static bool hdd_check_fils_rsn_n_set_auth_type(tCsrRoamProfile *roam_profile,
eCsrAuthType rsn_auth_type)
{
return false;
}
#endif
/**
* hdd_set_csr_auth_type() - set csr auth type
* @pAdapter: pointer to adapter
* @RSNAuthType: auth type
*
* Return: 0 on success, error number otherwise
*/
int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType)
{
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
pRoamProfile->AuthType.numEntries = 1;
hdd_debug("pHddStaCtx->conn_info.authType = %d",
pHddStaCtx->conn_info.authType);
switch (pHddStaCtx->conn_info.authType) {
case eCSR_AUTH_TYPE_OPEN_SYSTEM:
#ifdef FEATURE_WLAN_ESE
case eCSR_AUTH_TYPE_CCKM_WPA:
case eCSR_AUTH_TYPE_CCKM_RSN:
#endif
if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_DISABLED) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_OPEN_SYSTEM;
} else if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_WPA) {
#ifdef FEATURE_WLAN_ESE
if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) &&
((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)
== IW_AUTH_KEY_MGMT_802_1X)) {
hdd_debug("set authType to CCKM WPA. AKM also 802.1X.");
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_CCKM_WPA;
} else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) {
hdd_debug("Last chance to set authType to CCKM WPA.");
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_CCKM_WPA;
} else
#endif
if ((pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)
== IW_AUTH_KEY_MGMT_802_1X) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_WPA;
} else
if ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_PSK)
== IW_AUTH_KEY_MGMT_PSK) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_WPA_PSK;
} else {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_WPA_NONE;
}
}
if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_WPA2) {
#ifdef FEATURE_WLAN_ESE
if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) &&
((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)
== IW_AUTH_KEY_MGMT_802_1X)) {
hdd_debug("set authType to CCKM RSN. AKM also 802.1X.");
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_CCKM_RSN;
} else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) {
hdd_debug("Last chance to set authType to CCKM RSN.");
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_CCKM_RSN;
} else
#endif
if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN) &&
((pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)
== IW_AUTH_KEY_MGMT_802_1X)) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_FT_RSN;
} else if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN_PSK)
&&
((pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_PSK)
== IW_AUTH_KEY_MGMT_PSK)) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_FT_RSN_PSK;
} else
#ifdef WLAN_FEATURE_11W
if (RSNAuthType == eCSR_AUTH_TYPE_RSN_PSK_SHA256) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_RSN_PSK_SHA256;
} else if (RSNAuthType ==
eCSR_AUTH_TYPE_RSN_8021X_SHA256) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_RSN_8021X_SHA256;
} else
#endif
if (hdd_check_fils_rsn_n_set_auth_type(pRoamProfile,
RSNAuthType)) {
pRoamProfile->AuthType.authType[0] =
RSNAuthType;
hdd_info("updated profile authtype as %d",
RSNAuthType);
} else if ((pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)
== IW_AUTH_KEY_MGMT_802_1X) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_RSN;
} else
if ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_PSK)
== IW_AUTH_KEY_MGMT_PSK) {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_RSN_PSK;
} else {
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_UNKNOWN;
}
}
break;
case eCSR_AUTH_TYPE_SHARED_KEY:
pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY;
break;
default:
#ifdef FEATURE_WLAN_ESE
hdd_debug("In default, unknown auth type.");
#endif /* FEATURE_WLAN_ESE */
pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_UNKNOWN;
break;
}
hdd_debug("Set roam Authtype to %d",
pWextState->roamProfile.AuthType.authType[0]);
return 0;
}
/**
* __iw_set_essid() - This function sets the ssid received from wpa_supplicant
* to the CSR roam profile.
*
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure
*/
static int __iw_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
uint32_t status = 0;
hdd_wext_state_t *pWextState;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
uint32_t roamId;
tCsrRoamProfile *pRoamProfile;
eCsrAuthType RSNAuthType;
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
int ret;
ENTER_DEV(dev);
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
ret = hdd_check_standard_wext_control(hdd_ctx, info);
if (0 != ret)
return ret;
if (pAdapter->device_mode != QDF_STA_MODE &&
pAdapter->device_mode != QDF_IBSS_MODE &&
pAdapter->device_mode != QDF_P2P_CLIENT_MODE) {
hdd_warn("device mode %s(%d) is not allowed",
hdd_device_mode_to_string(pAdapter->device_mode),
pAdapter->device_mode);
return -EINVAL;
}
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if (pWextState->mTKIPCounterMeasures == TKIP_COUNTER_MEASURE_STARTED) {
hdd_warn("Counter measure is in progress");
return -EBUSY;
}
if (SIR_MAC_MAX_SSID_LENGTH < wrqu->essid.length)
return -EINVAL;
pRoamProfile = &pWextState->roamProfile;
/*Try disconnecting if already in connected state*/
status = wlan_hdd_try_disconnect(pAdapter);
if (0 > status) {
hdd_err("Failed to disconnect the existing connection");
return -EALREADY;
}
/*
* when cfg80211 defined, wpa_supplicant wext driver uses
* zero-length, null-string ssid for force disconnection.
* after disconnection (if previously connected) and cleaning ssid,
* driver MUST return success.
*/
if (0 == wrqu->essid.length)
return 0;
status = hdd_wmm_get_uapsd_mask(pAdapter,
&pWextState->roamProfile.uapsd_mask);
if (QDF_STATUS_SUCCESS != status)
pWextState->roamProfile.uapsd_mask = 0;
pWextState->roamProfile.SSIDs.numOfSSIDs = 1;
pWextState->roamProfile.SSIDs.SSIDList->SSID.length =
wrqu->essid.length;
qdf_mem_zero(pWextState->roamProfile.SSIDs.SSIDList->SSID.ssId,
sizeof(pWextState->roamProfile.SSIDs.SSIDList->SSID.ssId));
qdf_mem_copy((void *)(pWextState->roamProfile.SSIDs.SSIDList->SSID.
ssId), extra, wrqu->essid.length);
if (IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion
|| IW_AUTH_WPA_VERSION_WPA2 == pWextState->wpaVersion) {
/* set gen ie */
hdd_set_genie_to_csr(pAdapter, &RSNAuthType);
/* set auth */
hdd_set_csr_auth_type(pAdapter, RSNAuthType);
}
#ifdef FEATURE_WLAN_WAPI
hdd_debug("Setting WAPI AUTH Type and Encryption Mode values");
if (pAdapter->wapi_info.nWapiMode) {
switch (pAdapter->wapi_info.wapiAuthMode) {
case WAPI_AUTH_MODE_PSK:
{
hdd_debug("WAPI AUTH TYPE: PSK: %d",
pAdapter->wapi_info.wapiAuthMode);
pRoamProfile->AuthType.numEntries = 1;
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_WAPI_WAI_PSK;
break;
}
case WAPI_AUTH_MODE_CERT:
{
hdd_debug("WAPI AUTH TYPE: CERT: %d",
pAdapter->wapi_info.wapiAuthMode);
pRoamProfile->AuthType.numEntries = 1;
pRoamProfile->AuthType.authType[0] =
eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE;
break;
}
} /* End of switch */
if (pAdapter->wapi_info.wapiAuthMode == WAPI_AUTH_MODE_PSK ||
pAdapter->wapi_info.wapiAuthMode == WAPI_AUTH_MODE_CERT) {
hdd_debug("WAPI PAIRWISE/GROUP ENCRYPTION: WPI");
pRoamProfile->EncryptionType.numEntries = 1;
pRoamProfile->EncryptionType.encryptionType[0] =
eCSR_ENCRYPT_TYPE_WPI;
pRoamProfile->mcEncryptionType.numEntries = 1;
pRoamProfile->mcEncryptionType.encryptionType[0] =
eCSR_ENCRYPT_TYPE_WPI;
}
}
#endif /* FEATURE_WLAN_WAPI */
/* if previous genIE is not NULL, update AssocIE */
if (0 != pWextState->genIE.length) {
memset(&pWextState->assocAddIE, 0,
sizeof(pWextState->assocAddIE));
memcpy(pWextState->assocAddIE.addIEdata,
pWextState->genIE.addIEdata, pWextState->genIE.length);
pWextState->assocAddIE.length = pWextState->genIE.length;
pWextState->roamProfile.pAddIEAssoc =
pWextState->assocAddIE.addIEdata;
pWextState->roamProfile.nAddIEAssocLength =
pWextState->assocAddIE.length;
/* clear previous genIE after use it */
memset(&pWextState->genIE, 0, sizeof(pWextState->genIE));
}
/*
* Assumes it is not WPS Association by default, except when
* pAddIEAssoc has WPS IE.
*/
pWextState->roamProfile.bWPSAssociation = false;
if (NULL != wlan_hdd_get_wps_ie_ptr(pWextState->roamProfile.pAddIEAssoc,
pWextState->roamProfile.
nAddIEAssocLength))
pWextState->roamProfile.bWPSAssociation = true;
/* Disable auto BMPS entry by PMC until DHCP is done */
sme_set_dhcp_till_power_active_flag(WLAN_HDD_GET_HAL_CTX(pAdapter),
true);
pWextState->roamProfile.csrPersona = pAdapter->device_mode;
if (eCSR_BSS_TYPE_START_IBSS == pRoamProfile->BSSType) {
pRoamProfile->ch_params.ch_width = 0;
hdd_select_cbmode(pAdapter,
(WLAN_HDD_GET_CTX(pAdapter))->config->AdHocChannel5G,
&pRoamProfile->ch_params);
}
/*
* Change conn_state to connecting before sme_roam_connect(),
* because sme_roam_connect() has a direct path to call
* hdd_sme_roam_callback(), which will change the conn_state
* If direct path, conn_state will be accordingly changed to
* NotConnected or Associated by either
* hdd_association_completion_handler() or hdd_dis_connect_handler()
* in sme_RoamCallback()if sme_RomConnect is to be queued,
* Connecting state will remain until it is completed.
*
* If connection state is not changed,
* connection state will remain in eConnectionState_NotConnected state.
* In hdd_association_completion_handler, "hddDisconInProgress" is
* set to true if conn state is eConnectionState_NotConnected.
* If "hddDisconInProgress" is set to true then cfg80211 layer is not
* informed of connect result indication which is an issue.
*/
if (QDF_STA_MODE == pAdapter->device_mode ||
QDF_P2P_CLIENT_MODE == pAdapter->device_mode)
hdd_conn_set_connection_state(pAdapter,
eConnectionState_Connecting);
status = sme_roam_connect(hHal, pAdapter->sessionId,
&(pWextState->roamProfile), &roamId);
if ((QDF_STATUS_SUCCESS != status) &&
(QDF_STA_MODE == pAdapter->device_mode ||
QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) {
hdd_err("sme_roam_connect failed session_id: %d status %d -> NotConnected",
pAdapter->sessionId, status);
/* change back to NotAssociated */
hdd_conn_set_connection_state(pAdapter,
eConnectionState_NotConnected);
}
pRoamProfile->ChannelInfo.ChannelList = NULL;
pRoamProfile->ChannelInfo.numOfChannels = 0;
EXIT();
return status;
}
/**
* iw_set_essid() - set essid handler function
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure
*/
int iw_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
cds_ssr_protect(__func__);
ret = __iw_set_essid(dev, info, wrqu, extra);
cds_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_essid() - This function returns the essid to the wpa_supplicant
* @dev: pointer to the net device
* @info: pointer to the iw request info
* @dwrq: pointer to iw_point
* @extra: pointer to the data
*
* Return: 0 on success, error number otherwise
*/
static int __iw_get_essid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
hdd_wext_state_t *wextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
int ret;
ENTER_DEV(dev);
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
ret = hdd_check_standard_wext_control(hdd_ctx, info);
if (0 != ret)
return ret;
if ((pHddStaCtx->conn_info.connState == eConnectionState_Associated &&
wextBuf->roamProfile.SSIDs.SSIDList->SSID.length > 0) ||
((pHddStaCtx->conn_info.connState == eConnectionState_IbssConnected
|| pHddStaCtx->conn_info.connState ==
eConnectionState_IbssDisconnected)
&& wextBuf->roamProfile.SSIDs.SSIDList->SSID.length > 0)) {
dwrq->length = pHddStaCtx->conn_info.SSID.SSID.length;
memcpy(extra, pHddStaCtx->conn_info.SSID.SSID.ssId,
dwrq->length);
dwrq->flags = 1;
} else {
memset(extra, 0, dwrq->length);
dwrq->length = 0;
dwrq->flags = 0;
}
EXIT();
return 0;
}
/**
* iw_get_essid() - get essid handler function
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure
*/
int iw_get_essid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *wrqu, char *extra)
{
int ret;
cds_ssr_protect(__func__);
ret = __iw_get_essid(dev, info, wrqu, extra);
cds_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_auth() -
* This function sets the auth type received from the wpa_supplicant
* @dev: pointer to the net device
* @info: pointer to the iw request info
* @wrqu: pointer to iwreq_data
* @extra: pointer to the data
*
* Return: 0 on success, error number otherwise
*/
static int __iw_set_auth(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile;
eCsrEncryptionType mcEncryptionType;
eCsrEncryptionType ucEncryptionType;
int ret;
ENTER_DEV(dev);
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
ret = hdd_check_standard_wext_control(hdd_ctx, info);
if (0 != ret)
return ret;
switch (wrqu->param.flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
pWextState->wpaVersion = wrqu->param.value;
break;
case IW_AUTH_CIPHER_PAIRWISE:
{
if (wrqu->param.value & IW_AUTH_CIPHER_NONE) {
ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE;
} else if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) {
ucEncryptionType = eCSR_ENCRYPT_TYPE_TKIP;
} else if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) {
ucEncryptionType = eCSR_ENCRYPT_TYPE_AES;
} else if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) {
if ((IW_AUTH_KEY_MGMT_802_1X
==
(pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X))
&& (eCSR_AUTH_TYPE_OPEN_SYSTEM ==
pHddStaCtx->conn_info.authType))
/*Dynamic WEP key */
ucEncryptionType =
eCSR_ENCRYPT_TYPE_WEP40;
else
/*Static WEP key */
ucEncryptionType =
eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
} else if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) {
if ((IW_AUTH_KEY_MGMT_802_1X
==
(pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X))
&& (eCSR_AUTH_TYPE_OPEN_SYSTEM ==
pHddStaCtx->conn_info.authType))
/*Dynamic WEP key */
ucEncryptionType =
eCSR_ENCRYPT_TYPE_WEP104;
else
/*Static WEP key */
ucEncryptionType =
eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
} else {
hdd_warn("value %d UNKNOWN IW_AUTH_CIPHER",
wrqu->param.value);
return -EINVAL;
}
pRoamProfile->EncryptionType.numEntries = 1;
pRoamProfile->EncryptionType.encryptionType[0] =
ucEncryptionType;
}
break;
case IW_AUTH_CIPHER_GROUP:
{
if (wrqu->param.value & IW_AUTH_CIPHER_NONE) {
mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE;
} else if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) {
mcEncryptionType = eCSR_ENCRYPT_TYPE_TKIP;
} else if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) {
mcEncryptionType = eCSR_ENCRYPT_TYPE_AES;
} else if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) {
if ((IW_AUTH_KEY_MGMT_802_1X
==
(pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X))
&& (eCSR_AUTH_TYPE_OPEN_SYSTEM ==
pHddStaCtx->conn_info.authType))
mcEncryptionType =
eCSR_ENCRYPT_TYPE_WEP40;
else
mcEncryptionType =
eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
} else if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) {
/* Dynamic WEP keys won't work with shared keys */
if ((IW_AUTH_KEY_MGMT_802_1X
==
(pWextState->
authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X))
&& (eCSR_AUTH_TYPE_OPEN_SYSTEM ==
pHddStaCtx->conn_info.authType)) {
mcEncryptionType =
eCSR_ENCRYPT_TYPE_WEP104;
} else {
mcEncryptionType =
eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
}
} else {
hdd_warn("value %d UNKNOWN IW_AUTH_CIPHER",
wrqu->param.value);
return -EINVAL;
}
pRoamProfile->mcEncryptionType.numEntries = 1;
pRoamProfile->mcEncryptionType.encryptionType[0] =
mcEncryptionType;
}
break;
case IW_AUTH_80211_AUTH_ALG:
{
/* Save the auth algo here and set auth type to SME
* Roam profile in the iw_set_ap_address
*/
if (wrqu->param.value & IW_AUTH_ALG_OPEN_SYSTEM)
pHddStaCtx->conn_info.authType =
eCSR_AUTH_TYPE_OPEN_SYSTEM;
else if (wrqu->param.value & IW_AUTH_ALG_SHARED_KEY)
pHddStaCtx->conn_info.authType =
eCSR_AUTH_TYPE_SHARED_KEY;
else if (wrqu->param.value & IW_AUTH_ALG_LEAP)
/*Not supported */
pHddStaCtx->conn_info.authType =
eCSR_AUTH_TYPE_OPEN_SYSTEM;
pWextState->roamProfile.AuthType.authType[0] =
pHddStaCtx->conn_info.authType;
}
break;
case IW_AUTH_KEY_MGMT:
{
#ifdef FEATURE_WLAN_ESE
#define IW_AUTH_KEY_MGMT_CCKM 8 /* Should be in linux/wireless.h */
/*Check for CCKM AKM type */
if (wrqu->param.value & IW_AUTH_KEY_MGMT_CCKM) {
hdd_debug("CCKM AKM Set %d", wrqu->param.value);
/* Set the CCKM bit in authKeyMgmt */
/*
* Right now, this breaks all ref to authKeyMgmt because
* our code doesn't realize it is a "bitfield"
*/
pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_CCKM;
} else if (wrqu->param.value & IW_AUTH_KEY_MGMT_PSK) {
/* Save the key management */
pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK;
} else if (!(wrqu->param.value & IW_AUTH_KEY_MGMT_802_1X)) {
/* Save the key management anyway */
pWextState->authKeyMgmt = wrqu->param.value;
} else { /* It must be IW_AUTH_KEY_MGMT_802_1X */
/* Save the key management */
pWextState->authKeyMgmt |=
IW_AUTH_KEY_MGMT_802_1X;
}
#else
/* Save the key management */
pWextState->authKeyMgmt = wrqu->param.value;
#endif /* FEATURE_WLAN_ESE */
}
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
{
if (wrqu->param.value) {
hdd_debug("Counter Measure started %d",
wrqu->param.value);
pWextState->mTKIPCounterMeasures =
TKIP_COUNTER_MEASURE_STARTED;
} else {
hdd_debug("Counter Measure stopped=%d",
wrqu->param.value);
pWextState->mTKIPCounterMeasures =
TKIP_COUNTER_MEASURE_STOPED;
}
}
break;
case IW_AUTH_DROP_UNENCRYPTED:
case IW_AUTH_WPA_ENABLED:
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
case IW_AUTH_ROAMING_CONTROL:
case IW_AUTH_PRIVACY_INVOKED:
default:
hdd_warn("called with unsupported auth type %d",
wrqu->param.flags & IW_AUTH_INDEX);
break;
}
EXIT();
return 0;
}
/**
* iw_set_auth() - set auth callback function
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure.
*/
int iw_set_auth(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
cds_ssr_protect(__func__);
ret = __iw_set_auth(dev, info, wrqu, extra);
cds_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_auth() -
* This function returns the auth type to the wpa_supplicant
* @dev: pointer to the net device
* @info: pointer to the iw request info
* @wrqu: pointer to iwreq_data
* @extra: pointer to the data
*
* Return: 0 on success, error number otherwise
*/
static int __iw_get_auth(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile;
int ret;
ENTER_DEV(dev);
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
ret = hdd_check_standard_wext_control(hdd_ctx, info);
if (0 != ret)
return ret;
switch (pRoamProfile->negotiatedAuthType) {
case eCSR_AUTH_TYPE_WPA_NONE:
wrqu->param.flags = IW_AUTH_WPA_VERSION;
wrqu->param.value = IW_AUTH_WPA_VERSION_DISABLED;
break;
case eCSR_AUTH_TYPE_WPA:
wrqu->param.flags = IW_AUTH_WPA_VERSION;
wrqu->param.value = IW_AUTH_WPA_VERSION_WPA;
break;
case eCSR_AUTH_TYPE_FT_RSN:
case eCSR_AUTH_TYPE_RSN:
wrqu->param.flags = IW_AUTH_WPA_VERSION;
wrqu->param.value = IW_AUTH_WPA_VERSION_WPA2;
break;
case eCSR_AUTH_TYPE_OPEN_SYSTEM:
wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
break;
case eCSR_AUTH_TYPE_SHARED_KEY:
wrqu->param.value = IW_AUTH_ALG_SHARED_KEY;
break;
case eCSR_AUTH_TYPE_UNKNOWN:
hdd_debug("called with unknown auth type");
wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
break;
case eCSR_AUTH_TYPE_AUTOSWITCH:
wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
break;
case eCSR_AUTH_TYPE_WPA_PSK:
hdd_debug("called with WPA PSK auth type");
wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
return -EIO;
case eCSR_AUTH_TYPE_FT_RSN_PSK:
case eCSR_AUTH_TYPE_RSN_PSK:
#ifdef WLAN_FEATURE_11W
case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
case eCSR_AUTH_TYPE_RSN_8021X_SHA256:
#endif
hdd_debug("called with RSN PSK auth type");
wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
return -EIO;
default:
hdd_warn("Unknown auth type: %d",
pRoamProfile->negotiatedAuthType);
wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
return -EIO;
}
if (((wrqu->param.flags & IW_AUTH_INDEX) == IW_AUTH_CIPHER_PAIRWISE)) {
switch (pRoamProfile->negotiatedUCEncryptionType) {
case eCSR_ENCRYPT_TYPE_NONE:
wrqu->param.value = IW_AUTH_CIPHER_NONE;
break;
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
wrqu->param.value = IW_AUTH_CIPHER_WEP40;
break;
case eCSR_ENCRYPT_TYPE_TKIP:
wrqu->param.value = IW_AUTH_CIPHER_TKIP;
break;
case eCSR_ENCRYPT_TYPE_WEP104:
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
wrqu->param.value = IW_AUTH_CIPHER_WEP104;
break;
case eCSR_ENCRYPT_TYPE_AES:
wrqu->param.value = IW_AUTH_CIPHER_CCMP;
break;
default:
hdd_warn("called with unknown auth type %d",
pRoamProfile->negotiatedUCEncryptionType);
return -EIO;
}
}
if (((wrqu->param.flags & IW_AUTH_INDEX) == IW_AUTH_CIPHER_GROUP)) {
switch (pRoamProfile->negotiatedMCEncryptionType) {
case eCSR_ENCRYPT_TYPE_NONE:
wrqu->param.value = IW_AUTH_CIPHER_NONE;
break;
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
wrqu->param.value = IW_AUTH_CIPHER_WEP40;
break;
case eCSR_ENCRYPT_TYPE_TKIP:
wrqu->param.value = IW_AUTH_CIPHER_TKIP;
break;
case eCSR_ENCRYPT_TYPE_WEP104:
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
wrqu->param.value = IW_AUTH_CIPHER_WEP104;
break;
case eCSR_ENCRYPT_TYPE_AES:
wrqu->param.value = IW_AUTH_CIPHER_CCMP;
break;
default:
hdd_err("called with unknown auth type %d",
pRoamProfile->negotiatedMCEncryptionType);
return -EIO;
}
}
hdd_debug("called with auth type %d",
pRoamProfile->AuthType.authType[0]);
EXIT();
return 0;
}
/**
* iw_get_auth() - get auth callback function
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure.
*/
int iw_get_auth(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
cds_ssr_protect(__func__);
ret = __iw_get_auth(dev, info, wrqu, extra);
cds_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_ap_address() - set ap address
* @dev: pointer to the net device
* @info: pointer to the iw request info
* @wrqu: pointer to iwreq_data
* @extra: pointer to the data
*
* This function updates the HDD global station context connection info
* BSSID with the MAC address received from the wpa_supplicant.
*
* Return: 0 on success, error number otherwise
*/
static int __iw_set_ap_address(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *adapter;
hdd_context_t *hdd_ctx;
hdd_station_ctx_t *pHddStaCtx =
WLAN_HDD_GET_STATION_CTX_PTR(WLAN_HDD_GET_PRIV_PTR(dev));
uint8_t *pMacAddress = NULL;
int ret;
ENTER_DEV(dev);
adapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
ret = hdd_check_standard_wext_control(hdd_ctx, info);
if (0 != ret)
return ret;
pMacAddress = (uint8_t *) wrqu->ap_addr.sa_data;
hdd_debug(" " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pMacAddress));
qdf_mem_copy(pHddStaCtx->conn_info.bssId.bytes, pMacAddress,
sizeof(struct qdf_mac_addr));
EXIT();
return 0;
}
/**
* iw_set_ap_address() - set ap addresses callback function
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure.
*/
int iw_set_ap_address(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
cds_ssr_protect(__func__);
ret = __iw_set_ap_address(dev, info, wrqu, extra);
cds_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_ap_address() - get ap address
* @dev: pointer to the net device
* @info: pointer to the iw request info
* @wrqu: pointer to iwreq_data
* @extra: pointer to the data
*
* This function returns currently associated BSSID.
*
* Return: 0 on success, error number otherwise
*/
static int __iw_get_ap_address(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
hdd_station_ctx_t *pHddStaCtx =
WLAN_HDD_GET_STATION_CTX_PTR(adapter);
int ret;
ENTER_DEV(dev);
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
ret = hdd_check_standard_wext_control(hdd_ctx, info);
if (0 != ret)
return ret;
if (pHddStaCtx->conn_info.connState == eConnectionState_Associated ||
eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState) {
qdf_mem_copy(wrqu->ap_addr.sa_data,
pHddStaCtx->conn_info.bssId.bytes,
QDF_MAC_ADDR_SIZE);
} else {
memset(wrqu->ap_addr.sa_data, 0, sizeof(wrqu->ap_addr.sa_data));
}
EXIT();
return 0;
}
/**
* iw_get_ap_address() - get ap addresses callback function
* @dev: Pointer to the net device.
* @info: Pointer to the iw_request_info.
* @wrqu: Pointer to the iwreq_data.
* @extra: Pointer to the data.
*
* Return: 0 for success, error number on failure.
*/
int iw_get_ap_address(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
cds_ssr_protect(__func__);
ret = __iw_get_ap_address(dev, info, wrqu, extra);
cds_ssr_unprotect(__func__);
return ret;
}