[PATCH 11/11] batctl: icmp_helper: attach socket filter before packets can arrive

Sven Eckelmann <[email protected]> Tue, 07 Jul 2026 20:46:53 +0200
Newsgroups org.open-mesh.lists.batman
Message-ID <[email protected]>
The raw packet socket is created with ETH_P_ALL as protocol, which
registers the ethernet packet hook immediately. Frames from every interface
start queuing the moment the socket exists. The BPF filter that restricts
the socket to batman-adv ICMP packets with our uid is only attached after
bind(). Frames received in the window between socket() and SO_ATTACH_FILTER
are therefore queued unfiltered.

Delay the start of the capture by:

* create the socket with protocol 0 (no capture)
* attach the filter while the queue is guaranteed empty
* then bind() with sll_protocol = htons(ETH_P_ALL)

Only after the bind, packets will be captured.

Fixes: 4bd751eed4dc ("batctl: Implement non-routing batadv_icmp in userspace")
Signed-off-by: Sven Eckelmann <[email protected]>
---
 icmp_helper.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/icmp_helper.c b/icmp_helper.c
index 52ac22d..570f0b3 100644
--- a/icmp_helper.c
+++ b/icmp_helper.c
@@ -176,7 +176,12 @@ static int icmp_interface_add(const char *ifname, const uint8_t mac[ETH_ALEN])
 	strncpy(iface->name, ifname, IFNAMSIZ);
 	iface->name[sizeof(iface->name) - 1] = '\0';
 
-	iface->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	/* create the socket with protocol 0 so the kernel does not start
+	 * capturing yet - otherwise frames would queue unfiltered between
+	 * socket() and SO_ATTACH_FILTER. Delivery only starts at bind() below,
+	 * by which time the filter is already installed.
+	 */
+	iface->sock = socket(PF_PACKET, SOCK_RAW, 0);
 	if (iface->sock < 0) {
 		perror("Error - can't create raw socket");
 		ret = -errno;
@@ -194,6 +199,12 @@ static int icmp_interface_add(const char *ifname, const uint8_t mac[ETH_ALEN])
 		goto close_sock;
 	}
 
+	ret = icmp_interface_filter(iface->sock, uid);
+	if (ret < 0) {
+		fprintf(stderr, "Error - can't add filter to raw socket: %s\n", strerror(-ret));
+		goto close_sock;
+	}
+
 	memset(&sll, 0, sizeof(sll));
 	sll.sll_family = AF_PACKET;
 	sll.sll_protocol = htons(ETH_P_ALL);
@@ -207,12 +218,6 @@ static int icmp_interface_add(const char *ifname, const uint8_t mac[ETH_ALEN])
 		goto close_sock;
 	}
 
-	ret = icmp_interface_filter(iface->sock, uid);
-	if (ret < 0) {
-		fprintf(stderr, "Error - can't add filter to raw socket: %s\n", strerror(-ret));
-		goto close_sock;
-	}
-
 	list_add(&iface->list, &interface_list);
 
 	return 0;

-- 
2.47.3