qcacld-3.0: Add Support for FILS Association

Adds the following  support:
1) Add FILS IE's to assoc request.
2) AEAD encrypt/decrypt the assoc request/response frames for FILS
3) Process/Verify the Assoc response for the FILS params
4) Plumb the Auth keys to firmware after successful FILS assoc
5) Update the user space with Auth key details

Change-Id: I57f6319cecdf10e08047b510321b885c3cd711b5
CRs-Fixed: 2030038
This commit is contained in:
Sridhar Selvaraj 2017-08-17 17:30:01 +05:30 committed by Nandini Suresh
parent 7a412e492b
commit 0d5d2c745c
20 changed files with 1470 additions and 131 deletions

View File

@ -3139,7 +3139,7 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter,
if (pRoamInfo)
hdd_connect_result(dev,
pRoamInfo->bssid.bytes,
NULL, NULL, 0, NULL, 0,
pRoamInfo, NULL, 0, NULL, 0,
WLAN_STATUS_ASSOC_DENIED_UNSPEC,
GFP_KERNEL,
connect_timeout,
@ -3156,7 +3156,7 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter,
if (pRoamInfo)
hdd_connect_result(dev,
pRoamInfo->bssid.bytes,
NULL, NULL, 0, NULL, 0,
pRoamInfo, NULL, 0, NULL, 0,
pRoamInfo->reasonCode ?
pRoamInfo->reasonCode :
WLAN_STATUS_UNSPECIFIED_FAILURE,

View File

@ -4749,6 +4749,175 @@ static void hdd_connect_bss(struct net_device *dev, const u8 *bssid,
}
#endif
#ifdef WLAN_FEATURE_FILS_SK
#ifdef CFG80211_CONNECT_DONE
#ifdef CFG80211_FILS_SK_OFFLOAD_SUPPORT
/**
* hdd_populate_fils_params() - Populate FILS keys to connect response
* @fils_params: connect response to supplicant
* @fils_kek: FILS kek
* @fils_kek_len: FILS kek length
* @pmk: FILS PMK
* @pmk_len: FILS PMK length
* @pmkid: PMKID
* @fils_seq_num: FILS Seq number
*
* Return: None
*/
static void hdd_populate_fils_params(struct cfg80211_connect_resp_params
*fils_params, const uint8_t *fils_kek,
size_t fils_kek_len, const uint8_t *pmk,
size_t pmk_len, const uint8_t *pmkid,
uint16_t fils_seq_num)
{
/* Increament seq number to be used for next FILS */
fils_params->fils_erp_next_seq_num = fils_seq_num + 1;
fils_params->update_erp_next_seq_num = true;
fils_params->fils_kek = fils_kek;
fils_params->fils_kek_len = fils_kek_len;
fils_params->pmk = pmk;
fils_params->pmk_len = pmk_len;
fils_params->pmkid = pmkid;
}
#else
static inline void hdd_populate_fils_params(struct cfg80211_connect_resp_params
*fils_params, const uint8_t
*fils_kek, size_t fils_kek_len,
const uint8_t *pmk, size_t pmk_len,
const uint8_t *pmkid,
uint16_t fils_seq_num)
{ }
#endif
/**
* hdd_connect_done() - Wrapper API to call cfg80211_connect_done
* @dev: network device
* @bssid: bssid to which we want to associate
* @bss: cfg80211 bss info
* @roam_info: information about connected bss
* @req_ie: Request Information Element
* @req_ie_len: len of the req IE
* @resp_ie: Response IE
* @resp_ie_len: len of ht response IE
* @status: status
* @gfp: allocation flags
* @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp
* @timeout_reason: reason for connect timeout
* @roam_fils_params: FILS join response params
*
* This API is used as wrapper to send FILS key/sequence number
* params etc. to supplicant in case of FILS connection
*
* Return: None
*/
static void hdd_connect_done(struct net_device *dev, const u8 *bssid,
struct cfg80211_bss *bss, tCsrRoamInfo *roam_info,
const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len, u16 status,
gfp_t gfp, bool connect_timeout, tSirResultCodes
timeout_reason, struct fils_join_rsp_params
*roam_fils_params)
{
struct cfg80211_connect_resp_params fils_params;
qdf_mem_zero(&fils_params, sizeof(fils_params));
if (!roam_fils_params) {
fils_params.status = WLAN_STATUS_UNSPECIFIED_FAILURE;
} else {
fils_params.status = status;
fils_params.bssid = bssid;
fils_params.timeout_reason = timeout_reason;
fils_params.req_ie = req_ie;
fils_params.req_ie_len = req_ie_len;
fils_params.resp_ie = resp_ie;
fils_params.resp_ie_len = resp_ie_len;
fils_params.bss = bss;
hdd_populate_fils_params(&fils_params, roam_fils_params->kek,
roam_fils_params->kek_len,
roam_fils_params->fils_pmk,
roam_fils_params->fils_pmk_len,
roam_fils_params->fils_pmkid,
roam_info->fils_seq_num);
}
hdd_debug("FILS indicate connect status %d seq no %d",
fils_params.status,
fils_params.fils_erp_next_seq_num);
cfg80211_connect_done(dev, &fils_params, gfp);
/* Clear all the FILS key info */
if (roam_fils_params && roam_fils_params->fils_pmk)
qdf_mem_free(roam_fils_params->fils_pmk);
if (roam_fils_params)
qdf_mem_free(roam_fils_params);
roam_info->fils_join_rsp = NULL;
}
#else
static inline void hdd_connect_done(struct net_device *dev, const u8 *bssid,
struct cfg80211_bss *bss, tCsrRoamInfo
*roam_info, const u8 *req_ie,
size_t req_ie_len, const u8 *resp_ie,
size_t resp_ie_len, u16 status, gfp_t gfp,
bool connect_timeout, tSirResultCodes
timeout_reason, struct fils_join_rsp_params
*roam_fils_params)
{ }
#endif
#endif
#if defined(CFG80211_CONNECT_DONE) && defined(WLAN_FEATURE_FILS_SK)
/**
* hdd_fils_update_connect_results() - API to send fils connection status to
* supplicant.
* @dev: network device
* @bssid: bssid to which we want to associate
* @bss: cfg80211 bss info
* @roam_info: information about connected bss
* @req_ie: Request Information Element
* @req_ie_len: len of the req IE
* @resp_ie: Response IE
* @resp_ie_len: len of ht response IE
* @status: status
* @gfp: allocation flags
* @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp
* @timeout_reason: reason for connect timeout
*
* The API is a wrapper to send connection status to supplicant
*
* Return: 0 if success else failure
*/
static int hdd_fils_update_connect_results(struct net_device *dev,
const u8 *bssid,
struct cfg80211_bss *bss,
tCsrRoamInfo *roam_info, const u8 *req_ie,
size_t req_ie_len, const u8 *resp_ie,
size_t resp_ie_len, u16 status, gfp_t gfp,
bool connect_timeout,
tSirResultCodes timeout_reason)
{
ENTER();
if (!roam_info || !roam_info->is_fils_connection)
return -EINVAL;
hdd_connect_done(dev, bssid, bss, roam_info, req_ie, req_ie_len,
resp_ie, resp_ie_len, status, gfp, connect_timeout,
timeout_reason, roam_info->fils_join_rsp);
return 0;
}
#else
static inline int hdd_fils_update_connect_results(struct net_device *dev,
const u8 *bssid,
struct cfg80211_bss *bss,
tCsrRoamInfo *roam_info, const u8 *req_ie,
size_t req_ie_len, const u8 *resp_ie,
size_t resp_ie_len, u16 status, gfp_t gfp,
bool connect_timeout,
tSirResultCodes timeout_reason)
{
return -EINVAL;
}
#endif
/**
* hdd_connect_result() - API to send connection status to supplicant
* @dev: network device
@ -4796,9 +4965,14 @@ void hdd_connect_result(struct net_device *dev, const u8 *bssid,
roam_info->u.pConnectedProfile->SSID.length);
}
hdd_connect_bss(dev, bssid, bss, req_ie,
req_ie_len, resp_ie, resp_ie_len,
status, gfp, connect_timeout, timeout_reason);
if (hdd_fils_update_connect_results(dev, bssid, bss,
roam_info, req_ie, req_ie_len, resp_ie,
resp_ie_len, status, gfp, connect_timeout,
timeout_reason) != 0) {
hdd_connect_bss(dev, bssid, bss, req_ie,
req_ie_len, resp_ie, resp_ie_len,
status, gfp, connect_timeout, timeout_reason);
}
qdf_runtime_pm_allow_suspend(&padapter->connect_rpm_ctx.connect);
hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT);

View File

@ -329,6 +329,20 @@ typedef enum eSirResultCodes {
eSIR_DONOT_USE_RESULT_CODE = SIR_MAX_ENUM_SIZE
} tSirResultCodes;
#ifdef WLAN_FEATURE_FILS_SK
struct fils_join_rsp_params {
uint8_t *fils_pmk;
uint8_t fils_pmk_len;
uint8_t fils_pmkid[PMKID_LEN];
uint8_t kek[MAX_KEK_LEN];
uint8_t kek_len;
uint8_t tk[MAX_TK_LEN];
uint8_t tk_len;
uint8_t gtk_len;
uint8_t gtk[MAX_GTK_LEN];
};
#endif
#define RMENABLEDCAP_MAX_LEN 5
struct rrm_config_param {
@ -1295,6 +1309,11 @@ typedef struct sSirSmeJoinRsp {
tDot11fIEHTInfo ht_operation;
tDot11fIEVHTOperation vht_operation;
tDot11fIEhs20vendor_ie hs20vendor_ie;
bool is_fils_connection;
#ifdef WLAN_FEATURE_FILS_SK
uint16_t fils_seq_num;
struct fils_join_rsp_params *fils_join_rsp;
#endif
uint8_t frames[1];
} tSirSmeJoinRsp, *tpSirSmeJoinRsp;

View File

@ -414,6 +414,11 @@ typedef struct sSirAssocRsp {
tSirQCNIE QCN_IE;
tDot11fIEvendor_he_cap vendor_he_cap;
tDot11fIEvendor_he_op vendor_he_op;
#ifdef WLAN_FEATURE_FILS_SK
tDot11fIEfils_session fils_session;
tDot11fIEfils_key_confirmation fils_key_auth;
tDot11fIEfils_kde fils_kde;
#endif
} tSirAssocRsp, *tpSirAssocRsp;
#ifdef FEATURE_WLAN_ESE
@ -579,6 +584,7 @@ sir_convert_assoc_req_frame2_struct(struct sAniSirGlobal *pMac,
tSirRetStatus
sir_convert_assoc_resp_frame2_struct(struct sAniSirGlobal *pMac,
tpPESession session_entry,
uint8_t *frame, uint32_t len,
tpSirAssocRsp assoc);
@ -1065,6 +1071,27 @@ populate_dot11f_ext_cap(tpAniSirGlobal pMac, bool isVHTEnabled,
void populate_dot11f_qcn_ie(tDot11fIEQCN_IE *pDot11f);
#ifdef WLAN_FEATURE_FILS_SK
/**
* populate_dot11f_fils_params() - Populate FILS IE to frame
* @mac_ctx: global mac context
* @frm: Assoc request frame
* @pe_session: PE session
*
* This API is used to populate FILS IE to Association request
*
* Return: None
*/
void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx,
tDot11fAssocRequest * frm,
tpPESession pe_session);
#else
static inline void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx,
tDot11fAssocRequest *frm,
tpPESession pe_session)
{ }
#endif
tSirRetStatus
populate_dot11f_operating_mode(tpAniSirGlobal pMac,
tDot11fIEOperatingMode *pDot11f,

View File

@ -34,6 +34,9 @@
#define MAX_KEY_AUTH_DATA_LEN 48
#define MAX_GTK_LEN 255
#define MAX_IGTK_LEN 255
#define SIR_FILS_SESSION_IE_LEN 11
#define FILS_KEY_RSC_LEN 8
#define FILS_MAX_KEY_AUTH_LEN (MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN)
#define IPN_LEN 6
#define FILS_SESSION_LENGTH 8
@ -90,6 +93,18 @@
#define SIR_FILS_EAP_TLV_CRYPTO_LIST 5
#define SIR_FILS_EAP_TLV_AUTH_INDICATION 6
#define DATA_TYPE_GTK 1
#define DATA_TYPE_IGTK 9
#define KEY_RSC_LEN 8
#define KDE_IE_DATA_OFFSET 4
#define KDE_DATA_TYPE_OFFSET 3
#define GTK_OFFSET 2
#define IPN_OFFSET 2
#define IGTK_OFFSET 8
#define KDE_OUI_TYPE "\x00\x0F\xAC"
#define KDE_OUI_TYPE_SIZE 3
/*
* struct eap_auth_reserved: this structure defines flags format in eap packets
* as defined in RFC 6696 5.3.1

View File

@ -99,6 +99,84 @@ static inline void lim_increase_fils_sequence_number(tpPESession session_entry)
session_entry->fils_info->sequence_number++;
}
/**
* populate_fils_connect_params() - Populate FILS connect params to join rsp
* @mac_ctx: Mac context
* @session: PE session
* @sme_join_rsp: SME join rsp
*
* This API copies the FILS connect params from PE session to SME join rsp
*
* Return: None
*/
void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
tpPESession session,
tpSirSmeJoinRsp sme_join_rsp);
/**
* aead_encrypt_assoc_req() - Encrypt FILS IE's in assoc request
* @mac_ctx: mac context
* @pe_session: PE session
* @frame: packed frame buffer
* @payload: length of @frame
*
* This API is used to encrypt the all the IE present after FILS session IE
* in Association request frame
*
* Return: QDF_STATUS
*/
QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx,
tpPESession pe_session,
uint8_t *frame, uint32_t *payload);
/**
* aead_decrypt_assoc_rsp() - API for AEAD decryption in FILS connection
* @mac_ctx: MAC context
* @session: PE session
* @ar: Assoc response frame structure
* @p_frame: frame buffer received
* @n_frame: length of @p_frame
*
* This API is used to decrypt the AEAD encrypted part of FILS assoc response
* and populate the decrypted FILS IE's to Assoc response frame structure(ar)
*
* Return: QDF_STATUS
*/
QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
tpPESession session,
tDot11fAssocResponse *ar,
uint8_t *p_frame, uint32_t *n_frame);
/**
* lim_is_fils_connection() - Check if it is FILS connection
* @pe_session: PE session
*
* This API is used to check if current PE session is FILS connection
*
* Return: True if FILS connection, false if not
*/
static inline bool lim_is_fils_connection(tpPESession pe_session)
{
if (pe_session->fils_info->is_fils_connection)
return true;
return false;
}
/**
* lim_verify_fils_params_assoc_rsp() - Verify FILS params in assoc rsp
* @mac_ctx: Mac context
* @session_entry: PE session
* @assoc_rsp: Assoc response received
* @assoc_cnf: Assoc cnf msg to be sent to MLME
*
* This API is used to match FILS params received in Assoc response
* with Assoc params received/derived at the Authentication stage
*
* Return: True, if successfully matches. False, otherwise
*/
bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
tpPESession session_entry,
tpSirAssocRsp assoc_rsp,
tLimMlmAssocCnf * assoc_cnf);
#else
static inline bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx,
tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body)
@ -130,4 +208,39 @@ static inline uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx,
{
return 0;
}
static inline bool lim_is_fils_connection(tpPESession pe_session)
{
return false;
}
static inline void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
tpPESession session,
tpSirSmeJoinRsp sme_join_rsp)
{ }
static inline QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx,
tpPESession pe_session,
uint8_t *frame,
uint32_t *payload)
{
return QDF_STATUS_SUCCESS;
}
static inline QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
tpPESession session,
tDot11fAssocResponse *ar,
uint8_t *p_frame, uint32_t *n_frame)
{
return QDF_STATUS_SUCCESS;
}
static inline bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
tpPESession session_entry,
tpSirAssocRsp assoc_rsp,
tLimMlmAssocCnf *assoc_cnf)
{
return true;
}
#endif

View File

@ -646,4 +646,13 @@ void pe_delete_session(tpAniSirGlobal pMac, tpPESession psessionEntry);
tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx,
uint8_t sme_session_id);
uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx);
#ifdef WLAN_FEATURE_FILS_SK
/**
* pe_delete_fils_info: API to delete fils session info
* @session: pe session
*
* Return: void
*/
void pe_delete_fils_info(tpPESession session);
#endif
#endif /* #if !defined( __LIM_SESSION_H ) */

View File

@ -767,16 +767,15 @@ lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr,
mlmStaContext.protStatusCode,
psessionEntry->peSessionId);
if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
pe_delete_session(pMac, psessionEntry);
psessionEntry = NULL;
}
lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP,
mlmStaContext.resultCode,
mlmStaContext.protStatusCode,
psessionEntry, smesessionId,
smetransactionId);
if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
pe_delete_session(pMac, psessionEntry);
psessionEntry = NULL;
}
} else {
qdf_mem_free(psessionEntry->pLimJoinReq);
psessionEntry->pLimJoinReq = NULL;
@ -788,16 +787,16 @@ lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr,
mlmStaContext.protStatusCode,
psessionEntry->peSessionId);
if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
pe_delete_session(pMac, psessionEntry);
psessionEntry = NULL;
}
lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_JOIN_RSP,
mlmStaContext.resultCode,
mlmStaContext.protStatusCode,
psessionEntry, smesessionId,
smetransactionId);
if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
pe_delete_session(pMac, psessionEntry);
psessionEntry = NULL;
}
}
} else if (mlmStaContext.cleanupTrigger == eLIM_DUPLICATE_ENTRY) {

View File

@ -51,7 +51,7 @@
#include "lim_ser_des_utils.h"
#include "lim_sta_hash_api.h"
#include "lim_send_messages.h"
#include "lim_process_fils.h"
extern tSirRetStatus sch_beacon_edca_process(tpAniSirGlobal pMac,
tSirMacEdcaParamSetIE *edca, tpPESession psessionEntry);
@ -626,7 +626,7 @@ lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx,
else
body = WMA_GET_RX_MPDU_DATA(rx_pkt_info);
/* parse Re/Association Response frame. */
if (sir_convert_assoc_resp_frame2_struct(mac_ctx, body,
if (sir_convert_assoc_resp_frame2_struct(mac_ctx, session_entry, body,
frame_len, assoc_rsp) == eSIR_FAILURE) {
qdf_mem_free(assoc_rsp);
pe_err("Parse error Assoc resp subtype: %d" "length: %d",
@ -759,6 +759,23 @@ lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx,
hdr->sa, session_entry, false);
goto assocReject;
}
/*
* If it is FILS connection, check is FILS params are matching
* with Authentication stage.
*/
if (!lim_verify_fils_params_assoc_rsp(mac_ctx, session_entry,
assoc_rsp, &assoc_cnf)) {
pe_err("FILS params doesnot match");
assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED;
assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS;
/* Send advisory Disassociation frame to AP */
lim_send_disassoc_mgmt_frame(mac_ctx,
eSIR_MAC_UNSPEC_FAILURE_REASON,
hdr->sa, session_entry, false);
goto assocReject;
}
/*
* Association Response received with success code
* Set the link state to POSTASSOC now that we have received

View File

@ -1235,4 +1235,555 @@ uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx,
}
return frame_len;
}
void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
tpPESession session,
tpSirSmeJoinRsp sme_join_rsp)
{
struct fils_join_rsp_params *fils_join_rsp;
struct pe_fils_session *fils_info = session->fils_info;
if (!lim_is_fils_connection(session))
return;
if (!fils_info->fils_pmk_len ||
!fils_info->tk_len || !fils_info->gtk_len ||
!fils_info->fils_pmk || !fils_info->kek_len) {
pe_err("Invalid FILS info pmk len %d kek len %d tk len %d gtk len %d",
fils_info->fils_pmk_len,
fils_info->kek_len,
fils_info->tk_len,
fils_info->gtk_len);
return;
}
sme_join_rsp->fils_join_rsp = qdf_mem_malloc(sizeof(*fils_join_rsp));
if (!sme_join_rsp->fils_join_rsp) {
pe_err("fils_join_rsp malloc fails!");
pe_delete_fils_info(session);
return;
}
fils_join_rsp = sme_join_rsp->fils_join_rsp;
fils_join_rsp->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len);
if (!fils_join_rsp->fils_pmk) {
pe_err("fils_pmk malloc fails!");
qdf_mem_free(fils_join_rsp);
pe_delete_fils_info(session);
return;
}
fils_join_rsp->fils_pmk_len = fils_info->fils_pmk_len;
qdf_mem_copy(fils_join_rsp->fils_pmk, fils_info->fils_pmk,
fils_info->fils_pmk_len);
qdf_mem_copy(fils_join_rsp->fils_pmkid, fils_info->fils_pmkid,
IEEE80211_PMKID_LEN);
fils_join_rsp->kek_len = fils_info->kek_len;
qdf_mem_copy(fils_join_rsp->kek, fils_info->kek, fils_info->kek_len);
fils_join_rsp->tk_len = fils_info->tk_len;
qdf_mem_copy(fils_join_rsp->tk, fils_info->tk, fils_info->tk_len);
fils_join_rsp->gtk_len = fils_info->gtk_len;
qdf_mem_copy(fils_join_rsp->gtk, fils_info->gtk, fils_info->gtk_len);
pe_debug("FILS connect params copied lim");
pe_delete_fils_info(session);
}
/**
* lim_parse_kde_elements() - Parse Key Delivery Elements
* @mac_ctx: mac context
* @fils_info: FILS info
* @kde_list: KDE list buffer
* @kde_list_len: Length of @kde_list
*
* This API is used to parse the Key Delivery Elements from buffer
* and populate them in PE FILS session struct i.e @fils_info
*
* Key Delivery Element[KDE] format
* +----------+--------+-----------+------------+----------+
* | ID(0xDD) | length | KDE OUI | data type | IE data |
* |----------|--------|-----------|------------|----------|
* | 1 byte | 1 byte | 3 bytes | 1 byte | variable |
* +----------+--------+-----------+------------+----------+
*
* there can be multiple KDE present inside KDE list.
* the IE data could be GTK, IGTK etc based on the data type
*
* Return: QDF_STATUS_SUCCESS if we parse GTK successfully,
* QDF_STATUS_E_FAILURE otherwise
*/
static QDF_STATUS lim_parse_kde_elements(tpAniSirGlobal mac_ctx,
struct pe_fils_session *fils_info,
uint8_t *kde_list,
uint8_t kde_list_len)
{
uint8_t rem_len = kde_list_len;
uint8_t *temp_ie = kde_list;
uint8_t elem_id, data_type, data_len, *ie_data = NULL, *current_ie;
uint16_t elem_len;
if (!kde_list_len || !kde_list) {
pe_err("kde_list NULL or kde_list_len %d", kde_list_len);
return QDF_STATUS_E_FAILURE;
}
while (rem_len >= 2) {
current_ie = temp_ie;
elem_id = *temp_ie++;
elem_len = *temp_ie++;
rem_len -= 2;
if (lim_check_if_vendor_oui_match(mac_ctx, KDE_OUI_TYPE,
KDE_OUI_TYPE_SIZE, current_ie, elem_len)) {
data_type = *(temp_ie + KDE_DATA_TYPE_OFFSET);
ie_data = (temp_ie + KDE_IE_DATA_OFFSET);
data_len = (elem_len - KDE_IE_DATA_OFFSET);
switch (data_type) {
case DATA_TYPE_GTK:
qdf_mem_copy(fils_info->gtk, (ie_data +
GTK_OFFSET), (data_len -
GTK_OFFSET));
fils_info->gtk_len = (data_len - GTK_OFFSET);
lim_fils_data_dump("GTK: ", fils_info->gtk,
fils_info->gtk_len);
break;
case DATA_TYPE_IGTK:
fils_info->igtk_len = (data_len - IGTK_OFFSET);
qdf_mem_copy(fils_info->igtk, (ie_data +
IGTK_OFFSET), (data_len -
IGTK_OFFSET));
qdf_mem_copy(fils_info->ipn, (ie_data +
IPN_OFFSET), IPN_LEN);
lim_fils_data_dump("IGTK: ", fils_info->igtk,
fils_info->igtk_len);
break;
default:
pe_err("Unknown KDE data type %x", data_type);
break;
}
}
temp_ie += elem_len;
rem_len -= elem_len;
ie_data = NULL;
}
/* Expecting GTK in KDE */
if (!fils_info->gtk_len) {
pe_err("GTK not found in KDE");
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
tpPESession session_entry,
tpSirAssocRsp assoc_rsp,
tLimMlmAssocCnf *assoc_cnf)
{
struct pe_fils_session *fils_info = session_entry->fils_info;
tDot11fIEfils_session fils_session = assoc_rsp->fils_session;
tDot11fIEfils_key_confirmation fils_key_auth = assoc_rsp->fils_key_auth;
tDot11fIEfils_kde fils_kde = assoc_rsp->fils_kde;
QDF_STATUS status;
if (!lim_is_fils_connection(session_entry))
return true;
if (!assoc_rsp->fils_session.present) {
pe_err("FILS IE not present");
goto verify_fils_params_fails;
}
/* Compare FILS session */
if (qdf_mem_cmp(fils_info->fils_session,
fils_session.session, DOT11F_IE_FILS_SESSION_MAX_LEN)) {
pe_err("FILS session mismatch");
goto verify_fils_params_fails;
}
/* Compare FILS key auth */
if ((fils_key_auth.num_key_auth != fils_info->key_auth_len) ||
qdf_mem_cmp(fils_info->ap_key_auth_data, fils_key_auth.key_auth,
fils_info->ap_key_auth_len)) {
lim_fils_data_dump("session keyauth",
fils_info->ap_key_auth_data,
fils_info->ap_key_auth_len);
lim_fils_data_dump("Pkt keyauth",
fils_key_auth.key_auth,
fils_key_auth.num_key_auth);
goto verify_fils_params_fails;
}
/* Verify the Key Delivery Element presence */
if (!fils_kde.num_kde_list) {
pe_err("FILS KDE list absent");
goto verify_fils_params_fails;
}
/* Derive KDE elements */
status = lim_parse_kde_elements(mac_ctx, fils_info, fils_kde.kde_list,
fils_kde.num_kde_list);
if (!QDF_IS_STATUS_SUCCESS(status)) {
pe_err("KDE parsing fails");
goto verify_fils_params_fails;
}
return true;
verify_fils_params_fails:
assoc_cnf->resultCode = eSIR_SME_ASSOC_REFUSED;
assoc_cnf->protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS;
return false;
}
/**
* find_ie_data_after_fils_session_ie() - Find IE pointer after FILS Session IE
* @mac_ctx: MAC context
* @buf: IE buffer
* @buf_len: Length of @buf
* @ie: Pointer to update the found IE pointer after FILS session IE
* @ie_len: length of the IE data after FILS session IE
*
* This API is used to find the IE data ptr and length after FILS session IE
*
* Return: QDF_STATUS_SUCCESS if found, else QDF_STATUS_E_FAILURE
*/
static QDF_STATUS find_ie_data_after_fils_session_ie(tpAniSirGlobal mac_ctx,
uint8_t *buf,
uint32_t buf_len,
uint8_t **ie,
uint32_t *ie_len)
{
uint32_t left = buf_len;
uint8_t *ptr = buf;
uint8_t elem_id, elem_len;
if (NULL == buf || 0 == buf_len)
return QDF_STATUS_E_FAILURE;
while (left >= 2) {
elem_id = ptr[0];
elem_len = ptr[1];
left -= 2;
if (elem_len > left)
return QDF_STATUS_E_FAILURE;
if (elem_id == SIR_MAC_REQUEST_EID_MAX &&
ptr[2] == SIR_FILS_SESSION_EXT_EID) {
(*ie) = ((&ptr[1]) + ptr[1] + 1);
(*ie_len) = (left - elem_len);
return QDF_STATUS_SUCCESS;
}
left -= elem_len;
ptr += (elem_len + 2);
}
return QDF_STATUS_E_FAILURE;
}
/**
* fils_aead_encrypt() - API to do FILS AEAD encryption
*
* @kek: Pointer to KEK
* @kek_len: KEK length
* @own_mac: Pointer to own MAC address
* @bssid: Bssid
* @snonce: Supplicant Nonce
* @anonce: Authenticator Nonce
* @data: Pointer to data after MAC header
* @data_len: length of @data
* @plain_text: Pointer to data after FILS Session IE
* @plain_text_len: length of @plain_text
* @out: Pointer to the encrypted data
*
* length of AEAD encryption @out is @plain_text_len + AES_BLOCK_SIZE[16 bytes]
*
* Return: zero on success, error otherwise
*/
static int fils_aead_encrypt(const u8 *kek, unsigned int kek_len,
const u8 *own_mac, const u8 *bssid,
const u8 *snonce, const u8 *anonce,
const u8 *data, size_t data_len, u8 *plain_text,
size_t plain_text_len, u8 *out)
{
u8 v[AES_BLOCK_SIZE];
const u8 *aad[6];
size_t aad_len[6];
u8 *buf;
int ret;
/* SIV Encrypt/Decrypt takes input key of length 256, 384 or 512 bits */
if (kek_len != 32 && kek_len != 48 && kek_len != 64) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("Invalid key length: %u"), kek_len);
return -EINVAL;
}
if (own_mac == NULL || bssid == NULL || snonce == NULL ||
anonce == NULL || data_len == 0 || plain_text_len == 0 ||
out == NULL) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("Error missing params mac:%p bssid:%p snonce:%p anonce:%p data_len:%lu plain_text_len:%lu out:%p"),
own_mac, bssid, snonce, anonce, data_len,
plain_text_len, out);
return -EINVAL;
}
if (plain_text == out) {
buf = qdf_mem_malloc(plain_text_len);
if (buf == NULL) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("Failed to allocate memory"));
return -ENOMEM;
}
qdf_mem_copy(buf, plain_text, plain_text_len);
} else {
buf = plain_text;
}
aad[0] = own_mac;
aad_len[0] = QDF_MAC_ADDR_SIZE;
aad[1] = bssid;
aad_len[1] = QDF_MAC_ADDR_SIZE;
aad[2] = snonce;
aad_len[2] = SIR_FILS_NONCE_LENGTH;
aad[3] = anonce;
aad_len[3] = SIR_FILS_NONCE_LENGTH;
aad[4] = data;
aad_len[4] = data_len;
/* Plain text, P, is Sn in AES-SIV */
aad[5] = buf;
aad_len[5] = plain_text_len;
/* AES-SIV S2V */
/* K1 = leftmost(K, len(K)/2) */
ret = qdf_aes_s2v(kek, kek_len/2, aad, aad_len, 6, v);
if (ret)
goto error;
/* out = SIV || C (Synthetic Initialization Vector || Ciphered text) */
qdf_mem_copy(out, v, AES_BLOCK_SIZE);
/* AES-SIV CTR */
/* K2 = rightmost(K, len(K)/2) */
/* Clear 31st and 63rd bits in counter synthetic iv */
v[12] &= 0x7F;
v[8] &= 0x7F;
ret = qdf_aes_ctr(kek + kek_len/2, kek_len/2, v, buf, plain_text_len,
out + AES_BLOCK_SIZE, true);
error:
if (plain_text == out)
qdf_mem_free(buf);
return ret;
}
QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx,
tpPESession pe_session,
uint8_t *frm, uint32_t *frm_len)
{
uint8_t *plain_text = NULL, *data;
uint32_t plain_text_len = 0, data_len;
QDF_STATUS status;
struct pe_fils_session *fils_info = pe_session->fils_info;
/*
* data is the packet data after MAC header till
* FILS session IE(inclusive)
*/
data = frm + sizeof(tSirMacMgmtHdr);
/*
* plain_text is the packet data after FILS session IE
* which needs to be encrypted. Get plain_text ptr and
* plain_text_len values using find_ptr_aft_fils_session_ie()
*/
status = find_ie_data_after_fils_session_ie(mac_ctx, data +
FIXED_PARAM_OFFSET_ASSOC_REQ,
(*frm_len -
FIXED_PARAM_OFFSET_ASSOC_REQ),
&plain_text, &plain_text_len);
if (QDF_IS_STATUS_ERROR(status)) {
pe_err("Could not find FILS session IE");
return QDF_STATUS_E_FAILURE;
}
data_len = ((*frm_len) - plain_text_len);
lim_fils_data_dump("Plain text: ", plain_text, plain_text_len);
/* Overwrite the AEAD encrypted output @ plain_text */
if (fils_aead_encrypt(fils_info->kek, fils_info->kek_len,
pe_session->selfMacAddr, pe_session->bssId,
fils_info->fils_nonce,
fils_info->auth_info.fils_nonce,
data, data_len, plain_text, plain_text_len,
plain_text)) {
pe_err("AEAD Encryption fails!");
return QDF_STATUS_E_FAILURE;
}
/*
* AEAD encrypted output(cipher_text) will have length equals to
* plain_text_len + AES_BLOCK_SIZE(AEAD encryption header info).
* Add this to frm_len
*/
(*frm_len) += (AES_BLOCK_SIZE);
return QDF_STATUS_SUCCESS;
}
/**
* fils_aead_decrypt() - API to do AEAD decryption
*
* @kek: Pointer to KEK
* @kek_len: KEK length
* @own_mac: Pointer to own MAC address
* @bssid: Bssid
* @snonce: Supplicant Nonce
* @anonce: Authenticator Nonce
* @data: Pointer to data after MAC header
* @data_len: length of @data
* @plain_text: Pointer to data after FILS Session IE
* @plain_text_len: length of @plain_text
* @out: Pointer to the encrypted data
*
* Return: zero on success, error otherwise
*/
static int fils_aead_decrypt(const u8 *kek, unsigned int kek_len,
const u8 *own_mac, const u8 *bssid,
const u8 *snonce, const u8 *anonce,
const u8 *data, size_t data_len, u8 *ciphered_text,
size_t ciphered_text_len, u8 *plain_text)
{
const u8 *aad[6];
size_t aad_len[6];
u8 *buf;
size_t buf_len;
u8 v[AES_BLOCK_SIZE];
u8 siv[AES_BLOCK_SIZE];
int ret;
/* SIV Encrypt/Decrypt takes input key of length 256, 384 or 512 bits */
if (kek_len != 32 && kek_len != 48 && kek_len != 64) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("Invalid key length: %u"), kek_len);
return -EINVAL;
}
if (own_mac == NULL || bssid == NULL || snonce == NULL ||
anonce == NULL || data_len == 0 || ciphered_text_len == 0 ||
plain_text == NULL) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("Error missing params mac:%p bssid:%p snonce:%p anonce:%p data_len:%lu ciphered_text_len:%lu plain_text:%p"),
own_mac, bssid, snonce, anonce, data_len,
ciphered_text_len, plain_text);
return -EINVAL;
}
qdf_mem_copy(v, ciphered_text, AES_BLOCK_SIZE);
qdf_mem_copy(siv, ciphered_text, AES_BLOCK_SIZE);
v[12] &= 0x7F;
v[8] &= 0x7F;
buf_len = ciphered_text_len - AES_BLOCK_SIZE;
if (ciphered_text == plain_text) {
/* in place decryption */
buf = qdf_mem_malloc(buf_len);
if (buf == NULL) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("Failed to allocate memory"));
return -ENOMEM;
}
qdf_mem_copy(buf, ciphered_text + AES_BLOCK_SIZE, buf_len);
} else {
buf = ciphered_text + AES_BLOCK_SIZE;
}
/* AES-SIV CTR */
/* K2 = rightmost(K, len(K)/2) */
ret = qdf_aes_ctr(kek + kek_len/2, kek_len/2, v, buf, buf_len,
plain_text, false);
if (ret)
goto error;
aad[0] = bssid;
aad_len[0] = QDF_MAC_ADDR_SIZE;
aad[1] = own_mac;
aad_len[1] = QDF_MAC_ADDR_SIZE;
aad[2] = anonce;
aad_len[2] = SIR_FILS_NONCE_LENGTH;
aad[3] = snonce;
aad_len[3] = SIR_FILS_NONCE_LENGTH;
aad[4] = data;
aad_len[4] = data_len;
aad[5] = plain_text;
aad_len[5] = buf_len;
/* AES-SIV S2V */
/* K1 = leftmost(K, len(K)/2) */
ret = qdf_aes_s2v(kek, kek_len/2, aad, aad_len, 6, v);
if (ret)
goto error;
/* compare the iv generated against the one sent by AP */
if (memcmp(v, siv, AES_BLOCK_SIZE) != 0) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
FL("siv not same as frame siv"));
ret = -EINVAL;
}
error:
if (ciphered_text == plain_text)
qdf_mem_free(buf);
return ret;
}
QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
tpPESession session,
tDot11fAssocResponse *ar,
uint8_t *p_frame, uint32_t *n_frame)
{
QDF_STATUS status;
uint32_t data_len, fils_ies_len;
uint8_t *fils_ies;
struct pe_fils_session *fils_info = session->fils_info;
lim_fils_data_dump("Assoc Rsp :", p_frame, *n_frame);
status = find_ie_data_after_fils_session_ie(mac_ctx, p_frame +
FIXED_PARAM_OFFSET_ASSOC_RSP,
((*n_frame) -
FIXED_PARAM_OFFSET_ASSOC_RSP),
&fils_ies, &fils_ies_len);
if (!QDF_IS_STATUS_SUCCESS(status)) {
pe_err("FILS session IE not present");
return status;
}
data_len = (*n_frame) - fils_ies_len;
if (fils_aead_decrypt(fils_info->kek, fils_info->kek_len,
session->selfMacAddr, session->bssId,
fils_info->fils_nonce,
fils_info->auth_info.fils_nonce,
p_frame, data_len,
fils_ies, fils_ies_len, fils_ies)){
pe_err("AEAD decryption fails");
return QDF_STATUS_E_FAILURE;
}
/* Dump the output of AEAD decrypt */
lim_fils_data_dump("Plain text: ", fils_ies,
fils_ies_len - AES_BLOCK_SIZE);
(*n_frame) -= AES_BLOCK_SIZE;
return status;
}
#endif

View File

@ -1289,7 +1289,7 @@ static void lim_join_result_callback(tpAniSirGlobal mac, void *param,
lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_JOIN_RSP,
link_state_params->result_code,
link_state_params->prot_status_code,
NULL, sme_session_id, sme_trans_id);
session, sme_session_id, sme_trans_id);
pe_delete_session(mac, session);
qdf_mem_free(link_state_params);
}

View File

@ -59,6 +59,7 @@
#include "cds_utils.h"
#include "sme_trace.h"
#include "rrm_api.h"
#include "qdf_crypto.h"
#include "wma_types.h"
#include <cdp_txrx_cmn.h>
@ -1637,6 +1638,7 @@ lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx,
tDot11fIEExtCap bcn_ext_cap;
uint8_t *bcn_ie = NULL;
uint32_t bcn_ie_len = 0;
uint32_t aes_block_size_len = 0;
if (NULL == pe_session) {
pe_err("pe_session is NULL");
@ -1921,6 +1923,20 @@ lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx,
add_ie, &add_ie_len, &frm->SuppOperatingClasses))
pe_debug("Unable to Stripoff supp op classes IE from Assoc Req");
if (lim_is_fils_connection(pe_session)) {
populate_dot11f_fils_params(mac_ctx, frm, pe_session);
aes_block_size_len = AES_BLOCK_SIZE;
}
/*
* Do unpack to populate the add_ie buffer to frm structure
* before packing the frm structure. In this way, the IE ordering
* which the latest 802.11 spec mandates is maintained.
*/
if (add_ie_len)
dot11f_unpack_assoc_request(mac_ctx, add_ie,
add_ie_len, frm, true);
status = dot11f_get_packed_assoc_request_size(mac_ctx, frm, &payload);
if (DOT11F_FAILED(status)) {
pe_err("Association Request packet size failure(0x%08x)",
@ -1932,7 +1948,8 @@ lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx,
status);
}
bytes = payload + sizeof(tSirMacMgmtHdr) + add_ie_len;
bytes = payload + sizeof(tSirMacMgmtHdr) +
aes_block_size_len;
qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame,
(void **)&packet);
@ -1974,17 +1991,20 @@ lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx,
pe_warn("Assoc request pack warning (0x%08x)", status);
}
pe_debug("Sending Association Request length %d to ", bytes);
if (pe_session->assocReq != NULL) {
qdf_mem_free(pe_session->assocReq);
pe_session->assocReq = NULL;
pe_session->assocReqLen = 0;
}
if (add_ie_len) {
qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload,
add_ie, add_ie_len);
payload += add_ie_len;
if (lim_is_fils_connection(pe_session)) {
qdf_status = aead_encrypt_assoc_req(mac_ctx, pe_session,
frame, &payload);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
cds_packet_free((void *)packet);
qdf_mem_free(frm);
return;
}
}
pe_session->assocReq = qdf_mem_malloc(payload);
@ -2017,6 +2037,8 @@ lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx,
mac_hdr = (tpSirMacMgmtHdr) frame;
MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT,
pe_session->peSessionId, mac_hdr->fc.subType));
pe_debug("Sending Association Request length %d to ", bytes);
qdf_status =
wma_tx_frame(mac_ctx, packet,
(uint16_t) (sizeof(tSirMacMgmtHdr) + payload),

View File

@ -64,6 +64,7 @@
#ifdef CONVERGED_TDLS_ENABLE
#include "wlan_tdls_tgt_api.h"
#endif
#include "lim_process_fils.h"
static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx,
tpPESession session_entry, tSirResultCodes result_code,
@ -453,6 +454,18 @@ static void lim_add_bss_info(tpDphHashNode sta_ds, tpSirSmeJoinRsp sme_join_rsp)
sme_join_rsp->vht_operation = parsed_ies->vht_operation;
}
#ifdef WLAN_FEATURE_FILS_SK
static void lim_update_fils_seq_num(tpSirSmeJoinRsp sme_join_rsp,
tpPESession session_entry)
{
sme_join_rsp->fils_seq_num =
session_entry->fils_info->sequence_number;
}
#else
static inline void lim_update_fils_seq_num(tpSirSmeJoinRsp sme_join_rsp,
tpPESession session_entry)
{}
#endif
/**
* lim_send_sme_join_reassoc_rsp() - Send Response to Upper Layers
* @mac_ctx: Pointer to Global MAC structure
@ -516,6 +529,13 @@ lim_send_sme_join_reassoc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type,
pe_err("MemAlloc fail - JOIN/REASSOC_RSP");
return;
}
if (lim_is_fils_connection(session_entry)) {
sme_join_rsp->is_fils_connection = true;
lim_update_fils_seq_num(sme_join_rsp,
session_entry);
}
if (result_code == eSIR_SME_SUCCESS) {
sta_ds = dph_get_hash_entry(mac_ctx,
DPH_STA_HASH_INDEX_PEER,
@ -541,8 +561,13 @@ lim_send_sme_join_reassoc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type,
sme_join_rsp->max_rate_flags =
lim_get_max_rate_flags(mac_ctx, sta_ds);
lim_add_bss_info(sta_ds, sme_join_rsp);
/* Copy FILS params only for Successful join */
populate_fils_connect_params(mac_ctx,
session_entry, sme_join_rsp);
}
}
sme_join_rsp->beaconLength = 0;
sme_join_rsp->assocReqLength = 0;
sme_join_rsp->assocRspLength = 0;

