in_gif.c revision 291993
1116743Ssam/*- 2186904Ssam * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3116743Ssam * All rights reserved. 4116743Ssam * 5116743Ssam * Redistribution and use in source and binary forms, with or without 6116743Ssam * modification, are permitted provided that the following conditions 7116743Ssam * are met: 8116743Ssam * 1. Redistributions of source code must retain the above copyright 9116743Ssam * notice, this list of conditions and the following disclaimer. 10116743Ssam * 2. Redistributions in binary form must reproduce the above copyright 11116743Ssam * notice, this list of conditions and the following disclaimer in the 12116743Ssam * documentation and/or other materials provided with the distribution. 13116743Ssam * 3. Neither the name of the project nor the names of its contributors 14116743Ssam * may be used to endorse or promote products derived from this software 15116743Ssam * without specific prior written permission. 16116743Ssam * 17116743Ssam * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18116743Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19116743Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20116743Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21116743Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22116743Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23116743Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24116743Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25116743Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26116743Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27116743Ssam * SUCH DAMAGE. 28116743Ssam * 29116743Ssam * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ 30116743Ssam */ 31116743Ssam 32116743Ssam#include <sys/cdefs.h> 33116743Ssam__FBSDID("$FreeBSD: head/sys/netinet/in_gif.c 291993 2015-12-08 10:50:03Z melifaro $"); 34116743Ssam 35116743Ssam#include "opt_inet.h" 36116743Ssam#include "opt_inet6.h" 37116743Ssam 38227327Sadrian#include <sys/param.h> 39227327Sadrian#include <sys/lock.h> 40227327Sadrian#include <sys/rmlock.h> 41227327Sadrian#include <sys/systm.h> 42227327Sadrian#include <sys/socket.h> 43227327Sadrian#include <sys/sockio.h> 44227327Sadrian#include <sys/mbuf.h> 45227327Sadrian#include <sys/errno.h> 46227327Sadrian#include <sys/kernel.h> 47227327Sadrian#include <sys/sysctl.h> 48116743Ssam#include <sys/protosw.h> 49116743Ssam#include <sys/malloc.h> 50116743Ssam 51116743Ssam#include <net/if.h> 52155492Ssam#include <net/if_var.h> 53138570Ssam#include <net/route.h> 54116743Ssam#include <net/vnet.h> 55116743Ssam 56116743Ssam#include <netinet/in.h> 57138570Ssam#include <netinet/in_systm.h> 58116743Ssam#include <netinet/ip.h> 59138570Ssam#include <netinet/ip_var.h> 60116743Ssam#include <netinet/in_var.h> 61116743Ssam#include <netinet/ip_encap.h> 62116743Ssam#include <netinet/ip_ecn.h> 63116743Ssam#include <netinet/in_fib.h> 64116743Ssam 65116743Ssam#ifdef INET6 66116743Ssam#include <netinet/ip6.h> 67116743Ssam#endif 68116743Ssam 69116743Ssam#include <net/if_gif.h> 70116743Ssam 71116743Ssamstatic int in_gif_input(struct mbuf **, int *, int); 72116743Ssam 73116743Ssamextern struct domain inetdomain; 74116743Ssamstatic struct protosw in_gif_protosw = { 75116743Ssam .pr_type = SOCK_RAW, 76116743Ssam .pr_domain = &inetdomain, 77116743Ssam .pr_protocol = 0/* IPPROTO_IPV[46] */, 78116743Ssam .pr_flags = PR_ATOMIC|PR_ADDR, 79116743Ssam .pr_input = in_gif_input, 80127779Ssam .pr_output = rip_output, 81127779Ssam .pr_ctloutput = rip_ctloutput, 82170530Ssam .pr_usrreqs = &rip_usrreqs 83170530Ssam}; 84116743Ssam 85116743Ssam#define GIF_TTL 30 86116743Ssamstatic VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 87116743Ssam#define V_ip_gif_ttl VNET(ip_gif_ttl) 88116743SsamSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, 89116743Ssam &VNET_NAME(ip_gif_ttl), 0, ""); 90138570Ssam 91116743Ssamint 92218689Sadrianin_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 93119147Ssam{ 94127779Ssam GIF_RLOCK_TRACKER; 95138570Ssam struct gif_softc *sc = ifp->if_softc; 96138570Ssam struct ip *ip; 97119147Ssam int len; 98138570Ssam 99138570Ssam /* prepend new IP header */ 100161187Ssam len = sizeof(struct ip); 101138570Ssam#ifndef __NO_STRICT_ALIGNMENT 102116743Ssam if (proto == IPPROTO_ETHERIP) 103116743Ssam len += ETHERIP_ALIGN; 104116743Ssam#endif 105116743Ssam M_PREPEND(m, len, M_NOWAIT); 106116743Ssam if (m == NULL) 107116743Ssam return (ENOBUFS); 108116743Ssam#ifndef __NO_STRICT_ALIGNMENT 109138570Ssam if (proto == IPPROTO_ETHERIP) { 110138570Ssam len = mtod(m, vm_offset_t) & 3; 111138570Ssam KASSERT(len == 0 || len == ETHERIP_ALIGN, 112138570Ssam ("in_gif_output: unexpected misalignment")); 113159894Ssam m->m_data += len; 114159894Ssam m->m_len -= ETHERIP_ALIGN; 115160992Ssam } 116170530Ssam#endif 117170530Ssam ip = mtod(m, struct ip *); 118170530Ssam GIF_RLOCK(sc); 119170530Ssam if (sc->gif_family != AF_INET) { 120170530Ssam m_freem(m); 121170530Ssam GIF_RUNLOCK(sc); 122186904Ssam return (ENETDOWN); 123186904Ssam } 124186904Ssam bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 125186904Ssam GIF_RUNLOCK(sc); 126186904Ssam 127186904Ssam ip->ip_p = proto; 128188195Ssam /* version will be set in ip_output() */ 129188195Ssam ip->ip_ttl = V_ip_gif_ttl; 130188555Ssam ip->ip_len = htons(m->m_pkthdr.len); 131211299Sadrian ip->ip_tos = ecn; 132217684Sadrian 133218378Sadrian return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 134221965Sadrian} 135221965Sadrian 136221965Sadrianstatic int 137221965Sadrianin_gif_input(struct mbuf **mp, int *offp, int proto) 138221965Sadrian{ 139218689Sadrian struct mbuf *m = *mp; 140218924Sadrian struct gif_softc *sc; 141221965Sadrian struct ifnet *gifp; 142220772Sadrian struct ip *ip; 143220782Sadrian uint8_t ecn; 144221965Sadrian 145221965Sadrian sc = encap_getarg(m); 146221965Sadrian if (sc == NULL) { 147226798Sadrian m_freem(m); 148226798Sadrian KMOD_IPSTAT_INC(ips_nogif); 149226798Sadrian return (IPPROTO_DONE); 150226798Sadrian } 151226798Sadrian gifp = GIF2IFP(sc); 152226798Sadrian if ((gifp->if_flags & IFF_UP) != 0) { 153226798Sadrian ip = mtod(m, struct ip *); 154226798Sadrian ecn = ip->ip_tos; 155226798Sadrian m_adj(m, *offp); 156226798Sadrian gif_input(m, gifp, proto, ecn); 157116743Ssam } else { 158116743Ssam m_freem(m); 159116743Ssam KMOD_IPSTAT_INC(ips_nogif); 160188557Ssam } 161116743Ssam return (IPPROTO_DONE); 162123044Ssam} 163138570Ssam 164138570Ssam/* 165138570Ssam * we know that we are in IFF_UP, outer address available, and outer family 166138570Ssam * matched the physical addr family. see gif_encapcheck(). 167138570Ssam */ 168138570Ssamint 169138570Ssamin_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 170138570Ssam{ 171138570Ssam const struct ip *ip; 172138570Ssam struct gif_softc *sc; 173123044Ssam int ret; 174123044Ssam 175123044Ssam /* sanity check done in caller */ 176224245Sadrian sc = (struct gif_softc *)arg; 177123044Ssam GIF_RLOCK_ASSERT(sc); 178119783Ssam 179119783Ssam /* check for address match */ 180119783Ssam ip = mtod(m, const struct ip *); 181119783Ssam if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 182154140Ssam return (0); 183119783Ssam ret = 32; 184119783Ssam if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 185123928Ssam if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 186154140Ssam return (0); 187154140Ssam } else 188170530Ssam ret += 32; 189119783Ssam 190119783Ssam /* ingress filters on outer source */ 191119783Ssam if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { 192119783Ssam struct nhop4_basic nh4; 193154140Ssam struct in_addr dst; 194154140Ssam 195119783Ssam dst = ip->ip_src; 196170530Ssam 197170530Ssam if (fib4_lookup_nh_basic(sc->gif_fibnum, dst, 0, 0, &nh4) != 0) 198170530Ssam return (0); 199170530Ssam 200170530Ssam if (nh4.nh_ifp != m->m_pkthdr.rcvif) 201119783Ssam return (0); 202170530Ssam } 203170530Ssam return (ret); 204170530Ssam} 205119783Ssam 206119783Ssamint 207154140Ssamin_gif_attach(struct gif_softc *sc) 208119783Ssam{ 209119783Ssam 210123928Ssam KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 211123928Ssam sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 212170530Ssam &in_gif_protosw, sc); 213119783Ssam if (sc->gif_ecookie == NULL) 214119783Ssam return (EEXIST); 215119783Ssam return (0); 216119783Ssam} 217154140Ssam