1 //==========================================================================
3 // src/sys/netinet6/in6_gif.c
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
8 // -------------------------------------------
10 // Portions of this software may have been derived from OpenBSD,
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
17 // -------------------------------------------
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
22 /* $KAME: in6_gif.c,v 1.88 2001/12/21 03:32:34 itojun Exp $ */
25 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26 * All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of the project nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 /* define it if you want to use encap_attach_func (it helps *BSD merge) */
54 /*#define USE_ENCAPCHECK*/
56 #include <sys/param.h>
57 #include <sys/socket.h>
58 #include <sys/sockio.h>
60 #include <sys/errno.h>
61 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
62 #include <sys/ioctl.h>
64 #include <sys/queue.h>
65 #include <sys/protosw.h>
67 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
68 #include <sys/malloc.h>
72 #include <net/route.h>
74 #include <netinet/in.h>
75 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
79 #include <netinet/ip_encap.h>
81 #include <netinet/ip6.h>
82 #include <netinet6/ip6_var.h>
83 #include <netinet6/in6_gif.h>
84 #include <netinet6/in6_var.h>
86 #include <netinet6/ip6protosw.h>
87 #include <netinet/ip_ecn.h>
89 #include <netinet/ip_ipsp.h>
92 #include <net/if_gif.h>
98 static int gif_validate6 __P((const struct ip6_hdr *, struct gif_softc *,
100 static int in6_gif_rtcachettl = 300; /* XXX see in_gif.c */
102 int ip6_gif_hlim = GIF_HLIM;
104 extern struct domain inet6domain;
105 struct ip6protosw in6_gif_protosw =
106 { SOCK_RAW, &inet6domain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR,
107 in6_gif_input, rip6_output, in6_gif_ctlinput, rip6_ctloutput,
108 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
114 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
119 extern LIST_HEAD(, gif_softc) gif_softc_list;
122 #define offsetof(s, e) ((int)&((s *)0)->e)
126 in6_gif_output(ifp, family, m)
128 int family; /* family of the packet to be encapsulate. */
132 struct gif_softc *sc = (struct gif_softc*)ifp;
133 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
134 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
135 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
143 if (sin6_src == NULL || sin6_dst == NULL ||
144 sin6_src->sin6_family != AF_INET6 ||
145 sin6_dst->sin6_family != AF_INET6) {
150 /* setup dummy tdb. it highly depends on ipip_output() code. */
151 bzero(&tdb, sizeof(tdb));
152 bzero(&xfs, sizeof(xfs));
153 tdb.tdb_src.sin6.sin6_family = AF_INET6;
154 tdb.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6);
155 tdb.tdb_src.sin6.sin6_addr = sin6_src->sin6_addr;
156 tdb.tdb_dst.sin6.sin6_family = AF_INET6;
157 tdb.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
158 tdb.tdb_dst.sin6.sin6_addr = sin6_dst->sin6_addr;
159 tdb.tdb_xform = &xfs;
160 xfs.xf_type = -1; /* not XF_IP4 */
166 if (m->m_len < sizeof(struct ip)) {
167 m = m_pullup(m, sizeof(struct ip));
171 hlen = (mtod(m, struct ip *)->ip_hl) << 2;
172 poff = offsetof(struct ip, ip_p);
179 hlen = sizeof(struct ip6_hdr);
180 poff = offsetof(struct ip6_hdr, ip6_nxt);
190 printf("in6_gif_output: warning: unknown family %d passed\n",
198 if (family == AF_LINK) {
200 error = etherip_output(m, &tdb, &mp, 0, 0);
211 /* encapsulate into IPv6 packet */
213 error = ipip_output(m, &tdb, &mp, hlen, poff);
225 * compare address family just for safety. other validity checks
226 * are made in in6_selectsrc() called from ip6_output().
228 if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||
229 sc->rtcache_expire == 0 ||
230 time_second >= sc->rtcache_expire)) {
231 RTFREE(sc->gif_ro6.ro_rt);
232 sc->gif_ro6.ro_rt = NULL;
237 * force fragmentation to minimum MTU, to avoid path MTU discovery.
238 * it is too painful to ask for resend of inner packet, to achieve
239 * path MTU discovery for encapsulated packets.
241 error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL);
243 error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL);
246 if (sc->gif_ro6.ro_rt && time_second >= sc->rtcache_expire)
247 sc->rtcache_expire = time_second + in6_gif_rtcachettl;
250 #else /* !__OpenBSD__ */
251 struct gif_softc *sc = (struct gif_softc*)ifp;
252 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
253 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
254 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
258 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
262 if (sin6_src == NULL || sin6_dst == NULL ||
263 sin6_src->sin6_family != AF_INET6 ||
264 sin6_dst->sin6_family != AF_INET6) {
275 proto = IPPROTO_IPV4;
276 if (m->m_len < sizeof(*ip)) {
277 m = m_pullup(m, sizeof(*ip));
281 ip = mtod(m, struct ip *);
290 proto = IPPROTO_IPV6;
291 if (m->m_len < sizeof(*ip6)) {
292 m = m_pullup(m, sizeof(*ip6));
296 ip6 = mtod(m, struct ip6_hdr *);
297 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
301 #if defined(__NetBSD__) && defined(ISO)
309 printf("in6_gif_output: warning: unknown family %d passed\n",
316 /* prepend new IP header */
317 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
318 if (m && m->m_len < sizeof(struct ip6_hdr))
319 m = m_pullup(m, sizeof(struct ip6_hdr));
323 ip6 = mtod(m, struct ip6_hdr *);
325 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
326 ip6->ip6_vfc |= IPV6_VERSION;
327 ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
328 ip6->ip6_nxt = proto;
329 ip6->ip6_hlim = ip6_gif_hlim;
330 ip6->ip6_src = sin6_src->sin6_addr;
331 /* bidirectional configured tunnel mode */
332 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
333 ip6->ip6_dst = sin6_dst->sin6_addr;
338 if (ifp->if_flags & IFF_LINK1)
339 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
341 ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
342 ip6->ip6_flow &= ~ntohl(0xff00000);
343 ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
345 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
346 time_second = time.tv_sec;
349 * compare address family just for safety. other validity checks
350 * are made in in6_selectsrc() called from ip6_output().
352 if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||
353 sc->rtcache_expire == 0 ||
354 time_second >= sc->rtcache_expire)) {
356 * If the cached route is not valid or has expired,
357 * clear the stale cache and let ip6_output make a new cached
360 RTFREE(sc->gif_ro6.ro_rt);
361 sc->gif_ro6.ro_rt = NULL;
366 * force fragmentation to minimum MTU, to avoid path MTU discovery.
367 * it is too painful to ask for resend of inner packet, to achieve
368 * path MTU discovery for encapsulated packets.
370 error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL);
372 error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL);
376 * if a (new) cached route has been created in ip6_output(), extend
377 * the expiration time.
379 if (sc->gif_ro6.ro_rt && time_second >= sc->rtcache_expire)
380 sc->rtcache_expire = time_second + in6_gif_rtcachettl;
383 #endif /* __OpenBSD__ */
386 int in6_gif_input(mp, offp, proto)
390 struct mbuf *m = *mp;
391 struct ifnet *gifp = NULL;
398 ip6 = mtod(m, struct ip6_hdr *);
400 gifp = (struct ifnet *)encap_getarg(m);
402 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
404 ip6stat.ip6s_nogif++;
407 #ifndef USE_ENCAPCHECK
408 if (!gif_validate6(ip6, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) {
410 ip6stat.ip6s_nogif++;
416 m->m_pkthdr.rcvif = gifp;
418 gifp->if_ibytes += m->m_pkthdr.len;
419 ipip_input(m, *offp, gifp);
422 otos = ip6->ip6_flow;
432 otos8 = (ntohl(otos) >> 20) & 0xff;
433 if (m->m_len < sizeof(*ip)) {
434 m = m_pullup(m, sizeof(*ip));
438 ip = mtod(m, struct ip *);
439 if (gifp->if_flags & IFF_LINK1)
440 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
442 ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
451 if (m->m_len < sizeof(*ip6)) {
452 m = m_pullup(m, sizeof(*ip6));
456 ip6 = mtod(m, struct ip6_hdr *);
457 if (gifp->if_flags & IFF_LINK1)
458 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
460 ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
464 #if defined(__NetBSD__) && defined(ISO)
470 ip6stat.ip6s_nogif++;
475 gif_input(m, af, gifp);
481 * validate outer address.
484 gif_validate6(ip6, sc, ifp)
485 const struct ip6_hdr *ip6;
486 struct gif_softc *sc;
489 struct sockaddr_in6 *src, *dst;
491 src = (struct sockaddr_in6 *)sc->gif_psrc;
492 dst = (struct sockaddr_in6 *)sc->gif_pdst;
494 /* check for address match */
495 if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
496 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
499 /* martian filters on outer source - done in ip6_input */
501 /* ingress filters on outer source */
502 if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
503 struct sockaddr_in6 sin6;
506 bzero(&sin6, sizeof(sin6));
507 sin6.sin6_family = AF_INET6;
508 sin6.sin6_len = sizeof(struct sockaddr_in6);
509 sin6.sin6_addr = ip6->ip6_src;
512 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
514 rt = rtalloc1((struct sockaddr *)&sin6, 0);
516 if (!rt || rt->rt_ifp != ifp) {
518 log(LOG_WARNING, "%s: packet from %s dropped "
519 "due to ingress filter\n", if_name(&sc->gif_if),
520 ip6_sprintf(&sin6.sin6_addr));
533 * we know that we are in IFF_UP, outer address available, and outer family
534 * matched the physical addr family. see gif_encapcheck().
537 gif_encapcheck6(m, off, proto, arg)
538 const struct mbuf *m;
544 struct gif_softc *sc;
547 /* sanity check done in caller */
548 sc = (struct gif_softc *)arg;
550 /* LINTED const cast */
551 m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);
552 ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
554 return gif_validate6(&ip6, sc, ifp);
559 struct gif_softc *sc;
561 #ifndef USE_ENCAPCHECK
562 struct sockaddr_in6 mask6;
564 bzero(&mask6, sizeof(mask6));
565 mask6.sin6_len = sizeof(struct sockaddr_in6);
566 mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
567 mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
569 if (!sc->gif_psrc || !sc->gif_pdst)
571 sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,
572 (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,
573 (struct protosw *)&in6_gif_protosw, sc);
575 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
576 (struct protosw *)&in6_gif_protosw, sc);
578 if (sc->encap_cookie6 == NULL)
585 struct gif_softc *sc;
589 error = encap_detach(sc->encap_cookie6);
591 sc->encap_cookie6 = NULL;
596 in6_gif_ctlinput(cmd, sa, d)
601 struct gif_softc *sc;
602 struct ip6ctlparam *ip6cp = NULL;
607 const struct sockaddr_in6 *sa6_src = NULL;
608 struct sockaddr_in6 *dst6;
610 if (sa->sa_family != AF_INET6 ||
611 sa->sa_len != sizeof(struct sockaddr_in6))
614 if ((unsigned)cmd >= PRC_NCMDS)
616 if (cmd == PRC_HOSTDEAD)
618 else if (inet6ctlerrmap[cmd] == 0)
621 /* if the parameter is from icmp6, decode it. */
623 ip6cp = (struct ip6ctlparam *)d;
625 ip6 = ip6cp->ip6c_ip6;
626 off = ip6cp->ip6c_off;
627 cmdarg = ip6cp->ip6c_cmdarg;
628 sa6_src = ip6cp->ip6c_src;
640 * for now we don't care which type it was, just flush the route cache.
641 * XXX slow. sc (or sc->encap_cookie6) should be passed from
644 for (sc = LIST_FIRST(&gif_softc_list); sc;
645 sc = LIST_NEXT(sc, gif_list)) {
646 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
648 if (sc->gif_psrc->sa_family != AF_INET6)
650 if (!sc->gif_ro6.ro_rt)
653 dst6 = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
655 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) {
656 /* flush route cache */
657 RTFREE(sc->gif_ro6.ro_rt);
658 sc->gif_ro6.ro_rt = NULL;