[PATCH] wifi: mwifiex: fix parsing of more than two AKM suites

From: Sascha Hauer
Date: Thu May 23 2024 - 04:14:51 EST


params->crypto.n_akm_suites seems to be limited to two AKM suites. Once
there are more they will be passed as extra elements of type WLAN_EID_RSN
or WLAN_EID_VENDOR_SPECIFIC.

This takes some snippets from the downstream vendor driver to parse
these elements and to set the correct protocol and key_mgmt bits to
enable the desired key managements algorithms in the hardware.

This patch is not a request for inclusion, more a heads up that there's
something missing and the question if the approach taken is the right
one or if there are other preferred ways to fix this issue.

Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
---
drivers/net/wireless/marvell/mwifiex/fw.h | 3 +
.../net/wireless/marvell/mwifiex/uap_cmd.c | 149 +++++++++++++++---
2 files changed, 132 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index 3adc447b715f6..d576b2d71a6b9 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -415,6 +415,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define KEY_MGMT_NONE 0x04
#define KEY_MGMT_PSK 0x02
#define KEY_MGMT_EAP 0x01
+#define KEY_MGMT_PSK_SHA256 0x100
+#define KEY_MGMT_OWE 0x200
+#define KEY_MGMT_SAE 0x400
#define CIPHER_TKIP 0x04
#define CIPHER_AES_CCMP 0x08
#define VALID_CIPHER_BITMAP 0x0c
diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
index 491e366119096..4b21626e2dd7f 100644
--- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
@@ -9,6 +9,112 @@
#include "11ac.h"
#include "11n.h"

