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. 28273087Sae * 29273087Sae * $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: releng/11.0/sys/netinet/in_gif.c 291993 2015-12-08 10:50:03Z melifaro $"); 34172467Ssilby 3562587Sitojun#include "opt_inet.h" 3654263Sshin#include "opt_inet6.h" 3754263Sshin 3854263Sshin#include <sys/param.h> 39273087Sae#include <sys/lock.h> 40273087Sae#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> 52257176Sglebius#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> 63291993Smelifaro#include <netinet/in_fib.h> 6462587Sitojun 6554263Sshin#ifdef INET6 6662587Sitojun#include <netinet/ip6.h> 6754263Sshin#endif 6854263Sshin 69273087Sae#include <net/if_gif.h> 7054263Sshin 71276148Saestatic int in_gif_input(struct mbuf **, int *, int); 72105293Sume 73105293Sumeextern struct domain inetdomain; 74276148Saestatic struct protosw in_gif_protosw = { 75152242Sru .pr_type = SOCK_RAW, 76152242Sru .pr_domain = &inetdomain, 77152242Sru .pr_protocol = 0/* IPPROTO_IPV[46] */, 78152242Sru .pr_flags = PR_ATOMIC|PR_ADDR, 79152242Sru .pr_input = in_gif_input, 80270008Skevlo .pr_output = rip_output, 81152242Sru .pr_ctloutput = rip_ctloutput, 82152242Sru .pr_usrreqs = &rip_usrreqs 83105293Sume}; 84105293Sume 85276148Sae#define GIF_TTL 30 86276148Saestatic VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 87207369Sbz#define V_ip_gif_ttl VNET(ip_gif_ttl) 88274225SglebiusSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, 89195699Srwatson &VNET_NAME(ip_gif_ttl), 0, ""); 9054263Sshin 9154263Sshinint 92273087Saein_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 9354263Sshin{ 94273087Sae GIF_RLOCK_TRACKER; 95147256Sbrooks struct gif_softc *sc = ifp->if_softc; 96273087Sae struct ip *ip; 97273087Sae int len; 9854263Sshin 9954263Sshin /* prepend new IP header */ 100189494Smarius len = sizeof(struct ip); 101189494Smarius#ifndef __NO_STRICT_ALIGNMENT 102273087Sae if (proto == IPPROTO_ETHERIP) 103189494Smarius len += ETHERIP_ALIGN; 104189494Smarius#endif 105243882Sglebius M_PREPEND(m, len, M_NOWAIT); 106273087Sae if (m == NULL) 107273087Sae return (ENOBUFS); 108189494Smarius#ifndef __NO_STRICT_ALIGNMENT 109273087Sae if (proto == IPPROTO_ETHERIP) { 110189494Smarius len = mtod(m, vm_offset_t) & 3; 111189494Smarius KASSERT(len == 0 || len == ETHERIP_ALIGN, 112189494Smarius ("in_gif_output: unexpected misalignment")); 113189494Smarius m->m_data += len; 114189494Smarius m->m_len -= ETHERIP_ALIGN; 115189494Smarius } 116189494Smarius#endif 117273087Sae ip = mtod(m, struct ip *); 118273087Sae GIF_RLOCK(sc); 119273087Sae if (sc->gif_family != AF_INET) { 120273087Sae m_freem(m); 121273087Sae GIF_RUNLOCK(sc); 122273087Sae return (ENETDOWN); 12354263Sshin } 124273087Sae bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 125273087Sae GIF_RUNLOCK(sc); 12654263Sshin 127273087Sae ip->ip_p = proto; 128273087Sae /* version will be set in ip_output() */ 129273087Sae ip->ip_ttl = V_ip_gif_ttl; 130273087Sae ip->ip_len = htons(m->m_pkthdr.len); 131273087Sae ip->ip_tos = ecn; 13262587Sitojun 133273087Sae return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 13454263Sshin} 13554263Sshin 136276148Saestatic int 137269699Skevloin_gif_input(struct mbuf **mp, int *offp, int proto) 13854263Sshin{ 139273087Sae struct mbuf *m = *mp; 140147503Sbz struct gif_softc *sc; 141273087Sae struct ifnet *gifp; 14254263Sshin struct ip *ip; 143273087Sae uint8_t ecn; 14454263Sshin 145273087Sae sc = encap_getarg(m); 146147503Sbz if (sc == NULL) { 147147503Sbz m_freem(m); 148196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 149269699Skevlo return (IPPROTO_DONE); 150147503Sbz } 151147503Sbz gifp = GIF2IFP(sc); 152273087Sae if ((gifp->if_flags & IFF_UP) != 0) { 153273087Sae ip = mtod(m, struct ip *); 154273087Sae ecn = ip->ip_tos; 155273087Sae m_adj(m, *offp); 156273087Sae gif_input(m, gifp, proto, ecn); 157273087Sae } else { 15854263Sshin m_freem(m); 159196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 16054263Sshin } 161269699Skevlo return (IPPROTO_DONE); 16254263Sshin} 16362587Sitojun 16462587Sitojun/* 165286013Sae * we know that we are in IFF_UP, outer address available, and outer family 166286013Sae * matched the physical addr family. see gif_encapcheck(). 16762587Sitojun */ 168286013Saeint 169286013Saein_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 17062587Sitojun{ 171286013Sae const struct ip *ip; 172286013Sae struct gif_softc *sc; 173282965Sae int ret; 17462587Sitojun 175286013Sae /* sanity check done in caller */ 176286013Sae sc = (struct gif_softc *)arg; 177273087Sae GIF_RLOCK_ASSERT(sc); 17862587Sitojun 17962587Sitojun /* check for address match */ 180286013Sae ip = mtod(m, const struct ip *); 181282965Sae if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 182273087Sae return (0); 183282965Sae ret = 32; 184282965Sae if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 185282965Sae if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 186282965Sae return (0); 187282965Sae } else 188282965Sae ret += 32; 18962587Sitojun 19062587Sitojun /* ingress filters on outer source */ 191286013Sae if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { 192291993Smelifaro struct nhop4_basic nh4; 193291993Smelifaro struct in_addr dst; 19462587Sitojun 195291993Smelifaro dst = ip->ip_src; 196291993Smelifaro 197291993Smelifaro if (fib4_lookup_nh_basic(sc->gif_fibnum, dst, 0, 0, &nh4) != 0) 198273087Sae return (0); 199291993Smelifaro 200291993Smelifaro if (nh4.nh_ifp != m->m_pkthdr.rcvif) 201291993Smelifaro return (0); 20262587Sitojun } 203282965Sae return (ret); 20462587Sitojun} 205105293Sume 206105293Sumeint 207169454Srwatsonin_gif_attach(struct gif_softc *sc) 208105293Sume{ 209273087Sae 210273087Sae KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 211273087Sae sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 212105293Sume &in_gif_protosw, sc); 213273087Sae if (sc->gif_ecookie == NULL) 214273087Sae return (EEXIST); 215273087Sae return (0); 216105293Sume} 217