mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 22:44:08 -04:00
wifi: brcmfmac: add DPP support
Add DPP AKM handling and RSN parsing support. Map DPP to the firmware wpa_auth value and recognize DPP public action frames in the P2P action-frame TX path. Gate sup_wpa programming on firmware supplicant capability. Disable it only when the selected connection mode does not use firmware supplicant. This keeps pure SAE and 802.1X firmware-supplicant paths intact while avoiding stale firmware supplicant state for DPP. Signed-off-by: Kurt Lee <kurt.lee@cypress.com> Signed-off-by: Jason Huang <jason.huang2@infineon.com> Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com> Link: https://patch.msgid.link/20260715084718.667522-1-Jason.Huang2@infineon.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
d7cac6fced
commit
69bd85e933
@@ -8,6 +8,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/netlink.h>
|
||||
@@ -2174,6 +2175,9 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
||||
val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
|
||||
profile->is_ft = true;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_WFA_DPP:
|
||||
val = WFA_AUTH_DPP;
|
||||
break;
|
||||
default:
|
||||
bphy_err(drvr, "invalid akm suite (%d)\n",
|
||||
sme->crypto.akm_suites[0]);
|
||||
@@ -2483,43 +2487,50 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
brcmf_dbg(INFO, "using PSK offload\n");
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
|
||||
}
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
|
||||
u32 akm = sme->crypto.n_akm_suites ? sme->crypto.akm_suites[0] : 0;
|
||||
bool is_sae_akm = akm == WLAN_AKM_SUITE_SAE ||
|
||||
akm == WLAN_AKM_SUITE_FT_OVER_SAE;
|
||||
|
||||
if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
|
||||
/* enable firmware supplicant for this interface */
|
||||
err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
|
||||
if (err < 0) {
|
||||
bphy_err(drvr, "failed to enable fw supplicant\n");
|
||||
goto done;
|
||||
if (sme->crypto.psk && !is_sae_akm &&
|
||||
profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) {
|
||||
if (WARN_ON(profile->use_fwsup !=
|
||||
BRCMF_PROFILE_FWSUP_NONE)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
brcmf_dbg(INFO, "using PSK offload\n");
|
||||
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);
|
||||
else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) {
|
||||
/* clean up user-space RSNE */
|
||||
err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0);
|
||||
if (err) {
|
||||
bphy_err(drvr, "failed to clean up user-space RSNE\n");
|
||||
goto done;
|
||||
if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
|
||||
/* enable firmware supplicant for this interface */
|
||||
err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
|
||||
if (err < 0) {
|
||||
bphy_err(drvr, "failed to enable fw supplicant\n");
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 0);
|
||||
}
|
||||
err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto);
|
||||
if (!err && sme->crypto.psk)
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK)
|
||||
err = brcmf_set_pmk(ifp, sme->crypto.psk,
|
||||
BRCMF_WSEC_MAX_PSK_LEN);
|
||||
else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE &&
|
||||
sme->crypto.sae_pwd &&
|
||||
brcmf_feat_is_enabled(ifp, BRCMF_FEAT_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_fwvid_set_sae_password(ifp, &sme->crypto);
|
||||
if (!err && sme->crypto.psk)
|
||||
err = brcmf_set_pmk(ifp, sme->crypto.psk,
|
||||
BRCMF_WSEC_MAX_PSK_LEN);
|
||||
}
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
/* Join with specific BSSID and cached SSID
|
||||
* If SSID is zero join based on BSSID only
|
||||
*/
|
||||
@@ -4538,6 +4549,11 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
|
||||
return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
|
||||
}
|
||||
|
||||
static bool brcmf_valid_dpp_suite(u8 *oui)
|
||||
{
|
||||
return get_unaligned_be32(oui) == WLAN_AKM_SUITE_WFA_DPP;
|
||||
}
|
||||
|
||||
static s32
|
||||
brcmf_configure_wpaie(struct brcmf_if *ifp,
|
||||
const struct brcmf_vs_tlv *wpa_ie,
|
||||
@@ -4651,42 +4667,47 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
|
||||
goto exit;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
|
||||
if (brcmf_valid_dpp_suite(&data[offset])) {
|
||||
wpa_auth |= WFA_AUTH_DPP;
|
||||
offset += TLV_OUI_LEN;
|
||||
} else if (brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
|
||||
offset += TLV_OUI_LEN;
|
||||
switch (data[offset]) {
|
||||
case RSN_AKM_NONE:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
|
||||
wpa_auth |= WPA_AUTH_NONE;
|
||||
break;
|
||||
case RSN_AKM_UNSPECIFIED:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
|
||||
is_rsn_ie ?
|
||||
(wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
|
||||
(wpa_auth |= WPA_AUTH_UNSPECIFIED);
|
||||
break;
|
||||
case RSN_AKM_PSK:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
|
||||
is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
|
||||
(wpa_auth |= WPA_AUTH_PSK);
|
||||
break;
|
||||
case RSN_AKM_SHA256_PSK:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
|
||||
wpa_auth |= WPA2_AUTH_PSK_SHA256;
|
||||
break;
|
||||
case RSN_AKM_SHA256_1X:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
|
||||
wpa_auth |= WPA2_AUTH_1X_SHA256;
|
||||
break;
|
||||
case RSN_AKM_SAE:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_SAE\n");
|
||||
wpa_auth |= WPA3_AUTH_SAE_PSK;
|
||||
break;
|
||||
default:
|
||||
bphy_err(drvr, "Invalid key mgmt info\n");
|
||||
}
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
bphy_err(drvr, "invalid OUI\n");
|
||||
goto exit;
|
||||
}
|
||||
offset += TLV_OUI_LEN;
|
||||
switch (data[offset]) {
|
||||
case RSN_AKM_NONE:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
|
||||
wpa_auth |= WPA_AUTH_NONE;
|
||||
break;
|
||||
case RSN_AKM_UNSPECIFIED:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
|
||||
is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
|
||||
(wpa_auth |= WPA_AUTH_UNSPECIFIED);
|
||||
break;
|
||||
case RSN_AKM_PSK:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
|
||||
is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
|
||||
(wpa_auth |= WPA_AUTH_PSK);
|
||||
break;
|
||||
case RSN_AKM_SHA256_PSK:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
|
||||
wpa_auth |= WPA2_AUTH_PSK_SHA256;
|
||||
break;
|
||||
case RSN_AKM_SHA256_1X:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
|
||||
wpa_auth |= WPA2_AUTH_1X_SHA256;
|
||||
break;
|
||||
case RSN_AKM_SAE:
|
||||
brcmf_dbg(TRACE, "RSN_AKM_SAE\n");
|
||||
wpa_auth |= WPA3_AUTH_SAE_PSK;
|
||||
break;
|
||||
default:
|
||||
bphy_err(drvr, "Invalid key mgmt info\n");
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
@@ -4706,10 +4727,12 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
|
||||
*/
|
||||
if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
|
||||
WPA2_AUTH_1X_SHA256 |
|
||||
WFA_AUTH_DPP |
|
||||
WPA3_AUTH_SAE_PSK))) {
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Firmware has requirement that WPA2_AUTH_PSK/
|
||||
* WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
|
||||
* is to be included in the rsn ie.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include <brcmu_wifi.h>
|
||||
@@ -44,9 +45,6 @@
|
||||
|
||||
#define BRCMF_SCB_TIMEOUT_VALUE 20
|
||||
|
||||
#define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */
|
||||
#define P2P_PUB_AF_CATEGORY 0x04
|
||||
#define P2P_PUB_AF_ACTION 0x09
|
||||
#define P2P_AF_CATEGORY 0x7f
|
||||
#define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */
|
||||
#define P2P_OUI_LEN 3 /* P2P OUI length */
|
||||
@@ -143,10 +141,10 @@ struct brcmf_p2p_scan_le {
|
||||
/**
|
||||
* struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame
|
||||
*
|
||||
* @category: P2P_PUB_AF_CATEGORY
|
||||
* @action: P2P_PUB_AF_ACTION
|
||||
* @category: WLAN_CATEGORY_PUBLIC
|
||||
* @action: WLAN_PUB_ACTION_VENDOR_SPECIFIC
|
||||
* @oui: P2P_OUI
|
||||
* @oui_type: OUI type - P2P_VER
|
||||
* @oui_type: OUI type - WLAN_OUI_TYPE_WFA_P2P
|
||||
* @subtype: OUI subtype - P2P_TYPE_*
|
||||
* @dialog_token: nonzero, identifies req/rsp transaction
|
||||
* @elts: Variable length information elements.
|
||||
@@ -166,7 +164,7 @@ struct brcmf_p2p_pub_act_frame {
|
||||
*
|
||||
* @category: P2P_AF_CATEGORY
|
||||
* @oui: OUI - P2P_OUI
|
||||
* @type: OUI Type - P2P_VER
|
||||
* @type: OUI Type - WLAN_OUI_TYPE_WFA_P2P
|
||||
* @subtype: OUI Subtype - P2P_AF_*
|
||||
* @dialog_token: nonzero, identifies req/resp tranaction
|
||||
* @elts: Variable length information elements.
|
||||
@@ -228,10 +226,38 @@ static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
|
||||
if (frame_len < sizeof(*pact_frm))
|
||||
return false;
|
||||
|
||||
if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
|
||||
pact_frm->action == P2P_PUB_AF_ACTION &&
|
||||
pact_frm->oui_type == P2P_VER &&
|
||||
memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
|
||||
if (pact_frm->category == WLAN_CATEGORY_PUBLIC &&
|
||||
pact_frm->action == WLAN_PUB_ACTION_VENDOR_SPECIFIC &&
|
||||
pact_frm->oui_type == WLAN_OUI_TYPE_WFA_P2P &&
|
||||
get_unaligned_be24(pact_frm->oui) == WLAN_OUI_WFA)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* brcmf_p2p_is_dpp_pub_action() - true if dpp public type frame.
|
||||
*
|
||||
* @frame: action frame data.
|
||||
* @frame_len: length of action frame data.
|
||||
*
|
||||
* Determine if action frame is dpp public action type
|
||||
*/
|
||||
static bool brcmf_p2p_is_dpp_pub_action(void *frame, u32 frame_len)
|
||||
{
|
||||
struct brcmf_p2p_pub_act_frame *pact_frm;
|
||||
|
||||
if (!frame)
|
||||
return false;
|
||||
|
||||
pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
|
||||
if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
|
||||
return false;
|
||||
|
||||
if (pact_frm->category == WLAN_CATEGORY_PUBLIC &&
|
||||
pact_frm->action == WLAN_PUB_ACTION_VENDOR_SPECIFIC &&
|
||||
pact_frm->oui_type == WLAN_OUI_TYPE_WFA_DPP &&
|
||||
get_unaligned_be24(pact_frm->oui) == WLAN_OUI_WFA)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -257,7 +283,7 @@ static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
|
||||
return false;
|
||||
|
||||
if (act_frm->category == P2P_AF_CATEGORY &&
|
||||
act_frm->type == P2P_VER &&
|
||||
act_frm->type == WLAN_OUI_TYPE_WFA_P2P &&
|
||||
memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
|
||||
return true;
|
||||
|
||||
@@ -1782,7 +1808,9 @@ bool brcmf_p2p_send_action_frame(struct brcmf_if *ifp,
|
||||
goto exit;
|
||||
}
|
||||
} else if (brcmf_p2p_is_p2p_action(action_frame->data,
|
||||
action_frame_len)) {
|
||||
action_frame_len) ||
|
||||
brcmf_p2p_is_dpp_pub_action(action_frame->data,
|
||||
action_frame_len)) {
|
||||
/* do not configure anything. it will be */
|
||||
/* sent with a default configuration */
|
||||
} else {
|
||||
|
||||
@@ -233,6 +233,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
|
||||
|
||||
#define WPA3_AUTH_SAE_PSK 0x40000 /* SAE with 4-way handshake */
|
||||
|
||||
#define WFA_AUTH_DPP 0x200000 /* WFA DPP AUTH */
|
||||
|
||||
#define DOT11_DEFAULT_RTS_LEN 2347
|
||||
#define DOT11_DEFAULT_FRAG_LEN 2346
|
||||
|
||||
|
||||
Reference in New Issue
Block a user