+struct wpa_suite_ucast {
+ /* count */
+ u16 count;
+ /** wpa_suite list */
+ __be32 suite[1];
+} __packed;
+
+struct IEEEtypes_Rsn_t {
+ /** Rsn : version */
+ u16 version;
+ /** Rsn : group cipher */
+ __be32 group_cipher;
+ /** Rsn : pairwise cipher */
+ struct wpa_suite_ucast pairwise_cipher;
+} __packed;
+
+static void woal_check_rsn_ie(const struct IEEEtypes_Rsn_t *rsn_ie, int len,
+ struct mwifiex_uap_bss_param *bss_config, u8 *pairwise_cipher)
+{
+ int left, count, i;
+ struct wpa_suite_ucast *key_mgmt;
+
+ left = len;
+ if (left < (int)sizeof(struct IEEEtypes_Rsn_t))
+ return;
+
+ bss_config->wpa_cfg.group_cipher = 0;
+ *pairwise_cipher = 0;
+ bss_config->key_mgmt = 0;
+
+ /* check the group cipher */
+ switch (be32_to_cpu(rsn_ie->group_cipher)) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+
+ count = le16_to_cpu(rsn_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (be32_to_cpu(rsn_ie->pairwise_cipher.suite[i])) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ *pairwise_cipher |= CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *pairwise_cipher |= CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(struct IEEEtypes_Rsn_t) + (count - 1) * sizeof(__be32);
+ if (left < (int)sizeof(struct wpa_suite_ucast))
+ return;
+
+ key_mgmt = ((void *)rsn_ie + sizeof(struct IEEEtypes_Rsn_t) + (count - 1) * sizeof(__be32));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left < (int)(sizeof(struct wpa_suite_ucast) +
+ (count - 1) * sizeof(__be32)))
+ return;
+
+ for (i = 0; i < count; i++) {
+ switch (be32_to_cpu(key_mgmt->suite[i])) {
+ case WLAN_AKM_SUITE_8021X:
+ bss_config->key_mgmt |= KEY_MGMT_EAP;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ bss_config->key_mgmt |= KEY_MGMT_PSK;
+ break;
+ case WLAN_AKM_SUITE_PSK_SHA256:
+ bss_config->key_mgmt |= KEY_MGMT_PSK_SHA256;
+ break;
+ case WLAN_AKM_SUITE_SAE:
+ bss_config->key_mgmt |= KEY_MGMT_SAE;
+ break;
+ case WLAN_AKM_SUITE_OWE:
+ bss_config->key_mgmt |= KEY_MGMT_OWE;
+ break;
+ }
+ }
+}
+
+static void woal_find_wpa_ies(const void *ie, int len, struct mwifiex_uap_bss_param *bss_config)
+{
+ const struct element *e;
+
+ e = cfg80211_find_elem(WLAN_EID_RSN, ie, len);
+ if (e) {
+ woal_check_rsn_ie((void *)e->data, e->datalen, bss_config,
+ &bss_config->wpa_cfg.pairwise_cipher_wpa2);
+
+ bss_config->protocol |= PROTOCOL_WPA2;
+ }
+
+ e = cfg80211_find_vendor_elem(WLAN_EID_VENDOR_SPECIFIC, 0x1, ie, len);
+ if (e) {
+ woal_check_rsn_ie((void *)e->data, e->datalen, bss_config,
+ &bss_config->wpa_cfg.pairwise_cipher_wpa);
+ bss_config->protocol |= PROTOCOL_WPA;
+ }
+}
+
/* This function parses security related parameters from cfg80211_ap_settings
* and sets into FW understandable bss_config structure.
*/
@@ -17,6 +123,11 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params) {
int i;
struct mwifiex_wep_key wep_key;
+ const u8 *ie = NULL;
+ int ie_len;
+
+ ie = params->beacon.tail;
+ ie_len = params->beacon.tail_len;

if (!params->privacy) {
bss_config->protocol = PROTOCOL_NO_SECURITY;
@@ -46,36 +157,34 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,

bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;

+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ bss_config->protocol |= PROTOCOL_WPA;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ bss_config->protocol |= PROTOCOL_WPA2;
+
+ woal_find_wpa_ies(ie, ie_len, bss_config);
+
for (i = 0; i < params->crypto.n_akm_suites; i++) {
+ mwifiex_dbg(priv->adapter, MSG, "suite%d: 0x%08x\n", i, params->crypto.akm_suites[i]);
+
switch (params->crypto.akm_suites[i]) {
case WLAN_AKM_SUITE_8021X:
- if (params->crypto.wpa_versions &
- NL80211_WPA_VERSION_1) {
- bss_config->protocol = PROTOCOL_WPA;
- bss_config->key_mgmt = KEY_MGMT_EAP;
- }
- if (params->crypto.wpa_versions &
- NL80211_WPA_VERSION_2) {
- bss_config->protocol |= PROTOCOL_WPA2;
- bss_config->key_mgmt = KEY_MGMT_EAP;
- }
+ bss_config->key_mgmt |= KEY_MGMT_EAP;
break;
case WLAN_AKM_SUITE_PSK:
- if (params->crypto.wpa_versions &
- NL80211_WPA_VERSION_1) {
- bss_config->protocol = PROTOCOL_WPA;
- bss_config->key_mgmt = KEY_MGMT_PSK;
- }
- if (params->crypto.wpa_versions &
- NL80211_WPA_VERSION_2) {
- bss_config->protocol |= PROTOCOL_WPA2;
- bss_config->key_mgmt = KEY_MGMT_PSK;
- }
+ bss_config->key_mgmt |= KEY_MGMT_PSK;
+ break;
+ case WLAN_AKM_SUITE_PSK_SHA256:
+ bss_config->key_mgmt |= KEY_MGMT_PSK_SHA256;
break;
default:
break;
}
}
+
+ mwifiex_dbg(priv->adapter, MSG, "protocol: 0x%08x key_mgmt: 0x%08x\n",
+ bss_config->protocol, bss_config->key_mgmt);
+
for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
switch (params->crypto.ciphers_pairwise[i]) {
case WLAN_CIPHER_SUITE_WEP40:
--
2.39.2