View File

@ -274,7 +274,7 @@ pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx,
*
* Return: void
*/
static void pe_delete_fils_info(tpPESession session)
void pe_delete_fils_info(tpPESession session)
{
struct pe_fils_session *fils_info;

View File

@ -7988,3 +7988,22 @@ tCsrRoamSession *lim_get_session_by_macaddr(tpAniSirGlobal mac_ctx,
return NULL;
}
bool lim_check_if_vendor_oui_match(tpAniSirGlobal mac_ctx,
uint8_t *oui, uint8_t oui_len,
uint8_t *ie, uint8_t ie_len)
{
uint8_t *ptr = ie;
uint8_t elem_id = *ie;
if (NULL == ie || 0 == ie_len) {
pe_err("IE Null or ie len zero %d", ie_len);
return false;
}
if (elem_id == IE_EID_VENDOR &&
!qdf_mem_cmp(&ptr[2], oui, oui_len))
return true;
else
return false;
}

View File

@ -1127,4 +1127,19 @@ void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx,
* Return: None
*/
void lim_decrement_pending_mgmt_count(tpAniSirGlobal mac_ctx);
/**
* lim_check_if_vendor_oui_match() - Check if the given OUI match in IE buffer
* @mac_ctx: MAC context
* @ie: IE buffer
* @ie_len: length of @ie
*
* This API is used to check if given vendor OUI
* matches in given IE buffer
*
* Return: True, if mataches. False otherwise
*/
bool lim_check_if_vendor_oui_match(tpAniSirGlobal mac_ctx,
uint8_t *oui, uint8_t oui_len,
uint8_t *ie, uint8_t ie_len);
#endif /* __LIM_UTILS_H */

View File

@ -48,6 +48,8 @@
#include "rrm_api.h"
#include "cds_regdomain.h"
#include "qdf_crypto.h"
#include "lim_process_fils.h"
/* ////////////////////////////////////////////////////////////////////// */
void swap_bit_field16(uint16_t in, uint16_t *out)
@ -2269,8 +2271,53 @@ void sir_copy_caps_info(tpAniSirGlobal mac_ctx, tDot11fFfCapabilities caps,
}
#ifdef WLAN_FEATURE_FILS_SK
static void populate_dot11f_fils_rsn(tpAniSirGlobal mac_ctx,
tDot11fIERSNOpaque *p_dot11f,
uint8_t *rsn_ie)
{
pe_debug("FILS RSN IE length %d", rsn_ie[1]);
if (rsn_ie[1]) {
p_dot11f->present = 1;
p_dot11f->num_data = rsn_ie[1];
qdf_mem_copy(p_dot11f->data, &rsn_ie[2], rsn_ie[1]);
}
}
void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx,
tDot11fAssocRequest *frm,
tpPESession pe_session)
{
struct pe_fils_session *fils_info = pe_session->fils_info;
/* Populate RSN IE with FILS AKM */
populate_dot11f_fils_rsn(mac_ctx, &frm->RSNOpaque,
fils_info->rsn_ie);
/* Populate FILS session IE */
frm->fils_session.present = true;
qdf_mem_copy(frm->fils_session.session,
fils_info->fils_session, FILS_SESSION_LENGTH);
/* Populate FILS Key confirmation IE */
if (fils_info->key_auth_len) {
frm->fils_key_confirmation.present = true;
frm->fils_key_confirmation.num_key_auth =
fils_info->key_auth_len;
qdf_mem_copy(frm->fils_key_confirmation.key_auth,
fils_info->key_auth, fils_info->key_auth_len);
}
}
/**
* update_fils_data: update fils params from beacon/probe response
* @fils_ind: pointer to sir_fils_indication
* @fils_indication: pointer to tDot11fIEfils_indication
*
* Return: None
*/
void update_fils_data(struct sir_fils_indication *fils_ind,
tDot11fIEfils_indication *fils_indication)
tDot11fIEfils_indication *fils_indication)
{
uint8_t *data;
@ -2787,231 +2834,321 @@ sir_convert_assoc_req_frame2_struct(tpAniSirGlobal pMac,
} /* End sir_convert_assoc_req_frame2_struct. */
/**
* dot11f_parse_assoc_response() - API to parse Assoc IE buffer to struct
* @mac_ctx: MAC context
* @p_buf: Pointer to the assoc IE buffer
* @n_buf: length of the @p_buf
* @p_frm: Struct to populate the IE buffer after parsing
* @append_ie: Boolean to indicate whether to reset @p_frm or not. If @append_ie
* is true, @p_frm struct is not reset to zeros.
*
* Return: tSirRetStatus
*/
static tSirRetStatus dot11f_parse_assoc_response(tpAniSirGlobal mac_ctx,
uint8_t *p_buf, uint32_t n_buf,
tDot11fAssocResponse *p_frm,
bool append_ie)
{
uint32_t status;
status = dot11f_unpack_assoc_response(mac_ctx, p_buf,
n_buf, p_frm, append_ie);
if (DOT11F_FAILED(status)) {
pe_err("Failed to parse an Association Response (0x%08x, %d bytes):",
status, n_buf);
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR,
p_buf, n_buf);
return eSIR_FAILURE;
}
return eSIR_SUCCESS;
}
#ifdef WLAN_FEATURE_FILS_SK
/**
* fils_convert_assoc_rsp_frame2_struct() - Copy FILS IE's to Assoc rsp struct
* @ar: frame parser Assoc response struct
* @pAssocRsp: LIM Assoc response
*
* Return: None
*/
static void fils_convert_assoc_rsp_frame2_struct(tDot11fAssocResponse *ar,
tpSirAssocRsp pAssocRsp)
{
if (ar->fils_session.present) {
pe_debug("fils session IE present");
pAssocRsp->fils_session.present = true;
qdf_mem_copy(pAssocRsp->fils_session.session,
ar->fils_session.session,
DOT11F_IE_FILS_SESSION_MAX_LEN);
}
if (ar->fils_key_confirmation.present) {
pe_debug("fils key conf IE present");
pAssocRsp->fils_key_auth.num_key_auth =
ar->fils_key_confirmation.num_key_auth;
qdf_mem_copy(pAssocRsp->fils_key_auth.key_auth,
ar->fils_key_confirmation.key_auth,
pAssocRsp->fils_key_auth.num_key_auth);
}
if (ar->fils_kde.present) {
pe_debug("fils kde IE present %d",
ar->fils_kde.num_kde_list);
pAssocRsp->fils_kde.num_kde_list =
ar->fils_kde.num_kde_list;
qdf_mem_copy(pAssocRsp->fils_kde.key_rsc,
ar->fils_kde.key_rsc, KEY_RSC_LEN);
qdf_mem_copy(&pAssocRsp->fils_kde.kde_list,
&ar->fils_kde.kde_list,
pAssocRsp->fils_kde.num_kde_list);
}
}
#else
static inline void fils_convert_assoc_rsp_frame2_struct(tDot11fAssocResponse
*ar, tpSirAssocRsp
pAssocRsp)
{ }
#endif
tSirRetStatus
sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac,
uint8_t *pFrame,
uint32_t nFrame, tpSirAssocRsp pAssocRsp)
tpPESession session_entry,
uint8_t *pFrame, uint32_t nFrame,
tpSirAssocRsp pAssocRsp)
{
static tDot11fAssocResponse ar;
tDot11fAssocResponse *ar;
uint32_t status;
uint8_t cnt = 0;
/* Zero-init our [out] parameter, */
qdf_mem_set((uint8_t *) pAssocRsp, sizeof(tSirAssocRsp), 0);
/* delegate to the framesc-generated code, */
status = dot11f_unpack_assoc_response(pMac, pFrame, nFrame, &ar, false);
if (DOT11F_FAILED(status)) {
pe_err("Failed to parse an Association Response (0x%08x, %d bytes):",
status, nFrame);
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR,
pFrame, nFrame);
ar = qdf_mem_malloc(sizeof(*ar));
if (!ar) {
pe_err("Assoc rsp mem alloc fails");
return eSIR_FAILURE;
} else if (DOT11F_WARNED(status)) {
pe_debug("There were warnings while unpacking an Association Response (0x%08x, %d bytes):",
status, nFrame);
}
/* & "transliterate" from a 'tDot11fAssocResponse' a 'tSirAssocRsp'... */
/* decrypt the cipher text using AEAD decryption */
if (lim_is_fils_connection(session_entry)) {
status = aead_decrypt_assoc_rsp(pMac, session_entry,
ar, pFrame, &nFrame);
if (!QDF_IS_STATUS_SUCCESS(status)) {
pe_err("FILS assoc rsp AEAD decrypt fails");
qdf_mem_free(ar);
return eSIR_FAILURE;
}
}
status = dot11f_parse_assoc_response(pMac, pFrame, nFrame, ar, false);
if (eSIR_SUCCESS != status) {
qdf_mem_free(ar);
return status;
}
/* Capabilities */
pAssocRsp->capabilityInfo.ess = ar.Capabilities.ess;
pAssocRsp->capabilityInfo.ibss = ar.Capabilities.ibss;
pAssocRsp->capabilityInfo.cfPollable = ar.Capabilities.cfPollable;
pAssocRsp->capabilityInfo.cfPollReq = ar.Capabilities.cfPollReq;
pAssocRsp->capabilityInfo.privacy = ar.Capabilities.privacy;
pAssocRsp->capabilityInfo.shortPreamble = ar.Capabilities.shortPreamble;
pAssocRsp->capabilityInfo.pbcc = ar.Capabilities.pbcc;
pAssocRsp->capabilityInfo.ess = ar->Capabilities.ess;
pAssocRsp->capabilityInfo.ibss = ar->Capabilities.ibss;
pAssocRsp->capabilityInfo.cfPollable = ar->Capabilities.cfPollable;
pAssocRsp->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq;
pAssocRsp->capabilityInfo.privacy = ar->Capabilities.privacy;
pAssocRsp->capabilityInfo.shortPreamble =
ar->Capabilities.shortPreamble;
pAssocRsp->capabilityInfo.pbcc = ar->Capabilities.pbcc;
pAssocRsp->capabilityInfo.channelAgility =
ar.Capabilities.channelAgility;
pAssocRsp->capabilityInfo.spectrumMgt = ar.Capabilities.spectrumMgt;
pAssocRsp->capabilityInfo.qos = ar.Capabilities.qos;
pAssocRsp->capabilityInfo.shortSlotTime = ar.Capabilities.shortSlotTime;
pAssocRsp->capabilityInfo.apsd = ar.Capabilities.apsd;
pAssocRsp->capabilityInfo.rrm = ar.Capabilities.rrm;
pAssocRsp->capabilityInfo.dsssOfdm = ar.Capabilities.dsssOfdm;
pAssocRsp->capabilityInfo.delayedBA = ar.Capabilities.delayedBA;
pAssocRsp->capabilityInfo.immediateBA = ar.Capabilities.immediateBA;
ar->Capabilities.channelAgility;
pAssocRsp->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt;
pAssocRsp->capabilityInfo.qos = ar->Capabilities.qos;
pAssocRsp->capabilityInfo.shortSlotTime =
ar->Capabilities.shortSlotTime;
pAssocRsp->capabilityInfo.apsd = ar->Capabilities.apsd;
pAssocRsp->capabilityInfo.rrm = ar->Capabilities.rrm;
pAssocRsp->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm;
pAssocRsp->capabilityInfo.delayedBA = ar->Capabilities.delayedBA;
pAssocRsp->capabilityInfo.immediateBA = ar->Capabilities.immediateBA;
pAssocRsp->statusCode = ar.Status.status;
pAssocRsp->aid = ar.AID.associd;
pAssocRsp->statusCode = ar->Status.status;
pAssocRsp->aid = ar->AID.associd;
#ifdef WLAN_FEATURE_11W
if (ar.TimeoutInterval.present) {
if (ar->TimeoutInterval.present) {
pAssocRsp->TimeoutInterval.present = 1;
pAssocRsp->TimeoutInterval.timeoutType =
ar.TimeoutInterval.timeoutType;
ar->TimeoutInterval.timeoutType;
pAssocRsp->TimeoutInterval.timeoutValue =
ar.TimeoutInterval.timeoutValue;
ar->TimeoutInterval.timeoutValue;
}
#endif
if (!ar.SuppRates.present) {
if (!ar->SuppRates.present) {
pAssocRsp->suppRatesPresent = 0;
pe_warn("Mandatory IE Supported Rates not present!");
} else {
pAssocRsp->suppRatesPresent = 1;
convert_supp_rates(pMac, &pAssocRsp->supportedRates,
&ar.SuppRates);
&ar->SuppRates);
}
if (ar.ExtSuppRates.present) {
if (ar->ExtSuppRates.present) {
pAssocRsp->extendedRatesPresent = 1;
convert_ext_supp_rates(pMac, &pAssocRsp->extendedRates,
&ar.ExtSuppRates);
&ar->ExtSuppRates);
}
if (ar.EDCAParamSet.present) {
if (ar->EDCAParamSet.present) {
pAssocRsp->edcaPresent = 1;
convert_edca_param(pMac, &pAssocRsp->edca, &ar.EDCAParamSet);
convert_edca_param(pMac, &pAssocRsp->edca, &ar->EDCAParamSet);
}
if (ar.WMMParams.present) {
if (ar->WMMParams.present) {
pAssocRsp->wmeEdcaPresent = 1;
convert_wmm_params(pMac, &pAssocRsp->edca, &ar.WMMParams);
convert_wmm_params(pMac, &pAssocRsp->edca, &ar->WMMParams);
pe_debug("Received Assoc Resp with WMM Param");
__print_wmm_params(pMac, &ar.WMMParams);
__print_wmm_params(pMac, &ar->WMMParams);
}
if (ar.HTCaps.present) {
if (ar->HTCaps.present) {
pe_debug("Received Assoc Resp with HT Cap");
qdf_mem_copy(&pAssocRsp->HTCaps, &ar.HTCaps,
qdf_mem_copy(&pAssocRsp->HTCaps, &ar->HTCaps,
sizeof(tDot11fIEHTCaps));
}
if (ar.HTInfo.present) {
if (ar->HTInfo.present) {
pe_debug("Received Assoc Resp with HT Info");
qdf_mem_copy(&pAssocRsp->HTInfo, &ar.HTInfo,
qdf_mem_copy(&pAssocRsp->HTInfo, &ar->HTInfo,
sizeof(tDot11fIEHTInfo));
}
if (ar.MobilityDomain.present) {
if (ar->MobilityDomain.present) {
/* MobilityDomain */
pAssocRsp->mdiePresent = 1;
qdf_mem_copy((uint8_t *) &(pAssocRsp->mdie[0]),
(uint8_t *) &(ar.MobilityDomain.MDID),
sizeof(uint16_t));
pAssocRsp->mdie[2] =
((ar.MobilityDomain.overDSCap << 0) | (ar.MobilityDomain.
resourceReqCap <<
1));
(uint8_t *) &(ar->MobilityDomain.MDID),
sizeof(uint16_t));
pAssocRsp->mdie[2] = ((ar->MobilityDomain.overDSCap << 0) |
(ar->MobilityDomain.resourceReqCap << 1));
pe_debug("new mdie=%02x%02x%02x",
(unsigned int)pAssocRsp->mdie[0],
(unsigned int)pAssocRsp->mdie[1],
(unsigned int)pAssocRsp->mdie[2]);
}
if (ar.FTInfo.present) {
if (ar->FTInfo.present) {
pe_debug("FT Info present %d %d %d",
ar.FTInfo.R0KH_ID.num_PMK_R0_ID,
ar.FTInfo.R0KH_ID.present, ar.FTInfo.R1KH_ID.present);
ar->FTInfo.R0KH_ID.num_PMK_R0_ID,
ar->FTInfo.R0KH_ID.present, ar->FTInfo.R1KH_ID.present);
pAssocRsp->ftinfoPresent = 1;
qdf_mem_copy(&pAssocRsp->FTInfo, &ar.FTInfo,
sizeof(tDot11fIEFTInfo));
qdf_mem_copy(&pAssocRsp->FTInfo, &ar->FTInfo,
sizeof(tDot11fIEFTInfo));
}
if (ar.num_RICDataDesc && ar.num_RICDataDesc <= 2) {
for (cnt = 0; cnt < ar.num_RICDataDesc; cnt++) {
if (ar.RICDataDesc[cnt].present) {
if (ar->num_RICDataDesc && ar->num_RICDataDesc <= 2) {
for (cnt = 0; cnt < ar->num_RICDataDesc; cnt++) {
if (ar->RICDataDesc[cnt].present) {
qdf_mem_copy(&pAssocRsp->RICData[cnt],
&ar.RICDataDesc[cnt],
sizeof(tDot11fIERICDataDesc));
&ar->RICDataDesc[cnt],
sizeof(tDot11fIERICDataDesc));
}
}
pAssocRsp->num_RICData = ar.num_RICDataDesc;
pAssocRsp->num_RICData = ar->num_RICDataDesc;
pAssocRsp->ricPresent = true;
}
#ifdef FEATURE_WLAN_ESE
if (ar.num_WMMTSPEC) {
pAssocRsp->num_tspecs = ar.num_WMMTSPEC;
for (cnt = 0; cnt < ar.num_WMMTSPEC; cnt++) {
if (ar->num_WMMTSPEC) {
pAssocRsp->num_tspecs = ar->num_WMMTSPEC;
for (cnt = 0; cnt < ar->num_WMMTSPEC; cnt++) {
qdf_mem_copy(&pAssocRsp->TSPECInfo[cnt],
&ar.WMMTSPEC[cnt],
(sizeof(tDot11fIEWMMTSPEC) *
ar.num_WMMTSPEC));
&ar->WMMTSPEC[cnt],
(sizeof(tDot11fIEWMMTSPEC) *
ar->num_WMMTSPEC));
}
pAssocRsp->tspecPresent = true;
}
if (ar.ESETrafStrmMet.present) {
if (ar->ESETrafStrmMet.present) {
pAssocRsp->tsmPresent = 1;
qdf_mem_copy(&pAssocRsp->tsmIE.tsid,
&ar.ESETrafStrmMet.tsid, sizeof(tSirMacESETSMIE));
&ar->ESETrafStrmMet.tsid,
sizeof(tSirMacESETSMIE));
}
#endif
if (ar.VHTCaps.present) {
qdf_mem_copy(&pAssocRsp->VHTCaps, &ar.VHTCaps,
if (ar->VHTCaps.present) {
qdf_mem_copy(&pAssocRsp->VHTCaps, &ar->VHTCaps,
sizeof(tDot11fIEVHTCaps));
pe_debug("Received Assoc Response with VHT Cap");
lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps);
}
if (ar.VHTOperation.present) {
qdf_mem_copy(&pAssocRsp->VHTOperation, &ar.VHTOperation,
if (ar->VHTOperation.present) {
qdf_mem_copy(&pAssocRsp->VHTOperation, &ar->VHTOperation,
sizeof(tDot11fIEVHTOperation));
pe_debug("Received Assoc Response with VHT Operation");
lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation);
}
if (ar.ExtCap.present) {
if (ar->ExtCap.present) {
struct s_ext_cap *ext_cap;
qdf_mem_copy(&pAssocRsp->ExtCap, &ar.ExtCap,
sizeof(tDot11fIEExtCap));
qdf_mem_copy(&pAssocRsp->ExtCap, &ar->ExtCap,
sizeof(tDot11fIEExtCap));
ext_cap = (struct s_ext_cap *)&pAssocRsp->ExtCap.bytes;
pe_debug("timingMeas: %d, finetimingMeas Init: %d, Resp: %d",
ext_cap->timing_meas, ext_cap->fine_time_meas_initiator,
ext_cap->fine_time_meas_responder);
}
if (ar.QosMapSet.present) {
if (ar->QosMapSet.present) {
pAssocRsp->QosMapSet.present = 1;
convert_qos_mapset_frame(pMac, &pAssocRsp->QosMapSet,
&ar.QosMapSet);
&ar->QosMapSet);
pe_debug("Received Assoc Response with Qos Map Set");
lim_log_qos_map_set(pMac, &pAssocRsp->QosMapSet);
}
pAssocRsp->vendor_vht_ie.present = ar.vendor_vht_ie.present;
if (ar.vendor_vht_ie.present) {
pAssocRsp->vendor_vht_ie.type = ar.vendor_vht_ie.type;
pAssocRsp->vendor_vht_ie.sub_type = ar.vendor_vht_ie.sub_type;
pAssocRsp->vendor_vht_ie.present = ar->vendor_vht_ie.present;
if (ar->vendor_vht_ie.present) {
pAssocRsp->vendor_vht_ie.type = ar->vendor_vht_ie.type;
pAssocRsp->vendor_vht_ie.sub_type = ar->vendor_vht_ie.sub_type;
}
if (ar.OBSSScanParameters.present) {
if (ar->OBSSScanParameters.present) {
qdf_mem_copy(&pAssocRsp->obss_scanparams,
&ar.OBSSScanParameters,
sizeof(struct sDot11fIEOBSSScanParameters));
&ar->OBSSScanParameters,
sizeof(struct sDot11fIEOBSSScanParameters));
}
if (ar.vendor_vht_ie.VHTCaps.present) {
if (ar->vendor_vht_ie.VHTCaps.present) {
qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTCaps,
&ar.vendor_vht_ie.VHTCaps,
&ar->vendor_vht_ie.VHTCaps,
sizeof(tDot11fIEVHTCaps));
pe_debug("Received Assoc Response with Vendor specific VHT Cap");
lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps);
}
if (ar.vendor_vht_ie.VHTOperation.present) {
if (ar->vendor_vht_ie.VHTOperation.present) {
qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTOperation,
&ar.vendor_vht_ie.VHTOperation,
&ar->vendor_vht_ie.VHTOperation,
sizeof(tDot11fIEVHTOperation));
pe_debug("Received Assoc Response with Vendor specific VHT Oper");
lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation);
}
if (ar.vendor_he_cap.present) {
if (ar->vendor_he_cap.present) {
pe_debug("11AX: HE cap IE present");
qdf_mem_copy(&pAssocRsp->vendor_he_cap, &ar.vendor_he_cap,
qdf_mem_copy(&pAssocRsp->vendor_he_cap, &ar->vendor_he_cap,
sizeof(tDot11fIEvendor_he_cap));
}
if (ar.vendor_he_op.present) {
if (ar->vendor_he_op.present) {
pe_debug("11AX: HE Operation IE present");
qdf_mem_copy(&pAssocRsp->vendor_he_op, &ar.vendor_he_op,
qdf_mem_copy(&pAssocRsp->vendor_he_op, &ar->vendor_he_op,
sizeof(tDot11fIEvendor_he_op));
}
if (ar.MBO_IE.present && ar.MBO_IE.rssi_assoc_rej.present) {
if (ar->MBO_IE.present && ar->MBO_IE.rssi_assoc_rej.present) {
qdf_mem_copy(&pAssocRsp->rssi_assoc_rej,
&ar.MBO_IE.rssi_assoc_rej,
&ar->MBO_IE.rssi_assoc_rej,
sizeof(tDot11fTLVrssi_assoc_rej));
pe_debug("Received Assoc Response with rssi based assoc rej");
}
fils_convert_assoc_rsp_frame2_struct(ar, pAssocRsp);
qdf_mem_free(ar);
return eSIR_SUCCESS;
} /* End sir_convert_assoc_resp_frame2_struct. */

View File

@ -1487,6 +1487,11 @@ typedef struct tagCsrRoamInfo {
uint8_t tx_mcs_map;
/* Extended capabilities of STA */
uint8_t ecsa_capable;
bool is_fils_connection;
#ifdef WLAN_FEATURE_FILS_SK
uint16_t fils_seq_num;
struct fils_join_rsp_params *fils_join_rsp;
#endif
} tCsrRoamInfo;
typedef struct tagCsrFreqScanInfo {

View File

@ -6504,6 +6504,27 @@ static void csr_roam_copy_ht_profile(tCsrRoamHTProfile *dst_profile,
}
#endif
#if defined(WLAN_FEATURE_FILS_SK)
/**
* csr_update_fils_seq_number() - Copy FILS sequence number to roam info
* @session: CSR Roam Session
* @roam_info: Roam info
*
* Return: None
*/
static void csr_update_fils_seq_number(tCsrRoamSession *session,
tCsrRoamInfo *roam_info)
{
roam_info->is_fils_connection = true;
roam_info->fils_seq_num = session->fils_seq_num;
pe_debug("FILS sequence number %x", session->fils_seq_num);
}
#else
static inline void csr_update_fils_seq_number(tCsrRoamSession *session,
tCsrRoamInfo *roam_info)
{}
#endif
/**
* csr_roam_process_results_default() - Process the result for start bss
* @mac_ctx: Global MAC Context
@ -6526,7 +6547,8 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx,
}
session = CSR_GET_SESSION(mac_ctx, session_id);
sme_debug("receives no association indication");
sme_debug("receives no association indication; FILS %d",
session->is_fils_connection);
sme_debug("Assoc ref count: %d", session->bRefAssocStartCnt);
if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile)
|| CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, session_id)) {
@ -6540,6 +6562,11 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx,
csr_set_default_dot11_mode(mac_ctx);
}
qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
/* Copy FILS sequence number used to be updated to userspace */
if (session->is_fils_connection)
csr_update_fils_seq_number(session, &roam_info);
switch (cmd->u.roamCmd.roamReason) {
/*
* If this transition is because of an 802.11 OID, then we
@ -6552,7 +6579,6 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx,
case eCsrSmeIssuedDisassocForHandoff:
csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE,
session_id);
qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss;
roam_info.pProfile = &cmd->u.roamCmd.roamProfile;
roam_info.statusCode = session->joinFailStatusCode.statusCode;
@ -6922,6 +6948,154 @@ static void csr_roam_process_start_bss_success(tpAniSirGlobal mac_ctx,
}
#ifdef WLAN_FEATURE_FILS_SK
/**
* populate_fils_params_join_rsp() - Copy FILS params from JOIN rsp
* @mac_ctx: Global MAC Context
* @roam_info: CSR Roam Info
* @join_rsp: SME Join response
*
* Copy the FILS params from the join results
*
* Return: QDF_STATUS
*/
static QDF_STATUS populate_fils_params_join_rsp(tpAniSirGlobal mac_ctx,
tCsrRoamInfo *roam_info,
tSirSmeJoinRsp *join_rsp)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct fils_join_rsp_params *roam_fils_info,
*fils_join_rsp = join_rsp->fils_join_rsp;
if (!fils_join_rsp->fils_pmk_len ||
!fils_join_rsp->fils_pmk || !fils_join_rsp->tk_len ||
!fils_join_rsp->kek_len || !fils_join_rsp->gtk_len) {
sme_err("fils join rsp err: pmk len %d tk len %d kek len %d gtk len %d",
fils_join_rsp->fils_pmk_len,
fils_join_rsp->tk_len,
fils_join_rsp->kek_len,
fils_join_rsp->gtk_len);
status = QDF_STATUS_E_FAILURE;
goto free_fils_join_rsp;
}
roam_info->fils_join_rsp = qdf_mem_malloc(sizeof(*fils_join_rsp));
if (!roam_info->fils_join_rsp) {
sme_err("fils_join_rsp malloc fails!");
status = QDF_STATUS_E_FAILURE;
goto free_fils_join_rsp;
}
roam_fils_info = roam_info->fils_join_rsp;
roam_fils_info->fils_pmk = qdf_mem_malloc(fils_join_rsp->fils_pmk_len);
if (!roam_fils_info->fils_pmk) {
qdf_mem_free(roam_info->fils_join_rsp);
roam_info->fils_join_rsp = NULL;
sme_err("fils_pmk malloc fails!");
status = QDF_STATUS_E_FAILURE;
goto free_fils_join_rsp;
}
roam_info->fils_seq_num = join_rsp->fils_seq_num;
roam_fils_info->fils_pmk_len = fils_join_rsp->fils_pmk_len;
qdf_mem_copy(roam_fils_info->fils_pmk,
fils_join_rsp->fils_pmk, roam_fils_info->fils_pmk_len);
qdf_mem_copy(roam_fils_info->fils_pmkid,
fils_join_rsp->fils_pmkid, PMKID_LEN);
roam_fils_info->kek_len = fils_join_rsp->kek_len;
qdf_mem_copy(roam_fils_info->kek,
fils_join_rsp->kek, roam_fils_info->kek_len);
roam_fils_info->tk_len = fils_join_rsp->tk_len;
qdf_mem_copy(roam_fils_info->tk,
fils_join_rsp->tk, fils_join_rsp->tk_len);
roam_fils_info->gtk_len = fils_join_rsp->gtk_len;
qdf_mem_copy(roam_fils_info->gtk,
fils_join_rsp->gtk, roam_fils_info->gtk_len);
sme_debug("FILS connect params copied to CSR!");
free_fils_join_rsp:
qdf_mem_free(fils_join_rsp->fils_pmk);
qdf_mem_free(fils_join_rsp);
return status;
}
/**
* csr_process_fils_join_rsp() - Process join rsp for FILS connection
* @mac_ctx: Global MAC Context
* @profile: CSR Roam Profile
* @session_id: Session ID
* @roam_info: CSR Roam Info
* @bss_desc: BSS description
* @join_rsp: SME Join rsp
*
* Process SME join response for FILS connection
*
* Return: None
*/
static void csr_process_fils_join_rsp(tpAniSirGlobal mac_ctx,
tCsrRoamProfile *profile,
uint32_t session_id,
tCsrRoamInfo *roam_info,
tSirBssDescription *bss_desc,
tSirSmeJoinRsp *join_rsp)
{
tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
QDF_STATUS status;
if (!join_rsp || !join_rsp->fils_join_rsp) {
sme_err("Join rsp doesn't have FILS info");
goto process_fils_join_rsp_fail;
}
/* Copy FILS params */
status = populate_fils_params_join_rsp(mac_ctx, roam_info, join_rsp);
if (!QDF_IS_STATUS_SUCCESS(status)) {
sme_err("Copy FILS params join rsp fails");
goto process_fils_join_rsp_fail;
}
status = csr_roam_issue_set_context_req(mac_ctx, session_id,
profile->negotiatedMCEncryptionType,
bss_desc, &bcast_mac, true, false,
eSIR_RX_ONLY, 2,
roam_info->fils_join_rsp->gtk_len,
roam_info->fils_join_rsp->gtk, 0);
if (!QDF_IS_STATUS_SUCCESS(status)) {
sme_err("Set context for bcast fail");
goto process_fils_join_rsp_fail;
}
status = csr_roam_issue_set_context_req(mac_ctx, session_id,
profile->negotiatedUCEncryptionType,
bss_desc, &(bss_desc->bssId), true,
true, eSIR_TX_RX, 0,
roam_info->fils_join_rsp->tk_len,
roam_info->fils_join_rsp->tk, 0);
if (!QDF_IS_STATUS_SUCCESS(status)) {
sme_err("Set context for unicast fail");
goto process_fils_join_rsp_fail;
}
return;
process_fils_join_rsp_fail:
csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, session_id);
}
#else
static inline void csr_process_fils_join_rsp(tpAniSirGlobal mac_ctx,
tCsrRoamProfile *profile,
uint32_t session_id,
tCsrRoamInfo *roam_info,
tSirBssDescription *bss_desc,
tSirSmeJoinRsp *join_rsp)
{}
#endif
/**
* csr_roam_process_join_res() - Process the Join results
* @mac_ctx: Global MAC Context
@ -7097,6 +7271,11 @@ static void csr_roam_process_join_res(tpAniSirGlobal mac_ctx,
profile->negotiatedMCEncryptionType,
bss_desc, &bcast_mac, false, false,
eSIR_TX_RX, 0, 0, NULL, 0);
} else if (CSR_IS_AUTH_TYPE_FILS(profile->negotiatedAuthType)
&& join_rsp->is_fils_connection) {
roam_info.is_fils_connection = true;
csr_process_fils_join_rsp(mac_ctx, profile, session_id,
&roam_info, bss_desc, join_rsp);
} else {
/* Need to wait for supplicant authtication */
roam_info.fAuthRequired = true;
@ -7468,6 +7647,7 @@ static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd,
break;
case eCsrStopBssSuccess:
if (CSR_IS_NDI(profile)) {
qdf_mem_set(&roam_info, sizeof(roam_info), 0);
csr_roam_update_ndp_return_params(mac_ctx, res,
&roam_status, &roam_result, &roam_info);
csr_roam_call_callback(mac_ctx, session_id, &roam_info,
@ -7477,6 +7657,7 @@ static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd,
break;
case eCsrStopBssFailure:
if (CSR_IS_NDI(profile)) {
qdf_mem_set(&roam_info, sizeof(roam_info), 0);
csr_roam_update_ndp_return_params(mac_ctx, res,
&roam_status, &roam_result, &roam_info);
csr_roam_call_callback(mac_ctx, session_id, &roam_info,
@ -8873,6 +9054,11 @@ static void csr_roam_join_rsp_processor(tpAniSirGlobal pMac,
if (pEntry)
pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
sme_debug("is_fils_connection %d", pSmeJoinRsp->is_fils_connection);
/* Copy Sequence Number last used for FILS assoc failure case */
if (session_ptr->is_fils_connection)
session_ptr->fils_seq_num = pSmeJoinRsp->fils_seq_num;
if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) {
if (pCommand
&& eCsrSmeIssuedAssocToSimilarAP ==

View File

@ -181,6 +181,12 @@ typedef struct {
#define CSR_IS_ENC_TYPE_STATIC(encType) ((eCSR_ENCRYPT_TYPE_NONE == (encType)) || \
(eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == (encType)) || \
(eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == (encType)))
#define CSR_IS_AUTH_TYPE_FILS(auth_type) \
((eCSR_AUTH_TYPE_FILS_SHA256 == auth_type) || \
(eCSR_AUTH_TYPE_FILS_SHA384 == auth_type) || \
(eCSR_AUTH_TYPE_FT_FILS_SHA256 == auth_type) || \
(eCSR_AUTH_TYPE_FT_FILS_SHA384 == auth_type))
#define CSR_IS_WAIT_FOR_KEY(pMac, sessionId) \
(CSR_IS_ROAM_JOINED(pMac, sessionId) && \
CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId))