diff mbox series

[v2,2/2] Use control port over nl80211 also for rx path

Message ID 20200103151742.43551-3-markus.theil@tu-ilmenau.de
State Accepted
Headers show
Series Fixes and Rx path for Brendan's EAPoL over NL80211 | expand

Commit Message

Markus Theil Jan. 3, 2020, 3:17 p.m. UTC
This patch is based on the previous patch from Brendan Jackman
and adds rx support over nl80211. In order to receive frames
over the event nl socket, assoc/connect/beacon setting has to be
performed over the same socket, which should later receive the events.

With this patch ctrl port tx supports the no_encrypt flag.

wpa supplicant now uses the l2 socket only to obtain the device mac
address, future patches may split this out.

Sending frames over the nl80211 event socket should may be made harder
again, by xor-ing the socket handle outside of send_and_recv_msgs_event.

In order to correctly encrypt rekeying frames, wpa_supplicant now checks
if a PTK is currently installed and sets the corresponding encrypt
option for tx_control_port.

Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
---
 src/drivers/driver.h               |  6 +-
 src/drivers/driver_nl80211.c       | 99 +++++++++++++++++++++---------
 src/drivers/driver_nl80211.h       |  3 +
 src/drivers/driver_nl80211_capa.c  |  2 +-
 src/drivers/driver_nl80211_event.c | 15 +++++
 src/rsn_supp/wpa.c                 |  8 +++
 src/rsn_supp/wpa.h                 |  1 +
 wpa_supplicant/driver_i.h          |  5 +-
 wpa_supplicant/ibss_rsn.c          |  5 +-
 wpa_supplicant/wpa_supplicant.c    |  6 ++
 wpa_supplicant/wpas_glue.c         |  7 ++-
 11 files changed, 118 insertions(+), 39 deletions(-)

Comments

Jouni Malinen Jan. 5, 2020, 8:07 p.m. UTC | #1
On Fri, Jan 03, 2020 at 04:17:42PM +0100, Markus Theil wrote:
> This patch is based on the previous patch from Brendan Jackman
> and adds rx support over nl80211. In order to receive frames
> over the event nl socket, assoc/connect/beacon setting has to be
> performed over the same socket, which should later receive the events.

Thanks, I cleaned this up and split the changes into easier to
understand smaller commits. I applied the parts that I understood and
that did not break hwsim test cases. However, this change to use event
nl socket broke large number of test cases, so I could not apply it
(i.e., this is enabled only for TX for now). I'm not sure what exactly
goes wrong with the RX changes, but it looks like cfg80211 state is
somewhat strange when trying to disconnect and try to connect again with
a new network (NL80211_CMD_AUTHENTICATE fails).

I didn't fully understand what the changes were doing with nl_event and
why the changes looked so inconsistent on using
send_and_recv_msgs_event() vs. send_and_recv_msmgs(). I tried to fix
those, but that did not remove the issues (but probably fixed some other
cases that I did not hit yet due to those other problems preventing full
testing). Anyway, the change itself did allow a simple test sequence
like the ap_wpa2_psk test case to complete full connection on both the
AP and station side using the nl80211 control port, so most of the
functionality is working, but something is just messing up what happens
for following operations.

I'm attaching the remaining patches that I could not apply. These
include all the cleanup and fixes I did when trying to figure out what
is happening.

> With this patch ctrl port tx supports the no_encrypt flag.

This was fine, but I moved from encrypt to no_encrypt in the driver ops
API since this is really a special case requesting frames not to be
encrypted when keys are set rather than something that is needed for the
normal case where the EAPOL frames should be encrypted if PTK is set.

> wpa supplicant now uses the l2 socket only to obtain the device mac
> address, future patches may split this out.

I could not apply this one because it depends on the nl80211 control
port RX path working.

> Sending frames over the nl80211 event socket should may be made harder
> again, by xor-ing the socket handle outside of send_and_recv_msgs_event.

I'm not sure how to interpret this.. Are you noting that something
additional should be done in the future or are you commenting that that
is already done here?

