Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8a64f0e authored by Arend van Spriel's avatar Arend van Spriel Committed by Kalle Valo
Browse files

brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK



The firmware may have supplicant 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
pre-shared key material in the nl80211 CONNECT command.

Reviewed-by: default avatarGautam (Gautam Kumar) Shukla <gautams@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent fdcbe65d
Loading
Loading
Loading
Loading
+71 −4
Original line number Diff line number Diff line
@@ -1357,6 +1357,27 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
	return reason;
}

static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
{
	struct brcmf_wsec_pmk_le pmk;
	int i, err;

	/* convert to firmware key format */
	pmk.key_len = cpu_to_le16(pmk_len << 1);
	pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
	for (i = 0; i < pmk_len; i++)
		snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);

	/* store psk in firmware */
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
				     &pmk, sizeof(pmk));
	if (err < 0)
		brcmf_err("failed to change PSK in firmware (len=%u)\n",
			  pmk_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);
@@ -1379,6 +1400,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
	clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
	clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
	brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
	if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
		brcmf_set_pmk(vif->ifp, NULL, 0);
		vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
	}
	brcmf_dbg(TRACE, "Exit\n");
}

@@ -2012,6 +2037,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
		goto done;
	}

	if (sme->crypto.psk) {
		brcmf_dbg(INFO, "using PSK offload\n");

		/* enable firmware supplicant for this interface */
		err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
		if (err < 0) {
			brcmf_err("failed to enable fw supplicant\n");
			goto done;
		}
		ifp->vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_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
	 */
@@ -5247,16 +5289,30 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev)
		brcmf_free_vif(vif);
}

static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
			    const struct brcmf_event_msg *e)
{
	u32 event = e->event_code;
	u32 status = e->status;

	if (event == BRCMF_E_PSK_SUP &&
	    status == BRCMF_E_STATUS_FWSUP_COMPLETED)
		set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
	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)
			return true;

		set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
	}

	if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
	    test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
		clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
		clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
		return true;
	}
	return false;
}

@@ -5291,6 +5347,13 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
		return true;
	}

	if (event == BRCMF_E_PSK_SUP &&
	    status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
		brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
			  status);
		return true;
	}

	return false;
}

@@ -5448,7 +5511,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
			       &ifp->vif->sme_state)) {
		if (completed) {
			brcmf_get_assoc_ies(cfg, ifp);
			memcpy(profile->bssid, e->addr, ETH_ALEN);
			brcmf_update_bss_info(cfg, ifp);
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
@@ -5527,7 +5589,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,

	if (brcmf_is_apmode(ifp->vif)) {
		err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
	} else if (brcmf_is_linkup(e)) {
	} else if (brcmf_is_linkup(ifp->vif, e)) {
		brcmf_dbg(CONN, "Linkup\n");
		if (brcmf_is_ibssmode(ifp->vif)) {
			brcmf_inform_ibss(cfg, ndev, e->addr);
@@ -5695,6 +5757,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
			    brcmf_p2p_notify_action_tx_complete);
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
			    brcmf_p2p_notify_action_tx_complete);
	brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
			    brcmf_notify_connect_status);
}

