Subject: Re: /dev/tap and tcpdump don't go together very well? [conclusion & diff]
To: None <current-users@NetBSD.org>
From: Anders Hjalmarsson <hjalmar@hjalmar.to>
List: current-users
Date: 04/11/2007 23:51:55
On Sun, 08 Apr 2007 23:28:03 +0200, Rhialto wrote:


> 
> The problem with sending frames through bpf(4)[1] is that although they
> get sent out on the wire, the local host does not see them.
> Asymmetrically, packets that are sent by the local host *are* copied
> into bpf(4) (although this is undocumentedly optional, but default on).
> In a way this makes sense, since, being a packet filter it is more meant
> to see packets that are on the wire and sending packets out does not
> really fit in its philosophy. 
> 
> But this gives the weird effect that the emulator can successfully
> communicate with the whole world, *execpt* the host it is running on,
> and that in one direction only.
> 
 ...
> 
> On the other hand, bpf(4) could get fixed too. I looked at it briefly,
> but ether_input() consumes the packet so it was not just a matter of
> adding one call. Probably needs a 2 calls: a copy too.
> 


This patch is based on something Manuel Bouyer posted some years ago, but
fixed so that two bpf-using programs on the same host can communicate,
e.g. simh-vax and mopd.



Index: if_ethersubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_ethersubr.c,v
retrieving revision 1.148
diff -u -r1.148 if_ethersubr.c
--- if_ethersubr.c	7 Mar 2007 22:20:05 -0000	1.148
+++ if_ethersubr.c	11 Apr 2007 21:43:43 -0000
@@ -205,6 +205,7 @@
 	struct mbuf *m = m0;
 	struct rtentry *rt;
 	struct mbuf *mcopy = (struct mbuf *)0;
+	struct mbuf *minput;
 	struct ether_header *eh;
 	struct ifnet *ifp = ifp0;
 	ALTQ_DECL(struct altq_pktattr pktattr;)
@@ -433,6 +434,14 @@
 		    sizeof(edst));
 		/* AF_UNSPEC doesn't swap the byte order of the ether_type. */
 		etype = ((const struct ether_header *)dst->sa_data)->ether_type;
+		/* set M_BCAST or M_MCAST accrodingly, upper layer (e.g. bpf)
+		 * may not have set it.
+		 */
+		
+		if (memcmp(etherbroadcastaddr, edst, ETHER_ADDR_LEN) == 0)
+			m->m_flags |= M_BCAST;
+		else if (ETHER_IS_MULTICAST(edst))
+			m->m_flags |= M_MCAST;
 		break;
 
 	default:
@@ -478,6 +487,50 @@
 	if (m == NULL)
 		return (0);
 #endif
+	if (hdrcmplt) {
+		/* check if destination is for us */
+		if (memcmp(LLADDR(ifp->if_sadl), edst, ETHER_ADDR_LEN) == 0) {
+			/* just pass it to ether_input, no need to wire. */
+			int s;
+
+			m->m_pkthdr.rcvif = ifp;
+			s = splnet();
+#if NBPFILTER > 0
+			/*
+			 * Check if there's a BPF listener on this interface.
+			 * If so, hand off the raw packet to BPF.
+			 */
+			if (ifp->if_bpf)
+				bpf_mtap(ifp->if_bpf, m);
+#endif
+
+			ether_input(ifp, m);
+			splx(s);
+			return (0);
+		} else if (m->m_flags & (M_BCAST | M_MCAST)) {
+			/*
+			 * in this case we have to copy a packet to
+			 * ether_input.
+			 */
+			int s;
+
+			minput = m_copypacket(m, M_DONTWAIT);
+			if (minput) {
+				minput->m_pkthdr.rcvif = ifp;
+				s = splnet();
+#if NBPFILTER > 0
+				/*
+				 * Check if there's a BPF listener on this interface.
+				 * If so, hand off the raw packet to BPF.
+				 */
+				if (ifp->if_bpf)
+					bpf_mtap(ifp->if_bpf, minput);
+#endif
+				ether_input(ifp, minput);
+				splx(s);
+			}
+		}
+	}
 
 #if NBRIDGE > 0
 	/*