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. 28*0b9f5f8aSAndrey V. Elsukov * 29*0b9f5f8aSAndrey 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> 39*0b9f5f8aSAndrey V. Elsukov #include <sys/lock.h> 40*0b9f5f8aSAndrey 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> 606a800098SYoshinobu Inoue #include <netinet/in_gif.h> 61686cdd19SJun-ichiro itojun Hagino #include <netinet/in_var.h> 62686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 636a800098SYoshinobu Inoue #include <netinet/ip_ecn.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 719426aedfSHajimu UMEMOTO static int gif_validate4(const struct ip *, struct gif_softc *, 729426aedfSHajimu UMEMOTO struct ifnet *); 739426aedfSHajimu UMEMOTO 749426aedfSHajimu UMEMOTO extern struct domain inetdomain; 75303989a2SRuslan Ermilov struct protosw in_gif_protosw = { 76303989a2SRuslan Ermilov .pr_type = SOCK_RAW, 77303989a2SRuslan Ermilov .pr_domain = &inetdomain, 78303989a2SRuslan Ermilov .pr_protocol = 0/* IPPROTO_IPV[46] */, 79303989a2SRuslan Ermilov .pr_flags = PR_ATOMIC|PR_ADDR, 80303989a2SRuslan Ermilov .pr_input = in_gif_input, 8173d76e77SKevin Lo .pr_output = rip_output, 82303989a2SRuslan Ermilov .pr_ctloutput = rip_ctloutput, 83303989a2SRuslan Ermilov .pr_usrreqs = &rip_usrreqs 849426aedfSHajimu UMEMOTO }; 859426aedfSHajimu UMEMOTO 8682cea7e6SBjoern A. Zeeb VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 8782cea7e6SBjoern A. Zeeb #define V_ip_gif_ttl VNET(ip_gif_ttl) 88eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 89eddfbb76SRobert Watson &VNET_NAME(ip_gif_ttl), 0, ""); 90cfa1ca9dSYoshinobu Inoue 91cfa1ca9dSYoshinobu Inoue int 92*0b9f5f8aSAndrey V. Elsukov in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 93cfa1ca9dSYoshinobu Inoue { 94*0b9f5f8aSAndrey V. Elsukov GIF_RLOCK_TRACKER; 95fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 96cfa1ca9dSYoshinobu Inoue struct ip *ip; 97*0b9f5f8aSAndrey V. Elsukov int len; 98cfa1ca9dSYoshinobu Inoue 99cfa1ca9dSYoshinobu Inoue /* prepend new IP header */ 100c89c8a10SMarius Strobl len = sizeof(struct ip); 101c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 102*0b9f5f8aSAndrey V. Elsukov if (proto == IPPROTO_ETHERIP) 103c89c8a10SMarius Strobl len += ETHERIP_ALIGN; 104c89c8a10SMarius Strobl #endif 105eb1b1807SGleb Smirnoff M_PREPEND(m, len, M_NOWAIT); 106c89c8a10SMarius Strobl if (m != NULL && m->m_len < len) 107c89c8a10SMarius Strobl m = m_pullup(m, len); 108*0b9f5f8aSAndrey V. Elsukov if (m == NULL) 109*0b9f5f8aSAndrey V. Elsukov return (ENOBUFS); 110c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 111*0b9f5f8aSAndrey V. Elsukov if (proto == IPPROTO_ETHERIP) { 112c89c8a10SMarius Strobl len = mtod(m, vm_offset_t) & 3; 113c89c8a10SMarius Strobl KASSERT(len == 0 || len == ETHERIP_ALIGN, 114c89c8a10SMarius Strobl ("in_gif_output: unexpected misalignment")); 115c89c8a10SMarius Strobl m->m_data += len; 116c89c8a10SMarius Strobl m->m_len -= ETHERIP_ALIGN; 117c89c8a10SMarius Strobl } 118c89c8a10SMarius Strobl #endif 119*0b9f5f8aSAndrey V. Elsukov ip = mtod(m, struct ip *); 120*0b9f5f8aSAndrey V. Elsukov GIF_RLOCK(sc); 121*0b9f5f8aSAndrey V. Elsukov if (sc->gif_family != AF_INET) { 122cfa1ca9dSYoshinobu Inoue m_freem(m); 123*0b9f5f8aSAndrey V. Elsukov GIF_RUNLOCK(sc); 124*0b9f5f8aSAndrey V. Elsukov return (ENETDOWN); 125cfa1ca9dSYoshinobu Inoue } 126*0b9f5f8aSAndrey V. Elsukov bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 127*0b9f5f8aSAndrey V. Elsukov GIF_RUNLOCK(sc); 128686cdd19SJun-ichiro itojun Hagino 129*0b9f5f8aSAndrey V. Elsukov ip->ip_p = proto; 130*0b9f5f8aSAndrey V. Elsukov /* version will be set in ip_output() */ 131*0b9f5f8aSAndrey V. Elsukov ip->ip_ttl = V_ip_gif_ttl; 132*0b9f5f8aSAndrey V. Elsukov ip->ip_len = htons(m->m_pkthdr.len); 133*0b9f5f8aSAndrey V. Elsukov ip->ip_tos = ecn; 134cfa1ca9dSYoshinobu Inoue 135*0b9f5f8aSAndrey V. Elsukov return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 136cfa1ca9dSYoshinobu Inoue } 137cfa1ca9dSYoshinobu Inoue 1388f5a8818SKevin Lo int 1398f5a8818SKevin Lo in_gif_input(struct mbuf **mp, int *offp, int proto) 140cfa1ca9dSYoshinobu Inoue { 141*0b9f5f8aSAndrey V. Elsukov struct mbuf *m = *mp; 14267df9f38SBjoern A. Zeeb struct gif_softc *sc; 143*0b9f5f8aSAndrey V. Elsukov struct ifnet *gifp; 144cfa1ca9dSYoshinobu Inoue struct ip *ip; 145*0b9f5f8aSAndrey V. Elsukov uint8_t ecn; 146cfa1ca9dSYoshinobu Inoue 147*0b9f5f8aSAndrey V. Elsukov sc = encap_getarg(m); 14867df9f38SBjoern A. Zeeb if (sc == NULL) { 14967df9f38SBjoern A. Zeeb m_freem(m); 150315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 1518f5a8818SKevin Lo return (IPPROTO_DONE); 15267df9f38SBjoern A. Zeeb } 15367df9f38SBjoern A. Zeeb gifp = GIF2IFP(sc); 154*0b9f5f8aSAndrey V. Elsukov if ((gifp->if_flags & IFF_UP) != 0) { 155cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 156*0b9f5f8aSAndrey V. Elsukov ecn = ip->ip_tos; 157*0b9f5f8aSAndrey V. Elsukov m_adj(m, *offp); 158*0b9f5f8aSAndrey V. Elsukov gif_input(m, gifp, proto, ecn); 159*0b9f5f8aSAndrey V. Elsukov } else { 16059dfcba4SHajimu UMEMOTO m_freem(m); 161315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 162cfa1ca9dSYoshinobu Inoue } 1638f5a8818SKevin Lo return (IPPROTO_DONE); 164cfa1ca9dSYoshinobu Inoue } 165686cdd19SJun-ichiro itojun Hagino 166686cdd19SJun-ichiro itojun Hagino /* 1679426aedfSHajimu UMEMOTO * validate outer address. 168686cdd19SJun-ichiro itojun Hagino */ 1699426aedfSHajimu UMEMOTO static int 170f2565d68SRobert Watson gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) 1719426aedfSHajimu UMEMOTO { 172686cdd19SJun-ichiro itojun Hagino struct in_ifaddr *ia4; 173686cdd19SJun-ichiro itojun Hagino 174*0b9f5f8aSAndrey V. Elsukov GIF_RLOCK_ASSERT(sc); 175686cdd19SJun-ichiro itojun Hagino 176686cdd19SJun-ichiro itojun Hagino /* check for address match */ 177*0b9f5f8aSAndrey V. Elsukov if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr || 178*0b9f5f8aSAndrey V. Elsukov sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) 179*0b9f5f8aSAndrey V. Elsukov return (0); 180686cdd19SJun-ichiro itojun Hagino 181686cdd19SJun-ichiro itojun Hagino /* martian filters on outer source - NOT done in ip_input! */ 1829426aedfSHajimu UMEMOTO if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 183*0b9f5f8aSAndrey V. Elsukov return (0); 1849426aedfSHajimu UMEMOTO switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 185*0b9f5f8aSAndrey V. Elsukov case 0: 186*0b9f5f8aSAndrey V. Elsukov case 127: 187*0b9f5f8aSAndrey V. Elsukov case 255: 188*0b9f5f8aSAndrey V. Elsukov return (0); 189686cdd19SJun-ichiro itojun Hagino } 1902d9cfabaSRobert Watson 191686cdd19SJun-ichiro itojun Hagino /* reject packets with broadcast on source */ 1922d9cfabaSRobert Watson /* XXXRW: should use hash lists? */ 1932d9cfabaSRobert Watson IN_IFADDR_RLOCK(); 194603724d3SBjoern A. Zeeb TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { 195686cdd19SJun-ichiro itojun Hagino if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 196686cdd19SJun-ichiro itojun Hagino continue; 1972d9cfabaSRobert Watson if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { 1982d9cfabaSRobert Watson IN_IFADDR_RUNLOCK(); 199*0b9f5f8aSAndrey V. Elsukov return (0); 200686cdd19SJun-ichiro itojun Hagino } 2012d9cfabaSRobert Watson } 2022d9cfabaSRobert Watson IN_IFADDR_RUNLOCK(); 203686cdd19SJun-ichiro itojun Hagino 204686cdd19SJun-ichiro itojun Hagino /* ingress filters on outer source */ 205fc74a9f9SBrooks Davis if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 206686cdd19SJun-ichiro itojun Hagino struct sockaddr_in sin; 207686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 208686cdd19SJun-ichiro itojun Hagino 209686cdd19SJun-ichiro itojun Hagino bzero(&sin, sizeof(sin)); 210686cdd19SJun-ichiro itojun Hagino sin.sin_family = AF_INET; 211686cdd19SJun-ichiro itojun Hagino sin.sin_len = sizeof(struct sockaddr_in); 2129426aedfSHajimu UMEMOTO sin.sin_addr = ip->ip_src; 2138b07e49aSJulian Elischer /* XXX MRT check for the interface we would use on output */ 2148b07e49aSJulian Elischer rt = in_rtalloc1((struct sockaddr *)&sin, 0, 2158b07e49aSJulian Elischer 0UL, sc->gif_fibnum); 2169426aedfSHajimu UMEMOTO if (!rt || rt->rt_ifp != ifp) { 21733841545SHajimu UMEMOTO if (rt) 218bc60490aSChristian S.J. Peron RTFREE_LOCKED(rt); 219*0b9f5f8aSAndrey V. Elsukov return (0); 220686cdd19SJun-ichiro itojun Hagino } 221bc60490aSChristian S.J. Peron RTFREE_LOCKED(rt); 222686cdd19SJun-ichiro itojun Hagino } 223*0b9f5f8aSAndrey V. Elsukov return (32 * 2); 224686cdd19SJun-ichiro itojun Hagino } 2259426aedfSHajimu UMEMOTO 2269426aedfSHajimu UMEMOTO /* 2279426aedfSHajimu UMEMOTO * we know that we are in IFF_UP, outer address available, and outer family 2289426aedfSHajimu UMEMOTO * matched the physical addr family. see gif_encapcheck(). 2299426aedfSHajimu UMEMOTO */ 2309426aedfSHajimu UMEMOTO int 231*0b9f5f8aSAndrey V. Elsukov in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 2329426aedfSHajimu UMEMOTO { 2339426aedfSHajimu UMEMOTO struct ip ip; 2349426aedfSHajimu UMEMOTO struct gif_softc *sc; 2359426aedfSHajimu UMEMOTO struct ifnet *ifp; 2369426aedfSHajimu UMEMOTO 2379426aedfSHajimu UMEMOTO /* sanity check done in caller */ 2389426aedfSHajimu UMEMOTO sc = (struct gif_softc *)arg; 239*0b9f5f8aSAndrey V. Elsukov GIF_RLOCK_ASSERT(sc); 2409426aedfSHajimu UMEMOTO 2419426aedfSHajimu UMEMOTO m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 2429426aedfSHajimu UMEMOTO ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 243*0b9f5f8aSAndrey V. Elsukov return (gif_validate4(&ip, sc, ifp)); 2449426aedfSHajimu UMEMOTO } 2459426aedfSHajimu UMEMOTO 2469426aedfSHajimu UMEMOTO int 247f2565d68SRobert Watson in_gif_attach(struct gif_softc *sc) 2489426aedfSHajimu UMEMOTO { 249*0b9f5f8aSAndrey V. Elsukov 250*0b9f5f8aSAndrey V. Elsukov KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 251*0b9f5f8aSAndrey V. Elsukov sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 2529426aedfSHajimu UMEMOTO &in_gif_protosw, sc); 253*0b9f5f8aSAndrey V. Elsukov if (sc->gif_ecookie == NULL) 254*0b9f5f8aSAndrey V. Elsukov return (EEXIST); 255*0b9f5f8aSAndrey V. Elsukov return (0); 2569426aedfSHajimu UMEMOTO } 257