static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -6491,6 +6555,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
		wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
	if (!ifp->drvr->settings->roamoff)
		wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP))
		wiphy_ext_feature_set(wiphy,
				      NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
	wiphy->mgmt_stypes = brcmf_txrx_stypes;
	wiphy->max_remain_on_channel_duration = 5000;
	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
+12 −2
Original line number Diff line number Diff line
@@ -115,6 +115,11 @@ struct brcmf_cfg80211_security {
	u32 cipher_group;
};

enum brcmf_profile_fwsup {
	BRCMF_PROFILE_FWSUP_NONE,
	BRCMF_PROFILE_FWSUP_PSK
};

/**
 * struct brcmf_cfg80211_profile - profile information.
 *
@@ -126,6 +131,7 @@ struct brcmf_cfg80211_profile {
	u8 bssid[ETH_ALEN];
	struct brcmf_cfg80211_security sec;
	struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
	enum brcmf_profile_fwsup use_fwsup;
};

/**
@@ -133,16 +139,20 @@ struct brcmf_cfg80211_profile {
 *
 * @BRCMF_VIF_STATUS_READY: ready for operation.
 * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
 * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
 * @BRCMF_VIF_STATUS_CONNECTED: connected/joined successfully.
 * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
 * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
 * @BRCMF_VIF_STATUS_EAP_SUCCUSS: EAPOL handshake successful.
 * @BRCMF_VIF_STATUS_ASSOC_SUCCESS: successful SET_SSID received.
 */
enum brcmf_vif_status {
	BRCMF_VIF_STATUS_READY,
	BRCMF_VIF_STATUS_CONNECTING,
	BRCMF_VIF_STATUS_CONNECTED,
	BRCMF_VIF_STATUS_DISCONNECTING,
	BRCMF_VIF_STATUS_AP_CREATED
	BRCMF_VIF_STATUS_AP_CREATED,
	BRCMF_VIF_STATUS_EAP_SUCCESS,
	BRCMF_VIF_STATUS_ASSOC_SUCCESS,
};

/**
+1 −0
Original line number Diff line number Diff line
@@ -195,6 +195,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
			  drvr->settings->feature_disable);
		ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
	}
	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");

	/* set chip related quirks */
	switch (drvr->bus_if->chip) {
+3 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
 * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
 * MFP: 802.11w Management Frame Protection.
 * GSCAN: enhanced scan offload feature.
 * FWSUP: Firmware supplicant.
 */
#define BRCMF_FEAT_LIST \
	BRCMF_FEAT_DEF(MBSS) \
@@ -46,7 +47,8 @@
	BRCMF_FEAT_DEF(WOWL_GTK) \
	BRCMF_FEAT_DEF(WOWL_ARP_ND) \
	BRCMF_FEAT_DEF(MFP) \
	BRCMF_FEAT_DEF(GSCAN)
	BRCMF_FEAT_DEF(GSCAN) \
	BRCMF_FEAT_DEF(FWSUP)

/*
 * Quirks:
+30 −0
Original line number Diff line number Diff line
@@ -142,6 +142,16 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_STATUS_CS_ABORT			15
#define BRCMF_E_STATUS_ERROR			16

/* status field values for PSK_SUP event */
#define BRCMF_E_STATUS_FWSUP_WAIT_M1		4
#define BRCMF_E_STATUS_FWSUP_PREP_M2		5
#define BRCMF_E_STATUS_FWSUP_COMPLETED		6
#define BRCMF_E_STATUS_FWSUP_TIMEOUT		7
#define BRCMF_E_STATUS_FWSUP_WAIT_M3		8
#define BRCMF_E_STATUS_FWSUP_PREP_M4		9
#define BRCMF_E_STATUS_FWSUP_WAIT_G1		10
#define BRCMF_E_STATUS_FWSUP_PREP_G2		11

/* reason field values in struct brcmf_event_msg */
#define BRCMF_E_REASON_INITIAL_ASSOC		0
#define BRCMF_E_REASON_LOW_RSSI			1
@@ -161,6 +171,26 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_REASON_TDLS_PEER_CONNECTED	1
#define BRCMF_E_REASON_TDLS_PEER_DISCONNECTED	2

/* reason field values for PSK_SUP event */
#define BRCMF_E_REASON_FWSUP_OTHER		0
#define BRCMF_E_REASON_FWSUP_DECRYPT_KEY_DATA	1
#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP128	2
#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP40	3
#define BRCMF_E_REASON_FWSUP_UNSUP_KEY_LEN	4
#define BRCMF_E_REASON_FWSUP_PW_KEY_CIPHER	5
#define BRCMF_E_REASON_FWSUP_MSG3_TOO_MANY_IE	6
#define BRCMF_E_REASON_FWSUP_MSG3_IE_MISMATCH	7
#define BRCMF_E_REASON_FWSUP_NO_INSTALL_FLAG	8
#define BRCMF_E_REASON_FWSUP_MSG3_NO_GTK	9
#define BRCMF_E_REASON_FWSUP_GRP_KEY_CIPHER	10
#define BRCMF_E_REASON_FWSUP_GRP_MSG1_NO_GTK	11
#define BRCMF_E_REASON_FWSUP_GTK_DECRYPT_FAIL	12
#define BRCMF_E_REASON_FWSUP_SEND_FAIL		13
#define BRCMF_E_REASON_FWSUP_DEAUTH		14
#define BRCMF_E_REASON_FWSUP_WPA_PSK_TMO	15
#define BRCMF_E_REASON_FWSUP_WPA_PSK_M1_TMO	16
#define BRCMF_E_REASON_FWSUP_WPA_PSK_M3_TMO	17

/* action field values for brcmf_ifevent */
#define BRCMF_E_IF_ADD				1
#define BRCMF_E_IF_DEL				2
Loading