1139823Simp/*- 254263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 354263Sshin * All rights reserved. 454263Sshin * 554263Sshin * Redistribution and use in source and binary forms, with or without 654263Sshin * modification, are permitted provided that the following conditions 754263Sshin * are met: 854263Sshin * 1. Redistributions of source code must retain the above copyright 954263Sshin * notice, this list of conditions and the following disclaimer. 1054263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1154263Sshin * notice, this list of conditions and the following disclaimer in the 1254263Sshin * documentation and/or other materials provided with the distribution. 1354263Sshin * 3. Neither the name of the project nor the names of its contributors 1454263Sshin * may be used to endorse or promote products derived from this software 1554263Sshin * without specific prior written permission. 1654263Sshin * 1754263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1854263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1954263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2054263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2154263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2254263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2354263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2454263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2554263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2654263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2754263Sshin * SUCH DAMAGE. 28276149Sae * 29276149Sae * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ 3054263Sshin */ 3154263Sshin 32172467Ssilby#include <sys/cdefs.h> 33172467Ssilby__FBSDID("$FreeBSD$"); 34172467Ssilby 3562587Sitojun#include "opt_inet.h" 3654263Sshin#include "opt_inet6.h" 3754263Sshin 3854263Sshin#include <sys/param.h> 39276149Sae#include <sys/lock.h> 40276149Sae#include <sys/rmlock.h> 4154263Sshin#include <sys/systm.h> 4254263Sshin#include <sys/socket.h> 4354263Sshin#include <sys/sockio.h> 4454263Sshin#include <sys/mbuf.h> 4554263Sshin#include <sys/errno.h> 4654263Sshin#include <sys/kernel.h> 4754263Sshin#include <sys/sysctl.h> 48105293Sume#include <sys/protosw.h> 4962587Sitojun#include <sys/malloc.h> 5062587Sitojun 5154263Sshin#include <net/if.h> 52276149Sae#include <net/if_var.h> 5354263Sshin#include <net/route.h> 54196019Srwatson#include <net/vnet.h> 5554263Sshin 5654263Sshin#include <netinet/in.h> 5754263Sshin#include <netinet/in_systm.h> 5854263Sshin#include <netinet/ip.h> 5954263Sshin#include <netinet/ip_var.h> 6062587Sitojun#include <netinet/in_var.h> 6162587Sitojun#include <netinet/ip_encap.h> 6255009Sshin#include <netinet/ip_ecn.h> 6362587Sitojun 6454263Sshin#ifdef INET6 6562587Sitojun#include <netinet/ip6.h> 6654263Sshin#endif 6754263Sshin 68276149Sae#include <net/if_gif.h> 6954263Sshin 70105293Sumestatic int gif_validate4(const struct ip *, struct gif_softc *, 71105293Sume struct ifnet *); 72284072Saestatic int in_gif_input(struct mbuf **, int *, int); 73105293Sume 74276149Saestatic void in_gif_input10(struct mbuf *, int); 75105293Sumeextern struct domain inetdomain; 76284072Saestatic struct protosw in_gif_protosw = { 77152242Sru .pr_type = SOCK_RAW, 78152242Sru .pr_domain = &inetdomain, 79152242Sru .pr_protocol = 0/* IPPROTO_IPV[46] */, 80152242Sru .pr_flags = PR_ATOMIC|PR_ADDR, 81276149Sae .pr_input = in_gif_input10, 82152242Sru .pr_output = (pr_output_t*)rip_output, 83152242Sru .pr_ctloutput = rip_ctloutput, 84152242Sru .pr_usrreqs = &rip_usrreqs 85105293Sume}; 86105293Sume 87284072Sae#define GIF_TTL 30 88284072Saestatic VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 89207369Sbz#define V_ip_gif_ttl VNET(ip_gif_ttl) 90195699SrwatsonSYSCTL_VNET_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 91195699Srwatson &VNET_NAME(ip_gif_ttl), 0, ""); 9254263Sshin 9354263Sshinint 94276149Saein_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 9554263Sshin{ 96276149Sae GIF_RLOCK_TRACKER; 97147256Sbrooks struct gif_softc *sc = ifp->if_softc; 98276149Sae struct ip *ip; 99276149Sae int len; 10054263Sshin 10154263Sshin /* prepend new IP header */ 102189494Smarius len = sizeof(struct ip); 103189494Smarius#ifndef __NO_STRICT_ALIGNMENT 104276149Sae if (proto == IPPROTO_ETHERIP) 105189494Smarius len += ETHERIP_ALIGN; 106189494Smarius#endif 107243882Sglebius M_PREPEND(m, len, M_NOWAIT); 108276149Sae if (m == NULL) 109276149Sae return (ENOBUFS); 110189494Smarius#ifndef __NO_STRICT_ALIGNMENT 111276149Sae if (proto == IPPROTO_ETHERIP) { 112189494Smarius len = mtod(m, vm_offset_t) & 3; 113189494Smarius KASSERT(len == 0 || len == ETHERIP_ALIGN, 114189494Smarius ("in_gif_output: unexpected misalignment")); 115189494Smarius m->m_data += len; 116189494Smarius m->m_len -= ETHERIP_ALIGN; 117189494Smarius } 118189494Smarius#endif 119276149Sae ip = mtod(m, struct ip *); 120276149Sae GIF_RLOCK(sc); 121276149Sae if (sc->gif_family != AF_INET) { 122276149Sae m_freem(m); 123276149Sae GIF_RUNLOCK(sc); 124276149Sae return (ENETDOWN); 12554263Sshin } 126276149Sae bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 127276149Sae GIF_RUNLOCK(sc); 12854263Sshin 129276149Sae ip->ip_p = proto; 130276149Sae /* version will be set in ip_output() */ 131276149Sae ip->ip_ttl = V_ip_gif_ttl; 132276149Sae ip->ip_len = htons(m->m_pkthdr.len); 133276149Sae ip->ip_tos = ecn; 13462587Sitojun 135276149Sae return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 136276149Sae} 13754263Sshin 138276149Saestatic void 139276149Saein_gif_input10(struct mbuf *m, int off) 140276149Sae{ 141276149Sae int proto; 142138470Sglebius 143276149Sae proto = (mtod(m, struct ip *))->ip_p; 144276149Sae in_gif_input(&m, &off, proto); 14554263Sshin} 14654263Sshin 147284072Saestatic int 148276149Saein_gif_input(struct mbuf **mp, int *offp, int proto) 14954263Sshin{ 150276149Sae struct mbuf *m = *mp; 151147503Sbz struct gif_softc *sc; 152276149Sae struct ifnet *gifp; 15354263Sshin struct ip *ip; 154276149Sae uint8_t ecn; 15554263Sshin 156276149Sae sc = encap_getarg(m); 157147503Sbz if (sc == NULL) { 158147503Sbz m_freem(m); 159196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 160276149Sae return (IPPROTO_DONE); 161147503Sbz } 162147503Sbz gifp = GIF2IFP(sc); 163276149Sae if ((gifp->if_flags & IFF_UP) != 0) { 164276149Sae ip = mtod(m, struct ip *); 165276149Sae ecn = ip->ip_tos; 166276149Sae m_adj(m, *offp); 167276149Sae gif_input(m, gifp, proto, ecn); 168276149Sae } else { 16954263Sshin m_freem(m); 170196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 17154263Sshin } 172276149Sae return (IPPROTO_DONE); 17354263Sshin} 17462587Sitojun 17562587Sitojun/* 176105293Sume * validate outer address. 17762587Sitojun */ 178105293Sumestatic int 179169454Srwatsongif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) 18062587Sitojun{ 181283852Sae int ret; 18262587Sitojun 183276149Sae GIF_RLOCK_ASSERT(sc); 18462587Sitojun 18562587Sitojun /* check for address match */ 186283852Sae if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 187276149Sae return (0); 188283852Sae ret = 32; 189283852Sae if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 190283852Sae if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 191283852Sae return (0); 192283852Sae } else 193283852Sae ret += 32; 19462587Sitojun 19562587Sitojun /* martian filters on outer source - NOT done in ip_input! */ 196105293Sume if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 197276149Sae return (0); 198105293Sume switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 199276149Sae case 0: 200276149Sae case 127: 201276149Sae case 255: 202276149Sae return (0); 20362587Sitojun } 204194951Srwatson 20562587Sitojun /* ingress filters on outer source */ 206147256Sbrooks if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 20762587Sitojun struct sockaddr_in sin; 20862587Sitojun struct rtentry *rt; 20962587Sitojun 21062587Sitojun bzero(&sin, sizeof(sin)); 21162587Sitojun sin.sin_family = AF_INET; 21262587Sitojun sin.sin_len = sizeof(struct sockaddr_in); 213105293Sume sin.sin_addr = ip->ip_src; 214178888Sjulian /* XXX MRT check for the interface we would use on output */ 215178888Sjulian rt = in_rtalloc1((struct sockaddr *)&sin, 0, 216178888Sjulian 0UL, sc->gif_fibnum); 217105293Sume if (!rt || rt->rt_ifp != ifp) { 21878064Sume if (rt) 219172307Scsjp RTFREE_LOCKED(rt); 220276149Sae return (0); 22162587Sitojun } 222172307Scsjp RTFREE_LOCKED(rt); 22362587Sitojun } 224283852Sae return (ret); 22562587Sitojun} 226105293Sume 227105293Sume/* 228105293Sume * we know that we are in IFF_UP, outer address available, and outer family 229105293Sume * matched the physical addr family. see gif_encapcheck(). 230105293Sume */ 231105293Sumeint 232276149Saein_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 233105293Sume{ 234105293Sume struct ip ip; 235105293Sume struct gif_softc *sc; 236105293Sume struct ifnet *ifp; 237105293Sume 238105293Sume /* sanity check done in caller */ 239105293Sume sc = (struct gif_softc *)arg; 240276149Sae GIF_RLOCK_ASSERT(sc); 241105293Sume 242105293Sume m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 243105293Sume ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 244276149Sae return (gif_validate4(&ip, sc, ifp)); 245105293Sume} 246105293Sume 247105293Sumeint 248169454Srwatsonin_gif_attach(struct gif_softc *sc) 249105293Sume{ 250276149Sae 251276149Sae KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 252276149Sae sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 253105293Sume &in_gif_protosw, sc); 254276149Sae if (sc->gif_ecookie == NULL) 255276149Sae return (EEXIST); 256276149Sae return (0); 257105293Sume} 258