Browse Source

qcacmn: Add FILS AEAD crypto

Add aes_ctr, aes_siv and FILS AEAD crypto module.
This includes FILS AEAD encrypt and decrypt functions.

Change-Id: Ibbeb28ea53c91ad473247015335b593bc8038485
CRs-Fixed: 2093478
Subrat Mishra 7 years ago
parent
commit
2b75d6df39

+ 45 - 0
umac/cmn_services/crypto/inc/wlan_crypto_fils_api.h

@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef _WLAN_CRYPTO_FILS_API_H_
+#define _WLAN_CRYPTO_FILS_API_H_
+
+/**
+ * fils_register() - Register all callback functions to Crypto manager
+ *
+ * This function is invoked from crypto object manager to register
+ * FILS specific callbacks.
+ *
+ * Return: Pointer to wlan_crypto_cipher Object
+ */
+const struct wlan_crypto_cipher *fils_register(void);
+
+#ifdef WLAN_SUPPORT_FILS
+/**
+ * wlan_crypto_fils_delkey - Delete fils aad key
+ * @peer: Peer object
+ *
+ * This function delete the peer specific FILS AAD key data.
+ *
+ * Return: None
+ */
+void wlan_crypto_fils_delkey(struct wlan_objmgr_peer *peer);
+#endif /* WLAN_SUPPORT_FILS */
+
+#endif /* End of _WLAN_CRYPTO_FILS_API_H_ */
+

+ 49 - 0
umac/cmn_services/crypto/inc/wlan_crypto_fils_def.h

@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef _WLAN_CRYPTO_FILS_DEF_H_
+#define _WLAN_CRYPTO_FILS_DEF_H_
+
+/* Element ID Extension (EID 255) values */
+#define WLAN_ELEMID_EXT_ASSOC_DELAY_INFO       (1)
+#define WLAN_ELEMID_EXT_FILS_REQ_PARAMS        (2)
+#define WLAN_ELEMID_EXT_FILS_KEY_CONFIRM       (3)
+#define WLAN_ELEMID_EXT_FILS_SESSION           (4)
+#define WLAN_ELEMID_EXT_FILS_HLP_CONTAINER     (5)
+#define WLAN_ELEMID_EXT_FILS_IP_ADDR_ASSIGN    (6)
+#define WLAN_ELEMID_EXT_KEY_DELIVERY           (7)
+#define WLAN_ELEMID_EXT_FILS_WRAPPED_DATA      (8)
+#define WLAN_ELEMID_EXT_FILS_PUBLIC_KEY        (12)
+#define WLAN_ELEMID_EXT_FILS_NONCE             (13)
+
+#define WLAN_MAX_WPA_KEK_LEN                   (64)
+#define WLAN_FILS_NONCE_LEN                    (16)
+
+/* FILS AAD Crypto key data */
+struct wlan_crypto_fils_aad_key {
+	/* FILS aad ANounce */
+	uint8_t    a_nonce[WLAN_FILS_NONCE_LEN];
+	/* FILS aad SNounce */
+	uint8_t    s_nonce[WLAN_FILS_NONCE_LEN];
+	/* FILS aad kek */
+	uint8_t    kek[WLAN_MAX_WPA_KEK_LEN];
+	/* FILS aad kek length */
+	uint32_t   kek_len;
+};
+#endif /* end of _WLAN_CRYPTO_FILS_DEF_H_ */
+

+ 22 - 0
umac/cmn_services/crypto/inc/wlan_crypto_global_api.h

@@ -441,4 +441,26 @@ bool wlan_crypto_vdev_has_auth_mode(struct wlan_objmgr_vdev *vdev,
  */
 bool wlan_crypto_peer_has_auth_mode(struct wlan_objmgr_peer *peer,
 					wlan_crypto_auth_mode authvalue);
+
+/**
+ * wlan_crypto_get_peer_fils_aead - Get peer fils aead set flag
+ * @peer: Peer object
+ *
+ * This function returns the peer fils aead set flag value.
+ *
+ * Return: 1 for enabled, 0 for disabled
+ */
+uint8_t wlan_crypto_get_peer_fils_aead(struct wlan_objmgr_peer *peer);
+
+/**
+ * wlan_crypto_set_peer_fils_aead - Set peer fils aead set flag
+ * @peer: Peer object
+ * @value: Value to set the flag
+ *
+ * This function set the peer fils aead set flag once FILS AUTH received.
+ *
+ * Return: None
+ */
+void wlan_crypto_set_peer_fils_aead(
+			struct wlan_objmgr_peer *peer, uint8_t value);
 #endif /* end of _WLAN_CRYPTO_GLOBAL_API_H_ */

+ 6 - 1
umac/cmn_services/crypto/inc/wlan_crypto_global_def.h

@@ -24,6 +24,7 @@
 #define _WLAN_CRYPTO_GLOBAL_DEF_H_
 
 #include <wlan_cmn.h>
+#include "wlan_crypto_fils_def.h"
 
 #define WLAN_CRYPTO_TID_SIZE         (17)
 #define WLAN_CRYPTO_KEYBUF_SIZE      (32)
@@ -100,7 +101,8 @@ typedef enum wlan_crypto_cipher_type {
 	WLAN_CRYPTO_CIPHER_AES_GMAC     = 11,
 	WLAN_CRYPTO_CIPHER_AES_GMAC_256 = 12,
 	WLAN_CRYPTO_CIPHER_WAPI_GCM4    = 13,
-	WLAN_CRYPTO_CIPHER_NONE         = 14,
+	WLAN_CRYPTO_CIPHER_FILS_AEAD    = 14,
+	WLAN_CRYPTO_CIPHER_NONE         = 15,
 	WLAN_CRYPTO_CIPHER_MAX          = WLAN_CRYPTO_CIPHER_NONE,
 } wlan_crypto_cipher_type;
 
@@ -136,6 +138,7 @@ typedef enum wlan_crypto_cap {
 	WLAN_CRYPTO_CAP_PMF              = 14,
 	WLAN_CRYPTO_CAP_PMF_OFFLOAD      = 15,
 	WLAN_CRYPTO_CAP_PN_TID_BASED     = 16,
+	WLAN_CRYPTO_CAP_FILS_AEAD        = 17,
 } wlan_crypto_cap;
 
 typedef enum wlan_crypto_rsn_cap {
@@ -248,6 +251,8 @@ struct wlan_crypto_req_key {
 	uint8_t    txiv[WLAN_CRYPTO_WAPI_IV_SIZE];
 	/* wapi key rx iv */
 	uint8_t    recviv[WLAN_CRYPTO_WAPI_IV_SIZE];
+	/* FILS AEAD data */
+	struct     wlan_crypto_fils_aad_key   filsaad;
 };
 
 /**

+ 63 - 0
umac/cmn_services/crypto/src/wlan_crypto_aes_ctr.c

@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * AES-128/192/256 CTR
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <[email protected]>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef WLAN_SUPPORT_FILS
+
+#include <qdf_crypto.h>
+#include "wlan_crypto_aes_i.h"
+
+int32_t wlan_crypto_aes_ctr_encrypt(const uint8_t *key, size_t key_len,
+				    const uint8_t *nonce, uint8_t *data,
+				    size_t data_len)
+{
+	void *ctx;
+	size_t j, len, left = data_len;
+	int32_t i;
+	uint8_t *pos = data;
+	uint8_t counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+	int32_t status = -1;
+
+	ctx = wlan_crypto_aes_encrypt_init(key, key_len);
+	if (!ctx)
+		return status;
+
+	qdf_mem_copy(counter, nonce, AES_BLOCK_SIZE);
+
+	while (left > 0) {
+		wlan_crypto_aes_encrypt(ctx, counter, buf);
+
+		len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
+		for (j = 0; j < len; j++)
+			pos[j] ^= buf[j];
+		pos += len;
+		left -= len;
+
+		for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+			counter[i]++;
+			if (counter[i])
+				break;
+		}
+	}
+	wlan_crypto_aes_encrypt_deinit(ctx);
+
+	return 0;
+}
+
+int32_t wlan_crypto_aes_128_ctr_encrypt(const uint8_t *key,
+					const uint8_t *nonce, uint8_t *data,
+					size_t data_len)
+{
+	return wlan_crypto_aes_ctr_encrypt(key, 16, nonce, data, data_len);
+}
+
+#endif /* WLAN_SUPPORT_FILS */

+ 47 - 0
umac/cmn_services/crypto/src/wlan_crypto_aes_ctr_i.h

@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * AES functions
+ *
+ * Copyright (c) 2003-2006, Jouni Malinen <[email protected]>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef _WLAN_CRYPTO_AES_CTR_I_H_
+#define _WLAN_CRYPTO_AES_CTR_I_H_
+
+#ifdef WLAN_SUPPORT_FILS
+/**
+ * wlan_crypto_aes_ctr_encrypt - AES-128/192/256 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @key_len: Length of the key (16, 24, or 32 bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int32_t wlan_crypto_aes_ctr_encrypt(const uint8_t *key, size_t key_len,
+				    const uint8_t *nonce, uint8_t *data,
+				    size_t data_len);
+
+/**
+ * wlan_crypto_aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int32_t wlan_crypto_aes_128_ctr_encrypt(const uint8_t *key,
+					const uint8_t *nonce, uint8_t *data,
+					size_t data_len);
+#endif /* WLAN_SUPPORT_FILS */
+
+#endif /* end of _WLAN_CRYPTO_AES_CTR_I_H_ */
+

+ 2 - 0
umac/cmn_services/crypto/src/wlan_crypto_aes_i.h

@@ -252,4 +252,6 @@ int omac1_aes_128(const uint8_t *key, const uint8_t *data,
 				size_t data_len, uint8_t *mac);
 int omac1_aes_256(const uint8_t *key, const uint8_t *data,
 				size_t data_len, uint8_t *mac);
+int omac1_aes_vector(const uint8_t *key, size_t key_len, size_t num_elem,
+		     const uint8_t *addr[], const size_t *len, uint8_t *mac);
 #endif /* WLAN_CRYPTO_AES_I_H */

+ 213 - 0
umac/cmn_services/crypto/src/wlan_crypto_aes_siv.c

@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef WLAN_SUPPORT_FILS
+
+#include <qdf_crypto.h>
+#include <wlan_crypto_aes_i.h>
+#include "wlan_crypto_aes_ctr_i.h"
+
+static const uint8_t zero[AES_BLOCK_SIZE];
+
+static void dbl(uint8_t *pad)
+{
+	int32_t i, carry;
+
+	carry = pad[0] & 0x80;
+	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+	pad[AES_BLOCK_SIZE - 1] <<= 1;
+	if (carry)
+		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+static void xor(uint8_t *a, const uint8_t *b)
+{
+	int32_t i;
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		*a++ ^= *b++;
+}
+
+static void xorend(uint8_t *a, int32_t alen, const uint8_t *b, int32_t blen)
+{
+	int32_t i;
+
+	if (alen < blen)
+		return;
+
+	for (i = 0; i < blen; i++)
+		a[alen - blen + i] ^= b[i];
+}
+
+static void pad_block(uint8_t *pad, const uint8_t *addr, size_t len)
+{
+	qdf_mem_zero(pad, AES_BLOCK_SIZE);
+	qdf_mem_copy(pad, addr, len);
+
+	if (len < AES_BLOCK_SIZE)
+		pad[len] = 0x80;
+}
+
+static int32_t
+aes_s2v(const uint8_t *key, size_t key_len, size_t num_elem,
+	const uint8_t *addr[], size_t *len, uint8_t *mac)
+{
+	uint8_t tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
+	uint8_t *buf = NULL;
+	int32_t ret = -1;
+	size_t i;
+	const uint8_t *data[1];
+	size_t data_len[1];
+
+	if (!num_elem) {
+		qdf_mem_copy(tmp, zero, sizeof(zero));
+		tmp[AES_BLOCK_SIZE - 1] = 1;
+		data[0] = tmp;
+		data_len[0] = sizeof(tmp);
+		return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
+	}
+
+	data[0] = zero;
+	data_len[0] = sizeof(zero);
+	ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num_elem - 1; i++) {
+		ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
+				       tmp2);
+		if (ret)
+			return ret;
+
+		dbl(tmp);
+		xor(tmp, tmp2);
+	}
+	if (len[i] >= AES_BLOCK_SIZE) {
+		buf = OS_MALLOC(NULL, len[i], GFP_ATOMIC);
+		if (!buf)
+			return -ENOMEM;
+
+		qdf_mem_copy(buf, addr[i], len[i]);
+		xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
+		data[0] = buf;
+		ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
+		memset(buf, 0, len[i]);
+		OS_FREE(buf);
+		return ret;
+	}
+
+	dbl(tmp);
+	pad_block(tmp2, addr[i], len[i]);
+	xor(tmp, tmp2);
+
+	data[0] = tmp;
+	data_len[0] = sizeof(tmp);
+
+	return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
+}
+
+int32_t wlan_crypto_aes_siv_encrypt(const uint8_t *key, size_t key_len,
+				    const uint8_t *pw, size_t pwlen,
+				    size_t num_elem, const uint8_t *addr[],
+				    const size_t *len, uint8_t *out)
+{
+	const uint8_t *_addr[6];
+	size_t _len[6];
+	const uint8_t *k1, *k2;
+	uint8_t v[AES_BLOCK_SIZE];
+	size_t i;
+	uint8_t *iv, *crypt_pw;
+	int32_t status = -1;
+
+	if (num_elem > ARRAY_SIZE(_addr) - 1 ||
+	    (key_len != 32 && key_len != 48 && key_len != 64))
+		return status;
+
+	key_len /= 2;
+	k1 = key;
+	k2 = key + key_len;
+
+	for (i = 0; i < num_elem; i++) {
+		_addr[i] = addr[i];
+		_len[i] = len[i];
+	}
+	_addr[num_elem] = pw;
+	_len[num_elem] = pwlen;
+
+	if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
+		return status;
+
+	iv = out;
+	crypt_pw = out + AES_BLOCK_SIZE;
+
+	qdf_mem_copy(iv, v, AES_BLOCK_SIZE);
+	qdf_mem_copy(crypt_pw, pw, pwlen);
+
+	/* zero out 63rd and 31st bits of ctr (from right) */
+	v[8] &= 0x7f;
+	v[12] &= 0x7f;
+
+	return wlan_crypto_aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
+}
+
+int32_t wlan_crypto_aes_siv_decrypt(const uint8_t *key, size_t key_len,
+				    const uint8_t *iv_crypt, size_t iv_c_len,
+				    size_t num_elem, const uint8_t *addr[],
+				    const size_t *len, uint8_t *out)
+{
+	const uint8_t *_addr[6];
+	size_t _len[6];
+	const uint8_t *k1, *k2;
+	size_t crypt_len;
+	size_t i;
+	int32_t ret = -1;
+	uint8_t iv[AES_BLOCK_SIZE];
+	uint8_t check[AES_BLOCK_SIZE];
+
+	if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
+	    (key_len != 32 && key_len != 48 && key_len != 64))
+		return ret;
+
+	crypt_len = iv_c_len - AES_BLOCK_SIZE;
+	key_len /= 2;
+	k1 = key;
+	k2 = key + key_len;
+
+	for (i = 0; i < num_elem; i++) {
+		_addr[i] = addr[i];
+		_len[i] = len[i];
+	}
+	_addr[num_elem] = out;
+	_len[num_elem] = crypt_len;
+
+	qdf_mem_copy(iv, iv_crypt, AES_BLOCK_SIZE);
+	qdf_mem_copy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
+
+	iv[8] &= 0x7f;
+	iv[12] &= 0x7f;
+
+	ret = wlan_crypto_aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
+	if (ret)
+		return ret;
+
+	ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
+	if (ret)
+		return ret;
+
+	if (qdf_mem_cmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
+		return 0;
+
+	return ret;
+}
+
+#endif /* WLAN_SUPPORT_FILS */

+ 29 - 0
umac/cmn_services/crypto/src/wlan_crypto_aes_siv_i.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef _WLAN_CRYPTO_AES_SIV_I_H_
+#define _WLAN_CRYPTO_AES_SIV_I_H_
+
+#ifdef WLAN_SUPPORT_FILS
+int32_t wlan_crypto_aes_siv_encrypt(const uint8_t *key, size_t key_len,
+				    const uint8_t *pw, size_t pwlen,
+				    size_t num_elem, const uint8_t *addr[],
+				    const size_t *len, uint8_t *out);
+
+int32_t wlan_crypto_aes_siv_decrypt(const uint8_t *key, size_t key_len,
+				    const uint8_t *iv_crypt, size_t iv_c_len,
+				    size_t num_elem, const uint8_t *addr[],
+				    const size_t *len, uint8_t *out);
+#endif /* WLAN_SUPPORT_FILS */
+
+#endif /* end of _WLAN_CRYPTO_AES_SIV_I_H_ */
+

+ 3 - 0
umac/cmn_services/crypto/src/wlan_crypto_def_i.h

@@ -341,6 +341,8 @@ static inline void wlan_crypto_put_be64(u8 *a, u64 val)
 				 (_c == WLAN_CRYPTO_CIPHER_AES_GMAC) || \
 				 (_c == WLAN_CRYPTO_CIPHER_AES_GMAC_256))
 
