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

