blob: eea8cbd2fb27c350cc61c46b0ebeed120c0cfddf [file] [log] [blame]
/*
* Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/** ------------------------------------------------------------------------- *
------------------------------------------------------------------------- *
\file csr_util.c
Implementation supporting routines for CSR.
========================================================================== */
#include "ani_global.h"
#include "csr_support.h"
#include "csr_inside_api.h"
#include "sms_debug.h"
#include "sme_qos_internal.h"
#include "wma_types.h"
#include "cds_utils.h"
uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE] = {
{0x00, 0x50, 0xf2, 0x00}
,
{0x00, 0x50, 0xf2, 0x01}
,
{0x00, 0x50, 0xf2, 0x02}
,
{0x00, 0x50, 0xf2, 0x03}
,
{0x00, 0x50, 0xf2, 0x04}
,
{0x00, 0x50, 0xf2, 0x05}
,
#ifdef FEATURE_WLAN_ESE
{0x00, 0x40, 0x96, 0x00}
, /* CCKM */
#endif /* FEATURE_WLAN_ESE */
};
uint8_t csr_rsn_oui[][CSR_RSN_OUI_SIZE] = {
{0x00, 0x0F, 0xAC, 0x00}
, /* group cipher */
{0x00, 0x0F, 0xAC, 0x01}
, /* WEP-40 or RSN */
{0x00, 0x0F, 0xAC, 0x02}
, /* TKIP or RSN-PSK */
{0x00, 0x0F, 0xAC, 0x03}
, /* Reserved */
{0x00, 0x0F, 0xAC, 0x04}
, /* AES-CCMP */
{0x00, 0x0F, 0xAC, 0x05}
, /* WEP-104 */
{0x00, 0x40, 0x96, 0x00}
, /* CCKM */
{0x00, 0x0F, 0xAC, 0x06}
, /* BIP (encryption type) or
RSN-PSK-SHA256 (authentication type) */
/* RSN-8021X-SHA256 (authentication type) */
{0x00, 0x0F, 0xAC, 0x05}
};
#ifdef FEATURE_WLAN_WAPI
uint8_t csr_wapi_oui[][CSR_WAPI_OUI_SIZE] = {
{0x00, 0x14, 0x72, 0x00}
, /* Reserved */
{0x00, 0x14, 0x72, 0x01}
, /* WAI certificate or SMS4 */
{0x00, 0x14, 0x72, 0x02} /* WAI PSK */
};
#endif /* FEATURE_WLAN_WAPI */
uint8_t csr_wme_info_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 };
uint8_t csr_wme_parm_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 };
/* ////////////////////////////////////////////////////////////////////// */
/**
* \var g_phy_rates_suppt
*
* \brief Rate support lookup table
*
*
* This is a lookup table indexing rates & configuration parameters to
* support. Given a rate (in unites of 0.5Mpbs) & three bools (MIMO
* Enabled, Channel Bonding Enabled, & Concatenation Enabled), one can
* determine whether the given rate is supported by computing two
* indices. The first maps the rate to table row as indicated below
* (i.e. eHddSuppRate_6Mbps maps to row zero, eHddSuppRate_9Mbps to row
* 1, and so on). Index two can be computed like so:
*
* \code
* idx2 = ( fEsf ? 0x4 : 0x0 ) |
* ( fCb ? 0x2 : 0x0 ) |
* ( fMimo ? 0x1 : 0x0 );
* \endcode
*
*
* Given that:
*
* \code
* fSupported = g_phy_rates_suppt[idx1][idx2];
* \endcode
*
*
* This table is based on the document "PHY Supported Rates.doc". This
* table is permissive in that a rate is reflected as being supported
* even when turning off an enabled feature would be required. For
* instance, "PHY Supported Rates" lists 42Mpbs as unsupported when CB,
* ESF, & MIMO are all on. However, if we turn off either of CB or
* MIMO, it then becomes supported. Therefore, we mark it as supported
* even in index 7 of this table.
*
*
*/
static const bool g_phy_rates_suppt[24][8] = {
/* SSF SSF SSF SSF ESF ESF ESF ESF */
/* SIMO MIMO SIMO MIMO SIMO MIMO SIMO MIMO */
/* No CB No CB CB CB No CB No CB CB CB */
{true, true, true, true, true, true, true, true}, /* 6Mbps */
{true, true, true, true, true, true, true, true}, /* 9Mbps */
{true, true, true, true, true, true, true, true}, /* 12Mbps */
{true, true, true, true, true, true, true, true}, /* 18Mbps */
{false, false, true, true, false, false, true, true}, /* 20Mbps */
{true, true, true, true, true, true, true, true}, /* 24Mbps */
{true, true, true, true, true, true, true, true}, /* 36Mbps */
{false, false, true, true, false, true, true, true}, /* 40Mbps */
{false, false, true, true, false, true, true, true}, /* 42Mbps */
{true, true, true, true, true, true, true, true}, /* 48Mbps */
{true, true, true, true, true, true, true, true}, /* 54Mbps */
{false, true, true, true, false, true, true, true}, /* 72Mbps */
{false, false, true, true, false, true, true, true}, /* 80Mbps */
{false, false, true, true, false, true, true, true}, /* 84Mbps */
{false, true, true, true, false, true, true, true}, /* 96Mbps */
{false, true, true, true, false, true, true, true}, /* 108Mbps */
{false, false, true, true, false, true, true, true}, /* 120Mbps */
{false, false, true, true, false, true, true, true}, /* 126Mbps */
{false, false, false, true, false, false, false, true}, /* 144Mbps */
{false, false, false, true, false, false, false, true}, /* 160Mbps */
{false, false, false, true, false, false, false, true}, /* 168Mbps */
{false, false, false, true, false, false, false, true}, /* 192Mbps */
{false, false, false, true, false, false, false, true}, /* 216Mbps */
{false, false, false, true, false, false, false, true}, /* 240Mbps */
};
#define CASE_RETURN_STR(n) {\
case (n): return (# n);\
}
const char *get_e_roam_cmd_status_str(eRoamCmdStatus val)
{
switch (val) {
CASE_RETURN_STR(eCSR_ROAM_CANCELLED);
CASE_RETURN_STR(eCSR_ROAM_ROAMING_START);
CASE_RETURN_STR(eCSR_ROAM_ROAMING_COMPLETION);
CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_START);
CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_COMPLETION);
CASE_RETURN_STR(eCSR_ROAM_DISASSOCIATED);
CASE_RETURN_STR(eCSR_ROAM_SHOULD_ROAM);
CASE_RETURN_STR(eCSR_ROAM_SCAN_FOUND_NEW_BSS);
CASE_RETURN_STR(eCSR_ROAM_LOSTLINK);
default:
return "unknown";
}
}
const char *get_e_csr_roam_result_str(eCsrRoamResult val)
{
switch (val) {
CASE_RETURN_STR(eCSR_ROAM_RESULT_NONE);
CASE_RETURN_STR(eCSR_ROAM_RESULT_FAILURE);
CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOCIATED);
CASE_RETURN_STR(eCSR_ROAM_RESULT_NOT_ASSOCIATED);
CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_FAILURE);
CASE_RETURN_STR(eCSR_ROAM_RESULT_FORCED);
CASE_RETURN_STR(eCSR_ROAM_RESULT_DISASSOC_IND);
CASE_RETURN_STR(eCSR_ROAM_RESULT_DEAUTH_IND);
CASE_RETURN_STR(eCSR_ROAM_RESULT_CAP_CHANGED);
CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_CONNECT);
CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_INACTIVE);
CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_NEW_PEER);
CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_COALESCED);
default:
return "unknown";
}
}
bool csr_get_bss_id_bss_desc(tHalHandle hHal, tSirBssDescription *pSirBssDesc,
struct cdf_mac_addr *pBssId)
{
cdf_mem_copy(pBssId, &pSirBssDesc->bssId[0],
sizeof(struct cdf_mac_addr));
return true;
}
bool csr_is_bss_id_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1,
tSirBssDescription *pSirBssDesc2)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
bool fEqual = false;
struct cdf_mac_addr bssId1;
struct cdf_mac_addr bssId2;
do {
if (!pSirBssDesc1)
break;
if (!pSirBssDesc2)
break;
if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc1, &bssId1))
break;
if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc2, &bssId2))
break;
fEqual = cdf_is_macaddr_equal(&bssId1, &bssId2);
} while (0);
return fEqual;
}
bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, uint32_t sessionId)
{
return eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED ==
pMac->roam.roamSession[sessionId].connectState;
}
bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac,
uint32_t sessionId)
{
return eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED ==
pMac->roam.roamSession[sessionId].connectState;
}
bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, uint32_t sessionId)
{
return eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED ==
pMac->roam.roamSession[sessionId].connectState;
}
bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId)
{
if (csr_is_conn_state_connected_ibss(pMac, sessionId)
|| csr_is_conn_state_connected_infra(pMac, sessionId)
|| csr_is_conn_state_connected_wds(pMac, sessionId))
return true;
else
return false;
}
bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId)
{
return csr_is_conn_state_connected_infra(pMac, sessionId);
}
bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId)
{
return csr_is_conn_state_connected_ibss(pMac, sessionId) ||
csr_is_conn_state_disconnected_ibss(pMac, sessionId);
}
bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, uint32_t sessionId)
{
return eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED ==
pMac->roam.roamSession[sessionId].connectState;
}
bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac,
uint32_t sessionId)
{
return (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED ==
pMac->roam.roamSession[sessionId].connectState) ||
(eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED ==
pMac->roam.roamSession[sessionId].connectState);
}
bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, uint32_t sessionId)
{
return eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED ==
pMac->roam.roamSession[sessionId].connectState;
}
bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId)
{
return csr_is_conn_state_connected_wds(pMac, sessionId) ||
csr_is_conn_state_disconnected_wds(pMac, sessionId);
}
bool csr_is_conn_state_ap(tpAniSirGlobal pMac, uint32_t sessionId)
{
tCsrRoamSession *pSession;
pSession = CSR_GET_SESSION(pMac, sessionId);
if (!pSession)
return false;
if (CSR_IS_INFRA_AP(&pSession->connectedProfile))
return true;
return false;
}
bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac)
{
uint32_t i;
bool fRc = false;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i) &&
(csr_is_conn_state_infra(pMac, i)
|| csr_is_conn_state_ibss(pMac, i)
|| csr_is_conn_state_ap(pMac, i))) {
fRc = true;
break;
}
}
return fRc;
}
int8_t csr_get_infra_session_id(tpAniSirGlobal pMac)
{
uint8_t i;
int8_t sessionid = -1;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& csr_is_conn_state_infra(pMac, i)) {
sessionid = i;
break;
}
}
return sessionid;
}
uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId)
{
uint8_t channel;
if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
channel =
pMac->roam.roamSession[sessionId].connectedProfile.
operationChannel;
} else {
channel = 0;
}
return channel;
}
bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, uint8_t sessionId)
{
tCsrRoamSession *pSession = NULL;
if (CSR_IS_SESSION_VALID(pMac, sessionId)
&& csr_is_conn_state_infra(pMac, sessionId)) {
pSession = CSR_GET_SESSION(pMac, sessionId);
if (NULL != pSession->pCurRoamProfile) {
if ((pSession->pCurRoamProfile->csrPersona ==
CDF_STA_MODE)
|| (pSession->pCurRoamProfile->csrPersona ==
CDF_P2P_CLIENT_MODE))
return true;
}
}
return false;
}
/**
* csr_get_concurrent_operation_channel() - To get concurrent operating channel
* @mac_ctx: Pointer to mac context
*
* This routine will return operating channel on FIRST BSS that is
* active/operating to be used for concurrency mode.
* If other BSS is not up or not connected it will return 0
*
* Return: uint8_t
*/
uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal mac_ctx)
{
tCsrRoamSession *session = NULL;
uint8_t i = 0;
tCDF_CON_MODE persona;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (!CSR_IS_SESSION_VALID(mac_ctx, i))
continue;
session = CSR_GET_SESSION(mac_ctx, i);
if (NULL == session->pCurRoamProfile)
continue;
persona = session->pCurRoamProfile->csrPersona;
if ((((persona == CDF_STA_MODE) ||
(persona == CDF_P2P_CLIENT_MODE)) &&
(session->connectState ==
eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) ||
(((persona == CDF_P2P_GO_MODE) ||
(persona == CDF_SAP_MODE))
&& (session->connectState !=
eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)))
return session->connectedProfile.operationChannel;
}
return 0;
}
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
#define HALF_BW_OF(eCSR_bw_val) ((eCSR_bw_val)/2)
/* calculation of center channel based on V/HT BW and WIFI channel bw=5MHz) */
#define CSR_GET_HT40_PLUS_CCH(och) ((och)+2)
#define CSR_GET_HT40_MINUS_CCH(och) ((och)-2)
#define CSR_GET_HT80_PLUS_LL_CCH(och) ((och)+6)
#define CSR_GET_HT80_PLUS_HL_CCH(och) ((och)+2)
#define CSR_GET_HT80_MINUS_LH_CCH(och) ((och)-2)
#define CSR_GET_HT80_MINUS_HH_CCH(och) ((och)-6)
/**
* csr_get_ch_from_ht_profile() - to get channel from HT profile
* @pMac: pointer to Mac context
* @htp: pointer to HT profile
* @och: operating channel
* @cfreq: channel frequency
* @hbw: half bandwidth
*
* This function will fill half bandwidth and channel frequency based
* on the HT profile
*
* Return: none
*/
void csr_get_ch_from_ht_profile(tpAniSirGlobal pMac, tCsrRoamHTProfile *htp,
uint16_t och, uint16_t *cfreq, uint16_t *hbw)
{
uint16_t cch, ch_bond;
if (och > 14)
ch_bond = pMac->roam.configParam.channelBondingMode5GHz;
else
ch_bond = pMac->roam.configParam.channelBondingMode24GHz;
cch = och;
*hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
if (!ch_bond)
goto ret;
sms_log(pMac, LOG1, FL("##HTC: %d scbw: %d rcbw: %d sco: %d"
#ifdef WLAN_FEATURE_11AC
"VHTC: %d apc: %d apbw: %d"
#endif
),
htp->htCapability, htp->htSupportedChannelWidthSet,
htp->htRecommendedTxWidthSet,
htp->htSecondaryChannelOffset,
#ifdef WLAN_FEATURE_11AC
htp->vhtCapability, htp->apCenterChan, htp->apChanWidth
#endif
);
#ifdef WLAN_FEATURE_11AC
if (htp->vhtCapability) {
cch = htp->apCenterChan;
if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ)
*hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL);
else if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ)
*hbw = HALF_BW_OF(eCSR_BW_160MHz_VAL);
if (!*hbw && htp->htCapability) {
if (htp->htSupportedChannelWidthSet ==
eHT_CHANNEL_WIDTH_40MHZ)
*hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
else
*hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
}
} else
#endif
if (htp->htCapability) {
if (htp->htSupportedChannelWidthSet ==
eHT_CHANNEL_WIDTH_40MHZ) {
*hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
if (htp->htSecondaryChannelOffset ==
PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
cch = CSR_GET_HT40_PLUS_CCH(och);
else if (htp->htSecondaryChannelOffset ==
PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
cch = CSR_GET_HT40_MINUS_CCH(och);
} else {
cch = och;
*hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
}
}
ret:
*cfreq = cds_chan_to_freq(cch);
return;
}
/**
* csr_calc_chb_for_sap_phymode() - to calc channel bandwidth for sap phymode
* @mac_ctx: pointer to mac context
* @sap_ch: SAP operating channel
* @sap_phymode: SAP physical mode
* @sap_cch: concurrency channel
* @sap_hbw: SAP half bw
* @chb: channel bandwidth
*
* This routine is called to calculate channel bandwidth
*
* Return: none
*/
static void csr_calc_chb_for_sap_phymode(tpAniSirGlobal mac_ctx,
uint16_t *sap_ch, eCsrPhyMode *sap_phymode,
uint16_t *sap_cch, uint16_t *sap_hbw, uint8_t *chb)
{
if (*sap_phymode == eCSR_DOT11_MODE_11n ||
*sap_phymode == eCSR_DOT11_MODE_11n_ONLY) {
*sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
if (*chb == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
*sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch);
else if (*chb == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
*sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch);
}
#ifdef WLAN_FEATURE_11AC
else if (*sap_phymode == eCSR_DOT11_MODE_11ac ||
*sap_phymode == eCSR_DOT11_MODE_11ac_ONLY) {
/*11AC only 80/40/20 Mhz supported in Rome */
if (mac_ctx->roam.configParam.nVhtChannelWidth ==
(WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1)) {
*sap_hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL);
if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1))
*sap_cch = CSR_GET_HT80_PLUS_LL_CCH(*sap_ch);
else if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW
- 1))
*sap_cch = CSR_GET_HT80_PLUS_HL_CCH(*sap_ch);
else if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH
- 1))
*sap_cch = CSR_GET_HT80_MINUS_LH_CCH(*sap_ch);
else if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH
- 1))
*sap_cch = CSR_GET_HT80_MINUS_HH_CCH(*sap_ch);
} else {
*sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
if (*chb == (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW
- 1))
*sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch);
else if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW
- 1))
*sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch);
else if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH
- 1))
*sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch);
else if (*chb ==
(PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH
- 1))
*sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch);
}
}
#endif
}
/**
* csr_handle_conc_chnl_overlap_for_sap_go - To handle overlap for AP+AP
* @mac_ctx: pointer to mac context
* @session: Current session
* @sap_ch: SAP/GO operating channel
* @sap_hbw: SAP/GO half bw
* @sap_cfreq: SAP/GO channel frequency
* @intf_ch: concurrent SAP/GO operating channel
* @intf_hbw: concurrent SAP/GO half bw
* @intf_cfreq: concurrent SAP/GO channel frequency
*
* This routine is called to check if one SAP/GO channel is overlapping with
* other SAP/GO channel
*
* Return: none
*/
static void csr_handle_conc_chnl_overlap_for_sap_go(tpAniSirGlobal mac_ctx,
tCsrRoamSession *session,
uint16_t *sap_ch, uint16_t *sap_hbw, uint16_t *sap_cfreq,
uint16_t *intf_ch, uint16_t *intf_hbw, uint16_t *intf_cfreq)
{
/*
* if conc_custom_rule1 is defined then we don't
* want p2pgo to follow SAP's channel or SAP to
* follow P2PGO's channel.
*/
if (0 == mac_ctx->roam.configParam.conc_custom_rule1 &&
0 == mac_ctx->roam.configParam.conc_custom_rule2) {
if (*sap_ch == 0) {
*sap_ch = session->connectedProfile.operationChannel;
csr_get_ch_from_ht_profile(mac_ctx,
&session->connectedProfile.HTProfile,
*sap_ch, sap_cfreq, sap_hbw);
} else if (*sap_ch !=
session->connectedProfile.operationChannel) {
*intf_ch = session->connectedProfile.operationChannel;
csr_get_ch_from_ht_profile(mac_ctx,
&session->connectedProfile.HTProfile,
*intf_ch, intf_cfreq, intf_hbw);
}
} else if (*sap_ch == 0 &&
(session->pCurRoamProfile->csrPersona ==
CDF_SAP_MODE)) {
*sap_ch = session->connectedProfile.operationChannel;
csr_get_ch_from_ht_profile(mac_ctx,
&session->connectedProfile.HTProfile,
*sap_ch, sap_cfreq, sap_hbw);
}
}
/**
* csr_check_concurrent_channel_overlap() - To check concurrent overlap chnls
* @mac_ctx: Pointer to mac context
* @sap_ch: SAP channel
* @sap_phymode: SAP phy mode
* @cc_switch_mode: concurrent switch mode
*
* This routine will be called to check concurrent overlap channels
*
* Return: uint16_t
*/
uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal mac_ctx,
uint16_t sap_ch, eCsrPhyMode sap_phymode,
uint8_t cc_switch_mode)
{
tCsrRoamSession *session = NULL;
uint8_t i = 0, chb = PHY_SINGLE_CHANNEL_CENTERED;
uint16_t intf_ch = 0, sap_hbw = 0, intf_hbw = 0, intf_cfreq = 0;
uint16_t sap_cfreq = 0;
uint16_t sap_lfreq, sap_hfreq, intf_lfreq, intf_hfreq, sap_cch;
if (mac_ctx->roam.configParam.cc_switch_mode ==
CDF_MCC_TO_SCC_SWITCH_DISABLE)
return 0;
if (sap_ch != 0) {
sap_cch = sap_ch;
sap_hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
if (sap_ch > 14)
chb = mac_ctx->roam.configParam.channelBondingMode5GHz;
else
chb = mac_ctx->roam.configParam.channelBondingMode24GHz;
if (chb)
csr_calc_chb_for_sap_phymode(mac_ctx, &sap_ch,
&sap_phymode, &sap_cch, &sap_hbw, &chb);
sap_cfreq = cds_chan_to_freq(sap_cch);
}
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (!CSR_IS_SESSION_VALID(mac_ctx, i))
continue;
session = CSR_GET_SESSION(mac_ctx, i);
if (NULL == session->pCurRoamProfile)
continue;
if (((session->pCurRoamProfile->csrPersona == CDF_STA_MODE) ||
(session->pCurRoamProfile->csrPersona ==
CDF_P2P_CLIENT_MODE)) &&
(session->connectState ==
eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) {
intf_ch = session->connectedProfile.operationChannel;
csr_get_ch_from_ht_profile(mac_ctx,
&session->connectedProfile.HTProfile,
intf_ch, &intf_cfreq, &intf_hbw);
} else if (((session->pCurRoamProfile->csrPersona ==
CDF_P2P_GO_MODE) ||
(session->pCurRoamProfile->csrPersona ==
CDF_SAP_MODE)) &&
(session->connectState !=
eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
csr_handle_conc_chnl_overlap_for_sap_go(mac_ctx,
session, &sap_ch, &sap_hbw, &sap_cfreq,
&intf_ch, &intf_hbw, &intf_cfreq);
}
}
if (intf_ch && sap_ch != intf_ch &&
cc_switch_mode != CDF_MCC_TO_SCC_SWITCH_FORCE) {
sap_lfreq = sap_cfreq - sap_hbw;
sap_hfreq = sap_cfreq + sap_hbw;
intf_lfreq = intf_cfreq - intf_hbw;
intf_hfreq = intf_cfreq + intf_hbw;
sms_log(mac_ctx, LOGE,
FL("\nSAP: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d\n"
"INTF: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d"),
sap_ch, cds_chan_to_freq(sap_ch),
cds_freq_to_chan(sap_cfreq), sap_cfreq, sap_hbw * 2,
sap_lfreq, sap_hfreq, intf_ch,
cds_chan_to_freq(intf_ch), cds_freq_to_chan(intf_cfreq),
intf_cfreq, intf_hbw * 2, intf_lfreq, intf_hfreq);
if (!(((sap_lfreq > intf_lfreq && sap_lfreq < intf_hfreq) ||
(sap_hfreq > intf_lfreq && sap_hfreq < intf_hfreq)) ||
((intf_lfreq > sap_lfreq && intf_lfreq < sap_hfreq) ||
(intf_hfreq > sap_lfreq && intf_hfreq < sap_hfreq))))
intf_ch = 0;
} else if (intf_ch && sap_ch != intf_ch &&
cc_switch_mode == CDF_MCC_TO_SCC_SWITCH_FORCE) {
if (!((intf_ch < 14 && sap_ch < 14) ||
(intf_ch > 14 && sap_ch > 14)))
intf_ch = 0;
} else if (intf_ch == sap_ch) {
intf_ch = 0;
}
sms_log(mac_ctx, LOGE, FL("##Concurrent Channels %s Interfering"),
intf_ch == 0 ? "Not" : "Are");
return intf_ch;
}
#endif
bool csr_is_all_session_disconnected(tpAniSirGlobal pMac)
{
uint32_t i;
bool fRc = true;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& !csr_is_conn_state_disconnected(pMac, i)) {
fRc = false;
break;
}
}
return fRc;
}
/**
* csr_is_sta_session_connected() - to find if concurrent sta is active
* @mac_ctx: pointer to mac context
*
* This function will iterate through each session and check if sta
* session exist and active
*
* Return: true or false
*/
bool csr_is_sta_session_connected(tpAniSirGlobal mac_ctx)
{
uint32_t i;
tCsrRoamSession *pSession = NULL;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(mac_ctx, i) &&
!csr_is_conn_state_disconnected(mac_ctx, i)) {
pSession = CSR_GET_SESSION(mac_ctx, i);
if ((NULL != pSession->pCurRoamProfile) &&
(CDF_STA_MODE ==
pSession->pCurRoamProfile->csrPersona))
return true;
}
}
return false;
}
/**
* csr_is_p2p_session_connected() - to find if any p2p session is active
* @mac_ctx: pointer to mac context
*
* This function will iterate through each session and check if any p2p
* session exist and active
*
* Return: true or false
*/
bool csr_is_p2p_session_connected(tpAniSirGlobal pMac)
{
uint32_t i;
tCsrRoamSession *pSession = NULL;
tCDF_CON_MODE persona;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& !csr_is_conn_state_disconnected(pMac, i)) {
pSession = CSR_GET_SESSION(pMac, i);
persona = pSession->pCurRoamProfile->csrPersona;
if ((NULL != pSession->pCurRoamProfile) &&
((CDF_P2P_CLIENT_MODE == persona) ||
(CDF_P2P_GO_MODE == persona))) {
return true;
}
}
}
return false;
}
bool csr_is_any_session_connected(tpAniSirGlobal pMac)
{
uint32_t i, count;
bool fRc = false;
count = 0;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& !csr_is_conn_state_disconnected(pMac, i))
count++;
}
if (count > 0)
fRc = true;
return fRc;
}
bool csr_is_infra_connected(tpAniSirGlobal pMac)
{
uint32_t i;
bool fRc = false;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& csr_is_conn_state_connected_infra(pMac, i)) {
fRc = true;
break;
}
}
return fRc;
}
bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac)
{
uint32_t i, noOfConnectedInfra = 0;
bool fRc = false;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& csr_is_conn_state_connected_infra(pMac, i)) {
++noOfConnectedInfra;
}
}
/* More than one Infra Sta Connected */
if (noOfConnectedInfra > 1)
fRc = true;
return fRc;
}
bool csr_is_ibss_started(tpAniSirGlobal pMac)
{
uint32_t i;
bool fRc = false;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& csr_is_conn_state_ibss(pMac, i)) {
fRc = true;
break;
}
}
return fRc;
}
bool csr_is_btamp_started(tpAniSirGlobal pMac)
{
uint32_t i;
bool fRc = false;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& csr_is_conn_state_connected_wds(pMac, i)) {
fRc = true;
break;
}
}
return fRc;
}
bool csr_is_concurrent_session_running(tpAniSirGlobal pMac)
{
uint32_t sessionId, noOfCocurrentSession = 0;
eCsrConnectState connectState;
bool fRc = false;
for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
connectState =
pMac->roam.roamSession[sessionId].connectState;
if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED ==
connectState)
|| (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED ==
connectState)
|| (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED ==
connectState)) {
++noOfCocurrentSession;
}
}
}
/* More than one session is Up and Running */
if (noOfCocurrentSession > 1)
fRc = true;
return fRc;
}
bool csr_is_infra_ap_started(tpAniSirGlobal pMac)
{
uint32_t sessionId;
bool fRc = false;
for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
if (CSR_IS_SESSION_VALID(pMac, sessionId)
&& (csr_is_conn_state_connected_infra_ap(pMac, sessionId))) {
fRc = true;
break;
}
}
return fRc;
}
bool csr_is_btamp(tpAniSirGlobal pMac, uint32_t sessionId)
{
return csr_is_conn_state_connected_wds(pMac, sessionId);
}
bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId)
{
return eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED ==
pMac->roam.roamSession[sessionId].connectState;
}
/**
* csr_is_valid_mc_concurrent_session() - To check concurren session is valid
* @mac_ctx: pointer to mac context
* @session_id: session id
* @bss_descr: bss description
*
* This function validates the concurrent session
*
* Return: true or false
*/
bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal mac_ctx,
uint32_t session_id,
tSirBssDescription *bss_descr)
{
tCsrRoamSession *pSession = NULL;
/* Check for MCC support */
if (!mac_ctx->roam.configParam.fenableMCCMode)
return false;
if (!CSR_IS_SESSION_VALID(mac_ctx, session_id))
return false;
/* Validate BeaconInterval */
pSession = CSR_GET_SESSION(mac_ctx, session_id);
if (NULL == pSession->pCurRoamProfile)
return false;
if (CDF_STATUS_SUCCESS ==
csr_isconcurrentsession_valid(mac_ctx, session_id,
pSession->pCurRoamProfile->csrPersona)) {
if (CDF_STATUS_SUCCESS ==
csr_validate_mcc_beacon_interval(mac_ctx,
bss_descr->channelId,
&bss_descr->beaconInterval, session_id,
pSession->pCurRoamProfile->csrPersona))
return true;
}
return false;
}
static tSirMacCapabilityInfo csr_get_bss_capabilities(tSirBssDescription *
pSirBssDesc)
{
tSirMacCapabilityInfo dot11Caps;
/* tSirMacCapabilityInfo is 16-bit */
cdf_get_u16((uint8_t *) &pSirBssDesc->capabilityInfo,
(uint16_t *) &dot11Caps);
return dot11Caps;
}
bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc)
{
tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
return (bool) dot11Caps.ess;
}
bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc)
{
tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
return (bool) dot11Caps.ibss;
}
bool csr_is_qo_s_bss_desc(tSirBssDescription *pSirBssDesc)
{
tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
return (bool) dot11Caps.qos;
}
bool csr_is_privacy(tSirBssDescription *pSirBssDesc)
{
tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
return (bool) dot11Caps.privacy;
}
bool csr_is11d_supported(tpAniSirGlobal pMac)
{
return pMac->roam.configParam.Is11dSupportEnabled;
}
bool csr_is11h_supported(tpAniSirGlobal pMac)
{
return pMac->roam.configParam.Is11hSupportEnabled;
}
bool csr_is11e_supported(tpAniSirGlobal pMac)
{
return pMac->roam.configParam.Is11eSupportEnabled;
}
bool csr_is_mcc_supported(tpAniSirGlobal pMac)
{
return pMac->roam.configParam.fenableMCCMode;
}
bool csr_is_wmm_supported(tpAniSirGlobal pMac)
{
if (eCsrRoamWmmNoQos == pMac->roam.configParam.WMMSupportMode)
return false;
else
return true;
}
/* pIes is the IEs for pSirBssDesc2 */
bool csr_is_ssid_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1,
tSirBssDescription *pSirBssDesc2, tDot11fBeaconIEs *pIes2)
{
bool fEqual = false;
tSirMacSSid Ssid1, Ssid2;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
tDot11fBeaconIEs *pIes1 = NULL;
tDot11fBeaconIEs *pIesLocal = pIes2;
do {
if ((NULL == pSirBssDesc1) || (NULL == pSirBssDesc2))
break;
if (!pIesLocal
&&
!CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies
(pMac, pSirBssDesc2,
&pIesLocal))) {
sms_log(pMac, LOGE, FL(" fail to parse IEs"));
break;
}
if (!CDF_IS_STATUS_SUCCESS
(csr_get_parsed_bss_description_ies(pMac,
pSirBssDesc1, &pIes1))) {
break;
}
if ((!pIes1->SSID.present) || (!pIesLocal->SSID.present))
break;
if (pIes1->SSID.num_ssid != pIesLocal->SSID.num_ssid)
break;
cdf_mem_copy(Ssid1.ssId, pIes1->SSID.ssid,
pIes1->SSID.num_ssid);
cdf_mem_copy(Ssid2.ssId, pIesLocal->SSID.ssid,
pIesLocal->SSID.num_ssid);
fEqual =
cdf_mem_compare(Ssid1.ssId, Ssid2.ssId,
pIesLocal->SSID.num_ssid);
} while (0);
if (pIes1)
cdf_mem_free(pIes1);
if (pIesLocal && !pIes2)
cdf_mem_free(pIesLocal);
return fEqual;
}
/* pIes can be passed in as NULL if the caller doesn't have one prepared */
bool csr_is_bss_description_wme(tHalHandle hHal, tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
/* Assume that WME is found... */
bool fWme = true;
tDot11fBeaconIEs *pIesTemp = pIes;
do {
if (pIesTemp == NULL) {
if (!CDF_IS_STATUS_SUCCESS
(csr_get_parsed_bss_description_ies
(pMac, pSirBssDesc, &pIesTemp))) {
fWme = false;
break;
}
}
/* if the Wme Info IE is found, then WME is supported... */
if (CSR_IS_QOS_BSS(pIesTemp))
break;
/* if none of these are found, then WME is NOT supported... */
fWme = false;
} while (0);
if (!csr_is_wmm_supported(pMac) && fWme) {
if (!pIesTemp->HTCaps.present) {
fWme = false;
}
}
if ((pIes == NULL) && (NULL != pIesTemp)) {
/* we allocate memory here so free it before returning */
cdf_mem_free(pIesTemp);
}
return fWme;
}
eCsrMediaAccessType csr_get_qo_s_from_bss_desc(tHalHandle hHal,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes)
{
eCsrMediaAccessType qosType = eCSR_MEDIUM_ACCESS_DCF;
if (NULL == pIes) {
CDF_ASSERT(pIes != NULL);
return qosType;
}
do {
/* if we find WMM in the Bss Description, then we let this */
/* override and use WMM. */
if (csr_is_bss_description_wme(hHal, pSirBssDesc, pIes)) {
qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP;
} else {
/* if the QoS bit is on, then the AP is advertising 11E QoS... */
if (csr_is_qo_s_bss_desc(pSirBssDesc)) {
qosType = eCSR_MEDIUM_ACCESS_11e_eDCF;
} else {
qosType = eCSR_MEDIUM_ACCESS_DCF;
}
/* scale back based on the types turned on for the adapter... */
if (eCSR_MEDIUM_ACCESS_11e_eDCF == qosType
&& !csr_is11e_supported(hHal)) {
qosType = eCSR_MEDIUM_ACCESS_DCF;
}
}
} while (0);
return qosType;
}
/* Caller allocates memory for pIEStruct */
CDF_STATUS csr_parse_bss_description_ies(tHalHandle hHal,
tSirBssDescription *pBssDesc,
tDot11fBeaconIEs *pIEStruct)
{
CDF_STATUS status = CDF_STATUS_E_FAILURE;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
int ieLen =
(int)(pBssDesc->length + sizeof(pBssDesc->length) -
GET_FIELD_OFFSET(tSirBssDescription, ieFields));
if (ieLen > 0 && pIEStruct) {
if (!DOT11F_FAILED
(dot11f_unpack_beacon_i_es
(pMac, (uint8_t *) pBssDesc->ieFields, ieLen,
pIEStruct))) {
status = CDF_STATUS_SUCCESS;
}
}
return status;
}
/* This function will allocate memory for the parsed IEs to the caller. Caller must free the memory */
/* after it is done with the data only if this function succeeds */
CDF_STATUS csr_get_parsed_bss_description_ies(tHalHandle hHal,
tSirBssDescription *pBssDesc,
tDot11fBeaconIEs **ppIEStruct)
{
CDF_STATUS status = CDF_STATUS_E_INVAL;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
if (pBssDesc && ppIEStruct) {
*ppIEStruct = cdf_mem_malloc(sizeof(tDot11fBeaconIEs));
if ((*ppIEStruct) != NULL) {
cdf_mem_set((void *)*ppIEStruct,
sizeof(tDot11fBeaconIEs), 0);
status =
csr_parse_bss_description_ies(hHal, pBssDesc,
*ppIEStruct);
if (!CDF_IS_STATUS_SUCCESS(status)) {
cdf_mem_free(*ppIEStruct);
*ppIEStruct = NULL;
}
} else {
sms_log(pMac, LOGE, FL(" failed to allocate memory"));
CDF_ASSERT(0);
return CDF_STATUS_E_NOMEM;
}
}
return status;
}
bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len)
{
bool fNullSsid = false;
uint32_t SsidLength;
uint8_t *pSsidStr;
do {
if (0 == len) {
fNullSsid = true;
break;
}
/* Consider 0 or space for hidden SSID */
if (0 == pBssSsid[0]) {
fNullSsid = true;
break;
}
SsidLength = len;
pSsidStr = pBssSsid;
while (SsidLength) {
if (*pSsidStr)
break;
pSsidStr++;
SsidLength--;
}
if (0 == SsidLength) {
fNullSsid = true;
break;
}
} while (0);
return fNullSsid;
}
uint32_t csr_get_frag_thresh(tHalHandle hHal)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
return pMac->roam.configParam.FragmentationThreshold;
}
uint32_t csr_get_rts_thresh(tHalHandle hHal)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
return pMac->roam.configParam.RTSThreshold;
}
eCsrPhyMode csr_translate_to_phy_mode_from_bss_desc(tSirBssDescription *pSirBssDesc)
{
eCsrPhyMode phyMode;
switch (pSirBssDesc->nwType) {
case eSIR_11A_NW_TYPE:
phyMode = eCSR_DOT11_MODE_11a;
break;
case eSIR_11B_NW_TYPE:
phyMode = eCSR_DOT11_MODE_11b;
break;
case eSIR_11G_NW_TYPE:
phyMode = eCSR_DOT11_MODE_11g;
break;
case eSIR_11N_NW_TYPE:
phyMode = eCSR_DOT11_MODE_11n;
break;
#ifdef WLAN_FEATURE_11AC
case eSIR_11AC_NW_TYPE:
default:
phyMode = eCSR_DOT11_MODE_11ac;
#else
default:
phyMode = eCSR_DOT11_MODE_11n;
#endif
break;
}
return phyMode;
}
uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac,
eCsrCfgDot11Mode csrDot11Mode)
{
uint32_t ret;
switch (csrDot11Mode) {
case eCSR_CFG_DOT11_MODE_AUTO:
sms_log(pMac, LOGW,
FL(" Warning: sees eCSR_CFG_DOT11_MODE_AUTO "));
if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))
ret = WNI_CFG_DOT11_MODE_11AC;
else
ret = WNI_CFG_DOT11_MODE_11N;
break;
case eCSR_CFG_DOT11_MODE_11A:
ret = WNI_CFG_DOT11_MODE_11A;
break;
case eCSR_CFG_DOT11_MODE_11B:
ret = WNI_CFG_DOT11_MODE_11B;
break;
case eCSR_CFG_DOT11_MODE_11G:
ret = WNI_CFG_DOT11_MODE_11G;
break;
case eCSR_CFG_DOT11_MODE_11N:
ret = WNI_CFG_DOT11_MODE_11N;
break;
case eCSR_CFG_DOT11_MODE_11G_ONLY:
ret = WNI_CFG_DOT11_MODE_11G_ONLY;
break;
case eCSR_CFG_DOT11_MODE_11N_ONLY:
ret = WNI_CFG_DOT11_MODE_11N_ONLY;
break;
case eCSR_CFG_DOT11_MODE_11AC_ONLY:
if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))
ret = WNI_CFG_DOT11_MODE_11AC_ONLY;
else
ret = WNI_CFG_DOT11_MODE_11N;
break;
case eCSR_CFG_DOT11_MODE_11AC:
if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))
ret = WNI_CFG_DOT11_MODE_11AC;
else
ret = WNI_CFG_DOT11_MODE_11N;
break;
default:
sms_log(pMac, LOGW, FL("doesn't expect %d as csrDo11Mode"),
csrDot11Mode);
if (eCSR_BAND_24 == pMac->roam.configParam.eBand) {
ret = WNI_CFG_DOT11_MODE_11G;
} else {
ret = WNI_CFG_DOT11_MODE_11A;
}
break;
}
return ret;
}
/**
* csr_get_phy_mode_from_bss() - Get Phy Mode
* @pMac: Global MAC context
* @pBSSDescription: BSS Descriptor
* @pPhyMode: Physical Mode
* @pIes: Pointer to the IE fields
*
* This function should only return the super set of supported modes
* 11n implies 11b/g/a/n.
*
* Return: success
**/
CDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac,
tSirBssDescription *pBSSDescription,
eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes)
{
CDF_STATUS status = CDF_STATUS_SUCCESS;
eCsrPhyMode phyMode =
csr_translate_to_phy_mode_from_bss_desc(pBSSDescription);
if (pIes) {
if (pIes->HTCaps.present) {
phyMode = eCSR_DOT11_MODE_11n;
#ifdef WLAN_FEATURE_11AC
if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) ||
IS_BSS_VHT_CAPABLE(pIes->vendor2_ie.VHTCaps))
phyMode = eCSR_DOT11_MODE_11ac;
#endif
}
*pPhyMode = phyMode;
}
return status;
}
/**
* csr_get_phy_mode_in_use() - to get phymode
* @phyModeIn: physical mode
* @bssPhyMode: physical mode in bss
* @f5GhzBand: 5Ghz band
* @pCfgDot11ModeToUse: dot11 mode in use
*
* This function returns the correct eCSR_CFG_DOT11_MODE is the two phyModes
* matches. bssPhyMode is the mode derived from the BSS description
* f5GhzBand is derived from the channel id of BSS description
*
* Return: true or false
*/
bool csr_get_phy_mode_in_use(eCsrPhyMode phyModeIn, eCsrPhyMode bssPhyMode,
bool f5GhzBand, eCsrCfgDot11Mode *pCfgDot11ModeToUse)
{
bool fMatch = false;
eCsrCfgDot11Mode cfgDot11Mode;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
switch (phyModeIn) {
/* 11a or 11b or 11g */
case eCSR_DOT11_MODE_abg:
fMatch = true;
if (f5GhzBand)
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
else if (eCSR_DOT11_MODE_11b == bssPhyMode)
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
else
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
break;
case eCSR_DOT11_MODE_11a:
if (f5GhzBand) {
fMatch = true;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
}
break;
case eCSR_DOT11_MODE_11g:
if (!f5GhzBand) {
fMatch = true;
if (eCSR_DOT11_MODE_11b == bssPhyMode)
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
else
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
}
break;
case eCSR_DOT11_MODE_11g_ONLY:
if (eCSR_DOT11_MODE_11g == bssPhyMode) {
fMatch = true;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
}
break;
case eCSR_DOT11_MODE_11b:
if (!f5GhzBand) {
fMatch = true;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
}
break;
case eCSR_DOT11_MODE_11b_ONLY:
if (eCSR_DOT11_MODE_11b == bssPhyMode) {
fMatch = true;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
}
break;
case eCSR_DOT11_MODE_11n:
fMatch = true;
switch (bssPhyMode) {
case eCSR_DOT11_MODE_11g:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
break;
case eCSR_DOT11_MODE_11b:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
break;
case eCSR_DOT11_MODE_11a:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
break;
case eCSR_DOT11_MODE_11n:
#ifdef WLAN_FEATURE_11AC
case eCSR_DOT11_MODE_11ac:
#endif
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
break;
default:
#ifdef WLAN_FEATURE_11AC
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
#else
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
#endif
break;
}
break;
case eCSR_DOT11_MODE_11n_ONLY:
if ((eCSR_DOT11_MODE_11n == bssPhyMode)) {
fMatch = true;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
}
break;
#ifdef WLAN_FEATURE_11AC
case eCSR_DOT11_MODE_11ac:
fMatch = true;
switch (bssPhyMode) {
case eCSR_DOT11_MODE_11g:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
break;
case eCSR_DOT11_MODE_11b:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
break;
case eCSR_DOT11_MODE_11a:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
break;
case eCSR_DOT11_MODE_11n:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
break;
case eCSR_DOT11_MODE_11ac:
default:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
break;
}
break;
case eCSR_DOT11_MODE_11ac_ONLY:
if ((eCSR_DOT11_MODE_11ac == bssPhyMode)) {
fMatch = true;
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
}
break;
#endif
default:
fMatch = true;
switch (bssPhyMode) {
case eCSR_DOT11_MODE_11g:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
break;
case eCSR_DOT11_MODE_11b:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
break;
case eCSR_DOT11_MODE_11a:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
break;
case eCSR_DOT11_MODE_11n:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
break;
#ifdef WLAN_FEATURE_11AC
case eCSR_DOT11_MODE_11ac:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
break;
#endif
default:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO;
break;
}
break;
}
if (fMatch && pCfgDot11ModeToUse) {
#ifdef WLAN_FEATURE_11AC
if (cfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC
&& (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)))
*pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N;
else
#endif
*pCfgDot11ModeToUse = cfgDot11Mode;
}
return fMatch;
}
/**
* csr_is_phy_mode_match() - to find if phy mode matches
* @pMac: pointer to mac context
* @phyMode: physical mode
* @pSirBssDesc: bss description
* @pProfile: pointer to roam profile
* @pReturnCfgDot11Mode: dot1 mode to return
* @pIes: pointer to IEs
*
* This function decides whether the one of the bit of phyMode is matching the
* mode in the BSS and allowed by the user setting
*
* Return: true or false based on mode that fits the criteria
*/
bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode,
tSirBssDescription *pSirBssDesc,
tCsrRoamProfile *pProfile,
eCsrCfgDot11Mode *pReturnCfgDot11Mode,
tDot11fBeaconIEs *pIes)
{
bool fMatch = false;
eCsrPhyMode phyModeInBssDesc = eCSR_DOT11_MODE_AUTO, phyMode2;
eCsrCfgDot11Mode cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_AUTO;
uint32_t bitMask, loopCount;
if (!CDF_IS_STATUS_SUCCESS(csr_get_phy_mode_from_bss(pMac, pSirBssDesc,
&phyModeInBssDesc, pIes)))
return fMatch;
if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) {
if (eCSR_CFG_DOT11_MODE_ABG ==
pMac->roam.configParam.uCfgDot11Mode)
phyMode = eCSR_DOT11_MODE_abg;
else if (eCSR_CFG_DOT11_MODE_AUTO ==
pMac->roam.configParam.uCfgDot11Mode)
#ifdef WLAN_FEATURE_11AC
phyMode = eCSR_DOT11_MODE_11ac;
#else
phyMode = eCSR_DOT11_MODE_11n;
#endif
else
/* user's pick */
phyMode = pMac->roam.configParam.phyMode;
}
if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) {
if (0 != phyMode) {
if (eCSR_DOT11_MODE_AUTO & phyMode) {
phyMode2 =
eCSR_DOT11_MODE_AUTO & phyMode;
}
} else {
phyMode2 = phyMode;
}
fMatch = csr_get_phy_mode_in_use(phyMode2, phyModeInBssDesc,
CDS_IS_CHANNEL_5GHZ(pSirBssDesc->channelId),
&cfgDot11ModeToUse);
} else {
bitMask = 1;
loopCount = 0;
while (loopCount < eCSR_NUM_PHY_MODE) {
phyMode2 = (phyMode & (bitMask << loopCount++));
if (0 != phyMode2 && csr_get_phy_mode_in_use(phyMode2,
phyModeInBssDesc,
CDS_IS_CHANNEL_5GHZ
(pSirBssDesc->channelId),
&cfgDot11ModeToUse)) {
fMatch = true;
break;
}
}
}
if (fMatch && pReturnCfgDot11Mode) {
if (pProfile) {
/*
* IEEE 11n spec (8.4.3): HT STA shall
* eliminate TKIP as a choice for the pairwise
* cipher suite if CCMP is advertised by the AP
* or if the AP included an HT capabilities
* element in its Beacons and Probe Response.
*/
if ((!CSR_IS_11n_ALLOWED(
pProfile->negotiatedUCEncryptionType))
&& ((eCSR_CFG_DOT11_MODE_11N ==
cfgDot11ModeToUse) ||
#ifdef WLAN_FEATURE_11AC
(eCSR_CFG_DOT11_MODE_11AC ==
cfgDot11ModeToUse)
#endif
)) {
/* We cannot do 11n here */
if (!CDS_IS_CHANNEL_5GHZ
(pSirBssDesc->channelId)) {
cfgDot11ModeToUse =
eCSR_CFG_DOT11_MODE_11G;
} else {
cfgDot11ModeToUse =
eCSR_CFG_DOT11_MODE_11A;
}
}
}
*pReturnCfgDot11Mode = cfgDot11ModeToUse;
}
return fMatch;
}
eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode)
{
eCsrCfgDot11Mode cfgDot11ModeToUse;
eCsrBand eBand = pMac->roam.configParam.eBand;
if ((0 == phyMode) ||
#ifdef WLAN_FEATURE_11AC
(eCSR_DOT11_MODE_11ac & phyMode) ||
#endif
(eCSR_DOT11_MODE_AUTO & phyMode)) {
#ifdef WLAN_FEATURE_11AC
if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC;
} else
#endif
{
/* Default to 11N mode if user has configured 11ac mode
* and FW doesn't supports 11ac mode .
*/
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N;
}
} else {
if ((eCSR_DOT11_MODE_11n | eCSR_DOT11_MODE_11n_ONLY) & phyMode) {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N;
} else if (eCSR_DOT11_MODE_abg & phyMode) {
if (eCSR_BAND_24 != eBand) {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A;
} else {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G;
}
} else if (eCSR_DOT11_MODE_11a & phyMode) {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A;
} else if ((eCSR_DOT11_MODE_11g | eCSR_DOT11_MODE_11g_ONLY) &
phyMode) {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G;
} else {
cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11B;
}
}
return cfgDot11ModeToUse;
}
uint32_t csr_get11h_power_constraint(tHalHandle hHal,
tDot11fIEPowerConstraints *pPowerConstraint)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
uint32_t localPowerConstraint = 0;
/* check if .11h support is enabled, if not, the power constraint is 0. */
if (pMac->roam.configParam.Is11hSupportEnabled
&& pPowerConstraint->present) {
localPowerConstraint = pPowerConstraint->localPowerConstraints;
}
return localPowerConstraint;
}
bool csr_is_profile_wpa(tCsrRoamProfile *pProfile)
{
bool fWpaProfile = false;
switch (pProfile->negotiatedAuthType) {
case eCSR_AUTH_TYPE_WPA:
case eCSR_AUTH_TYPE_WPA_PSK:
case eCSR_AUTH_TYPE_WPA_NONE:
#ifdef FEATURE_WLAN_ESE
case eCSR_AUTH_TYPE_CCKM_WPA:
#endif
fWpaProfile = true;
break;
default:
fWpaProfile = false;
break;
}
if (fWpaProfile) {
switch (pProfile->negotiatedUCEncryptionType) {
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP104:
case eCSR_ENCRYPT_TYPE_TKIP:
case eCSR_ENCRYPT_TYPE_AES:
fWpaProfile = true;
break;
default:
fWpaProfile = false;
break;
}
}
return fWpaProfile;
}
bool csr_is_profile_rsn(tCsrRoamProfile *pProfile)
{
bool fRSNProfile = false;
switch (pProfile->negotiatedAuthType) {
case eCSR_AUTH_TYPE_RSN:
case eCSR_AUTH_TYPE_RSN_PSK:
#ifdef WLAN_FEATURE_VOWIFI_11R
case eCSR_AUTH_TYPE_FT_RSN:
case eCSR_AUTH_TYPE_FT_RSN_PSK:
#endif
#ifdef FEATURE_WLAN_ESE
case eCSR_AUTH_TYPE_CCKM_RSN:
#endif
#ifdef WLAN_FEATURE_11W
case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
case eCSR_AUTH_TYPE_RSN_8021X_SHA256:
#endif
fRSNProfile = true;
break;
default:
fRSNProfile = false;
break;
}
if (fRSNProfile) {
switch (pProfile->negotiatedUCEncryptionType) {
/* !!REVIEW - For WPA2, use of RSN IE mandates */
/* use of AES as encryption. Here, we qualify */
/* even if encryption type is WEP or TKIP */
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP104:
case eCSR_ENCRYPT_TYPE_TKIP:
case eCSR_ENCRYPT_TYPE_AES:
fRSNProfile = true;
break;
default:
fRSNProfile = false;
break;
}
}
return fRSNProfile;
}
/**
* csr_isconcurrentsession_valid() - check if concurrent session is valid
* @mac_ctx: pointer to mac context
* @cur_sessionid: current session id
* @cur_bss_persona: current BSS persona
*
* This function will check if concurrent session is valid
*
* Return: CDF_STATUS
*/
CDF_STATUS
csr_isconcurrentsession_valid(tpAniSirGlobal mac_ctx, uint32_t cur_sessionid,
tCDF_CON_MODE cur_bss_persona)
{
uint32_t sessionid = 0;
tCDF_CON_MODE bss_persona;
eCsrConnectState connect_state, temp;
tCsrRoamSession *roam_session;
for (sessionid = 0; sessionid < CSR_ROAM_SESSION_MAX; sessionid++) {
if (cur_sessionid == sessionid)
continue;
if (!CSR_IS_SESSION_VALID(mac_ctx, sessionid))
continue;
roam_session = &mac_ctx->roam.roamSession[sessionid];
bss_persona = roam_session->bssParams.bssPersona;
connect_state = roam_session->connectState;
switch (cur_bss_persona) {
case CDF_STA_MODE:
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_INFO,
FL("** STA session **"));
return CDF_STATUS_SUCCESS;
case CDF_SAP_MODE:
temp = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED;
#ifndef WLAN_FEATURE_MBSSID
if ((bss_persona == CDF_SAP_MODE) &&
(connect_state !=
eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("sap mode already exist"));
return CDF_STATUS_E_FAILURE;
} else
#endif
if ((bss_persona == CDF_IBSS_MODE)
&& (connect_state != temp)) {
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("Can't start GO"));
return CDF_STATUS_E_FAILURE;
}
break;
case CDF_P2P_GO_MODE:
temp = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED;
if ((bss_persona == CDF_P2P_GO_MODE) &&
(connect_state !=
eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("GO mode already exists"));
return CDF_STATUS_E_FAILURE;
} else if ((bss_persona == CDF_IBSS_MODE)
&& (connect_state != temp)) {
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("Can't start SAP"));
return CDF_STATUS_E_FAILURE;
}
break;
case CDF_IBSS_MODE:
if ((bss_persona == CDF_IBSS_MODE) && (connect_state !=
eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED)) {
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("IBSS mode already exist"));
return CDF_STATUS_E_FAILURE;
} else if (((bss_persona == CDF_P2P_GO_MODE) ||
(bss_persona == CDF_SAP_MODE)) &&
(connect_state !=
eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("Can't start GO"));
return CDF_STATUS_E_FAILURE;
}
break;
case CDF_P2P_CLIENT_MODE:
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_INFO,
FL("**P2P-Client session**"));
return CDF_STATUS_SUCCESS;
default:
CDF_TRACE(CDF_MODULE_ID_SME,
CDF_TRACE_LEVEL_ERROR,
FL("Persona not handled = %d"),
cur_bss_persona);
break;
}
}
return CDF_STATUS_SUCCESS;
}
/**
* csr_update_mcc_p2p_beacon_interval() - update p2p beacon interval
* @mac_ctx: pointer to mac context
*
* This function is to update the mcc p2p beacon interval
*
* Return: CDF_STATUS
*/
CDF_STATUS csr_update_mcc_p2p_beacon_interval(tpAniSirGlobal mac_ctx)
{
uint32_t session_id = 0;
tCsrRoamSession *roam_session;
/* If MCC is not supported just break and return SUCCESS */
if (!mac_ctx->roam.configParam.fenableMCCMode)
return CDF_STATUS_E_FAILURE;
for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) {
/*
* If GO in MCC support different beacon interval,
* change the BI of the P2P-GO
*/
roam_session = &mac_ctx->roam.roamSession[session_id];
if (roam_session->bssParams.bssPersona != CDF_P2P_GO_MODE)
continue;
/*
* Handle different BI scneario based on the
* configuration set.If Config is set to 0x02 then
* Disconnect all the P2P clients associated. If config
* is set to 0x04 then update the BI without
* disconnecting all the clients
*/
if ((mac_ctx->roam.configParam.fAllowMCCGODiffBI == 0x04)
&& (roam_session->bssParams.
updatebeaconInterval)) {
return csr_send_chng_mcc_beacon_interval(mac_ctx,
session_id);
} else if (roam_session->bssParams.updatebeaconInterval) {
/*
* If the configuration of fAllowMCCGODiffBI is set to
* other than 0x04
*/
return csr_roam_call_callback(mac_ctx,
session_id,
NULL, 0,
eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS,
eCSR_ROAM_RESULT_NONE);
}
}
return CDF_STATUS_E_FAILURE;
}
uint16_t csr_calculate_mcc_beacon_interval(tpAniSirGlobal pMac, uint16_t sta_bi,
uint16_t go_gbi)
{
uint8_t num_beacons = 0;
uint8_t is_multiple = 0;
uint16_t go_cbi = 0;
uint16_t go_fbi = 0;
uint16_t sta_cbi = 0;
/* If GO's given beacon Interval is less than 100 */
if (go_gbi < 100)
go_cbi = 100;
/* if GO's given beacon Interval is greater than or equal to 100 */
else
go_cbi = 100 + (go_gbi % 100);
if (sta_bi == 0) {
/* There is possibility to receive zero as value.
Which will cause divide by zero. Hence initialise with 100
*/
sta_bi = 100;
sms_log(pMac, LOGW,
FL("sta_bi 2nd parameter is zero, initialize to %d"),
sta_bi);
}
/* check, if either one is multiple of another */
if (sta_bi > go_cbi) {
is_multiple = !(sta_bi % go_cbi);
} else {
is_multiple = !(go_cbi % sta_bi);
}
/* if it is multiple, then accept GO's beacon interval range [100,199] as it is */
if (is_multiple) {
return go_cbi;
}
/* else , if it is not multiple, then then check for number of beacons to be */
/* inserted based on sta BI */
num_beacons = sta_bi / 100;
if (num_beacons) {
/* GO's final beacon interval will be aligned to sta beacon interval, but */
/* in the range of [100, 199]. */
sta_cbi = sta_bi / num_beacons;
go_fbi = sta_cbi;
} else {
/* if STA beacon interval is less than 100, use GO's change bacon interval */
/* instead of updating to STA's beacon interval. */
go_fbi = go_cbi;
}
return go_fbi;
}
CDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId,
uint16_t *beaconInterval,
uint32_t cursessionId,
tCDF_CON_MODE currBssPersona)
{
uint32_t sessionId = 0;
uint16_t new_beaconInterval = 0;
/* If MCC is not supported just break */
if (!pMac->roam.configParam.fenableMCCMode) {
return CDF_STATUS_E_FAILURE;
}
for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
if (cursessionId != sessionId) {
if (!CSR_IS_SESSION_VALID(pMac, sessionId)) {
continue;
}
switch (currBssPersona) {
case CDF_STA_MODE:
if (pMac->roam.roamSession[sessionId].
pCurRoamProfile &&
(pMac->roam.roamSession[sessionId].
pCurRoamProfile->csrPersona ==
CDF_P2P_CLIENT_MODE)) {
/* check for P2P client mode */
sms_log(pMac, LOG1,
FL
(" Beacon Interval Validation not required for STA/CLIENT"));
}
/*
* IF SAP has started and STA wants to connect
* on different channel MCC should
* MCC should not be enabled so making it
* false to enforce on same channel
*/
else if (pMac->roam.roamSession[sessionId].
bssParams.bssPersona ==
CDF_SAP_MODE) {
if (pMac->roam.roamSession[sessionId].
bssParams.operationChn !=
channelId) {
sms_log(pMac, LOGE,
FL
("*** MCC with SAP+STA sessions ****"));
return CDF_STATUS_SUCCESS;
}
} else if (pMac->roam.roamSession[sessionId].
bssParams.bssPersona ==
CDF_P2P_GO_MODE) {
/*
* Check for P2P go scenario
* if GO in MCC support different
* beacon interval,
* change the BI of the P2P-GO
*/
if ((pMac->roam.roamSession[sessionId].
bssParams.operationChn !=
channelId)
&& (pMac->roam.
roamSession[sessionId].
bssParams.beaconInterval !=
*beaconInterval)) {
/* if GO in MCC support different beacon interval, return success */
if (pMac->roam.configParam.
fAllowMCCGODiffBI == 0x01) {
return
CDF_STATUS_SUCCESS;
}
/* Send only Broadcast disassoc and update beaconInterval */
/* If configuration is set to 0x04 then dont */
/* disconnect all the station */
else if ((pMac->roam.
configParam.
fAllowMCCGODiffBI ==
0x02)
|| (pMac->roam.
configParam.
fAllowMCCGODiffBI
== 0x04)) {
/* Check to pass the right beacon Interval */
if (pMac->roam.configParam.conc_custom_rule1 ||
pMac->roam.configParam.conc_custom_rule2) {
new_beaconInterval = CSR_CUSTOM_CONC_GO_BI;
} else {
new_beaconInterval =
csr_calculate_mcc_beacon_interval(pMac,
*beaconInterval,
pMac->roam.
roamSession
[sessionId].
bssParams.
beaconInterval);
}
sms_log(pMac, LOG1,
FL
(" Peer AP BI : %d, new Beacon Interval: %d"),
*beaconInterval,
new_beaconInterval);
/* Update the becon Interval */
if (new_beaconInterval
!=
pMac->roam.
roamSession
[sessionId].
bssParams.
beaconInterval) {
/* Update the beaconInterval now */
sms_log(pMac,
LOGE,
FL
(" Beacon Interval got changed config used: %d\n"),
pMac->
roam.
configParam.
fAllowMCCGODiffBI);
pMac->roam.
roamSession
[sessionId].
bssParams.
beaconInterval
=
new_beaconInterval;
pMac->roam.
roamSession
[sessionId].
bssParams.
updatebeaconInterval
= true;
return
csr_update_mcc_p2p_beacon_interval
(pMac);
}
return
CDF_STATUS_SUCCESS;
}
/* Disconnect the P2P session */
else if (pMac->roam.configParam.
fAllowMCCGODiffBI ==
0x03) {
pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval = false;
return
csr_roam_call_callback
(pMac, sessionId,
NULL, 0,
eCSR_ROAM_SEND_P2P_STOP_BSS,
eCSR_ROAM_RESULT_NONE);
} else {
sms_log(pMac, LOGE,
FL
("BeaconInterval is different cannot connect to preferred AP..."));
return
CDF_STATUS_E_FAILURE;
}
}
}
break;
case CDF_P2P_CLIENT_MODE:
if (pMac->roam.roamSession[sessionId].
pCurRoamProfile &&
(pMac->roam.roamSession[sessionId].
pCurRoamProfile->csrPersona ==
CDF_STA_MODE)) {
/* check for P2P client mode */
sms_log(pMac, LOG1,
FL
(" Ignore Beacon Interval Validation..."));
} else if (pMac->roam.roamSession[sessionId].
bssParams.bssPersona ==
CDF_P2P_GO_MODE) {
/* Check for P2P go scenario */
if ((pMac->roam.roamSession[sessionId].
bssParams.operationChn !=
channelId)
&& (pMac->roam.
roamSession[sessionId].
bssParams.beaconInterval !=
*beaconInterval)) {
sms_log(pMac, LOGE,
FL
("BeaconInterval is different cannot connect to P2P_GO network ..."));
return CDF_STATUS_E_FAILURE;
}
}
break;
case CDF_SAP_MODE:
break;
case CDF_P2P_GO_MODE:
{
if (pMac->roam.roamSession[sessionId].
pCurRoamProfile &&
((pMac->roam.roamSession[sessionId].
pCurRoamProfile->csrPersona ==
CDF_P2P_CLIENT_MODE) ||
(pMac->roam.roamSession[sessionId].
pCurRoamProfile->csrPersona ==
CDF_STA_MODE))) {
/* check for P2P_client scenario */
if ((pMac->roam.
roamSession[sessionId].
connectedProfile.
operationChannel == 0)
&& (pMac->roam.
roamSession[sessionId].
connectedProfile.
beaconInterval == 0)) {
continue;
}
if (csr_is_conn_state_connected_infra
(pMac, sessionId)
&& (pMac->roam.
roamSession[sessionId].
connectedProfile.
operationChannel !=
channelId)
&& (pMac->roam.
roamSession[sessionId].
connectedProfile.
beaconInterval !=
*beaconInterval)) {
/*
* Updated beaconInterval should be used only when we are starting a new BSS
* not incase of client or STA case
*/
/* Calculate beacon Interval for P2P-GO incase of MCC */
if (pMac->roam.configParam.conc_custom_rule1 ||
pMac->roam.configParam.conc_custom_rule2) {
new_beaconInterval = CSR_CUSTOM_CONC_GO_BI;
} else {
new_beaconInterval =
csr_calculate_mcc_beacon_interval
(pMac,
pMac->roam.
roamSession
[sessionId].
connectedProfile.
beaconInterval,
*beaconInterval);
}
if (*beaconInterval !=
new_beaconInterval)
*beaconInterval
=
new_beaconInterval;
return
CDF_STATUS_SUCCESS;
}
}
}
break;
default:
sms_log(pMac, LOGE,
FL(" Persona not supported : %d"),
currBssPersona);
return CDF_STATUS_E_FAILURE;
}
}
}
return CDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_VOWIFI_11R
/* Function to return true if the authtype is 11r */
bool csr_is_auth_type11r(eCsrAuthType AuthType, uint8_t mdiePresent)
{
switch (AuthType) {
case eCSR_AUTH_TYPE_OPEN_SYSTEM:
if (mdiePresent)
return true;
break;
case eCSR_AUTH_TYPE_FT_RSN_PSK:
case eCSR_AUTH_TYPE_FT_RSN:
return true;
break;
default:
break;
}
return false;
}
/* Function to return true if the profile is 11r */
bool csr_is_profile11r(tCsrRoamProfile *pProfile)
{
return csr_is_auth_type11r(pProfile->negotiatedAuthType,
pProfile->MDID.mdiePresent);
}
#endif
#ifdef FEATURE_WLAN_ESE
/* Function to return true if the authtype is ESE */
bool csr_is_auth_type_ese(eCsrAuthType AuthType)
{
switch (AuthType) {
case eCSR_AUTH_TYPE_CCKM_WPA:
case eCSR_AUTH_TYPE_CCKM_RSN:
return true;
break;
default:
break;
}
return false;
}
/* Function to return true if the profile is ESE */
bool csr_is_profile_ese(tCsrRoamProfile *pProfile)
{
return csr_is_auth_type_ese(pProfile->negotiatedAuthType);
}
#endif
#ifdef FEATURE_WLAN_WAPI
bool csr_is_profile_wapi(tCsrRoamProfile *pProfile)
{
bool fWapiProfile = false;
switch (pProfile->negotiatedAuthType) {
case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE:
case eCSR_AUTH_TYPE_WAPI_WAI_PSK:
fWapiProfile = true;
break;
default:
fWapiProfile = false;
break;
}
if (fWapiProfile) {
switch (pProfile->negotiatedUCEncryptionType) {
case eCSR_ENCRYPT_TYPE_WPI:
fWapiProfile = true;
break;
default:
fWapiProfile = false;
break;
}
}
return fWapiProfile;
}
static bool csr_is_wapi_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1,
uint8_t *Oui2)
{
return cdf_mem_compare(Oui1, Oui2, CSR_WAPI_OUI_SIZE);
}
static bool csr_is_wapi_oui_match(tpAniSirGlobal pMac,
uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE],
uint8_t cAllCyphers, uint8_t Cypher[],
uint8_t Oui[])
{
bool fYes = false;
uint8_t idx;
for (idx = 0; idx < cAllCyphers; idx++) {
if (csr_is_wapi_oui_equal(pMac, AllCyphers[idx], Cypher)) {
fYes = true;
break;
}
}
if (fYes && Oui) {
cdf_mem_copy(Oui, AllCyphers[idx], CSR_WAPI_OUI_SIZE);
}
return fYes;
}
#endif /* FEATURE_WLAN_WAPI */
static bool csr_is_wpa_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1,
uint8_t *Oui2)
{
return cdf_mem_compare(Oui1, Oui2, CSR_WPA_OUI_SIZE);
}
static bool csr_is_oui_match(tpAniSirGlobal pMac,
uint8_t AllCyphers[][CSR_WPA_OUI_SIZE],
uint8_t cAllCyphers, uint8_t Cypher[], uint8_t Oui[])
{
bool fYes = false;
uint8_t idx;
for (idx = 0; idx < cAllCyphers; idx++) {
if (csr_is_wpa_oui_equal(pMac, AllCyphers[idx], Cypher)) {
fYes = true;
break;
}
}
if (fYes && Oui) {
cdf_mem_copy(Oui, AllCyphers[idx], CSR_WPA_OUI_SIZE);
}
return fYes;
}
static bool csr_match_rsnoui_index(tpAniSirGlobal pMac,
uint8_t AllCyphers[][CSR_RSN_OUI_SIZE],
uint8_t cAllCyphers, uint8_t ouiIndex,
uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllCyphers, cAllCyphers, csr_rsn_oui[ouiIndex], Oui);
}
#ifdef FEATURE_WLAN_WAPI
static bool csr_match_wapi_oui_index(tpAniSirGlobal pMac,
uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE],
uint8_t cAllCyphers, uint8_t ouiIndex,
uint8_t Oui[])
{
return csr_is_wapi_oui_match
(pMac, AllCyphers, cAllCyphers, csr_wapi_oui[ouiIndex], Oui);
}
#endif /* FEATURE_WLAN_WAPI */
static bool csr_match_wpaoui_index(tpAniSirGlobal pMac,
uint8_t AllCyphers[][CSR_RSN_OUI_SIZE],
uint8_t cAllCyphers, uint8_t ouiIndex,
uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllCyphers, cAllCyphers, csr_wpa_oui[ouiIndex], Oui);
}
#ifdef FEATURE_WLAN_WAPI
static bool csr_is_auth_wapi_cert(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_WAPI_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_wapi_oui_match
(pMac, AllSuites, cAllSuites, csr_wapi_oui[1], Oui);
}
static bool csr_is_auth_wapi_psk(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_WAPI_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_wapi_oui_match
(pMac, AllSuites, cAllSuites, csr_wapi_oui[2], Oui);
}
#endif /* FEATURE_WLAN_WAPI */
#ifdef WLAN_FEATURE_VOWIFI_11R
/*
* Function for 11R FT Authentication. We match the FT Authentication Cipher
* suite here. This matches for FT Auth with the 802.1X exchange.
*/
static bool csr_is_ft_auth_rsn(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[03], Oui);
}
/*
* Function for 11R FT Authentication. We match the FT Authentication Cipher
* suite here. This matches for FT Auth with the PSK.
*/
static bool csr_is_ft_auth_rsn_psk(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[04], Oui);
}
#endif
#ifdef FEATURE_WLAN_ESE
/*
* Function for ESE CCKM AKM Authentication. We match the CCKM AKM
* Authentication Key Management suite here. This matches for CCKM AKM Auth
* with the 802.1X exchange.
*/
static bool csr_is_ese_cckm_auth_rsn(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[06], Oui);
}
static bool csr_is_ese_cckm_auth_wpa(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_WPA_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_wpa_oui[06], Oui);
}
#endif
static bool csr_is_auth_rsn(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[01], Oui);
}
static bool csr_is_auth_rsn_psk(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[02], Oui);
}
#ifdef WLAN_FEATURE_11W
static bool csr_is_auth_rsn_psk_sha256(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[07], Oui);
}
static bool csr_is_auth_rsn8021x_sha256(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_rsn_oui[8], Oui);
}
#endif
static bool csr_is_auth_wpa(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_WPA_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_wpa_oui[01], Oui);
}
static bool csr_is_auth_wpa_psk(tpAniSirGlobal pMac,
uint8_t AllSuites[][CSR_WPA_OUI_SIZE],
uint8_t cAllSuites, uint8_t Oui[])
{
return csr_is_oui_match
(pMac, AllSuites, cAllSuites, csr_wpa_oui[02], Oui);
}
uint8_t csr_get_oui_index_from_cipher(eCsrEncryptionType enType)
{
uint8_t OUIIndex;
switch (enType) {
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
OUIIndex = CSR_OUI_WEP40_OR_1X_INDEX;
break;
case eCSR_ENCRYPT_TYPE_WEP104:
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
OUIIndex = CSR_OUI_WEP104_INDEX;
break;
case eCSR_ENCRYPT_TYPE_TKIP:
OUIIndex = CSR_OUI_TKIP_OR_PSK_INDEX;
break;
case eCSR_ENCRYPT_TYPE_AES:
OUIIndex = CSR_OUI_AES_INDEX;
break;
case eCSR_ENCRYPT_TYPE_NONE:
OUIIndex = CSR_OUI_USE_GROUP_CIPHER_INDEX;
break;
#ifdef FEATURE_WLAN_WAPI
case eCSR_ENCRYPT_TYPE_WPI:
OUIIndex = CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX;
break;
#endif /* FEATURE_WLAN_WAPI */
default: /* HOWTO handle this? */
OUIIndex = CSR_OUI_RESERVED_INDEX;
break;
} /* switch */
return OUIIndex;
}
/**
* csr_get_rsn_information() - to get RSN infomation
* @hal: pointer to HAL
* @auth_type: auth type
* @encr_type: encryption type
* @mc_encryption: multicast encryption type
* @rsn_ie: pointer to RSN IE
* @ucast_cipher: Unicast cipher
* @mcast_cipher: Multicast cipher
* @auth_suite: Authentication suite
* @capabilities: RSN capabilities
* @negotiated_authtype: Negotiated auth type
* @negotiated_mccipher: negotiated multicast cipher
*
* This routine will get all RSN information
*
* Return: bool
*/
bool csr_get_rsn_information(tHalHandle hal, tCsrAuthList *auth_type,
eCsrEncryptionType encr_type,
tCsrEncryptionList *mc_encryption,
tDot11fIERSN *rsn_ie, uint8_t *ucast_cipher,
uint8_t *mcast_cipher, uint8_t *auth_suite,
tCsrRSNCapabilities *capabilities,
eCsrAuthType *negotiated_authtype,
eCsrEncryptionType *negotiated_mccipher)
{
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
bool acceptable_cipher = false;
uint8_t c_ucast_cipher = 0;
uint8_t c_mcast_cipher = 0;
uint8_t c_auth_suites = 0, i;
uint8_t unicast[CSR_RSN_OUI_SIZE];
uint8_t multicast[CSR_RSN_OUI_SIZE];
uint8_t authsuites[CSR_RSN_MAX_AUTH_SUITES][CSR_RSN_OUI_SIZE];
uint8_t authentication[CSR_RSN_OUI_SIZE];
uint8_t mccipher_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE];
eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
if (!rsn_ie->present)
goto end;
c_mcast_cipher++;
cdf_mem_copy(mccipher_arr, rsn_ie->gp_cipher_suite,
CSR_RSN_OUI_SIZE);
c_ucast_cipher =
(uint8_t) (rsn_ie->pwise_cipher_suite_count);
c_auth_suites = (uint8_t) (rsn_ie->akm_suite_count);
for (i = 0; i < c_auth_suites && i < CSR_RSN_MAX_AUTH_SUITES; i++) {
cdf_mem_copy((void *)&authsuites[i],
(void *)&rsn_ie->akm_suites[i], CSR_RSN_OUI_SIZE);
}
/* Check - Is requested unicast Cipher supported by the BSS. */
acceptable_cipher = csr_match_rsnoui_index(mac_ctx,
rsn_ie->pwise_cipher_suites, c_ucast_cipher,
csr_get_oui_index_from_cipher(encr_type),
unicast);
if (!acceptable_cipher)
goto end;
/* unicast is supported. Pick the first matching Group cipher, if any */
for (i = 0; i < mc_encryption->numEntries; i++) {
acceptable_cipher = csr_match_rsnoui_index(mac_ctx,
mccipher_arr, c_mcast_cipher,
csr_get_oui_index_from_cipher(
mc_encryption->encryptionType[i]),
multicast);
if (acceptable_cipher)
break;
}
if (!acceptable_cipher)
goto end;
if (negotiated_mccipher)
*negotiated_mccipher = mc_encryption->encryptionType[i];
/* Initializing with false as it has true value already */
acceptable_cipher = false;
for (i = 0; i < auth_type->numEntries; i++) {
/*
* Ciphers are supported, Match authentication algorithm and
* pick first matching authtype.
*/
#ifdef WLAN_FEATURE_VOWIFI_11R
/* Changed the AKM suites according to order of preference */
if (csr_is_ft_auth_rsn(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_FT_RSN == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_FT_RSN;
}
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
&& csr_is_ft_auth_rsn_psk(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_FT_RSN_PSK ==
auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_FT_RSN_PSK;
}
#endif
#ifdef FEATURE_WLAN_ESE
/* ESE only supports 802.1X. No PSK. */
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) &&
csr_is_ese_cckm_auth_rsn(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_CCKM_RSN == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_CCKM_RSN;
}
#endif
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
&& csr_is_auth_rsn(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_RSN == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_RSN;
}
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
&& csr_is_auth_rsn_psk(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_RSN_PSK == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_RSN_PSK;
}
#ifdef WLAN_FEATURE_11W
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
&& csr_is_auth_rsn_psk_sha256(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_RSN_PSK_SHA256 ==
auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_RSN_PSK_SHA256;
}
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) &&
csr_is_auth_rsn8021x_sha256(mac_ctx, authsuites,
c_auth_suites, authentication)) {
if (eCSR_AUTH_TYPE_RSN_8021X_SHA256 ==
auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_RSN_8021X_SHA256;
}
#endif
/*
* The 1st auth type in the APs RSN IE, to match stations
* connecting profiles auth type will cause us to exit this
* loop. This is added as some APs advertise multiple akms in
* the RSN IE
*/
if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) {
acceptable_cipher = true;
break;
}
} /* for */
end:
if (acceptable_cipher) {
if (mcast_cipher)
cdf_mem_copy(mcast_cipher, multicast,
CSR_RSN_OUI_SIZE);
if (ucast_cipher)
cdf_mem_copy(ucast_cipher, unicast, CSR_RSN_OUI_SIZE);
if (auth_suite)
cdf_mem_copy(auth_suite, authentication,
CSR_RSN_OUI_SIZE);
if (negotiated_authtype)
*negotiated_authtype = neg_authtype;
if (capabilities) {
/* Bit 0 Preauthentication */
capabilities->PreAuthSupported =
(rsn_ie->RSN_Cap[0] >> 0) & 0x1;
/* Bit 1 No Pairwise */
capabilities->NoPairwise =
(rsn_ie->RSN_Cap[0] >> 1) & 0x1;
/* Bit 2, 3 PTKSA Replay Counter */
capabilities->PTKSAReplayCounter =
(rsn_ie->RSN_Cap[0] >> 2) & 0x3;
/* Bit 4, 5 GTKSA Replay Counter */
capabilities->GTKSAReplayCounter =
(rsn_ie->RSN_Cap[0] >> 4) & 0x3;
#ifdef WLAN_FEATURE_11W
/* Bit 6 MFPR */
capabilities->MFPRequired =
(rsn_ie->RSN_Cap[0] >> 6) & 0x1;
/* Bit 7 MFPC */
capabilities->MFPCapable =
(rsn_ie->RSN_Cap[0] >> 7) & 0x1;
#else
/* Bit 6 MFPR */
capabilities->MFPRequired = 0;
/* Bit 7 MFPC */
capabilities->MFPCapable = 0;
#endif
/* remaining reserved */
capabilities->Reserved = rsn_ie->RSN_Cap[1] & 0xff;
}
}
return acceptable_cipher;
}
#ifdef WLAN_FEATURE_11W
/**
* csr_is_pmf_capabilities_in_rsn_match() - check for PMF capability
* @hHal: Global HAL handle
* @pFilterMFPEnabled: given by supplicant to us to specify what kind
* of connection supplicant is expecting to make
* if it is enabled then make PMF connection.
* if it is disabled then make normal connection.
* @pFilterMFPRequired: given by supplicant based on our configuration
* if it is 1 then we will require mandatory
* PMF connection and if it is 0 then we PMF
* connection is optional.
* @pFilterMFPCapable: given by supplicant based on our configuration
* if it 1 then we are PMF capable and if it 0
* then we are not PMF capable.
* @pRSNIe: RSNIe from Beacon/probe response of
* neighbor AP against which we will compare
* our capabilities.
*
* This function is to match our current capabilities with the AP
* to which we are expecting make the connection.
*
* Return: if our PMF capabilities matches with AP then we
* will return true to indicate that we are good
* to make connection with it. Else we will return false
**/
static bool
csr_is_pmf_capabilities_in_rsn_match(tHalHandle hHal,
bool *pFilterMFPEnabled,
uint8_t *pFilterMFPRequired,
uint8_t *pFilterMFPCapable,
tDot11fIERSN *pRSNIe)
{
uint8_t apProfileMFPCapable = 0;
uint8_t apProfileMFPRequired = 0;
if (pRSNIe && pFilterMFPEnabled && pFilterMFPCapable
&& pFilterMFPRequired) {
/* Extracting MFPCapable bit from RSN Ie */
apProfileMFPCapable = (pRSNIe->RSN_Cap[0] >> 7) & 0x1;
apProfileMFPRequired = (pRSNIe->RSN_Cap[0] >> 6) & 0x1;
if (*pFilterMFPEnabled && *pFilterMFPCapable
&& *pFilterMFPRequired && (apProfileMFPCapable == 0)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
"AP is not capable to make PMF connection");
return false;
} else if (*pFilterMFPEnabled && *pFilterMFPCapable &&
!(*pFilterMFPRequired) &&
(apProfileMFPCapable == 0)) {
/*
* This is tricky, because supplicant asked us to
* make mandatory PMF connection eventhough PMF
* connection is optional here.
* so if AP is not capable of PMF then drop it.
* Don't try to connect with it.
*/
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
"we need PMF connection & AP isn't capable to make PMF connection");
return false;
} else if (!(*pFilterMFPCapable) &&
apProfileMFPCapable && apProfileMFPRequired) {
/*
* In this case, AP with whom we trying to connect
* requires mandatory PMF connections and we are not
* capable so this AP is not good choice to connect
*/
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
"AP needs PMF connection and we are not capable of pmf connection");
return false;
} else if (!(*pFilterMFPEnabled) && *pFilterMFPCapable &&
(apProfileMFPCapable == 1)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
"we don't need PMF connection even though both parties are capable");
return false;
}
}
return true;
}
#endif
bool csr_is_rsn_match(tHalHandle hHal, tCsrAuthList *pAuthType,
eCsrEncryptionType enType,
tCsrEncryptionList *pEnMcType,
bool *pMFPEnabled, uint8_t *pMFPRequired,
uint8_t *pMFPCapable,
tDot11fBeaconIEs *pIes,
eCsrAuthType *pNegotiatedAuthType,
eCsrEncryptionType *pNegotiatedMCCipher)
{
bool fRSNMatch = false;
/* See if the cyphers in the Bss description match with the settings in the profile. */
fRSNMatch =
csr_get_rsn_information(hHal, pAuthType, enType, pEnMcType, &pIes->RSN,
NULL, NULL, NULL, NULL, pNegotiatedAuthType,
pNegotiatedMCCipher);
#ifdef WLAN_FEATURE_11W
/* If all the filter matches then finally checks for PMF capabilities */
if (fRSNMatch) {
fRSNMatch = csr_is_pmf_capabilities_in_rsn_match(hHal, pMFPEnabled,
pMFPRequired,
pMFPCapable,
&pIes->RSN);
}
#endif
return fRSNMatch;
}
bool csr_lookup_pmkid(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t *pBSSId,
uint8_t *pPMKId)
{
bool fRC = false, fMatchFound = false;
uint32_t Index;
tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
if (!pSession) {
sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
return false;
}
do {
for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) {
sms_log(pMac, LOG1,
"match PMKID " MAC_ADDRESS_STR " to ",
MAC_ADDR_ARRAY(pBSSId));
if (cdf_mem_compare
(pBSSId, pSession->PmkidCacheInfo[Index].BSSID.bytes,
sizeof(struct cdf_mac_addr))) {
/* match found */
fMatchFound = true;
break;
}
}
if (!fMatchFound)
break;
cdf_mem_copy(pPMKId, pSession->PmkidCacheInfo[Index].PMKID,
CSR_RSN_PMKID_SIZE);
fRC = true;
} while (0);
sms_log(pMac, LOGW,
"csr_lookup_pmkid called return match = %d pMac->roam.NumPmkidCache = %d",
fRC, pSession->NumPmkidCache);
return fRC;
}
uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId,
tCsrRoamProfile *pProfile,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
bool fRSNMatch;
uint8_t cbRSNIe = 0;
uint8_t UnicastCypher[CSR_RSN_OUI_SIZE];
uint8_t MulticastCypher[CSR_RSN_OUI_SIZE];
uint8_t AuthSuite[CSR_RSN_OUI_SIZE];
tCsrRSNAuthIe *pAuthSuite;
tCsrRSNCapabilities RSNCapabilities;
tCsrRSNPMKIe *pPMK;
uint8_t PMKId[CSR_RSN_PMKID_SIZE];
#ifdef WLAN_FEATURE_11W
uint8_t *pGroupMgmtCipherSuite;
#endif
tDot11fBeaconIEs *pIesLocal = pIes;
eCsrAuthType negAuthType = eCSR_AUTH_TYPE_UNKNOWN;
sms_log(pMac, LOGW, "%s called...", __func__);
do {
if (!csr_is_profile_rsn(pProfile))
break;
if (!pIesLocal
&&
(!CDF_IS_STATUS_SUCCESS
(csr_get_parsed_bss_description_ies
(pMac, pSirBssDesc, &pIesLocal)))) {
break;
}
/* See if the cyphers in the Bss description match with the settings in the profile. */
fRSNMatch =
csr_get_rsn_information(hHal, &pProfile->AuthType,
pProfile->negotiatedUCEncryptionType,
&pProfile->mcEncryptionType,
&pIesLocal->RSN, UnicastCypher,
MulticastCypher, AuthSuite,
&RSNCapabilities, &negAuthType, NULL);
if (!fRSNMatch)
break;
pRSNIe->IeHeader.ElementID = SIR_MAC_RSN_EID;
pRSNIe->Version = CSR_RSN_VERSION_SUPPORTED;
cdf_mem_copy(pRSNIe->MulticastOui, MulticastCypher,
sizeof(MulticastCypher));
pRSNIe->cUnicastCyphers = 1;
cdf_mem_copy(&pRSNIe->UnicastOui[0], UnicastCypher,
sizeof(UnicastCypher));
pAuthSuite =
(tCsrRSNAuthIe *) (&pRSNIe->
UnicastOui[pRSNIe->cUnicastCyphers]);
pAuthSuite->cAuthenticationSuites = 1;
cdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite,
sizeof(AuthSuite));
/* RSN capabilities follows the Auth Suite (two octects) */
/* !!REVIEW - What should STA put in RSN capabilities, currently */
/* just putting back APs capabilities */
/* For one, we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */
/* For another, we should use the Management Frame Protection values given by the supplicant */
RSNCapabilities.PreAuthSupported = 0;
#ifdef WLAN_FEATURE_11W
if (RSNCapabilities.MFPCapable && pProfile->MFPCapable) {
RSNCapabilities.MFPCapable = pProfile->MFPCapable;
RSNCapabilities.MFPRequired = pProfile->MFPRequired;
} else {
RSNCapabilities.MFPCapable = 0;
RSNCapabilities.MFPRequired = 0;
}
#endif
*(uint16_t *) (&pAuthSuite->AuthOui[1]) =
*((uint16_t *) (&RSNCapabilities));
pPMK =
(tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1])) +
sizeof(uint16_t));
/* Don't include the PMK SA IDs for CCKM associations. */
if (
#ifdef FEATURE_WLAN_ESE
(eCSR_AUTH_TYPE_CCKM_RSN != negAuthType) &&
#endif
csr_lookup_pmkid(pMac, sessionId, pSirBssDesc->bssId,
&(PMKId[0]))) {
pPMK->cPMKIDs = 1;
cdf_mem_copy(pPMK->PMKIDList[0].PMKID, PMKId,
CSR_RSN_PMKID_SIZE);
} else {
pPMK->cPMKIDs = 0;
}
#ifdef WLAN_FEATURE_11W
if (pProfile->MFPEnabled) {
pGroupMgmtCipherSuite =
(uint8_t *) pPMK + sizeof(uint16_t) +
(pPMK->cPMKIDs * CSR_RSN_PMKID_SIZE);
cdf_mem_copy(pGroupMgmtCipherSuite, csr_rsn_oui[07],
CSR_WPA_OUI_SIZE);
}
#endif
/* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */
/* Add in the size of the Auth suite (count plus a single OUI) */
/* Add in the RSN caps field. */
/* Add PMKID count and PMKID (if any) */
/* Add group management cipher suite */
pRSNIe->IeHeader.Length =
(uint8_t) (sizeof(*pRSNIe) - sizeof(pRSNIe->IeHeader) +
sizeof(*pAuthSuite) +
sizeof(tCsrRSNCapabilities));
if (pPMK->cPMKIDs) {
pRSNIe->IeHeader.Length += (uint8_t) (sizeof(uint16_t) +
(pPMK->cPMKIDs *
CSR_RSN_PMKID_SIZE));
}
#ifdef WLAN_FEATURE_11W
if (pProfile->MFPEnabled) {
if (0 == pPMK->cPMKIDs)
pRSNIe->IeHeader.Length += sizeof(uint16_t);
pRSNIe->IeHeader.Length += CSR_WPA_OUI_SIZE;
}
#endif
/* return the size of the IE header (total) constructed... */
cbRSNIe = pRSNIe->IeHeader.Length + sizeof(pRSNIe->IeHeader);
} while (0);
if (!pIes && pIesLocal) {
/* locally allocated */
cdf_mem_free(pIesLocal);
}
return cbRSNIe;
}
#ifdef FEATURE_WLAN_WAPI
/**
* csr_get_wapi_information() - to get WAPI infomation
* @hal: pointer to HAL
* @auth_type: auth type
* @encr_type: encryption type
* @mc_encryption: multicast encryption type
* @wapi_ie: pointer to WAPI IE
* @ucast_cipher: Unicast cipher
* @mcast_cipher: Multicast cipher
* @auth_suite: Authentication suite
* @negotiated_authtype: Negotiated auth type
* @negotiated_mccipher: negotiated multicast cipher
*
* This routine will get all WAPI information
*
* Return: bool
*/
bool csr_get_wapi_information(tHalHandle hal, tCsrAuthList *auth_type,
eCsrEncryptionType encr_type,
tCsrEncryptionList *mc_encryption,
tDot11fIEWAPI *wapi_ie, uint8_t *ucast_cipher,
uint8_t *mcast_cipher, uint8_t *auth_suite,
eCsrAuthType *negotiated_authtype,
eCsrEncryptionType *negotiated_mccipher)
{
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
bool acceptable_cipher = false;
uint8_t c_ucast_cipher = 0;
uint8_t c_mcast_cipher = 0;
uint8_t c_auth_suites = 0, i;
uint8_t unicast[CSR_WAPI_OUI_SIZE];
uint8_t multicast[CSR_WAPI_OUI_SIZE];
uint8_t authsuites[CSR_WAPI_MAX_AUTH_SUITES][CSR_WAPI_OUI_SIZE];
uint8_t authentication[CSR_WAPI_OUI_SIZE];
uint8_t mccipher_arr[CSR_WAPI_MAX_MULTICAST_CYPHERS][CSR_WAPI_OUI_SIZE];
eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
uint8_t wapioui_idx = 0;
if (!wapi_ie->present)
goto end;
c_mcast_cipher++;
cdf_mem_copy(mccipher_arr, wapi_ie->multicast_cipher_suite,
CSR_WAPI_OUI_SIZE);
c_ucast_cipher = (uint8_t) (wapi_ie->unicast_cipher_suite_count);
c_auth_suites = (uint8_t) (wapi_ie->akm_suite_count);
for (i = 0; i < c_auth_suites && i < CSR_WAPI_MAX_AUTH_SUITES; i++)
cdf_mem_copy((void *)&authsuites[i],
(void *)&wapi_ie->akm_suites[i], CSR_WAPI_OUI_SIZE);
wapioui_idx = csr_get_oui_index_from_cipher(encr_type);
if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) {
sms_log(mac_ctx, LOGE,
FL("Wapi OUI index = %d out of limit"),
wapioui_idx);
acceptable_cipher = false;
goto end;
}
/* Check - Is requested unicast Cipher supported by the BSS. */
acceptable_cipher = csr_match_wapi_oui_index(mac_ctx,
wapi_ie->unicast_cipher_suites,
c_ucast_cipher, wapioui_idx, unicast);
if (!acceptable_cipher)
goto end;
/* unicast is supported. Pick the first matching Group cipher, if any */
for (i = 0; i < mc_encryption->numEntries; i++) {
wapioui_idx = csr_get_oui_index_from_cipher(
mc_encryption->encryptionType[i]);
if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) {
sms_log(mac_ctx, LOGE,
FL("Wapi OUI index = %d out of limit"),
wapioui_idx);
acceptable_cipher = false;
break;
}
acceptable_cipher = csr_match_wapi_oui_index(mac_ctx,
mccipher_arr, c_mcast_cipher,
wapioui_idx, multicast);
if (acceptable_cipher)
break;
}
if (!acceptable_cipher)
goto end;
if (negotiated_mccipher)
*negotiated_mccipher =
mc_encryption->encryptionType[i];
/*
* Ciphers are supported, Match authentication algorithm and
* pick first matching authtype
*/
if (csr_is_auth_wapi_cert
(mac_ctx, authsuites, c_auth_suites, authentication)) {
neg_authtype =
eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE;
} else if (csr_is_auth_wapi_psk(mac_ctx, authsuites,
c_auth_suites, authentication)) {
neg_authtype = eCSR_AUTH_TYPE_WAPI_WAI_PSK;
} else {
acceptable_cipher = false;
neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
}
/* Caller doesn't care about auth type, or BSS doesn't match */
if ((0 == auth_type->numEntries) || (false == acceptable_cipher))
goto end;
acceptable_cipher = false;
for (i = 0; i < auth_type->numEntries; i++) {
if (auth_type->authType[i] == neg_authtype) {
acceptable_cipher = true;
break;
}
}
end:
if (acceptable_cipher) {
if (mcast_cipher)
cdf_mem_copy(mcast_cipher, multicast,
CSR_WAPI_OUI_SIZE);
if (ucast_cipher)
cdf_mem_copy(ucast_cipher, unicast, CSR_WAPI_OUI_SIZE);
if (auth_suite)
cdf_mem_copy(auth_suite, authentication,
CSR_WAPI_OUI_SIZE);
if (negotiated_authtype)
*negotiated_authtype = neg_authtype;
}
return acceptable_cipher;
}
bool csr_is_wapi_match(tHalHandle hHal, tCsrAuthList *pAuthType,
eCsrEncryptionType enType, tCsrEncryptionList *pEnMcType,
tDot11fBeaconIEs *pIes, eCsrAuthType *pNegotiatedAuthType,
eCsrEncryptionType *pNegotiatedMCCipher)
{
bool fWapiMatch = false;
/* See if the cyphers in the Bss description match with the settings in the profile. */
fWapiMatch =
csr_get_wapi_information(hHal, pAuthType, enType, pEnMcType,
&pIes->WAPI, NULL, NULL, NULL,
pNegotiatedAuthType, pNegotiatedMCCipher);
return fWapiMatch;
}
bool csr_lookup_bkid(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t *pBSSId,
uint8_t *pBKId)
{
bool fRC = false, fMatchFound = false;
uint32_t Index;
tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
if (!pSession) {
sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
return false;
}
do {
for (Index = 0; Index < pSession->NumBkidCache; Index++) {
sms_log(pMac, LOGW, "match BKID " MAC_ADDRESS_STR " to ",
MAC_ADDR_ARRAY(pBSSId));
if (cdf_mem_compare
(pBSSId, pSession->BkidCacheInfo[Index].BSSID.bytes,
sizeof(struct cdf_mac_addr))) {
/* match found */
fMatchFound = true;
break;
}
}
if (!fMatchFound)
break;
cdf_mem_copy(pBKId, pSession->BkidCacheInfo[Index].BKID,
CSR_WAPI_BKID_SIZE);
fRC = true;
} while (0);
sms_log(pMac, LOGW,
"csr_lookup_bkid called return match = %d pMac->roam.NumBkidCache = %d",
fRC, pSession->NumBkidCache);
return fRC;
}
uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId,
tCsrRoamProfile *pProfile,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe)
{
bool fWapiMatch = false;
uint8_t cbWapiIe = 0;
uint8_t UnicastCypher[CSR_WAPI_OUI_SIZE];
uint8_t MulticastCypher[CSR_WAPI_OUI_SIZE];
uint8_t AuthSuite[CSR_WAPI_OUI_SIZE];
uint8_t BKId[CSR_WAPI_BKID_SIZE];
uint8_t *pWapi = NULL;
bool fBKIDFound = false;
tDot11fBeaconIEs *pIesLocal = pIes;
do {
if (!csr_is_profile_wapi(pProfile))
break;
if (!pIesLocal
&&
(!CDF_IS_STATUS_SUCCESS
(csr_get_parsed_bss_description_ies
(pMac, pSirBssDesc, &pIesLocal)))) {
break;
}
/* See if the cyphers in the Bss description match with the settings in the profile. */
fWapiMatch =
csr_get_wapi_information(pMac, &pProfile->AuthType,
pProfile->negotiatedUCEncryptionType,
&pProfile->mcEncryptionType,
&pIesLocal->WAPI, UnicastCypher,
MulticastCypher, AuthSuite, NULL,
NULL);
if (!fWapiMatch)
break;
cdf_mem_set(pWapiIe, sizeof(tCsrWapiIe), 0);
pWapiIe->IeHeader.ElementID = DOT11F_EID_WAPI;
pWapiIe->Version = CSR_WAPI_VERSION_SUPPORTED;
pWapiIe->cAuthenticationSuites = 1;
cdf_mem_copy(&pWapiIe->AuthOui[0], AuthSuite,
sizeof(AuthSuite));
pWapi = (uint8_t *) (&pWapiIe->AuthOui[1]);
*pWapi = (uint16_t) 1; /* cUnicastCyphers */
pWapi += 2;
cdf_mem_copy(pWapi, UnicastCypher, sizeof(UnicastCypher));
pWapi += sizeof(UnicastCypher);
cdf_mem_copy(pWapi, MulticastCypher, sizeof(MulticastCypher));
pWapi += sizeof(MulticastCypher);
/* WAPI capabilities follows the Auth Suite (two octects) */
/* we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */
/* & since we already did a memset pWapiIe to 0, skip these fields */
pWapi += 2;
fBKIDFound =
csr_lookup_bkid(pMac, sessionId, pSirBssDesc->bssId,
&(BKId[0]));
if (fBKIDFound) {
/* Do we need to change the endianness here */
*pWapi = (uint16_t) 1; /* cBKIDs */
pWapi += 2;
cdf_mem_copy(pWapi, BKId, CSR_WAPI_BKID_SIZE);
} else {
*pWapi = 0;
pWapi += 1;
*pWapi = 0;
pWapi += 1;
}
/* Add in the IE fields except the IE header */
/* Add BKID count and BKID (if any) */
pWapiIe->IeHeader.Length =
(uint8_t) (sizeof(*pWapiIe) - sizeof(pWapiIe->IeHeader));
/*2 bytes for BKID Count field */
pWapiIe->IeHeader.Length += sizeof(uint16_t);
if (fBKIDFound) {
pWapiIe->IeHeader.Length += CSR_WAPI_BKID_SIZE;
}
/* return the size of the IE header (total) constructed... */
cbWapiIe = pWapiIe->IeHeader.Length + sizeof(pWapiIe->IeHeader);
} while (0);
if (!pIes && pIesLocal) {
/* locally allocated */
cdf_mem_free(pIesLocal);
}
return cbWapiIe;
}
#endif /* FEATURE_WLAN_WAPI */
/**
* csr_get_wpa_cyphers() - to get WPA cipher info
* @mac_ctx: pointer to mac context
* @auth_type: auth type
* @encr_type: encryption type
* @mc_encryption: multicast encryption type
* @wpa_ie: pointer to WPA IE
* @ucast_cipher: Unicast cipher
* @mcast_cipher: Multicast cipher
* @auth_suite: Authentication suite
* @negotiated_authtype: Negotiated auth type
* @negotiated_mccipher: negotiated multicast cipher
*
* This routine will get all WPA information
*
* Return: bool
*/
bool csr_get_wpa_cyphers(tpAniSirGlobal mac_ctx, tCsrAuthList *auth_type,
eCsrEncryptionType encr_type, tCsrEncryptionList *mc_encryption,
tDot11fIEWPA *wpa_ie, uint8_t *ucast_cipher,
uint8_t *mcast_cipher, uint8_t *auth_suite,
eCsrAuthType *negotiated_authtype,
eCsrEncryptionType *negotiated_mccipher)
{
bool acceptable_cipher = false;
uint8_t c_ucast_cipher = 0;
uint8_t c_mcast_cipher = 0;
uint8_t c_auth_suites = 0;
uint8_t unicast[CSR_WPA_OUI_SIZE];
uint8_t multicast[CSR_WPA_OUI_SIZE];
uint8_t authentication[CSR_WPA_OUI_SIZE];
uint8_t mccipher_arr[1][CSR_WPA_OUI_SIZE];
uint8_t i;
eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
if (!wpa_ie->present)
goto end;
c_mcast_cipher = 1;
cdf_mem_copy(mccipher_arr, wpa_ie->multicast_cipher, CSR_WPA_OUI_SIZE);
c_ucast_cipher = (uint8_t) (wpa_ie->unicast_cipher_count);
c_auth_suites = (uint8_t) (wpa_ie->auth_suite_count);
/* Check - Is requested unicast Cipher supported by the BSS. */
acceptable_cipher = csr_match_wpaoui_index(mac_ctx,
wpa_ie->unicast_ciphers, c_ucast_cipher,
csr_get_oui_index_from_cipher(encr_type),
unicast);
if (!acceptable_cipher)
goto end;
/* unicast is supported. Pick the first matching Group cipher, if any */
for (i = 0; i < mc_encryption->numEntries; i++) {
acceptable_cipher = csr_match_wpaoui_index(mac_ctx,
mccipher_arr, c_mcast_cipher,
csr_get_oui_index_from_cipher(
mc_encryption->encryptionType[i]),
multicast);
if (acceptable_cipher)
break;
}
if (!acceptable_cipher)
goto end;
if (negotiated_mccipher)
*negotiated_mccipher = mc_encryption->encryptionType[i];
/* Initializing with false as it has true value already */
acceptable_cipher = false;
for (i = 0; i < auth_type->numEntries; i++) {
/*
* Ciphers are supported, Match authentication algorithm and
* pick first matching authtype
*/
if (csr_is_auth_wpa(mac_ctx, wpa_ie->auth_suites, c_auth_suites,
authentication)) {
if (eCSR_AUTH_TYPE_WPA == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_WPA;
}
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) &&
csr_is_auth_wpa_psk(mac_ctx,
wpa_ie->auth_suites, c_auth_suites,
authentication)) {
if (eCSR_AUTH_TYPE_WPA_PSK == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_WPA_PSK;
}
#ifdef FEATURE_WLAN_ESE
if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
&& csr_is_ese_cckm_auth_wpa(mac_ctx,
wpa_ie->auth_suites, c_auth_suites,
authentication)) {
if (eCSR_AUTH_TYPE_CCKM_WPA == auth_type->authType[i])
neg_authtype = eCSR_AUTH_TYPE_CCKM_WPA;
}
#endif /* FEATURE_WLAN_ESE */
/*
* The 1st auth type in the APs WPA IE, to match stations
* connecting profiles auth type will cause us to exit this
* loop. This is added as some APs advertise multiple akms in
* the WPA IE
*/
if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) {
acceptable_cipher = true;
break;
}
}
end:
if (acceptable_cipher) {
if (mcast_cipher)
cdf_mem_copy((uint8_t **) mcast_cipher, multicast,
CSR_WPA_OUI_SIZE);
if (ucast_cipher)
cdf_mem_copy((uint8_t **) ucast_cipher, unicast,
CSR_WPA_OUI_SIZE);
if (auth_suite)
cdf_mem_copy((uint8_t **) auth_suite, authentication,
CSR_WPA_OUI_SIZE);
if (negotiated_authtype)
*negotiated_authtype = neg_authtype;
}
return acceptable_cipher;
}
bool csr_is_wpa_encryption_match(tpAniSirGlobal pMac, tCsrAuthList *pAuthType,
eCsrEncryptionType enType,
tCsrEncryptionList *pEnMcType,
tDot11fBeaconIEs *pIes,
eCsrAuthType *pNegotiatedAuthtype,
eCsrEncryptionType *pNegotiatedMCCipher)
{
bool fWpaMatch = false;
/* See if the cyphers in the Bss description match with the settings in the profile. */
fWpaMatch =
csr_get_wpa_cyphers(pMac, pAuthType, enType, pEnMcType, &pIes->WPA,
NULL, NULL, NULL, pNegotiatedAuthtype,
pNegotiatedMCCipher);
return fWpaMatch;
}
uint8_t csr_construct_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
bool fWpaMatch;
uint8_t cbWpaIe = 0;
uint8_t UnicastCypher[CSR_WPA_OUI_SIZE];
uint8_t MulticastCypher[CSR_WPA_OUI_SIZE];
uint8_t AuthSuite[CSR_WPA_OUI_SIZE];
tCsrWpaAuthIe *pAuthSuite;
tDot11fBeaconIEs *pIesLocal = pIes;
do {
if (!csr_is_profile_wpa(pProfile))
break;
if (!pIesLocal
&&
(!CDF_IS_STATUS_SUCCESS
(csr_get_parsed_bss_description_ies
(pMac, pSirBssDesc, &pIesLocal)))) {
break;
}
/* See if the cyphers in the Bss description match with the settings in the profile. */
fWpaMatch =
csr_get_wpa_cyphers(hHal, &pProfile->AuthType,
pProfile->negotiatedUCEncryptionType,
&pProfile->mcEncryptionType,
&pIesLocal->WPA, UnicastCypher,
MulticastCypher, AuthSuite, NULL, NULL);
if (!fWpaMatch)
break;
pWpaIe->IeHeader.ElementID = SIR_MAC_WPA_EID;
cdf_mem_copy(pWpaIe->Oui, csr_wpa_oui[01], sizeof(pWpaIe->Oui));
pWpaIe->Version = CSR_WPA_VERSION_SUPPORTED;
cdf_mem_copy(pWpaIe->MulticastOui, MulticastCypher,
sizeof(MulticastCypher));
pWpaIe->cUnicastCyphers = 1;
cdf_mem_copy(&pWpaIe->UnicastOui[0], UnicastCypher,
sizeof(UnicastCypher));
pAuthSuite =
(tCsrWpaAuthIe *) (&pWpaIe->
UnicastOui[pWpaIe->cUnicastCyphers]);
pAuthSuite->cAuthenticationSuites = 1;
cdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite,
sizeof(AuthSuite));
/* The WPA capabilities follows the Auth Suite (two octects)-- */
/* this field is optional, and we always "send" zero, so just */
/* remove it. This is consistent with our assumptions in the */
/* frames compiler; c.f. bug 15234: */
/* http://gold.woodsidenet.com/bugzilla/show_bug.cgi?id=15234 */
/* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */
/* Add in the size of the Auth suite (count plus a single OUI) */
pWpaIe->IeHeader.Length =
sizeof(*pWpaIe) - sizeof(pWpaIe->IeHeader) +
sizeof(*pAuthSuite);
/* return the size of the IE header (total) constructed... */
cbWpaIe = pWpaIe->IeHeader.Length + sizeof(pWpaIe->IeHeader);
} while (0);
if (!pIes && pIesLocal) {
/* locally allocated */
cdf_mem_free(pIesLocal);
}
return cbWpaIe;
}
/* If a WPAIE exists in the profile, just use it. Or else construct one from the BSS */
/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */
uint8_t csr_retrieve_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
uint8_t cbWpaIe = 0;
do {
if (!csr_is_profile_wpa(pProfile))
break;
if (pProfile->nWPAReqIELength && pProfile->pWPAReqIE) {
if (SIR_MAC_WPA_IE_MAX_LENGTH >=
pProfile->nWPAReqIELength) {
cbWpaIe = (uint8_t) pProfile->nWPAReqIELength;
cdf_mem_copy(pWpaIe, pProfile->pWPAReqIE,
cbWpaIe);
} else {
sms_log(pMac, LOGW,
" csr_retrieve_wpa_ie detect invalid WPA IE length (%d) ",
pProfile->nWPAReqIELength);
}
} else {
cbWpaIe =
csr_construct_wpa_ie(pMac, pProfile, pSirBssDesc, pIes,
pWpaIe);
}
} while (0);
return cbWpaIe;
}
/* If a RSNIE exists in the profile, just use it. Or else construct one from the BSS */
/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */
uint8_t csr_retrieve_rsn_ie(tHalHandle hHal, uint32_t sessionId,
tCsrRoamProfile *pProfile,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
uint8_t cbRsnIe = 0;
do {
if (!csr_is_profile_rsn(pProfile))
break;
#ifdef FEATURE_WLAN_LFR
if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) {
/* If "Legacy Fast Roaming" is enabled ALWAYS rebuild the RSN IE from */
/* scratch. So it contains the current PMK-IDs */
cbRsnIe =
csr_construct_rsn_ie(pMac, sessionId, pProfile,
pSirBssDesc, pIes, pRsnIe);
} else
#endif
if (pProfile->nRSNReqIELength && pProfile->pRSNReqIE) {
/* If you have one started away, re-use it. */
if (SIR_MAC_WPA_IE_MAX_LENGTH >=
pProfile->nRSNReqIELength) {
cbRsnIe = (uint8_t) pProfile->nRSNReqIELength;
cdf_mem_copy(pRsnIe, pProfile->pRSNReqIE,
cbRsnIe);
} else {
sms_log(pMac, LOGW,
" csr_retrieve_rsn_ie detect invalid RSN IE length (%d) ",
pProfile->nRSNReqIELength);
}
} else {
cbRsnIe =
csr_construct_rsn_ie(pMac, sessionId, pProfile,
pSirBssDesc, pIes, pRsnIe);
}
} while (0);
return cbRsnIe;
}
#ifdef FEATURE_WLAN_WAPI
/* If a WAPI IE exists in the profile, just use it. Or else construct one from the BSS */
/* Caller allocated memory for pWapiIe and guarrantee it can contain a max length WAPI IE */
uint8_t csr_retrieve_wapi_ie(tHalHandle hHal, uint32_t sessionId,
tCsrRoamProfile *pProfile,
tSirBssDescription *pSirBssDesc,
tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
uint8_t cbWapiIe = 0;
do {
if (!csr_is_profile_wapi(pProfile))
break;
if (pProfile->nWAPIReqIELength && pProfile->pWAPIReqIE) {
if (DOT11F_IE_WAPI_MAX_LEN >=
pProfile->nWAPIReqIELength) {
cbWapiIe = (uint8_t) pProfile->nWAPIReqIELength;
cdf_mem_copy(pWapiIe, pProfile->pWAPIReqIE,
cbWapiIe);
} else {
sms_log(pMac, LOGW,
" csr_retrieve_wapi_ie detect invalid WAPI IE length (%d) ",
pProfile->nWAPIReqIELength);
}
} else {
cbWapiIe =
csr_construct_wapi_ie(pMac, sessionId, pProfile,
pSirBssDesc, pIes, pWapiIe);
}
} while (0);
return cbWapiIe;
}
#endif /* FEATURE_WLAN_WAPI */
bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate)
{
bool fSupported = false;
uint16_t nonBasicRate =
(uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK));
switch (nonBasicRate) {
case eCsrSuppRate_1Mbps:
case eCsrSuppRate_2Mbps:
case eCsrSuppRate_5_5Mbps:
case eCsrSuppRate_11Mbps:
fSupported = true;
break;
default:
break;
}
return fSupported;
}
bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate)
{
bool fSupported = false;
uint16_t nonBasicRate =
(uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK));
switch (nonBasicRate) {
case eCsrSuppRate_6Mbps:
case eCsrSuppRate_9Mbps:
case eCsrSuppRate_12Mbps:
case eCsrSuppRate_18Mbps:
case eCsrSuppRate_24Mbps:
case eCsrSuppRate_36Mbps:
case eCsrSuppRate_48Mbps:
case eCsrSuppRate_54Mbps:
fSupported = true;
break;
default:
break;
}
return fSupported;
}
tAniEdType csr_translate_encrypt_type_to_ed_type(eCsrEncryptionType EncryptType)
{
tAniEdType edType;
switch (EncryptType) {
default:
case eCSR_ENCRYPT_TYPE_NONE:
edType = eSIR_ED_NONE;
break;
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP40:
edType = eSIR_ED_WEP40;
break;
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP104:
edType = eSIR_ED_WEP104;
break;
case eCSR_ENCRYPT_TYPE_TKIP:
edType = eSIR_ED_TKIP;
break;
case eCSR_ENCRYPT_TYPE_AES:
edType = eSIR_ED_CCMP;
break;
#ifdef FEATURE_WLAN_WAPI
case eCSR_ENCRYPT_TYPE_WPI:
edType = eSIR_ED_WPI;
break;
#endif
#ifdef WLAN_FEATURE_11W
/* 11w BIP */
case eCSR_ENCRYPT_TYPE_AES_CMAC:
edType = eSIR_ED_AES_128_CMAC;
break;
#endif
}
return edType;
}
/**
* csr_validate_wep() - to validate wep
* @uc_encry_type: unicast encryption type
* @auth_list: Auth list
* @mc_encryption_list: multicast encryption type
* @negotiated_authtype: negotiated auth type
* @negotiated_mc_encry: negotiated mc encry type
* @bss_descr: BSS description
* @ie_ptr: IE pointer
*
* This function just checks whether HDD is giving correct values for
* Multicast cipher and Auth
*
* Return: bool
*/
bool csr_validate_wep(tpAniSirGlobal mac_ctx, eCsrEncryptionType uc_encry_type,
tCsrAuthList *auth_list,
tCsrEncryptionList *mc_encryption_list,
eCsrAuthType *negotiated_authtype,
eCsrEncryptionType *negotiated_mc_encry,
tSirBssDescription *bss_descr, tDot11fBeaconIEs *ie_ptr)
{
uint32_t idx;
bool match = false;
eCsrAuthType negotiated_auth = eCSR_AUTH_TYPE_OPEN_SYSTEM;
eCsrEncryptionType negotiated_mccipher = eCSR_ENCRYPT_TYPE_UNKNOWN;
/* If privacy bit is not set, consider no match */
if (!csr_is_privacy(bss_descr))
goto end;
for (idx = 0; idx < mc_encryption_list->numEntries; idx++) {
switch (mc_encryption_list->encryptionType[idx]) {
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP104:
/*
* Multicast list may contain WEP40/WEP104.
* Check whether it matches UC.
*/
if (uc_encry_type ==
mc_encryption_list->encryptionType[idx]) {
match = true;
negotiated_mccipher =
mc_encryption_list->encryptionType[idx];
}
break;
default:
match = false;
break;
}
if (match)
break;
}
if (!match)
goto end;
for (idx = 0; idx < auth_list->numEntries; idx++) {
switch (auth_list->authType[idx]) {
case eCSR_AUTH_TYPE_OPEN_SYSTEM:
case eCSR_AUTH_TYPE_SHARED_KEY:
case eCSR_AUTH_TYPE_AUTOSWITCH:
match = true;
negotiated_auth = auth_list->authType[idx];
break;
default:
match = false;
}
if (match)
break;
}
if (!match)
goto end;
if (!ie_ptr)
goto end;
/*
* In case of WPA / WPA2, check whether it supports WEP as well.
* Prepare the encryption type for WPA/WPA2 functions
*/
if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == uc_encry_type)
uc_encry_type = eCSR_ENCRYPT_TYPE_WEP40;
else if (eCSR_ENCRYPT_TYPE_WEP104 == uc_encry_type)
uc_encry_type = eCSR_ENCRYPT_TYPE_WEP104;
/* else we can use the encryption type directly */
if (ie_ptr->WPA.present) {
match = cdf_mem_compare(ie_ptr->WPA.multicast_cipher,
csr_wpa_oui[csr_get_oui_index_from_cipher(
uc_encry_type)],
CSR_WPA_OUI_SIZE);
if (match)
goto end;
}
if (ie_ptr->RSN.present) {
match = cdf_mem_compare(ie_ptr->RSN.gp_cipher_suite,
csr_rsn_oui[csr_get_oui_index_from_cipher(
uc_encry_type)],
CSR_RSN_OUI_SIZE);
}
end:
if (match) {
if (negotiated_authtype)
*negotiated_authtype = negotiated_auth;
if (negotiated_mc_encry)
*negotiated_mc_encry = negotiated_mccipher;
}
return match;
}
/**
* csr_validate_open_none() - Check if the security is matching
* @bss_desc: BSS Descriptor on which the check is done
* @mc_enc_type: Multicast encryption type
* @mc_cipher: Multicast Cipher
* @auth_type: Authentication type
* @neg_auth_type: Negotiated Auth type with the AP
*
* Return: Boolean value to tell if matched or not.
*/
static bool csr_validate_open_none(tSirBssDescription *bss_desc,
tCsrEncryptionList *mc_enc_type, eCsrEncryptionType *mc_cipher,
tCsrAuthList *auth_type, eCsrAuthType *neg_auth_type)
{
bool match;
uint8_t idx;
/*
* for NO encryption, if the Bss description has the
* Privacy bit turned on, then encryption is required
* so we have to reject this Bss.
*/
if (csr_is_privacy(bss_desc))
match = false;
else
match = true;
if (match) {
match = false;
/* Check MC cipher and Auth type requested. */
for (idx = 0; idx < mc_enc_type->numEntries; idx++) {
if (eCSR_ENCRYPT_TYPE_NONE ==
mc_enc_type->encryptionType[idx]) {
match = true;
*mc_cipher = mc_enc_type->encryptionType[idx];
break;
}
}
if (!match)
return match;
match = false;
/* Check Auth list. It should contain AuthOpen. */
for (idx = 0; idx < auth_type->numEntries; idx++) {
if ((eCSR_AUTH_TYPE_OPEN_SYSTEM ==
auth_type->authType[idx]) ||
(eCSR_AUTH_TYPE_AUTOSWITCH ==
auth_type->authType[idx])) {
match = true;
*neg_auth_type =
eCSR_AUTH_TYPE_OPEN_SYSTEM;
break;
}
}
if (!match)
return match;
}
return match;
}
/**
* csr_validate_any_default() - Check if the security is matching
* @hal: Global HAL handle
* @auth_type: Authentication type
* @mc_enc_type: Multicast encryption type
* @mfp_enabled: Management frame protection feature
* @mfp_required: Mangement frame protection mandatory
* @mfp_capable: Device capable of MFP
* @ies_ptr: Pointer to the IE fields
* @neg_auth_type: Negotiated Auth type with the AP
* @bss_desc: BSS Descriptor
* @neg_uc_cipher: Negotiated unicast cipher suite
* @neg_mc_cipher: Negotiated multicast cipher
*
* Return: Boolean value to tell if matched or not.
*/
static bool csr_validate_any_default(tHalHandle hal, tCsrAuthList *auth_type,
tCsrEncryptionList *mc_enc_type, bool *mfp_enabled,
uint8_t *mfp_required, uint8_t *mfp_capable,
tDot11fBeaconIEs *ies_ptr, eCsrAuthType *neg_auth_type,
tSirBssDescription *bss_desc, eCsrEncryptionType *uc_cipher,
eCsrEncryptionType *mc_cipher)
{
bool match_any = false;
bool match = true;
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
/* It is allowed to match anything. Try the more secured ones first. */
if (ies_ptr) {
/* Check AES first */
*uc_cipher = eCSR_ENCRYPT_TYPE_AES;
match_any = csr_is_rsn_match(hal, auth_type,
*uc_cipher, mc_enc_type, mfp_enabled,
mfp_required, mfp_capable, ies_ptr,
neg_auth_type, mc_cipher);
if (!match_any) {
/* Check TKIP */
*uc_cipher = eCSR_ENCRYPT_TYPE_TKIP;
match_any = csr_is_rsn_match(hal, auth_type, *uc_cipher,
mc_enc_type, mfp_enabled, mfp_required,
mfp_capable, ies_ptr, neg_auth_type,
mc_cipher);
}
#ifdef FEATURE_WLAN_WAPI
if (!match_any) {
/* Check WAPI */
*uc_cipher = eCSR_ENCRYPT_TYPE_WPI;
match_any = csr_is_wapi_match(hal, auth_type,
*uc_cipher, mc_enc_type, ies_ptr,
neg_auth_type, mc_cipher);
}
#endif
}
if (match_any)
return match;
*uc_cipher = eCSR_ENCRYPT_TYPE_WEP104;
if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
neg_auth_type, mc_cipher, bss_desc, ies_ptr))
return match;
*uc_cipher = eCSR_ENCRYPT_TYPE_WEP40;
if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
neg_auth_type, mc_cipher, bss_desc, ies_ptr))
return match;
*uc_cipher = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
neg_auth_type, mc_cipher, bss_desc, ies_ptr))
return match;
*uc_cipher = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
neg_auth_type, mc_cipher, bss_desc, ies_ptr))
return match;
/* It must be open and no enc */
if (csr_is_privacy(bss_desc)) {
match = false;
return match;
}
*neg_auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM;
*mc_cipher = eCSR_ENCRYPT_TYPE_NONE;
*uc_cipher = eCSR_ENCRYPT_TYPE_NONE;
return match;
}
/**
* csr_is_security_match() - Check if the security is matching
* @hal: Global HAL handle
* @auth_type: Authentication type
* @uc_enc_type: Unicast Encryption type
* @mc_enc_type: Multicast encryption type
* @mfp_enabled: Management frame protection feature
* @mfp_required: Mangement frame protection mandatory
* @mfp_capable: Device capable of MFP
* @bss_desc: BSS Descriptor
* @ies_ptr: Pointer to the IE fields
* @neg_auth_type: Negotiated Auth type with the AP
* @neg_uc_cipher: Negotiated unicast cipher suite
* @neg_mc_cipher: Negotiated multicast cipher
*
* Return: Boolean value to tell if matched or not.
*/
bool csr_is_security_match(tHalHandle hal, tCsrAuthList *auth_type,
tCsrEncryptionList *uc_enc_type,
tCsrEncryptionList *mc_enc_type, bool *mfp_enabled,
uint8_t *mfp_required, uint8_t *mfp_capable,
tSirBssDescription *bss_desc, tDot11fBeaconIEs *ies_ptr,
eCsrAuthType *neg_auth_type,
eCsrEncryptionType *neg_uc_cipher,
eCsrEncryptionType *neg_mc_cipher)
{
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
bool match = false;
uint8_t i;
eCsrEncryptionType mc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN;
eCsrEncryptionType uc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN;
eCsrAuthType local_neg_auth_type = eCSR_AUTH_TYPE_UNKNOWN;
for (i = 0; ((i < uc_enc_type->numEntries) && (!match)); i++) {
uc_cipher = uc_enc_type->encryptionType[i];
/*
* If the Bss description shows the Privacy bit is on, then we
* must have some sort of encryption configured for the profile
* to work. Don't attempt to join networks with Privacy bit
* set when profiles say NONE for encryption type.
*/
switch (uc_cipher) {
case eCSR_ENCRYPT_TYPE_NONE:
match = csr_validate_open_none(bss_desc, mc_enc_type,
&mc_cipher, auth_type,
&local_neg_auth_type);
break;
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
/*
* !! might want to check for WEP keys set in the
* Profile.... ? !! don't need to have the privacy bit
* in the Bss description. Many AP policies make
* legacy encryption 'optional' so we don't know if we
* can associate or not. The AP will reject if
* encryption is not allowed without the Privacy bit
* turned on.
*/
match = csr_validate_wep(mac_ctx, uc_cipher, auth_type,
mc_enc_type, &local_neg_auth_type,
&mc_cipher, bss_desc, ies_ptr);
break;
/* these are all of the WPA encryption types... */
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP104:
match = csr_validate_wep(mac_ctx, uc_cipher, auth_type,
mc_enc_type, &local_neg_auth_type,
&mc_cipher, bss_desc, ies_ptr);
break;
case eCSR_ENCRYPT_TYPE_TKIP:
case eCSR_ENCRYPT_TYPE_AES:
if (!ies_ptr) {
match = false;
break;
}
/* First check if there is a RSN match */
match = csr_is_rsn_match(mac_ctx, auth_type,
uc_cipher, mc_enc_type,
mfp_enabled, mfp_required,
mfp_capable, ies_ptr,
&local_neg_auth_type,
&mc_cipher);
/* If not RSN, then check WPA match */
if (!match)
match = csr_is_wpa_encryption_match(
mac_ctx, auth_type,
uc_cipher, mc_enc_type,
ies_ptr,
&local_neg_auth_type,
&mc_cipher);
break;
#ifdef FEATURE_WLAN_WAPI
case eCSR_ENCRYPT_TYPE_WPI: /* WAPI */
if (ies_ptr)
match = csr_is_wapi_match(hal, auth_type,
uc_cipher, mc_enc_type, ies_ptr,
&local_neg_auth_type,
&mc_cipher);
else
match = false;
break;
#endif /* FEATURE_WLAN_WAPI */
case eCSR_ENCRYPT_TYPE_ANY:
default:
match = csr_validate_any_default(hal, auth_type,
mc_enc_type, mfp_enabled, mfp_required,
mfp_capable, ies_ptr,
&local_neg_auth_type, bss_desc,
&uc_cipher, &mc_cipher);
break;
}
}
if (match) {
if (neg_uc_cipher)
*neg_uc_cipher = uc_cipher;
if (neg_mc_cipher)
*neg_mc_cipher = mc_cipher;
if (neg_auth_type)
*neg_auth_type = local_neg_auth_type;
}
return match;
}
bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len,
uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired)
{
bool fMatch = false;
do {
/*
* Check for the specification of the Broadcast SSID at the
* beginning of the list. If specified, then all SSIDs are
* matches (broadcast SSID means accept all SSIDs).
*/
if (ssid1Len == 0) {
fMatch = true;
break;
}
/* There are a few special cases. If the Bss description has a Broadcast SSID, */
/* then our Profile must have a single SSID without Wildcards so we can program */
/* the SSID. */
/* SSID could be suppressed in beacons. In that case SSID IE has valid length */
/* but the SSID value is all NULL characters. That condition is trated same */
/* as NULL SSID */
if (csr_is_nullssid(bssSsid, bssSsidLen)) {
if (false == fSsidRequired) {
fMatch = true;
break;
}
}
if (ssid1Len != bssSsidLen)
break;
if (cdf_mem_compare(bssSsid, ssid1, bssSsidLen)) {
fMatch = true;
break;
}
} while (0);
return fMatch;
}
/* Null ssid means match */
bool csr_is_ssid_in_list(tHalHandle hHal, tSirMacSSid *pSsid,
tCsrSSIDs *pSsidList)
{
bool fMatch = false;
uint32_t i;
if (pSsidList && pSsid) {
for (i = 0; i < pSsidList->numOfSSIDs; i++) {
if (csr_is_nullssid
(pSsidList->SSIDList[i].SSID.ssId,
pSsidList->SSIDList[i].SSID.length)
||
((pSsidList->SSIDList[i].SSID.length ==
pSsid->length)
&& cdf_mem_compare(pSsid->ssId,
pSsidList->SSIDList[i].SSID.
ssId, pSsid->length))) {
fMatch = true;
break;
}
}
}
return fMatch;
}
bool csr_is_bssid_match(tHalHandle hHal, struct cdf_mac_addr *pProfBssid,
struct cdf_mac_addr *BssBssid)
{
bool fMatch = false;
struct cdf_mac_addr ProfileBssid;
/* for efficiency of the MAC_ADDRESS functions, move the */
/* Bssid's into MAC_ADDRESS structs. */
cdf_mem_copy(&ProfileBssid, pProfBssid, sizeof(struct cdf_mac_addr));
do {
/* Give the profile the benefit of the doubt... accept either all 0 or */
/* the real broadcast Bssid (all 0xff) as broadcast Bssids (meaning to */
/* match any Bssids). */
if (cdf_is_macaddr_zero(&ProfileBssid) ||
cdf_is_macaddr_broadcast(&ProfileBssid)) {
fMatch = true;
break;
}
if (cdf_is_macaddr_equal(BssBssid, &ProfileBssid)) {
fMatch = true;
break;
}
} while (0);
return fMatch;
}
bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2)
{
if ((eCSR_BSS_TYPE_ANY != bssType1 && eCSR_BSS_TYPE_ANY != bssType2)
&& (bssType1 != bssType2))
return false;
else
return true;
}
bool csr_is_bss_type_ibss(eCsrRoamBssType bssType)
{
return (bool)
(eCSR_BSS_TYPE_START_IBSS == bssType
|| eCSR_BSS_TYPE_IBSS == bssType);
}
bool csr_is_bss_type_wds(eCsrRoamBssType bssType)
{
return (bool)
(eCSR_BSS_TYPE_WDS_STA == bssType
|| eCSR_BSS_TYPE_WDS_AP == bssType);
}
bool csr_is_bss_type_caps_match(eCsrRoamBssType bssType,
tSirBssDescription *pSirBssDesc)
{
bool fMatch = true;
do {
switch (bssType) {
case eCSR_BSS_TYPE_ANY:
break;
case eCSR_BSS_TYPE_INFRASTRUCTURE:
case eCSR_BSS_TYPE_WDS_STA:
if (!csr_is_infra_bss_desc(pSirBssDesc))
fMatch = false;
break;
case eCSR_BSS_TYPE_IBSS:
case eCSR_BSS_TYPE_START_IBSS:
if (!csr_is_ibss_bss_desc(pSirBssDesc))
fMatch = false;
break;
case eCSR_BSS_TYPE_WDS_AP: /* For WDS AP, no need to match anything */
default:
fMatch = false;
break;
}
} while (0);
return fMatch;
}
static bool csr_is_capabilities_match(tpAniSirGlobal pMac, eCsrRoamBssType bssType,
tSirBssDescription *pSirBssDesc)
{
return csr_is_bss_type_caps_match(bssType, pSirBssDesc);
}
static bool csr_is_specific_channel_match(tpAniSirGlobal pMac,
tSirBssDescription *pSirBssDesc,
uint8_t Channel)
{
bool fMatch = true;
do {
/* if the channel is ANY, then always match... */
if (eCSR_OPERATING_CHANNEL_ANY == Channel)
break;
if (Channel == pSirBssDesc->channelId)
break;
/* didn't match anything.. so return NO match */
fMatch = false;
} while (0);
return fMatch;
}
bool csr_is_channel_band_match(tpAniSirGlobal pMac, uint8_t channelId,
tSirBssDescription *pSirBssDesc)
{
bool fMatch = true;
do {
/* if the profile says Any channel AND the global settings says ANY channel, then we */
/* always match... */
if (eCSR_OPERATING_CHANNEL_ANY == channelId)
break;
if (eCSR_OPERATING_CHANNEL_ANY != channelId) {
fMatch =
csr_is_specific_channel_match(pMac, pSirBssDesc,
channelId);
}
} while (0);
return fMatch;
}
/**
* csr_is_aggregate_rate_supported() - to check if aggregate rate is supported
* @mac_ctx: pointer to mac context
* @rate: A rate in units of 500kbps
*
*
* The rate encoding is just as in 802.11 Information Elements, except
* that the high bit is \em not interpreted as indicating a Basic Rate,
* and proprietary rates are allowed, too.
*
* Note that if the adapter's dot11Mode is g, we don't restrict the
* rates. According to hwReadEepromParameters, this will happen when:
* ... the card is configured for ALL bands through the property
* page. If this occurs, and the card is not an ABG card ,then this
* code is setting the dot11Mode to assume the mode that the
* hardware can support. For example, if the card is an 11BG card
* and we are configured to support ALL bands, then we change the
* dot11Mode to 11g because ALL in this case is only what the
* hardware can support.
*
* Return: true if the adapter is currently capable of supporting this rate
*/
static bool csr_is_aggregate_rate_supported(tpAniSirGlobal mac_ctx,
uint16_t rate)
{
bool supported = false;
uint16_t idx, new_rate;
/* In case basic rate flag is set */
new_rate = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
if (eCSR_CFG_DOT11_MODE_11A ==
mac_ctx->roam.configParam.uCfgDot11Mode) {
switch (new_rate) {
case eCsrSuppRate_6Mbps:
case eCsrSuppRate_9Mbps:
case eCsrSuppRate_12Mbps:
case eCsrSuppRate_18Mbps:
case eCsrSuppRate_24Mbps:
case eCsrSuppRate_36Mbps:
case eCsrSuppRate_48Mbps:
case eCsrSuppRate_54Mbps:
supported = true;
break;
default:
supported = false;
break;
}
} else if (eCSR_CFG_DOT11_MODE_11B ==
mac_ctx->roam.configParam.uCfgDot11Mode) {
switch (new_rate) {
case eCsrSuppRate_1Mbps:
case eCsrSuppRate_2Mbps:
case eCsrSuppRate_5_5Mbps:
case eCsrSuppRate_11Mbps:
supported = true;
break;
default:
supported = false;
break;
}
} else if (!mac_ctx->roam.configParam.ProprietaryRatesEnabled) {
switch (new_rate) {
case eCsrSuppRate_1Mbps:
case eCsrSuppRate_2Mbps:
case eCsrSuppRate_5_5Mbps:
case eCsrSuppRate_6Mbps:
case eCsrSuppRate_9Mbps:
case eCsrSuppRate_11Mbps:
case eCsrSuppRate_12Mbps:
case eCsrSuppRate_18Mbps:
case eCsrSuppRate_24Mbps:
case eCsrSuppRate_36Mbps:
case eCsrSuppRate_48Mbps:
case eCsrSuppRate_54Mbps:
supported = true;
break;
default:
supported = false;
break;
}
} else if (eCsrSuppRate_1Mbps == new_rate ||
eCsrSuppRate_2Mbps == new_rate ||
eCsrSuppRate_5_5Mbps == new_rate ||
eCsrSuppRate_11Mbps == new_rate) {
supported = true;
} else {
idx = 0x1;
switch (new_rate) {
case eCsrSuppRate_6Mbps:
supported = g_phy_rates_suppt[0][idx];
break;
case eCsrSuppRate_9Mbps:
supported = g_phy_rates_suppt[1][idx];
break;
case eCsrSuppRate_12Mbps:
supported = g_phy_rates_suppt[2][idx];
break;
case eCsrSuppRate_18Mbps:
supported = g_phy_rates_suppt[3][idx];
break;
case eCsrSuppRate_20Mbps:
supported = g_phy_rates_suppt[4][idx];
break;
case eCsrSuppRate_24Mbps:
supported = g_phy_rates_suppt[5][idx];
break;
case eCsrSuppRate_36Mbps:
supported = g_phy_rates_suppt[6][idx];
break;
case eCsrSuppRate_40Mbps:
supported = g_phy_rates_suppt[7][idx];
break;
case eCsrSuppRate_42Mbps:
supported = g_phy_rates_suppt[8][idx];
break;
case eCsrSuppRate_48Mbps:
supported = g_phy_rates_suppt[9][idx];
break;
case eCsrSuppRate_54Mbps:
supported = g_phy_rates_suppt[10][idx];
break;
case eCsrSuppRate_72Mbps:
supported = g_phy_rates_suppt[11][idx];
break;
case eCsrSuppRate_80Mbps:
supported = g_phy_rates_suppt[12][idx];
break;
case eCsrSuppRate_84Mbps:
supported = g_phy_rates_suppt[13][idx];
break;
case eCsrSuppRate_96Mbps:
supported = g_phy_rates_suppt[14][idx];
break;
case eCsrSuppRate_108Mbps:
supported = g_phy_rates_suppt[15][idx];
break;
case eCsrSuppRate_120Mbps:
supported = g_phy_rates_suppt[16][idx];
break;
case eCsrSuppRate_126Mbps:
supported = g_phy_rates_suppt[17][idx];
break;
case eCsrSuppRate_144Mbps:
supported = g_phy_rates_suppt[18][idx];
break;
case eCsrSuppRate_160Mbps:
supported = g_phy_rates_suppt[19][idx];
break;
case eCsrSuppRate_168Mbps:
supported = g_phy_rates_suppt[20][idx];
break;
case eCsrSuppRate_192Mbps:
supported = g_phy_rates_suppt[21][idx];
break;
case eCsrSuppRate_216Mbps:
supported = g_phy_rates_suppt[22][idx];
break;
case eCsrSuppRate_240Mbps:
supported = g_phy_rates_suppt[23][idx];
break;
default:
supported = false;
break;
}
}
return supported;
}
/**
* csr_is_rate_set_match() - to check if rate set is matching
* @mac_ctx: pointer to mac context
* @bss_supported_rates: supported rates of BSS
* @bss_ext_supp_rates: extended rates of bss
*
* This routine is to checke if rate set is matched or no
*
* Return: bool
*/
static bool csr_is_rate_set_match(tpAniSirGlobal mac_ctx,
tDot11fIESuppRates *bss_supported_rates,
tDot11fIEExtSuppRates *bss_ext_supp_rates)
{
bool match = true;
uint32_t i;
/*
* Validate that all of the Basic rates advertised in the Bss
* description are supported
*/
if (bss_supported_rates) {
for (i = 0; i < bss_supported_rates->num_rates; i++) {
if (!CSR_IS_BASIC_RATE(bss_supported_rates->rates[i]))
continue;
if (!csr_is_aggregate_rate_supported(mac_ctx,
bss_supported_rates->rates[i])) {
match = false;
break;
}
}
}
if (match && bss_ext_supp_rates) {
for (i = 0; i < bss_ext_supp_rates->num_rates; i++) {
if (!CSR_IS_BASIC_RATE(bss_ext_supp_rates->rates[i]))
continue;
if (!csr_is_aggregate_rate_supported(mac_ctx,
bss_ext_supp_rates->rates[i])) {
match = false;
break;
}
}
}
return match;
}
/**
* csr_match_bss() - to compare the bss
* @hal: pointer to hal context
* @bss_descr: pointer bss description
* @filter: scan filter
* @neg_auth: negotiated auth
* @neg_uc: negotiated for unicast
* @neg_mc: negotiated for multicast
* @ie_dblptr: double pointer to IE
*
* This routine will be called to match the bss
* If caller want to get the *ie_dblptr allocated by this function,
* pass in *ie_dblptr = NULL
*
* Return: bool
*/
bool csr_match_bss(tHalHandle hal, tSirBssDescription *bss_descr,
tCsrScanResultFilter *filter, eCsrAuthType *neg_auth,
eCsrEncryptionType *neg_uc, eCsrEncryptionType *neg_mc,
tDot11fBeaconIEs **ie_dblptr)
{
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
bool rc = false, check, blacklist_check;
uint32_t i;
tDot11fBeaconIEs *ie_ptr = NULL;
uint8_t *pb;
struct roam_ext_params *roam_params;
uint8_t *p2p_macaddr = NULL;
roam_params = &mac_ctx->roam.configParam.roam_params;
if ((NULL == ie_dblptr) || (*ie_dblptr) == NULL) {
/* If no IEs passed in, get our own. */
if (!CDF_IS_STATUS_SUCCESS(
csr_get_parsed_bss_description_ies(mac_ctx,
bss_descr, &ie_ptr))) {
goto end;
}
} else {
/* Save the one pass in for local use */
ie_ptr = *ie_dblptr;
}
/* Check if caller wants P2P */
check = (!filter->p2pResult || ie_ptr->P2PBeaconProbeRes.present);
if (!check)
goto end;
/* Check for Blacklist BSSID's and avoid connections */
blacklist_check = false;
for (i = 0; i < roam_params->num_bssid_avoid_list; i++) {
if (cdf_is_macaddr_equal((struct cdf_mac_addr *)
&roam_params->bssid_avoid_list[i],
(struct cdf_mac_addr *)bss_descr->bssId)) {
blacklist_check = true;
break;
}
}
if (blacklist_check) {
sms_log(mac_ctx, LOGE,
FL("Don't Attempt connect to blacklist bssid"));
goto end;
}
if (ie_ptr->SSID.present) {
for (i = 0; i < filter->SSIDs.numOfSSIDs; i++) {
check = csr_is_ssid_match(mac_ctx,
filter->SSIDs.SSIDList[i].SSID.ssId,
filter->SSIDs.SSIDList[i].SSID.length,
ie_ptr->SSID.ssid,
ie_ptr->SSID.num_ssid, true);
if (check)
break;
}
if (!check)
goto end;
}
check = true;
p2p_macaddr = ie_ptr->P2PBeaconProbeRes.P2PDeviceInfo.P2PDeviceAddress;
for (i = 0; i < filter->BSSIDs.numOfBSSIDs; i++) {
check = csr_is_bssid_match(mac_ctx,
(struct cdf_mac_addr *)&filter->BSSIDs.bssid[i],
(struct cdf_mac_addr *)bss_descr->bssId);
if (check)
break;
if (filter->p2pResult && ie_ptr->P2PBeaconProbeRes.present) {
check = csr_is_bssid_match(mac_ctx,
(struct cdf_mac_addr *)
&filter->BSSIDs.bssid[i],
(struct cdf_mac_addr *)p2p_macaddr);
if (check)
break;
}
}
if (!check)
goto end;
check = true;
for (i = 0; i < filter->ChannelInfo.numOfChannels; i++) {
check = csr_is_channel_band_match(mac_ctx,
filter->ChannelInfo.ChannelList[i], bss_descr);
if (check)
break;
}
if (!check)
goto end;
#if defined WLAN_FEATURE_VOWIFI
/* If this is for measurement filtering */
if (filter->fMeasurement) {
rc = true;
goto end;
}
#endif
if (!csr_is_phy_mode_match(mac_ctx, filter->phyMode, bss_descr,
NULL, NULL, ie_ptr))
goto end;
#ifdef WLAN_FEATURE_11W
if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) &&
!csr_is_security_match(mac_ctx, &filter->authType,
&filter->EncryptionType,
&filter->mcEncryptionType,
&filter->MFPEnabled,
&filter->MFPRequired,
&filter->MFPCapable,
bss_descr, ie_ptr, neg_auth,
neg_uc, neg_mc))
#else
if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) &&
!csr_is_security_match(mac_ctx, &filter->authType,
&filter->EncryptionType,
&filter->mcEncryptionType,
NULL, NULL, NULL,
bss_descr, ie_ptr, neg_auth,
neg_uc, neg_mc))
#endif
goto end;
if (!csr_is_capabilities_match(mac_ctx, filter->BSSType, bss_descr))
goto end;
if (!csr_is_rate_set_match(mac_ctx, &ie_ptr->SuppRates,
&ie_ptr->ExtSuppRates))
goto end;
if ((eCsrRoamWmmQbssOnly == mac_ctx->roam.configParam.WMMSupportMode)
&& !CSR_IS_QOS_BSS(ie_ptr))
goto end;
/*
* Check country. check even when pb is NULL because we may
* want to make sure
*/
pb = (filter->countryCode[0]) ? (filter->countryCode) : NULL;
check = csr_match_country_code(mac_ctx, pb, ie_ptr);
if (!check)
goto end;
#ifdef WLAN_FEATURE_VOWIFI_11R
if (filter->MDID.mdiePresent && csr_roam_is11r_assoc(mac_ctx,
mac_ctx->roam.roamSession->sessionId)) {
if (bss_descr->mdiePresent) {
if (filter->MDID.mobilityDomain !=
(bss_descr->mdie[1] << 8 |
bss_descr->mdie[0]))
goto end;
} else {
goto end;
}
}
#endif
rc = true;
end:
if (ie_dblptr)
*ie_dblptr = ie_ptr;
else if (ie_ptr)
cdf_mem_free(ie_ptr);
return rc;
}
bool csr_match_connected_bss_security(tpAniSirGlobal pMac,
tCsrRoamConnectedProfile *pProfile,
tSirBssDescription *pBssDesc,
tDot11fBeaconIEs *pIes)
{
tCsrEncryptionList ucEncryptionList, mcEncryptionList;
tCsrAuthList authList;
ucEncryptionList.numEntries = 1;
ucEncryptionList.encryptionType[0] = pProfile->EncryptionType;
mcEncryptionList.numEntries = 1;
mcEncryptionList.encryptionType[0] = pProfile->mcEncryptionType;
authList.numEntries = 1;
authList.authType[0] = pProfile->AuthType;
return csr_is_security_match(pMac, &authList, &ucEncryptionList,
&mcEncryptionList, NULL, NULL, NULL,
pBssDesc, pIes, NULL, NULL, NULL);
}
bool csr_match_bss_to_connect_profile(tHalHandle hHal,
tCsrRoamConnectedProfile *pProfile,
tSirBssDescription *pBssDesc,
tDot11fBeaconIEs *pIes)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
bool fRC = false, fCheck;
tDot11fBeaconIEs *pIesLocal = pIes;
do {
if (!pIes) {
if (!CDF_IS_STATUS_SUCCESS
(csr_get_parsed_bss_description_ies
(pMac, pBssDesc, &pIesLocal))) {
break;
}
}
fCheck = true;
if (pIesLocal->SSID.present) {
bool fCheckSsid = false;
if (pProfile->SSID.length) {
fCheckSsid = true;
}
fCheck =
csr_is_ssid_match(pMac, pProfile->SSID.ssId,
pProfile->SSID.length,
pIesLocal->SSID.ssid,
pIesLocal->SSID.num_ssid,
fCheckSsid);
if (!fCheck)
break;
}
if (!csr_match_connected_bss_security
(pMac, pProfile, pBssDesc, pIesLocal))
break;
if (!csr_is_capabilities_match(pMac, pProfile->BSSType, pBssDesc))
break;
if (!csr_is_rate_set_match
(pMac, &pIesLocal->SuppRates, &pIesLocal->ExtSuppRates))
break;
fCheck =
csr_is_channel_band_match(pMac, pProfile->operationChannel,
pBssDesc);
if (!fCheck)
break;
fRC = true;
} while (0);
if (!pIes && pIesLocal) {
/* locally allocated */
cdf_mem_free(pIesLocal);
}
return fRC;
}
void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap)
{
uint16_t rateBitmap;
uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
rateBitmap = *pRateBitmap;
switch (n) {
case SIR_MAC_RATE_1:
rateBitmap |= SIR_MAC_RATE_1_BITMAP;
break;
case SIR_MAC_RATE_2:
rateBitmap |= SIR_MAC_RATE_2_BITMAP;
break;
case SIR_MAC_RATE_5_5:
rateBitmap |= SIR_MAC_RATE_5_5_BITMAP;
break;
case SIR_MAC_RATE_11:
rateBitmap |= SIR_MAC_RATE_11_BITMAP;
break;
case SIR_MAC_RATE_6:
rateBitmap |= SIR_MAC_RATE_6_BITMAP;
break;
case SIR_MAC_RATE_9:
rateBitmap |= SIR_MAC_RATE_9_BITMAP;
break;
case SIR_MAC_RATE_12:
rateBitmap |= SIR_MAC_RATE_12_BITMAP;
break;
case SIR_MAC_RATE_18:
rateBitmap |= SIR_MAC_RATE_18_BITMAP;
break;
case SIR_MAC_RATE_24:
rateBitmap |= SIR_MAC_RATE_24_BITMAP;
break;
case SIR_MAC_RATE_36:
rateBitmap |= SIR_MAC_RATE_36_BITMAP;
break;
case SIR_MAC_RATE_48:
rateBitmap |= SIR_MAC_RATE_48_BITMAP;
break;
case SIR_MAC_RATE_54:
rateBitmap |= SIR_MAC_RATE_54_BITMAP;
break;
}
*pRateBitmap = rateBitmap;
}
bool csr_check_rate_bitmap(uint8_t rate, uint16_t rateBitmap)
{
uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
switch (n) {
case SIR_MAC_RATE_1:
rateBitmap &= SIR_MAC_RATE_1_BITMAP;
break;
case SIR_MAC_RATE_2:
rateBitmap &= SIR_MAC_RATE_2_BITMAP;
break;
case SIR_MAC_RATE_5_5:
rateBitmap &= SIR_MAC_RATE_5_5_BITMAP;
break;
case SIR_MAC_RATE_11:
rateBitmap &= SIR_MAC_RATE_11_BITMAP;
break;
case SIR_MAC_RATE_6:
rateBitmap &= SIR_MAC_RATE_6_BITMAP;
break;
case SIR_MAC_RATE_9:
rateBitmap &= SIR_MAC_RATE_9_BITMAP;
break;
case SIR_MAC_RATE_12:
rateBitmap &= SIR_MAC_RATE_12_BITMAP;
break;
case SIR_MAC_RATE_18:
rateBitmap &= SIR_MAC_RATE_18_BITMAP;
break;
case SIR_MAC_RATE_24:
rateBitmap &= SIR_MAC_RATE_24_BITMAP;
break;
case SIR_MAC_RATE_36:
rateBitmap &= SIR_MAC_RATE_36_BITMAP;
break;
case SIR_MAC_RATE_48:
rateBitmap &= SIR_MAC_RATE_48_BITMAP;
break;
case SIR_MAC_RATE_54:
rateBitmap &= SIR_MAC_RATE_54_BITMAP;
break;
}
return !!rateBitmap;
}
bool csr_rates_is_dot11_rate_supported(tHalHandle hHal, uint8_t rate)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
return csr_is_aggregate_rate_supported(pMac, n);
}
uint16_t csr_rates_mac_prop_to_dot11(uint16_t Rate)
{
uint16_t ConvertedRate = Rate;
switch (Rate) {
case SIR_MAC_RATE_1:
ConvertedRate = 2;
break;
case SIR_MAC_RATE_2:
ConvertedRate = 4;
break;
case SIR_MAC_RATE_5_5:
ConvertedRate = 11;
break;
case SIR_MAC_RATE_11:
ConvertedRate = 22;
break;
case SIR_MAC_RATE_6:
ConvertedRate = 12;
break;
case SIR_MAC_RATE_9:
ConvertedRate = 18;
break;
case SIR_MAC_RATE_12:
ConvertedRate = 24;
break;
case SIR_MAC_RATE_18:
ConvertedRate = 36;
break;
case SIR_MAC_RATE_24:
ConvertedRate = 48;
break;
case SIR_MAC_RATE_36:
ConvertedRate = 72;
break;
case SIR_MAC_RATE_42:
ConvertedRate = 84;
break;
case SIR_MAC_RATE_48:
ConvertedRate = 96;
break;
case SIR_MAC_RATE_54:
ConvertedRate = 108;
break;
case SIR_MAC_RATE_72:
ConvertedRate = 144;
break;
case SIR_MAC_RATE_84:
ConvertedRate = 168;
break;
case SIR_MAC_RATE_96:
ConvertedRate = 192;
break;
case SIR_MAC_RATE_108:
ConvertedRate = 216;
break;
case SIR_MAC_RATE_126:
ConvertedRate = 252;
break;
case SIR_MAC_RATE_144:
ConvertedRate = 288;
break;
case SIR_MAC_RATE_168:
ConvertedRate = 336;
break;
case SIR_MAC_RATE_192:
ConvertedRate = 384;
break;
case SIR_MAC_RATE_216:
ConvertedRate = 432;
break;
case SIR_MAC_RATE_240:
ConvertedRate = 480;
break;
case 0xff:
ConvertedRate = 0;
break;
}
return ConvertedRate;
}
uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates,
tSirMacRateSet *pExtRates,
tSirMacPropRateSet *pPropRates)
{
uint8_t i;
uint16_t nBest;
nBest = pSuppRates->rate[0] & (~CSR_DOT11_BASIC_RATE_MASK);
if (pSuppRates->numRates > SIR_MAC_RATESET_EID_MAX) {
pSuppRates->numRates = SIR_MAC_RATESET_EID_MAX;
}
for (i = 1U; i < pSuppRates->numRates; ++i) {
nBest =
(uint16_t) CSR_MAX(nBest,
pSuppRates->
rate[i] & (~CSR_DOT11_BASIC_RATE_MASK));
}
if (NULL != pExtRates) {
for (i = 0U; i < pExtRates->numRates; ++i) {
nBest =
(uint16_t) CSR_MAX(nBest,
pExtRates->
rate[i] &
(~CSR_DOT11_BASIC_RATE_MASK));
}
}
if (NULL != pPropRates) {
for (i = 0U; i < pPropRates->numPropRates; ++i) {
nBest =
(uint16_t) CSR_MAX(nBest,
csr_rates_mac_prop_to_dot11
(pPropRates->propRate[i]));
}
}
return nBest;
}
void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile)
{
if (pProfile) {
if (pProfile->BSSIDs.bssid) {
cdf_mem_free(pProfile->BSSIDs.bssid);
pProfile->BSSIDs.bssid = NULL;
}
if (pProfile->SSIDs.SSIDList) {
cdf_mem_free(pProfile->SSIDs.SSIDList);
pProfile->SSIDs.SSIDList = NULL;
}
if (pProfile->pWPAReqIE) {
cdf_mem_free(pProfile->pWPAReqIE);
pProfile->pWPAReqIE = NULL;
}
if (pProfile->pRSNReqIE) {
cdf_mem_free(pProfile->pRSNReqIE);
pProfile->pRSNReqIE = NULL;
}
#ifdef FEATURE_WLAN_WAPI
if (pProfile->pWAPIReqIE) {
cdf_mem_free(pProfile->pWAPIReqIE);
pProfile->pWAPIReqIE = NULL;
}
#endif /* FEATURE_WLAN_WAPI */
if (pProfile->pAddIEScan) {
cdf_mem_free(pProfile->pAddIEScan);
pProfile->pAddIEScan = NULL;
}
if (pProfile->pAddIEAssoc) {
cdf_mem_free(pProfile->pAddIEAssoc);
pProfile->pAddIEAssoc = NULL;
}
if (pProfile->ChannelInfo.ChannelList) {
cdf_mem_free(pProfile->ChannelInfo.ChannelList);
pProfile->ChannelInfo.ChannelList = NULL;
}
cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
}
}
void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter)
{
if (pScanFilter->BSSIDs.bssid) {
cdf_mem_free(pScanFilter->BSSIDs.bssid);
pScanFilter->BSSIDs.bssid = NULL;
}
if (pScanFilter->ChannelInfo.ChannelList) {
cdf_mem_free(pScanFilter->ChannelInfo.ChannelList);
pScanFilter->ChannelInfo.ChannelList = NULL;
}
if (pScanFilter->SSIDs.SSIDList) {
cdf_mem_free(pScanFilter->SSIDs.SSIDList);
pScanFilter->SSIDs.SSIDList = NULL;
}
}
void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId)
{
tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId];
if (pSession->pCurRoamProfile) {
csr_release_profile(pMac, pSession->pCurRoamProfile);
cdf_mem_free(pSession->pCurRoamProfile);
pSession->pCurRoamProfile = NULL;
}
}
void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId)
{
tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId];
if (pSession->pConnectBssDesc) {
cdf_mem_free(pSession->pConnectBssDesc);
pSession->pConnectBssDesc = NULL;
}
}
tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp *
pSmeDisassocRsp)
{
uint8_t *pBuffer = (uint8_t *) pSmeDisassocRsp;
uint32_t ret;
pBuffer += (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(tSirMacAddr));
/* tSirResultCodes is an enum, assuming is 32bit */
/* If we cannot make this assumption, use copymemory */
cdf_get_u32(pBuffer, &ret);
return (tSirResultCodes) ret;
}
tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp)
{
uint8_t *pBuffer = (uint8_t *) pSmeRsp;
uint32_t ret;
pBuffer +=
(sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint8_t) +
sizeof(uint16_t));
/* tSirResultCodes is an enum, assuming is 32bit */
/* If we cannot make this assumption, use copymemory */
cdf_get_u32(pBuffer, &ret);
return (tSirResultCodes) ret;
}
tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId)
{
tSirScanType scanType = eSIR_PASSIVE_SCAN;
CHANNEL_STATE channelEnabledType;
channelEnabledType = cds_get_channel_state(chnId);
if (CHANNEL_STATE_ENABLE == channelEnabledType) {
scanType = eSIR_ACTIVE_SCAN;
}
return scanType;
}
uint8_t csr_to_upper(uint8_t ch)
{
uint8_t chOut;
if (ch >= 'a' && ch <= 'z') {
chOut = ch - 'a' + 'A';
} else {
chOut = ch;
}
return chOut;
}
tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype)
{
tSirBssType ret;
switch (csrtype) {
case eCSR_BSS_TYPE_INFRASTRUCTURE:
ret = eSIR_INFRASTRUCTURE_MODE;
break;
case eCSR_BSS_TYPE_IBSS:
case eCSR_BSS_TYPE_START_IBSS:
ret = eSIR_IBSS_MODE;
break;
case eCSR_BSS_TYPE_WDS_AP:
ret = eSIR_BTAMP_AP_MODE;
break;
case eCSR_BSS_TYPE_WDS_STA:
ret = eSIR_BTAMP_STA_MODE;
break;
case eCSR_BSS_TYPE_INFRA_AP:
ret = eSIR_INFRA_AP_MODE;
break;
case eCSR_BSS_TYPE_ANY:
default:
ret = eSIR_AUTO_MODE;
break;
}
return ret;
}
/* This function use the parameters to decide the CFG value. */
/* CSR never sets WNI_CFG_DOT11_MODE_ALL to the CFG */
/* So PE should not see WNI_CFG_DOT11_MODE_ALL when it gets the CFG value */
eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile,
eCsrPhyMode phyMode,
bool fProprietary)
{
uint32_t cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG;
switch (phyMode) {
case eCSR_DOT11_MODE_11a:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
break;
case eCSR_DOT11_MODE_11b:
case eCSR_DOT11_MODE_11b_ONLY:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
break;
case eCSR_DOT11_MODE_11g:
case eCSR_DOT11_MODE_11g_ONLY:
if (pProfile && (CSR_IS_INFRA_AP(pProfile))
&& (phyMode == eCSR_DOT11_MODE_11g_ONLY))
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G_ONLY;
else
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
break;
case eCSR_DOT11_MODE_11n:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
break;
case eCSR_DOT11_MODE_11n_ONLY:
if (pProfile && CSR_IS_INFRA_AP(pProfile))
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N_ONLY;
else
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
break;
case eCSR_DOT11_MODE_abg:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG;
break;
case eCSR_DOT11_MODE_AUTO:
cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO;
break;
#ifdef WLAN_FEATURE_11AC
case eCSR_DOT11_MODE_11ac:
if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
} else {
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
}
break;
case eCSR_DOT11_MODE_11ac_ONLY:
if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC_ONLY;
} else {
cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
}
break;
#endif
default:
/* No need to assign anything here */
break;
}
return cfgDot11Mode;
}
CDF_STATUS csr_get_regulatory_domain_for_country
(tpAniSirGlobal pMac,
uint8_t *pCountry,
v_REGDOMAIN_t *pDomainId, v_CountryInfoSource_t source) {
CDF_STATUS status = CDF_STATUS_E_INVAL;
CDF_STATUS cdf_status;
country_code_t countryCode;
v_REGDOMAIN_t domainId;
if (pCountry) {
countryCode[0] = pCountry[0];
countryCode[1] = pCountry[1];
cdf_status = cds_get_reg_domain_from_country_code(&domainId,
countryCode,
source);
if (CDF_IS_STATUS_SUCCESS(cdf_status)) {
if (pDomainId) {
*pDomainId = domainId;
}
status = CDF_STATUS_SUCCESS;
} else {
sms_log(pMac, LOGW,
FL
(" Couldn't find domain for country code %c%c"),
pCountry[0], pCountry[1]);
status = CDF_STATUS_E_INVAL;
}
}
return status;
}
/* To check whether a country code matches the one in the IE */
/* Only check the first two characters, ignoring in/outdoor */
/* pCountry -- caller allocated buffer contain the country code that is checking against */
/* the one in pIes. It can be NULL. */
/* caller must provide pIes, it cannot be NULL */
/* This function always return true if 11d support is not turned on. */
bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry,
tDot11fBeaconIEs *pIes)
{
bool fRet = true;
do {
if (!csr_is11d_supported(pMac)) {
break;
}
if (!pIes) {
sms_log(pMac, LOGE, FL(" No IEs"));
break;
}
if (pCountry) {
uint32_t i;
if (!pIes->Country.present) {
fRet = false;
break;
}
/* Convert the CountryCode characters to upper */
for (i = 0; i < WNI_CFG_COUNTRY_CODE_LEN - 1; i++) {
pCountry[i] = csr_to_upper(pCountry[i]);
}
if (!cdf_mem_compare(pIes->Country.country, pCountry,
WNI_CFG_COUNTRY_CODE_LEN - 1)) {
fRet = false;
break;
}
}
} while (0);
return fRet;
}
CDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId,
tCsrRoamModifyProfileFields *
pModifyProfileFields)
{
if (!pModifyProfileFields) {
return CDF_STATUS_E_FAILURE;
}
cdf_mem_copy(pModifyProfileFields,
&pMac->roam.roamSession[sessionId].connectedProfile.
modifyProfileFields, sizeof(tCsrRoamModifyProfileFields));
return CDF_STATUS_SUCCESS;
}
CDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId,
tCsrRoamModifyProfileFields *
pModifyProfileFields)
{
tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
cdf_mem_copy(&pSession->connectedProfile.modifyProfileFields,
pModifyProfileFields, sizeof(tCsrRoamModifyProfileFields));
return CDF_STATUS_SUCCESS;
}
bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId)
{
bool fRet = true;
tCsrRoamSession *pSession;
pSession = CSR_GET_SESSION(pMac, sessionId);
/*
* This condition is not working for infra state. When infra is in
* not-connected state the pSession->pCurRoamProfile is NULL, this
* function returns true, that is incorrect.
* Since SAP requires to set key without any BSS started, it needs
* this condition to be met. In other words, this function is useless.
* The current work-around is to process setcontext_rsp no matter
* what the state is.
*/
sms_log(pMac, LOG2,
FL(" is not what it intends to. Must be revisit or removed"));
if ((NULL == pSession)
|| (csr_is_conn_state_disconnected(pMac, sessionId)
&& (pSession->pCurRoamProfile != NULL)
&& (!(CSR_IS_INFRA_AP(pSession->pCurRoamProfile))))
) {
fRet = false;
}
return fRet;
}
/* no need to acquire lock for this basic function */
uint16_t sme_chn_to_freq(uint8_t chanNum)
{
int i;
for (i = 0; i < NUM_RF_CHANNELS; i++) {
if (rf_channels[i].channelNum == chanNum) {
return rf_channels[i].targetFreq;
}
}
return 0;
}
/* Disconnect all active sessions by sending disassoc. This is mainly used to disconnect the remaining session when we
* transition from concurrent sessions to a single session. The use case is Infra STA and wifi direct multiple sessions are up and
* P2P session is removed. The Infra STA session remains and should resume BMPS if BMPS is enabled by default. However, there
* are some issues seen with BMPS resume during this transition and this is a workaround which will allow the Infra STA session to
* disconnect and auto connect back and enter BMPS this giving the same effect as resuming BMPS
*/
/* Remove this code once SLM_Sessionization is supported */
/* BMPS_WORKAROUND_NOT_NEEDED */
void csr_disconnect_all_active_sessions(tpAniSirGlobal pMac)
{
uint8_t i;
/* Disconnect all the active sessions */
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
if (CSR_IS_SESSION_VALID(pMac, i)
&& !csr_is_conn_state_disconnected(pMac, i)) {
csr_roam_disconnect_internal(pMac, i,
eCSR_DISCONNECT_REASON_UNSPECIFIED);
}
}
}
#ifdef FEATURE_WLAN_LFR
bool csr_is_channel_present_in_list(uint8_t *pChannelList,
int numChannels, uint8_t channel)
{
int i = 0;
/* Check for NULL pointer */
if (!pChannelList || (numChannels == 0)) {
return false;
}
/* Look for the channel in the list */
for (i = 0; (i < numChannels) &&
(i < WNI_CFG_VALID_CHANNEL_LIST_LEN); i++) {
if (pChannelList[i] == channel)
return true;
}
return false;
}
CDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList,
int numChannels, uint8_t channel)
{
int i = 0;
/* Check for NULL pointer */
if (!pChannelList)
return CDF_STATUS_E_NULL_VALUE;
/* Make room for the addition. (Start moving from the back.) */
for (i = numChannels; i > 0; i--) {
pChannelList[i] = pChannelList[i - 1];
}
/* Now add the NEW channel...at the front */
pChannelList[0] = channel;
return CDF_STATUS_SUCCESS;
}
#endif
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* csr_diag_event_report() - send PE diag event
* @pmac: pointer to global MAC context.
* @event_typev: sub event type for DIAG event.
* @status: status of the event
* @reasoncode: reasoncode for the given status
*
* This function is called to send diag event
*
* Return: NA
*/
void csr_diag_event_report(tpAniSirGlobal pmac, uint16_t event_type,
uint16_t status, uint16_t reasoncode)
{
WLAN_HOST_DIAG_EVENT_DEF(diag_event, host_event_wlan_pe_payload_type);
cdf_mem_zero(&diag_event, sizeof(host_event_wlan_pe_payload_type));
/* diag_event.bssid is already all zeroes */
diag_event.sme_state = sme_get_lim_sme_state(pmac);
diag_event.mlm_state = sme_get_lim_mlm_state(pmac);
diag_event.event_type = event_type;
diag_event.status = status;
diag_event.reason_code = reasoncode;
WLAN_HOST_DIAG_EVENT_REPORT(&diag_event, EVENT_WLAN_PE);
return;
}
#endif