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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

Signed-off-by: Markus Theil <markus.theil@xxxxxxxxxxxxx>
---
 src/drivers/driver.h               |   6 +-
 src/drivers/driver_nl80211.c       | 107 ++++++++++++++++++++---------
 src/drivers/driver_nl80211.h       |   3 +
 src/drivers/driver_nl80211_capa.c  |   2 +-
 src/drivers/driver_nl80211_event.c |  15 ++++
 wpa_supplicant/driver_i.h          |   2 +-
 wpa_supplicant/ibss_rsn.c          |   2 +-
 wpa_supplicant/wpa_supplicant.c    |   6 ++
 wpa_supplicant/wpas_glue.c         |   2 +-
 9 files changed, 106 insertions(+), 39 deletions(-)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 9ba313ed0..d0e5a26a5 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 fa8a622d6..a0d5b0da3 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -456,6 +456,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_handle *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;
@@ -2034,25 +2048,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);
+			}
 		}
 	}
 
@@ -3004,7 +3020,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;
@@ -3012,8 +3029,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);
@@ -3026,6 +3043,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)
@@ -4362,7 +4381,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));
@@ -4985,7 +5012,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);
@@ -5181,11 +5209,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)",
@@ -5222,12 +5258,13 @@ static int wpa_driver_nl80211_hapd_send_eapol(
 	memcpy(pos, data, data_len);
 
 	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
-					    0, 0, 0, 0, NULL, 0);
+				    0, 0, 0, 0, NULL, 0);
 	if (res < 0) {
-		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
-			   "failed: %d (%s)",
-			   (unsigned long) len, errno, strerror(errno));
+	wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
+		   "failed: %d (%s)",
+		   (unsigned long) len, errno, strerror(errno));
 	}
+
 	os_free(hdr);
 
 	return res;
@@ -5806,6 +5843,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;
 }
 
@@ -5932,7 +5976,6 @@ static int wpa_driver_nl80211_connect(
 	return ret;
 }
 
-
 static int wpa_driver_nl80211_associate(
 	void *priv, struct wpa_driver_associate_params *params)
 {
@@ -5999,7 +6042,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,
@@ -9839,7 +9882,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 716504c10..53f8de595 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -231,6 +231,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 2aecc7492..8bcbe8125 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/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 1184b04b5..ec8eebb19 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -153,7 +153,7 @@ static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s,
                                           u16 proto, const u8 *buf, size_t len)
 {
 	return wpa_s->driver->tx_control_port(wpa_s->drv_priv,
-					      dest, proto, buf, len);
+					      dest, proto, buf, len, 0);
 }
 
 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 811e3f119..255d27c4e 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -86,7 +86,7 @@ static int supp_tx_control_port(void *ctx, const u8 *dest, u16 proto,
 		   "len=%lu)",
 		   __func__, MAC2STR(dest), proto, (unsigned long) len);
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TX_CONTROL_PORT)
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
 		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len);
 	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 ce4ce0bfb..b45638b45 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4658,6 +4658,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..49f187f78 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -145,7 +145,7 @@ static int wpa_supplicant_tx_control_port(void *ctx, const u8 *dest,
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	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);
-- 
2.24.1


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux