Subject: DLT_NULL and bpf writes
To: None <tech-net@netbsd.org>
From: Matthew Luckie <mjl@luckie.org.nz>
List: tech-net
Date: 06/09/2005 11:41:53
Hi

I spent some time going through all drivers in NetBSD -current that export
DLT_NULL bpf devices with an eye to enabling BPF write support on them.

It seems that all but one or two interface types do not currently support
BPF writes, returning EAFNOSUPPORT, as bpf_movein sets dst->sa_family to
AF_UNSPEC before passing the packet to the appropriate if_output function.
The exception was if_faith.c which expects a 4 byte pseudo header that
contains the underlying address family of the packet for if_output to pick
up in that case.

The 4 byte pseudo header on write seems to have become the default method
to accomplish a BPF write, as most DLT_NULL devices on FreeBSD permit writes
on interfaces with this type.  (although due to a long standing bug in the
implementation, the maximum packet size that can be written is 4 bytes less
than the IP MTU of the interface, as the code did not correctly account for
the 4 byte pseudo header when checking for packets which are too big to tx).

To start with, I identified which interfaces expose DLT_NULL to BPF writers
with egrep -r 'bpfattach.+DLT_NULL' *

which corresponded to the following drivers:

arch/alpha/a12/if_xb.c: bpfattach(&xbi, DLT_NULL, 0);
dev/ppbus/if_plip.c:    bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
net/if_faith.c:         bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
net/if_gif.c:           bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
net/if_gre.c:           bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
net/if_loop.c:          bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
net/if_ppp.c:           bpfattach(&sc->sc_if, DLT_NULL, 0);
net/if_stf.c:           bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
net/if_tun.c:           bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
netisdn/i4b_ipr.c:      bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
netisdn/i4b_ipr.c:      bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));

I went through and added BPF write support using the 4 byte pseudo header
method for if_plip, if_faith (modified), if_gif, if_gre, if_loop, if_stf,
if_tun, and i4b_ipr.  I've put a patch of this work at

http://www.wand.net.nz/~mjl12/netbsd-current-dlt_null-write.diff

I did not touch if_ppp with this patch.  It seems possible that there are
BPF writers in the wild which may possibly be able to write packets without
the 4 byte pseudo header, as pppoutput handles the AF_UNSPEC case currently.
Is there a reason why if_ppp is not a DLT_PPP device, as is the case with
the FreeBSD if_ppp?  I am happy to handle the grunt work of modifying if_ppp
to DLT_PPP if it will help my chances of getting this patch accepted.

I also did not touch if_xb with this patch.  I'm not sure if it is considered
safe to write raw frames with BPF using this device.  Also, I'm not sure
if it is a true DLT_NULL device with a 4 byte pseudo header on read based
on the bpfattach function call.

More information about the context of this work can be found at:
http://lists.freebsd.org/pipermail/freebsd-net/2005-June/007503.html
http://marc.theaimsgroup.com/?l=tcpdump-workers&m=111818619022560&w=2

Please review.

Thanks

Matthew