diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c --- a/sys/net/if_ovpn.c +++ b/sys/net/if_ovpn.c @@ -390,15 +390,11 @@ has_peers = ovpn_has_peers(sc); - /* Only remove the tunnel function if we're releasing the socket for - * the last peer. */ - if (! has_peers) - (void)udp_set_kernel_tunneling(sc->so, NULL, NULL, NULL); - - sorele(sc->so); - - if (! has_peers) - sc->so = NULL; + if (! has_peers) { + MPASS(sc->peercount == 0); + } else { + MPASS(sc->peercount > 0); + } } static void @@ -628,26 +624,23 @@ if (sc->so != NULL && so != sc->so) goto error_locked; - if (sc->so == NULL) + if (sc->so == NULL) { sc->so = so; + /* + * Maintain one extra ref so the socket doesn't go away until + * we're destroying the ifp. + */ + soref(sc->so); + } /* Insert the peer into the list. */ RB_INSERT(ovpn_kpeers, &sc->peers, peer); sc->peercount++; - soref(sc->so); - - ret = udp_set_kernel_tunneling(sc->so, ovpn_udp_input, NULL, sc); - if (ret == EBUSY) { - /* Fine, another peer already set the input function. */ - ret = 0; - } - if (ret != 0) { - RB_REMOVE(ovpn_kpeers, &sc->peers, peer); - sc->peercount--; - goto error_locked; - } OVPN_WUNLOCK(sc); + ret = udp_set_kernel_tunneling(sc->so, ovpn_udp_input, NULL, sc); + MPASS(ret == 0 || ret == EBUSY); + ret = 0; goto done; @@ -2493,12 +2486,21 @@ ovpn_clone_destroy_cb(struct epoch_context *ctx) { struct ovpn_softc *sc; + int ret __diagused; sc = __containerof(ctx, struct ovpn_softc, epoch_ctx); MPASS(sc->peercount == 0); MPASS(RB_EMPTY(&sc->peers)); + if (sc->so != NULL) { + CURVNET_SET(sc->ifp->if_vnet); + ret = udp_set_kernel_tunneling(sc->so, NULL, NULL, NULL); + MPASS(ret == 0); + sorele(sc->so); + CURVNET_RESTORE(); + } + COUNTER_ARRAY_FREE(sc->counters, OVPN_COUNTER_SIZE); if_free(sc->ifp);