Commit 3b1e0a7b authored by Chung-Hsien Hsu's avatar Chung-Hsien Hsu Committed by Kalle Valo

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: default avatarChung-Hsien Hsu <stanley.hsu@cypress.com>
Signed-off-by: default avatarChi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent f4268729
...@@ -1282,6 +1282,31 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) ...@@ -1282,6 +1282,31 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
return err; 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) static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); 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, ...@@ -1505,6 +1530,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3)
val = WPA3_AUTH_SAE_PSK;
else else
val = WPA_AUTH_DISABLED; val = WPA_AUTH_DISABLED;
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); 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, ...@@ -1537,6 +1564,10 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
val = 1; val = 1;
brcmf_dbg(CONN, "shared key\n"); brcmf_dbg(CONN, "shared key\n");
break; break;
case NL80211_AUTHTYPE_SAE:
val = 3;
brcmf_dbg(CONN, "SAE authentication\n");
break;
default: default:
val = 2; val = 2;
brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type); 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) ...@@ -1705,6 +1736,16 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
sme->crypto.cipher_group); sme->crypto.cipher_group);
return -EINVAL; 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) if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
...@@ -1776,7 +1817,8 @@ brcmf_set_sharedkey(struct net_device *ndev, ...@@ -1776,7 +1817,8 @@ brcmf_set_sharedkey(struct net_device *ndev,
brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n", brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
sec->wpa_versions, sec->cipher_pairwise); 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; return 0;
if (!(sec->cipher_pairwise & if (!(sec->cipher_pairwise &
...@@ -1983,7 +2025,13 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, ...@@ -1983,7 +2025,13 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done; 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)) { if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
err = -EINVAL; err = -EINVAL;
goto done; goto done;
...@@ -2001,12 +2049,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, ...@@ -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, err = brcmf_set_pmk(ifp, sme->crypto.psk,
BRCMF_WSEC_MAX_PSK_LEN); 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; 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 /* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only * If SSID is zero join based on BSSID only
...@@ -5362,7 +5421,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, ...@@ -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) { if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
brcmf_dbg(CONN, "Processing set ssid\n"); brcmf_dbg(CONN, "Processing set ssid\n");
memcpy(vif->profile.bssid, e->addr, ETH_ALEN); 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; return true;
set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); 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) ...@@ -6672,6 +6732,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
wiphy_ext_feature_set(wiphy, wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); 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->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000; wiphy->max_remain_on_channel_duration = 5000;
......
...@@ -107,7 +107,8 @@ struct brcmf_cfg80211_security { ...@@ -107,7 +107,8 @@ struct brcmf_cfg80211_security {
enum brcmf_profile_fwsup { enum brcmf_profile_fwsup {
BRCMF_PROFILE_FWSUP_NONE, BRCMF_PROFILE_FWSUP_NONE,
BRCMF_PROFILE_FWSUP_PSK, BRCMF_PROFILE_FWSUP_PSK,
BRCMF_PROFILE_FWSUP_1X BRCMF_PROFILE_FWSUP_1X,
BRCMF_PROFILE_FWSUP_SAE
}; };
/** /**
......
...@@ -39,7 +39,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { ...@@ -39,7 +39,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
{ BRCMF_FEAT_P2P, "p2p" }, { BRCMF_FEAT_P2P, "p2p" },
{ BRCMF_FEAT_MONITOR, "monitor" }, { BRCMF_FEAT_MONITOR, "monitor" },
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" }, { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
{ BRCMF_FEAT_DOT11H, "802.11h" } { BRCMF_FEAT_DOT11H, "802.11h" },
{ BRCMF_FEAT_SAE, "sae" },
}; };
#ifdef DEBUG #ifdef DEBUG
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header * MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header
* MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header * MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
* DOT11H: firmware supports 802.11h * DOT11H: firmware supports 802.11h
* SAE: simultaneous authentication of equals
*/ */
#define BRCMF_FEAT_LIST \ #define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \ BRCMF_FEAT_DEF(MBSS) \
...@@ -45,7 +46,8 @@ ...@@ -45,7 +46,8 @@
BRCMF_FEAT_DEF(MONITOR) \ BRCMF_FEAT_DEF(MONITOR) \
BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \ BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \ BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
BRCMF_FEAT_DEF(DOT11H) BRCMF_FEAT_DEF(DOT11H) \
BRCMF_FEAT_DEF(SAE)
/* /*
* Quirks: * Quirks:
......
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
#define BRCMF_WSEC_MAX_PSK_LEN 32 #define BRCMF_WSEC_MAX_PSK_LEN 32
#define BRCMF_WSEC_PASSPHRASE BIT(0) #define BRCMF_WSEC_PASSPHRASE BIT(0)
#define BRCMF_WSEC_MAX_SAE_PASSWORD_LEN 128
/* primary (ie tx) key */ /* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1) #define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2 #define DOT11_BSSTYPE_ANY 2
...@@ -518,6 +520,17 @@ struct brcmf_wsec_pmk_le { ...@@ -518,6 +520,17 @@ struct brcmf_wsec_pmk_le {
u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; 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 */ /* Used to get specific STA parameters */
struct brcmf_scb_val_le { struct brcmf_scb_val_le {
__le32 val; __le32 val;
......
...@@ -231,6 +231,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) ...@@ -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_FT 0x4000 /* Fast BSS Transition */
#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ #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_RTS_LEN 2347
#define DOT11_DEFAULT_FRAG_LEN 2346 #define DOT11_DEFAULT_FRAG_LEN 2346
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment