From 0d5d2c745c129e53f47cf739ae13d6abb44919a0 Mon Sep 17 00:00:00 2001 From: Sridhar Selvaraj Date: Thu, 17 Aug 2017 17:30:01 +0530 Subject: [PATCH] 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 --- core/hdd/src/wlan_hdd_assoc.c | 4 +- core/hdd/src/wlan_hdd_main.c | 180 +++++- core/mac/inc/sir_api.h | 19 + core/mac/src/include/parser_api.h | 27 + core/mac/src/pe/include/lim_fils_defs.h | 15 + core/mac/src/pe/include/lim_process_fils.h | 113 ++++ core/mac/src/pe/include/lim_session.h | 9 + core/mac/src/pe/lim/lim_assoc_utils.c | 19 +- .../src/pe/lim/lim_process_assoc_rsp_frame.c | 21 +- core/mac/src/pe/lim/lim_process_fils.c | 551 ++++++++++++++++++ .../src/pe/lim/lim_process_mlm_rsp_messages.c | 2 +- .../src/pe/lim/lim_send_management_frames.c | 34 +- .../src/pe/lim/lim_send_sme_rsp_messages.c | 25 + core/mac/src/pe/lim/lim_session.c | 2 +- core/mac/src/pe/lim/lim_utils.c | 19 + core/mac/src/pe/lim/lim_utils.h | 15 + .../src/sys/legacy/src/utils/src/parser_api.c | 345 +++++++---- core/sme/inc/csr_api.h | 5 + core/sme/src/csr/csr_api_roam.c | 190 +++++- core/sme/src/csr/csr_inside_api.h | 6 + 20 files changed, 1470 insertions(+), 131 deletions(-) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 681769102467..790808dbfa8c 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -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, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 62a6c51ad400..c0c5921c4df1 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -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); diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 548d95e51e9f..840cec0cc75b 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -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; diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h index 25f92003b8f6..70e548a64e9f 100644 --- a/core/mac/src/include/parser_api.h +++ b/core/mac/src/include/parser_api.h @@ -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, diff --git a/core/mac/src/pe/include/lim_fils_defs.h b/core/mac/src/pe/include/lim_fils_defs.h index c3619cbdb456..7e0286dfdd86 100644 --- a/core/mac/src/pe/include/lim_fils_defs.h +++ b/core/mac/src/pe/include/lim_fils_defs.h @@ -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 diff --git a/core/mac/src/pe/include/lim_process_fils.h b/core/mac/src/pe/include/lim_process_fils.h index 5070bb25896f..a214f9297699 100644 --- a/core/mac/src/pe/include/lim_process_fils.h +++ b/core/mac/src/pe/include/lim_process_fils.h @@ -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 diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h index cb0de7b3c3a2..54cbe04b9422 100644 --- a/core/mac/src/pe/include/lim_session.h +++ b/core/mac/src/pe/include/lim_session.h @@ -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 ) */ diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c index f33dd7b467c0..4b58c2211e56 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.c +++ b/core/mac/src/pe/lim/lim_assoc_utils.c @@ -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) { diff --git a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c index f9d6fe6730aa..2bdcea069720 100644 --- a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c +++ b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c @@ -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 diff --git a/core/mac/src/pe/lim/lim_process_fils.c b/core/mac/src/pe/lim/lim_process_fils.c index 79e8df36ac4b..01b49fbaa4ed 100644 --- a/core/mac/src/pe/lim/lim_process_fils.c +++ b/core/mac/src/pe/lim/lim_process_fils.c @@ -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 diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c index 274c3d90beee..361d7876d842 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -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); } diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c index f9cbf7a239df..889a561c994a 100644 --- a/core/mac/src/pe/lim/lim_send_management_frames.c +++ b/core/mac/src/pe/lim/lim_send_management_frames.c @@ -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 @@ -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), diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c index 330974a15876..67728c641f4a 100644 --- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -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; diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c index 747981c88908..09d88ed14092 100644 --- a/core/mac/src/pe/lim/lim_session.c +++ b/core/mac/src/pe/lim/lim_session.c @@ -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; diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c index ba386119c2de..79087d7b1c55 100644 --- a/core/mac/src/pe/lim/lim_utils.c +++ b/core/mac/src/pe/lim/lim_utils.c @@ -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; +} diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index 9736827692b7..d4630b0f7cd7 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -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 */ diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c index ae1fea99c191..b376bbe51517 100644 --- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c +++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -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. */ diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index f361c58e4026..630db794ad4f 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -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 { diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 3d8e91c56017..112fb0099c47 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -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 == diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h index 3090375a4c8d..afc24279a41a 100644 --- a/core/sme/src/csr/csr_inside_api.h +++ b/core/sme/src/csr/csr_inside_api.h @@ -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))