Subject: Re: problem with promiscous mode and vlans
To: None <tech-net@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-net
Date: 03/19/2003 19:25:23
--fdj2RfSjLxBAspz7
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Mar 14, 2003 at 06:57:48PM +0100, Manuel Bouyer wrote:
> Hi,
> there is currently a problem with promiscous mode and vlan(4) interfaces.
> When a vlan interface is put in promiscous ode, the underlying inerface
> is as well. But the packets for others hosts never get delivered to the
> vlan interface, because they are filtered too early in ether_input().
> The main problem is that this breaks bridges on top of vlans.
> 
> I see two ways of fixing this:
> a) deliver the packet to vlans devices before the (ifp->if_flags & IFF_PROMISC)
>    check. The bad effect is that we'll have to do this check again in
>    vlan_input, and we'll test etype one more time.
> b) add a new M_PROMISC mbuf flag, and set it in the (ifp->if_flags &
>    IFF_PROMISC) check in ether_input instead of dropping the packet
>    if it's not for us. We'll drop it later if approriate, either in
>    vlan_input() or in the others switch (etype) cases.
>    This may also allow to fix the XXX comment before
>    (ifp->if_flags & IFF_PROMISC) in ether_input() (I didn't look at this
>    yet).

I've gone with solution b), but using one of the M_LINK flag instead of
burning a new one (there's only one byte left in m_flags).
See attached patch
comments ?

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
     NetBSD: 24 ans d'experience feront toujours la difference
--

--fdj2RfSjLxBAspz7
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff

Index: if_ether.h
===================================================================
RCS file: /cvsroot/src/sys/net/if_ether.h,v
retrieving revision 1.29
diff -u -r1.29 if_ether.h
--- if_ether.h	2003/02/26 06:31:12	1.29
+++ if_ether.h	2003/03/19 18:23:02
@@ -103,7 +103,8 @@
 /*
  * Ethernet-specific mbuf flags.
  */
-#define	M_HASFCS	M_LINK0		/* FCS included at end of frame */
+#define	M_HASFCS	M_LINK0	/* FCS included at end of frame */
+#define	M_PROMISC	M_LINK1	/* this packet is not for us */
 
 #ifdef _KERNEL
 /*
Index: if_ethersubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_ethersubr.c,v
retrieving revision 1.105
diff -u -r1.105 if_ethersubr.c
--- if_ethersubr.c	2003/03/02 10:50:14	1.105
+++ if_ethersubr.c	2003/03/19 18:23:02
@@ -738,29 +738,27 @@
 		 * to "bridge" the packet locally.
 		 */
 		ifp = m->m_pkthdr.rcvif;
-	}
+	} else 
 #endif /* NBRIDGE > 0 */
-
-	/*
-	 * XXX This comparison is redundant if we are a bridge
-	 * XXX and processing the packet locally.
-	 */
-	if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
-	    (ifp->if_flags & IFF_PROMISC) != 0 &&
-	    memcmp(LLADDR(ifp->if_sadl), eh->ether_dhost,
-		   ETHER_ADDR_LEN) != 0) {
-		m_freem(m);
-		return;
+	{
+		if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
+		    (ifp->if_flags & IFF_PROMISC) != 0 &&
+		    memcmp(LLADDR(ifp->if_sadl), eh->ether_dhost,
+			   ETHER_ADDR_LEN) != 0) {
+			m->m_flags |= M_PROMISC;
+		}
 	}
 
 #ifdef PFIL_HOOKS
-	if (pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
-		return;
-	if (m == NULL)
-		return;
+	if ((m->m_flags & M_PROMISC) == 0) {
+		if (pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
+			return;
+		if (m == NULL)
+			return;
 
-	eh = mtod(m, struct ether_header *);
-	etype = ntohs(eh->ether_type);
+		eh = mtod(m, struct ether_header *);
+		etype = ntohs(eh->ether_type);
+	}
 #endif
 
 	/*
@@ -775,6 +773,7 @@
 		 * vlan_input() will either recursively call ether_input()
 		 * or drop the packet.
 		 */
+		m->m_flags &= ~M_PROMISC;
 		vlan_input(ifp, m);
 #else
 		m_freem(m);
@@ -793,15 +792,21 @@
 		 * vlan_input() will either recursively call ether_input()
 		 * or drop the packet.
 		 */
-		if (((struct ethercom *)ifp)->ec_nvlans != 0)
+		if (((struct ethercom *)ifp)->ec_nvlans != 0) {
+			m->m_flags &= ~M_PROMISC;
 			vlan_input(ifp, m);
-		else
+		} else {
 			m_freem(m);
+		}
 		return;
 #endif /* NVLAN > 0 */
 #if NPPPOE > 0
 	case ETHERTYPE_PPPOEDISC:
 	case ETHERTYPE_PPPOE:
+		if (m->m_flags & M_PROMISC) {
+			m_freem(m);
+			return;
+		}
 #ifndef PPPOE_SERVER
 		if (m->m_flags & (M_MCAST | M_BCAST)) {
 			m_freem(m);
@@ -829,7 +834,10 @@
 		return;
 #endif /* NPPPOE > 0 */
 	default:
-		; /* Nothing. */
+		if (m->m_flags & M_PROMISC) {
+			m_freem(m);
+			return;
+		}
 	}
 
 	/* Strip off the Ethernet header. */

--fdj2RfSjLxBAspz7--