in_gif.c revision 286013
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: head/sys/netinet/in_gif.c 286013 2015-07-29 14:07:43Z ae $"); 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> 6362587Sitojun 6454263Sshin#ifdef INET6 6562587Sitojun#include <netinet/ip6.h> 6654263Sshin#endif 6754263Sshin 68273087Sae#include <net/if_gif.h> 6954263Sshin 70276148Saestatic int in_gif_input(struct mbuf **, int *, int); 71105293Sume 72105293Sumeextern struct domain inetdomain; 73276148Saestatic struct protosw in_gif_protosw = { 74152242Sru .pr_type = SOCK_RAW, 75152242Sru .pr_domain = &inetdomain, 76152242Sru .pr_protocol = 0/* IPPROTO_IPV[46] */, 77152242Sru .pr_flags = PR_ATOMIC|PR_ADDR, 78152242Sru .pr_input = in_gif_input, 79270008Skevlo .pr_output = rip_output, 80152242Sru .pr_ctloutput = rip_ctloutput, 81152242Sru .pr_usrreqs = &rip_usrreqs 82105293Sume}; 83105293Sume 84276148Sae#define GIF_TTL 30 85276148Saestatic VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 86207369Sbz#define V_ip_gif_ttl VNET(ip_gif_ttl) 87274225SglebiusSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, 88195699Srwatson &VNET_NAME(ip_gif_ttl), 0, ""); 8954263Sshin 9054263Sshinint 91273087Saein_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 9254263Sshin{ 93273087Sae GIF_RLOCK_TRACKER; 94147256Sbrooks struct gif_softc *sc = ifp->if_softc; 95273087Sae struct ip *ip; 96273087Sae int len; 9754263Sshin 9854263Sshin /* prepend new IP header */ 99189494Smarius len = sizeof(struct ip); 100189494Smarius#ifndef __NO_STRICT_ALIGNMENT 101273087Sae if (proto == IPPROTO_ETHERIP) 102189494Smarius len += ETHERIP_ALIGN; 103189494Smarius#endif 104243882Sglebius M_PREPEND(m, len, M_NOWAIT); 105273087Sae if (m == NULL) 106273087Sae return (ENOBUFS); 107189494Smarius#ifndef __NO_STRICT_ALIGNMENT 108273087Sae if (proto == IPPROTO_ETHERIP) { 109189494Smarius len = mtod(m, vm_offset_t) & 3; 110189494Smarius KASSERT(len == 0 || len == ETHERIP_ALIGN, 111189494Smarius ("in_gif_output: unexpected misalignment")); 112189494Smarius m->m_data += len; 113189494Smarius m->m_len -= ETHERIP_ALIGN; 114189494Smarius } 115189494Smarius#endif 116273087Sae ip = mtod(m, struct ip *); 117273087Sae GIF_RLOCK(sc); 118273087Sae if (sc->gif_family != AF_INET) { 119273087Sae m_freem(m); 120273087Sae GIF_RUNLOCK(sc); 121273087Sae return (ENETDOWN); 12254263Sshin } 123273087Sae bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 124273087Sae GIF_RUNLOCK(sc); 12554263Sshin 126273087Sae ip->ip_p = proto; 127273087Sae /* version will be set in ip_output() */ 128273087Sae ip->ip_ttl = V_ip_gif_ttl; 129273087Sae ip->ip_len = htons(m->m_pkthdr.len); 130273087Sae ip->ip_tos = ecn; 13162587Sitojun 132273087Sae return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 13354263Sshin} 13454263Sshin 135276148Saestatic int 136269699Skevloin_gif_input(struct mbuf **mp, int *offp, int proto) 13754263Sshin{ 138273087Sae struct mbuf *m = *mp; 139147503Sbz struct gif_softc *sc; 140273087Sae struct ifnet *gifp; 14154263Sshin struct ip *ip; 142273087Sae uint8_t ecn; 14354263Sshin 144273087Sae sc = encap_getarg(m); 145147503Sbz if (sc == NULL) { 146147503Sbz m_freem(m); 147196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 148269699Skevlo return (IPPROTO_DONE); 149147503Sbz } 150147503Sbz gifp = GIF2IFP(sc); 151273087Sae if ((gifp->if_flags & IFF_UP) != 0) { 152273087Sae ip = mtod(m, struct ip *); 153273087Sae ecn = ip->ip_tos; 154273087Sae m_adj(m, *offp); 155273087Sae gif_input(m, gifp, proto, ecn); 156273087Sae } else { 15754263Sshin m_freem(m); 158196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 15954263Sshin } 160269699Skevlo return (IPPROTO_DONE); 16154263Sshin} 16262587Sitojun 16362587Sitojun/* 164286013Sae * we know that we are in IFF_UP, outer address available, and outer family 165286013Sae * matched the physical addr family. see gif_encapcheck(). 16662587Sitojun */ 167286013Saeint 168286013Saein_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 16962587Sitojun{ 170286013Sae const struct ip *ip; 171286013Sae struct gif_softc *sc; 172282965Sae int ret; 17362587Sitojun 174286013Sae /* sanity check done in caller */ 175286013Sae sc = (struct gif_softc *)arg; 176273087Sae GIF_RLOCK_ASSERT(sc); 17762587Sitojun 17862587Sitojun /* check for address match */ 179286013Sae ip = mtod(m, const struct ip *); 180282965Sae if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 181273087Sae return (0); 182282965Sae ret = 32; 183282965Sae if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 184282965Sae if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 185282965Sae return (0); 186282965Sae } else 187282965Sae ret += 32; 18862587Sitojun 18962587Sitojun /* ingress filters on outer source */ 190286013Sae if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { 19162587Sitojun struct sockaddr_in sin; 19262587Sitojun struct rtentry *rt; 19362587Sitojun 19462587Sitojun bzero(&sin, sizeof(sin)); 19562587Sitojun sin.sin_family = AF_INET; 19662587Sitojun sin.sin_len = sizeof(struct sockaddr_in); 197105293Sume sin.sin_addr = ip->ip_src; 198178888Sjulian /* XXX MRT check for the interface we would use on output */ 199178888Sjulian rt = in_rtalloc1((struct sockaddr *)&sin, 0, 200178888Sjulian 0UL, sc->gif_fibnum); 201286013Sae if (rt == NULL || rt->rt_ifp != m->m_pkthdr.rcvif) { 202286013Sae if (rt != NULL) 203172307Scsjp RTFREE_LOCKED(rt); 204273087Sae return (0); 20562587Sitojun } 206172307Scsjp RTFREE_LOCKED(rt); 20762587Sitojun } 208282965Sae return (ret); 20962587Sitojun} 210105293Sume 211105293Sumeint 212169454Srwatsonin_gif_attach(struct gif_softc *sc) 213105293Sume{ 214273087Sae 215273087Sae KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 216273087Sae sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 217105293Sume &in_gif_protosw, sc); 218273087Sae if (sc->gif_ecookie == NULL) 219273087Sae return (EEXIST); 220273087Sae return (0); 221105293Sume} 222