in6_gif.c revision 240233
1119418Sobrien/*-
265312Smsmith * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
382092Sscottl * All rights reserved.
465312Smsmith *
565312Smsmith * Redistribution and use in source and binary forms, with or without
665312Smsmith * modification, are permitted provided that the following conditions
765312Smsmith * are met:
865312Smsmith * 1. Redistributions of source code must retain the above copyright
965312Smsmith *    notice, this list of conditions and the following disclaimer.
1065312Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1165312Smsmith *    notice, this list of conditions and the following disclaimer in the
1265312Smsmith *    documentation and/or other materials provided with the distribution.
1365312Smsmith * 3. Neither the name of the project nor the names of its contributors
1465312Smsmith *    may be used to endorse or promote products derived from this software
1565312Smsmith *    without specific prior written permission.
1665312Smsmith *
1765312Smsmith * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1865312Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965312Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2065312Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2165312Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2265312Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2365312Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2465312Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25128964Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26128964Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27128964Sscottl * SUCH DAMAGE.
28128964Sscottl *
29128964Sscottl *	$KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $
3096554Sobrien */
3196554Sobrien
3282092Sscottl#include <sys/cdefs.h>
3382092Sscottl__FBSDID("$FreeBSD: head/sys/netinet6/in6_gif.c 240233 2012-09-08 06:41:54Z glebius $");
3496554Sobrien
3596554Sobrien#include "opt_inet.h"
3696554Sobrien#include "opt_inet6.h"
3796554Sobrien
3896554Sobrien#include <sys/param.h>
3996554Sobrien#include <sys/systm.h>
4096554Sobrien#include <sys/socket.h>
4196554Sobrien#include <sys/sockio.h>
4296554Sobrien#include <sys/mbuf.h>
4396554Sobrien#include <sys/errno.h>
4496554Sobrien#include <sys/kernel.h>
4596554Sobrien#include <sys/queue.h>
4696554Sobrien#include <sys/syslog.h>
4796554Sobrien#include <sys/sysctl.h>
4896554Sobrien#include <sys/protosw.h>
4996554Sobrien#include <sys/malloc.h>
5096554Sobrien
5196554Sobrien#include <net/if.h>
5296554Sobrien#include <net/route.h>
5396554Sobrien
5496554Sobrien#include <netinet/in.h>
5596554Sobrien#include <netinet/in_systm.h>
5696554Sobrien#ifdef INET
5796554Sobrien#include <netinet/ip.h>
5896554Sobrien#endif
5996554Sobrien#include <netinet/ip_encap.h>
6096554Sobrien#ifdef INET6
6196554Sobrien#include <netinet/ip6.h>
6296554Sobrien#include <netinet6/ip6_var.h>
6396554Sobrien#include <netinet6/in6_gif.h>
6496554Sobrien#include <netinet6/in6_var.h>
6596554Sobrien#endif
6696554Sobrien#include <netinet6/ip6protosw.h>
6796554Sobrien#include <netinet/ip_ecn.h>
6896554Sobrien#ifdef INET6
6996554Sobrien#include <netinet6/ip6_ecn.h>
7096554Sobrien#endif
7196554Sobrien
7296554Sobrien#include <net/if_gif.h>
7396554Sobrien
7496554SobrienVNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM;
7596554Sobrien#define	V_ip6_gif_hlim			VNET(ip6_gif_hlim)
7696554Sobrien
7796554SobrienSYSCTL_DECL(_net_inet6_ip6);
7896554SobrienSYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_RW,
7996554Sobrien    &VNET_NAME(ip6_gif_hlim), 0, "");
8096554Sobrien
8196554Sobrienstatic int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
8296554Sobrien			 struct ifnet *);
8396554Sobrien
8496554Sobrienextern  struct domain inet6domain;
8596554Sobrienstruct ip6protosw in6_gif_protosw = {
8696554Sobrien	.pr_type =	SOCK_RAW,
8796554Sobrien	.pr_domain =	&inet6domain,
8896554Sobrien	.pr_protocol =	0,			/* IPPROTO_IPV[46] */
8996554Sobrien	.pr_flags =	PR_ATOMIC|PR_ADDR,
9096554Sobrien	.pr_input =	in6_gif_input,
9196554Sobrien	.pr_output =	rip6_output,
9296554Sobrien	.pr_ctloutput =	rip6_ctloutput,
9396554Sobrien	.pr_usrreqs =	&rip6_usrreqs
9496554Sobrien};
9596554Sobrien
9696554Sobrienint
9796554Sobrienin6_gif_output(struct ifnet *ifp,
9896554Sobrien    int family,			/* family of the packet to be encapsulate */
9996554Sobrien    struct mbuf *m)
10096554Sobrien{
10196554Sobrien	struct gif_softc *sc = ifp->if_softc;
10296554Sobrien	struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
10396554Sobrien	struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
10496554Sobrien	struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
10596554Sobrien	struct ip6_hdr *ip6;
10696554Sobrien	struct etherip_header eiphdr;
10796554Sobrien	int error, len, proto;
10896554Sobrien	u_int8_t itos, otos;
10996554Sobrien
11065312Smsmith	GIF_LOCK_ASSERT(sc);
11165312Smsmith
112119418Sobrien	if (sin6_src == NULL || sin6_dst == NULL ||
113128786Sscottl	    sin6_src->sin6_family != AF_INET6 ||
114128786Sscottl	    sin6_dst->sin6_family != AF_INET6) {
115129879Sphk		m_freem(m);
116128786Sscottl		return EAFNOSUPPORT;
117128786Sscottl	}
118128786Sscottl
119128786Sscottl	switch (family) {
120164033Srwatson#ifdef INET
121128786Sscottl	case AF_INET:
122128786Sscottl	    {
123128786Sscottl		struct ip *ip;
124128786Sscottl
125128786Sscottl		proto = IPPROTO_IPV4;
126128786Sscottl		if (m->m_len < sizeof(*ip)) {
127155286Sscottl			m = m_pullup(m, sizeof(*ip));
128128786Sscottl			if (!m)
129128786Sscottl				return ENOBUFS;
130128786Sscottl		}
131128786Sscottl		ip = mtod(m, struct ip *);
132128786Sscottl		itos = ip->ip_tos;
133128786Sscottl		break;
134128786Sscottl	    }
135128786Sscottl#endif
136128786Sscottl#ifdef INET6
137128786Sscottl	case AF_INET6:
138128786Sscottl	    {
139128786Sscottl		struct ip6_hdr *ip6;
140128786Sscottl		proto = IPPROTO_IPV6;
141143729Scognet		if (m->m_len < sizeof(*ip6)) {
142128786Sscottl			m = m_pullup(m, sizeof(*ip6));
143143729Scognet			if (!m)
144143729Scognet				return ENOBUFS;
145143729Scognet		}
146143729Scognet		ip6 = mtod(m, struct ip6_hdr *);
147128786Sscottl		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
148128786Sscottl		break;
149128786Sscottl	    }
150128786Sscottl#endif
151128786Sscottl	case AF_LINK:
152128786Sscottl		proto = IPPROTO_ETHERIP;
153128786Sscottl
154128786Sscottl		/*
155155286Sscottl		 * GIF_SEND_REVETHIP (disabled by default) intentionally
156155286Sscottl		 * sends an EtherIP packet with revered version field in
157155286Sscottl		 * the header.  This is a knob for backward compatibility
158155286Sscottl		 * with FreeBSD 7.2R or prior.
159155286Sscottl		 */
160128786Sscottl		if ((sc->gif_options & GIF_SEND_REVETHIP)) {
161155286Sscottl			eiphdr.eip_ver = 0;
162128786Sscottl			eiphdr.eip_resvl = ETHERIP_VERSION;
163119418Sobrien			eiphdr.eip_resvh = 0;
164119418Sobrien		} else {
16596615Sobrien			eiphdr.eip_ver = ETHERIP_VERSION;
166128964Sscottl			eiphdr.eip_resvl = 0;
167128964Sscottl			eiphdr.eip_resvh = 0;
168128964Sscottl		}
169128964Sscottl		/* prepend Ethernet-in-IP header */
170128964Sscottl		M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
17165312Smsmith		if (m && m->m_len < sizeof(struct etherip_header))
17265312Smsmith			m = m_pullup(m, sizeof(struct etherip_header));
17396554Sobrien		if (m == NULL)
17465312Smsmith			return ENOBUFS;
17565312Smsmith		bcopy(&eiphdr, mtod(m, struct etherip_header *),
176128786Sscottl		    sizeof(struct etherip_header));
177128786Sscottl		break;
178128786Sscottl
179128786Sscottl	default:
180128786Sscottl#ifdef DEBUG
181128786Sscottl		printf("in6_gif_output: warning: unknown family %d passed\n",
182128786Sscottl			family);
183128786Sscottl#endif
184128786Sscottl		m_freem(m);
185128786Sscottl		return EAFNOSUPPORT;
18696554Sobrien	}
187128786Sscottl
18865312Smsmith	/* prepend new IP header */
18965312Smsmith	len = sizeof(struct ip6_hdr);
190128786Sscottl#ifndef __NO_STRICT_ALIGNMENT
19165312Smsmith	if (family == AF_LINK)
192128786Sscottl		len += ETHERIP_ALIGN;
193128786Sscottl#endif
194128786Sscottl	M_PREPEND(m, len, M_DONTWAIT);
19565312Smsmith	if (m != NULL && m->m_len < len)
196128535Sscottl		m = m_pullup(m, len);
197128535Sscottl	if (m == NULL) {
198128535Sscottl		printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
19965312Smsmith		return ENOBUFS;
20065312Smsmith	}
20165312Smsmith#ifndef __NO_STRICT_ALIGNMENT
20296554Sobrien	if (family == AF_LINK) {
20396554Sobrien		len = mtod(m, vm_offset_t) & 3;
20496554Sobrien		KASSERT(len == 0 || len == ETHERIP_ALIGN,
20596554Sobrien		    ("in6_gif_output: unexpected misalignment"));
20665312Smsmith		m->m_data += len;
20765312Smsmith		m->m_len -= ETHERIP_ALIGN;
208128535Sscottl	}
209128786Sscottl#endif
210128786Sscottl
211128786Sscottl	ip6 = mtod(m, struct ip6_hdr *);
212128786Sscottl	ip6->ip6_flow	= 0;
213128786Sscottl	ip6->ip6_vfc	&= ~IPV6_VERSION_MASK;
214128786Sscottl	ip6->ip6_vfc	|= IPV6_VERSION;
215128786Sscottl	ip6->ip6_plen	= htons((u_short)m->m_pkthdr.len);
216128786Sscottl	ip6->ip6_nxt	= proto;
217128786Sscottl	ip6->ip6_hlim	= V_ip6_gif_hlim;
21896554Sobrien	ip6->ip6_src	= sin6_src->sin6_addr;
219128786Sscottl	/* bidirectional configured tunnel mode */
220128535Sscottl	if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
221128535Sscottl		ip6->ip6_dst = sin6_dst->sin6_addr;
222128535Sscottl	else  {
223128535Sscottl		m_freem(m);
224128535Sscottl		return ENETUNREACH;
225128535Sscottl	}
226128786Sscottl	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
227128786Sscottl		       &otos, &itos);
228128535Sscottl	ip6->ip6_flow &= ~htonl(0xff << 20);
229128535Sscottl	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
230128535Sscottl
231128535Sscottl	M_SETFIB(m, sc->gif_fibnum);
23265312Smsmith
233128535Sscottl	if (dst->sin6_family != sin6_dst->sin6_family ||
234128786Sscottl	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
235128535Sscottl		/* cache route doesn't match */
236128535Sscottl		bzero(dst, sizeof(*dst));
237128535Sscottl		dst->sin6_family = sin6_dst->sin6_family;
23865312Smsmith		dst->sin6_len = sizeof(struct sockaddr_in6);
23965312Smsmith		dst->sin6_addr = sin6_dst->sin6_addr;
24065312Smsmith		if (sc->gif_ro6.ro_rt) {
241128535Sscottl			RTFREE(sc->gif_ro6.ro_rt);
242128535Sscottl			sc->gif_ro6.ro_rt = NULL;
24365312Smsmith		}
244128535Sscottl#if 0
245128535Sscottl		GIF2IFP(sc)->if_mtu = GIF_MTU;
24665312Smsmith#endif
24765312Smsmith	}
248143729Scognet
249143729Scognet	if (sc->gif_ro6.ro_rt == NULL) {
250143729Scognet		in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum);
251143729Scognet		if (sc->gif_ro6.ro_rt == NULL) {
25265312Smsmith			m_freem(m);
25365312Smsmith			return ENETUNREACH;
25465312Smsmith		}
25596554Sobrien
25696554Sobrien		/* if it constitutes infinite encapsulation, punt. */
257128945Sscottl		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
25896554Sobrien			m_freem(m);
25996554Sobrien			return ENETUNREACH;	/*XXX*/
26096554Sobrien		}
26196554Sobrien#if 0
26296554Sobrien		ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
26365312Smsmith			- sizeof(struct ip6_hdr);
26465312Smsmith#endif
26565312Smsmith	}
26665312Smsmith
26796615Sobrien#ifdef IPV6_MINMTU
26896615Sobrien	/*
26996615Sobrien	 * force fragmentation to minimum MTU, to avoid path MTU discovery.
27096615Sobrien	 * it is too painful to ask for resend of inner packet, to achieve
27196615Sobrien	 * path MTU discovery for encapsulated packets.
27296615Sobrien	 */
27396615Sobrien	error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
27496615Sobrien#else
27596554Sobrien	error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL);
27696554Sobrien#endif
27765312Smsmith
27865312Smsmith	if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
279128944Sscottl	    sc->gif_ro6.ro_rt != NULL) {
280128944Sscottl		RTFREE(sc->gif_ro6.ro_rt);
281128944Sscottl		sc->gif_ro6.ro_rt = NULL;
282128944Sscottl	}
28365312Smsmith
284128944Sscottl	return (error);
285128944Sscottl}
28665312Smsmith
28765312Smsmithint
28865312Smsmithin6_gif_input(struct mbuf **mp, int *offp, int proto)
28965312Smsmith{
29065312Smsmith	struct mbuf *m = *mp;
29165312Smsmith	struct ifnet *gifp = NULL;
29296554Sobrien	struct gif_softc *sc;
29396554Sobrien	struct ip6_hdr *ip6;
29465312Smsmith	int af = 0;
29565312Smsmith	u_int32_t otos;
29665312Smsmith
29796554Sobrien	ip6 = mtod(m, struct ip6_hdr *);
29896554Sobrien
29965312Smsmith	sc = (struct gif_softc *)encap_getarg(m);
30065312Smsmith	if (sc == NULL) {
30165312Smsmith		m_freem(m);
30296554Sobrien		V_ip6stat.ip6s_nogif++;
30396554Sobrien		return IPPROTO_DONE;
30496554Sobrien	}
30596554Sobrien
30696554Sobrien	gifp = GIF2IFP(sc);
30765312Smsmith	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
30865312Smsmith		m_freem(m);
30996554Sobrien		V_ip6stat.ip6s_nogif++;
31096554Sobrien		return IPPROTO_DONE;
31196554Sobrien	}
31265312Smsmith
31365312Smsmith	otos = ip6->ip6_flow;
314155307Sscottl	m_adj(m, *offp);
315155307Sscottl
316155307Sscottl	switch (proto) {
317155307Sscottl#ifdef INET
318155307Sscottl	case IPPROTO_IPV4:
319128944Sscottl	    {
320128944Sscottl		struct ip *ip;
321128944Sscottl		u_int8_t otos8;
322128944Sscottl		af = AF_INET;
323128944Sscottl		otos8 = (ntohl(otos) >> 20) & 0xff;
324128944Sscottl		if (m->m_len < sizeof(*ip)) {
32565312Smsmith			m = m_pullup(m, sizeof(*ip));
326155286Sscottl			if (!m)
32796554Sobrien				return IPPROTO_DONE;
328128944Sscottl		}
329128944Sscottl		ip = mtod(m, struct ip *);
330128944Sscottl		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
331128944Sscottl				  ECN_ALLOWED : ECN_NOCARE,
332128944Sscottl				  &otos8, &ip->ip_tos) == 0) {
333128944Sscottl			m_freem(m);
33496554Sobrien			return IPPROTO_DONE;
33596554Sobrien		}
336155286Sscottl		break;
337155286Sscottl	    }
338155307Sscottl#endif /* INET */
339155307Sscottl#ifdef INET6
340155307Sscottl	case IPPROTO_IPV6:
341155307Sscottl	    {
342155286Sscottl		struct ip6_hdr *ip6;
34396554Sobrien		af = AF_INET6;
34496554Sobrien		if (m->m_len < sizeof(*ip6)) {
34596554Sobrien			m = m_pullup(m, sizeof(*ip6));
34696554Sobrien			if (!m)
34796554Sobrien				return IPPROTO_DONE;
34896554Sobrien		}
34996554Sobrien		ip6 = mtod(m, struct ip6_hdr *);
350128535Sscottl		if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ?
351128535Sscottl				   ECN_ALLOWED : ECN_NOCARE,
352128535Sscottl				   &otos, &ip6->ip6_flow) == 0) {
353128535Sscottl			m_freem(m);
354128535Sscottl			return IPPROTO_DONE;
355128535Sscottl		}
356128535Sscottl		break;
357128535Sscottl	    }
358128535Sscottl#endif
35996554Sobrien	case IPPROTO_ETHERIP:
36096554Sobrien		af = AF_LINK;
36196554Sobrien		break;
36265312Smsmith
36396554Sobrien	default:
364128535Sscottl		V_ip6stat.ip6s_nogif++;
365128535Sscottl		m_freem(m);
366128535Sscottl		return IPPROTO_DONE;
367128535Sscottl	}
36896554Sobrien
36996554Sobrien	gif_input(m, af, gifp);
37096554Sobrien	return IPPROTO_DONE;
37196554Sobrien}
37296554Sobrien
37396554Sobrien/*
37496554Sobrien * validate outer address.
37596554Sobrien */
37696554Sobrienstatic int
37796554Sobriengif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
37896554Sobrien    struct ifnet *ifp)
37965312Smsmith{
38096554Sobrien	struct sockaddr_in6 *src, *dst;
381234503Sdim
382130585Sphk	src = (struct sockaddr_in6 *)sc->gif_psrc;
38365312Smsmith	dst = (struct sockaddr_in6 *)sc->gif_pdst;
38465312Smsmith
385234503Sdim	/*
386234503Sdim	 * Check for address match.  Note that the check is for an incoming
38765312Smsmith	 * packet.  We should compare the *source* address in our configuration
38896554Sobrien	 * and the *destination* address of the packet, and vice versa.
38965312Smsmith	 */
39065312Smsmith	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
39165312Smsmith	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
392154363Sscottl		return 0;
393154363Sscottl
39465312Smsmith	/* martian filters on outer source - done in ip6_input */
395130585Sphk
396128784Sscottl	/* ingress filters on outer source */
397130585Sphk	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
398128784Sscottl		struct sockaddr_in6 sin6;
399130585Sphk		struct rtentry *rt;
400128784Sscottl
401128784Sscottl		bzero(&sin6, sizeof(sin6));
402128784Sscottl		sin6.sin6_family = AF_INET6;
403128784Sscottl		sin6.sin6_len = sizeof(struct sockaddr_in6);
404128784Sscottl		sin6.sin6_addr = ip6->ip6_src;
405128784Sscottl		sin6.sin6_scope_id = 0; /* XXX */
406128784Sscottl
407128784Sscottl		rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL,
40865312Smsmith		    sc->gif_fibnum);
409275982Ssmh		if (!rt || rt->rt_ifp != ifp) {
410275982Ssmh#if 0
411275982Ssmh			char ip6buf[INET6_ADDRSTRLEN];
412275982Ssmh			log(LOG_WARNING, "%s: packet from %s dropped "
413275982Ssmh			    "due to ingress filter\n", if_name(GIF2IFP(sc)),
414275982Ssmh			    ip6_sprintf(ip6buf, &sin6.sin6_addr));
415275982Ssmh#endif
416275982Ssmh			if (rt)
417275982Ssmh				RTFREE_LOCKED(rt);
418275982Ssmh			return 0;
419275982Ssmh		}
420275982Ssmh		RTFREE_LOCKED(rt);
421275982Ssmh	}
422275982Ssmh
423275982Ssmh	return 128 * 2;
424275982Ssmh}
425275982Ssmh
426275982Ssmh/*
427275982Ssmh * we know that we are in IFF_UP, outer address available, and outer family
42865312Smsmith * matched the physical addr family.  see gif_encapcheck().
42996554Sobrien * sanity check for arg should have been done in the caller.
43096554Sobrien */
43165312Smsmithint
432128784Sscottlgif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg)
43396554Sobrien{
43496554Sobrien	struct ip6_hdr ip6;
43596554Sobrien	struct gif_softc *sc;
43665312Smsmith	struct ifnet *ifp;
43765312Smsmith
438128784Sscottl	/* sanity check done in caller */
43996554Sobrien	sc = (struct gif_softc *)arg;
44096554Sobrien
44196554Sobrien	/* LINTED const cast */
44265312Smsmith	m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
44365312Smsmith	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
444128784Sscottl
44565312Smsmith	return gif_validate6(&ip6, sc, ifp);
446165102Smjacob}
447165102Smjacob
44865312Smsmithint
44965312Smsmithin6_gif_attach(struct gif_softc *sc)
45065312Smsmith{
45165312Smsmith	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
45265312Smsmith	    (void *)&in6_gif_protosw, sc);
45365312Smsmith	if (sc->encap_cookie6 == NULL)
454128784Sscottl		return EEXIST;
455126080Sphk	return 0;
456126080Sphk}
457111815Sphk
458111815Sphkint
459111815Sphkin6_gif_detach(struct gif_softc *sc)
460111815Sphk{
46165312Smsmith	int error;
46265312Smsmith
46365312Smsmith	error = encap_detach(sc->encap_cookie6);
46465312Smsmith	if (error == 0)
465128944Sscottl		sc->encap_cookie6 = NULL;
466128944Sscottl	return error;
467128944Sscottl}
468128944Sscottl