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

Commit 1dd2eefb authored by Johannes Berg's avatar Johannes Berg
Browse files

Merge branch 'eapol-over-nl80211' into mac80211-next



This is the EAPoL over nl80211 patchset from Denis Kenzior, minus some
infrastructure patches I'd split out and applied earlier. Denis described
it as follows:

This patchset adds support for running 802.11 authentication mechanisms (e.g.
802.1X, 4-Way Handshake, etc) over NL80211 instead of putting them onto the
network device.  This has the advantage of fixing several long-standing race
conditions that result from userspace operating on multiple transports in order
to manage a 802.11 connection (e.g. NL80211 and wireless netdev, wlan0, etc).

For example, userspace would sometimes see 4-Way handshake packets before
NL80211 signaled that the connection has been established.  Leading to ugly
hacks or having the STA wait for retransmissions from the AP.

This also provides a way to mitigate a particularly nasty race condition where
the encryption key could be set prior to the 4-way handshake packet 4/4 being
sent.  This would result in the packet being sent encrypted and discarded by
the peer.  The mitigation strategy for this race is for userspace to explicitly
tell the kernel that a particular EAPoL packet should not be encrypted.

To make this possible this patchset introduces a new NL80211 command and several
new attributes.  A userspace that is capable of processing EAPoL packets over
NL80211 includes a new NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute in its
NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT requests being sent to the kernel.
The previously added NL80211_ATTR_SOCKET_OWNER attribute must also be included.
The latter is used by the kernel to send NL80211_CMD_CONTROL_PORT_FRAME
notifications back to userspace via a netlink unicast.  If the
NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute is not specified, then legacy
behavior is kept and control port packets continue to flow over the network
interface.

If control port over nl80211 transport is requested, then control port packets
are intercepted just prior to being handed to the network device and sent over
netlink via the NL80211_CMD_CONTROL_PORT_FRAME notification.
NL80211_ATTR_CONTROL_PORT_ETHERTYPE and NL80211_ATTR_MAC are included to
specify the control port frame protocol and source address respectively.  If
the control port frame was received unencrypted then
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag is also included.  NL80211_ATTR_FRAME
attribute contains the raw control port frame with all transport layer headers
stripped (e.g. this would be the raw EAPoL frame).

Userspace can reply to control port frames either via legacy methods (by sending
frames to the network device) or via NL80211_CMD_CONTROL_PORT_FRAME request.
Userspace would included NL80211_ATTR_FRAME with the raw control port frame as
well as NL80211_Attr_MAC and NL80211_ATTR_CONTROL_PORT_ETHERTYPE attributes to
specify the destination address and protocol respectively.  This allows
Pre-Authentication (protocol 0x88c7) frames to be sent via this mechanism as
well.  Finally, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag can be included to
tell the driver to send the frame unencrypted, e.g. for 4-Way handshake 4/4
frames.

