From 67deaa582d0e1e3cc264dd7b2133f839c430e864 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 19 Oct 2015 12:40:42 +0530 Subject: [PATCH] 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 --- src/l2_packet/l2_packet_linux.c | 17 +++++++++++++++-- wpa_supplicant/Makefile | 4 ++++ wpa_supplicant/defconfig | 6 ++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c index 41de2f85d..f52f7a23b 100644 --- a/src/l2_packet/l2_packet_linux.c +++ b/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); } diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 0129031e4..d6bebe3c8 100644 --- a/wpa_supplicant/Makefile +++ b/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 diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 9f75993e7..e2e4bdc65 100644 --- a/wpa_supplicant/defconfig +++ b/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