From 29d5267f428e8d14720dbe67980990df89728a4f Mon Sep 17 00:00:00 2001
From: Carter Chen <carter.chen@infineon.com>
Date: Wed, 12 Oct 2022 21:19:47 -0500
Subject: [PATCH 124/296] brcmfmac: ext_owe supporting

parsing the AKM setting of OWE.
parsing the ie in the cfg80211_connect_params, to find the owe extension
ie we need to set to firmware.

Fixes: SWLINUX-2956

Signed-off-by: Carter Chen <carter.chen@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/cfg80211.c    | 154 +++++++++++++++++-
 .../broadcom/brcm80211/include/brcmu_wifi.h   |   2 +-
 2 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 09770656b12f..e08d6b3f9d38 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -146,7 +146,6 @@ struct cca_msrmnt_query {
 /* start enum value for BSS properties */
 #define WL_WSEC_INFO_BSS_BASE 0x0100
 #define WL_WSEC_INFO_BSS_ALGOS (WL_WSEC_INFO_BSS_BASE + 6)
-
 #define WL_HE_CMD_BSSCOLOR 5
 
 static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
@@ -332,6 +331,32 @@ struct parsed_vndr_ies {
 	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 };
 
+struct brcmf_ext_tlv {
+	u8 id;
+	u8 len;
+	u8 ext_id;
+};
+
+struct parsed_ext_ie_info {
+	u8 *ie_ptr;
+	u32 ie_len;	/* total length including id & length field */
+	struct brcmf_ext_tlv ie_data;
+};
+
+struct parsed_extension_ies {
+	u32 count;
+	struct parsed_ext_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
+};
+
+struct dot11_assoc_resp {
+	u16	capability;	/* capability information */
+	u16	status;		/* status code */
+	u16	aid;		/* association ID */
+};
+
+#define WLC_E_IF_ROLE_STA		0	/* Infra STA */
+#define WLC_E_IF_ROLE_AP		1	/* Access Point */
+
 #define WL_INTERFACE_CREATE_VER_1		1
 #define WL_INTERFACE_CREATE_VER_2		2
 #define WL_INTERFACE_CREATE_VER_3		3
@@ -2165,6 +2190,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
 	} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
 		if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_SAE)
 			val = WPA3_AUTH_SAE_PSK;
+		else if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_OWE)
+			val = WPA3_AUTH_OWE;
 		else
 			val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
 	} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) {
@@ -2418,6 +2445,10 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
 			val = WFA_AUTH_DPP;
 			profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
 			break;
+		case WLAN_AKM_SUITE_OWE:
+			val = WPA3_AUTH_OWE;
+			profile->use_fwsup = BRCMF_PROFILE_FWSUP_ROAM;
+			break;
 		case WLAN_AKM_SUITE_8021X_SUITE_B_192:
 			val = WPA3_AUTH_1X_SUITE_B_SHA384;
 			if (sme->want_1x)
@@ -5306,6 +5337,58 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
 	return ie_len + VNDR_IE_HDR_SIZE;
 }
 
+static s32
+brcmf_parse_extension_ies(const u8 *extension_ie_buf, u32 extension_ie_len,
+			  struct parsed_extension_ies *extension_ies)
+{
+	struct brcmf_ext_tlv *ext_ie;
+	struct brcmf_tlv *ie;
+	struct parsed_ext_ie_info *parsed_info;
+	s32 remaining_len;
+
+	remaining_len = (s32)extension_ie_len;
+	memset(extension_ies, 0, sizeof(*extension_ies));
+
+	ie = (struct brcmf_tlv *)extension_ie_buf;
+	while (ie) {
+		if (ie->id != WLAN_EID_EXTENSION)
+			goto next;
+		ext_ie = (struct brcmf_ext_tlv *)ie;
+
+		/* len should be bigger than ext_id + one data */
+		if (ext_ie->len < 2) {
+			brcmf_err("invalid ext_ie ie. length is too small %d\n",
+				  ext_ie->len);
+			goto next;
+		}
+
+		parsed_info = &extension_ies->ie_info[extension_ies->count];
+
+		parsed_info->ie_ptr = (char *)ext_ie;
+		parsed_info->ie_len = ext_ie->len + TLV_HDR_LEN;
+		memcpy(&parsed_info->ie_data, ext_ie, sizeof(*ext_ie));
+
+		extension_ies->count++;
+
+		brcmf_dbg(TRACE, "** EXT_IE %d, len 0x%02x EXT_ID: %d\n",
+			  parsed_info->ie_data.id,
+			  parsed_info->ie_data.len,
+			  parsed_info->ie_data.ext_id);
+
+		/* temperory parsing at most 5 EXT_ID, will review it.*/
+		if (extension_ies->count >= VNDR_IE_PARSE_LIMIT)
+			break;
+next:
+		remaining_len -= (ie->len + TLV_HDR_LEN);
+		if (remaining_len <= TLV_HDR_LEN)
+			ie = NULL;
+		else
+			ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
+				TLV_HDR_LEN);
+	}
+	return 0;
+}
+
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 			  const u8 *vndr_ie_buf, u32 vndr_ie_len)
 {
@@ -5327,6 +5410,9 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 	s32 i;
 	u8 *ptr;
 	int remained_buf_len;
+	struct parsed_extension_ies new_ext_ies;
+	struct parsed_extension_ies old_ext_ies;
+	struct parsed_ext_ie_info *extie_info;
 
 	if (!vif)
 		return -ENODEV;
@@ -5388,6 +5474,13 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 			       vndrie_info->ie_len);
 			parsed_ie_buf_len += vndrie_info->ie_len;
 		}