The proposed patchset has been tested in a mac80211_hwsim based environment with
hostapd and iwd.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parents 4d191c75 018f6fbf
Loading
Loading
Loading
Loading
+40 −0
Original line number Original line Diff line number Diff line
@@ -647,6 +647,8 @@ struct survey_info {
 *	allowed through even on unauthorized ports
 *	allowed through even on unauthorized ports
 * @control_port_no_encrypt: TRUE to prevent encryption of control port
 * @control_port_no_encrypt: TRUE to prevent encryption of control port
 *	protocol frames.
 *	protocol frames.
 * @control_port_over_nl80211: TRUE if userspace expects to exchange control
 *	port frames over NL80211 instead of the network interface.
 * @wep_keys: static WEP keys, if not NULL points to an array of
 * @wep_keys: static WEP keys, if not NULL points to an array of
 *	CFG80211_MAX_WEP_KEYS WEP keys
 *	CFG80211_MAX_WEP_KEYS WEP keys
 * @wep_tx_key: key index (0..3) of the default TX static WEP key
 * @wep_tx_key: key index (0..3) of the default TX static WEP key
@@ -662,6 +664,7 @@ struct cfg80211_crypto_settings {
	bool control_port;
	bool control_port;
	__be16 control_port_ethertype;
	__be16 control_port_ethertype;
	bool control_port_no_encrypt;
	bool control_port_no_encrypt;
	bool control_port_over_nl80211;
	struct key_params *wep_keys;
	struct key_params *wep_keys;
	int wep_tx_key;
	int wep_tx_key;
	const u8 *psk;
	const u8 *psk;
@@ -1451,6 +1454,8 @@ struct mesh_config {
 * @userspace_handles_dfs: whether user space controls DFS operation, i.e.
 * @userspace_handles_dfs: whether user space controls DFS operation, i.e.
 *	changes the channel when a radar is detected. This is required
 *	changes the channel when a radar is detected. This is required
 *	to operate on DFS channels.
 *	to operate on DFS channels.
 * @control_port_over_nl80211: TRUE if userspace expects to exchange control
 *	port frames over NL80211 instead of the network interface.
 *
 *
 * These parameters are fixed when the mesh is created.
 * These parameters are fixed when the mesh is created.
 */
 */
@@ -1473,6 +1478,7 @@ struct mesh_setup {
	u32 basic_rates;
	u32 basic_rates;
	struct cfg80211_bitrate_mask beacon_rate;
	struct cfg80211_bitrate_mask beacon_rate;
	bool userspace_handles_dfs;
	bool userspace_handles_dfs;
	bool control_port_over_nl80211;
};
};


/**
/**
@@ -2031,6 +2037,8 @@ struct cfg80211_disassoc_request {
 *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
 *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
 *	required to assume that the port is unauthorized until authorized by
 *	required to assume that the port is unauthorized until authorized by
 *	user space. Otherwise, port is marked authorized by default.
 *	user space. Otherwise, port is marked authorized by default.
 * @control_port_over_nl80211: TRUE if userspace expects to exchange control
 *	port frames over NL80211 instead of the network interface.
 * @userspace_handles_dfs: whether user space controls DFS operation, i.e.
 * @userspace_handles_dfs: whether user space controls DFS operation, i.e.
 *	changes the channel when a radar is detected. This is required
 *	changes the channel when a radar is detected. This is required
 *	to operate on DFS channels.
 *	to operate on DFS channels.
@@ -2054,6 +2062,7 @@ struct cfg80211_ibss_params {
	bool channel_fixed;
	bool channel_fixed;
	bool privacy;
	bool privacy;
	bool control_port;
	bool control_port;
	bool control_port_over_nl80211;
	bool userspace_handles_dfs;
	bool userspace_handles_dfs;
	int mcast_rate[NUM_NL80211_BANDS];
	int mcast_rate[NUM_NL80211_BANDS];
	struct ieee80211_ht_cap ht_capa;
	struct ieee80211_ht_cap ht_capa;
@@ -2961,6 +2970,9 @@ struct cfg80211_external_auth_params {
 *
 *
 * @external_auth: indicates result of offloaded authentication processing from
 * @external_auth: indicates result of offloaded authentication processing from
 *     user space
 *     user space
 *
 * @tx_control_port: TX a control port frame (EAPoL).  The noencrypt parameter
 *	tells the driver that the frame should not be encrypted.
 */
 */
struct cfg80211_ops {
struct cfg80211_ops {
	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3256,6 +3268,12 @@ struct cfg80211_ops {
			   const u8 *aa);
			   const u8 *aa);
	int     (*external_auth)(struct wiphy *wiphy, struct net_device *dev,
	int     (*external_auth)(struct wiphy *wiphy, struct net_device *dev,
				 struct cfg80211_external_auth_params *params);
				 struct cfg80211_external_auth_params *params);

	int	(*tx_control_port)(struct wiphy *wiphy,
				   struct net_device *dev,
				   const u8 *buf, size_t len,
				   const u8 *dest, const __be16 proto,
				   const bool noencrypt);
};
};


/*
/*
@@ -5721,6 +5739,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
			     const u8 *buf, size_t len, bool ack, gfp_t gfp);
			     const u8 *buf, size_t len, bool ack, gfp_t gfp);




/**
 * cfg80211_rx_control_port - notification about a received control port frame
 * @dev: The device the frame matched to
 * @buf: control port frame
 * @len: length of the frame data
 * @addr: The peer from which the frame was received
 * @proto: frame protocol, typically PAE or Pre-authentication
 * @unencrypted: Whether the frame was received unencrypted
 *
 * This function is used to inform userspace about a received control port
 * frame.  It should only be used if userspace indicated it wants to receive
 * control port frames over nl80211.
 *
 * The frame is the data portion of the 802.3 or 802.11 data frame with all
 * network layer headers removed (e.g. the raw EAPoL frame).
 *
 * Return: %true if the frame was passed to userspace
 */
bool cfg80211_rx_control_port(struct net_device *dev,
			      const u8 *buf, size_t len,
			      const u8 *addr, u16 proto, bool unencrypted);

/**
/**
 * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
 * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
 * @dev: network device
 * @dev: network device
+29 −1
Original line number Original line Diff line number Diff line
@@ -542,7 +542,8 @@
 *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
 *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
 *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
 *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
 *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
 *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
 *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
 *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
 *	%NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
 *	%NL80211_ATTR_WIPHY_FREQ_HINT.
 *	%NL80211_ATTR_WIPHY_FREQ_HINT.
 *	If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
 *	If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
 *	restrictions on BSS selection, i.e., they effectively prevent roaming
 *	restrictions on BSS selection, i.e., they effectively prevent roaming
@@ -990,6 +991,17 @@
 *	&NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
 *	&NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
 *	&NL80211_CMD_DISCONNECT should be indicated instead.
 *	&NL80211_CMD_DISCONNECT should be indicated instead.
 *
 *
 * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
 *	and RX notification.  This command is used both as a request to transmit
 *	a control port frame and as a notification that a control port frame
 *	has been received. %NL80211_ATTR_FRAME is used to specify the
 *	frame contents.  The frame is the raw EAPoL data, without ethernet or
 *	802.11 headers.
 *	When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
 *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
 *	indicating the protocol type of the received frame; whether the frame
 *	was received unencrypted and the MAC address of the peer respectively.
 *
 * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
 * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
 *
 *
 * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
 * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
@@ -1228,6 +1240,8 @@ enum nl80211_commands {


	NL80211_CMD_STA_OPMODE_CHANGED,
	NL80211_CMD_STA_OPMODE_CHANGED,


	NL80211_CMD_CONTROL_PORT_FRAME,

	/* add new commands above here */
	/* add new commands above here */


	/* used to define NL80211_CMD_MAX below */
	/* used to define NL80211_CMD_MAX below */
@@ -1475,6 +1489,15 @@ enum nl80211_commands {
 * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
 * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
 *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
 *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
 *	ethertype frames used for key negotiation must not be encrypted.
 *	ethertype frames used for key negotiation must not be encrypted.
 * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control
 *	port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
 *	will be sent directly to the network interface or sent via the NL80211
 *	socket.  If this attribute is missing, then legacy behavior of sending
 *	control port frames directly to the network interface is used.  If the
 *	flag is included, then control port frames are sent over NL80211 instead
 *	using %CMD_CONTROL_PORT_FRAME.  If control port routing over NL80211 is
 *	to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
 *	flag.
 *
 *
 * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
 * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
 *	We recommend using nested, driver-specific attributes within this.
 *	We recommend using nested, driver-specific attributes within this.
@@ -2634,6 +2657,8 @@ enum nl80211_attrs {
	NL80211_ATTR_NSS,
	NL80211_ATTR_NSS,
	NL80211_ATTR_ACK_SIGNAL,
	NL80211_ATTR_ACK_SIGNAL,


	NL80211_ATTR_CONTROL_PORT_OVER_NL80211,

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


	__NL80211_ATTR_AFTER_LAST,
	__NL80211_ATTR_AFTER_LAST,
@@ -5011,6 +5036,8 @@ enum nl80211_feature_flags {
 *	channel change triggered by radar detection event.
 *	channel change triggered by radar detection event.
 *	No need to start CAC from user-space, no need to react to
 *	No need to start CAC from user-space, no need to react to
 *	"radar detected" event.
 *	"radar detected" event.
 * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
 *	receiving control port frames over nl80211 instead of the netdevice.
 *
 *
 * @NUM_NL80211_EXT_FEATURES: number of extended features.
 * @NUM_NL80211_EXT_FEATURES: number of extended features.
 * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
 * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5042,6 +5069,7 @@ enum nl80211_ext_feature_index {
	NL80211_EXT_FEATURE_LOW_POWER_SCAN,
	NL80211_EXT_FEATURE_LOW_POWER_SCAN,
	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
	NL80211_EXT_FEATURE_DFS_OFFLOAD,
	NL80211_EXT_FEATURE_DFS_OFFLOAD,
	NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,


	/* add new features before the definition below */
	/* add new features before the definition below */
	NUM_NL80211_EXT_FEATURES,
	NUM_NL80211_EXT_FEATURES,
+7 −0
Original line number Original line Diff line number Diff line
@@ -926,6 +926,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
	 */
	 */
	sdata->control_port_protocol = params->crypto.control_port_ethertype;
	sdata->control_port_protocol = params->crypto.control_port_ethertype;
	sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
	sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
	sdata->control_port_over_nl80211 =
				params->crypto.control_port_over_nl80211;
	sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
	sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
							&params->crypto,
							&params->crypto,
							sdata->vif.type);
							sdata->vif.type);
@@ -935,6 +937,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
			params->crypto.control_port_ethertype;
			params->crypto.control_port_ethertype;
		vlan->control_port_no_encrypt =
		vlan->control_port_no_encrypt =
			params->crypto.control_port_no_encrypt;
			params->crypto.control_port_no_encrypt;
		vlan->control_port_over_nl80211 =
			params->crypto.control_port_over_nl80211;
		vlan->encrypt_headroom =
		vlan->encrypt_headroom =
			ieee80211_cs_headroom(sdata->local,
			ieee80211_cs_headroom(sdata->local,
					      &params->crypto,
					      &params->crypto,
@@ -2020,6 +2024,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
	if (err)
	if (err)
		return err;
		return err;


	sdata->control_port_over_nl80211 = setup->control_port_over_nl80211;

	/* can mesh use other SMPS modes? */
	/* can mesh use other SMPS modes? */
	sdata->smps_mode = IEEE80211_SMPS_OFF;
	sdata->smps_mode = IEEE80211_SMPS_OFF;
	sdata->needed_rx_chains = sdata->local->rx_chains;
	sdata->needed_rx_chains = sdata->local->rx_chains;
@@ -3791,4 +3797,5 @@ const struct cfg80211_ops mac80211_config_ops = {
	.add_nan_func = ieee80211_add_nan_func,
	.add_nan_func = ieee80211_add_nan_func,
	.del_nan_func = ieee80211_del_nan_func,
	.del_nan_func = ieee80211_del_nan_func,
	.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
	.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
	.tx_control_port = ieee80211_tx_control_port,
};
};
+1 −0
Original line number Original line Diff line number Diff line
@@ -1844,6 +1844,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,


	sdata->smps_mode = IEEE80211_SMPS_OFF;
	sdata->smps_mode = IEEE80211_SMPS_OFF;
	sdata->needed_rx_chains = local->rx_chains;
	sdata->needed_rx_chains = local->rx_chains;
	sdata->control_port_over_nl80211 = params->control_port_over_nl80211;


	ieee80211_queue_work(&local->hw, &sdata->work);
	ieee80211_queue_work(&local->hw, &sdata->work);


+4 −0
Original line number Original line Diff line number Diff line
@@ -900,6 +900,7 @@ struct ieee80211_sub_if_data {
	u16 sequence_number;
	u16 sequence_number;
	__be16 control_port_protocol;
	__be16 control_port_protocol;
	bool control_port_no_encrypt;
	bool control_port_no_encrypt;
	bool control_port_over_nl80211;
	int encrypt_headroom;
	int encrypt_headroom;


	atomic_t num_tx_queued;
	atomic_t num_tx_queued;
@@ -1735,6 +1736,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta);
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_clear_fast_xmit(struct sta_info *sta);
void ieee80211_clear_fast_xmit(struct sta_info *sta);
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
			      const u8 *buf, size_t len,
			      const u8 *dest, __be16 proto, bool unencrypted);


/* HT */
/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
Loading