summaryrefslogtreecommitdiff
path: root/sys/net/if_mpe.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2019-02-20 00:20:20 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2019-02-20 00:20:20 +0000
commit3048ca3d80a80b570b62f71ac06eff96ff6d863e (patch)
tree8f3e33e9983963f694dfac8978da044e594ca2ca /sys/net/if_mpe.c
parent1d5c70fd50fe1f8fb4124b859f6e0112a477e89e (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/if_mpe.c')
-rw-r--r--sys/net/if_mpe.c38
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;