+		brcmf_parse_extension_ies(vndr_ie_buf, vndr_ie_len, &new_ext_ies);
+		for (i = 0; i < new_ext_ies.count; i++) {
+			extie_info = &new_ext_ies.ie_info[i];
+			memcpy(ptr + parsed_ie_buf_len, extie_info->ie_ptr,
+			       extie_info->ie_len);
+			parsed_ie_buf_len += extie_info->ie_len;
+		}
 	}
 
 	if (mgmt_ie_buf && *mgmt_ie_len) {
@@ -5400,6 +5493,8 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 
 		/* parse old vndr_ie */
 		brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
+		/* parse old ext_ie */
+		brcmf_parse_extension_ies(mgmt_ie_buf, *mgmt_ie_len, &old_ext_ies);
 
 		/* make a command to delete old ie */
 		for (i = 0; i < old_vndr_ies.count; i++) {
@@ -5417,6 +5512,23 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 			curr_ie_buf += del_add_ie_buf_len;
 			total_ie_buf_len += del_add_ie_buf_len;
 		}
+		/* make a command to delete old extension ie */
+		for (i = 0; i < old_ext_ies.count; i++) {
+			extie_info = &old_ext_ies.ie_info[i];
+
+			brcmf_dbg(TRACE, "DEL EXT_IE : %d, Len: %d , ext_id:%d\n",
+				  extie_info->ie_data.id,
+				  extie_info->ie_data.len,
+				  extie_info->ie_data.ext_id);
+
+			del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf,
+							   pktflag | BRCMF_VNDR_IE_CUSTOM_FLAG,
+							   extie_info->ie_ptr,
+							   extie_info->ie_len,
+							   "del");
+			curr_ie_buf += del_add_ie_buf_len;
+			total_ie_buf_len += del_add_ie_buf_len;
+		}
 	}
 
 	*mgmt_ie_len = 0;
@@ -5455,6 +5567,39 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 			       vndrie_info->ie_len);
 			*mgmt_ie_len += vndrie_info->ie_len;
 
+			curr_ie_buf += del_add_ie_buf_len;
+			total_ie_buf_len += del_add_ie_buf_len;
+		}
+		/* make a command to add new EXT ie */
+		for (i = 0; i < new_ext_ies.count; i++) {
+			extie_info = &new_ext_ies.ie_info[i];
+
+			/* verify remained buf size before copy data */
+			if (remained_buf_len < (extie_info->ie_data.len +
+							VNDR_IE_VSIE_OFFSET)) {
+				bphy_err(drvr, "no space in mgmt_ie_buf: len left %d",
+					 remained_buf_len);
+				break;
+			}
+			remained_buf_len -= (extie_info->ie_len +
+					     VNDR_IE_VSIE_OFFSET);
+
+			brcmf_dbg(TRACE, "ADDED EXT ID : %d, Len: %d, OUI:%d\n",
+				  extie_info->ie_data.id,
+				  extie_info->ie_data.len,
+				  extie_info->ie_data.ext_id);
+
+			del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf,
+							   pktflag | BRCMF_VNDR_IE_CUSTOM_FLAG,
+							   extie_info->ie_ptr,
+							   extie_info->ie_len,
+							   "add");
+
+			/* save the parsed IE in wl struct */
+			memcpy(ptr + (*mgmt_ie_len), extie_info->ie_ptr,
+			       extie_info->ie_len);
+			*mgmt_ie_len += extie_info->ie_len;
+
 			curr_ie_buf += del_add_ie_buf_len;
 			total_ie_buf_len += del_add_ie_buf_len;
 		}
@@ -7151,6 +7296,11 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
 		conn_info->req_ie_len = 0;
 		conn_info->req_ie = NULL;
 	}
+
+	/* resp_len is the total length of assoc resp
+	 * which includes 6 bytes of aid/status code/capabilities.
+	 * the assoc_resp_ie length should minus the 6 bytes which starts from rate_ie.
+	 */
 	if (resp_len) {
 		err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
 					       cfg->extra_buf,
@@ -7159,7 +7309,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
 			bphy_err(drvr, "could not get assoc resp (%d)\n", err);
 			return err;
 		}
-		conn_info->resp_ie_len = resp_len;
+		conn_info->resp_ie_len = resp_len - sizeof(struct dot11_assoc_resp);
 		conn_info->resp_ie =
 		    kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
 			    GFP_KERNEL);
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
index 04bf1c0b3b06..de5b585b91a8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
@@ -240,7 +240,7 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
 #define WPA2_AUTH_PSK_SHA256	0x8000	/* PSK with SHA256 key derivation */
 
 #define WPA3_AUTH_SAE_PSK	0x40000	/* SAE with 4-way handshake */
-
+#define WPA3_AUTH_OWE		0x100000 /* OWE */
 #define WFA_AUTH_DPP		0x200000 /* WFA DPP AUTH */
 #define WPA3_AUTH_1X_SUITE_B_SHA384	0x400000 /* Suite B-192 SHA384 */
 
-- 
2.25.1

