Index: if_tun.c =================================================================== RCS file: /cvs/src/sys/net/if_tun.c,v retrieving revision 1.231 diff -u -p -r1.231 if_tun.c --- if_tun.c 9 Mar 2021 20:05:14 -0000 1.231 +++ if_tun.c 15 Feb 2022 03:17:56 -0000 @@ -130,7 +130,7 @@ int filt_tunread(struct knote *, long); int filt_tunwrite(struct knote *, long); void filt_tunrdetach(struct knote *); void filt_tunwdetach(struct knote *); -void tun_link_state(struct tun_softc *, int); +void tun_link_state(struct ifnet *, int); const struct filterops tunread_filtops = { .f_flags = FILTEROP_ISFD, @@ -218,6 +218,8 @@ 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); + ifp = &sc->sc_if; snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", ifc->ifc_name, unit); @@ -267,7 +269,6 @@ tun_create(struct if_clone *ifc, int uni } sigio_init(&sc->sc_sigio); - refcnt_init(&sc->sc_refs); /* tell tun_dev_open we're initialised */ @@ -381,7 +382,7 @@ tun_dev_open(dev_t dev, const struct if_ rdomain = rtable_l2(p->p_p->ps_rtableid); /* let's find or make an interface to work with */ - while ((ifp = if_unit(name)) == NULL) { + while ((sc = tun_name_lookup(name)) == NULL) { error = if_clone_create(name, rdomain); switch (error) { case 0: /* it's probably ours */ @@ -394,32 +395,45 @@ tun_dev_open(dev_t dev, const struct if_ } } - sc = ifp->if_softc; + refcnt_take(&sc->sc_refs); + /* wait for it to be fully constructed before we use it */ - while (!ISSET(sc->sc_flags, TUN_INITED)) { + for (;;) { + if (ISSET(sc->sc_flags, TUN_DEAD)) { + error = ENXIO; + goto done; + } + + if (ISSET(sc->sc_flags, TUN_INITED)) + break; + error = tsleep_nsec(sc, PCATCH, "tuninit", INFSLP); if (error != 0) { /* XXX if_clone_destroy if stayup? */ - if_put(ifp); - return (error); + goto done; } } if (sc->sc_dev != 0) { /* aww, we lost */ - if_put(ifp); - return (EBUSY); + error = EBUSY; + goto done; } /* it's ours now */ sc->sc_dev = dev; CLR(sc->sc_flags, stayup); /* automatically mark the interface running on open */ + ifp = &sc->sc_if; + NET_LOCK(); SET(ifp->if_flags, IFF_UP | IFF_RUNNING); - if_put(ifp); - tun_link_state(sc, LINK_STATE_FULL_DUPLEX); + NET_UNLOCK(); + tun_link_state(ifp, LINK_STATE_FULL_DUPLEX); + error = 0; - return (0); +done: + tun_put(sc); + return (error); } /* @@ -456,7 +470,9 @@ tun_dev_close(dev_t dev, struct proc *p) /* * junk all pending output */ + NET_LOCK(); CLR(ifp->if_flags, IFF_UP | IFF_RUNNING); + NET_UNLOCK(); ifq_purge(&ifp->if_snd); CLR(sc->sc_flags, TUN_ASYNC); @@ -469,8 +485,7 @@ tun_dev_close(dev_t dev, struct proc *p) destroy = 1; strlcpy(name, ifp->if_xname, sizeof(name)); } else { - CLR(ifp->if_flags, IFF_UP | IFF_RUNNING); - tun_link_state(sc, LINK_STATE_DOWN); + tun_link_state(ifp, LINK_STATE_DOWN); } } @@ -1066,10 +1081,8 @@ tun_start(struct ifnet *ifp) } void -tun_link_state(struct tun_softc *sc, int link_state) +tun_link_state(struct ifnet *ifp, int link_state) { - struct ifnet *ifp = &sc->sc_if; - if (ifp->if_link_state != link_state) { ifp->if_link_state = link_state; if_link_state_change(ifp);