diff --git a/Kbuild b/Kbuild index 16831f50af24..be748a8d011a 100644 --- a/Kbuild +++ b/Kbuild @@ -109,6 +109,8 @@ ifeq ($(KERNEL_BUILD), 0) #Flag to enable Fast Transition (11r) feature CONFIG_QCOM_VOWIFI_11R := y + #Flag to enable FILS Feature (11ai) + CONFIG_WLAN_FEATURE_FILS := y ifneq ($(CONFIG_QCA_CLD_WLAN),) ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2) $(CONFIG_ICNSS))) #Flag to enable Protected Managment Frames (11w) feature @@ -596,6 +598,10 @@ ifeq ($(CONFIG_QCOM_TDLS),y) MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_tdls.o endif +ifeq ($(CONFIG_WLAN_FEATURE_FILS),y) +MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_fils.o +endif + ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y) MAC_NDP_OBJS += $(MAC_SRC_DIR)/pe/nan/nan_datapath.o endif @@ -792,6 +798,7 @@ QDF_OBJS := $(QDF_OBJ_DIR)/qdf_defer.o \ $(QDF_OBJ_DIR)/qdf_mem.o \ $(QDF_OBJ_DIR)/qdf_nbuf.o \ $(QDF_OBJ_DIR)/qdf_threads.o \ + $(QDF_OBJ_DIR)/qdf_crypto.o \ $(QDF_OBJ_DIR)/qdf_trace.o ifeq ($(CONFIG_WLAN_DEBUGFS), y) @@ -1624,6 +1631,10 @@ ifneq ($(CONFIG_HIF_USB), 1) CDEFINES += -DWLAN_LOGGING_SOCK_SVC_ENABLE endif +ifeq ($(CONFIG_WLAN_FEATURE_FILS),y) +CDEFINES += -DWLAN_FEATURE_FILS_SK +endif + ifeq ($(CONFIG_CNSS), y) ifeq ($(CONFIG_CNSS_SDIO), y) CDEFINES += -DCONFIG_PLD_SDIO_CNSS diff --git a/core/cds/inc/cds_config.h b/core/cds/inc/cds_config.h index 8e4f47f03def..a52158f554e5 100644 --- a/core/cds/inc/cds_config.h +++ b/core/cds/inc/cds_config.h @@ -164,4 +164,27 @@ struct cds_config_info { bool auto_power_save_fail_mode; uint8_t ito_repeat_count; }; + +#ifdef WLAN_FEATURE_FILS_SK +#define MAX_PMK_LEN 48 +#define FILS_MAX_KEYNAME_NAI_LENGTH 255 +#define FILS_MAX_REALM_LEN 255 +#define FILS_MAX_RRK_LENGTH 64 + +struct cds_fils_connection_info { + bool is_fils_connection; + uint8_t keyname_nai[FILS_MAX_KEYNAME_NAI_LENGTH]; + uint32_t key_nai_length; + uint16_t sequence_number; + uint8_t r_rk[FILS_MAX_RRK_LENGTH]; + uint32_t r_rk_length; + uint8_t realm[FILS_MAX_REALM_LEN]; + uint32_t realm_len; + uint8_t akm_type; + uint8_t auth_type; + uint8_t pmk[MAX_PMK_LEN]; + uint8_t pmk_len; + uint8_t pmkid[16]; +}; +#endif #endif /* !defined( __CDS_CONFIG_H ) */ diff --git a/core/cds/inc/cds_utils.h b/core/cds/inc/cds_utils.h index cb3f6f427025..fe9ba8c8f0ad 100644 --- a/core/cds/inc/cds_utils.h +++ b/core/cds/inc/cds_utils.h @@ -126,6 +126,15 @@ QDF_STATUS cds_rand_get_bytes(uint32_t handle, uint8_t *pbBuf, uint32_t cds_chan_to_freq(uint8_t chan); uint8_t cds_freq_to_chan(uint32_t freq); enum cds_band_type cds_chan_to_band(uint32_t chan); + +/** + * cds_upper_to_lower: API to convert upper case string into lower case + * @txt: input text + * @length: length of input string + * + * Return: None + */ +void cds_upper_to_lower(uint8_t *txt, uint32_t length); #ifdef WLAN_FEATURE_11W bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn, uint8_t *frm, uint8_t *efrm); diff --git a/core/cds/src/cds_utils.c b/core/cds/src/cds_utils.c index 8eaa2f501d4a..3350a31a16f2 100644 --- a/core/cds/src/cds_utils.c +++ b/core/cds/src/cds_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -597,6 +597,16 @@ uint8_t cds_freq_to_chan(uint32_t freq) return chan; } +void cds_upper_to_lower(uint8_t *txt, uint32_t length) +{ + int i; + + for (i = 0; i < length; i++) { + if (txt[i] >= 'A' && txt[i] <= 'Z') + txt[i] = txt[i] + 32; + } +} + enum cds_band_type cds_chan_to_band(uint32_t chan) { if (chan <= CDS_24_GHZ_CHANNEL_14) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index caca6e493537..ad5cbb27d798 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2637,4 +2637,17 @@ void hdd_update_ie_whitelist_attr(struct probe_req_whitelist_attr *ie_whitelist, int hdd_get_rssi_snr_by_bssid(hdd_adapter_t *adapter, const uint8_t *bssid, int8_t *rssi, int8_t *snr); +#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) +/** + * hdd_clear_fils_connection_info: API to clear fils info from roam profile and + * free allocated memory + * @adapter: pointer to hdd adapter + * + * Return: None + */ +void hdd_clear_fils_connection_info(hdd_adapter_t *adapter); +#else +static inline void hdd_clear_fils_connection_info(hdd_adapter_t *adapter) +{ } +#endif #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 26c85c833092..b2ba1ae089f0 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -2485,6 +2485,23 @@ void hdd_perform_roam_set_key_complete(hdd_adapter_t *pAdapter) pHddStaCtx->roam_info.deferKeyComplete = false; } +#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) +void hdd_clear_fils_connection_info(hdd_adapter_t *adapter) +{ + hdd_wext_state_t *wext_state; + + if ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) + return; + + wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + if (wext_state->roamProfile.fils_con_info) { + qdf_mem_free(wext_state->roamProfile.fils_con_info); + wext_state->roamProfile.fils_con_info = NULL; + } +} +#endif + /** * hdd_association_completion_handler() - association completion handler * @pAdapter: pointer to adapter @@ -5426,6 +5443,28 @@ hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]) return cipher_type; } +#ifdef WLAN_FEATURE_FILS_SK +/* + * hdd_is_fils_connection: API to determine if connection is FILS + * @adapter: hdd adapter + * + * Return: true if fils connection else false + */ +static inline bool hdd_is_fils_connection(hdd_adapter_t *adapter) +{ + hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + + if (wext_state->roamProfile.fils_con_info) + return wext_state->roamProfile. + fils_con_info->is_fils_connection; +} +#else +static inline bool hdd_is_fils_connection(hdd_adapter_t *adapter) +{ + return false; +} +#endif + /** * hdd_process_genie() - process gen ie * @pAdapter: pointer to adapter @@ -5617,23 +5656,33 @@ int hdd_set_genie_to_csr(hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType) #ifdef WLAN_FEATURE_FILS_SK /** - * hdd_is_rsn_is_fils() - This API checks whether a give auth type is FILS + * hdd_check_fils_rsn_n_set_auth_type() - This API checks whether a give + * auth type is fils if yes, sets it in profile. * @rsn_auth_type: auth type * * Return: true if FILS auth else false */ -static bool hdd_is_rsn_is_fils(eCsrAuthType rsn_auth_type) +static bool hdd_check_fils_rsn_n_set_auth_type(tCsrRoamProfile *roam_profile, + eCsrAuthType rsn_auth_type) { + bool is_fils_rsn = false; + + if (!roam_profile->fils_con_info) + return false; + if ((rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA256) || (rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA384) || (rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA256) || (rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA384)) - return true; + is_fils_rsn = true; + if (is_fils_rsn) + roam_profile->fils_con_info->akm_type = rsn_auth_type; - return false; + return is_fils_rsn; } #else -static inline bool hdd_is_rsn_is_fils(eCsrAuthType rsn_auth_type) +static bool hdd_check_fils_rsn_n_set_auth_type(tCsrRoamProfile *roam_profile, + eCsrAuthType rsn_auth_type) { return false; } @@ -5736,10 +5785,13 @@ int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType) eCSR_AUTH_TYPE_RSN_8021X_SHA256; } else #endif - if (hdd_is_rsn_is_fils(RSNAuthType)) { - hdd_info("updated fils auth"); + if (hdd_check_fils_rsn_n_set_auth_type(pRoamProfile, + RSNAuthType)) { pRoamProfile->AuthType.authType[0] = RSNAuthType; + hdd_info("updated profile authtype as %d", + RSNAuthType); + } else if ((pWextState-> authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) == IW_AUTH_KEY_MGMT_802_1X) { diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index f63ab784eb3d..3ef2861b86c1 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1759,7 +1759,7 @@ static int hdd_update_reg_chan_info(hdd_adapter_t *adapter, if (icv->flags & IEEE80211_CHAN_PASSIVE) icv->flagext |= IEEE80211_CHAN_DFS; - hdd_info("freq %d flags %d flagext %d ieee %d maxreg %d maxpw %d minpw %d regClass %d antenna %d seg0 %d seg1 %d", + hdd_debug("freq %d flags %d flagext %d ieee %d maxreg %d maxpw %d minpw %d regClass %d antenna %d seg0 %d seg1 %d", icv->freq, icv->flags, icv->flagext, icv->ieee_chan_number, icv->max_reg_power, icv->max_radio_power, @@ -11688,6 +11688,17 @@ static void wlan_hdd_cfg80211_scan_randomization_init(struct wiphy *wiphy) #endif #define WLAN_HDD_MAX_NUM_CSA_COUNTERS 2 +#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) +static void wlan_hdd_cfg80211_set_wiphy_fils_feature(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD); +} +#else +static void wlan_hdd_cfg80211_set_wiphy_fils_feature(struct wiphy *wiphy) +{ +} +#endif + /* * FUNCTION: wlan_hdd_cfg80211_init * This function is called by hdd_wlan_startup() @@ -11741,6 +11752,7 @@ int wlan_hdd_cfg80211_init(struct device *dev, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); #endif + wlan_hdd_cfg80211_set_wiphy_fils_feature(wiphy); hdd_config_sched_scan_plans_to_wiphy(wiphy, pCfg); @@ -14978,7 +14990,12 @@ static int wlan_hdd_cfg80211_set_auth_type(hdd_adapter_t *pAdapter, pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_CCKM_WPA; break; #endif - +#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) + case NL80211_AUTHTYPE_FILS_SK: + hdd_notice("set authentication type to FILS SHARED"); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; +#endif default: hdd_err("Unsupported authentication type: %d", auth_type); pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_UNKNOWN; @@ -14990,6 +15007,36 @@ static int wlan_hdd_cfg80211_set_auth_type(hdd_adapter_t *pAdapter, return 0; } +#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) +/** + * hdd_validate_fils_info_ptr() - check fils info for FILS AKMs + * @wext_state: wext state pointer + * @fils_akm_check: boolean to update whether + * fils info is present or not + * + * Return: None + */ +static void hdd_validate_fils_info_ptr(hdd_wext_state_t *wext_state, + bool *fils_akm_check) +{ + struct cds_fils_connection_info *fils_con_info; + + fils_con_info = wext_state->roamProfile.fils_con_info; + if (!fils_con_info) { + hdd_debug("No valid Roam profile"); + *fils_akm_check = false; + } + + *fils_akm_check = true; +} +#else +static void hdd_validate_fils_info_ptr(hdd_wext_state_t *wext_state, + bool *fils_akm_check) +{ + *fils_akm_check = true; +} +#endif + /** * wlan_hdd_set_akm_suite() - set key management type * @pAdapter: Pointer to adapter @@ -15002,6 +15049,11 @@ static int wlan_hdd_cfg80211_set_auth_type(hdd_adapter_t *pAdapter, static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt) { hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *roam_profile; + bool fils_akm_check; + + roam_profile = &pWextState->roamProfile; + hdd_validate_fils_info_ptr(pWextState, &fils_akm_check); #ifndef WLAN_AKM_SUITE_8021X_SHA256 #define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05 @@ -15041,10 +15093,39 @@ static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt) break; #ifdef WLAN_FEATURE_FILS_SK case WLAN_AKM_SUITE_FILS_SHA256: - case WLAN_AKM_SUITE_FILS_SHA384: - case WLAN_AKM_SUITE_FT_FILS_SHA256: - case WLAN_AKM_SUITE_FT_FILS_SHA384: + if (!fils_akm_check) + return -EINVAL; + + hdd_debug("setting key mgmt type to FILS SHA256"); pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FILS_SHA256; + break; + + case WLAN_AKM_SUITE_FILS_SHA384: + if (!fils_akm_check) + return -EINVAL; + hdd_debug("setting key mgmt type to FILS SH384"); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FILS_SHA384; + break; + + case WLAN_AKM_SUITE_FT_FILS_SHA256: + if (!fils_akm_check) + return -EINVAL; + hdd_debug("setting key mgmt type to FILS FT SH256"); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FT_FILS_SHA256; + break; + + case WLAN_AKM_SUITE_FT_FILS_SHA384: + if (!fils_akm_check) + return -EINVAL; + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FT_FILS_SHA384; break; #endif default: @@ -15520,6 +15601,115 @@ static bool hdd_is_wpaie_present(const uint8_t *ie, uint8_t ie_len) return false; } +#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) +/** + * wlan_hdd_get_fils_auth_type() - API to get FILS auth type + * @auth: enum of auth type + * + * This API converts nl80211 FILS auth type to driver specific + * auth type enum + * + * Return: FILS auth type + */ +static int wlan_hdd_get_fils_auth_type(enum nl80211_auth_type auth) +{ + switch (auth) { + case NL80211_AUTHTYPE_FILS_SK: + return eSIR_FILS_SK_WITHOUT_PFS; + case NL80211_AUTHTYPE_FILS_SK_PFS: + return eSIR_FILS_SK_WITH_PFS; + case NL80211_AUTHTYPE_FILS_PK: + return eSIR_FILS_PK_AUTH; + default: + return -EINVAL; + } +} + +/** + * wlan_hdd_cfg80211_set_fils_config() - set fils config params during connect + * @adapter: Pointer to adapter + * @req: Pointer to fils parameters + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_fils_config(hdd_adapter_t *adapter, + struct cfg80211_connect_params *req) +{ + hdd_wext_state_t *wext_state; + tCsrRoamProfile *roam_profile; + int auth_type; + uint8_t *buf; + + wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + roam_profile = &wext_state->roamProfile; + + hdd_clear_fils_connection_info(adapter); + roam_profile->fils_con_info = + qdf_mem_malloc(sizeof(struct cds_fils_connection_info)); + + if (!roam_profile->fils_con_info) { + hdd_err("failed to allocate memory"); + return -EINVAL; + } + + if (req->auth_type != NL80211_AUTHTYPE_FILS_SK) { + roam_profile->fils_con_info->is_fils_connection = false; + return 0; + } + + roam_profile->fils_con_info->is_fils_connection = true; + roam_profile->fils_con_info->sequence_number = + req->fils_erp_next_seq_num; + auth_type = wlan_hdd_get_fils_auth_type(req->auth_type); + if (auth_type < 0) { + hdd_err("invalid auth type for fils %d", req->auth_type); + return -EINVAL; + } + roam_profile->fils_con_info->auth_type = auth_type; + + roam_profile->fils_con_info->r_rk_length = + req->fils_erp_rrk_len; + if (req->fils_erp_rrk_len) + qdf_mem_copy(roam_profile->fils_con_info->r_rk, + req->fils_erp_rrk, + roam_profile->fils_con_info->r_rk_length); + + roam_profile->fils_con_info->realm_len = req->fils_erp_realm_len; + if (req->fils_erp_realm_len) + qdf_mem_copy(roam_profile->fils_con_info->realm, + req->fils_erp_realm, + roam_profile->fils_con_info->realm_len); + + roam_profile->fils_con_info->key_nai_length = + req->fils_erp_username_len + sizeof(char) + + req->fils_erp_realm_len; + if (req->fils_erp_username_len) { + buf = roam_profile->fils_con_info->keyname_nai; + qdf_mem_copy(buf, + req->fils_erp_username, + req->fils_erp_username_len); + buf += req->fils_erp_username_len; + qdf_mem_copy(buf, "@", sizeof(char)); + buf += sizeof(char); + qdf_mem_copy(buf, req->fils_erp_realm, + req->fils_erp_realm_len); + } + hdd_debug("fils connection seq=%d auth=%d user_len=%zu rrk_len=%zu realm_len=%zu keyname nai len %d\n", + req->fils_erp_next_seq_num, req->auth_type, + req->fils_erp_username_len, req->fils_erp_rrk_len, + req->fils_erp_realm_len, + roam_profile->fils_con_info->key_nai_length); + + return 0; +} +#else +static int wlan_hdd_cfg80211_set_fils_config(hdd_adapter_t *adapter, + struct cfg80211_connect_params *req) +{ + return 0; +} +#endif + /** * wlan_hdd_cfg80211_set_privacy() - set security parameters during connection * @pAdapter: Pointer to adapter @@ -15550,6 +15740,9 @@ static int wlan_hdd_cfg80211_set_privacy(hdd_adapter_t *pAdapter, /*set authentication type */ status = wlan_hdd_cfg80211_set_auth_type(pAdapter, req->auth_type); + /* Parase extra info from connect request */ + status = wlan_hdd_cfg80211_set_fils_config(pAdapter, req); + if (0 > status) { hdd_err("Failed to set authentication type"); return status; @@ -17309,7 +17502,7 @@ static void hdd_fill_pmksa_info(tPmkidCacheInfo *pmk_cache, qdf_mem_copy(pmk_cache->pmk, pmksa->pmk, pmksa->pmk_len); pmk_cache->pmk_len = pmksa->pmk_len; } else - hdd_info("pmk len is %zu", pmksa->pmk_len); + hdd_debug("pmk len is %zu", pmksa->pmk_len); } #else /* diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 3a656db43c6b..4610744af8a7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -89,6 +89,28 @@ #define BASIC_RATE_MASK 0x80 #define RATE_MASK 0x7f +#ifndef NL80211_AUTHTYPE_FILS_SK +#define NL80211_AUTHTYPE_FILS_SK 5 +#endif +#ifndef NL80211_AUTHTYPE_FILS_SK_PFS +#define NL80211_AUTHTYPE_FILS_SK_PFS 6 +#endif +#ifndef NL80211_AUTHTYPE_FILS_PK +#define NL80211_AUTHTYPE_FILS_PK 7 +#endif +#ifndef WLAN_AKM_SUITE_FILS_SHA256 +#define WLAN_AKM_SUITE_FILS_SHA256 0x000FAC0E +#endif +#ifndef WLAN_AKM_SUITE_FILS_SHA384 +#define WLAN_AKM_SUITE_FILS_SHA384 0x000FAC0F +#endif +#ifndef WLAN_AKM_SUITE_FT_FILS_SHA256 +#define WLAN_AKM_SUITE_FT_FILS_SHA256 0x000FAC10 +#endif +#ifndef WLAN_AKM_SUITE_FT_FILS_SHA384 +#define WLAN_AKM_SUITE_FT_FILS_SHA384 0x000FAC11 +#endif + #ifdef FEATURE_WLAN_TDLS #define WLAN_IS_TDLS_SETUP_ACTION(action) \ ((SIR_MAC_TDLS_SETUP_REQ <= action) && \ diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index e32b203d545a..7d5d683cf14b 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4277,6 +4277,7 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, wlan_hdd_scan_abort(adapter); wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + hdd_clear_fils_connection_info(adapter); #ifdef WLAN_OPEN_SOURCE cancel_work_sync(&adapter->ipv4NotifierWorkQueue); @@ -4496,6 +4497,7 @@ QDF_STATUS hdd_reset_all_adapters(hdd_context_t *hdd_ctx) clear_bit(WMM_INIT_DONE, &adapter->event_flags); } + hdd_clear_fils_connection_info(adapter); if (adapter->device_mode == QDF_SAP_MODE) { /* * If adapter is SAP, set session ID to invalid diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index e4b17ad9a3be..07e59f5a824f 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -14248,6 +14248,16 @@ static int hdd_set_wext(hdd_adapter_t *pAdapter) } +#ifdef WLAN_FEATURE_FILS_SK +static void hdd_initialize_fils_info(hdd_wext_state_t *pwextBuf) +{ + pwextBuf->roamProfile.fils_con_info = NULL; +} +#else +static void hdd_initialize_fils_info(hdd_wext_state_t *pwextBuf) +{ } +#endif + /** * hdd_register_wext() - register wext context * @dev: net device handle @@ -14285,6 +14295,7 @@ int hdd_register_wext(struct net_device *dev) return QDF_STATUS_E_FAILURE; } + hdd_initialize_fils_info(pwextBuf); /* Register as a wireless device */ dev->wireless_handlers = (struct iw_handler_def *)&we_handler_def; diff --git a/core/mac/inc/ani_system_defs.h b/core/mac/inc/ani_system_defs.h index 7cc076f7ad6e..99fd5eeb63d1 100644 --- a/core/mac/inc/ani_system_defs.h +++ b/core/mac/inc/ani_system_defs.h @@ -72,6 +72,9 @@ typedef enum eAniAuthType { eSIR_LEAP_AUTH = 0x80, #endif eSIR_AUTO_SWITCH, + eSIR_FILS_SK_WITHOUT_PFS = 4, + eSIR_FILS_SK_WITH_PFS = 5, + eSIR_FILS_PK_AUTH = 6, eSIR_DONOT_USE_AUTH_TYPE = SIR_MAX_ENUM_SIZE } tAniAuthType; diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 763e1c99134c..548d95e51e9f 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -67,6 +67,8 @@ typedef struct sAniSirGlobal *tpAniSirGlobal; #define SIR_MDIE_ELEMENT_ID 54 #define SIR_MDIE_SIZE 3 /* MD ID(2 bytes), Capability(1 byte) */ +#define SIR_MAX_ELEMENT_ID 255 + /* Increase dwell time for P2P search in ms */ #define P2P_SEARCH_DWELL_TIME_INCREASE 20 #define P2P_SOCIAL_CHANNELS 3 @@ -1226,6 +1228,10 @@ typedef struct sSirSmeJoinReq { tSirMacPowerCapInfo powerCap; tSirSupChnl supportedChannels; bool enable_bcast_probe_rsp; +#ifdef WLAN_FEATURE_FILS_SK + struct cds_fils_connection_info fils_con_info; +#endif + /* Pls make this as last variable in struct */ tSirBssDescription bssDescription; /* * WARNING: Pls make bssDescription as last variable in struct diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h index 6436de3e960a..50ecb791582f 100644 --- a/core/mac/inc/sir_mac_prot_def.h +++ b/core/mac/inc/sir_mac_prot_def.h @@ -39,6 +39,7 @@ #include "cds_api.h" #include "sir_types.h" #include "wni_cfg.h" +#include /* /Capability information related */ #define CAPABILITY_INFO_DELAYED_BA_BIT 14 @@ -1955,6 +1956,14 @@ typedef struct sSirMacAuthFrameBody { uint8_t type; /* = SIR_MAC_CHALLENGE_TEXT_EID */ uint8_t length; /* = SIR_MAC_AUTH_CHALLENGE_LENGTH */ uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; +#ifdef WLAN_FEATURE_FILS_SK + tSirMacRsnInfo rsn_ie; + uint8_t assoc_delay_info; + uint8_t session[SIR_FILS_SESSION_LENGTH]; + uint8_t wrapped_data_len; + uint8_t wrapped_data[SIR_FILS_WRAPPED_DATA_MAX_SIZE]; + uint8_t nonce[SIR_FILS_NONCE_LENGTH]; +#endif } qdf_packed tSirMacAuthFrameBody, *tpSirMacAuthFrameBody; typedef struct sSirMacAuthenticationFrame { diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h index a5762b4065db..25f92003b8f6 100644 --- a/core/mac/src/include/parser_api.h +++ b/core/mac/src/include/parser_api.h @@ -115,7 +115,7 @@ typedef struct sSirQCNIE { #define SIR_HESSID_LEN 6 #define SIR_MAX_KEY_CNT 7 #define SIR_MAX_KEY_LEN 48 - +#define SIR_FILS_IND_ELEM_OFFSET 2 /* * struct public_key_identifier: structure for public key identifier * present in fils indication element diff --git a/core/mac/src/pe/include/lim_fils_defs.h b/core/mac/src/pe/include/lim_fils_defs.h new file mode 100644 index 000000000000..c3619cbdb456 --- /dev/null +++ b/core/mac/src/pe/include/lim_fils_defs.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#define FILS_EAP_TLV_MAX_DATA_LEN 255 +#define FILS_SHA256_128_AUTH_TAG 16 +#define FILS_SHA256_256_AUTH_TAG 32 + +#define FILS_SHA256_CRYPTO_TYPE "hmac(sha256)" +#define FILS_SHA384_CRYPTO_TYPE "hmac(sha384)" + +/* RFC 6696 */ +#define RMSK_LABEL "Re-authentication Master Session Key@ietf.org" + +/* 12.12.2.5.3 80211-ai draft */ +#define PTK_KEY_LABEL "FILS PTK Derivation" +#define MAX_ICK_LEN 48 +#define MAX_KEK_LEN 64 +#define MAX_TK_LEN 32 +#define MAX_KEY_AUTH_DATA_LEN 48 +#define MAX_GTK_LEN 255 +#define MAX_IGTK_LEN 255 + +#define IPN_LEN 6 +#define FILS_SESSION_LENGTH 8 +#define FILS_MAX_KDE_LIST_LEN 255 + +/* 12.12.2.5.3 80211-ai draft */ +#define FILS_SHA384_KEK_LEN 64 +#define FILS_SHA256_KEK_LEN 32 + +/* 12.12.2.5.3 80211-ai draft */ +#define FILS_SHA256_ICK_LEN 32 +#define FILS_SHA384_ICK_LEN 48 + +#define TK_LEN_TKIP 32 +#define TK_LEN_CCMP 16 +#define TK_LEN_AES_128_CMAC 32 + +#define FILS_SHA256_PKM_LEN 32 +#define FILS_SHA384_PKM_LEN 48 + +#define PMKID_LEN 16 + +#define MAX_PRF_INTERATIONS_COUNT 255 + +/* 9.4.2.180 FILS Session element */ +#define SIR_FILS_SESSION_LENGTH 8 +#define SIR_FILS_SESSION_EXT_EID 4 + +/* 9.4.2.190 FILS Nonce element */ +#define SIR_FILS_NONCE_LENGTH 16 +#define SIR_FILS_NONCE_EXT_EID 13 + +/*9.4.2.188 FILS Wrapped Data element */ +#define SIR_FILS_WRAPPED_DATA_MAX_SIZE 255 +#define SIR_FILS_WRAPPED_DATA_EXT_EID 8 + +#define MAX_IE_LENGTH 255 + +/* RFC 6696 5.3.1: EAP-Initiate/Re-auth-Start Packet */ +#define SIR_FILS_EAP_REAUTH_PACKET_TYPE 1 +#define SIR_FILS_EAP_INIT_PACKET_TYPE 2 + +#define FILS_AUTH_TAG_MAX_LENGTH 32 + +#define SIR_FILS_OPTIONAL_DATA_LEN 3 +/* RFC 6696 4.3: RiK deriavtion */ +#define SIR_FILS_RIK_LABEL "Re-authentication Integrity Key@ietf.org" + +/* RFC 6696 5.3.1: EAP-Initiate/Re-auth-Start Packet */ +#define SIR_FILS_EAP_TLV_KEYNAME_NAI 1 +#define SIR_FILS_EAP_TLV_R_RK_LIFETIME 2 +#define SIR_FILS_EAP_TLV_R_MSK_LIFETIME 3 +#define SIR_FILS_EAP_TLV_DOMAIN_NAME 4 +#define SIR_FILS_EAP_TLV_CRYPTO_LIST 5 +#define SIR_FILS_EAP_TLV_AUTH_INDICATION 6 + +/* + * struct eap_auth_reserved: this structure defines flags format in eap packets + * as defined in RFC 6696 5.3.1 + * flag_r: + * flag_b: + * flag_l: + */ +struct eap_auth_reserved { + uint8_t flag_r:1; + uint8_t flag_b:1; + uint8_t flag_l:1; + uint8_t reverved:5; +}; + +/* + * enum fils_erp_cryptosuite: this enum defines the cryptosuites used + * to calculate auth tag and auth tag length as defined by RFC 6696 5.3.1 + * @HMAC_SHA256_64: sha256 with auth tag len as 64 bits + * @HMAC_SHA256_128: sha256 with auth tag len as 128 bits + * @HMAC_SHA256_256: sha256 with auth tag len as 256 bits + */ +enum fils_erp_cryptosuite { + INVALID_CRYPTO = 0, /* reserved */ + HMAC_SHA256_64, + HMAC_SHA256_128, + HMAC_SHA256_256, +}; + +/* + * struct fils_eap_tlv: this structure defines the eap header + * for eap packet present in warpped data element IE + * @type: type of packet + * @length: length of packet + * @data: pointer to eap data + */ +struct fils_eap_tlv { + uint8_t type; + uint8_t length; + uint8_t data[FILS_EAP_TLV_MAX_DATA_LEN]; +}; + +/* struct fils_auth_rsp_info: this structure saves the info from + * fils auth response. + * @keyname: pointer to keyname nai + * @keylength: keyname nai length + * @domain_name: pointer to domain name + * @domain_len: domain length + * @r_rk_lifetime: rRk lifetime + * @r_msk_lifetime: RMSK lifetime + * @sequence: sequence number to be validated + * @fils_nonce: anonce + * @assoc_delay: time in ms, DUT needs to wait after association req + */ +struct fils_auth_rsp_info { + uint8_t *keyname; + uint8_t keylength; + uint8_t *domain_name; + uint8_t domain_len; + uint32_t r_rk_lifetime; + uint32_t r_msk_lifetime; + uint16_t sequence; + uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH]; + uint8_t assoc_delay; +}; + +/* + * struct pe_fils_session: fils session info used in PE session + * @is_fils_connection: whether connection is fils or not + * @keyname_nai_data: keyname nai data + * @keyname_nai_length: keyname nai length + * @akm: akm type will be used + * @auth: authentication type + * @cipher: cipher type + * @fils_erp_reauth_pkt: pointer to fils reauth packet data + * @fils_erp_reauth_pkt_len: reauth packet length + * @fils_r_rk: pointer to fils rRk + * @fils_r_rk_len: fils rRk length + * @fils_r_ik: pointer to fils rIk + * @fils_r_ik_len: fils rIk length + * @sequence_number: sequence number needs to be used in eap packet + * @fils_session: fils session IE element + * @fils_nonce: fils snonce + * @rsn_ie: rsn ie used in auth request + * @rsn_ie_len: rsn ie length + * @fils_eap_finish_pkt: pointer to eap finish packet + * @fils_eap_finish_pkt_len: eap finish packet length + * @fils_rmsk: rmsk data pointer + * @fils_rmsk_len: rmsk data length + * @fils_pmk: pointer to pmk data + * @fils_pmk_len: pmk length + * @fils_pmkid: pointer to pmkid derived + * @auth_info: data obtained from auth response + * @ick: pointer to ick + * @ick_len: ick length + * @kek: pointer to kek + * @kek_len: kek length + * @tk: pointer to tk + * @tk_len: tk length + * @key_auth: data needs to be sent in assoc req, will be validated by AP + * @key_auth_len: key auth data length + * @ap_key_auth_data: data needs to be validated in assoc rsp + * @ap_key_auth_len: ap key data length + * @gtk_len: gtk key length + * @gtk: pointer to gtk data + * @rsc: rsc value + * @igtk_len: igtk length + * @igtk: igtk data pointer + * @ipn: pointer to ipn data + */ +struct pe_fils_session { + bool is_fils_connection; + uint8_t *keyname_nai_data; + uint8_t keyname_nai_length; + uint8_t akm; + uint8_t auth; + uint8_t cipher; + uint8_t *fils_erp_reauth_pkt; + uint32_t fils_erp_reauth_pkt_len; + uint8_t *fils_r_rk; + uint8_t fils_r_rk_len; + uint8_t *fils_r_ik; + uint32_t fils_r_ik_len; + uint16_t sequence_number; + uint8_t fils_session[SIR_FILS_SESSION_LENGTH]; + uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH]; + uint8_t rsn_ie[MAX_IE_LENGTH]; + uint8_t rsn_ie_len; + uint8_t *fils_eap_finish_pkt; + uint8_t fils_eap_finish_pkt_len; + uint8_t *fils_rmsk; + uint8_t fils_rmsk_len; + uint8_t *fils_pmk; + uint8_t fils_pmk_len; + uint8_t fils_pmkid[PMKID_LEN]; + struct fils_auth_rsp_info auth_info; + uint8_t ick[MAX_ICK_LEN]; + uint8_t ick_len; + uint8_t kek[MAX_KEK_LEN]; + uint8_t kek_len; + uint8_t tk[MAX_TK_LEN]; + uint8_t tk_len; + uint8_t key_auth[MAX_KEY_AUTH_DATA_LEN]; + uint8_t key_auth_len; + uint8_t ap_key_auth_data[MAX_KEY_AUTH_DATA_LEN]; + uint8_t ap_key_auth_len; + uint8_t gtk_len; + uint8_t gtk[MAX_GTK_LEN]; + uint8_t rsc; + uint8_t igtk_len; + uint8_t igtk[MAX_IGTK_LEN]; + uint8_t ipn[IPN_LEN]; +}; diff --git a/core/mac/src/pe/include/lim_process_fils.h b/core/mac/src/pe/include/lim_process_fils.h new file mode 100644 index 000000000000..5070bb25896f --- /dev/null +++ b/core/mac/src/pe/include/lim_process_fils.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#ifdef WLAN_FEATURE_FILS_SK + +/** + * lim_process_fils_auth_frame2()- This API processes fils data from auth resp + * @mac_ctx: mac context + * @session: PE session + * @rx_auth_frm_body: pointer to auth frame + * + * Return: true if fils data needs to be processed else false + */ +bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tSirMacAuthFrameBody * rx_auth_frm_body); + +/** + * lim_add_fils_data_to_auth_frame()- This API adds fils data to auth frame. + * Following will be added in this. + * 1. RSNIE + * 2. SNonce + * 3. Session + * 4. Wrapped data + * @session: PE session + * @body: pointer to auth frame where data needs to be added + * + * Return: None + */ +void lim_add_fils_data_to_auth_frame(tpPESession session, uint8_t *body); + +/** + * lim_is_valid_fils_auth_frame()- This API checks whether auth frame is a + * valid frame. + * @mac_ctx: mac context + * @pe_session: pe session pointer + * @rx_auth_frm_body: pointer to autherntication frame + * + * Return: true if frame is valid or fils is disable, false otherwise + */ +bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body); + +/** + * lim_update_fils_config()- This API updates fils session info to csr config + * from join request. + * @session: PE session + * @sme_join_req: pointer to join request + * + * Return: None + */ +void lim_update_fils_config(tpPESession session, tpSirSmeJoinReq sme_join_req); + +/** + * lim_create_fils_auth_data()- This API creates the fils auth data + * which needs to be sent in auth req. + * @mac_ctx: mac context + * @auth_frame: pointer to auth frame + * @session: PE session + * + * Return: length of fils data + */ +uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, tpPESession session); + +/** + * lim_increase_fils_sequence_number: this API increases fils sequence number in + * the event of resending auth packet + * @session_entry: pointer to PE session + * + * Return: None + */ +static inline void lim_increase_fils_sequence_number(tpPESession session_entry) +{ + if (!session_entry->fils_info) + return; + + if (session_entry->fils_info->is_fils_connection) + session_entry->fils_info->sequence_number++; +} + +#else +static inline bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body) +{ + return false; +} + +static inline void +lim_increase_fils_sequence_number(tpPESession session_entry) +{ } + +static inline void +lim_add_fils_data_to_auth_frame(tpPESession session, uint8_t *body) +{ +} + +static inline bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body) +{ + return true; +} + +static inline void +lim_update_fils_config(tpPESession session, tpSirSmeJoinReq sme_join_req) +{ } + +static inline uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, tpPESession session) +{ + return 0; +} +#endif diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h index cd8d8355200f..cb0de7b3c3a2 100644 --- a/core/mac/src/pe/include/lim_session.h +++ b/core/mac/src/pe/include/lim_session.h @@ -519,6 +519,9 @@ typedef struct sPESession /* Added to Support BT-AMP */ bool enable_bcast_probe_rsp; uint8_t ht_client_cnt; bool ch_switch_in_progress; +#ifdef WLAN_FEATURE_FILS_SK + struct pe_fils_session *fils_info; +#endif } tPESession, *tpPESession; /*------------------------------------------------------------------------- diff --git a/core/mac/src/pe/lim/lim_process_auth_frame.c b/core/mac/src/pe/lim/lim_process_auth_frame.c index a1f5ec951473..a2a6b4dceee6 100644 --- a/core/mac/src/pe/lim/lim_process_auth_frame.c +++ b/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -51,6 +51,7 @@ #include "lim_ft.h" #include "cds_utils.h" #include "lim_send_messages.h" +#include "lim_process_fils.h" /** * is_auth_valid @@ -618,6 +619,13 @@ static void lim_process_auth_frame_type2(tpAniSirGlobal mac_ctx, return; } + if (lim_process_fils_auth_frame2(mac_ctx, pe_session, + rx_auth_frm_body)) { + lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS, + rx_auth_frm_body->authStatusCode, pe_session); + return; + } + if (rx_auth_frm_body->authAlgoNumber == eSIR_OPEN_SYSTEM) { pe_session->limCurrentAuthType = eSIR_OPEN_SYSTEM; auth_node = lim_acquire_free_pre_auth_node(mac_ctx, @@ -1090,7 +1098,7 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, uint8_t decrypt_result; uint16_t frame_len, curr_seq_num = 0; uint32_t val, key_length = 8; - tSirMacAuthFrameBody *rx_auth_frm_body, rx_auth_frame, auth_frame; + tSirMacAuthFrameBody *rx_auth_frm_body, *rx_auth_frame, *auth_frame; tpSirMacMgmtHdr mac_hdr; struct tLimPreAuthNode *auth_node; @@ -1131,6 +1139,19 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, pe_session->defaultAuthFailureTimeout); } + + rx_auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!rx_auth_frame) { + pe_err("failed to allocate memory"); + return; + } + + auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!auth_frame) { + pe_err("failed to allocate memory"); + goto free; + } + /* * Determine if WEP bit is set in the FC or received MAC header * Note: WEP bit is set in FC of MAC header. @@ -1147,7 +1168,7 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, lim_send_deauth_mgmt_frame(mac_ctx, eSIR_MAC_MIC_FAILURE_REASON, mac_hdr->sa, pe_session, false); - return; + goto free; } /* Extract key ID from IV (most 2 bits of 4th byte of IV) */ key_id = (*(body_ptr + 3)) >> 6; @@ -1161,18 +1182,18 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, * Out-of-sequence-Authentication-Frame status code. */ if (LIM_IS_STA_ROLE(pe_session)) { - auth_frame.authAlgoNumber = eSIR_SHARED_KEY; - auth_frame.authTransactionSeqNumber = + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; - auth_frame.authStatusCode = + auth_frame->authStatusCode = eSIR_MAC_CHALLENGE_FAILURE_STATUS; /* Log error */ pe_err("rx Auth frm with wep bit set role: %d %pM", GET_LIM_SYSTEM_ROLE(pe_session), mac_hdr->sa); - lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session, false); - return; + goto free; } if (frame_len < LIM_ENCR_AUTH_BODY_LEN) { @@ -1180,7 +1201,7 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, pe_err("Not enough size: %d to decry rx Auth frm", frame_len); lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGE); - return; + goto free; } if (LIM_IS_AP_ROLE(pe_session)) { val = pe_session->privacy; @@ -1207,15 +1228,15 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, * another strange thing in the spec. Status code * should have been 'unsupported algorithm' status code. */ - auth_frame.authAlgoNumber = eSIR_SHARED_KEY; - auth_frame.authTransactionSeqNumber = + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; - auth_frame.authStatusCode = + auth_frame->authStatusCode = eSIR_MAC_CHALLENGE_FAILURE_STATUS; - lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session, false); - return; + goto free; } /* @@ -1234,15 +1255,15 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, * bit set. Send Auth frame4 with * 'out of sequence' status code. */ - auth_frame.authAlgoNumber = eSIR_SHARED_KEY; - auth_frame.authTransactionSeqNumber = + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; - auth_frame.authStatusCode = + auth_frame->authStatusCode = eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; - lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session, false); - return; + goto free; } /* Change the auth-response timeout */ lim_deactivate_and_change_per_sta_id_timer(mac_ctx, @@ -1262,16 +1283,16 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, * Reject by sending Authenticaton frame with * out of sequence Auth frame status code. */ - auth_frame.authAlgoNumber = eSIR_SHARED_KEY; - auth_frame.authTransactionSeqNumber = + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; - auth_frame.authStatusCode = + auth_frame->authStatusCode = eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; - lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session, false); - return; + goto free; } val = SIR_MAC_KEY_LENGTH; @@ -1291,15 +1312,15 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, * Send Authentication frame * with challenge failure status code */ - auth_frame.authAlgoNumber = eSIR_SHARED_KEY; - auth_frame.authTransactionSeqNumber = + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; - auth_frame.authStatusCode = + auth_frame->authStatusCode = eSIR_MAC_CHALLENGE_FAILURE_STATUS; - lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session, false); - return; + goto free; } key_length = val; @@ -1313,33 +1334,33 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, MAC_ADDR_ARRAY(mac_hdr->sa)); /* ICV failure */ lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); - auth_frame.authAlgoNumber = eSIR_SHARED_KEY; - auth_frame.authTransactionSeqNumber = + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; - auth_frame.authStatusCode = + auth_frame->authStatusCode = eSIR_MAC_CHALLENGE_FAILURE_STATUS; - lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session, false); - return; + goto free; } if ((sir_convert_auth_frame2_struct(mac_ctx, plainbody, - frame_len - 8, &rx_auth_frame) != eSIR_SUCCESS) - || (!is_auth_valid(mac_ctx, &rx_auth_frame, + frame_len - 8, rx_auth_frame) != eSIR_SUCCESS) + || (!is_auth_valid(mac_ctx, rx_auth_frame, pe_session))) { pe_err("failed to convert Auth Frame to structure or Auth is not valid"); - return; + goto free; } } else if ((sir_convert_auth_frame2_struct(mac_ctx, body_ptr, - frame_len, &rx_auth_frame) != eSIR_SUCCESS) - || (!is_auth_valid(mac_ctx, &rx_auth_frame, + frame_len, rx_auth_frame) != eSIR_SUCCESS) + || (!is_auth_valid(mac_ctx, rx_auth_frame, pe_session))) { pe_err("failed to convert Auth Frame to structure or Auth is not valid"); - return; + goto free; } - rx_auth_frm_body = &rx_auth_frame; + rx_auth_frm_body = rx_auth_frame; pe_debug("Received Auth frame with type: %d seqnum: %d status: %d %d", (uint32_t) rx_auth_frm_body->authAlgoNumber, @@ -1347,6 +1368,12 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, (uint32_t) rx_auth_frm_body->authStatusCode, (uint32_t) mac_ctx->lim.gLimNumPreAuthContexts); + if (!lim_is_valid_fils_auth_frame(mac_ctx, pe_session, + rx_auth_frm_body)) { + pe_err("Received invalid FILS auth packet"); + goto free; + } + /* * IOT Workaround: with invalid WEP key, some APs reply * AuthFrame 4 with invalid seqNumber. This AuthFrame @@ -1372,16 +1399,16 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, case SIR_MAC_AUTH_FRAME_1: lim_process_auth_frame_type1(mac_ctx, mac_hdr, rx_auth_frm_body, rx_pkt_info, - curr_seq_num, &auth_frame, pe_session); + curr_seq_num, auth_frame, pe_session); break; case SIR_MAC_AUTH_FRAME_2: lim_process_auth_frame_type2(mac_ctx, - mac_hdr, rx_auth_frm_body, &auth_frame, plainbody, + mac_hdr, rx_auth_frm_body, auth_frame, plainbody, body_ptr, frame_len, pe_session); break; case SIR_MAC_AUTH_FRAME_3: lim_process_auth_frame_type3(mac_ctx, - mac_hdr, rx_auth_frm_body, &auth_frame, pe_session); + mac_hdr, rx_auth_frm_body, auth_frame, pe_session); break; case SIR_MAC_AUTH_FRAME_4: lim_process_auth_frame_type4(mac_ctx, @@ -1394,6 +1421,11 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, mac_hdr->sa); break; } +free: + if (auth_frame) + qdf_mem_free(auth_frame); + if (rx_auth_frame) + qdf_mem_free(rx_auth_frame); } /*---------------------------------------------------------------------- diff --git a/core/mac/src/pe/lim/lim_process_fils.c b/core/mac/src/pe/lim/lim_process_fils.c new file mode 100644 index 000000000000..79e8df36ac4b --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_fils.c @@ -0,0 +1,1238 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "lim_process_fils.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WLAN_FEATURE_FILS_SK + +#define WLAN_FILS_DEBUG +#ifdef WLAN_FILS_DEBUG +/** + * lim_fils_data_dump()- dump fils data + * @type: Data name + * @data: pointer to data buffer + * @len: data len + * + * Return: None + */ +static void lim_fils_data_dump(char *type, uint8_t *data, uint32_t len) +{ + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + ("%s : length %d"), type, len); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, data, len); +} +#else +static void lim_fils_data_dump(char *type, uint8_t *data, uint32_t len) +{ } +#endif + +/** + * lim_get_crypto_digest_len()- Returns hash length based on crypto type + * @type: Crypto type + * + * Return: hash length + */ +static int lim_get_crypto_digest_len(uint8_t *type) +{ + if (!strcmp(type, HMAC_SHA386_CRYPTO_TYPE)) + return SHA384_DIGEST_SIZE; + else if (!strcmp(type, HMAC_SHA256_CRYPTO_TYPE)) + return SHA256_DIGEST_SIZE; + return -EINVAL; +} + +/** + * lim_get_auth_tag_len()- This API returns auth tag len based on crypto suit + * used to encrypt erp packet. + * @crypto_suite: Crtpto suit + * + * Return: tag length + */ +static uint8_t lim_get_auth_tag_len(enum fils_erp_cryptosuite crypto_suite) +{ + switch (crypto_suite) { + case HMAC_SHA256_64: + return -EINVAL; + case HMAC_SHA256_128: + return FILS_SHA256_128_AUTH_TAG; + case HMAC_SHA256_256: + return FILS_SHA256_256_AUTH_TAG; + default: + return -EINVAL; + } +} + + +/** + * lim_get_crypto_type()- This API returns crypto type based on akm suite used + * @akm: akm used for authentication + * + * Return: Crypto type + */ +static uint8_t *lim_get_crypto_type(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_CRYPTO_TYPE; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + default: + return FILS_SHA256_CRYPTO_TYPE; + } +} + +/** + * lim_get_pmk_length()- This API returns pmk length based on akm used + * @akm: akm used for authentication + * + * Return: PMK length + */ +static uint8_t lim_get_pmk_length(int akm_type) +{ + switch (akm_type) { + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return FILS_SHA256_PKM_LEN; + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_PKM_LEN; + default: + return FILS_SHA256_PKM_LEN; + } +} + +/** + * lim_get_kek_len()- This API returns kek length based on akm used + * @akm: akm used for authentication + * + * Return: KEK length + */ +static uint8_t lim_get_kek_len(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_KEK_LEN; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return FILS_SHA256_KEK_LEN; + default: + return FILS_SHA256_KEK_LEN; + } +} + +/** + * lim_get_tk_len()- This API returns tk length based on cypher used + * @akm: cypher used + * + * Return: TK length + */ +static uint8_t lim_get_tk_len(int cypher_suite) +{ + switch (cypher_suite) { + case eSIR_ED_TKIP: + return TK_LEN_TKIP; + case eSIR_ED_CCMP: + return TK_LEN_CCMP; + case eSIR_ED_AES_128_CMAC: + return TK_LEN_AES_128_CMAC; + default: + return 0; + } +} + +/** + * lim_get_ick_len()- This API returns ick length based on akm used + * @akm: akm used for authentication + * + * Return: ICK length + */ +static int lim_get_ick_len(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_ICK_LEN; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + default: + return FILS_SHA256_ICK_LEN; + } +} + +/** + * lim_get_key_from_prf()- This API returns key data using PRF-X as defined in + * 11.6.1.7.2 ieee-80211-2012. + * @type: crypto type needs to be used + * @secret: key which needs to be used in crypto + * @secret_len: key_len of secret + * @label: PRF label + * @optional_data: Data used for hash + * @optional_data_len: data length + * @key: key data output + * @keylen: key data length + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_get_key_from_prf(uint8_t *type, uint8_t *secret, + uint32_t secret_len, uint8_t *label, uint8_t *optional_data, + uint32_t optional_data_len, uint8_t *key, uint32_t keylen) +{ + uint8_t count[2]; + uint8_t *addr[4]; + uint32_t len[4]; + uint16_t key_bit_length = keylen * 8; + uint8_t key_length[2]; + uint32_t i = 0, remain_len; + uint16_t interation; + uint8_t crypto_digest_len = lim_get_crypto_digest_len(type); + uint8_t tmp_hash[SHA384_DIGEST_SIZE] = {0}; + + addr[0] = count; + len[0] = sizeof(count); + + addr[1] = label; + len[1] = strlen(label); + + addr[2] = optional_data; + len[2] = optional_data_len; + + qdf_mem_copy(key_length, &key_bit_length, sizeof(key_bit_length)); + addr[3] = key_length; + len[3] = sizeof(key_length); + + for (interation = 1; i < keylen; interation++) { + remain_len = keylen - i; + qdf_mem_copy(count, &interation, sizeof(interation)); + + if (remain_len >= crypto_digest_len) + remain_len = crypto_digest_len; + + if (qdf_get_hmac_hash(type, secret, secret_len, 4, + addr, len, tmp_hash) < 0) { + pe_err("qdf_get_hmac_hash failed"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&key[i], tmp_hash, remain_len); + i += crypto_digest_len; + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_default_hmac_sha256_kdf()- This API calculates key data using default kdf + * defined in RFC4306. + * @secret: key which needs to be used in crypto + * @secret_len: key_len of secret + * @label: PRF label + * @optional_data: Data used for hash + * @optional_data_len: data length + * @key: key data output + * @keylen: key data length + * + * This API creates default KDF as defined in RFC4306 + * PRF+ (K,S) = T1 | T2 | T3 | T4 | ... + * T1 = PRF (K, S | 0x01) + * T2 = PRF (K, T1 | S | 0x02) + * T3 = PRF (K, T2 | S | 0x03) + * T4 = PRF (K, T3 | S | 0x04) + * + * for every iteration its creates 32 bit of hash + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_default_hmac_sha256_kdf(uint8_t *secret, uint32_t secret_len, + uint8_t *label, uint8_t *optional_data, + uint32_t optional_data_len, uint8_t *key, uint32_t keylen) +{ + uint8_t tmp_hash[SHA256_DIGEST_SIZE] = {0}; + uint8_t count = 1; + uint8_t *addr[4]; + uint32_t len[4]; + uint32_t current_position = 0, remaining_data = SHA256_DIGEST_SIZE; + + addr[0] = tmp_hash; + len[0] = SHA256_DIGEST_SIZE; + addr[1] = label; + len[1] = strlen(label) + 1; + addr[2] = optional_data; + len[2] = optional_data_len; + addr[3] = &count; + len[3] = 1; + + if (keylen == 0 || + (keylen > (MAX_PRF_INTERATIONS_COUNT * SHA256_DIGEST_SIZE))) { + pe_err("invalid key length %d", keylen); + return QDF_STATUS_E_FAILURE; + } + + /* Create T1 */ + if (qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, secret, secret_len, 3, + &addr[1], &len[1], tmp_hash) < 0) { + pe_err("failed to get hmac hash"); + return QDF_STATUS_E_FAILURE; + } + + /* Update hash from tmp_hash */ + qdf_mem_copy(key + current_position, tmp_hash, remaining_data); + current_position += remaining_data; + + for (count = 2; current_position < keylen; count++) { + remaining_data = keylen - current_position; + if (remaining_data > SHA256_DIGEST_SIZE) + remaining_data = SHA256_DIGEST_SIZE; + + /* Create T-n */ + if (qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, secret, + secret_len, 4, addr, len, tmp_hash) < 0) { + pe_err("failed to get hmac hash"); + return QDF_STATUS_E_FAILURE; + } + /* Update hash from tmp_hash */ + qdf_mem_copy(key + current_position, tmp_hash, remaining_data); + current_position += remaining_data; + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_fils_eap_tlv()- This API process eap tlv available in auth resp + * and returns remaining length. + * @pe_session: PE session + * @wrapped_data: wrapped data + * @data_len: length of tlv + * + * Return: remaining length + */ +static uint32_t lim_process_fils_eap_tlv(tpPESession pe_session, + uint8_t *wrapped_data, uint32_t data_len) +{ + struct fils_eap_tlv *tlv; + struct fils_auth_rsp_info *auth_info; + uint8_t auth_tag_len; + + auth_info = &pe_session->fils_info->auth_info; + /* Minimum */ + auth_tag_len = lim_get_auth_tag_len(HMAC_SHA256_128); + + while (data_len > (auth_tag_len + 1)) { + tlv = (struct fils_eap_tlv *) wrapped_data; + + pe_debug("tlv type %x len %u total %u", + tlv->type, tlv->length, data_len); + switch (tlv->type) { + case SIR_FILS_EAP_TLV_KEYNAME_NAI: + auth_info->keyname = qdf_mem_malloc(tlv->length); + if (!auth_info->keyname) { + pe_err("failed to alloc memory"); + return 0; + } + qdf_mem_copy(auth_info->keyname, + tlv->data, tlv->length); + auth_info->keylength = tlv->length; + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + case SIR_FILS_EAP_TLV_R_RK_LIFETIME: + /* TODO check this */ + auth_info->r_rk_lifetime = lim_get_u32(tlv->data); + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + case SIR_FILS_EAP_TLV_R_MSK_LIFETIME: + /* TODO check this */ + auth_info->r_msk_lifetime = lim_get_u32(tlv->data); + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + case SIR_FILS_EAP_TLV_DOMAIN_NAME: + auth_info->domain_name = qdf_mem_malloc(tlv->length); + if (!auth_info->domain_name) { + pe_err("failed to alloc memory"); + return 0; + } + qdf_mem_copy(auth_info->domain_name, + tlv->data, tlv->length); + auth_info->domain_len = tlv->length; + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + /* TODO process these now */ + case SIR_FILS_EAP_TLV_CRYPTO_LIST: + case SIR_FILS_EAP_TLV_AUTH_INDICATION: + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + default: + pe_debug("Unknown type"); + return data_len; + } + } + return data_len; +} + +/** + * lim_generate_key_data()- This API generates key data using prf + * FILS-Key-Data = KDF-X(PMK, "FILS PTK Derivation", SPA||AA||SNonce||ANonce) + * @fils_info: fils session info + * @key_label: label used + * @data: data buffer + * @data_len: data buffer len + * @key_data: hash data needs to be generated + * @key_data_len: hash data len + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_generate_key_data(struct pe_fils_session *fils_info, + uint8_t *key_label, uint8_t *data, uint32_t data_len, + uint8_t *key_data, uint32_t key_data_len) +{ + QDF_STATUS status; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + status = lim_get_key_from_prf(lim_get_crypto_type(fils_info->akm), + fils_info->fils_pmk, + fils_info->fils_pmk_len, + key_label, data, data_len, key_data, key_data_len); + if (status != QDF_STATUS_SUCCESS) + pe_err("failed to generate keydata"); + return status; +} + +/** + * lim_generate_ap_key_auth()- This API generates ap auth data which needs to be + * verified in assoc response. + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_ap_key_auth(tpPESession pe_session) +{ + uint8_t *buf, *addr[1]; + uint32_t len; + struct pe_fils_session *fils_info = pe_session->fils_info; + uint8_t data[SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE] = {0}; + + if (!fils_info) + return; + + len = SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE; + addr[0] = data; + buf = data; + qdf_mem_copy(buf, fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(buf, pe_session->selfMacAddr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm), + fils_info->ick, fils_info->ick_len, 1, &addr[0], + &len, fils_info->ap_key_auth_data) < 0) + pe_err("failed to generate PMK id"); + fils_info->ap_key_auth_len = lim_get_crypto_digest_len( + lim_get_crypto_type(fils_info->akm)); + lim_fils_data_dump("AP Key Auth", fils_info->ap_key_auth_data, + fils_info->ap_key_auth_len); +} + +/** + * lim_generate_key_auth()- This API generates sta auth data which needs to be + * send to AP in assoc request, AP will generate the same the verify it. + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_key_auth(tpPESession pe_session) +{ + uint8_t *buf, *addr[1]; + uint32_t len; + struct pe_fils_session *fils_info = pe_session->fils_info; + uint8_t data[SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE] = {0}; + + if (!fils_info) + return; + + len = SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE; + + addr[0] = data; + buf = data; + qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, pe_session->selfMacAddr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm), + fils_info->ick, fils_info->ick_len, 1, + &addr[0], &len, fils_info->key_auth) < 0) + pe_err("failed to generate key auth"); + fils_info->key_auth_len = lim_get_crypto_digest_len( + lim_get_crypto_type(fils_info->akm)); + lim_fils_data_dump("STA Key Auth", + fils_info->key_auth, fils_info->key_auth_len); +} + +/** + * lim_get_keys()- This API generates keys keydata which is generated after + * parsing of auth response. + * KCK = L(FILS-Key-Data, 0, KCK_bits) + * KEK = L(FILS-Key-Data, KCK_bits, KEK_bits) + * TK = L(FILS-Key-Data, KCK_bits + KEK_bits, TK_bits) + * FILS-FT = L(FILS-Key-Data, KCK_bits + KEK_bits + TK_bits, FILS-FT_bits) + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_get_keys(tpPESession pe_session) +{ + uint8_t key_label[] = PTK_KEY_LABEL; + uint8_t *data; + uint8_t data_len; + struct pe_fils_session *fils_info = pe_session->fils_info; + uint8_t key_data[MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN] = {0}; + uint8_t key_data_len; + uint8_t ick_len = lim_get_ick_len(fils_info->akm); + uint8_t kek_len = lim_get_kek_len(fils_info->akm); + uint8_t tk_len = lim_get_tk_len(pe_session->encryptType); + uint8_t *buf; + + if (!fils_info) + return; + + key_data_len = ick_len + kek_len + tk_len; + + data_len = 2 * SIR_FILS_NONCE_LENGTH + 2 * QDF_MAC_ADDR_SIZE; + data = qdf_mem_malloc(data_len); + if (!data) { + pe_err("failed to alloc memory"); + return; + } + + /* Update data */ + buf = data; + qdf_mem_copy(buf, pe_session->selfMacAddr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + lim_generate_key_data(fils_info, key_label, data, data_len, + key_data, key_data_len); + buf = key_data; + qdf_mem_copy(fils_info->ick, buf, ick_len); + fils_info->ick_len = ick_len; + buf += ick_len; + qdf_mem_copy(fils_info->kek, buf, kek_len); + fils_info->kek_len = kek_len; + buf += kek_len; + qdf_mem_copy(fils_info->tk, buf, tk_len); + fils_info->tk_len = tk_len; + lim_fils_data_dump("Key Data", key_data, key_data_len); + lim_fils_data_dump("ICK", fils_info->ick, ick_len); + lim_fils_data_dump("KEK", fils_info->kek, kek_len); + lim_fils_data_dump("TK", fils_info->tk, tk_len); + qdf_mem_free(data); +} + +/** + * lim_generate_pmkid()- This API generates PMKID using hash of erp auth packet + * parsing of auth response. + * PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_pmkid(tpPESession pe_session) +{ + uint8_t hash[SHA384_DIGEST_SIZE]; + struct pe_fils_session *fils_info = pe_session->fils_info; + + if (!fils_info) + return; + + qdf_get_hash(lim_get_crypto_type(fils_info->akm), 1, + &fils_info->fils_erp_reauth_pkt, + &fils_info->fils_erp_reauth_pkt_len, hash); + qdf_mem_copy(fils_info->fils_pmkid, hash, PMKID_LEN); + lim_fils_data_dump("PMKID", fils_info->fils_pmkid, PMKID_LEN); +} + +/** + * lim_generate_pmk()- This API generates PMK using hmac hash of rmsk data + * anonce, snonce will be used as key for this + * PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_pmk(tpPESession pe_session) +{ + uint8_t nounce[2 * SIR_FILS_NONCE_LENGTH] = {0}; + uint8_t nounce_len = 2 * SIR_FILS_NONCE_LENGTH; + uint8_t *addr[1]; + uint32_t len[1]; + struct pe_fils_session *fils_info = pe_session->fils_info; + + if (!fils_info) + return; + + /* Snounce */ + qdf_mem_copy(nounce, pe_session->fils_info->fils_nonce, + SIR_FILS_NONCE_LENGTH); + /* anounce */ + qdf_mem_copy(nounce + SIR_FILS_NONCE_LENGTH, + pe_session->fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + fils_info->fils_pmk_len = lim_get_pmk_length(fils_info->akm); + + if (fils_info->fils_pmk) + qdf_mem_free(fils_info->fils_pmk); + + fils_info->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len); + if (!fils_info->fils_pmk) { + pe_err("failed to alloc memory"); + return; + } + + addr[0] = fils_info->fils_rmsk; + len[0] = fils_info->fils_rmsk_len; + lim_fils_data_dump("Nonce", nounce, nounce_len); + if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm), nounce, + nounce_len, 1, + &addr[0], &len[0], fils_info->fils_pmk) < 0) + pe_err("failed to generate PMK"); + lim_fils_data_dump("PMK", fils_info->fils_pmk, fils_info->fils_pmk_len); +} + +/** + * lim_generate_rmsk_data()- This API generates RMSK data using + * default kdf as defined in RFC4306. + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_rmsk_data(tpPESession pe_session) +{ + uint8_t optional_data[4] = {0}; + uint8_t rmsk_label[] = RMSK_LABEL; + struct pe_fils_session *fils_info = pe_session->fils_info; + struct fils_auth_rsp_info *auth_info; + + if (!fils_info) + return; + + auth_info = &(pe_session->fils_info->auth_info); + fils_info->fils_rmsk_len = fils_info->fils_r_rk_len; + fils_info->fils_rmsk = qdf_mem_malloc(fils_info->fils_r_rk_len); + if (!fils_info->fils_rmsk) { + pe_err("failed to alloc memory"); + return; + } + + /* + * Sequence number sent in EAP-INIT packet, + * it should be in network byte order + */ + lim_copy_u16_be(&optional_data[0], fils_info->sequence_number); + lim_copy_u16_be(&optional_data[2], fils_info->fils_r_rk_len); + lim_default_hmac_sha256_kdf(fils_info->fils_r_rk, + fils_info->fils_r_rk_len, rmsk_label, + optional_data, sizeof(optional_data), + fils_info->fils_rmsk, fils_info->fils_rmsk_len); + lim_fils_data_dump("RMSK", fils_info->fils_rmsk, + fils_info->fils_rmsk_len); +} + +/** + * lim_process_auth_wrapped_data()- This API process wrapped data element + * of auth response. + * @pe_session: pe session pointer + * @wrapped_data: wrapped data pointer + * @data_len: wrapped data len + * + * Return: None + */ +static QDF_STATUS lim_process_auth_wrapped_data(tpPESession pe_session, + uint8_t *wrapped_data, uint32_t data_len) +{ + uint8_t code; + uint8_t identifier; + uint16_t length; + uint8_t type; + unsigned long flags; + struct pe_fils_session *fils_info; + uint8_t hash[32], crypto; + uint32_t remaining_len = data_len, new_len; + uint8_t *input_data[1]; + uint32_t input_len[1]; + uint8_t auth_tag_len; + + fils_info = pe_session->fils_info; + input_data[0] = wrapped_data; + input_len[0] = data_len; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + pe_debug("trying to process the wrappped data"); + + code = *wrapped_data; + wrapped_data++; + remaining_len--; + identifier = *wrapped_data; + wrapped_data++; + remaining_len--; + + length = lim_get_u16(wrapped_data); + wrapped_data += sizeof(uint16_t); + remaining_len -= sizeof(uint16_t); + + type = *wrapped_data; /* val should be 2 here */ + wrapped_data++; + remaining_len--; + + flags = *wrapped_data; + if (test_bit(7, &flags)) { + pe_err("R bit is set in flag, error"); + return QDF_STATUS_E_FAILURE; + } + wrapped_data++; + remaining_len--; + + fils_info->auth_info.sequence = lim_get_u16_be(wrapped_data); + wrapped_data += sizeof(uint16_t); + remaining_len -= sizeof(uint16_t); + /* Validate Auth sequence number */ + if (fils_info->auth_info.sequence < fils_info->sequence_number) { + pe_err("sequence EAP-finish:%d is less than EAP-init:%d", + fils_info->auth_info.sequence, + fils_info->sequence_number); + return QDF_STATUS_E_FAILURE; + } + + /* Parse attached TLVs */ + new_len = lim_process_fils_eap_tlv(pe_session, + wrapped_data, remaining_len); + + wrapped_data += remaining_len - new_len; + remaining_len = new_len; + /* Remove cryptosuite */ + crypto = *wrapped_data; + wrapped_data++; + remaining_len--; + + auth_tag_len = lim_get_auth_tag_len(crypto); + input_len[0] -= auth_tag_len; + /* if we have auth tag remaining */ + if (remaining_len == auth_tag_len) { + qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, fils_info->fils_r_ik, + fils_info->fils_r_ik_len, 1, + input_data, input_len, hash); + } else { + pe_err("invalid remaining len %d", + remaining_len); + } + if (qdf_mem_cmp(wrapped_data, hash, auth_tag_len)) { + pe_err("integratity check failed for auth, crypto %d", + crypto); + return QDF_STATUS_E_FAILURE; + } + + lim_generate_rmsk_data(pe_session); + lim_generate_pmk(pe_session); + lim_generate_pmkid(pe_session); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_is_valid_fils_auth_frame()- This API check whether auth frame is a + * valid frame. + * @mac_ctx: mac context + * @pe_session: pe session pointer + * @rx_auth_frm_body: pointer to autherntication frame + * + * Return: true if frame is valid or fils is disable, false otherwise + */ +bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tSirMacAuthFrameBody *rx_auth_frm_body) +{ + if (!pe_session->fils_info) + return true; + + if (pe_session->fils_info->is_fils_connection == false) + return true; + + if (qdf_mem_cmp(rx_auth_frm_body->session, + pe_session->fils_info->fils_session, + SIR_FILS_SESSION_LENGTH)) { + lim_fils_data_dump("Current FILS session", + pe_session->fils_info->fils_session, + SIR_FILS_SESSION_LENGTH); + lim_fils_data_dump("FILS Session in pkt", + rx_auth_frm_body->session, + SIR_FILS_SESSION_LENGTH); + return false; + } + qdf_mem_copy(pe_session->fils_info->auth_info.fils_nonce, + rx_auth_frm_body->nonce, SIR_FILS_NONCE_LENGTH); + pe_session->fils_info->auth_info.assoc_delay = + rx_auth_frm_body->assoc_delay_info; + return true; +} + +/** + * lim_create_fils_r_ik()- This API create rik using rrk coming from + * supplicant. + * rIK = KDF (K, S), where + * K = rRK and + * S = rIK Label + "\0" + cryptosuite + length + * The rIK Label is the 8-bit ASCII string: + * Re-authentication Integrity Key@ietf.org + * @fils_info: fils session info + * + * Return: None + */ +static QDF_STATUS lim_create_fils_r_ik(struct pe_fils_session *fils_info) +{ + uint8_t optional_data[SIR_FILS_OPTIONAL_DATA_LEN]; + uint8_t label[] = SIR_FILS_RIK_LABEL; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + optional_data[0] = HMAC_SHA256_128; + /* basic validation */ + if (fils_info->fils_r_rk_len <= 0) { + pe_err("invalid r_rk length %d", fils_info->fils_r_rk_len); + return QDF_STATUS_E_FAILURE; + } + lim_copy_u16_be(&optional_data[1], fils_info->fils_r_rk_len); + fils_info->fils_r_ik = qdf_mem_malloc(fils_info->fils_r_rk_len); + if (!fils_info->fils_r_ik) { + pe_err("failed to alloc memory"); + return QDF_STATUS_E_FAILURE; + } + if (lim_default_hmac_sha256_kdf(fils_info->fils_r_rk, + fils_info->fils_r_rk_len, label, + optional_data, sizeof(optional_data), + fils_info->fils_r_ik, fils_info->fils_r_rk_len) + != QDF_STATUS_SUCCESS) { + pe_err("failed to create r_ik"); + return QDF_STATUS_E_FAILURE; + } + fils_info->fils_r_ik_len = fils_info->fils_r_rk_len; + lim_fils_data_dump("rRk", fils_info->fils_r_rk, + fils_info->fils_r_rk_len); + lim_fils_data_dump("rIk", fils_info->fils_r_ik, + fils_info->fils_r_rk_len); + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_create_fils_wrapper_data()- This API create warpped data which will be + * sent in auth request. + * @fils_info: fils session info + * + * Return: 0 if success else error code + */ +static int lim_create_fils_wrapper_data(struct pe_fils_session *fils_info) +{ + uint8_t *buf; + uint8_t auth_tag[FILS_AUTH_TAG_MAX_LENGTH] = {0}; + uint32_t length = 0; + int buf_len = + /* code + identifier */ + sizeof(uint8_t) * 2 + + /* length */ + sizeof(uint16_t) + + /* type + flags */ + sizeof(uint8_t) * 2 + + /* sequence */ + sizeof(uint16_t) + + /* tlv : type, length, data */ + sizeof(uint8_t) * 2 + fils_info->keyname_nai_length + + /* cryptosuite + auth_tag */ + sizeof(uint8_t) + lim_get_auth_tag_len(HMAC_SHA256_128); + + if (!fils_info) + return 0; + + fils_info->fils_erp_reauth_pkt = qdf_mem_malloc(buf_len); + if (!fils_info->fils_erp_reauth_pkt) { + pe_err("failed to allocate memory"); + return -EINVAL; + } + buf = fils_info->fils_erp_reauth_pkt; + *buf = 5; + buf++; + /* Identifier */ + *buf = 0; + buf++; + /* Length */ + lim_copy_u16_be(buf, buf_len); + buf += sizeof(uint16_t); + /* type */ + *buf = SIR_FILS_EAP_INIT_PACKET_TYPE; + buf++; + + /** + * flag + * 0 1 2 <-- 5 --> + * ---------------- + * |R|B|L| Reserved| + * ----------------- + */ + *buf = 0x20; /* l=1, b=0, r=0 */ + buf++; + /* sequence */ + lim_copy_u16_be(buf, fils_info->sequence_number); + buf += sizeof(uint16_t); + + /* tlv */ + /* Type */ + *buf = SIR_FILS_EAP_TLV_KEYNAME_NAI; + buf++; + /* NAI Length */ + *buf = fils_info->keyname_nai_length; + buf++; + /* NAI Data */ + qdf_mem_copy(buf, fils_info->keyname_nai_data, + fils_info->keyname_nai_length); + buf += fils_info->keyname_nai_length; + + /* cryptosuite */ + *buf = HMAC_SHA256_128; + buf++; + + /* + * This should be moved to just after sending probe to save time + * lim_process_switch_channel_join_req ?? + */ + lim_create_fils_r_ik(fils_info); + fils_info->fils_erp_reauth_pkt_len = buf_len; + length = fils_info->fils_erp_reauth_pkt_len - + lim_get_auth_tag_len(HMAC_SHA256_128); + qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, + fils_info->fils_r_ik, fils_info->fils_r_ik_len, 1, + &fils_info->fils_erp_reauth_pkt, &length, auth_tag); + + lim_fils_data_dump("Auth tag", auth_tag, + lim_get_auth_tag_len(HMAC_SHA256_128)); + lim_fils_data_dump("EAP init pkt", fils_info->fils_erp_reauth_pkt, + fils_info->fils_erp_reauth_pkt_len); + + qdf_mem_copy(buf, auth_tag, lim_get_auth_tag_len(HMAC_SHA256_128)); + buf += lim_get_auth_tag_len(HMAC_SHA256_128); + + return buf_len; +} + +/** + * lim_add_fils_data_to_auth_frame()- This API add fils data to auth frame. + * Following will be added in this. + * RSNIE + * SNonce + * Session + * Wrapped data + * @session: PE session + * @body: pointer to auth frame where data needs to be added + * + * Return: None + */ +void lim_add_fils_data_to_auth_frame(tpPESession session, + uint8_t *body) +{ + struct pe_fils_session *fils_info; + + fils_info = session->fils_info; + + if (!fils_info) + return; + + /* RSN IE */ + qdf_mem_copy(body, fils_info->rsn_ie, fils_info->rsn_ie_len); + body += fils_info->rsn_ie_len; + lim_fils_data_dump("FILS RSN", fils_info->rsn_ie, + fils_info->rsn_ie_len); + + /* ***Nounce*** */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add nounce length + 1 for ext element id */ + *body = SIR_FILS_NONCE_LENGTH + 1; + body++; + /* Add ext element */ + *body = SIR_FILS_NONCE_EXT_EID; + body++; + /* Add data */ + cds_rand_get_bytes(0, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + qdf_mem_copy(body, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + body = body + SIR_FILS_NONCE_LENGTH; + /* Dump data */ + lim_fils_data_dump("fils anonce", fils_info->fils_nonce, + SIR_FILS_NONCE_LENGTH); + + /* *** Session *** */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add nounce length + 1 for ext element id */ + *body = SIR_FILS_SESSION_LENGTH + 1; + body++; + /* Add ext element */ + *body = SIR_FILS_SESSION_EXT_EID; + body++; + /* Add data */ + cds_rand_get_bytes(0, fils_info->fils_session, SIR_FILS_SESSION_LENGTH); + qdf_mem_copy(body, fils_info->fils_session, SIR_FILS_SESSION_LENGTH); + body = body + SIR_FILS_SESSION_LENGTH; + /* dump data */ + lim_fils_data_dump("Fils Session", + fils_info->fils_session, SIR_FILS_SESSION_LENGTH); + + /* ERP Packet */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add packet length + 1 for ext element id */ + *body = fils_info->fils_erp_reauth_pkt_len + 1; + body++; + /* Add ext element */ + *body = SIR_FILS_WRAPPED_DATA_EXT_EID; + body++; + /* Copy data */ + qdf_mem_copy(body, fils_info->fils_erp_reauth_pkt, + fils_info->fils_erp_reauth_pkt_len); + lim_fils_data_dump("Fils ERP reauth Pkt", + fils_info->fils_erp_reauth_pkt, + fils_info->fils_erp_reauth_pkt_len); + body = body + fils_info->fils_erp_reauth_pkt_len; +} + +/** + * lim_process_fils_auth_frame2()- This API process fils data from auth response + * @mac_ctx: mac context + * @session: PE session + * @rx_auth_frm_body: pointer to auth frame + * + * Return: true if fils data needs to be processed else false + */ +bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tSirMacAuthFrameBody *rx_auth_frm_body) +{ + bool pmkid_found = false; + int i; + tDot11fIERSN dot11f_ie_rsn = {0}; + + if (!pe_session->fils_info) + return false; + + if (rx_auth_frm_body->authAlgoNumber != eSIR_FILS_SK_WITHOUT_PFS) + return false; + + dot11f_unpack_ie_rsn(mac_ctx, + &rx_auth_frm_body->rsn_ie.info[0], + rx_auth_frm_body->rsn_ie.length, + &dot11f_ie_rsn, 0); + + for (i = 0; i < dot11f_ie_rsn.pmkid_count; i++) { + if (qdf_mem_cmp(dot11f_ie_rsn.pmkid[i], + pe_session->fils_info->fils_pmkid, + PMKID_LEN) == 0) { + pmkid_found = true; + pe_debug("pmkid match in rsn ie total_count %d", + dot11f_ie_rsn.pmkid_count); + break; + } + } + if (!pmkid_found) { + if (QDF_STATUS_SUCCESS != + lim_process_auth_wrapped_data(pe_session, + rx_auth_frm_body->wrapped_data, + rx_auth_frm_body->wrapped_data_len)) + return false; + } else { + lim_fils_data_dump("PMK", + pe_session->fils_info->fils_pmk, + pe_session->fils_info->fils_pmk_len); + } + lim_get_keys(pe_session); + lim_generate_key_auth(pe_session); + lim_generate_ap_key_auth(pe_session); + return true; +} + +/** + * lim_update_fils_config()- This API update fils session info to csr config + * from join request. + * @session: PE session + * @sme_join_req: pointer to join request + * + * Return: None + */ +void lim_update_fils_config(tpPESession session, + tpSirSmeJoinReq sme_join_req) +{ + struct pe_fils_session *csr_fils_info; + struct cds_fils_connection_info *fils_config_info; + + fils_config_info = &sme_join_req->fils_con_info; + csr_fils_info = session->fils_info; + + if (!csr_fils_info) + return; + + if (fils_config_info->is_fils_connection == false) + return; + + csr_fils_info->is_fils_connection = + fils_config_info->is_fils_connection; + csr_fils_info->keyname_nai_length = + fils_config_info->key_nai_length; + csr_fils_info->fils_r_rk_len = + fils_config_info->r_rk_length; + csr_fils_info->akm = fils_config_info->akm_type; + csr_fils_info->auth = fils_config_info->auth_type; + csr_fils_info->sequence_number = fils_config_info->sequence_number; + csr_fils_info->keyname_nai_data = + qdf_mem_malloc(fils_config_info->key_nai_length); + if (!csr_fils_info->keyname_nai_data) { + pe_err("failed to alloc memory"); + return; + } + qdf_mem_copy(csr_fils_info->keyname_nai_data, + fils_config_info->keyname_nai, + fils_config_info->key_nai_length); + csr_fils_info->fils_r_rk = + qdf_mem_malloc(fils_config_info->r_rk_length); + if (!csr_fils_info->fils_r_rk) { + pe_err("failed to alloc memory"); + qdf_mem_free(csr_fils_info->keyname_nai_data); + return; + } + qdf_mem_copy(csr_fils_info->fils_r_rk, + fils_config_info->r_rk, + fils_config_info->r_rk_length); + + qdf_mem_copy(csr_fils_info->fils_pmkid, + fils_config_info->pmkid, PMKID_LEN); + csr_fils_info->rsn_ie_len = sme_join_req->rsnIE.length; + qdf_mem_copy(csr_fils_info->rsn_ie, + sme_join_req->rsnIE.rsnIEdata, + sme_join_req->rsnIE.length); + + csr_fils_info->fils_pmk_len = fils_config_info->pmk_len; + if (fils_config_info->pmk_len) { + csr_fils_info->fils_pmk = + qdf_mem_malloc(fils_config_info->pmk_len); + if (!csr_fils_info->fils_pmk) { + qdf_mem_free(csr_fils_info->keyname_nai_data); + qdf_mem_free(csr_fils_info->fils_r_rk); + pe_err("failed to alloc memory"); + return; + } + qdf_mem_copy(csr_fils_info->fils_pmk, fils_config_info->pmk, + fils_config_info->pmk_len); + } + pe_debug("fils=%d nai-len=%d rrk_len=%d akm=%d auth=%d pmk_len=%d", + fils_config_info->is_fils_connection, + fils_config_info->key_nai_length, + fils_config_info->r_rk_length, + fils_config_info->akm_type, + fils_config_info->auth_type, + fils_config_info->pmk_len); +} + +#define EXTENDED_IE_HEADER_LEN 3 +/** + * lim_create_fils_auth_data()- This API creates the fils auth data + * which needs to be sent in auth req. + * @mac_ctx: mac context + * @auth_frame: pointer to auth frame + * @session: PE session + * + * Return: length of fils data + */ +uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, + tpPESession session) +{ + uint32_t frame_len = 0; + uint32_t wrapped_data_len; + + if (!session->fils_info) + return 0; + + /* These memory may already been allocated if auth retry */ + if (session->fils_info->fils_r_ik) { + qdf_mem_free(session->fils_info->fils_r_ik); + session->fils_info->fils_r_ik = NULL; + } + if (session->fils_info->fils_erp_reauth_pkt) { + qdf_mem_free(session->fils_info->fils_erp_reauth_pkt); + session->fils_info->fils_erp_reauth_pkt = NULL; + } + if (auth_frame->authAlgoNumber == eSIR_FILS_SK_WITHOUT_PFS) { + frame_len += session->fils_info->rsn_ie_len; + /* FILS nounce */ + frame_len += SIR_FILS_NONCE_LENGTH + EXTENDED_IE_HEADER_LEN; + /* FILS Session */ + frame_len += SIR_FILS_SESSION_LENGTH + EXTENDED_IE_HEADER_LEN; + /* Calculate data/length for FILS Wrapped Data */ + wrapped_data_len = + lim_create_fils_wrapper_data(session->fils_info); + if (wrapped_data_len < 0) { + pe_err("failed to create warpped data"); + return 0; + } + frame_len += wrapped_data_len + EXTENDED_IE_HEADER_LEN; + } + return frame_len; +} +#endif diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c index 2f39e45e1897..c290d0976390 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -47,6 +47,7 @@ #endif #include "wma_if.h" #include "wlan_reg_services_api.h" +#include "lim_process_fils.h" static void lim_process_mlm_start_req(tpAniSirGlobal, uint32_t *); static void lim_process_mlm_join_req(tpAniSirGlobal, uint32_t *); @@ -2296,6 +2297,7 @@ static void lim_process_auth_retry_timer(tpAniSirGlobal mac_ctx) auth_frame.authStatusCode = 0; pe_warn("Retry Auth"); mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + lim_increase_fils_sequence_number(session_entry); lim_send_auth_mgmt_frame(mac_ctx, &auth_frame, mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, 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 73d1b5476a84..274c3d90beee 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 @@ -2243,6 +2243,29 @@ end: } } +#ifdef WLAN_FEATURE_FILS_SK +/* + * lim_update_fils_auth_mode: API to update Auth mode in case of fils session + * @session_entry: pe session entry + * @auth_mode: auth mode needs to be updated + * + * Return: None + */ +static void lim_update_fils_auth_mode(tpPESession session_entry, + tAniAuthType *auth_mode) +{ + if (!session_entry->fils_info) + return; + + if (session_entry->fils_info->is_fils_connection) + *auth_mode = session_entry->fils_info->auth; +} +#else +static void lim_update_fils_auth_mode(tpPESession session_entry, + tAniAuthType *auth_mode) +{ } +#endif + /** * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request * @mac_ctx: Pointer to mac context @@ -2295,6 +2318,7 @@ lim_process_sta_add_bss_rsp_pre_assoc(tpAniSirGlobal mac_ctx, else authMode = cfgAuthType; + lim_update_fils_auth_mode(session_entry, &authMode); /* Trigger MAC based Authentication */ pMlmAuthReq = qdf_mem_malloc(sizeof(tLimMlmAuthReq)); if (NULL == pMlmAuthReq) { diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index b74f7c3ef9d6..ac831c229ac0 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -64,6 +64,7 @@ #include #include "cds_regdomain.h" +#include "lim_process_fils.h" /* * This overhead is time for sending NOA start to host in case of GO/sending @@ -1786,6 +1787,7 @@ __lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) session->txLdpcIniFeatureEnabled = sme_join_req->txLdpcIniFeatureEnabled; + lim_update_fils_config(session, sme_join_req); if (session->bssType == eSIR_INFRASTRUCTURE_MODE) { session->limSystemRole = eLIM_STA_ROLE; } else { diff --git a/core/mac/src/pe/lim/lim_security_utils.c b/core/mac/src/pe/lim/lim_security_utils.c index e6d6afbe8e68..18f883e4c212 100644 --- a/core/mac/src/pe/lim/lim_security_utils.c +++ b/core/mac/src/pe/lim/lim_security_utils.c @@ -487,6 +487,29 @@ lim_restore_from_auth_state(tpAniSirGlobal pMac, tSirResultCodes resultCode, lim_post_sme_message(pMac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf); } /*** end lim_restore_from_auth_state() ***/ +#ifdef WLAN_FEATURE_FILS_SK +/* + * lim_get_fils_auth_data_len: This API will return + * extra auth data len in case of fils session + * + * Return: fils data len in auth packet + */ +static int lim_get_fils_auth_data_len(void) +{ + int len = sizeof(tSirMacRsnInfo) + + sizeof(uint8_t) + /* assoc_delay_info */ + SIR_FILS_SESSION_LENGTH + + sizeof(uint8_t) + /* wrapped_data_len */ + SIR_FILS_WRAPPED_DATA_MAX_SIZE + SIR_FILS_NONCE_LENGTH; + return len; +} +#else +static inline int lim_get_fils_auth_data_len(void) +{ + return 0; +} +#endif + /** * lim_encrypt_auth_frame() * @@ -519,8 +542,7 @@ lim_encrypt_auth_frame(tpAniSirGlobal pMac, uint8_t keyId, uint8_t *pKey, uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; uint16_t frame_len; - frame_len = ((tpSirMacAuthFrameBody)pPlainText)->length + - SIR_MAC_AUTH_FRAME_INFO_LEN + SIR_MAC_CHALLENGE_ID_LEN; + frame_len = sizeof(tSirMacAuthFrameBody) - lim_get_fils_auth_data_len(); keyLength += 3; /* Bytes 3-7 of seed is key */ 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 a038d01f6b26..f9cbf7a239df 100644 --- a/core/mac/src/pe/lim/lim_send_management_frames.c +++ b/core/mac/src/pe/lim/lim_send_management_frames.c @@ -63,6 +63,7 @@ #include "wma_types.h" #include #include +#include "lim_process_fils.h" /** * @@ -2083,7 +2084,6 @@ static QDF_STATUS lim_auth_tx_complete_cnf(void *context, * * Return: void */ - void lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx, tpSirMacAuthFrameBody auth_frame, @@ -2147,6 +2147,8 @@ lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx, body_len = SIR_MAC_AUTH_FRAME_INFO_LEN; frame_len = sizeof(tSirMacMgmtHdr) + body_len; + frame_len += lim_create_fils_auth_data(mac_ctx, + auth_frame, session); if (auth_frame->authAlgoNumber == eSIR_FT_AUTH) { if (NULL != session->ftPEContext.pFTPreAuthReq && 0 != session->ftPEContext.pFTPreAuthReq-> @@ -2329,6 +2331,11 @@ alloc_packet: pbssDescription->mdie[0], SIR_MDIE_SIZE); } + } else if (auth_frame->authAlgoNumber == + eSIR_FILS_SK_WITHOUT_PFS) { + /* TODO MDIE */ + pe_debug("appending fils Auth data"); + lim_add_fils_data_to_auth_frame(session, body); } pe_debug("*** Sending Auth seq# %d status %d (%d) to " diff --git a/core/mac/src/pe/lim/lim_ser_des_utils.h b/core/mac/src/pe/lim/lim_ser_des_utils.h index 82b9c48cf7f5..e2b52084c1a9 100644 --- a/core/mac/src/pe/lim/lim_ser_des_utils.h +++ b/core/mac/src/pe/lim/lim_ser_des_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -95,6 +95,31 @@ static inline uint32_t lim_get_u32(uint8_t *ptr) #endif } +/** + * lim_copy_u16_be()- This API copies a u16 value in buffer + * to network byte order + * @ptr: pointer to buffer + * @u16_val: value needs to be copied + * + * Return: None + */ +static inline void lim_copy_u16_be(uint8_t *ptr, uint16_t u16_val) +{ + ptr[0] = u16_val >> 8; + ptr[1] = u16_val & 0xff; +} + +/** + * lim_copy_u16_be()- This API reads u16 value from network byte order buffer + * @ptr: pointer to buffer + * + * Return: 16bit value + */ +static inline uint16_t lim_get_u16_be(uint8_t *buf) +{ + return (buf[0] << 8) | buf[1]; +} + tSirRetStatus lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx, struct sme_send_disassoc_frm_req *disassoc_frm_req, uint8_t *buf); diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c index 957e871600a9..747981c88908 100644 --- a/core/mac/src/pe/lim/lim_session.c +++ b/core/mac/src/pe/lim/lim_session.c @@ -267,6 +267,86 @@ pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx, } #endif +#ifdef WLAN_FEATURE_FILS_SK +/** + * pe_delete_fils_info: API to delete fils session info + * @session: pe session + * + * Return: void + */ +static void pe_delete_fils_info(tpPESession session) +{ + struct pe_fils_session *fils_info; + + if (!session || (session && !session->valid)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("session is not valid")); + return; + } + fils_info = session->fils_info; + if (!fils_info) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("fils info not found")); + return; + } + if (fils_info->keyname_nai_data) + qdf_mem_free(fils_info->keyname_nai_data); + if (fils_info->fils_erp_reauth_pkt) + qdf_mem_free(fils_info->fils_erp_reauth_pkt); + if (fils_info->fils_r_rk) + qdf_mem_free(fils_info->fils_r_rk); + if (fils_info->fils_r_ik) + qdf_mem_free(fils_info->fils_r_ik); + if (fils_info->fils_eap_finish_pkt) + qdf_mem_free(fils_info->fils_eap_finish_pkt); + if (fils_info->fils_rmsk) + qdf_mem_free(fils_info->fils_rmsk); + if (fils_info->fils_pmk) + qdf_mem_free(fils_info->fils_pmk); + if (fils_info->auth_info.keyname) + qdf_mem_free(fils_info->auth_info.keyname); + if (fils_info->auth_info.domain_name) + qdf_mem_free(fils_info->auth_info.domain_name); + qdf_mem_free(fils_info); + session->fils_info = NULL; +} +/** + * pe_init_fils_info: API to initialize fils session info elements to null + * @session: pe session + * + * Return: void + */ +static void pe_init_fils_info(tpPESession session) +{ + struct pe_fils_session *fils_info; + + if (!session || (session && !session->valid)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("session is not valid")); + return; + } + session->fils_info = qdf_mem_malloc(sizeof(struct pe_fils_session)); + fils_info = session->fils_info; + if (!fils_info) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("fils info not found")); + return; + } + fils_info->keyname_nai_data = NULL; + fils_info->fils_erp_reauth_pkt = NULL; + fils_info->fils_r_rk = NULL; + fils_info->fils_r_ik = NULL; + fils_info->fils_eap_finish_pkt = NULL; + fils_info->fils_rmsk = NULL; + fils_info->fils_pmk = NULL; + fils_info->auth_info.keyname = NULL; + fils_info->auth_info.domain_name = NULL; +} +#else +static void pe_delete_fils_info(tpPESession session) { } +static void pe_init_fils_info(tpPESession session) { } +#endif + /** * lim_get_peer_idxpool_size: get number of peer idx pool size * @num_sta: Max number of STA @@ -454,6 +534,7 @@ pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId, if (status != QDF_STATUS_SUCCESS) pe_err("cannot create or start protectionFieldsResetTimer"); } + pe_init_fils_info(session_ptr); pe_init_pmf_comeback_timer(pMac, session_ptr, *sessionId); session_ptr->ht_client_cnt = 0; @@ -746,6 +827,7 @@ void pe_delete_session(tpAniSirGlobal mac_ctx, tpPESession session) qdf_mc_timer_stop(&session->pmfComebackTimer); qdf_mc_timer_destroy(&session->pmfComebackTimer); #endif + pe_delete_fils_info(session); session->valid = false; if (session->access_policy_vendor_ie) 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 00a927e7ee7f..ae1fea99c191 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 @@ -4139,6 +4139,51 @@ sir_convert_beacon_frame2_struct(tpAniSirGlobal pMac, } /* End sir_convert_beacon_frame2_struct. */ +#ifdef WLAN_FEATURE_FILS_SK +/* sir_update_auth_frame2_struct_fils_conf: API to update fils info from auth + * packet type 2 + * @auth: auth packet pointer received from AP + * @auth_frame: data structure needs to be updated + * + * Return: None + */ +static void sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth, + tpSirMacAuthFrameBody auth_frame) +{ + if (auth->AuthAlgo.algo != eSIR_FILS_SK_WITHOUT_PFS) + return; + + if (auth->fils_assoc_delay_info.present) + auth_frame->assoc_delay_info = + auth->fils_assoc_delay_info.assoc_delay_info; + + if (auth->fils_session.present) + qdf_mem_copy(auth_frame->session, auth->fils_session.session, + SIR_FILS_SESSION_LENGTH); + + if (auth->fils_nonce.present) + qdf_mem_copy(auth_frame->nonce, auth->fils_nonce.nonce, + SIR_FILS_NONCE_LENGTH); + + if (auth->fils_wrapped_data.present) { + qdf_mem_copy(auth_frame->wrapped_data, + auth->fils_wrapped_data.wrapped_data, + auth->fils_wrapped_data.num_wrapped_data); + auth_frame->wrapped_data_len = + auth->fils_wrapped_data.num_wrapped_data; + } + if (auth->RSNOpaque.present) { + qdf_mem_copy(auth_frame->rsn_ie.info, auth->RSNOpaque.data, + auth->RSNOpaque.num_data); + auth_frame->rsn_ie.length = auth->RSNOpaque.num_data; + } +} +#else +static void sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth, + tpSirMacAuthFrameBody auth_frame) +{ } +#endif + tSirRetStatus sir_convert_auth_frame2_struct(tpAniSirGlobal pMac, uint8_t *pFrame, @@ -4174,6 +4219,7 @@ sir_convert_auth_frame2_struct(tpAniSirGlobal pMac, qdf_mem_copy(pAuth->challengeText, auth.ChallengeText.text, auth.ChallengeText.num_text); } + sir_update_auth_frame2_struct_fils_conf(&auth, pAuth); return eSIR_SUCCESS; diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index 3a9c577b9bbc..f361c58e4026 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -409,6 +409,10 @@ typedef struct tagCsrScanResultFilter { struct sCsrChannel_ pcl_channels; struct qdf_mac_addr bssid_hint; enum tQDF_ADAPTER_MODE csrPersona; +#ifdef WLAN_FEATURE_FILS_SK + bool realm_check; + uint8_t fils_realm[2]; +#endif } tCsrScanResultFilter; typedef struct sCsrChnPower_ { @@ -999,7 +1003,10 @@ typedef struct tagCsrRoamProfile { bool do_not_roam; uint32_t cac_duration_ms; uint32_t dfs_regdomain; - +#ifdef WLAN_FEATURE_FILS_SK + bool fils_connection; + struct cds_fils_connection_info *fils_con_info; +#endif } tCsrRoamProfile; #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index 4e246cdd9210..ac15f00b4773 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -968,6 +968,8 @@ typedef struct tagCsrRoamSession { uint8_t uapsd_mask; struct scan_cmd_info scan_info; qdf_mc_timer_t roaming_offload_timer; + bool is_fils_connection; + uint16_t fils_seq_num; } tCsrRoamSession; typedef struct tagCsrRoamStruct { diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index fa0994052ad5..3d8e91c56017 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -54,6 +54,7 @@ #include "sme_nan_datapath.h" #include "pld_common.h" #include "wlan_reg_services_api.h" +#include "qdf_crypto.h" #include #include "wlan_objmgr_psoc_obj.h" #include @@ -7493,6 +7494,38 @@ static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, return release_cmd; } +#ifdef WLAN_FEATURE_FILS_SK +/* + * update_profile_fils_info: API to update FILS info from + * source profile to destination profile. + * @des_profile: pointer to destination profile + * @src_profile: pointer to souce profile + * + * Return: None + */ +static inline void update_profile_fils_info(tCsrRoamProfile *des_profile, + tCsrRoamProfile *src_profile) +{ + if (!src_profile->fils_con_info) + return; + + if (src_profile->fils_con_info->is_fils_connection) { + des_profile->fils_con_info = + qdf_mem_malloc(sizeof(struct cds_fils_connection_info)); + if (!des_profile->fils_con_info) { + sme_err("failed to allocate memory"); + return; + } + qdf_mem_copy(des_profile->fils_con_info, + src_profile->fils_con_info, + sizeof(struct cds_fils_connection_info)); + } +} +#else +static inline void update_profile_fils_info(tCsrRoamProfile *des_profile, + tCsrRoamProfile *src_profile) +{ } +#endif QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pDstProfile, tCsrRoamProfile *pSrcProfile) @@ -7664,6 +7697,9 @@ QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, } qdf_mem_copy(&pDstProfile->addIeParams, &pSrcProfile->addIeParams, sizeof(tSirAddIeParams)); + + update_profile_fils_info(pDstProfile, pSrcProfile); + if (pSrcProfile->supported_rates.numRates) { qdf_mem_copy(pDstProfile->supported_rates.rate, pSrcProfile->supported_rates.rate, @@ -7943,6 +7979,27 @@ QDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason, return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_FILS_SK +/** + * csr_is_fils_connection() - API to check if FILS connection + * @profile: CSR Roam Profile + * + * Return: true, if fils connection, false otherwise + */ +static bool csr_is_fils_connection(tCsrRoamProfile *profile) +{ + if (!profile->fils_con_info) + return false; + + return profile->fils_con_info->is_fils_connection; +} +#else +static bool csr_is_fils_connection(tCsrRoamProfile *pProfile) +{ + return false; +} +#endif + QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, tCsrRoamProfile *pProfile, uint32_t *pRoamId) @@ -7974,6 +8031,7 @@ QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, /* Initialize the count before proceeding with the Join requests */ pSession->join_bssid_count = 0; + pSession->is_fils_connection = csr_is_fils_connection(pProfile); sme_debug( "called BSSType = %s (%d) authtype = %d encryType = %d", sme_bss_type_to_string(pProfile->BSSType), @@ -10346,6 +10404,62 @@ QDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, return status; } +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_create_fils_realm_hash: API to create hash using realm + * @fils_con_info: fils connection info obtained from supplicant + * @tmp_hash: pointer to new hash + * + * Return: None + */ +static bool +csr_create_fils_realm_hash(struct cds_fils_connection_info *fils_con_info, + uint8_t *tmp_hash) +{ + uint8_t hash[SHA256_DIGEST_SIZE] = {0}; + uint8_t *data[1]; + + if (!fils_con_info->realm_len) + return false; + + data[0] = fils_con_info->realm; + qdf_get_hash(SHA256_CRYPTO_TYPE, 1, data, + &fils_con_info->realm_len, hash); + qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + hash, SHA256_DIGEST_SIZE); + qdf_mem_copy(tmp_hash, hash, 2); + return true; +} + +/* + * csr_update_fils_scan_filter: update scan filter in case of fils session + * @scan_fltr: pointer to scan filer + * @profile: csr profile pointer + * + * Return: None + */ +static void csr_update_fils_scan_filter(tCsrScanResultFilter *scan_fltr, + tCsrRoamProfile *profile) +{ + if (profile->fils_con_info && + profile->fils_con_info->is_fils_connection) { + uint8_t realm_hash[2]; + + sme_debug("creating realm based on fils info %d", + profile->fils_con_info->is_fils_connection); + scan_fltr->realm_check = csr_create_fils_realm_hash( + profile->fils_con_info, realm_hash); + memcpy(scan_fltr->fils_realm, realm_hash, + sizeof(uint8_t) * 2); + } + +} +#else +static void csr_update_fils_scan_filter(tCsrScanResultFilter *scan_fltr, + tCsrRoamProfile *profile) +{ } +#endif + /* * Prepare a filter base on a profile for parsing the scan results. * Upon successful return, caller MUST call csr_free_scan_filter on @@ -10500,6 +10614,7 @@ csr_roam_prepare_filter_from_profile(tpAniSirGlobal mac_ctx, scan_fltr->MFPCapable = profile->MFPCapable; #endif scan_fltr->csrPersona = profile->csrPersona; + csr_update_fils_scan_filter(scan_fltr, profile); free_filter: if (!QDF_IS_STATUS_SUCCESS(status)) @@ -13813,11 +13928,12 @@ QDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, pmksa->cache_id, CACHE_ID_LEN))) fMatchFound = 1; - if (fMatchFound) - /* Clear this - the matched entry */ + if (fMatchFound) { + /* Clear this - matched entry */ qdf_mem_zero(cached_pmksa, sizeof(tPmkidCacheInfo)); break; + } } if (Index == CSR_MAX_PMKID_ALLOWED && !fMatchFound) { @@ -14241,6 +14357,34 @@ static inline void csr_set_mgmt_enc_type(tCsrRoamProfile *profile, } #endif +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_update_fils_connection_info: Copy fils connection info to join request + * @profile: pointer to profile + * @csr_join_req: csr join request + * + * Return: None + */ +static void csr_update_fils_connection_info(tCsrRoamProfile *profile, + tSirSmeJoinReq *csr_join_req) +{ + if (!profile->fils_con_info) + return; + + if (profile->fils_con_info->is_fils_connection) { + qdf_mem_copy(&csr_join_req->fils_con_info, + profile->fils_con_info, + sizeof(struct cds_fils_connection_info)); + } else { + qdf_mem_zero(&csr_join_req->fils_con_info, + sizeof(struct cds_fils_connection_info)); + } +} +#else +static void csr_update_fils_connection_info(tCsrRoamProfile *profile, + tSirSmeJoinReq *csr_join_req) +{ } +#endif /** * The communication between HDD and LIM is thru mailbox (MB). @@ -14912,7 +15056,7 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, qdf_mem_copy(&csr_join_req->bssDescription, pBssDescription, pBssDescription->length + sizeof(pBssDescription->length)); - + csr_update_fils_connection_info(pProfile, csr_join_req); /* * conc_custom_rule1: * If SAP comes up first and STA comes up later then SAP diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c index 9b1c6c77e92b..bcec9aacb5d3 100644 --- a/core/sme/src/csr/csr_api_scan.c +++ b/core/sme/src/csr/csr_api_scan.c @@ -5508,6 +5508,12 @@ static QDF_STATUS csr_prepare_scan_filter(tpAniSirGlobal mac_ctx, pFilter->ChannelInfo.ChannelList, filter->num_of_channels); + if (pFilter->realm_check) { + filter->fils_scan_filter.realm_check = true; + qdf_mem_copy(filter->fils_scan_filter.fils_realm, + pFilter->fils_realm, REAM_HASH_LEN); + } + filter->num_of_auth = pFilter->authType.numEntries; if (filter->num_of_auth > WLAN_NUM_OF_SUPPORT_AUTH_TYPE) @@ -5590,7 +5596,8 @@ static void csr_update_bss_with_fils_data(tpAniSirGlobal mac_ctx, return; dot11f_unpack_ie_fils_indication(mac_ctx, - scan_entry->ie_list.fils_indication, + scan_entry->ie_list.fils_indication + + SIR_FILS_IND_ELEM_OFFSET, *(scan_entry->ie_list.fils_indication + 1), &fils_indication, false); diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c index fefec6724a4e..7072570a4d14 100644 --- a/core/sme/src/csr/csr_util.c +++ b/core/sme/src/csr/csr_util.c @@ -3716,6 +3716,73 @@ static bool csr_lookup_pmkid(tpAniSirGlobal pMac, uint32_t sessionId, return fRC; } +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_update_pmksa_for_cache_id: update tPmkidCacheInfo to lookup using + * ssid and cache id + * @bss_desc: bss description + * @profile: csr roam profile + * @pmkid_cache: pmksa cache + * + * Return: true if cache identifier present else false + */ +static bool csr_update_pmksa_for_cache_id(tSirBssDescription *bss_desc, + tCsrRoamProfile *profile, + tPmkidCacheInfo *pmkid_cache) +{ + if (!bss_desc->fils_info_element.is_cache_id_present) + return false; + + pmkid_cache->ssid_len = + profile->SSIDs.SSIDList[0].SSID.length; + qdf_mem_copy(pmkid_cache->ssid, + profile->SSIDs.SSIDList[0].SSID.ssId, + profile->SSIDs.SSIDList[0].SSID.length); + qdf_mem_copy(pmkid_cache->cache_id, + bss_desc->fils_info_element.cache_id, + CACHE_ID_LEN); + qdf_mem_copy(pmkid_cache->BSSID.bytes, + bss_desc->bssId, QDF_MAC_ADDR_SIZE); + + return true; + +} + +/* + * csr_update_pmksa_to_profile: update pmk and pmkid to profile which will be + * used in case of fils session + * @profile: profile + * @pmkid_cache: pmksa cache + * + * Return: None + */ +static inline void csr_update_pmksa_to_profile(tCsrRoamProfile *profile, + tPmkidCacheInfo *pmkid_cache) +{ + if (!profile->fils_con_info) + return; + + profile->fils_con_info->pmk_len = pmkid_cache->pmk_len; + qdf_mem_copy(profile->fils_con_info->pmk, + pmkid_cache->pmk, pmkid_cache->pmk_len); + qdf_mem_copy(profile->fils_con_info->pmkid, + pmkid_cache->PMKID, CSR_RSN_PMKID_SIZE); + +} +#else +static inline bool csr_update_pmksa_for_cache_id(tSirBssDescription *bss_desc, + tCsrRoamProfile *profile, + tPmkidCacheInfo *pmkid_cache) +{ + return false; +} + +static inline void csr_update_pmksa_to_profile(tCsrRoamProfile *profile, + tPmkidCacheInfo *pmkid_cache) +{ +} +#endif + uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, tCsrRoamProfile *pProfile, tSirBssDescription *pSirBssDesc, @@ -3803,7 +3870,9 @@ uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, pPMK = (tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1])) + sizeof(uint16_t)); - qdf_mem_copy(pmkid_cache.BSSID.bytes, + if (!csr_update_pmksa_for_cache_id(pSirBssDesc, + pProfile, &pmkid_cache)) + qdf_mem_copy(pmkid_cache.BSSID.bytes, pSirBssDesc->bssId, QDF_MAC_ADDR_SIZE); /* Don't include the PMK SA IDs for CCKM associations. */ if ( @@ -3819,8 +3888,10 @@ uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, qdf_mem_copy(pPMK->PMKIDList[0].PMKID, pmkid_cache.PMKID, CSR_RSN_PMKID_SIZE); - } else + csr_update_pmksa_to_profile(pProfile, &pmkid_cache); + } else { pPMK->cPMKIDs = 0; + } #ifdef WLAN_FEATURE_11W /* Advertise BIP in group cipher key management only if PMF is @@ -5448,6 +5519,41 @@ static bool csr_is_rate_set_match(tpAniSirGlobal mac_ctx, return match; } +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_is_fils_realm_match: API to check whether realm in scan filter is + * matching with realm in bss info + * @bss_descr: bss description + * @filter: scan filter + * + * Return: true if success else false + */ +static bool csr_is_fils_realm_match(tSirBssDescription *bss_descr, + tCsrScanResultFilter *filter) +{ + int i; + bool is_match = true; + + if (filter->realm_check) { + is_match = false; + for (i = 0; i < bss_descr->fils_info_element.realm_cnt; i++) { + if (!qdf_mem_cmp(filter->fils_realm, + bss_descr->fils_info_element.realm[i], + SIR_REALM_LEN)) { + return true; + } + } + } + + return is_match; +} +#else +static bool csr_is_fils_realm_match(tSirBssDescription *bss_descr, + tCsrScanResultFilter *filter) +{ + return true; +} +#endif /** * csr_match_bss() - to compare the bss * @hal: pointer to hal context @@ -5611,6 +5717,8 @@ bool csr_match_bss(tHalHandle hal, tSirBssDescription *bss_descr, } } rc = true; + if (rc) + rc = csr_is_fils_realm_match(bss_descr, filter); end: if (ie_dblptr) @@ -5936,6 +6044,19 @@ uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, return nBest; } +#ifdef WLAN_FEATURE_FILS_SK +static inline void csr_free_fils_profile_info(tCsrRoamProfile *profile) +{ + if (profile->fils_con_info) { + qdf_mem_free(profile->fils_con_info); + profile->fils_con_info = NULL; + } +} +#else +static inline void csr_free_fils_profile_info(tCsrRoamProfile *profile) +{ } +#endif + void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile) { if (pProfile) { @@ -5975,6 +6096,7 @@ void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile) qdf_mem_free(pProfile->ChannelInfo.ChannelList); pProfile->ChannelInfo.ChannelList = NULL; } + csr_free_fils_profile_info(pProfile); qdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0); } }