From: Michael Reeves <[email protected]>

Some firmware rejects the legacy BRCMF_C_SET_WSEC_PMK payload despite
advertising firmware supplicant support.

Add the extended PMK layout. Try the legacy payload first when the key
fits, and retry with the extended layout only after -EBADE. Use the
extended layout directly for larger keys and reject keys that exceed its
capacity.

Co-developed-by: Hector Martin <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
Signed-off-by: Michael Reeves <[email protected]>
---
 .../broadcom/brcm80211/brcmfmac/cfg80211.c         | 39 ++++++++++++++++------
 .../broadcom/brcm80211/brcmfmac/fwil_types.h       | 18 ++++++++++
 2 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c 
b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 2a742ae8cc..c9cc6e0ccd 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1584,28 +1584,45 @@ int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, 
u16 key_len, u16 flags)
 {
        struct brcmf_pub *drvr = ifp->drvr;
        struct brcmf_wsec_pmk_le pmk;
+       struct brcmf_wsec_pmk_ext_le pmk_ext;
        int err;
 
-       if (key_len > sizeof(pmk.key)) {
+       if (key_len > sizeof(pmk_ext.key)) {
                bphy_err(drvr, "key must be less than %zu bytes\n",
-                        sizeof(pmk.key));
+                        sizeof(pmk_ext.key));
                return -EINVAL;
        }
 
-       memset(&pmk, 0, sizeof(pmk));
+       if (key_len <= sizeof(pmk.key)) {
+               memset(&pmk, 0, sizeof(pmk));
 
-       /* pass key material directly */
-       pmk.key_len = cpu_to_le16(key_len);
-       pmk.flags = cpu_to_le16(flags);
-       memcpy(pmk.key, key, key_len);
+               pmk.key_len = cpu_to_le16(key_len);
+               pmk.flags = cpu_to_le16(flags);
+               memcpy(pmk.key, key, key_len);
+
+               err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
+                                            &pmk, sizeof(pmk));
+               if (!err)
+                       return 0;
+               if (err != -EBADE)
+                       goto fail;
+       }
+
+       memset(&pmk_ext, 0, sizeof(pmk_ext));
+       pmk_ext.key_len = cpu_to_le16(key_len);
+       pmk_ext.flags = cpu_to_le16(flags);
+       memcpy(pmk_ext.key, key, key_len);
 
-       /* store key material in firmware */
        err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
-                                    &pmk, sizeof(pmk));
+                                    &pmk_ext, sizeof(pmk_ext));
        if (err < 0)
-               bphy_err(drvr, "failed to change PSK in firmware (len=%u)\n",
-                        key_len);
+               goto fail;
+
+       return 0;
 
+fail:
+       bphy_err(drvr, "failed to change PSK in firmware (len=%u, err=%d)\n",
+                key_len, err);
        return err;
 }
 BRCMF_EXPORT_SYMBOL_GPL(brcmf_set_wsec);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h 
b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 917966ad70..37d9414546 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -75,6 +75,7 @@
 #define BRCMF_WSEC_MAX_PSK_LEN         32
 #define        BRCMF_WSEC_PASSPHRASE           BIT(0)
 
+#define BRCMF_WSEC_MAX_PMK_LEN         256
 #define BRCMF_WSEC_MAX_SAE_PASSWORD_LEN 128
 
 /* primary (ie tx) key */
@@ -667,6 +668,23 @@ struct brcmf_wsec_pmk_le {
        u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN];
 };
 
+/**
+ * struct brcmf_wsec_pmk_ext_le - extended firmware pmk material.
+ *
+ * @key_len: number of octets in key material.
+ * @flags: key handling qualifiers.
+ * @key: PMK key material.
+ * @opt_len: optional field length.
+ * @opt_tlvs: optional fields in TLV format.
+ */
+struct brcmf_wsec_pmk_ext_le {
+       __le16  key_len;
+       __le16  flags;
+       u8 key[BRCMF_WSEC_MAX_PMK_LEN];
+       __le16  opt_len;
+       u8 opt_tlvs[];
+};
+
 /**
  * struct brcmf_wsec_sae_pwd_le - firmware SAE password material.
  *

-- 
2.55.0



Reply via email to