diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 43bf0f4e3d1d..110210cd6b83 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -98,29 +98,6 @@ struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
     gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
 
 static int gifmodevent(module_t, int, void *);
-void gif_delete_tunnel(struct gif_softc *);
-static int gif_encapcheck(const struct mbuf *, int, int, void *);
-
-#ifdef INET
-extern  struct domain inetdomain;
-struct protosw in_gif_protosw =
-{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
-  in_gif_input,	(pr_output_t*)rip_output, 0,		rip_ctloutput,
-  0,
-  0,		0,		0,		0,
-  &rip_usrreqs
-};
-#endif
-#ifdef INET6
-extern  struct domain inet6domain;
-struct ip6protosw in6_gif_protosw =
-{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
-  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
-  0,
-  0,		0,		0,		0,
-  &rip6_usrreqs
-};
-#endif
 
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
@@ -167,30 +144,20 @@ gif_clone_create(ifc, unit)
 	sc->gif_if.if_name = GIFNAME;
 	sc->gif_if.if_unit = unit;
 
-	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
-#ifdef INET
-	sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
-	    gif_encapcheck, (struct protosw*)&in_gif_protosw, sc);
-	if (sc->encap_cookie4 == NULL) {
-		printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
-		free(sc, M_GIF);
-		return (EIO);	/* XXX */
-	}
-#endif
-#ifdef INET6
-	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
-	    gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
-	if (sc->encap_cookie6 == NULL) {
-		if (sc->encap_cookie4) {
-			encap_detach(sc->encap_cookie4);
-			sc->encap_cookie4 = NULL;
-		}
-		printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
-		free(sc, M_GIF);
-		return (EIO);	/* XXX */
-	}
-#endif
+	gifattach0(sc);
 
+	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
+	return (0);
+}
+
+void
+gifattach0(sc)
+	struct gif_softc *sc;
+{
+
+	sc->encap_cookie4 = sc->encap_cookie6 = NULL;
+
+	sc->gif_if.if_addrlen = 0;
 	sc->gif_if.if_mtu    = GIF_MTU;
 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
 #if 0
@@ -205,8 +172,6 @@ gif_clone_create(ifc, unit)
 	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
 	if (ng_gif_attach_p != NULL)
 		(*ng_gif_attach_p)(&sc->gif_if);
-	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_link);
-	return (0);
 }
 
 void
@@ -216,16 +181,20 @@ gif_clone_destroy(ifp)
 	int err;
 	struct gif_softc *sc = ifp->if_softc;
 
-	gif_delete_tunnel(sc);
-	LIST_REMOVE(sc, gif_link);
-	if (sc->encap_cookie4 != NULL) {
-		err = encap_detach(sc->encap_cookie4);
-		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
-	}
+	gif_delete_tunnel(&sc->gif_if);
+	LIST_REMOVE(sc, gif_list);
+#ifdef INET6
 	if (sc->encap_cookie6 != NULL) {
 		err = encap_detach(sc->encap_cookie6);
 		KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
 	}
+#endif
+#ifdef INET
+	if (sc->encap_cookie4 != NULL) {
+		err = encap_detach(sc->encap_cookie4);
+		KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
+	}
+#endif
 
 	if (ng_gif_detach_p != NULL)
 		(*ng_gif_detach_p)(ifp);
@@ -275,7 +244,7 @@ static moduledata_t gif_mod = {
 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
 MODULE_VERSION(if_gif, 1);
 
-static int
+int
 gif_encapcheck(m, off, proto, arg)
 	const struct mbuf *m;
 	int off;
@@ -321,6 +290,8 @@ gif_encapcheck(m, off, proto, arg)
 #endif
 #ifdef INET6
 	case 6:
+		if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
+			return 0;
 		if (sc->gif_psrc->sa_family != AF_INET6 ||
 		    sc->gif_pdst->sa_family != AF_INET6)
 			return 0;
@@ -520,12 +491,10 @@ gif_ioctl(ifp, cmd, data)
 	struct ifreq     *ifr = (struct ifreq*)data;
 	int error = 0, size;
 	struct sockaddr *dst, *src;
-	struct sockaddr *sa;
-	struct ifnet *ifp2;
-	struct gif_softc *sc2;
 		
 	switch (cmd) {
 	case SIOCSIFADDR:
+		ifp->if_flags |= IFF_UP;
 		break;
 		
 	case SIOCSIFDSTADDR:
@@ -578,9 +547,9 @@ gif_ioctl(ifp, cmd, data)
 				&(((struct if_laddrreq *)data)->addr);
 			dst = (struct sockaddr *)
 				&(((struct if_laddrreq *)data)->dstaddr);
+			break;
 		default:
-			error = EADDRNOTAVAIL;
-			goto bad;
+			return EINVAL;
 		}
 
 		/* sa_family must be equal */
@@ -638,80 +607,12 @@ gif_ioctl(ifp, cmd, data)
 			break;
 		}
 
-		TAILQ_FOREACH(ifp2, &ifnet, if_link) {
-			if (strcmp(ifp2->if_name, GIFNAME) != 0)
-				continue;
-			sc2 = ifp2->if_softc;
-			if (sc2 == sc)
-				continue;
-			if (!sc2->gif_pdst || !sc2->gif_psrc)
-				continue;
-			if (sc2->gif_pdst->sa_family != dst->sa_family ||
-			    sc2->gif_pdst->sa_len != dst->sa_len ||
-			    sc2->gif_psrc->sa_family != src->sa_family ||
-			    sc2->gif_psrc->sa_len != src->sa_len)
-				continue;
-
-			/*
-			 * Disallow parallel tunnels unless instructed
-			 * otherwise.
-			 */
-			if (!parallel_tunnels &&
-			    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
-			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
-				error = EADDRNOTAVAIL;
-				goto bad;
-			}
-
-			/* can't configure multiple multi-dest interfaces */
-#define multidest(x) \
-	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
-#ifdef INET6
-#define multidest6(x) \
-	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
-#endif
-			if (dst->sa_family == AF_INET &&
-			    multidest(dst) && multidest(sc2->gif_pdst)) {
-				error = EADDRNOTAVAIL;
-				goto bad;
-			}
-#ifdef INET6
-			if (dst->sa_family == AF_INET6 &&
-			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
-				error = EADDRNOTAVAIL;
-				goto bad;
-			}
-#endif
-		}
-
-		if (sc->gif_psrc)
-			free((caddr_t)sc->gif_psrc, M_IFADDR);
-		sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
-		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
-		sc->gif_psrc = sa;
-
-		if (sc->gif_pdst)
-			free((caddr_t)sc->gif_pdst, M_IFADDR);
-		sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
-		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
-		sc->gif_pdst = sa;
-
-		ifp->if_flags |= IFF_RUNNING;
-
-		error = 0;
+		error = gif_set_tunnel(&sc->gif_if, src, dst);
 		break;
 
 #ifdef SIOCDIFPHYADDR
 	case SIOCDIFPHYADDR:
-		if (sc->gif_psrc) {
-			free((caddr_t)sc->gif_psrc, M_IFADDR);
-			sc->gif_psrc = NULL;
-		}
-		if (sc->gif_pdst) {
-			free((caddr_t)sc->gif_pdst, M_IFADDR);
-			sc->gif_pdst = NULL;
-		}
-		/* change the IFF_{UP, RUNNING} flag as well? */
+		gif_delete_tunnel(&sc->gif_if);
 		break;
 #endif
 			
@@ -816,11 +717,122 @@ gif_ioctl(ifp, cmd, data)
 	return error;
 }
 
-void
-gif_delete_tunnel(sc)
-	struct gif_softc *sc;
+int
+gif_set_tunnel(ifp, src, dst)
+	struct ifnet *ifp;
+	struct sockaddr *src;
+	struct sockaddr *dst;
 {
-	/* XXX: NetBSD protects this function with splsoftnet() */
+	struct gif_softc *sc = (struct gif_softc *)ifp;
+	struct gif_softc *sc2;
+	struct sockaddr *osrc, *odst, *sa;
+	int s;
+	int error = 0; 
+
+	s = splnet();
+
+	LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
+		if (sc2 == sc)
+			continue;
+		if (!sc2->gif_pdst || !sc2->gif_psrc)
+			continue;
+		if (sc2->gif_pdst->sa_family != dst->sa_family ||
+		    sc2->gif_pdst->sa_len != dst->sa_len ||
+		    sc2->gif_psrc->sa_family != src->sa_family ||
+		    sc2->gif_psrc->sa_len != src->sa_len)
+			continue;
+
+		/*
+		 * Disallow parallel tunnels unless instructed
+		 * otherwise.
+		 */
+		if (!parallel_tunnels &&
+		    bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
+		    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
+			error = EADDRNOTAVAIL;
+			goto bad;
+		}
+
+		/* XXX both end must be valid? (I mean, not 0.0.0.0) */
+	}
+
+	/* XXX we can detach from both, but be polite just in case */
+	if (sc->gif_psrc)
+		switch (sc->gif_psrc->sa_family) {
+#ifdef INET
+		case AF_INET:
+			(void)in_gif_detach(sc);
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			(void)in6_gif_detach(sc);
+			break;
+#endif
+		}
+
+	osrc = sc->gif_psrc;
+	sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
+	bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
+	sc->gif_psrc = sa;
+
+	odst = sc->gif_pdst;
+	sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
+	bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
+	sc->gif_pdst = sa;
+
+	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
+	}
+	if (error) {
+		/* rollback */
+		free((caddr_t)sc->gif_psrc, M_IFADDR);
+		free((caddr_t)sc->gif_pdst, M_IFADDR);
+		sc->gif_psrc = osrc;
+		sc->gif_pdst = odst;
+		goto bad;
+	}
+
+	if (osrc)
+		free((caddr_t)osrc, M_IFADDR);
+	if (odst)
+		free((caddr_t)odst, M_IFADDR);
+
+	if (sc->gif_psrc && sc->gif_pdst)
+		ifp->if_flags |= IFF_RUNNING;
+	else
+		ifp->if_flags &= ~IFF_RUNNING;
+	splx(s);
+
+	return 0;
+
+ bad:
+	if (sc->gif_psrc && sc->gif_pdst)
+		ifp->if_flags |= IFF_RUNNING;
+	else
+		ifp->if_flags &= ~IFF_RUNNING;
+	splx(s);
+
+	return error;
+}
+
+void
+gif_delete_tunnel(ifp)
+	struct ifnet *ifp;
+{
+	struct gif_softc *sc = (struct gif_softc *)ifp;
+	int s;
+
+	s = splnet();
 
 	if (sc->gif_psrc) {
 		free((caddr_t)sc->gif_psrc, M_IFADDR);
@@ -830,5 +842,17 @@ gif_delete_tunnel(sc)
 		free((caddr_t)sc->gif_pdst, M_IFADDR);
 		sc->gif_pdst = NULL;
 	}
-	/* change the IFF_UP flag as well? */
+	/* it is safe to detach from both */
+#ifdef INET
+	(void)in_gif_detach(sc);
+#endif
+#ifdef INET6
+	(void)in6_gif_detach(sc);
+#endif
+
+	if (sc->gif_psrc && sc->gif_pdst)
+		ifp->if_flags |= IFF_RUNNING;
+	else
+		ifp->if_flags &= ~IFF_RUNNING;
+	splx(s);
 }
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index 1d02348e0bf0..8a0ac564256f 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -69,7 +69,7 @@ struct gif_softc {
 	const struct encaptab *encap_cookie4;
 	const struct encaptab *encap_cookie6;
 	void		*gif_netgraph;	/* ng_gif(4) netgraph node info */
-	LIST_ENTRY(gif_softc) gif_link; /* all gif's are linked */
+	LIST_ENTRY(gif_softc) gif_list; /* all gif's are linked */
 };
 
 #define gif_ro gifsc_gifscr.gifscr_ro
