Updated to hostap_2_6
[mech_eap.git] / libeap / src / l2_packet / l2_packet_linux.c
index 41de2f8..a7a300e 100644 (file)
@@ -30,11 +30,14 @@ 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;
+       int last_from_br, last_from_br_prev;
        u8 last_hash[SHA1_MAC_LEN];
-       unsigned int num_rx, num_rx_br;
+       u8 last_hash_prev[SHA1_MAC_LEN];
+       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 +130,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 +143,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];
@@ -169,14 +172,24 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
                                   __func__);
                        return;
                }
+               if (l2->last_from_br_prev &&
+                   os_memcmp(hash, l2->last_hash_prev, SHA1_MAC_LEN) == 0) {
+                       wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX(prev)",
+                                  __func__);
+                       return;
+               }
+               os_memcpy(l2->last_hash_prev, l2->last_hash, SHA1_MAC_LEN);
+               l2->last_from_br_prev = l2->last_from_br;
                os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN);
        }
 
        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;
@@ -202,6 +215,11 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
        wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d",
                   __func__, MAC2STR(ll.sll_addr), (int) res);
 
+       if (os_memcmp(ll.sll_addr, l2->own_addr, ETH_ALEN) == 0) {
+               wpa_printf(MSG_DEBUG, "%s: Drop RX of own frame", __func__);
+               return;
+       }
+
        addr[0] = buf;
        len[0] = res;
        sha1_vector(1, addr, len, hash);
@@ -210,10 +228,18 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
                wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", __func__);
                return;
        }
+       if (!l2->last_from_br_prev &&
+           os_memcmp(hash, l2->last_hash_prev, SHA1_MAC_LEN) == 0) {
+               wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX(prev)", __func__);
+               return;
+       }
+       os_memcpy(l2->last_hash_prev, l2->last_hash, SHA1_MAC_LEN);
+       l2->last_from_br_prev = l2->last_from_br;
        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);
 }
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
 
 struct l2_packet_data * l2_packet_init(
@@ -233,7 +259,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 +317,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 +333,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 +388,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 +404,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);
 }