> In order to correctly encrypt rekeying frames, wpa_supplicant now checks
> if a PTK is currently installed and sets the corresponding encrypt
> option for tx_control_port.

I'm not completely confident on this being accurate for all cases, but I
applied these as well. Especially PTK rekeying part is unclear since the
EAPOL frames need to be encrypted, but with the old key, not the new
one. Anyway, all test cases seemed to be passing fine with the changes
on the TX path.
Markus Theil Jan. 5, 2020, 9:06 p.m. UTC | #2
On 1/5/20 9:07 PM, Jouni Malinen wrote:
> On Fri, Jan 03, 2020 at 04:17:42PM +0100, Markus Theil wrote:
>> This patch is based on the previous patch from Brendan Jackman
>> and adds rx support over nl80211. In order to receive frames
>> over the event nl socket, assoc/connect/beacon setting has to be
>> performed over the same socket, which should later receive the events.
> Thanks, I cleaned this up and split the changes into easier to
> understand smaller commits. I applied the parts that I understood and
> that did not break hwsim test cases. However, this change to use event
> nl socket broke large number of test cases, so I could not apply it
> (i.e., this is enabled only for TX for now). I'm not sure what exactly
> goes wrong with the RX changes, but it looks like cfg80211 state is
> somewhat strange when trying to disconnect and try to connect again with
> a new network (NL80211_CMD_AUTHENTICATE fails).
>
> I didn't fully understand what the changes were doing with nl_event and
> why the changes looked so inconsistent on using
> send_and_recv_msgs_event() vs. send_and_recv_msmgs(). I tried to fix
> those, but that did not remove the issues (but probably fixed some other
> cases that I did not hit yet due to those other problems preventing full
> testing). Anyway, the change itself did allow a simple test sequence
> like the ap_wpa2_psk test case to complete full connection on both the
> AP and station side using the nl80211 control port, so most of the
> functionality is working, but something is just messing up what happens
> for following operations.
>
> I'm attaching the remaining patches that I could not apply. These
> include all the cleanup and fixes I did when trying to figure out what
> is happening.
>
>> With this patch ctrl port tx supports the no_encrypt flag.
> This was fine, but I moved from encrypt to no_encrypt in the driver ops
> API since this is really a special case requesting frames not to be
> encrypted when keys are set rather than something that is needed for the
> normal case where the EAPOL frames should be encrypted if PTK is set.
>
>> wpa supplicant now uses the l2 socket only to obtain the device mac
>> address, future patches may split this out.
> I could not apply this one because it depends on the nl80211 control
> port RX path working.
>
>> Sending frames over the nl80211 event socket should may be made harder
>> again, by xor-ing the socket handle outside of send_and_recv_msgs_event.
> I'm not sure how to interpret this.. Are you noting that something
> additional should be done in the future or are you commenting that that
> is already done here?
>
>> In order to correctly encrypt rekeying frames, wpa_supplicant now checks
>> if a PTK is currently installed and sets the corresponding encrypt
>> option for tx_control_port.
> I'm not completely confident on this being accurate for all cases, but I
> applied these as well. Especially PTK rekeying part is unclear since the
> EAPOL frames need to be encrypted, but with the old key, not the new
> one. Anyway, all test cases seemed to be passing fine with the changes
> on the TX path.
>
Thanks a lot for reviewing and splitting the patch. I have time to look 
into the Rx path issues by the end of next week and will send another 
patch when ready.
> _______________________________________________
> Hostap mailing list
> Hostap@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap
Alexander Wetzel Jan. 5, 2020, 9:20 p.m. UTC | #3
Am 05.01.20 um 22:06 schrieb Markus Theil:
> I didn't fully understand what the changes were doing with nl_event and
> why the changes looked so inconsistent on using
> send_and_recv_msgs_event() vs. send_and_recv_msmgs(). I tried to fix
> those, but that did not remove the issues (but probably fixed some other
> cases that I did not hit yet due to those other problems preventing full
> testing). Anyway, the change itself did allow a simple test sequence
> like the ap_wpa2_psk test case to complete full connection on both the
> AP and station side using the nl80211 control port, so most of the
> functionality is working, but something is just messing up what happens
> for following operations.

I also tried the series with the tests and it broke the very first..
Not finished looking into that when I had to stop for today at least but 
it looks like the patch series is breaking deauthentication for 
wpa_supplicant or at least for the test ap_mixed_security.

It seems to generate invalid deauthentication requests and I assume it's 
also not deleting the STA from the kernel. Nl80211 then balks when asked 
to associate again when already having an association... at least that 
is assumption I was planning to verify tomorrow.

(I checked the pcapng file from the test, try the filter
"(wlan.fc.type_subtype == 0x000c) || (frame.cap_len == 48))" and compare 
it to a working testrun.)

Alexander
diff mbox series

Patch

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index ce7d62abf..6ceb7bf05 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1704,8 +1704,8 @@  struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_FTM_RESPONDER		0x0100000000000000ULL
 /** Driver support 4-way handshake offload for WPA-Personal */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK	0x0200000000000000ULL
-/** Driver has working tx_control_port */
-#define WPA_DRIVER_FLAGS_TX_CONTROL_PORT	0x0400000000000000ULL
+/** Driver has working control_port */
+#define WPA_DRIVER_FLAGS_CONTROL_PORT		0x0400000000000000ULL
 	u64 flags;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2384,7 +2384,7 @@  struct wpa_driver_ops {
 	 * users should fall back to sending the frame via a normal socket.
 	 */
 	int (*tx_control_port)(void *priv, const u8 *dest,
-			       u16 proto, const u8 *buf, size_t len);
+			       u16 proto, const u8 *buf, size_t len, Boolean encrypt);
 	/**
 	 * init - Initialize driver interface
 	 * @ctx: context to be used when calling wpa_supplicant functions,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d20abce87..7f0ab015d 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -438,6 +438,20 @@  int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
 }
 
 
+int send_and_recv_msgs_event(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
+		       int (*valid_handler)(struct nl_msg *, void *),
+		       void *valid_data)
+{
+	struct nl_sock *handle;
+
+	handle = (void *) (((intptr_t) drv->global->nl_event) ^
+		   ELOOP_SOCKET_INVALID);
+
+	return send_and_recv(drv->global, handle, msg,
+			     valid_handler, valid_data);
+}
+
+
 struct family_data {
 	const char *group;
 	int id;
@@ -2042,25 +2056,27 @@  static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
 	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
 		goto failed;
 
-	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
-	if (drv->eapol_tx_sock < 0)
-		goto failed;
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT)) {
+		drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+		if (drv->eapol_tx_sock < 0)
+			goto failed;
 
-	if (drv->data_tx_status) {
-		int enabled = 1;
+		if (drv->data_tx_status) {
+			int enabled = 1;
 
-		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
-			       &enabled, sizeof(enabled)) < 0) {
-			wpa_printf(MSG_DEBUG,
-				"nl80211: wifi status sockopt failed\n");
-			drv->data_tx_status = 0;
-			if (!drv->use_monitor)
-				drv->capa.flags &=
-					~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-		} else {
-			eloop_register_read_sock(drv->eapol_tx_sock,
-				wpa_driver_nl80211_handle_eapol_tx_status,
-				drv, NULL);
+			if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+				       &enabled, sizeof(enabled)) < 0) {
+				wpa_printf(MSG_DEBUG,
+					"nl80211: wifi status sockopt failed\n");
+				drv->data_tx_status = 0;
+				if (!drv->use_monitor)
+					drv->capa.flags &=
+						~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+			} else {
+				eloop_register_read_sock(drv->eapol_tx_sock,
+					wpa_driver_nl80211_handle_eapol_tx_status,
+					drv, NULL);
+			}
 		}
 	}
 
@@ -3012,7 +3028,8 @@  static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
 
 
 static int driver_nl80211_tx_control_port(void *priv, const u8 *dest,
-					  u16 proto, const u8 *buf, size_t len)
+					  u16 proto, const u8 *buf, size_t len,
+					  Boolean encrypt)
 {
 	struct i802_bss *bss = priv;
 	struct nl_msg *msg = NULL;
@@ -3020,8 +3037,8 @@  static int driver_nl80211_tx_control_port(void *priv, const u8 *dest,
 	int ret = 0;
 
 	wpa_printf(MSG_DEBUG,
-		   "nl80211: tx_control_port "MACSTR" proto=0x%04x len=%zu",
-		   MAC2STR(dest), proto, len);
+		   "nl80211: tx_control_port "MACSTR" proto=0x%04x len=%zu encrypt=%i",
+		   MAC2STR(dest), proto, len, encrypt);
 
 	msg = nl80211_ifindex_msg(bss->drv, ifindex, 0,
 				  NL80211_CMD_CONTROL_PORT_FRAME);
@@ -3034,6 +3051,8 @@  static int driver_nl80211_tx_control_port(void *priv, const u8 *dest,
 		goto fail;
 	if (nla_put(msg, NL80211_ATTR_FRAME, len, buf))
 		goto fail;
+	if (!encrypt && nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+		goto fail;
 
 	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
 	if (ret)
@@ -4340,7 +4359,15 @@  static int wpa_driver_nl80211_set_ap(void *priv,
 	}
 #endif /* CONFIG_IEEE80211AX */
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+		if(nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
+		   nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
+		   nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+			       ETH_P_PAE))
+			goto fail;
+	}
+
+	ret = send_and_recv_msgs_event(drv, msg, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
 			   ret, strerror(-ret));
@@ -4963,7 +4990,8 @@  static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 	 * Tell cfg80211 that the interface belongs to the socket that created
 	 * it, and the interface should be deleted when the socket is closed.
 	 */
-	if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+	if(!(drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) &&
+	   nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
 		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, handler, arg);
@@ -5159,11 +5187,19 @@  static int wpa_driver_nl80211_hapd_send_eapol(
 	int res;
 	int qos = flags & WPA_STA_WMM;
 
-	if (drv->device_ap_sme || !drv->use_monitor)
-		return nl80211_send_eapol_data(bss, addr, data, data_len);
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+		return driver_nl80211_tx_control_port(bss, addr,
+						      ETH_P_EAPOL,
+						      data, data_len,
+						      encrypt);
+
+	if (drv->device_ap_sme || !drv->use_monitor) {
+		return nl80211_send_eapol_data(bss, addr,
+					       data, data_len);
+	}
 
 	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
-		data_len;
+	      data_len;
 	hdr = os_zalloc(len);
 	if (hdr == NULL) {
 		wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
@@ -5205,6 +5241,7 @@  static int wpa_driver_nl80211_hapd_send_eapol(
 			   "failed: %d (%s)",
 			   (unsigned long) len, res, strerror(res));
 	}
+
 	os_free(hdr);
 
 	return res;
@@ -5783,6 +5820,13 @@  static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
 	    nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
 		return -1;
 
+	if((drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) &&
+	   (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
+	    nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+			ETH_P_PAE))) {
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -5909,7 +5953,6 @@  static int wpa_driver_nl80211_connect(
 	return ret;
 }
 
-
 static int wpa_driver_nl80211_associate(
 	void *priv, struct wpa_driver_associate_params *params)
 {
@@ -5976,7 +6019,7 @@  static int wpa_driver_nl80211_associate(
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs_event(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -9814,7 +9857,7 @@  static int nl80211_join_mesh(struct i802_bss *bss,
 	if (nl80211_put_mesh_config(msg, &params->conf) < 0)
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs_event(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index e4d81b125..f4cebda81 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -224,6 +224,9 @@  struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
 		       int (*valid_handler)(struct nl_msg *, void *),
 		       void *valid_data);
+int send_and_recv_msgs_event(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
+		       int (*valid_handler)(struct nl_msg *, void *),
+		       void *valid_data);
 int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 			 const char *ifname, enum nl80211_iftype iftype,
 			 const u8 *addr, int wds,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 8305b05bb..e1cf9f7b1 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -436,7 +436,7 @@  static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
 
 	if (ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
-		capa->flags |= WPA_DRIVER_FLAGS_TX_CONTROL_PORT;
+		capa->flags |= WPA_DRIVER_FLAGS_CONTROL_PORT;
 }
 
 
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 6c6e5c185..a6debe145 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -505,6 +505,18 @@  static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void mlme_event_rx_eapol(struct wpa_driver_nl80211_data *drv,
+				struct nlattr **tb)
+{
+	if(tb[NL80211_ATTR_FRAME]) {
+		drv_event_eapol_rx(drv->ctx,
+				   nla_data(tb[NL80211_ATTR_MAC]),
+				   nla_data(tb[NL80211_ATTR_FRAME]),
+				   nla_len(tb[NL80211_ATTR_FRAME]));
+	}
+}
+
+
 static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
 {
 	int freq1 = 0;
@@ -2663,6 +2675,9 @@  static void do_process_drv_event(struct i802_bss *bss, int cmd,
 	case NL80211_CMD_UPDATE_OWE_INFO:
 		mlme_event_dh_event(drv, bss, tb);
 		break;
+	case NL80211_CMD_CONTROL_PORT_FRAME:
+		mlme_event_rx_eapol(drv, tb);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e55351352..7daece42c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -3510,6 +3510,14 @@  int wpa_sm_has_ptk(struct wpa_sm *sm)
 }
 
 
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->ptk.installed;
+}
+
+
 void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
 {
 	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 1ef87dbb7..701050a30 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -174,6 +174,7 @@  int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
 			const void *network_ctx);
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
 
 void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 738666e40..012c104c2 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -145,10 +145,11 @@  static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid)
 
 static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s,
                                           const u8 *dest,
-                                          u16 proto, const u8 *buf, size_t len)
+                                          u16 proto, const u8 *buf, size_t len,
+                                          Boolean encrypt)
 {
 	return wpa_s->driver->tx_control_port(wpa_s->drv_priv,
-					      dest, proto, buf, len);
+					      dest, proto, buf, len, encrypt);
 }
 
 static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index cd940e40c..56b3d42e0 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -81,13 +81,14 @@  static int supp_tx_control_port(void *ctx, const u8 *dest, u16 proto,
 {
 	struct ibss_rsn_peer *peer = ctx;
 	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+	Boolean encrypt = peer->authentication_status & IBSS_RSN_REPORTED_PTK;
 
 	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
 		   "len=%lu)",
 		   __func__, MAC2STR(dest), proto, (unsigned long) len);
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TX_CONTROL_PORT)
-		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len);
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len, encrypt);
 	else
 		return supp_ether_send(wpa_s, dest, proto, buf, len);
 }
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 0a9e37c3b..e2a866d33 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4685,6 +4685,12 @@  int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
 	wpas_wps_update_mac_addr(wpa_s);
 
+	/* use l2 socket only to get mac address */
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+		l2_packet_deinit(wpa_s->l2);
+		wpa_s->l2 = NULL;
+	}
+
 #ifdef CONFIG_FST
 	if (wpa_s->fst)
 		fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index eb56c8b5b..47ee1c0e7 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -144,11 +144,12 @@  static int wpa_supplicant_tx_control_port(void *ctx, const u8 *dest,
 					  u16 proto, const u8 *buf, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+	Boolean encrypt = wpa_s->wpa && wpa_sm_has_ptk_installed(wpa_s->wpa);
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TX_CONTROL_PORT) {
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
 		if (ext_eapol_frame_io_notify_tx(wpa_s, dest, proto, buf, len))
 			return 0;
-		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len);
+		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len, encrypt);
 	} else {
 		return wpa_ether_send(wpa_s, dest, proto, buf, len);
 	}
@@ -247,7 +248,7 @@  static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
 
 	wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst));
 	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
-	res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
+	res = wpa_supplicant_tx_control_port(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
 	os_free(msg);
 	return res;
 }