]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
l2_packet: Extend bridge workaround RX processing to cover two frames
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 7 Jan 2016 11:30:59 +0000 (13:30 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 7 Jan 2016 11:30:59 +0000 (13:30 +0200)
There was a race condition in how the l2_packet sockets got read that
could result in the same socket (e.g., non-bridge) to process both the
EAP-Success and the immediately following EAPOL-Key msg 1/4 instead of
each frame going in alternative order between the bridge and non-bridge
sockets. This could be hit, e.g., if the wpa_supplicant process did not
have enough CPU to process all the incoming frames without them getting
buffered and both sockets reporting frames simultaneously.

This resulted in the duplicated EAP-Success frame getting delivered
twice for processing and likely also the EAPOL-Key msg 1/4 getting
processed twice. While the latter does not do much harm, the former did
clear the EAP authentication state and could result in issues.

Fix this by extended the l2_packet Linux packet socket workaround for
bridge to check for duplicates against the last two received frames
instead of just the last one.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/l2_packet/l2_packet_linux.c

index a283a512f2ffb662b3ec12afd3d87eec48591c39..a7a300e568e6d8dc88d195fd8aaa072d476e90e8 100644 (file)
@@ -33,8 +33,9 @@ struct l2_packet_data {
 #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];
+       u8 last_hash_prev[SHA1_MAC_LEN];
        unsigned int num_rx_br;
 #endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 };
@@ -171,6 +172,14 @@ 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);
        }
 
@@ -219,6 +228,13 @@ 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);