+#define IS_FILS_CIPHER(_c)      ((_c) == WLAN_CRYPTO_CIPHER_FILS_AEAD)
+
 #define MGMT_CIPHER_IS_CMAC(_param)    \
 		HAS_MGMT_CIPHER((_param), WLAN_CRYPTO_CIPHER_AES_CMAC)
 #define MGMT_CIPHER_IS_CMAC256(_param) \
@@ -388,6 +390,7 @@ struct wlan_crypto_comp_priv {
 	uint32_t igtk_key_type;
 	uint8_t def_tx_keyid;
 	uint8_t def_igtk_tx_keyid;
+	uint8_t fils_aead_set;
 };
 
 

+ 476 - 0
umac/cmn_services/crypto/src/wlan_crypto_fils.c

@@ -0,0 +1,476 @@
+/*
+ * 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.
+ */
+
+/**
+ * DOC: Private API for handling FILS related operations
+ */
+
+#include <qdf_types.h>
+#include <wlan_cmn.h>
+#include <wlan_objmgr_cmn.h>
+
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+
+#include "wlan_crypto_global_def.h"
+#include "wlan_crypto_global_api.h"
+#include "wlan_crypto_def_i.h"
+#include "wlan_crypto_main_i.h"
+#include "wlan_crypto_obj_mgr_i.h"
+#ifdef WLAN_SUPPORT_FILS
+#include "wlan_crypto_aes_siv_i.h"
+#endif /* WLAN_SUPPORT_FILS */
+
+#define ASSOC_RESP_FIXED_FIELDS_LEN  6 /* cap info + status + assoc id */
+#define ASSOC_REQ_FIXED_FIELDS_LEN   4 /* cap info + listen interval */
+#define REASSOC_REQ_FIXED_FIELDS_LEN 10 /* cap info + listen interval + BSSID */
+
+#ifdef WLAN_SUPPORT_FILS
+/**
+ * fils_parse_ie - Parse IEs from (Re-)association Req/Response frames
+ * @wbuf: Packet buffer
+ * @hdrlen: Header length
+ * @cap_info: Pointer to capability Information
+ * @fils_sess: Pointer to the end of Fils session Element
+ * @ie_start: Pointer to the start of Information element
+ *
+ * Parse IE  and return required pointers to encrypt/decrypt routines
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+fils_parse_ie(qdf_nbuf_t wbuf, uint8_t hdrlen, uint8_t **cap_info,
+	      uint8_t **fils_sess, uint8_t **ie_start)
+{
+	struct ieee80211_hdr *hdr;
+	uint32_t pktlen_left = 0;
+	bool fils_found = 0;
+	uint16_t subtype = 0;
+	uint8_t *frm = NULL;
+	uint8_t elem_id;
+	uint32_t len;
+
+	frm = (uint8_t *)qdf_nbuf_data(wbuf);
+	hdr = (struct ieee80211_hdr *)frm;
+	subtype = WLAN_FC_GET_STYPE(hdr->frame_control);
+
+	pktlen_left = qdf_nbuf_len(wbuf);
+
+	if (pktlen_left < hdrlen) {
+		qdf_print(FL("Parse error.pktlen_left:%d Framehdr size:%d\n"),
+			  pktlen_left, hdrlen);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	frm += hdrlen;
+	pktlen_left -= hdrlen;
+
+	/* pointer to the capability information field */
+	*cap_info = (uint8_t *)frm;
+
+	if (subtype == WLAN_FC_STYPE_ASSOC_RESP ||
+	    subtype == WLAN_FC_STYPE_REASSOC_RESP) {
+		/* assoc resp frame - capability (2), status (2), associd (2) */
+		if (pktlen_left < ASSOC_RESP_FIXED_FIELDS_LEN) {
+			qdf_print(
+			FL("Parse error.pktlen_left:%d Fixed Fields len:%d\n"),
+				pktlen_left, ASSOC_RESP_FIXED_FIELDS_LEN);
+			return QDF_STATUS_E_INVAL;
+		}
+
+		frm += ASSOC_RESP_FIXED_FIELDS_LEN;
+		pktlen_left -= ASSOC_RESP_FIXED_FIELDS_LEN;
+	} else if (subtype == WLAN_FC_STYPE_ASSOC_REQ) {
+		/* assoc req frame - capability(2), listen interval (2) */
+		if (pktlen_left < ASSOC_REQ_FIXED_FIELDS_LEN) {
+			qdf_print(
+			FL("Parse Error.pktlen_left:%d Fixed Fields len:%d\n"),
+				pktlen_left, ASSOC_REQ_FIXED_FIELDS_LEN);
+			return QDF_STATUS_E_INVAL;
+		}
+
+		frm += ASSOC_REQ_FIXED_FIELDS_LEN;
+		pktlen_left -= ASSOC_REQ_FIXED_FIELDS_LEN;
+	} else if (subtype == WLAN_FC_STYPE_REASSOC_REQ) {
+		/* assoc req frame - capability(2),
+		 * Listen interval(2),
+		 * Current AP address(6)
+		 */
+		if (pktlen_left < REASSOC_REQ_FIXED_FIELDS_LEN) {
+			qdf_print(
+			FL("Parse Error.pktlen_left:%d Fixed Fields len:%d\n"),
+				pktlen_left, REASSOC_REQ_FIXED_FIELDS_LEN);
+			return QDF_STATUS_E_INVAL;
+		}
+
+		frm += REASSOC_REQ_FIXED_FIELDS_LEN;
+		pktlen_left -= REASSOC_REQ_FIXED_FIELDS_LEN;
+	}
+
+	*ie_start = frm;
+	/* 'frm' now pointing to TLVs.
+	 * Parse through All IE's till FILS Session Element
+	 */
+	while ((pktlen_left >= 2) && frm) {
+		/* element ID & len*/
+		elem_id = *frm++;
+		len = *frm++;
+		pktlen_left -= 2;
+
+		/* for extension element, check the sub element ID */
+		if (elem_id == WLAN_ELEMID_EXTN_ELEM) {
+			if ((len + 1) > pktlen_left) {
+				qdf_print(FL("Parse Error.pktlen_left:%did:%d"),
+					  pktlen_left, elem_id);
+				qdf_print("len:%dextid:%d\n", len, *frm);
+				return QDF_STATUS_E_INVAL;
+			}
+
+			if (*frm == WLAN_ELEMID_EXT_FILS_SESSION) {
+				fils_found = 1;
+				break;
+			}
+			frm++;
+			pktlen_left--;
+		}
+
+		if (len > pktlen_left) {
+			qdf_print(
+			FL("Parse Error.pktlen_left:%did:%dlen:%dextid:%d\n"),
+				pktlen_left, elem_id, len, *frm);
+			return QDF_STATUS_E_INVAL;
+		}
+
+		/* switch to the next IE */
+		frm += len;
+		pktlen_left -= len;
+	}
+
+	if (!fils_found) {
+		qdf_print(FL("FILS session element not found. Parse failed\n"));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* Points to end of FILS session element */
+	*fils_sess = (frm + len);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * fils_aead_setkey - Setkey function
+ * @key: Pointer to wlan_crypto_key
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
+static QDF_STATUS fils_aead_setkey(struct wlan_crypto_key *key)
+{
+	struct wlan_crypto_req_key *req_key;
+	struct wlan_crypto_fils_aad_key *fils_key;
+
+	if (!key || !key->private) {
+		qdf_print(FL("Failed to set FILS key\n"));
+		return QDF_STATUS_E_INVAL;
+	}
+	req_key = key->private;
+	fils_key = qdf_mem_malloc(sizeof(struct wlan_crypto_fils_aad_key));
+	if (!fils_key) {
+		qdf_print(FL("FILS key alloc failed\n"));
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(fils_key, &req_key->filsaad,
+		     sizeof(struct wlan_crypto_fils_aad_key));
+
+	/* Reassign the allocated fils_aad key object */
+	key->private = fils_key;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * fils_aead_encap - FILS AEAD encryption function
+ * @key: Pointer to wlan_crypto_key
+ * @wbuf: Packet buffer
+ * @keyid: Encrypting key ID
+ * @hdrlen: Header length
+ *
+ * This function encrypts FILS Association Response Packet
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+fils_aead_encap(struct wlan_crypto_key *key, qdf_nbuf_t wbuf,
+		uint8_t keyid, uint8_t hdrlen)
+{
+	const uint8_t *address[5 + 1];
+	size_t length[5 + 1];
+	uint8_t *cap_info = NULL, *fils_session = NULL, *ie_start = NULL;
+	uint32_t crypt_len = 0;
+	struct ieee80211_hdr *hdr = NULL;
+	struct wlan_crypto_fils_aad_key *fils_key = NULL;
+	uint8_t *buf = NULL;
+	uint32_t bufsize = 0;
+	uint16_t subtype = 0;
+
+	if (!key) {
+		qdf_print(FL("Invalid Input\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	fils_key = (struct wlan_crypto_fils_aad_key *)key->private;
+	if (!fils_key) {
+		qdf_print(FL("Key is not set\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!fils_key->kek_len) {
+		qdf_print(FL("Key len is zero. Returning error\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	hdr = (struct ieee80211_hdr *)qdf_nbuf_data(wbuf);
+	if (!hdr) {
+		qdf_print(FL("Invalid header\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	subtype = WLAN_FC_GET_STYPE(hdr->frame_control);
+	if ((subtype != WLAN_FC_STYPE_ASSOC_RESP) &&
+	    (subtype != WLAN_FC_STYPE_REASSOC_RESP))
+		return QDF_STATUS_E_FAILURE;
+
+	if (fils_parse_ie(wbuf, hdrlen, &cap_info, &fils_session, &ie_start)
+			!= QDF_STATUS_SUCCESS) {
+		qdf_print(FL("FILS Parsing failed\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* The AP's BSSID */
+	address[0] = hdr->addr2;
+	length[0] = WLAN_ALEN;
+	/* The STA's MAC address */
+	address[1] = hdr->addr1;
+	length[1] = WLAN_ALEN;
+	/* The AP's nonce */
+	address[2] = fils_key->a_nonce;
+	length[2] = WLAN_FILS_NONCE_LEN;
+	/* The STA's nonce */
+	address[3] = fils_key->s_nonce;
+	length[3] = WLAN_FILS_NONCE_LEN;
+	address[4] = cap_info;
+	length[4] = fils_session - cap_info;
+
+	crypt_len = (uint8_t *)hdr + (uint32_t)qdf_nbuf_len(wbuf)
+					- fils_session;
+
+	bufsize = ((uint8_t *)hdr + (uint32_t)qdf_nbuf_len(wbuf) - ie_start)
+					+ AES_BLOCK_SIZE;
+	buf = qdf_mem_malloc(bufsize);
+	if (!buf) {
+		qdf_print(FL("temp buf allocation failed\n"));
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(buf, ie_start, bufsize);
+
+	if (wlan_crypto_aes_siv_encrypt(fils_key->kek, fils_key->kek_len,
+					fils_session, crypt_len, 5, address,
+					length, buf + (fils_session - ie_start))
+					< 0) {
+		qdf_print(FL("aes siv_encryption failed\n"));
+		qdf_mem_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!qdf_nbuf_put_tail(wbuf, AES_BLOCK_SIZE))
+		qdf_print(FL("Unable to put data in nbuf\n"));
+
+	qdf_mem_copy(ie_start, buf, bufsize);
+	qdf_mem_free(buf);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * fils_aead_decap - FILS AEAD decryption function
+ * @key: Pointer to wlan_crypto_key
+ * @wbuf: Packet buffer
+ * @tid: TID
+ * @hdrlen: Header length
+ *
+ * This function decrypts FILS Association Request Packet
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+fils_aead_decap(struct wlan_crypto_key *key, qdf_nbuf_t wbuf,
+		uint8_t tid, uint8_t hdrlen)
+{
+	const uint8_t *address[5];
+	size_t length[5];
+	uint8_t *cap_info = NULL, *fils_session = NULL, *ie_start = NULL;
+	struct ieee80211_hdr *hdr = NULL;
+	struct wlan_crypto_fils_aad_key *fils_key = NULL;
+	uint32_t crypt_len = 0;
+	uint8_t *buf = NULL;
+	uint32_t bufsize = 0;
+
+	if (!key) {
+		qdf_print(FL("Invalid Input\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	fils_key = (struct wlan_crypto_fils_aad_key *)key->private;
+	if (!fils_key) {
+		qdf_print(FL("Key is not set\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!fils_key->kek_len) {
+		qdf_print(FL("Key len is zero. Returning error\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (fils_parse_ie(wbuf, hdrlen, &cap_info, &fils_session, &ie_start)
+			!= QDF_STATUS_SUCCESS) {
+		qdf_print(FL("IE parse failed\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	hdr = (struct ieee80211_hdr *)qdf_nbuf_data(wbuf);
+	if (!hdr) {
+		qdf_print(FL("Invalid header\n"));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* The STA's MAC address */
+	address[0] = hdr->addr1;
+	length[0] = WLAN_ALEN;
+	/* The AP's BSSID */
+	address[1] = hdr->addr2;
+	length[1] = WLAN_ALEN;
+	/* The STA's nonce */
+	address[2] = fils_key->s_nonce;
+	length[2] = WLAN_FILS_NONCE_LEN;
+	/* The AP's nonce */
+	address[3] = fils_key->a_nonce;
+	length[3] = WLAN_FILS_NONCE_LEN;
+
+	address[4] = cap_info;
+	length[4] = fils_session - cap_info;
+
+	crypt_len = ((uint8_t *)hdr + (uint32_t)qdf_nbuf_len(wbuf))
+				- fils_session;
+	if (crypt_len < AES_BLOCK_SIZE) {
+		qdf_print(FL(
+			"Not enough room for AES-SIV data after FILS Session"));
+		qdf_print(
+		" element in (Re)Association Request frame from %pM\n",
+						hdr->addr1);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* Allocate temp buf & copy contents */
+	bufsize = (uint8_t *)hdr + (uint32_t)qdf_nbuf_len(wbuf) - ie_start;
+	buf = qdf_mem_malloc(bufsize);
+	if (!buf) {
+		qdf_print(FL("temp buf allocation failed\n"));
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(buf, ie_start, bufsize);
+
+	if (wlan_crypto_aes_siv_decrypt(fils_key->kek, fils_key->kek_len,
+					fils_session, crypt_len, 5, address,
+					length, buf + (fils_session - ie_start))
+					< 0) {
+		qdf_print(FL("AES decrypt of assocreq frame from %s failed\n"),
+			  ether_sprintf(hdr->addr1));
+		qdf_mem_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+	qdf_mem_copy(ie_start, buf, bufsize);
+	qdf_nbuf_trim_tail(wbuf, AES_BLOCK_SIZE);
+	qdf_mem_free(buf);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void wlan_crypto_fils_delkey(struct wlan_objmgr_peer *peer)
+{
+	struct wlan_crypto_comp_priv *crypto_priv = NULL;
+	struct wlan_crypto_key *key = NULL;
+
+	if (!peer) {
+		qdf_print(FL("Invalid Input\n"));
+		return;
+	}
+
+	crypto_priv = wlan_get_peer_crypto_obj(peer);
+	if (!crypto_priv) {
+		qdf_print(FL("crypto_priv NULL\n"));
+		return;
+	}
+
+	key = crypto_priv->key[0];
+	if (key && key->private)
+		qdf_mem_free((struct wlan_crypto_fils_aad_key *)key->private);
+	key->private = 0;
+}
+#else
+
+static QDF_STATUS fils_aead_setkey(struct wlan_crypto_key *key)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+fils_aead_encap(struct wlan_crypto_key *key, qdf_nbuf_t wbuf,
+		uint8_t keyid, uint8_t hdrlen)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+fils_aead_decap(struct wlan_crypto_key *key, qdf_nbuf_t wbuf,
+		uint8_t tid, uint8_t hdrlen)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_SUPPORT_FILS */
+
+static const struct wlan_crypto_cipher fils_aead_cipher_table = {
+	"FILS AEAD",
+	WLAN_CRYPTO_CIPHER_FILS_AEAD,
+	0,
+	0,
+	0,
+	WLAN_MAX_WPA_KEK_LEN,
+	fils_aead_setkey,
+	fils_aead_encap,
+	fils_aead_decap,
+	0,
+	0,
+};
+
+const struct wlan_crypto_cipher *fils_register(void)
+{
+	return &fils_aead_cipher_table;
+}
+

+ 76 - 11
umac/cmn_services/crypto/src/wlan_crypto_global_api.c

@@ -286,7 +286,7 @@ QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
 
 	isbcast = qdf_is_macaddr_broadcast(
 				(struct qdf_mac_addr *)req_key->macaddr);
-	if (req_key->keylen == 0) {
+	if ((req_key->keylen == 0) && !IS_FILS_CIPHER(req_key->type)) {
 		/* zero length keys, only set default key id if flags are set*/
 		if ((req_key->flags & WLAN_CRYPTO_KEY_DEFAULT)
 			&& (req_key->keyix != WLAN_CRYPTO_KEYIX_NONE)
@@ -308,9 +308,10 @@ QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_INVAL;
 	}
 
-	if (cipher && (!IS_MGMT_CIPHER(req_key->type))
-		&& ((req_key->keylen != (cipher->keylen/NBBY))
-		&& (req_key->type != WLAN_CRYPTO_CIPHER_WEP))) {
+	if (cipher && (!IS_FILS_CIPHER(req_key->type)) &&
+	    (!IS_MGMT_CIPHER(req_key->type)) &&
+	    ((req_key->keylen != (cipher->keylen / NBBY)) &&
+	    (req_key->type != WLAN_CRYPTO_CIPHER_WEP))) {
 		qdf_print("%s[%d] cipher invalid\n", __func__, __LINE__);
 		return QDF_STATUS_E_INVAL;
 	} else if ((req_key->type == WLAN_CRYPTO_CIPHER_WEP) &&
@@ -388,6 +389,11 @@ QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
 			crypto_priv->igtk_key_type = req_key->type;
 			crypto_priv->def_igtk_tx_keyid = igtk_idx;
 		} else {
+			if (IS_FILS_CIPHER(req_key->type)) {
+				qdf_print(FL(
+				"FILS key is not for BroadCast packet\n"));
+				return QDF_STATUS_E_INVAL;
+			}
 			if (!HAS_MCAST_CIPHER(crypto_params, req_key->type)
 				&& (req_key->type != WLAN_CRYPTO_CIPHER_WEP)) {
 				return QDF_STATUS_E_INVAL;
@@ -545,8 +551,10 @@ QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
 		}
 		status = wlan_crypto_set_igtk_key(key);
 		return status;
+	} else if (IS_FILS_CIPHER(req_key->type)) {
+		/* Take request key object to FILS setkey */
+		key->private = req_key;
 	} else {
-
 		if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
 			WLAN_CRYPTO_TX_OPS_SETKEY(psoc)(vdev, key,
 							macaddr, req_key->type);
@@ -872,11 +880,9 @@ QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev,
 	QDF_STATUS status;
 	struct wlan_crypto_cipher *cipher_table;
 	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_peer *peer;
 	uint8_t bssid_mac[WLAN_ALEN];
 
-	if (!wlan_crypto_is_data_protected((uint8_t *)qdf_nbuf_data(wbuf)))
-		return QDF_STATUS_E_INVAL;
-
 	wlan_vdev_obj_lock(vdev);
 	qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev), WLAN_ALEN);
 	psoc = wlan_vdev_get_psoc(vdev);
@@ -887,6 +893,18 @@ QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev,
 	}
 	wlan_vdev_obj_unlock(vdev);
 
+	/* FILS Encap required only for (Re-)Assoc response */
+	peer = wlan_objmgr_get_peer(psoc, mac_addr, WLAN_CRYPTO_ID);
+
+	if (!wlan_crypto_is_data_protected((uint8_t *)qdf_nbuf_data(wbuf)) &&
+	    peer && !wlan_crypto_get_peer_fils_aead(peer)) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (peer)
+		wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
+
 	if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) {
 		crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
 								&crypto_priv);
@@ -955,11 +973,9 @@ QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev,
 	QDF_STATUS status;
 	struct wlan_crypto_cipher *cipher_table;
 	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_peer *peer;
 	uint8_t bssid_mac[WLAN_ALEN];
 
-	if (!wlan_crypto_is_data_protected((uint8_t *)qdf_nbuf_data(wbuf)))
-		return QDF_STATUS_E_INVAL;
-
 	wlan_vdev_obj_lock(vdev);
 	qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev), WLAN_ALEN);
 	psoc = wlan_vdev_get_psoc(vdev);
@@ -970,6 +986,18 @@ QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev,
 	}
 	wlan_vdev_obj_unlock(vdev);
 
+	/* FILS Decap required only for (Re-)Assoc request */
+	peer = wlan_objmgr_get_peer(psoc, mac_addr, WLAN_CRYPTO_ID);
+
+	if (!wlan_crypto_is_data_protected((uint8_t *)qdf_nbuf_data(wbuf)) &&
+	    peer && !wlan_crypto_get_peer_fils_aead(peer)) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (peer)
+		wlan_objmgr_peer_release_ref(peer, WLAN_CRYPTO_ID);
+
 	if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac_addr)) {
 		crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
 								&crypto_priv);
@@ -2678,3 +2706,40 @@ bool wlan_crypto_peer_has_auth_mode(struct wlan_objmgr_peer *peer,
 	return wlan_crypto_get_peer_param(peer, WLAN_CRYPTO_PARAM_AUTH_MODE)
 			& authvalue;
 }
+
+uint8_t wlan_crypto_get_peer_fils_aead(struct wlan_objmgr_peer *peer)
+{
+	struct wlan_crypto_comp_priv *crypto_priv = NULL;
+
+	if (!peer) {
+		qdf_print(FL("Invalid Input\n"));
+		return 0;
+	}
+
+	crypto_priv = wlan_get_peer_crypto_obj(peer);
+	if (!crypto_priv) {
+		qdf_print(FL("crypto_priv NULL\n"));
+		return 0;
+	}
+
+	return crypto_priv->fils_aead_set;
+}
+
+void
+wlan_crypto_set_peer_fils_aead(struct wlan_objmgr_peer *peer, uint8_t value)
+{
+	struct wlan_crypto_comp_priv *crypto_priv = NULL;
+
+	if (!peer) {
+		qdf_print(FL("Invalid Input\n"));
+		return;
+	}
+
+	crypto_priv = wlan_get_peer_crypto_obj(peer);
+	if (!crypto_priv) {
+		qdf_print(FL("crypto_priv NULL\n"));
+		return;
+	}
+
+	crypto_priv->fils_aead_set = value;
+}

+ 6 - 0
umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c

@@ -34,6 +34,7 @@
 #include "wlan_crypto_def_i.h"
 #include "wlan_crypto_main_i.h"
 #include "wlan_crypto_obj_mgr_i.h"
+#include "wlan_crypto_fils_api.h"
 
 
 extern const struct wlan_crypto_cipher *wep_register(void);
@@ -73,6 +74,10 @@ static QDF_STATUS wlan_crypto_register_all_ciphers(
 		wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_WAPI_SMS4]
 							= wapi_register();
 	}
+	if (HAS_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_FILS_AEAD)) {
+		wlan_crypto_cipher_ops[WLAN_CRYPTO_CIPHER_FILS_AEAD]
+							= fils_register();
+	}
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -124,6 +129,7 @@ static QDF_STATUS wlan_crypto_vdev_obj_create_handler(
 		SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_CKIP);
 	if (wlan_pdev_nif_fw_cap_get(pdev, WLAN_SOC_C_WAPI))
 		SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_WAPI_SMS4);
+	SET_CIPHER_CAP(crypto_param, WLAN_CRYPTO_CAP_FILS_AEAD);
 	wlan_pdev_obj_unlock(pdev);
 	/* update the crypto cipher table based on the fw caps*/
 	/* update the fw_caps into ciphercaps then attach to objmgr*/

+ 1 - 0
umac/cmn_services/crypto/src/wlan_crypto_param_handling.c

@@ -49,6 +49,7 @@ cipher2cap(int cipher)
 	case WLAN_CRYPTO_CIPHER_TKIP: return WLAN_CRYPTO_CAP_TKIP_MIC;
 	case WLAN_CRYPTO_CIPHER_WAPI_SMS4: return WLAN_CRYPTO_CAP_WAPI_SMS4;
 	case WLAN_CRYPTO_CIPHER_WAPI_GCM4: return WLAN_CRYPTO_CAP_WAPI_GCM4;
+	case WLAN_CRYPTO_CIPHER_FILS_AEAD: return WLAN_CRYPTO_CAP_FILS_AEAD;
 	}
 	return 0;
 }

+ 2 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h

@@ -150,6 +150,8 @@
 #define WLAN_VDEV_FEXT_SON_SPL_RPT          0x00800000
 /* SON IE update in MGMT frame */
 #define WLAN_VDEV_FEXT_SON_INFO_UPDATE      0x01000000
+/* FILS AEAD in MGMT frame */
+#define WLAN_VDEV_FEXT_FILS                 0x02000000
 
 /* VDEV OP flags  */
   /* if the vap destroyed by user */