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

Commit 3a00df57 authored by Avraham Stern's avatar Avraham Stern Committed by Johannes Berg
Browse files

cfg80211: support 4-way handshake offloading for 802.1X



Add API for setting the PMK to the driver. For FT support, allow
setting also the PMK-R0 Name.

This can be used by drivers that support 4-Way handshake offload
while IEEE802.1X authentication is managed by upper layers.

Signed-off-by: default avatarAvraham Stern <avraham.stern@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
[arend.vanspriel@broadcom.com: add WANT_1X_4WAY_HS attribute]
Signed-off-by: default avatarArend van Spriel <arend.vanspriel@broadcom.com>
[reword NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X docs a bit to
say that the device may require it]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 91b5ab62
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2400,8 +2400,11 @@ enum ieee80211_sa_query_action {

#define WLAN_MAX_KEY_LEN		32

#define WLAN_PMK_NAME_LEN		16
#define WLAN_PMKID_LEN			16
#define WLAN_PMK_LEN_EAP_LEAP		16
#define WLAN_PMK_LEN			32
#define WLAN_PMK_LEN_SUITE_B_192	48

#define WLAN_OUI_WFA			0x506f9a
#define WLAN_OUI_TYPE_WFA_P2P		9
+32 −0
Original line number Diff line number Diff line
@@ -2112,6 +2112,8 @@ struct cfg80211_bss_selection {
 * @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional
 *	keys in FILS or %NULL if not specified.
 * @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
 * @want_1x: indicates user-space supports and wants to use 802.1X driver
 *	offload of 4-way handshake.
 */
struct cfg80211_connect_params {
	struct ieee80211_channel *channel;
@@ -2144,6 +2146,7 @@ struct cfg80211_connect_params {
	u16 fils_erp_next_seq_num;
	const u8 *fils_erp_rrk;
	size_t fils_erp_rrk_len;
	bool want_1x;
};

/**
@@ -2565,6 +2568,23 @@ struct cfg80211_nan_func {
	u64 cookie;
};

/**
 * struct cfg80211_pmk_conf - PMK configuration
 *
 * @aa: authenticator address
 * @pmk_len: PMK length in bytes.
 * @pmk: the PMK material
 * @pmk_r0_name: PMK-R0 Name. NULL if not applicable (i.e., the PMK
 *	is not PMK-R0). When pmk_r0_name is not NULL, the pmk field
 *	holds PMK-R0.
 */
struct cfg80211_pmk_conf {
	const u8 *aa;
	u8 pmk_len;
	const u8 *pmk;
	const u8 *pmk_r0_name;
};

/**
 * struct cfg80211_ops - backend description for wireless configuration
 *
@@ -2881,6 +2901,13 @@ struct cfg80211_nan_func {
 *	All other parameters must be ignored.
 *
 * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
 *
 * @set_pmk: configure the PMK to be used for offloaded 802.1X 4-Way handshake.
 *	If not deleted through @del_pmk the PMK remains valid until disconnect
 *	upon which the driver should clear it.
 *	(invoked with the wireless_dev mutex held)
 * @del_pmk: delete the previously configured PMK for the given authenticator.
 *	(invoked with the wireless_dev mutex held)
 */
struct cfg80211_ops {
	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3169,6 +3196,11 @@ struct cfg80211_ops {
	int	(*set_multicast_to_unicast)(struct wiphy *wiphy,
					    struct net_device *dev,
					    const bool enabled);

	int	(*set_pmk)(struct wiphy *wiphy, struct net_device *dev,
			   const struct cfg80211_pmk_conf *conf);
	int	(*del_pmk)(struct wiphy *wiphy, struct net_device *dev,
			   const u8 *aa);
};

/*
+38 −1
Original line number Diff line number Diff line
@@ -182,6 +182,17 @@
 * this offload may reject the %NL80211_CMD_CONNECT when no preshared
 * key material is provided, for example when that driver does not
 * support setting the temporal keys through %CMD_NEW_KEY.
 *
 * Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be
 * set by drivers indicating offload support of the PTK/GTK EAPOL
 * handshakes during 802.1X authentication. In order to use the offload
 * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS
 * attribute flag. Drivers supporting this offload may reject the
 * %NL80211_CMD_CONNECT when the attribute flag is not present.
 *
 * For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK
 * using %NL80211_CMD_SET_PMK. For offloaded FT support also
 * %NL80211_ATTR_PMKR0_NAME must be provided.
 */

/**
@@ -959,6 +970,14 @@
 *	does not result in a change for the current association. Currently,
 *	only the %NL80211_ATTR_IE data is used and updated with this command.
 *
 * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
 *	for the given authenticator address (specified with &NL80211_ATTR_MAC).
 *	When &NL80211_ATTR_PMKR0_NAME is set, &NL80211_ATTR_PMK specifies the
 *	PMK-R0, otherwise it specifies the PMK.
 * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
 *	configured PMK for the authenticator address identified by
 *	&NL80211_ATTR_MAC.
 *
 * @NL80211_CMD_MAX: highest used command number
 * @__NL80211_CMD_AFTER_LAST: internal use
 */
@@ -1158,6 +1177,9 @@ enum nl80211_commands {

	NL80211_CMD_UPDATE_CONNECT_PARAMS,

	NL80211_CMD_SET_PMK,
	NL80211_CMD_DEL_PMK,

	/* add new commands above here */

	/* used to define NL80211_CMD_MAX below */
@@ -2095,13 +2117,20 @@ enum nl80211_commands {
 * @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
 *	%NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
 *	For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
 *	handshake for WPA/WPA2-PSK networks.
 *	handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is
 *	used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute
 *	specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well.
 *
 * @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
 *	indicate that it supports multiple active scheduled scan requests.
 * @NL80211_ATTR_SCHED_SCAN_MAX_REQS: indicates maximum number of scheduled
 *	scan request that may be active for the device (u32).
 *
 * @NL80211_ATTR_WANT_1X_4WAY_HS: flag attribute which user-space can include
 *	in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it
 *	wants to use the supported offload of the 4-way handshake.
 * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
 *
 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
 * @NL80211_ATTR_MAX: highest attribute number currently defined
 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2524,6 +2553,9 @@ enum nl80211_attrs {
	NL80211_ATTR_SCHED_SCAN_MULTI,
	NL80211_ATTR_SCHED_SCAN_MAX_REQS,

	NL80211_ATTR_WANT_1X_4WAY_HS,
	NL80211_ATTR_PMKR0_NAME,

	/* add attributes here, update the policy in nl80211.c */

	__NL80211_ATTR_AFTER_LAST,
@@ -4869,6 +4901,10 @@ enum nl80211_feature_flags {
 * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device wants to do 4-way
 *	handshake with PSK in station mode (PSK is passed as part of the connect
 *	and associate commands), doing it in the host might not be supported.
 * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X: Device wants to do doing 4-way
 *	handshake with 802.1X in station mode (will pass EAP frames to the host
 *	and accept the set_pmk/del_pmk commands), doing it in the host might not
 *	be supported.
 *
 * @NUM_NL80211_EXT_FEATURES: number of extended features.
 * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4890,6 +4926,7 @@ enum nl80211_ext_feature_index {
	NL80211_EXT_FEATURE_CQM_RSSI_LIST,
	NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
	NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
	NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,

	/* add new features before the definition below */
	NUM_NL80211_EXT_FEATURES,
+5 −0
Original line number Diff line number Diff line
@@ -711,6 +711,11 @@ int wiphy_register(struct wiphy *wiphy)
		    (wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2))))
		return -EINVAL;

	if (WARN_ON(wiphy_ext_feature_isset(&rdev->wiphy,
					    NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X) &&
		    (!rdev->ops->set_pmk || !rdev->ops->del_pmk)))
		return -EINVAL;

	if (wiphy->addresses)
		memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);

+105 −0
Original line number Diff line number Diff line
@@ -8881,6 +8881,12 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)

	connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];

	if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
	    !wiphy_ext_feature_isset(&rdev->wiphy,
				     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
		return -EINVAL;
	connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];

	err = nl80211_crypto_settings(rdev, info, &connect.crypto,
				      NL80211_MAX_NR_CIPHER_SUITES);
	if (err)
@@ -12265,6 +12271,90 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
	return rdev_set_multicast_to_unicast(rdev, dev, enabled);
}

static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_pmk_conf pmk_conf = {};
	int ret;

	if (wdev->iftype != NL80211_IFTYPE_STATION &&
	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;

	if (!wiphy_ext_feature_isset(&rdev->wiphy,
				     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
		return -EINVAL;

	wdev_lock(wdev);
	if (!wdev->current_bss) {
		ret = -ENOTCONN;
		goto out;
	}

	pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
	if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
		ret = -EINVAL;
		goto out;
	}

	pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
	pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
	if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
	    pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
		ret = -EINVAL;
		goto out;
	}

	if (info->attrs[NL80211_ATTR_PMKR0_NAME]) {
		int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]);

		if (r0_name_len != WLAN_PMK_NAME_LEN) {
			ret = -EINVAL;
			goto out;
		}

		pmk_conf.pmk_r0_name =
			nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
	}

	ret = rdev_set_pmk(rdev, dev, &pmk_conf);
out:
	wdev_unlock(wdev);
	return ret;
}

static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct net_device *dev = info->user_ptr[1];
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	const u8 *aa;
	int ret;

	if (wdev->iftype != NL80211_IFTYPE_STATION &&
	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
		return -EOPNOTSUPP;

	if (!wiphy_ext_feature_isset(&rdev->wiphy,
				     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
		return -EOPNOTSUPP;

	if (!info->attrs[NL80211_ATTR_MAC])
		return -EINVAL;

	wdev_lock(wdev);
	aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
	ret = rdev_del_pmk(rdev, dev, aa);
	wdev_unlock(wdev);

	return ret;
}

#define NL80211_FLAG_NEED_WIPHY		0x01
#define NL80211_FLAG_NEED_NETDEV	0x02
#define NL80211_FLAG_NEED_RTNL		0x04
@@ -13140,6 +13230,21 @@ static const struct genl_ops nl80211_ops[] = {
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_SET_PMK,
		.doit = nl80211_set_pmk,
		.policy = nl80211_policy,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL80211_CMD_DEL_PMK,
		.doit = nl80211_del_pmk,
		.policy = nl80211_policy,
		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},

};

static struct genl_family nl80211_fam __ro_after_init = {
Loading