Browse Source

l2_packet: Add build option to disable Linux packet socket workaround

Linux packet socket workaround(*) has an impact in performance when the
workaround socket needs to be kept open to receive EAPOL frames. While
this is normally avoided with a kernel that has the issue addressed by
closing the workaround packet socket when detecting a frame through the
main socket, it is possible for that mechanism to not be sufficient,
e.g., when an open network connection (no EAPOL frames) is used.

Add a build option (CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y) to disable the
workaround. This build option is disabled by default and can be enabled
explicitly on distributions which have an older kernel or a fix for the
kernel regression.

Also remove the unused variable num_rx.

(*) Linux kernel commit 576eb62598f10c8c7fd75703fe89010cdcfff596
('bridge: respect RFC2863 operational state') from 2012 introduced a
regression for using wpa_supplicant with EAPOL frames and a station
interface in a bridge.

Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
Mohammed Shafi Shajakhan 9 years ago
parent
commit
67deaa582d
3 changed files with 25 additions and 2 deletions
  1. 15 2
      src/l2_packet/l2_packet_linux.c
  2. 4 0
      wpa_supplicant/Makefile
  3. 6 0
      wpa_supplicant/defconfig

+ 15 - 2
src/l2_packet/l2_packet_linux.c

@@ -30,11 +30,13 @@ struct l2_packet_data {
 	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
 		     * buffers */
 
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 	/* For working around Linux packet socket behavior and regression. */
 	int fd_br_rx;
 	int last_from_br;
 	u8 last_hash[SHA1_MAC_LEN];
-	unsigned int num_rx, num_rx_br;
+	unsigned int num_rx_br;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 };
 
 /* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and
@@ -127,7 +129,6 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
 	struct sockaddr_ll ll;
 	socklen_t fromlen;
 
-	l2->num_rx++;
 	os_memset(&ll, 0, sizeof(ll));
 	fromlen = sizeof(ll);
 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
@@ -141,6 +142,7 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
 	wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d",
 		   __func__, MAC2STR(ll.sll_addr), (int) res);
 
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 	if (l2->fd_br_rx >= 0) {
 		u8 hash[SHA1_MAC_LEN];
 		const u8 *addr[1];
@@ -173,10 +175,12 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
 	}
 
 	l2->last_from_br = 0;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
 }
 
 
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
 {
 	struct l2_packet_data *l2 = eloop_ctx;
@@ -214,6 +218,7 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
 	os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN);
 	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
 }
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
 
 struct l2_packet_data * l2_packet_init(
@@ -233,7 +238,9 @@ struct l2_packet_data * l2_packet_init(
 	l2->rx_callback = rx_callback;
 	l2->rx_callback_ctx = rx_callback_ctx;
 	l2->l2_hdr = l2_hdr;
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 	l2->fd_br_rx = -1;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
 	l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
 			htons(protocol));
@@ -289,6 +296,7 @@ struct l2_packet_data * l2_packet_init_bridge(
 	void *rx_callback_ctx, int l2_hdr)
 {
 	struct l2_packet_data *l2;
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 	struct sock_filter ethertype_sock_filter_insns[] = {
 		/* Load ethertype */
 		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 2 * ETH_ALEN),
@@ -304,12 +312,14 @@ struct l2_packet_data * l2_packet_init_bridge(
 		.filter = ethertype_sock_filter_insns,
 	};
 	struct sockaddr_ll ll;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
 	l2 = l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
 			    rx_callback_ctx, l2_hdr);
 	if (!l2)
 		return NULL;
 
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 	/*
 	 * The Linux packet socket behavior has changed over the years and there
 	 * is an inconvenient regression in it that breaks RX for a specific
@@ -357,6 +367,7 @@ struct l2_packet_data * l2_packet_init_bridge(
 	}
 
 	eloop_register_read_sock(l2->fd_br_rx, l2_packet_receive_br, l2, NULL);
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
 	return l2;
 }
@@ -372,10 +383,12 @@ void l2_packet_deinit(struct l2_packet_data *l2)
 		close(l2->fd);
 	}
 
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
 	if (l2->fd_br_rx >= 0) {
 		eloop_unregister_read_sock(l2->fd_br_rx);
 		close(l2->fd_br_rx);
 	}
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
 	os_free(l2);
 }

+ 4 - 0
wpa_supplicant/Makefile

@@ -1453,6 +1453,10 @@ ifdef CONFIG_IPV6
 CFLAGS += -DCONFIG_IPV6
 endif
 
+ifdef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+CFLAGS += -DCONFIG_NO_LINUX_PACKET_SOCKET_WAR
+endif
+
 ifdef NEED_BASE64
 OBJS += ../src/utils/base64.o
 endif

+ 6 - 0
wpa_supplicant/defconfig

@@ -279,6 +279,12 @@ CONFIG_BACKEND=file
 # none = Empty template
 #CONFIG_L2_PACKET=linux
 
+# Disable Linux packet socket workaround applicable for station interface
+# in a bridge for EAPOL frames. This should be uncommented only if the kernel
+# is known to not have the regression issue in packet socket behavior with
+# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
+#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
+
 # PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
 CONFIG_PEERKEY=y