@@ -82,10 +82,14 @@ struct gif_softc {
 #define	GIF_MTU_MAX	(8192)	/* Maximum MTU */
 
 /* Prototypes */
+void gifattach0(struct gif_softc *);
 void gif_input(struct mbuf *, int, struct ifnet *);
 int gif_output(struct ifnet *, struct mbuf *, struct sockaddr *,
 	       struct rtentry *);
 int gif_ioctl(struct ifnet *, u_long, caddr_t);
+int gif_set_tunnel(struct ifnet *, struct sockaddr *, struct sockaddr *);
+void gif_delete_tunnel(struct ifnet *);
+int gif_encapcheck(const struct mbuf *, int, int, void *);
 
 #endif /* _KERNEL */
 
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index ffd877b04d63..d6508d5a0385 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -42,6 +42,7 @@
 #include <sys/errno.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
+#include <sys/protosw.h>
 
 #include <sys/malloc.h>
 
@@ -69,6 +70,18 @@
 
 #include <net/net_osdep.h>
 
+static int gif_validate4(const struct ip *, struct gif_softc *,
+	struct ifnet *);
+
+extern  struct domain inetdomain;
+struct protosw in_gif_protosw =
+{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
+  in_gif_input,	(pr_output_t*)rip_output, 0,		rip_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip_usrreqs
+};
+
 static int ip_gif_ttl = GIF_TTL;
 SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
 	&ip_gif_ttl,	0, "");
@@ -277,43 +290,29 @@ in_gif_input(m, off)
 }
 
 /*
- * we know that we are in IFF_UP, outer address available, and outer family
- * matched the physical addr family.  see gif_encapcheck().
+ * validate outer address.
  */
-int
-gif_encapcheck4(m, off, proto, arg)
-	const struct mbuf *m;
-	int off;
-	int proto;
-	void *arg;
-{
-	struct ip ip;
+static int
+gif_validate4(ip, sc, ifp)
+	const struct ip *ip;
 	struct gif_softc *sc;
+	struct ifnet *ifp;
+{
 	struct sockaddr_in *src, *dst;
-	int addrmatch;
 	struct in_ifaddr *ia4;
 
-	/* sanity check done in caller */
-	sc = (struct gif_softc *)arg;
 	src = (struct sockaddr_in *)sc->gif_psrc;
 	dst = (struct sockaddr_in *)sc->gif_pdst;
 
-	/* LINTED const cast */
-	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
-
 	/* check for address match */
-	addrmatch = 0;
-	if (src->sin_addr.s_addr == ip.ip_dst.s_addr)
-		addrmatch |= 1;
-	if (dst->sin_addr.s_addr == ip.ip_src.s_addr)
-		addrmatch |= 2;
-	if (addrmatch != 3)
+	if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
+	    dst->sin_addr.s_addr != ip->ip_src.s_addr)
 		return 0;
 
 	/* martian filters on outer source - NOT done in ip_input! */
-	if (IN_MULTICAST(ntohl(ip.ip_src.s_addr)))
+	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
 		return 0;
-	switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) {
+	switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
 	case 0: case 127: case 255:
 		return 0;
 	}
@@ -322,22 +321,21 @@ gif_encapcheck4(m, off, proto, arg)
 	{
 		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
 			continue;
-		if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
+		if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
 			return 0;
 	}
 
 	/* ingress filters on outer source */
