Commit 240d61a9 authored by Hante Meuleman's avatar Hante Meuleman Committed by Kalle Valo
Browse files

brcmfmac: add 802.11w management frame protection support



Add full support for both AP and STA for management frame protection.

Reviewed-by: default avatarArend Van Spriel <arend.van@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <franky.lin@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Signed-off-by: default avatarHante Meuleman <hante.meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 219e0f74
Loading
Loading
Loading
Loading
+200 −72
Original line number Diff line number Diff line
@@ -72,8 +72,13 @@
#define RSN_AKM_NONE			0	/* None (IBSS) */
#define RSN_AKM_UNSPECIFIED		1	/* Over 802.1x */
#define RSN_AKM_PSK			2	/* Pre-shared Key */
#define RSN_AKM_SHA256_1X		5	/* SHA256, 802.1X */
#define RSN_AKM_SHA256_PSK		6	/* SHA256, Pre-shared Key */
#define RSN_CAP_LEN			2	/* Length of RSN capabilities */
#define RSN_CAP_PTK_REPLAY_CNTR_MASK	0x000C
#define RSN_CAP_PTK_REPLAY_CNTR_MASK	(BIT(2) | BIT(3))
#define RSN_CAP_MFPR_MASK		BIT(6)
#define RSN_CAP_MFPC_MASK		BIT(7)
#define RSN_PMKID_COUNT_LEN		2

#define VNDR_IE_CMD_LEN			4	/* length of the set command
						 * string :"add", "del" (+ NUL)
@@ -211,12 +216,19 @@ static const struct ieee80211_regdomain brcmf_regdom = {
		REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
};

static const u32 __wl_cipher_suites[] = {
/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
 * are supported. A pointer to this array and the number of entries is passed
 * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
 * So the cipher suite AES_CMAC has to be the last one in the array, and when
 * device does not support MFP then the number of suites will be decreased by 1
 */
static const u32 brcmf_cipher_suites[] = {
	WLAN_CIPHER_SUITE_WEP40,
	WLAN_CIPHER_SUITE_WEP104,
	WLAN_CIPHER_SUITE_TKIP,
	WLAN_CIPHER_SUITE_CCMP,
	WLAN_CIPHER_SUITE_AES_CMAC,
	/* Keep as last entry: */
	WLAN_CIPHER_SUITE_AES_CMAC
};

/* Vendor specific ie. id = 221, oui and type defines exact ie */
@@ -1533,7 +1545,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,

static s32
brcmf_set_wsec_mode(struct net_device *ndev,
		     struct cfg80211_connect_params *sme, bool mfp)
		    struct cfg80211_connect_params *sme)
{
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
	struct brcmf_cfg80211_security *sec;
@@ -1592,9 +1604,6 @@ brcmf_set_wsec_mode(struct net_device *ndev,
	    sme->privacy)
		pval = AES_ENABLED;

