umb(4) is currently the only user of DLT_RAW. The problem with this is
that it only works for IPv4 packets and that is less than ideal.
This diff switches umb(4) to DLT_LOOP like lo(4), tun(4), gif(4), ...
To make this work the driver injects the af header in umb_decap() when
pulling the packet of the ring and pops that header in umb_input() this
way the common interface input handling can still be used.
For the outbound packets umb_output() will now set ph_family header in the
mbuf so that umb_start() can use this in bpf_mtap_af().
With this tcpdump should be able to show also IPv6 packets.
My provider does not do IPv6 (neither via umb MBIM_CID_IP_CONFIGURATION or
via slaac) but maybe someone else has a more tech competent provider than
me and is willing to make IPv6 go on umb(4).
--
:wq Claudio
Index: dev/usb/if_umb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_umb.c,v
retrieving revision 1.26
diff -u -p -r1.26 if_umb.c
--- dev/usb/if_umb.c 29 Sep 2019 15:31:16 -0000 1.26
+++ dev/usb/if_umb.c 1 Oct 2019 11:00:10 -0000
@@ -516,7 +516,7 @@ umb_attach(struct device *parent, struct
if_alloc_sadl(ifp);
ifp->if_softc = sc;
#if NBPFILTER > 0
- bpfattach(&ifp->if_bpf, ifp, DLT_RAW, 0);
+ bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
#endif
/*
* Open the device now so that we are able to query device information.
@@ -759,19 +759,20 @@ umb_output(struct ifnet *ifp, struct mbu
m_freem(m);
return ENETDOWN;
}
+ m->m_pkthdr.ph_family = dst->sa_family;
return if_enqueue(ifp, m);
}
int
umb_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
{
- uint8_t ipv;
+ uint32_t af;
if ((ifp->if_flags & IFF_UP) == 0) {
m_freem(m);
return 1;
}
- if (m->m_pkthdr.len < sizeof (struct ip)) {
+ if (m->m_pkthdr.len < sizeof (struct ip) + sizeof(af)) {
ifp->if_ierrors++;
DPRINTFN(4, "%s: dropping short packet (len %d)\n", __func__,
m->m_pkthdr.len);
@@ -779,16 +780,19 @@ umb_input(struct ifnet *ifp, struct mbuf
return 1;
}
m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
- m_copydata(m, 0, sizeof (ipv), &ipv);
- ipv >>= 4;
+
+ /* pop of DLT_LOOP header, no longer needed */
+ af = *mtod(m, uint32_t *);
+ m_adj(m, sizeof (af));
+ af = ntohl(af);
ifp->if_ibytes += m->m_pkthdr.len;
- switch (ipv) {
- case 4:
+ switch (af) {
+ case AF_INET:
ipv4_input(ifp, m);
return 1;
#ifdef INET6
- case 6:
+ case AF_INET6:
ipv6_input(ifp, m);
return 1;
#endif /* INET6 */
@@ -878,7 +882,8 @@ umb_start(struct ifnet *ifp)
#if NBPFILTER > 0
if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+ bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, m,
+ BPF_DIRECTION_OUT);
#endif
}
if (ml_empty(&sc->sc_tx_ml))
@@ -1916,7 +1921,7 @@ umb_decap(struct umb_softc *sc, struct u
struct ifnet *ifp = GET_IFP(sc);
int s;
void *buf;
- uint32_t len;
+ uint32_t len, af = 0;
char *dp;
struct ncm_header16 *hdr16;
struct ncm_header32 *hdr32;
@@ -2033,12 +2038,25 @@ umb_decap(struct umb_softc *sc, struct u
dp = buf + doff;
DPRINTFN(3, "%s: decap %d bytes\n", DEVNAM(sc), dlen);
- m = m_devget(dp, dlen, 0);
+ m = m_devget(dp, dlen, sizeof(uint32_t));
if (m == NULL) {
ifp->if_iqdrops++;
continue;
}
-
+ m = m_prepend(m, sizeof(uint32_t), M_DONTWAIT);
+ if (m == NULL) {
+ ifp->if_iqdrops++;
+ continue;
+ }
+ switch (*dp & 0xf0) {
+ case 4 << 4:
+ af = htonl(AF_INET);
+ break;
+ case 6 << 4:
+ af = htonl(AF_INET6);
+ break;
+ }
+ *mtod(m, uint32_t *) = af;
ml_enqueue(&ml, m);
}
done: