bpf writes on tun device

Matthew Luckie mjl at luckie.org.nz
Mon Jun 6 08:17:42 GMT 2005


> I can successfully write BPF packets up to 1500 bytes in size (1496 IP 
> bytes without the address family integer).  Writes larger than this 
> return EMSGSIZE.

http://lists.freebsd.org/pipermail/freebsd-net/2005-May/007371.html

Just for the record, the patch below fixes this on 4.11; the same
problem exists in HEAD today.  I'm pondering making an effort to add
write support to all interface types.  I would do this by adding an
extra parameter to bpf_if that specifies the size of the 'link layer'
it expects to encounter when bpfwrite is called.

struct bpf_if {
	LIST_ENTRY(bpf_if)	bif_next;	/* list of all interfaces */
	LIST_HEAD(, bpf_d)	bif_dlist;	/* descriptor list */
	struct bpf_if **bif_driverp;	/* pointer into softc */
	u_int bif_dlt;			/* link layer type */
-	u_int bif_hdrlen;               /* length of header (with padding) */
+	u_int bif_hdrlen_rx;		/* link header passed to bpf reader */
+	u_int bif_hdrlen_tx;            /* link header passed by bpf writer */
	struct ifnet *bif_ifp;		/* corresponding interface */
	struct mtx	bif_mtx;	/* mutex for interface */
};

If I was to pursue this, would someone on this list consider committing the
work to current?

Index: bpf.c
===================================================================
RCS file: /home/ncvs/src/sys/net/bpf.c,v
retrieving revision 1.59.2.13
diff -u -p -r1.59.2.13 bpf.c
--- bpf.c	21 Aug 2003 23:50:54 -0000	1.59.2.13
+++ bpf.c	6 Jun 2005 07:54:12 -0000
@@ -120,7 +120,7 @@ static void	bpf_detachd __P((struct bpf_
 static void	bpf_freed __P((struct bpf_d *));
 static void	bpf_mcopy __P((const void *, void *, size_t));
 static int	bpf_movein __P((struct uio *, int,
-		    struct mbuf **, struct sockaddr *, int *));
+		    struct mbuf **, struct sockaddr *, struct ifnet *));
 static int	bpf_setif __P((struct bpf_d *, struct ifreq *));
 static void	bpf_timed_out __P((void *));
 static inline void
@@ -164,9 +164,10 @@ static struct filterops bpfread_filtops 
 	{ 1, NULL, filt_bpfdetach, filt_bpfread };
 
 static int
-bpf_movein(uio, linktype, mp, sockp, datlen)
+bpf_movein(uio, linktype, mp, sockp, ifp)
 	register struct uio *uio;
-	int linktype, *datlen;
+	int linktype;
+	struct ifnet *ifp;
 	register struct mbuf **mp;
 	register struct sockaddr *sockp;
 {
@@ -209,11 +210,18 @@ bpf_movein(uio, linktype, mp, sockp, dat
 		break;
 
 	case DLT_RAW:
-	case DLT_NULL:
 		sockp->sa_family = AF_UNSPEC;
 		hlen = 0;
 		break;
 
+	case DLT_NULL:
+		sockp->sa_family = AF_UNSPEC;
+		if(strcmp(ifp->if_name, "tun") == 0)
+			hlen = sizeof(int);
+		else
+			hlen = 0;
+		break;
+
 #ifdef __FreeBSD__
 	case DLT_ATM_RFC1483:
 		/*
@@ -235,7 +243,10 @@ bpf_movein(uio, linktype, mp, sockp, dat
 	}
 
 	len = uio->uio_resid;
-	*datlen = len - hlen;
+
+	if (len - hlen > ifp->if_mtu)
+		return (EMSGSIZE);
+
 	if ((unsigned)len > MCLBYTES)
 		return (EIO);
 
@@ -619,7 +630,6 @@ bpfwrite(dev, uio, ioflag)
 	struct mbuf *m;
 	int error, s;
 	static struct sockaddr dst;
-	int datlen;
 
 	if (d->bd_bif == 0)
 		return (ENXIO);
@@ -629,12 +639,9 @@ bpfwrite(dev, uio, ioflag)
 	if (uio->uio_resid == 0)
 		return (0);
 
-	error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen);
+	error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, ifp);
 	if (error)
 		return (error);
-
-	if (datlen > ifp->if_mtu)
-		return (EMSGSIZE);
 
 	if (d->bd_hdrcmplt)
 		dst.sa_family = pseudo_AF_HDRCMPLT;
Index: if_tun.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_tun.c,v
retrieving revision 1.74.2.8
diff -u -p -r1.74.2.8 if_tun.c
--- if_tun.c	13 Feb 2002 00:43:11 -0000	1.74.2.8
+++ if_tun.c	6 Jun 2005 07:54:13 -0000
@@ -328,10 +328,8 @@ tunoutput(ifp, m0, dst, rt)
 
 	/* BPF write needs to be handled specially */
 	if (dst->sa_family == AF_UNSPEC) {
-		dst->sa_family = *(mtod(m0, int *));
-		m0->m_len -= sizeof(int);
-		m0->m_pkthdr.len -= sizeof(int);
-		m0->m_data += sizeof(int);
+		bcopy(dst->sa_data, &s, 4);
+		dst->sa_family = s; 
 	}
 
 	if (ifp->if_bpf) {


More information about the freebsd-net mailing list