-	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
-	    (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
+	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
 		struct sockaddr_in sin;
 		struct rtentry *rt;
 
 		bzero(&sin, sizeof(sin));
 		sin.sin_family = AF_INET;
 		sin.sin_len = sizeof(struct sockaddr_in);
-		sin.sin_addr = ip.ip_src;
+		sin.sin_addr = ip->ip_src;
 		rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
-		if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
+		if (!rt || rt->rt_ifp != ifp) {
 #if 0
 			log(LOG_WARNING, "%s: packet from 0x%x dropped "
 			    "due to ingress filter\n", if_name(&sc->gif_if),
@@ -352,3 +350,65 @@ gif_encapcheck4(m, off, proto, arg)
 
 	return 32 * 2;
 }
+
+/*
+ * we know that we are in IFF_UP, outer address available, and outer family
+ * matched the physical addr family.  see gif_encapcheck().
+ */
+int
+gif_encapcheck4(m, off, proto, arg)
+	const struct mbuf *m;
+	int off;
+	int proto;
+	void *arg;
+{
+	struct ip ip;
+	struct gif_softc *sc;
+	struct ifnet *ifp;
+
+	/* sanity check done in caller */
+	sc = (struct gif_softc *)arg;
+
+	/* LINTED const cast */
+	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
+	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
+
+	return gif_validate4(&ip, sc, ifp);
+}
+
+int
+in_gif_attach(sc)
+	struct gif_softc *sc;
+{
+#ifndef USE_ENCAPCHECK
+	struct sockaddr_in mask4;
+
+	bzero(&mask4, sizeof(mask4));
+	mask4.sin_len = sizeof(struct sockaddr_in);
+	mask4.sin_addr.s_addr = ~0;
+
+	if (!sc->gif_psrc || !sc->gif_pdst)
+		return EINVAL;
+	sc->encap_cookie4 = encap_attach(AF_INET, -1, sc->gif_psrc,
+	    (struct sockaddr *)&mask4, sc->gif_pdst, (struct sockaddr *)&mask4,
+	    (struct protosw *)&in_gif_protosw, sc);
+#else
+	sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
+	    &in_gif_protosw, sc);
+#endif
+	if (sc->encap_cookie4 == NULL)
+		return EEXIST;
+	return 0;
+}
+
+int
+in_gif_detach(sc)
+	struct gif_softc *sc;
+{
+	int error;
+
+	error = encap_detach(sc->encap_cookie4);
+	if (error == 0)
+		sc->encap_cookie4 = NULL;
+	return error;
+}
diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h
index 262d9bad396b..8197d2966c0c 100644
--- a/sys/netinet/in_gif.h
+++ b/sys/netinet/in_gif.h
@@ -35,8 +35,11 @@
 
 #define GIF_TTL		30
 
+struct gif_softc;
 void in_gif_input(struct mbuf *, int off);
 int in_gif_output(struct ifnet *, int, struct mbuf *, struct rtentry *);
 int gif_encapcheck4(const struct mbuf *, int, int, void *);
+int in_gif_attach(struct gif_softc *);
+int in_gif_detach(struct gif_softc *);
 
 #endif /*_NETINET_IN_GIF_H_*/
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 6d48afdaf01f..83a2fe6263d1 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -41,6 +41,7 @@
 #include <sys/errno.h>
 #include <sys/queue.h>
 #include <sys/syslog.h>
+#include <sys/protosw.h>
 
 #include <sys/malloc.h>
 
@@ -59,6 +60,7 @@
 #include <netinet6/in6_gif.h>
 #include <netinet6/in6_var.h>
 #endif
+#include <netinet6/ip6protosw.h>
 #include <netinet/ip_ecn.h>
 #ifdef INET6
 #include <netinet6/ip6_ecn.h>
@@ -68,6 +70,18 @@
 
 #include <net/net_osdep.h>
 
+static int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
+			 struct ifnet *);
+
+extern  struct domain inet6domain;
+struct ip6protosw in6_gif_protosw =
+{ SOCK_RAW,	&inet6domain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
+  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
+  0,
+  0,		0,		0,		0,
+  &rip6_usrreqs
+};
+
 int
 in6_gif_output(ifp, family, m, rt)
 	struct ifnet *ifp;
@@ -281,52 +295,45 @@ int in6_gif_input(mp, offp, proto)
 }
 
 /*
- * we know that we are in IFF_UP, outer address available, and outer family
- * matched the physical addr family.  see gif_encapcheck().
+ * validate outer address.
  */
