Index: if_tun.c =================================================================== RCS file: /cvs/src/sys/net/if_tun.c,v diff -u -p -r1.250 if_tun.c --- if_tun.c 30 Dec 2024 02:46:00 -0000 1.250 +++ if_tun.c 17 Feb 2025 03:49:18 -0000 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -77,22 +78,23 @@ #include struct tun_softc { - struct arpcom sc_ac; /* ethernet common data */ -#define sc_if sc_ac.ac_if - struct mutex sc_mtx; - struct klist sc_rklist; /* knotes for read */ - struct klist sc_wklist; /* knotes for write (unused) */ + struct ifnet *sc_ifp; + + struct mutex sc_mtx; + struct klist sc_rklist; /* knotes for read */ + struct klist sc_wklist; /* knotes for write (unused) */ SMR_LIST_ENTRY(tun_softc) - sc_entry; /* all tunnel interfaces */ - int sc_unit; - struct sigio_ref sc_sigio; /* async I/O registration */ - unsigned int sc_flags; /* misc flags */ -#define TUN_DEAD (1 << 16) + sc_entry; /* all tunnel interfaces */ + struct sigio_ref sc_sigio; /* async I/O registration */ + unsigned int sc_flags; /* misc flags */ #define TUN_HDR (1 << 17) - dev_t sc_dev; - struct refcnt sc_refs; - unsigned int sc_reading; + dev_t sc_dev; + struct refcnt sc_refs; + unsigned int sc_reading; + unsigned int sc_dead; + + struct vnode *sc_vp; }; #ifdef TUN_DEBUG @@ -139,6 +141,7 @@ int filt_tunprocess(struct knote *, stru void filt_tunrdetach(struct knote *); void filt_tunwdetach(struct knote *); void tun_link_state(struct ifnet *, int); +void tun_revoke(struct ifnet *); const struct filterops tunread_filtops = { .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, @@ -176,52 +179,60 @@ tunattach(int n) int tun_clone_create(struct if_clone *ifc, int unit) { - return (tun_create(ifc, unit, 0)); -} + struct ifnet *ifp; -int -tap_clone_create(struct if_clone *ifc, int unit) -{ - return (tun_create(ifc, unit, TUN_LAYER2)); -} + if (unit > minor(~0U)) + return (ENXIO); -struct tun_list tun_devs_list = SMR_LIST_HEAD_INITIALIZER(tun_list); + KERNEL_ASSERT_LOCKED(); -struct tun_softc * -tun_name_lookup(const char *name) -{ - struct tun_softc *sc; + ifp = malloc(sizeof(*ifp), M_DEVBUF, M_WAITOK|M_ZERO); + snprintf(ifp->if_xname, sizeof(ifp->if_xname), + "%s%d", ifc->ifc_name, unit); - KERNEL_ASSERT_LOCKED(); + ifp->if_ioctl = tun_ioctl; + ifp->if_enqueue = tun_enqueue; + ifp->if_start = tun_start; + ifp->if_hardmtu = TUNMRU; + ifp->if_link_state = LINK_STATE_DOWN; - SMR_LIST_FOREACH_LOCKED(sc, &tun_devs_list, sc_entry) { - if (strcmp(sc->sc_if.if_xname, name) == 0) - return (sc); - } +#if NBPFILTER > 0 + ifp->if_bpf_mtap = bpf_mtap; +#endif + ifp->if_input = tun_input; + ifp->if_output = tun_output; + ifp->if_mtu = ETHERMTU; + ifp->if_type = IFT_TUNNEL; + ifp->if_hdrlen = sizeof(u_int32_t); + ifp->if_rtrequest = p2p_rtrequest; + ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); - return (NULL); + if_counters_alloc(ifp); + if_attach(ifp); + if_alloc_sadl(ifp); + +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t)); +#endif + + return (0); } int -tun_insert(struct tun_softc *sc) +tun_clone_destroy(struct ifnet *ifp) { - int error = 0; + tun_revoke(ifp); - /* check for a race */ - if (tun_name_lookup(sc->sc_if.if_xname) != NULL) - error = EEXIST; - else { - /* tun_name_lookup checks for the right lock already */ - SMR_LIST_INSERT_HEAD_LOCKED(&tun_devs_list, sc, sc_entry); - } + if_detach(ifp); - return (error); + free(ifp, M_DEVBUF, sizeof(*ifp)); + return (0); } int -tun_create(struct if_clone *ifc, int unit, int flags) +tap_clone_create(struct if_clone *ifc, int unit) { - struct tun_softc *sc; + struct arpcom *ac; struct ifnet *ifp; if (unit > minor(~0U)) @@ -229,23 +240,11 @@ tun_create(struct if_clone *ifc, int uni KERNEL_ASSERT_LOCKED(); - sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); - refcnt_init(&sc->sc_refs); + ac = malloc(sizeof(*ac), M_DEVBUF, M_WAITOK|M_ZERO); - ifp = &sc->sc_if; + ifp = &ac->ac_if; snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", ifc->ifc_name, unit); - mtx_init(&sc->sc_mtx, IPL_NET); - klist_init_mutex(&sc->sc_rklist, &sc->sc_mtx); - klist_init_mutex(&sc->sc_wklist, &sc->sc_mtx); - ifp->if_softc = sc; - - /* this is enough state for tun_dev_open to work with */ - - if (tun_insert(sc) != 0) - goto exists; - - /* build the interface */ ifp->if_ioctl = tun_ioctl; ifp->if_enqueue = tun_enqueue; @@ -253,102 +252,49 @@ tun_create(struct if_clone *ifc, int uni ifp->if_hardmtu = TUNMRU; ifp->if_link_state = LINK_STATE_DOWN; - if_counters_alloc(ifp); - - if ((flags & TUN_LAYER2) == 0) { -#if NBPFILTER > 0 - ifp->if_bpf_mtap = bpf_mtap; -#endif - ifp->if_input = tun_input; - ifp->if_output = tun_output; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); - ifp->if_type = IFT_TUNNEL; - ifp->if_hdrlen = sizeof(u_int32_t); - ifp->if_rtrequest = p2p_rtrequest; + ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); - if_attach(ifp); - if_alloc_sadl(ifp); + ether_fakeaddr(ifp); -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t)); -#endif - } else { - sc->sc_flags |= TUN_LAYER2; - ether_fakeaddr(ifp); - ifp->if_flags = - (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); - - if_attach(ifp); - ether_ifattach(ifp); - } - - sigio_init(&sc->sc_sigio); - - /* tell tun_dev_open we're initialised */ - - sc->sc_flags |= TUN_INITED|TUN_STAYUP; - wakeup(sc); + if_counters_alloc(ifp); + if_attach(ifp); + ether_ifattach(ifp); return (0); - -exists: - klist_free(&sc->sc_rklist); - klist_free(&sc->sc_wklist); - free(sc, M_DEVBUF, sizeof(*sc)); - return (EEXIST); } int -tun_clone_destroy(struct ifnet *ifp) +tap_clone_destroy(struct ifnet *ifp) { - struct tun_softc *sc = ifp->if_softc; - dev_t dev; - - KERNEL_ASSERT_LOCKED(); - - if (ISSET(sc->sc_flags, TUN_DEAD)) - return (ENXIO); - SET(sc->sc_flags, TUN_DEAD); - - /* kick userland off the device */ - dev = sc->sc_dev; - if (dev) { - struct vnode *vp; + struct arpcom *ac = (struct arpcom *)ifp; - if (vfinddev(dev, VCHR, &vp)) - VOP_REVOKE(vp, REVOKEALL); - - KASSERT(sc->sc_dev == 0); - } - - /* prevent userland from getting to the device again */ - SMR_LIST_REMOVE_LOCKED(sc, sc_entry); - smr_barrier(); + tun_revoke(ifp); - /* help read() give up */ - if (sc->sc_reading) - wakeup(&ifp->if_snd); - - /* wait for device entrypoints to finish */ - refcnt_finalize(&sc->sc_refs, "tundtor"); + ether_ifdetach(ifp); + if_detach(ifp); - klist_invalidate(&sc->sc_rklist); - klist_invalidate(&sc->sc_wklist); + free(ac, M_DEVBUF, sizeof(*ac)); + return (0); +} - klist_free(&sc->sc_rklist); - klist_free(&sc->sc_wklist); +void +tun_revoke(struct ifnet *ifp) +{ + struct tun_softc *sc; - if (ISSET(sc->sc_flags, TUN_LAYER2)) - ether_ifdetach(ifp); + KERNEL_ASSERT_LOCKED(); + sc = SMR_PTR_GET_LOCKED(&ifp->if_softc); + if (sc == NULL) + return; - if_detach(ifp); - sigio_free(&sc->sc_sigio); + /* we're destroying the interface so tun_dev_close doesn't have to */ + SET(sc->sc_flags, TUN_STAYUP); - free(sc, M_DEVBUF, sizeof *sc); - return (0); + VOP_REVOKE(sc->sc_vp, REVOKEALL); } +struct tun_list tun_devs_list = SMR_LIST_HEAD_INITIALIZER(tun_list); + static struct tun_softc * tun_get(dev_t dev) { @@ -387,10 +333,9 @@ tapopen(dev_t dev, int flag, int mode, s int tun_dev_open(dev_t dev, const struct if_clone *ifc, int mode, struct proc *p) { - struct tun_softc *sc; + struct tun_softc *sc, *osc; struct ifnet *ifp; int error; - u_short stayup = 0; struct vnode *vp; char name[IFNAMSIZ]; @@ -398,73 +343,106 @@ tun_dev_open(dev_t dev, const struct if_ /* * Find the vnode associated with this open before we sleep - * and let something else revoke it. Our caller has a reference - * to it so we don't need to account for it. + * and let something else revoke it. Note that at this point + * there can be many threads in this function for the same + * cdev instance on the one vnode. Exclusive access to this + * cdev instance is enforced by this function below, so we + * need to handle the situation where we may be one of these + * many embryonic opens of the cdev that are accidentally + * revoked by tun_revoke. */ if (!vfinddev(dev, VCHR, &vp)) panic("%s vfinddev failed", __func__); - snprintf(name, sizeof(name), "%s%u", ifc->ifc_name, minor(dev)); - rdomain = rtable_l2(p->p_p->ps_rtableid); + KERNEL_ASSERT_LOCKED(); - /* let's find or make an interface to work with */ - while ((sc = tun_name_lookup(name)) == NULL) { - error = if_clone_create(name, rdomain); - switch (error) { - case 0: /* it's probably ours */ - stayup = TUN_STAYUP; - /* FALLTHROUGH */ - case EEXIST: /* we may have lost a race with someone else */ - break; - default: - return (error); - } + SMR_LIST_FOREACH_LOCKED(osc, &tun_devs_list, sc_entry) { + if (osc->sc_dev == dev) + return (EBUSY); } - refcnt_take(&sc->sc_refs); + sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); + if (sc == NULL) + return (ENOMEM); - /* wait for it to be fully constructed before we use it */ - for (;;) { - if (ISSET(sc->sc_flags, TUN_DEAD)) { - error = ENXIO; - goto done; - } + sc->sc_dev = dev; + vref(vp); + sc->sc_vp = vp; - if (ISSET(sc->sc_flags, TUN_INITED)) - break; + mtx_init(&sc->sc_mtx, IPL_NET); + klist_init_mutex(&sc->sc_rklist, &sc->sc_mtx); + klist_init_mutex(&sc->sc_wklist, &sc->sc_mtx); + sigio_init(&sc->sc_sigio); + + snprintf(name, sizeof(name), "%s%u", ifc->ifc_name, minor(dev)); + rdomain = rtable_l2(p->p_p->ps_rtableid); + + /* let's find or make an interface to work with */ + ifp = if_unit(name); + if (ifp == NULL) { + do { + error = if_clone_create(name, rdomain); + switch (error) { + case 0: + case EEXIST: + break; + default: + goto done; + } - error = tsleep_nsec(sc, PCATCH, "tuninit", INFSLP); - if (error != 0) { - /* XXX if_clone_destroy if stayup? */ + ifp = if_unit(name); + } while (ifp == NULL); + } else + SET(sc->sc_flags, TUN_STAYUP); + + /* Let's see if we won */ + SMR_LIST_FOREACH_LOCKED(osc, &tun_devs_list, sc_entry) { + if (osc->sc_dev == dev) { + /* aww, we lost */ + error = EBUSY; goto done; } } - /* Has tun_clone_destroy torn the rug out under us? */ + /* Has tun_revoke torn the rug out under us? */ if (vp->v_type == VBAD) { error = ENXIO; goto done; } - if (sc->sc_dev != 0) { - /* aww, we lost */ - error = EBUSY; - goto done; - } /* it's ours now */ - sc->sc_dev = dev; - CLR(sc->sc_flags, stayup); + sc->sc_ifp = ifp; + SMR_LIST_INSERT_HEAD_LOCKED(&tun_devs_list, sc, sc_entry); + + /* + * "publish" that this cdev instance is associated with the + * network interface. a consequence of this is that destroying + * the interface will try call VOP_REVOKE against it. revoke can + * call tun_dev_close and destroy the interface, so we take + * a ref here to keep the ifp alive. + */ + + KASSERT(SMR_PTR_GET_LOCKED(&ifp->if_softc) == NULL); + SMR_PTR_SET_LOCKED(&ifp->if_softc, sc); + + ifp = if_get(ifp->if_index); /* automatically mark the interface running on open */ - ifp = &sc->sc_if; NET_LOCK(); SET(ifp->if_flags, IFF_UP | IFF_RUNNING); NET_UNLOCK(); tun_link_state(ifp, LINK_STATE_FULL_DUPLEX); - error = 0; + if_put(ifp); + + return (0); done: - tun_put(sc); + if_put(ifp); + klist_free(&sc->sc_rklist); + klist_free(&sc->sc_wklist); + vrele(sc->sc_vp); + free(sc, M_DEVBUF, sizeof(*sc)); + /* XXX stayup? */ return (error); } @@ -489,46 +467,61 @@ tun_dev_close(dev_t dev, struct proc *p) { struct tun_softc *sc; struct ifnet *ifp; - int error = 0; char name[IFNAMSIZ]; int destroy = 0; + KERNEL_ASSERT_LOCKED(); + sc = tun_get(dev); - if (sc == NULL) - return (ENXIO); + KASSERT(sc != NULL); + sc->sc_dead = 1; - ifp = &sc->sc_if; + ifp = sc->sc_ifp; - /* - * junk all pending output - */ - NET_LOCK(); - CLR(ifp->if_flags, IFF_UP | IFF_RUNNING); - CLR(ifp->if_capabilities, TUN_IF_CAPS); - NET_UNLOCK(); - ifq_purge(&ifp->if_snd); + if (!ISSET(sc->sc_flags, TUN_STAYUP)) { + destroy = 1; + strlcpy(name, ifp->if_xname, sizeof(name)); + } else { + /* + * junk all pending output + */ + tun_link_state(ifp, LINK_STATE_DOWN); + NET_LOCK(); + CLR(ifp->if_flags, IFF_UP | IFF_RUNNING); + CLR(ifp->if_capabilities, TUN_IF_CAPS); + NET_UNLOCK(); + ifq_purge(&ifp->if_snd); + } - CLR(sc->sc_flags, TUN_ASYNC|TUN_HDR); - sigio_free(&sc->sc_sigio); + KASSERT(SMR_PTR_GET_LOCKED(&ifp->if_softc) == sc); + SMR_PTR_SET_LOCKED(&ifp->if_softc, NULL); - if (!ISSET(sc->sc_flags, TUN_DEAD)) { - /* we can't hold a reference to sc before we start a dtor */ - if (!ISSET(sc->sc_flags, TUN_STAYUP)) { - destroy = 1; - strlcpy(name, ifp->if_xname, sizeof(name)); - } else { - tun_link_state(ifp, LINK_STATE_DOWN); - } - } + /* prevent userland from getting to the device again */ + SMR_LIST_REMOVE_LOCKED(sc, sc_entry); + smr_barrier(); - sc->sc_dev = 0; + /* help read() give up */ + if (sc->sc_reading) + wakeup(&ifp->if_snd); - tun_put(sc); + klist_invalidate(&sc->sc_rklist); + klist_invalidate(&sc->sc_wklist); + + /* wait for device entrypoints to finish. */ + refcnt_finalize(&sc->sc_refs, "tunclose"); + if_put(ifp); + + sigio_free(&sc->sc_sigio); + klist_free(&sc->sc_rklist); + klist_free(&sc->sc_wklist); + + vrele(sc->sc_vp); + free(sc, M_DEVBUF, sizeof(*sc)); if (destroy) if_clone_destroy(name); - return (error); + return (0); } /* @@ -537,7 +530,6 @@ tun_dev_close(dev_t dev, struct proc *p) int tun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct tun_softc *sc = (struct tun_softc *)(ifp->if_softc); struct ifreq *ifr = (struct ifreq *)data; int error = 0; @@ -562,9 +554,10 @@ tun_ioctl(struct ifnet *ifp, u_long cmd, case SIOCDELMULTI: break; default: - if (sc->sc_flags & TUN_LAYER2) - error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); - else + if (!ISSET(ifp->if_flags, IFF_POINTOPOINT)) { + error = ether_ioctl(ifp, (struct arpcom *)ifp, + cmd, data); + } else error = ENOTTY; } @@ -597,23 +590,32 @@ tun_output(struct ifnet *ifp, struct mbu int tun_enqueue(struct ifnet *ifp, struct mbuf *m0) { - struct tun_softc *sc = ifp->if_softc; + struct tun_softc *sc; int error; - error = ifq_enqueue(&ifp->if_snd, m0); - if (error != 0) - return (error); + smr_read_enter(); + sc = SMR_PTR_GET(&ifp->if_softc); + if (sc != NULL) { + error = ifq_enqueue(&ifp->if_snd, m0); + if (error == 0) + tun_wakeup(sc); + } + smr_read_leave(); - tun_wakeup(sc); + if (sc == NULL) { + m_freem(m0); + counters_inc(ifp->if_counters, ifc_oerrors); + error = ENETDOWN; + } - return (0); + return (error); } void tun_wakeup(struct tun_softc *sc) { if (sc->sc_reading) - wakeup(&sc->sc_if.if_snd); + wakeup(&sc->sc_ifp->if_snd); knote(&sc->sc_rklist, 0); @@ -637,7 +639,8 @@ tapioctl(dev_t dev, u_long cmd, caddr_t } static int -tun_set_capabilities(struct tun_softc *sc, const struct tun_capabilities *cap) +tun_set_capabilities(struct tun_softc *sc, struct ifnet *ifp, + const struct tun_capabilities *cap) { if (ISSET(cap->tun_if_capabilities, ~TUN_IF_CAPS)) return (EINVAL); @@ -646,21 +649,22 @@ tun_set_capabilities(struct tun_softc *s SET(sc->sc_flags, TUN_HDR); NET_LOCK(); - CLR(sc->sc_if.if_capabilities, TUN_IF_CAPS); - SET(sc->sc_if.if_capabilities, cap->tun_if_capabilities); + CLR(ifp->if_capabilities, TUN_IF_CAPS); + SET(ifp->if_capabilities, cap->tun_if_capabilities); NET_UNLOCK(); return (0); } static int -tun_get_capabilities(struct tun_softc *sc, struct tun_capabilities *cap) +tun_get_capabilities(struct tun_softc *sc, struct ifnet *ifp, + 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); + (ifp->if_capabilities & TUN_IF_CAPS); } else error = ENODEV; NET_UNLOCK_SHARED(); @@ -669,10 +673,10 @@ tun_get_capabilities(struct tun_softc *s } static int -tun_del_capabilities(struct tun_softc *sc) +tun_del_capabilities(struct tun_softc *sc, struct ifnet *ifp) { NET_LOCK(); - CLR(sc->sc_if.if_capabilities, TUN_IF_CAPS); + CLR(ifp->if_capabilities, TUN_IF_CAPS); NET_UNLOCK(); KERNEL_ASSERT_LOCKED(); @@ -684,7 +688,7 @@ tun_del_capabilities(struct tun_softc *s static int tun_hdatalen(struct tun_softc *sc) { - struct ifnet *ifp = &sc->sc_if; + struct ifnet *ifp = sc->sc_ifp; int len; len = ifq_hdatalen(&ifp->if_snd); @@ -698,12 +702,15 @@ int tun_dev_ioctl(dev_t dev, u_long cmd, void *data) { struct tun_softc *sc; + struct ifnet *ifp; + struct arpcom *ac; struct tuninfo *tunp; int error = 0; sc = tun_get(dev); if (sc == NULL) return (ENXIO); + ifp = sc->sc_ifp; switch (cmd) { case TUNSIFINFO: @@ -712,23 +719,23 @@ tun_dev_ioctl(dev_t dev, u_long cmd, voi error = EINVAL; break; } - if (tunp->type != sc->sc_if.if_type) { + if (tunp->type != ifp->if_type) { error = EINVAL; break; } - if (tunp->flags != (sc->sc_if.if_flags & TUN_IFF_FLAGS)) { + if (tunp->flags != (ifp->if_flags & TUN_IFF_FLAGS)) { error = EINVAL; break; } - sc->sc_if.if_mtu = tunp->mtu; - sc->sc_if.if_baudrate = tunp->baudrate; + ifp->if_mtu = tunp->mtu; + ifp->if_baudrate = tunp->baudrate; break; case TUNGIFINFO: tunp = (struct tuninfo *)data; - tunp->mtu = sc->sc_if.if_mtu; - tunp->type = sc->sc_if.if_type; - tunp->flags = sc->sc_if.if_flags & TUN_IFF_FLAGS; - tunp->baudrate = sc->sc_if.if_baudrate; + tunp->mtu = ifp->if_mtu; + tunp->type = ifp->if_type; + tunp->flags = ifp->if_flags & TUN_IFF_FLAGS; + tunp->baudrate = ifp->if_baudrate; break; #ifdef TUN_DEBUG case TUNSDEBUG: @@ -739,22 +746,22 @@ tun_dev_ioctl(dev_t dev, u_long cmd, voi break; #endif case TUNSIFMODE: - if (*(int *)data != (sc->sc_if.if_flags & TUN_IFF_FLAGS)) { + if (*(int *)data != (ifp->if_flags & TUN_IFF_FLAGS)) { error = EINVAL; break; } break; case TUNSCAP: - error = tun_set_capabilities(sc, + error = tun_set_capabilities(sc, ifp, (const struct tun_capabilities *)data); break; case TUNGCAP: - error = tun_get_capabilities(sc, + error = tun_get_capabilities(sc, ifp, (struct tun_capabilities *)data); break; case TUNDCAP: - error = tun_del_capabilities(sc); + error = tun_del_capabilities(sc, ifp); break; case FIOASYNC: @@ -775,21 +782,21 @@ tun_dev_ioctl(dev_t dev, u_long cmd, voi sigio_getown(&sc->sc_sigio, cmd, data); break; case SIOCGIFADDR: - if (!(sc->sc_flags & TUN_LAYER2)) { + if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) { error = EINVAL; break; } - bcopy(sc->sc_ac.ac_enaddr, data, - sizeof(sc->sc_ac.ac_enaddr)); + ac = (struct arpcom *)ifp; + bcopy(ac->ac_enaddr, data, sizeof(ac->ac_enaddr)); break; case SIOCSIFADDR: - if (!(sc->sc_flags & TUN_LAYER2)) { + if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) { error = EINVAL; break; } - bcopy(data, sc->sc_ac.ac_enaddr, - sizeof(sc->sc_ac.ac_enaddr)); + ac = (struct arpcom *)ifp; + bcopy(data, ac->ac_enaddr, sizeof(ac->ac_enaddr)); break; default: error = ENOTTY; @@ -828,11 +835,10 @@ tun_dev_read(dev_t dev, struct uio *uio, sc = tun_get(dev); if (sc == NULL) return (ENXIO); - - ifp = &sc->sc_if; + ifp = sc->sc_ifp; error = ifq_deq_sleep(&ifp->if_snd, &m0, ISSET(ioflag, IO_NDELAY), - (PZERO + 1)|PCATCH, "tunread", &sc->sc_reading, &sc->sc_dev); + (PZERO + 1)|PCATCH, "tunread", &sc->sc_reading, &sc->sc_dead); if (error != 0) goto put; @@ -929,8 +935,7 @@ tun_dev_write(dev_t dev, struct uio *uio sc = tun_get(dev); if (sc == NULL) return (ENXIO); - - ifp = &sc->sc_if; + ifp = sc->sc_ifp; hlen = ifp->if_hdrlen; if (ISSET(sc->sc_flags, TUN_HDR)) @@ -979,7 +984,7 @@ tun_dev_write(dev_t dev, struct uio *uio } if (ISSET(th.th_flags, TUN_H_VTAG)) { - if (!ISSET(sc->sc_flags, TUN_LAYER2)) { + if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) { error = EINVAL; goto drop; } @@ -1044,14 +1049,14 @@ tun_dev_write(dev_t dev, struct uio *uio if_vinput(ifp, m0); NET_UNLOCK(); + error = 0; +put: tun_put(sc); - return (0); + return (error); drop: m_freem(m0); -put: - tun_put(sc); - return (error); + goto put; } void @@ -1163,11 +1168,12 @@ int filt_tunwrite(struct knote *kn, long hint) { struct tun_softc *sc = kn->kn_hook; - struct ifnet *ifp = &sc->sc_if; + struct ifnet *ifp = sc->sc_ifp; MUTEX_ASSERT_LOCKED(&sc->sc_mtx); kn->kn_data = ifp->if_hdrlen + ifp->if_hardmtu; + /* TUN_HDR? */ return (1); } @@ -1201,12 +1207,13 @@ filt_tunprocess(struct knote *kn, struct void tun_start(struct ifnet *ifp) { - struct tun_softc *sc = ifp->if_softc; - - splassert(IPL_NET); + struct tun_softc *sc; - if (ifq_len(&ifp->if_snd)) + smr_read_enter(); + sc = ifp->if_softc; + if (sc != NULL && ifq_len(&ifp->if_snd)) tun_wakeup(sc); + smr_read_leave(); } void Index: ifq.c =================================================================== RCS file: /cvs/src/sys/net/ifq.c,v diff -u -p -r1.56 ifq.c --- ifq.c 3 Feb 2025 08:58:52 -0000 1.56 +++ ifq.c 17 Feb 2025 03:49:18 -0000 @@ -479,8 +479,8 @@ ifq_dequeue(struct ifqueue *ifq) int ifq_deq_sleep(struct ifqueue *ifq, struct mbuf **mp, int nbio, int priority, - const char *wmesg, volatile unsigned int *sleeping, - volatile unsigned int *alive) + const char *wmesg, unsigned int * volatile sleeping, + unsigned int * volatile dead) { struct mbuf *m; void *cookie; @@ -505,7 +505,7 @@ ifq_deq_sleep(struct ifqueue *ifq, struc (*sleeping)--; if (error != 0) break; - if (!(*alive)) { + if (*dead) { error = EIO; break; } Index: ifq.h =================================================================== RCS file: /cvs/src/sys/net/ifq.h,v diff -u -p -r1.43 ifq.h --- ifq.h 3 Feb 2025 08:58:52 -0000 1.43 +++ ifq.h 17 Feb 2025 03:49:18 -0000 @@ -447,8 +447,8 @@ void ifq_set_oactive(struct ifqueue *) void ifq_deq_set_oactive(struct ifqueue *); int ifq_deq_sleep(struct ifqueue *, struct mbuf **, int, int, - const char *, volatile unsigned int *, - volatile unsigned int *); + const char *, unsigned int * volatile, + unsigned int * volatile); #define ifq_len(_ifq) READ_ONCE((_ifq)->ifq_len) #define ifq_empty(_ifq) (ifq_len(_ifq) == 0)