diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2019-02-20 00:20:20 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2019-02-20 00:20:20 +0000 |
commit | 3048ca3d80a80b570b62f71ac06eff96ff6d863e (patch) | |
tree | 8f3e33e9983963f694dfac8978da044e594ca2ca /sys/net | |
parent | 1d5c70fd50fe1f8fb4124b859f6e0112a477e89e (diff) |
add the locking for coordinating between ioctls and a clone destroy.
i wrote this in mpe before porting and committing it in mpw, but
forgot to commit the mpe version.
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_mpe.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/sys/net/if_mpe.c b/sys/net/if_mpe.c index e4ebe1665a9..ce1d4301b23 100644 --- a/sys/net/if_mpe.c +++ b/sys/net/if_mpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mpe.c,v 1.84 2019/02/14 03:27:42 dlg Exp $ */ +/* $OpenBSD: if_mpe.c,v 1.85 2019/02/20 00:20:19 dlg Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -58,6 +58,9 @@ struct mpe_softc { unsigned int sc_rdomain; struct ifaddr sc_ifa; struct sockaddr_mpls sc_smpls; + + struct rwlock sc_lock; + int sc_dead; }; #define MPE_HDRLEN sizeof(struct shim_hdr) @@ -110,6 +113,10 @@ mpe_clone_create(struct if_clone *ifc, int unit) ifp->if_type = IFT_MPLS; ifp->if_hdrlen = MPE_HDRLEN; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + + rw_init(&sc->sc_lock, ifp->if_xname); + sc->sc_dead = 0; + if_attach(ifp); if_alloc_sadl(ifp); #if NBPFILTER > 0 @@ -130,11 +137,16 @@ mpe_clone_destroy(struct ifnet *ifp) { struct mpe_softc *sc = ifp->if_softc; + rw_enter_write(&sc->sc_lock); + sc->sc_dead = 1; + if (sc->sc_smpls.smpls_label) { rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL, smplstosa(&sc->sc_smpls), sc->sc_rdomain); } + rw_exit_write(&sc->sc_lock); + if_detach(ifp); free(sc, M_DEVBUF, sizeof *sc); return (0); @@ -281,6 +293,10 @@ mpe_set_label(struct mpe_softc *sc, uint32_t label, unsigned int rdomain) { int error; + rw_assert_wrlock(&sc->sc_lock); + if (sc->sc_dead) + return (ENXIO); + if (sc->sc_smpls.smpls_label) { /* remove old MPLS route */ rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL, @@ -337,9 +353,12 @@ mpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } shim.shim_label = MPLS_LABEL2SHIM(shim.shim_label); - if (sc->sc_smpls.smpls_label == shim.shim_label) - break; - error = mpe_set_label(sc, shim.shim_label, sc->sc_rdomain); + rw_enter_write(&sc->sc_lock); + if (sc->sc_smpls.smpls_label != shim.shim_label) { + error = mpe_set_label(sc, shim.shim_label, + sc->sc_rdomain); + } + rw_exit_write(&sc->sc_lock); break; case SIOCSLIFPHYRTABLE: if (ifr->ifr_rdomainid < 0 || @@ -349,11 +368,12 @@ mpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = EINVAL; break; } - if (sc->sc_rdomain == ifr->ifr_rdomainid) - break; - - error = mpe_set_label(sc, sc->sc_smpls.smpls_label, - ifr->ifr_rdomainid); + rw_enter_write(&sc->sc_lock); + if (sc->sc_rdomain != ifr->ifr_rdomainid) { + error = mpe_set_label(sc, sc->sc_smpls.smpls_label, + ifr->ifr_rdomainid); + } + rw_exit_write(&sc->sc_lock); break; case SIOCGLIFPHYRTABLE: ifr->ifr_rdomainid = sc->sc_rdomain; |