	if (mfp)
		wsec = pval | gval | MFP_CAPABLE;
	else
	wsec = pval | gval;
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
	if (err) {
@@ -1612,14 +1621,21 @@ brcmf_set_wsec_mode(struct net_device *ndev,
static s32
brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
{
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;
	struct brcmf_if *ifp = netdev_priv(ndev);
	s32 val;
	s32 err;
	const struct brcmf_tlv *rsn_ie;
	const u8 *ie;
	u32 ie_len;
	u32 offset;
	u16 rsn_cap;
	u32 mfp;
	u16 count;

	if (!sme->crypto.n_akm_suites)
		return 0;

	if (sme->crypto.n_akm_suites) {
		err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
					       "wpa_auth", &val);
	err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
	if (err) {
		brcmf_err("could not get wpa_auth (%d)\n", err);
		return err;
@@ -1642,6 +1658,12 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
		case WLAN_AKM_SUITE_8021X:
			val = WPA2_AUTH_UNSPECIFIED;
			break;
		case WLAN_AKM_SUITE_8021X_SHA256:
			val = WPA2_AUTH_1X_SHA256;
			break;
		case WLAN_AKM_SUITE_PSK_SHA256:
			val = WPA2_AUTH_PSK_SHA256;
			break;
		case WLAN_AKM_SUITE_PSK:
			val = WPA2_AUTH_PSK;
			break;
@@ -1652,16 +1674,47 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
		}
	}

	if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
		goto skip_mfp_config;
	/* The MFP mode (1 or 2) needs to be determined, parse IEs. The
	 * IE will not be verified, just a quick search for MFP config
	 */
	rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
				  WLAN_EID_RSN);
	if (!rsn_ie)
		goto skip_mfp_config;
	ie = (const u8 *)rsn_ie;
	ie_len = rsn_ie->len + TLV_HDR_LEN;
	/* Skip unicast suite */
	offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
	if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
		goto skip_mfp_config;
	/* Skip multicast suite */
	count = ie[offset] + (ie[offset + 1] << 8);
	offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
	if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
		goto skip_mfp_config;
	/* Skip auth key management suite(s) */
	count = ie[offset] + (ie[offset + 1] << 8);
	offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
	if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
		goto skip_mfp_config;
	/* Ready to read capabilities */
	mfp = BRCMF_MFP_NONE;
	rsn_cap = ie[offset] + (ie[offset + 1] << 8);
	if (rsn_cap & RSN_CAP_MFPR_MASK)
		mfp = BRCMF_MFP_REQUIRED;
	else if (rsn_cap & RSN_CAP_MFPC_MASK)
		mfp = BRCMF_MFP_CAPABLE;
	brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);

skip_mfp_config:
	brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
					       "wpa_auth", val);
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
	if (err) {
		brcmf_err("could not set wpa_auth (%d)\n", err);
		return err;
	}
	}
	sec = &profile->sec;
	sec->wpa_auth = sme->crypto.akm_suites[0];

	return err;
}
@@ -1827,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
		goto done;
	}

	err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
	err = brcmf_set_wsec_mode(ndev, sme);
	if (err) {
		brcmf_err("wl_set_set_cipher failed (%d)\n", err);
		goto done;
@@ -2077,10 +2130,12 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
		       u8 key_idx, bool pairwise, const u8 *mac_addr)
{
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_wsec_key key;
	s32 err = 0;
	struct brcmf_wsec_key *key;
	s32 err;

	brcmf_dbg(TRACE, "Enter\n");
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);

	if (!check_vif_up(ifp->vif))
		return -EIO;

@@ -2089,16 +2144,19 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
		return -EINVAL;
	}

	memset(&key, 0, sizeof(key));
	key = &ifp->vif->profile.key[key_idx];

	key.index = (u32)key_idx;
	key.flags = BRCMF_PRIMARY_KEY;
	key.algo = CRYPTO_ALGO_OFF;
	if (key->algo == CRYPTO_ALGO_OFF) {
		brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
		return -EINVAL;
	}

	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
	memset(key, 0, sizeof(*key));
	key->index = (u32)key_idx;
	key->flags = BRCMF_PRIMARY_KEY;

	/* Set the new key/index */
	err = send_key_to_dongle(ifp, &key);
	/* Clear the key/index */
	err = send_key_to_dongle(ifp, key);

	brcmf_dbg(TRACE, "Exit\n");
	return err;
@@ -2214,9 +2272,10 @@ done:
}

static s32
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
		    u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
		    void (*callback) (void *cookie, struct key_params * params))
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
		       bool pairwise, const u8 *mac_addr, void *cookie,
		       void (*callback)(void *cookie,
					struct key_params *params))
{
	struct key_params params;
	struct brcmf_if *ifp = netdev_priv(ndev);
@@ -2270,6 +2329,13 @@ static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
				       struct net_device *ndev, u8 key_idx)
{
	struct brcmf_if *ifp = netdev_priv(ndev);

	brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);

	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
		return 0;

	brcmf_dbg(INFO, "Not supported\n");

	return -EOPNOTSUPP;
@@ -3769,7 +3835,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
	u32 auth = 0; /* d11 open authentication */
	u16 count;
	s32 err = 0;
	s32 len = 0;
	s32 len;
	u32 i;
	u32 wsec;
	u32 pval = 0;
@@ -3779,6 +3845,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
	u8 *data;
	u16 rsn_cap;
	u32 wme_bss_disable;
	u32 mfp;

	brcmf_dbg(TRACE, "Enter\n");
	if (wpa_ie == NULL)
@@ -3893,19 +3960,53 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
			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;
		default:
			brcmf_err("Ivalid key mgmt info\n");
		}
		offset++;
	}

	mfp = BRCMF_MFP_NONE;
	if (is_rsn_ie) {
		wme_bss_disable = 1;
		if ((offset + RSN_CAP_LEN) <= len) {
			rsn_cap = data[offset] + (data[offset + 1] << 8);
			if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
				wme_bss_disable = 0;
			if (rsn_cap & RSN_CAP_MFPR_MASK) {
				brcmf_dbg(TRACE, "MFP Required\n");
				mfp = BRCMF_MFP_REQUIRED;
				/* Firmware only supports mfp required in
				 * combination with WPA2_AUTH_PSK_SHA256 or
				 * WPA2_AUTH_1X_SHA256.
				 */
				if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
						  WPA2_AUTH_1X_SHA256))) {
					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.
				 */
				if (wpa_auth & WPA2_AUTH_PSK_SHA256)
					wpa_auth |= WPA2_AUTH_PSK;
				else if (wpa_auth & WPA2_AUTH_1X_SHA256)
					wpa_auth |= WPA2_AUTH_UNSPECIFIED;
			} else if (rsn_cap & RSN_CAP_MFPC_MASK) {
				brcmf_dbg(TRACE, "MFP Capable\n");
				mfp = BRCMF_MFP_CAPABLE;
			}
		}
		offset += RSN_CAP_LEN;
		/* set wme_bss_disable to sync RSN Capabilities */
		err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
					       wme_bss_disable);
@@ -3913,6 +4014,21 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
			brcmf_err("wme_bss_disable error %d\n", err);
			goto exit;
		}

		/* Skip PMKID cnt as it is know to be 0 for AP. */
		offset += RSN_PMKID_COUNT_LEN;

		/* See if there is BIP wpa suite left for MFP */
		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
		    ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
			err = brcmf_fil_bsscfg_data_set(ifp, "bip",
							&data[offset],
							WPA_IE_MIN_OUI_LEN);
			if (err < 0) {
				brcmf_err("bip error %d\n", err);
				goto exit;
			}
		}
	}
	/* FOR WPS , set SES_OW_ENABLED */
	wsec = (pval | gval | SES_OW_ENABLED);
@@ -3929,6 +4045,16 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
		brcmf_err("wsec error %d\n", err);
		goto exit;
	}
	/* Configure MFP, this needs to go after wsec otherwise the wsec command
	 * will overwrite the values set by MFP
	 */
	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
		err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
		if (err < 0) {
			brcmf_err("mfp error %d\n", err);
			goto exit;
		}
	}
	/* set upper-layer auth */
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
	if (err < 0) {
@@ -6149,8 +6275,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
	wiphy->n_addresses = i;

	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
	wiphy->cipher_suites = __wl_cipher_suites;
	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
	wiphy->cipher_suites = brcmf_cipher_suites;
	wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
	if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
		wiphy->n_cipher_suites--;
	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
			WIPHY_FLAG_OFFCHAN_TX |
			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+1 −2
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@

#define BRCMF_VNDR_IE_P2PAF_SHIFT	12

#define BRCMF_MAX_DEFAULT_KEYS		4
#define BRCMF_MAX_DEFAULT_KEYS		6

/* beacon loss timeout defaults */
#define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON	2
@@ -107,7 +107,6 @@ struct brcmf_cfg80211_security {
	u32 auth_type;
	u32 cipher_pairwise;
	u32 cipher_group;
	u32 wpa_auth;
};

/**
+1 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
		ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");

	pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
	err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
+3 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
 * WOWL_ND: WOWL net detect (PNO)
 * WOWL_GTK: (WOWL) GTK rekeying offload
 * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
 * MFP: 802.11w Management Frame Protection.
 */
#define BRCMF_FEAT_LIST \
	BRCMF_FEAT_DEF(MBSS) \
@@ -42,7 +43,8 @@
	BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \
	BRCMF_FEAT_DEF(WOWL_ND) \
	BRCMF_FEAT_DEF(WOWL_GTK) \
	BRCMF_FEAT_DEF(WOWL_ARP_ND)
	BRCMF_FEAT_DEF(WOWL_ARP_ND) \
	BRCMF_FEAT_DEF(MFP)

/*
 * Quirks:
+4 −0
Original line number Diff line number Diff line
@@ -142,6 +142,10 @@
#define BRCMF_RSN_KEK_LENGTH		16
#define BRCMF_RSN_REPLAY_LEN		8

#define BRCMF_MFP_NONE			0
#define BRCMF_MFP_CAPABLE		1
#define BRCMF_MFP_REQUIRED		2

/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
	BRCMF_JOIN_PREF_RSSI = 1,
Loading