Index: if_tun.c =================================================================== RCS file: /cvs/src/sys/net/if_tun.c,v diff -u -p -r1.244 if_tun.c --- if_tun.c 1 Nov 2024 02:07:14 -0000 1.244 +++ if_tun.c 5 Nov 2024 05:02:04 -0000 @@ -88,6 +88,7 @@ struct tun_softc { struct sigio_ref sc_sigio; /* async I/O registration */ unsigned int sc_flags; /* misc flags */ #define TUN_DEAD (1 << 16) +#define TUN_HDR (1 << 17) dev_t sc_dev; struct refcnt sc_refs; @@ -104,6 +105,13 @@ int tundebug = TUN_DEBUG; /* Pretend that these IFF flags are changeable by TUNSIFINFO */ #define TUN_IFF_FLAGS (IFF_POINTOPOINT|IFF_MULTICAST|IFF_BROADCAST) +#define TUN_IF_CAPS ( \ + IFCAP_CSUM_IPv4 | \ + IFCAP_CSUM_TCPv4|IFCAP_CSUM_UDPv4|IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6 | \ + IFCAP_VLAN_MTU|IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_HWOFFLOAD | \ + IFCAP_TSOv4|IFCAP_TSOv6|IFCAP_LRO \ +) + void tunattach(int); int tun_dev_open(dev_t, const struct if_clone *, int, struct proc *); @@ -627,6 +635,47 @@ tapioctl(dev_t dev, u_long cmd, caddr_t return (tun_dev_ioctl(dev, cmd, data)); } +static int +tun_set_capabilities(struct tun_softc *sc, const struct tun_capabilities *cap) +{ + if (ISSET(cap->tun_if_capabilities, ~TUN_IF_CAPS)) + return (EINVAL); + + NET_LOCK(); + CLR(sc->sc_if.if_capabilities, TUN_IF_CAPS); + SET(sc->sc_if.if_capabilities, cap->tun_if_capabilities); + SET(sc->sc_flags, TUN_HDR); + NET_UNLOCK(); + return (0); +} + +static int +tun_get_capabilities(struct tun_softc *sc, struct tun_capabilities *cap) +{ + int error = 0; + + NET_LOCK_SHARED(); + if (ISSET(sc->sc_flags, TUN_HDR)) { + cap->tun_if_capabilities = + (sc->sc_if.if_capabilities & TUN_IF_CAPS); + } else + error = ENODEV; + NET_UNLOCK_SHARED(); + + return (error); +} + +static int +tun_del_capabilities(struct tun_softc *sc) +{ + NET_LOCK(); + CLR(sc->sc_flags, TUN_HDR); + CLR(sc->sc_if.if_capabilities, TUN_IF_CAPS); + NET_UNLOCK(); + + return (0); +} + int tun_dev_ioctl(dev_t dev, u_long cmd, void *data) { @@ -678,6 +727,18 @@ tun_dev_ioctl(dev_t dev, u_long cmd, voi } break; + case TUNSCAP: + error = tun_set_capabilities(sc, + (const struct tun_capabilities *)data); + break; + case TUNGCAP: + error = tun_get_capabilities(sc, + (struct tun_capabilities *)data); + break; + case TUNDCAP: + error = tun_del_capabilities(sc); + break; + case FIONBIO: break; case FIOASYNC: @@ -745,6 +806,7 @@ tun_dev_read(dev_t dev, struct uio *uio, struct tun_softc *sc; struct ifnet *ifp; struct mbuf *m, *m0; + size_t len; int error = 0; sc = tun_get(dev); @@ -760,12 +822,49 @@ tun_dev_read(dev_t dev, struct uio *uio, #if NBPFILTER > 0 if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); + (*ifp->if_bpf_mtap)(ifp->if_bpf, m0, BPF_DIRECTION_OUT); #endif + if (ISSET(sc->sc_flags, TUN_HDR)) { + struct tun_hdr th; + + KASSERT(ISSET(m0->m_flags, M_PKTHDR)); + + th.th_flags = 0; + if (ISSET(m0->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT)) + SET(th.th_flags, TUN_H_IPV4_CSUM); + if (ISSET(m0->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) + SET(th.th_flags, TUN_H_TCP_CSUM); + if (ISSET(m0->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) + SET(th.th_flags, TUN_H_UDP_CSUM); + if (ISSET(m0->m_pkthdr.csum_flags, M_ICMP_CSUM_OUT)) + SET(th.th_flags, TUN_H_ICMP_CSUM); + + th.th_pad = 0; + + th.th_vtag = 0; + if (ISSET(m0->m_flags, M_VLANTAG)) { + SET(th.th_flags, TUN_H_VTAG); + th.th_vtag = m0->m_pkthdr.ether_vtag; + } + + th.th_mss = 0; + if (ISSET(m0->m_pkthdr.csum_flags, M_TCP_TSO)) { + SET(th.th_flags, TUN_H_TCP_MSS); + th.th_mss = m0->m_pkthdr.ph_mss; + } + + len = ulmin(uio->uio_resid, sizeof(th)); + if (len > 0) { + error = uiomove(&th, len, uio); + if (error != 0) + goto free; + } + } + m = m0; while (uio->uio_resid > 0) { - size_t len = ulmin(uio->uio_resid, m->m_len); + len = ulmin(uio->uio_resid, m->m_len); if (len > 0) { error = uiomove(mtod(m, void *), len, uio); if (error != 0) @@ -777,6 +876,7 @@ tun_dev_read(dev_t dev, struct uio *uio, break; } +free: m_freem(m0); put: @@ -807,6 +907,8 @@ tun_dev_write(dev_t dev, struct uio *uio struct mbuf *m0; int error = 0; size_t mlen; + size_t hlen; + struct tun_hdr th; sc = tun_get(dev); if (sc == NULL) @@ -814,8 +916,11 @@ tun_dev_write(dev_t dev, struct uio *uio ifp = &sc->sc_if; - if (uio->uio_resid < ifp->if_hdrlen || - uio->uio_resid > (ifp->if_hdrlen + ifp->if_hardmtu)) { + hlen = ifp->if_hdrlen; + if (ISSET(sc->sc_flags, TUN_HDR)) + hlen += sizeof(th); + if (uio->uio_resid < hlen || + uio->uio_resid > (hlen + ifp->if_hardmtu)) { error = EMSGSIZE; goto put; } @@ -839,6 +944,39 @@ tun_dev_write(dev_t dev, struct uio *uio m_align(m0, mlen); m0->m_pkthdr.len = m0->m_len = mlen; m_adj(m0, align); + + if (ISSET(sc->sc_flags, TUN_HDR)) { + error = uiomove(&th, sizeof(th), uio); + if (error != 0) + goto drop; + + if (ISSET(th.th_flags, TUN_H_IPV4_CSUM)) { + SET(m0->m_pkthdr.csum_flags, + M_IPV4_CSUM_OUT | M_IPV4_CSUM_IN_OK); + } + if (ISSET(th.th_flags, TUN_H_TCP_CSUM)) { + SET(m0->m_pkthdr.csum_flags, + M_TCP_CSUM_OUT | M_TCP_CSUM_IN_OK); + } + if (ISSET(th.th_flags, TUN_H_UDP_CSUM)) { + SET(m0->m_pkthdr.csum_flags, + M_UDP_CSUM_OUT | M_UDP_CSUM_IN_OK); + } + if (ISSET(th.th_flags, TUN_H_ICMP_CSUM)) { + SET(m0->m_pkthdr.csum_flags, + M_ICMP_CSUM_OUT | M_ICMP_CSUM_IN_OK); + } + + if (ISSET(th.th_flags, TUN_H_VTAG)) { + SET(m0->m_flags, M_VLANTAG); + m0->m_pkthdr.ether_vtag = th.th_vtag; + } + + if (ISSET(th.th_flags, TUN_H_TCP_MSS)) { + SET(m0->m_pkthdr.csum_flags, M_TCP_TSO); + m0->m_pkthdr.ph_mss = th.th_mss; + } + } error = uiomove(mtod(m0, void *), m0->m_len, uio); if (error != 0) Index: if_tun.h =================================================================== RCS file: /cvs/src/sys/net/if_tun.h,v diff -u -p -r1.15 if_tun.h --- if_tun.h 6 Feb 2007 10:49:40 -0000 1.15 +++ if_tun.h 5 Nov 2024 05:02:04 -0000 @@ -31,6 +31,22 @@ #include +struct tun_hdr { + uint16_t th_flags; +#define TUN_H_VTAG (1 << 0) /* th_vtag is set */ +#define TUN_H_TCP_MSS (1 << 1) /* Cut TCP frame up by th_mss */ + +#define TUN_H_IPV4_CSUM (1 << 8) /* IPv4 cksum needed */ +#define TUN_H_TCP_CSUM (1 << 9) /* TCP cksum needed */ +#define TUN_H_UDP_CSUM (1 << 10) /* UDP cksum needed */ +#define TUN_H_ICMP_CSUM (1 << 11) /* ICMP/ICMPv6 cksum needed */ + + uint16_t th_pad; + + uint16_t th_vtag; + uint16_t th_mss; +}; + #define TUN_OPEN 0x0001 #define TUN_INITED 0x0002 #define TUN_RCOLL 0x0004 /* unused */ @@ -67,5 +83,13 @@ struct tuninfo { /* ioctl's for get/set debug */ #define TUNSDEBUG _IOW('t', 94, int) #define TUNGDEBUG _IOR('t', 95, int) + +struct tun_capabilities { + uint32_t tun_if_capabilities; +}; + +#define TUNSCAP _IOW('t', 96, struct tun_capabilities) +#define TUNGCAP _IOR('t', 96, struct tun_capabilities) +#define TUNDCAP _IO('t', 96) #endif /* _NET_IF_TUN_H_ */