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