-int
-gif_encapcheck6(m, off, proto, arg)
-	const struct mbuf *m;
-	int off;
-	int proto;
-	void *arg;
-{
-	struct ip6_hdr ip6;
+static int
+gif_validate6(ip6, sc, ifp)
+	const struct ip6_hdr *ip6;
 	struct gif_softc *sc;
+	struct ifnet *ifp;
+{
 	struct sockaddr_in6 *src, *dst;
-	int addrmatch;
 
-	/* sanity check done in caller */
-	sc = (struct gif_softc *)arg;
 	src = (struct sockaddr_in6 *)sc->gif_psrc;
 	dst = (struct sockaddr_in6 *)sc->gif_pdst;
 
-	m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
-
-	/* check for address match */
-	addrmatch = 0;
-	if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst))
-		addrmatch |= 1;
-	if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src))
-		addrmatch |= 2;
-	if (addrmatch != 3)
+	/*
+	 * Check for address match.  Note that the check is for an incoming
+	 * packet.  We should compare the *source* address in our configuration
+	 * and the *destination* address of the packet, and vice versa.
+	 */
+	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
+	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
 		return 0;
 
 	/* martian filters on outer source - done in ip6_input */
 
 	/* ingress filters on outer source */
-	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
-	    (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
+	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
 		struct sockaddr_in6 sin6;
 		struct rtentry *rt;
 
 		bzero(&sin6, sizeof(sin6));
 		sin6.sin6_family = AF_INET6;
 		sin6.sin6_len = sizeof(struct sockaddr_in6);
-		sin6.sin6_addr = ip6.ip6_src;
-		/* XXX scopeid */
+		sin6.sin6_addr = ip6->ip6_src;
+#ifndef SCOPEDROUTING
+		sin6.sin6_scope_id = 0; /* XXX */
+#endif
+
 		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
-		if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
+		if (!rt || rt->rt_ifp != ifp) {
 #if 0
 			log(LOG_WARNING, "%s: packet from %s dropped "
 			    "due to ingress filter\n", if_name(&sc->gif_if),
@@ -341,3 +348,68 @@ gif_encapcheck6(m, off, proto, arg)
 
 	return 128 * 2;
 }
+
+/*
+ * we know that we are in IFF_UP, outer address available, and outer family
+ * matched the physical addr family.  see gif_encapcheck().
+ * sanity check for arg should have been done in the caller.
+ */
+int
+gif_encapcheck6(m, off, proto, arg)
+	const struct mbuf *m;
+	int off;
+	int proto;
+	void *arg;
+{
+	struct ip6_hdr ip6;
+	struct gif_softc *sc;
+	struct ifnet *ifp;
+
+	/* sanity check done in caller */
+	sc = (struct gif_softc *)arg;
+
+	/* LINTED const cast */
+	m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
+	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
+
+	return gif_validate6(&ip6, sc, ifp);
+}
+
+int
+in6_gif_attach(sc)
+	struct gif_softc *sc;
+{
+#ifndef USE_ENCAPCHECK
+	struct sockaddr_in6 mask6;
+
+	bzero(&mask6, sizeof(mask6));
+	mask6.sin6_len = sizeof(struct sockaddr_in6);
+	mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
+	    mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
+	mask6.sin6_scope_id = ~0;
+
+	if (!sc->gif_psrc || !sc->gif_pdst)
+		return EINVAL;
+	sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,
+	    (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,
+	    (struct protosw *)&in6_gif_protosw, sc);
+#else
+	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
+	    (struct protosw *)&in6_gif_protosw, sc);
+#endif
+	if (sc->encap_cookie6 == NULL)
+		return EEXIST;
+	return 0;
+}
+
+int
+in6_gif_detach(sc)
+	struct gif_softc *sc;
+{
+	int error;
+
+	error = encap_detach(sc->encap_cookie6);
+	if (error == 0)
+		sc->encap_cookie6 = NULL;
+	return error;
+}
diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h
index b1fe10484bf5..12884a28d3c1 100644
--- a/sys/netinet6/in6_gif.h
+++ b/sys/netinet6/in6_gif.h
@@ -35,8 +35,11 @@
 
 #define GIF_HLIM	30
 
+struct gif_softc;
 int in6_gif_input __P((struct mbuf **, int *, int));
 int in6_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *));
 int gif_encapcheck6 __P((const struct mbuf *, int, int, void *));
+int in6_gif_attach __P((struct gif_softc *));
+int in6_gif_detach __P((struct gif_softc *));
 
 #endif /*_NETINET6_IN6_GIF_H_*/