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