summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tap.c
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2007-02-03 02:57:45 +0000
committerbms <bms@FreeBSD.org>2007-02-03 02:57:45 +0000
commitcb84e5a9bd809b0fc9ae4a9601889aa89770481d (patch)
tree16921ed174ef8881a2165e678af900074228fa19 /sys/net/if_tap.c
parent3910945fa0e5f58974ad6be73b36658186af7759 (diff)
downloadFreeBSD-src-cb84e5a9bd809b0fc9ae4a9601889aa89770481d.zip
FreeBSD-src-cb84e5a9bd809b0fc9ae4a9601889aa89770481d.tar.gz
Drop unicast Ethernet frames not destined for the configured address
of a tap(4) instance, if IFF_PROMISC is not set. In tap(4), we should emulate the effect IFF_PROMISC would have on hardware, otherwise we risk introducing layer 2 loops if tap(4) is used with bridges. This means not even bpf(4) gets to see them. This patch has been tested in a variety of situations. Multicast and broadcast frames are correctly allowed through. I have observed this behaviour causing problems with multiple QEMU instances hosted on the same FreeBSD machine. The checks in in ether_demux() [if_ethersubr.c, rev 1.222, line 638] are insufficient to prevent this bug from occurring, as ifp->if_vlantrunk will always be NULL for the non-vlan case. MFC after: 3 weeks PR: 86429 Submitted by: Pieter de Boer (with changes)
Diffstat (limited to 'sys/net/if_tap.c')
-rw-r--r--sys/net/if_tap.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index 1b51647..653d618 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -813,6 +813,7 @@ tapread(struct cdev *dev, struct uio *uio, int flag)
static int
tapwrite(struct cdev *dev, struct uio *uio, int flag)
{
+ struct ether_header *eh;
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = tp->tap_ifp;
struct mbuf *m;
@@ -838,6 +839,23 @@ tapwrite(struct cdev *dev, struct uio *uio, int flag)
m->m_pkthdr.rcvif = ifp;
+ /*
+ * Only pass a unicast frame to ether_input(), if it would actually
+ * have been received by non-virtual hardware.
+ */
+ if (m->m_len < sizeof(struct ether_header)) {
+ m_freem(m);
+ return (0);
+ }
+ eh = mtod(m, struct ether_header *);
+
+ if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
+ !ETHER_IS_MULTICAST(eh->ether_dhost) &&
+ bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
+ m_freem(m);
+ return (0);
+ }
+
/* Pass packet up to parent. */
(*ifp->if_input)(ifp, m);
ifp->if_ipackets ++; /* ibytes are counted in parent */
OpenPOWER on IntegriCloud