Module Name:    src
Committed By:   ozaki-r
Date:           Thu Jul 23 10:52:34 UTC 2015

Modified Files:
        src/sys/net: if_bridge.c

Log Message:
Fix PR 48104

So far bridge cannot receive frames via a member interface when the frames
come from another member interface. So when we assign an IP address to
a member interface, hosts connected to another member interface cannot
ping to the IP address. That behavior isn't expected. See PR 48104 for
more realistic examples of this issue.

The change does:
- drop M_PROMISC before ether_input, which allows a bridge member interface
  to receive a frame coming from another bridge member interface
- receive broadcast/multicast frames via all bridge member interfaces,
  which is required to receive IPv6 multicast packets destined to a
  multicast group belonging to a bridge member interface that is different
  from a packet arrival interface

roy@ helped testing of the fix, thanks!


To generate a diff of this commit:
cvs rdiff -u -r1.99 -r1.100 src/sys/net/if_bridge.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_bridge.c
diff -u src/sys/net/if_bridge.c:1.99 src/sys/net/if_bridge.c:1.100
--- src/sys/net/if_bridge.c:1.99	Mon Jun  1 06:14:43 2015
+++ src/sys/net/if_bridge.c	Thu Jul 23 10:52:34 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_bridge.c,v 1.99 2015/06/01 06:14:43 matt Exp $	*/
+/*	$NetBSD: if_bridge.c,v 1.100 2015/07/23 10:52:34 ozaki-r Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.99 2015/06/01 06:14:43 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.100 2015/07/23 10:52:34 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_bridge_ipf.h"
@@ -1942,9 +1942,10 @@ out:
 
 		if (_bif != NULL) {
 			bridge_release_member(sc, bif);
-			if (_ifp != NULL)
+			if (_ifp != NULL) {
+				m->m_flags &= ~M_PROMISC;
 				ether_input(_ifp, m);
-			else
+			} else
 				m_freem(m);
 			return;
 		}
@@ -1989,10 +1990,10 @@ bridge_broadcast(struct bridge_softc *sc
 	struct bridge_iflist *bif;
 	struct mbuf *mc;
 	struct ifnet *dst_if;
-	bool used, bmcast;
+	bool bmcast;
 	int s;
 
-	used = bmcast = m->m_flags & (M_BCAST|M_MCAST);
+	bmcast = m->m_flags & (M_BCAST|M_MCAST);
 
 	BRIDGE_PSZ_RENTER(s);
 	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
@@ -2002,8 +2003,6 @@ bridge_broadcast(struct bridge_softc *sc
 		BRIDGE_PSZ_REXIT(s);
 
 		dst_if = bif->bif_ifp;
-		if (dst_if == src_if)
-			goto next;
 
 		if (bif->bif_flags & IFBIF_STP) {
 			switch (bif->bif_state) {
@@ -2019,28 +2018,33 @@ bridge_broadcast(struct bridge_softc *sc
 		if ((dst_if->if_flags & IFF_RUNNING) == 0)
 			goto next;
 
-		if (!used && LIST_NEXT(bif, bif_next) == NULL) {
-			mc = m;
-			used = true;
-		} else {
+		if (dst_if != src_if) {
 			mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
 			if (mc == NULL) {
 				sc->sc_if.if_oerrors++;
 				goto next;
 			}
+			bridge_enqueue(sc, dst_if, mc, 1);
 		}
 
-		bridge_enqueue(sc, dst_if, mc, 1);
+		if (bmcast) {
+			mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
+			if (mc == NULL) {
+				sc->sc_if.if_oerrors++;
+				goto next;
+			}
+
+			mc->m_pkthdr.rcvif = dst_if;
+			mc->m_flags &= ~M_PROMISC;
+			ether_input(dst_if, mc);
+		}
 next:
 		bridge_release_member(sc, bif);
 		BRIDGE_PSZ_RENTER(s);
 	}
 	BRIDGE_PSZ_REXIT(s);
 
-	if (bmcast)
-		ether_input(src_if, m);
-	else if (!used)
-		m_freem(m);
+	m_freem(m);
 }
 
 static int

Reply via email to