1c398230bSWarner Losh /*- 2cfa1ca9dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3cfa1ca9dSYoshinobu Inoue * All rights reserved. 4cfa1ca9dSYoshinobu Inoue * 5cfa1ca9dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 6cfa1ca9dSYoshinobu Inoue * modification, are permitted provided that the following conditions 7cfa1ca9dSYoshinobu Inoue * are met: 8cfa1ca9dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 9cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 10cfa1ca9dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 11cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 12cfa1ca9dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 13cfa1ca9dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 14cfa1ca9dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 15cfa1ca9dSYoshinobu Inoue * without specific prior written permission. 16cfa1ca9dSYoshinobu Inoue * 17cfa1ca9dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18cfa1ca9dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19cfa1ca9dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20cfa1ca9dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21cfa1ca9dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22cfa1ca9dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23cfa1ca9dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24cfa1ca9dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25cfa1ca9dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26cfa1ca9dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27cfa1ca9dSYoshinobu Inoue * SUCH DAMAGE. 280b9f5f8aSAndrey V. Elsukov * 290b9f5f8aSAndrey V. Elsukov * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ 30cfa1ca9dSYoshinobu Inoue */ 31cfa1ca9dSYoshinobu Inoue 324b421e2dSMike Silbersack #include <sys/cdefs.h> 334b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 344b421e2dSMike Silbersack 35686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 36cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 37cfa1ca9dSYoshinobu Inoue 38cfa1ca9dSYoshinobu Inoue #include <sys/param.h> 390b9f5f8aSAndrey V. Elsukov #include <sys/lock.h> 400b9f5f8aSAndrey V. Elsukov #include <sys/rmlock.h> 41cfa1ca9dSYoshinobu Inoue #include <sys/systm.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 47cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h> 489426aedfSHajimu UMEMOTO #include <sys/protosw.h> 49686cdd19SJun-ichiro itojun Hagino #include <sys/malloc.h> 50cfa1ca9dSYoshinobu Inoue 51cfa1ca9dSYoshinobu Inoue #include <net/if.h> 5276039bc8SGleb Smirnoff #include <net/if_var.h> 53cfa1ca9dSYoshinobu Inoue #include <net/route.h> 54530c0060SRobert Watson #include <net/vnet.h> 55cfa1ca9dSYoshinobu Inoue 56cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 57cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 58cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 596a800098SYoshinobu Inoue #include <netinet/ip_var.h> 60686cdd19SJun-ichiro itojun Hagino #include <netinet/in_var.h> 61686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 626a800098SYoshinobu Inoue #include <netinet/ip_ecn.h> 63*65ff3638SAlexander V. Chernikov #include <netinet/in_fib.h> 64686cdd19SJun-ichiro itojun Hagino 656a800098SYoshinobu Inoue #ifdef INET6 66686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 676a800098SYoshinobu Inoue #endif 68cfa1ca9dSYoshinobu Inoue 69cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 70cfa1ca9dSYoshinobu Inoue 71132c4490SAndrey V. Elsukov static int in_gif_input(struct mbuf **, int *, int); 729426aedfSHajimu UMEMOTO 739426aedfSHajimu UMEMOTO extern struct domain inetdomain; 74132c4490SAndrey V. Elsukov static struct protosw in_gif_protosw = { 75303989a2SRuslan Ermilov .pr_type = SOCK_RAW, 76303989a2SRuslan Ermilov .pr_domain = &inetdomain, 77303989a2SRuslan Ermilov .pr_protocol = 0/* IPPROTO_IPV[46] */, 78303989a2SRuslan Ermilov .pr_flags = PR_ATOMIC|PR_ADDR, 79303989a2SRuslan Ermilov .pr_input = in_gif_input, 8073d76e77SKevin Lo .pr_output = rip_output, 81303989a2SRuslan Ermilov .pr_ctloutput = rip_ctloutput, 82303989a2SRuslan Ermilov .pr_usrreqs = &rip_usrreqs 839426aedfSHajimu UMEMOTO }; 849426aedfSHajimu UMEMOTO 85132c4490SAndrey V. Elsukov #define GIF_TTL 30 86132c4490SAndrey V. Elsukov static VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 8782cea7e6SBjoern A. Zeeb #define V_ip_gif_ttl VNET(ip_gif_ttl) 886df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, 89eddfbb76SRobert Watson &VNET_NAME(ip_gif_ttl), 0, ""); 90cfa1ca9dSYoshinobu Inoue 91cfa1ca9dSYoshinobu Inoue int 920b9f5f8aSAndrey V. Elsukov in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 93cfa1ca9dSYoshinobu Inoue { 940b9f5f8aSAndrey V. Elsukov GIF_RLOCK_TRACKER; 95fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 96cfa1ca9dSYoshinobu Inoue struct ip *ip; 970b9f5f8aSAndrey V. Elsukov int len; 98cfa1ca9dSYoshinobu Inoue 99cfa1ca9dSYoshinobu Inoue /* prepend new IP header */ 100c89c8a10SMarius Strobl len = sizeof(struct ip); 101c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 1020b9f5f8aSAndrey V. Elsukov if (proto == IPPROTO_ETHERIP) 103c89c8a10SMarius Strobl len += ETHERIP_ALIGN; 104c89c8a10SMarius Strobl #endif 105eb1b1807SGleb Smirnoff M_PREPEND(m, len, M_NOWAIT); 1060b9f5f8aSAndrey V. Elsukov if (m == NULL) 1070b9f5f8aSAndrey V. Elsukov return (ENOBUFS); 108c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 1090b9f5f8aSAndrey V. Elsukov if (proto == IPPROTO_ETHERIP) { 110c89c8a10SMarius Strobl len = mtod(m, vm_offset_t) & 3; 111c89c8a10SMarius Strobl KASSERT(len == 0 || len == ETHERIP_ALIGN, 112c89c8a10SMarius Strobl ("in_gif_output: unexpected misalignment")); 113c89c8a10SMarius Strobl m->m_data += len; 114c89c8a10SMarius Strobl m->m_len -= ETHERIP_ALIGN; 115c89c8a10SMarius Strobl } 116c89c8a10SMarius Strobl #endif 1170b9f5f8aSAndrey V. Elsukov ip = mtod(m, struct ip *); 1180b9f5f8aSAndrey V. Elsukov GIF_RLOCK(sc); 1190b9f5f8aSAndrey V. Elsukov if (sc->gif_family != AF_INET) { 120cfa1ca9dSYoshinobu Inoue m_freem(m); 1210b9f5f8aSAndrey V. Elsukov GIF_RUNLOCK(sc); 1220b9f5f8aSAndrey V. Elsukov return (ENETDOWN); 123cfa1ca9dSYoshinobu Inoue } 1240b9f5f8aSAndrey V. Elsukov bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 1250b9f5f8aSAndrey V. Elsukov GIF_RUNLOCK(sc); 126686cdd19SJun-ichiro itojun Hagino 1270b9f5f8aSAndrey V. Elsukov ip->ip_p = proto; 1280b9f5f8aSAndrey V. Elsukov /* version will be set in ip_output() */ 1290b9f5f8aSAndrey V. Elsukov ip->ip_ttl = V_ip_gif_ttl; 1300b9f5f8aSAndrey V. Elsukov ip->ip_len = htons(m->m_pkthdr.len); 1310b9f5f8aSAndrey V. Elsukov ip->ip_tos = ecn; 132cfa1ca9dSYoshinobu Inoue 1330b9f5f8aSAndrey V. Elsukov return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 134cfa1ca9dSYoshinobu Inoue } 135cfa1ca9dSYoshinobu Inoue 136132c4490SAndrey V. Elsukov static int 1378f5a8818SKevin Lo in_gif_input(struct mbuf **mp, int *offp, int proto) 138cfa1ca9dSYoshinobu Inoue { 1390b9f5f8aSAndrey V. Elsukov struct mbuf *m = *mp; 14067df9f38SBjoern A. Zeeb struct gif_softc *sc; 1410b9f5f8aSAndrey V. Elsukov struct ifnet *gifp; 142cfa1ca9dSYoshinobu Inoue struct ip *ip; 1430b9f5f8aSAndrey V. Elsukov uint8_t ecn; 144cfa1ca9dSYoshinobu Inoue 1450b9f5f8aSAndrey V. Elsukov sc = encap_getarg(m); 14667df9f38SBjoern A. Zeeb if (sc == NULL) { 14767df9f38SBjoern A. Zeeb m_freem(m); 148315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 1498f5a8818SKevin Lo return (IPPROTO_DONE); 15067df9f38SBjoern A. Zeeb } 15167df9f38SBjoern A. Zeeb gifp = GIF2IFP(sc); 1520b9f5f8aSAndrey V. Elsukov if ((gifp->if_flags & IFF_UP) != 0) { 153cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 1540b9f5f8aSAndrey V. Elsukov ecn = ip->ip_tos; 1550b9f5f8aSAndrey V. Elsukov m_adj(m, *offp); 1560b9f5f8aSAndrey V. Elsukov gif_input(m, gifp, proto, ecn); 1570b9f5f8aSAndrey V. Elsukov } else { 15859dfcba4SHajimu UMEMOTO m_freem(m); 159315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 160cfa1ca9dSYoshinobu Inoue } 1618f5a8818SKevin Lo return (IPPROTO_DONE); 162cfa1ca9dSYoshinobu Inoue } 163686cdd19SJun-ichiro itojun Hagino 164686cdd19SJun-ichiro itojun Hagino /* 16510a0e0bfSAndrey V. Elsukov * we know that we are in IFF_UP, outer address available, and outer family 16610a0e0bfSAndrey V. Elsukov * matched the physical addr family. see gif_encapcheck(). 167686cdd19SJun-ichiro itojun Hagino */ 16810a0e0bfSAndrey V. Elsukov int 16910a0e0bfSAndrey V. Elsukov in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 1709426aedfSHajimu UMEMOTO { 17110a0e0bfSAndrey V. Elsukov const struct ip *ip; 17210a0e0bfSAndrey V. Elsukov struct gif_softc *sc; 173c1b4f79dSAndrey V. Elsukov int ret; 174686cdd19SJun-ichiro itojun Hagino 17510a0e0bfSAndrey V. Elsukov /* sanity check done in caller */ 17610a0e0bfSAndrey V. Elsukov sc = (struct gif_softc *)arg; 1770b9f5f8aSAndrey V. Elsukov GIF_RLOCK_ASSERT(sc); 178686cdd19SJun-ichiro itojun Hagino 179686cdd19SJun-ichiro itojun Hagino /* check for address match */ 18010a0e0bfSAndrey V. Elsukov ip = mtod(m, const struct ip *); 181c1b4f79dSAndrey V. Elsukov if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 1820b9f5f8aSAndrey V. Elsukov return (0); 183c1b4f79dSAndrey V. Elsukov ret = 32; 184c1b4f79dSAndrey V. Elsukov if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 185c1b4f79dSAndrey V. Elsukov if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 186c1b4f79dSAndrey V. Elsukov return (0); 187c1b4f79dSAndrey V. Elsukov } else 188c1b4f79dSAndrey V. Elsukov ret += 32; 189686cdd19SJun-ichiro itojun Hagino 190686cdd19SJun-ichiro itojun Hagino /* ingress filters on outer source */ 19110a0e0bfSAndrey V. Elsukov if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { 192*65ff3638SAlexander V. Chernikov struct nhop4_basic nh4; 193*65ff3638SAlexander V. Chernikov struct in_addr dst; 194686cdd19SJun-ichiro itojun Hagino 195*65ff3638SAlexander V. Chernikov dst = ip->ip_src; 196*65ff3638SAlexander V. Chernikov 197*65ff3638SAlexander V. Chernikov if (fib4_lookup_nh_basic(sc->gif_fibnum, dst, 0, 0, &nh4) != 0) 1980b9f5f8aSAndrey V. Elsukov return (0); 199*65ff3638SAlexander V. Chernikov 200*65ff3638SAlexander V. Chernikov if (nh4.nh_ifp != m->m_pkthdr.rcvif) 201*65ff3638SAlexander V. Chernikov return (0); 202686cdd19SJun-ichiro itojun Hagino } 203c1b4f79dSAndrey V. Elsukov return (ret); 204686cdd19SJun-ichiro itojun Hagino } 2059426aedfSHajimu UMEMOTO 2069426aedfSHajimu UMEMOTO int 207f2565d68SRobert Watson in_gif_attach(struct gif_softc *sc) 2089426aedfSHajimu UMEMOTO { 2090b9f5f8aSAndrey V. Elsukov 2100b9f5f8aSAndrey V. Elsukov KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 2110b9f5f8aSAndrey V. Elsukov sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 2129426aedfSHajimu UMEMOTO &in_gif_protosw, sc); 2130b9f5f8aSAndrey V. Elsukov if (sc->gif_ecookie == NULL) 2140b9f5f8aSAndrey V. Elsukov return (EEXIST); 2150b9f5f8aSAndrey V. Elsukov return (0); 2169426aedfSHajimu UMEMOTO } 217