diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c index c4e73f694..41de2f85d 100644 --- a/src/l2_packet/l2_packet_linux.c +++ b/src/l2_packet/l2_packet_linux.c @@ -14,6 +14,8 @@ #include "common.h" #include "eloop.h" +#include "crypto/sha1.h" +#include "crypto/crypto.h" #include "l2_packet.h" @@ -30,6 +32,9 @@ struct l2_packet_data { /* 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; }; /* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and @@ -122,6 +127,7 @@ 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, @@ -132,14 +138,41 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) return; } + wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d", + __func__, MAC2STR(ll.sll_addr), (int) res); + if (l2->fd_br_rx >= 0) { - wpa_printf(MSG_DEBUG, "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket", - l2->ifname); - eloop_unregister_read_sock(l2->fd_br_rx); - close(l2->fd_br_rx); - l2->fd_br_rx = -1; + u8 hash[SHA1_MAC_LEN]; + const u8 *addr[1]; + size_t len[1]; + + /* + * Close the workaround socket if the kernel version seems to be + * able to deliver packets through the packet socket before + * authorization has been completed (in dormant state). + */ + if (l2->num_rx_br <= 1) { + wpa_printf(MSG_DEBUG, + "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket", + l2->ifname); + eloop_unregister_read_sock(l2->fd_br_rx); + close(l2->fd_br_rx); + l2->fd_br_rx = -1; + } + + addr[0] = buf; + len[0] = res; + sha1_vector(1, addr, len, hash); + if (l2->last_from_br && + os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) { + wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", + __func__); + return; + } + os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN); } + l2->last_from_br = 0; l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); } @@ -151,7 +184,11 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx) int res; struct sockaddr_ll ll; socklen_t fromlen; + u8 hash[SHA1_MAC_LEN]; + const u8 *addr[1]; + size_t len[1]; + l2->num_rx_br++; os_memset(&ll, 0, sizeof(ll)); fromlen = sizeof(ll); res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, @@ -162,6 +199,19 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx) return; } + wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d", + __func__, MAC2STR(ll.sll_addr), (int) res); + + addr[0] = buf; + len[0] = res; + sha1_vector(1, addr, len, hash); + if (!l2->last_from_br && + os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) { + wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", __func__); + return; + } + l2->last_from_br = 1; + os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN); l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); }