qcacld-3.0: Changes to support FILS authentication
Add changes to add support of sending and parsing
authentication packets based on 80211ai specifications.
Change-Id: I684dbc89945ba3aef3186c872e5e1f7564d7e44c
CRs-Fixed: 2028113
diff --git a/Kbuild b/Kbuild
index 16831f5..be748a8 100644
--- a/Kbuild
+++ b/Kbuild
@@ -109,6 +109,8 @@
#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 @@
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_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 @@
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 8e4f47f..a52158f 100644
--- a/core/cds/inc/cds_config.h
+++ b/core/cds/inc/cds_config.h
@@ -164,4 +164,27 @@
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 cb3f6f4..fe9ba8c 100644
--- a/core/cds/inc/cds_utils.h
+++ b/core/cds/inc/cds_utils.h
@@ -126,6 +126,15 @@
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 8eaa2f5..3350a31 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 @@
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 caca6e4..ad5cbb2 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -2637,4 +2637,17 @@
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 26c85c8..b2ba1ae 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -2485,6 +2485,23 @@
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 @@
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 @@
#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 @@
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 f63ab78..3ef2861 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -1759,7 +1759,7 @@
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 @@
#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 @@
#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 @@
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 @@
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_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 @@
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 @@
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 @@
/*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 @@
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 3a656db..4610744 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 e32b203..7d5d683 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -4277,6 +4277,7 @@
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 @@
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 e4b17ad..07e59f5 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -14248,6 +14248,16 @@
}
+#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 @@
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 7cc076f..99fd5ee 100644
--- a/core/mac/inc/ani_system_defs.h
+++ b/core/mac/inc/ani_system_defs.h
@@ -72,6 +72,9 @@
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 763e1c9..548d95e 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -67,6 +67,8 @@
#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 @@
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 6436de3..50ecb79 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 <lim_fils_defs.h>
/* /Capability information related */
#define CAPABILITY_INFO_DELAYED_BA_BIT 14
@@ -1955,6 +1956,14 @@
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 a5762b4..25f9200 100644
--- a/core/mac/src/include/parser_api.h
+++ b/core/mac/src/include/parser_api.h
@@ -115,7 +115,7 @@
#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 0000000..c3619cb
--- /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 0000000..5070bb2
--- /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 <cds_api.h>
+#include <lim_global.h>
+#include <ani_global.h>
+#include <lim_ser_des_utils.h>
+
+#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 cd8d835..cb0de7b 100644
--- a/core/mac/src/pe/include/lim_session.h
+++ b/core/mac/src/pe/include/lim_session.h
@@ -519,6 +519,9 @@
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 a1f5ec9..a2a6b4d 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 @@
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 @@
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 @@
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_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 @@
* 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 @@
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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
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 @@
(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 @@
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 @@
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 0000000..79e8df3
--- /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 <lim_send_messages.h>
+#include <lim_types.h>
+#include <lim_utils.h>
+#include <lim_prop_exts_utils.h>
+#include <lim_assoc_utils.h>
+#include <lim_session.h>
+#include <cds_ieee80211_defines.h>
+#include <qdf_crypto.h>
+
+#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 2f39e45..c290d09 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 @@
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 73d1b54..274c3d9 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 @@
}
}
+#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 @@
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 b74f7c3..ac831c2 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 <lim_ft.h>
#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 @@
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 e6d6afb..18f883e 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_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 @@
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 a038d01..f9cbf7a 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 <cdp_txrx_cmn.h>
#include <cdp_txrx_peer_ops.h>
+#include "lim_process_fils.h"
/**
*
@@ -2083,7 +2084,6 @@
*
* Return: void
*/
-
void
lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx,
tpSirMacAuthFrameBody auth_frame,
@@ -2147,6 +2147,8 @@
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 @@
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 82b9c48..e2b5208 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 @@
#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 957e871..747981c 100644
--- a/core/mac/src/pe/lim/lim_session.c
+++ b/core/mac/src/pe/lim/lim_session.c
@@ -267,6 +267,86 @@
}
#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 @@
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 @@
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 00a927e..ae1fea9 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 @@
} /* 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 @@
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 3a9c577..f361c58 100644
--- a/core/sme/inc/csr_api.h
+++ b/core/sme/inc/csr_api.h
@@ -409,6 +409,10 @@
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 @@
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 4e246cd..ac15f00 100644
--- a/core/sme/inc/csr_internal.h
+++ b/core/sme/inc/csr_internal.h
@@ -968,6 +968,8 @@
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 fa09940..3d8e91c 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 <wlan_logging_sock_svc.h>
#include "wlan_objmgr_psoc_obj.h"
#include <wlan_scan_ucfg_api.h>
@@ -7493,6 +7494,38 @@
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_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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
}
#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_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 9b1c6c7..bcec9aa 100644
--- a/core/sme/src/csr/csr_api_scan.c
+++ b/core/sme/src/csr/csr_api_scan.c
@@ -5508,6 +5508,12 @@
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 @@
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 fefec67..7072570 100644
--- a/core/sme/src/csr/csr_util.c
+++ b/core/sme/src/csr/csr_util.c
@@ -3716,6 +3716,73 @@
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 @@
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 @@
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 @@
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 @@
}
}
rc = true;
+ if (rc)
+ rc = csr_is_fils_realm_match(bss_descr, filter);
end:
if (ie_dblptr)
@@ -5936,6 +6044,19 @@
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 @@
qdf_mem_free(pProfile->ChannelInfo.ChannelList);
pProfile->ChannelInfo.ChannelList = NULL;
}
+ csr_free_fils_profile_info(pProfile);
qdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
}
}