Module Name: src Committed By: knakahara Date: Wed Dec 9 03:31:28 UTC 2015
Modified Files: src/sys/net: if_gif.c Log Message: Improve gif_set_tunnel() rollback code. To generate a diff of this commit: cvs rdiff -u -r1.95 -r1.96 src/sys/net/if_gif.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_gif.c diff -u src/sys/net/if_gif.c:1.95 src/sys/net/if_gif.c:1.96 --- src/sys/net/if_gif.c:1.95 Fri Dec 4 02:26:11 2015 +++ src/sys/net/if_gif.c Wed Dec 9 03:31:28 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_gif.c,v 1.95 2015/12/04 02:26:11 knakahara Exp $ */ +/* $NetBSD: if_gif.c,v 1.96 2015/12/09 03:31:28 knakahara Exp $ */ /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.95 2015/12/04 02:26:11 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.96 2015/12/09 03:31:28 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -683,6 +683,7 @@ gif_set_tunnel(struct ifnet *ifp, struct struct gif_softc *sc = ifp->if_softc; struct gif_softc *sc2; struct sockaddr *osrc, *odst; + struct sockaddr *nsrc, *ndst; int s; int error; @@ -696,19 +697,29 @@ gif_set_tunnel(struct ifnet *ifp, struct /* can't configure same pair of address onto two gifs */ if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 && sockaddr_cmp(sc2->gif_psrc, src) == 0) { - error = EADDRNOTAVAIL; /* continue to use the old configureation. */ - goto out; + splx(s); + return EADDRNOTAVAIL; } /* XXX both end must be valid? (I mean, not 0.0.0.0) */ } + if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) { + splx(s); + return ENOMEM; + } + if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) { + sockaddr_free(nsrc); + splx(s); + return ENOMEM; + } + + /* Firstly, clear old configurations. */ if (sc->gif_si) { softint_disestablish(sc->gif_si); sc->gif_si = NULL; } - /* XXX we can detach from both, but be polite just in case */ if (sc->gif_psrc) switch (sc->gif_psrc->sa_family) { @@ -724,65 +735,79 @@ gif_set_tunnel(struct ifnet *ifp, struct #endif } - osrc = sc->gif_psrc; - odst = sc->gif_pdst; - sc->gif_psrc = sc->gif_pdst = NULL; - sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc); - if (sc->gif_si == NULL) { - error = ENOMEM; - goto rollback; - } + /* + * Secondly, try to set new configurations. + * If the setup failed, rollback to old configurations. + */ + do { + osrc = sc->gif_psrc; + odst = sc->gif_pdst; + sc->gif_psrc = nsrc; + sc->gif_pdst = ndst; - if ((sc->gif_psrc = sockaddr_dup(src, M_WAITOK)) == NULL) { - error = ENOMEM; - goto rollback; - } + switch (sc->gif_psrc->sa_family) { +#ifdef INET + case AF_INET: + error = in_gif_attach(sc); + break; +#endif +#ifdef INET6 + case AF_INET6: + error = in6_gif_attach(sc); + break; +#endif + default: + error = EINVAL; + break; + } + if (error) { + /* rollback to the last configuration. */ + nsrc = osrc; + ndst = odst; + osrc = sc->gif_psrc; + odst = sc->gif_pdst; - if ((sc->gif_pdst = sockaddr_dup(dst, M_WAITOK)) == NULL) { - error = ENOMEM; - goto rollback; - } + continue; + } - switch (sc->gif_psrc->sa_family) { + sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc); + if (sc->gif_si == NULL) { + switch (sc->gif_psrc->sa_family) { #ifdef INET - case AF_INET: - error = in_gif_attach(sc); - break; + case AF_INET: + (void)in_gif_detach(sc); + break; #endif #ifdef INET6 - case AF_INET6: - error = in6_gif_attach(sc); - break; + case AF_INET6: + (void)in6_gif_detach(sc); + break; #endif - default: - error = EINVAL; - break; + } + + /* rollback to the last configuration. */ + nsrc = osrc; + ndst = odst; + osrc = sc->gif_psrc; + odst = sc->gif_pdst; + + error = ENOMEM; + continue; + } + } while (error != 0 && (nsrc != NULL && ndst != NULL)); + /* Thirdly, even rollback failed, clear configurations. */ + if (error) { + osrc = sc->gif_psrc; + odst = sc->gif_pdst; + sc->gif_psrc = NULL; + sc->gif_pdst = NULL; } - if (error) - goto rollback; if (osrc) sockaddr_free(osrc); if (odst) sockaddr_free(odst); - error = 0; - goto out; - -rollback: - if (sc->gif_psrc != NULL) - sockaddr_free(sc->gif_psrc); - if (sc->gif_pdst != NULL) - sockaddr_free(sc->gif_pdst); - sc->gif_psrc = osrc; - sc->gif_pdst = odst; - - if (sc->gif_si) { - softint_disestablish(sc->gif_si); - sc->gif_si = NULL; - } - -out: if (sc->gif_psrc && sc->gif_pdst) ifp->if_flags |= IFF_RUNNING; else