diff options
Diffstat (limited to 'freebsd/sys/net/if_ipsec.c')
-rw-r--r-- | freebsd/sys/net/if_ipsec.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/freebsd/sys/net/if_ipsec.c b/freebsd/sys/net/if_ipsec.c index 08465911..7cc2c961 100644 --- a/freebsd/sys/net/if_ipsec.c +++ b/freebsd/sys/net/if_ipsec.c @@ -220,6 +220,12 @@ ipsec_clone_destroy(struct ifnet *ifp) sx_xlock(&ipsec_ioctl_sx); sc = ifp->if_softc; ipsec_delete_tunnel(sc); + /* + * Delete softc from idhash on interface destroy, since + * ipsec_delete_tunnel() keeps reqid unchanged. + */ + if (sc->reqid != 0) + CK_LIST_REMOVE(sc, idhash); bpfdetach(ifp); if_detach(ifp); ifp->if_softc = NULL; @@ -273,6 +279,13 @@ vnet_ipsec_uninit(const void *unused __unused) if_clone_detach(V_ipsec_cloner); free(V_ipsec_idhtbl, M_IPSEC); + /* + * Use V_ipsec_idhtbl pointer as indicator that VNET is going to be + * destroyed, it is used by ipsec_srcaddr() callback. + */ + V_ipsec_idhtbl = NULL; + IPSEC_WAIT(); + #ifdef INET if (IS_DEFAULT_VNET(curvnet)) ip_encap_unregister_srcaddr(ipsec4_srctab); @@ -785,6 +798,10 @@ ipsec_srcaddr(void *arg __unused, const struct sockaddr *sa, struct ipsec_softc *sc; struct secasindex *saidx; + /* Check that VNET is ready */ + if (V_ipsec_idhtbl == NULL) + return; + MPASS(in_epoch(net_epoch_preempt)); CK_LIST_FOREACH(sc, ipsec_srchash(sa), srchash) { if (sc->family == 0) @@ -1031,13 +1048,11 @@ ipsec_delete_tunnel(struct ipsec_softc *sc) sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; if (sc->family != 0) { CK_LIST_REMOVE(sc, srchash); - IPSEC_WAIT(); - + sc->family = 0; /* * Make sure that ipsec_if_input() will not do access * to softc's policies. */ - sc->family = 0; IPSEC_WAIT(); key_unregister_ifnet(sc->sp, IPSEC_SPCOUNT); |