Subject: bpf write() to local host
To: None <tech-net@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-net
Date: 01/18/2003 22:10:00
--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,
I'd like to commit the attached patch. This patch makes packets coming 
to ether_output with the pseudo-family pseudo_AF_HDRCMPLT and a dest address
matching the local host redirected or copied to ether_input() (depending
if they are unicast or not). Only bpf write() seems to use pseudo_AF_HDRCMPLT
right now.
This is to solve a problem with simh: it uses bpf writes to send packets,
which makes it impossible to send packets to the local machine.
With this change (and a fix to simh) I can NFS mount from a NetBSD/vax in simh
a partition of the NetBSD/i386 hosting it.

Does anyone object to this change ?
Yes it's incomplete; similar changes should probably be done to other
output routines supporting pseudo_AF_HDRCMPLT but as I can't test I won't
do it.

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

--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff.input"

Index: if_ethersubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_ethersubr.c,v
retrieving revision 1.95
diff -u -r1.95 if_ethersubr.c
--- if_ethersubr.c	2002/05/18 22:52:44	1.95
+++ if_ethersubr.c	2003/01/18 20:58:08
@@ -202,6 +202,7 @@
 	struct mbuf *m = m0;
 	struct rtentry *rt;
 	struct mbuf *mcopy = (struct mbuf *)0;
+	struct mbuf *minput;
 	struct ether_header *eh;
 	ALTQ_DECL(struct altq_pktattr pktattr;)
 #ifdef INET
@@ -456,6 +457,14 @@
  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
 		/* AF_UNSPEC doesn't swap the byte order of the ether_type. */
 		etype = eh->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:
@@ -495,6 +504,29 @@
 	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. */
+			m->m_pkthdr.rcvif = ifp;
+			s = splnet();
+			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.
+			 */
+			minput = m_copypacket(m, M_DONTWAIT);
+			if (minput) {
+				minput->m_pkthdr.rcvif = ifp;
+				s = splnet();
+				ether_input(ifp, minput);
+				splx(s);
+			}
+		}
+	}
 
 #if NBRIDGE > 0
 	/*

--YiEDa0DAkWCtVeE4--