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
/*