brcmfmac: add support for SAE authentication offload

The firmware may have SAE authentication code built-in. This is
detected by the driver and indicated in the wiphy features flags.
User-space can use this flag to determine whether or not to provide
the password material for SAE authentication in the nl80211 CONNECT
command.

Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com>
Signed-off-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Chung-Hsien Hsu 2019-10-02 09:31:12 +00:00 committed by Kalle Valo
parent f4268729eb
commit 3b1e0a7bdf
6 changed files with 90 additions and 8 deletions

View File

@ -1282,6 +1282,31 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
return err;
}
static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data,
u16 pwd_len)
{
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_wsec_sae_pwd_le sae_pwd;
int err;
if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) {
bphy_err(drvr, "sae_password must be less than %d\n",
BRCMF_WSEC_MAX_SAE_PASSWORD_LEN);
return -EINVAL;
}
sae_pwd.key_len = cpu_to_le16(pwd_len);
memcpy(sae_pwd.key, pwd_data, pwd_len);
err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd,
sizeof(sae_pwd));
if (err < 0)
bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n",
pwd_len);
return err;
}
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
@ -1505,6 +1530,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3)
val = WPA3_AUTH_SAE_PSK;
else
val = WPA_AUTH_DISABLED;
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
@ -1537,6 +1564,10 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
val = 1;
brcmf_dbg(CONN, "shared key\n");
break;
case NL80211_AUTHTYPE_SAE:
val = 3;
brcmf_dbg(CONN, "SAE authentication\n");
break;
default:
val = 2;
brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
@ -1705,6 +1736,16 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
sme->crypto.cipher_group);
return -EINVAL;
}
} else if (val & WPA3_AUTH_SAE_PSK) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_SAE:
val = WPA3_AUTH_SAE_PSK;
break;
default:
bphy_err(drvr, "invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
}
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
@ -1776,7 +1817,8 @@ brcmf_set_sharedkey(struct net_device *ndev,
brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
sec->wpa_versions, sec->cipher_pairwise);
if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2 |
NL80211_WPA_VERSION_3))
return 0;
if (!(sec->cipher_pairwise &
@ -1983,7 +2025,13 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
if (sme->crypto.psk) {
if (sme->crypto.sae_pwd) {
brcmf_dbg(INFO, "using SAE offload\n");
profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE;
}
if (sme->crypto.psk &&
profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) {
if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
err = -EINVAL;
goto done;
@ -2001,12 +2049,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
}
}
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK)
err = brcmf_set_pmk(ifp, sme->crypto.psk,
BRCMF_WSEC_MAX_PSK_LEN);
if (err)
else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) {
/* clean up user-space RSNE */
if (brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0)) {
bphy_err(drvr, "failed to clean up user-space RSNE\n");
goto done;
}
err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd,
sme->crypto.sae_pwd_len);
if (!err && sme->crypto.psk)
err = brcmf_set_pmk(ifp, sme->crypto.psk,
BRCMF_WSEC_MAX_PSK_LEN);
}
if (err)
goto done;
/* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only
@ -5362,7 +5421,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
brcmf_dbg(CONN, "Processing set ssid\n");
memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK &&
vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_SAE)
return true;
set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
@ -6672,6 +6732,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE))
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_SAE_OFFLOAD);
}
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;

View File

@ -107,7 +107,8 @@ struct brcmf_cfg80211_security {
enum brcmf_profile_fwsup {
BRCMF_PROFILE_FWSUP_NONE,
BRCMF_PROFILE_FWSUP_PSK,
BRCMF_PROFILE_FWSUP_1X
BRCMF_PROFILE_FWSUP_1X,
BRCMF_PROFILE_FWSUP_SAE
};
/**

View File

@ -39,7 +39,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
{ BRCMF_FEAT_P2P, "p2p" },
{ BRCMF_FEAT_MONITOR, "monitor" },
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
{ BRCMF_FEAT_DOT11H, "802.11h" }
{ BRCMF_FEAT_DOT11H, "802.11h" },
{ BRCMF_FEAT_SAE, "sae" },
};
#ifdef DEBUG

View File

@ -26,6 +26,7 @@
* MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header
* MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
* DOT11H: firmware supports 802.11h
* SAE: simultaneous authentication of equals
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@ -45,7 +46,8 @@
BRCMF_FEAT_DEF(MONITOR) \
BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
BRCMF_FEAT_DEF(DOT11H)
BRCMF_FEAT_DEF(DOT11H) \
BRCMF_FEAT_DEF(SAE)
/*
* Quirks:

View File

@ -61,6 +61,8 @@
#define BRCMF_WSEC_MAX_PSK_LEN 32
#define BRCMF_WSEC_PASSPHRASE BIT(0)
#define BRCMF_WSEC_MAX_SAE_PASSWORD_LEN 128
/* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2
@ -518,6 +520,17 @@ struct brcmf_wsec_pmk_le {
u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1];
};
/**
* struct brcmf_wsec_sae_pwd_le - firmware SAE password material.
*
* @key_len: number of octets in key materials.
* @key: SAE password material.
*/
struct brcmf_wsec_sae_pwd_le {
__le16 key_len;
u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN];
};
/* Used to get specific STA parameters */
struct brcmf_scb_val_le {
__le32 val;

View File

@ -231,6 +231,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
#define WPA2_AUTH_FT 0x4000 /* Fast BSS Transition */
#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */
#define WPA3_AUTH_SAE_PSK 0x40000 /* SAE with 4-way handshake */
#define DOT11_DEFAULT_RTS_LEN 2347
#define DOT11_DEFAULT_FRAG_LEN 2346