Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Aug 2007 16:00:26 +1200
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        FreeBSD Current <current@freebsd.org>
Subject:   multicast packets from bpf
Message-ID:  <20070828040026.GB42201@heff.fud.org.nz>

next in thread | raw e-mail | index | archive | help

--QTprm0S8XgL7H0Dt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,


At the moment packets injected via bpf do not get the M_BCAST or M_MCAST
flags set. One consequence of this is that it messes up broadcasting
from if_bridge which assumes these flags are correct, using dhcpd on a
bridge interface is one way to trigger it.

Attached is a patch (bpf_mcast.diff) that fixes this up. There is some
concern about having bpf inspecting the protocol headers but i seems
unavoidable in order to determine if its multicast. tap(4) was also
thought to have this problem but it turned out not to since it passes
the frames to ether_input.

The other way is for the bridge to recheck for multicast destinations
for locally generated packets (bridge_bpfmcast.diff), but this is less
desirable.


Andrew

--QTprm0S8XgL7H0Dt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="bpf_mcast.diff"

Index: bpf.c
===================================================================
RCS file: /home/ncvs/src/sys/net/bpf.c,v
retrieving revision 1.180
diff -u -p -r1.180 bpf.c
--- bpf.c	6 Aug 2007 14:26:00 -0000	1.180
+++ bpf.c	28 Aug 2007 01:34:27 -0000
@@ -599,6 +599,7 @@ bpfwrite(struct cdev *dev, struct uio *u
 	struct ifnet *ifp;
 	struct mbuf *m, *mc;
 	struct sockaddr dst;
+	struct ether_header *eh;
 	int error, hlen;
 
 	if (d->bd_bif == NULL)
@@ -620,6 +621,20 @@ bpfwrite(struct cdev *dev, struct uio *u
 	if (error)
 		return (error);
 
+	/* Check for multicast destination */
+	switch (d->bd_bif->bif_dlt) {
+	case DLT_EN10MB:
+		eh = mtod(m, struct ether_header *);
+		if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+			if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost,
+			    ETHER_ADDR_LEN) == 0)
+				m->m_flags |= M_BCAST;
+			else
+				m->m_flags |= M_MCAST;
+		}
+		break;
+	}
+
 	if (d->bd_hdrcmplt)
 		dst.sa_family = pseudo_AF_HDRCMPLT;
 

--QTprm0S8XgL7H0Dt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="bridge_bpfmcast.diff"

Index: if_bridge.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_bridge.c,v
retrieving revision 1.102
diff -u -p -r1.102 if_bridge.c
--- if_bridge.c	1 Aug 2007 00:33:52 -0000	1.102
+++ if_bridge.c	14 Aug 2007 02:11:16 -0000
@@ -1852,9 +1852,16 @@ bridge_start(struct ifnet *ifp)
 		dst_if = NULL;
 
 		BRIDGE_LOCK(sc);
-		if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
+		if (ETHER_IS_MULTICAST(eh->ether_dhost))
+			/*
+			 * XXX bpf injected packets do not have M_MCAST or
+			 * M_BCAST set, bridge_broadcast() makes assumptions
+			 * based on this.
+			 */
+			if ((m->m_flags & (M_BCAST|M_MCAST)) == 0)
+				m->m_flags |= M_MCAST;
+		else
 			dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1);
-		}
 
 		if (dst_if == NULL)
 			bridge_broadcast(sc, ifp, m, 0);

--QTprm0S8XgL7H0Dt--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070828040026.GB42201>