1139823Simp/*- 2103026Ssobomax * Copyright (c) 1998 The NetBSD Foundation, Inc. 3284066Sae * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org> 4103026Ssobomax * All rights reserved. 5103026Ssobomax * 6103026Ssobomax * This code is derived from software contributed to The NetBSD Foundation 7103026Ssobomax * by Heiko W.Rupp <hwr@pilhuhn.de> 8103026Ssobomax * 9148613Sbz * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de> 10148613Sbz * 11103026Ssobomax * Redistribution and use in source and binary forms, with or without 12103026Ssobomax * modification, are permitted provided that the following conditions 13103026Ssobomax * are met: 14103026Ssobomax * 1. Redistributions of source code must retain the above copyright 15103026Ssobomax * notice, this list of conditions and the following disclaimer. 16103026Ssobomax * 2. Redistributions in binary form must reproduce the above copyright 17103026Ssobomax * notice, this list of conditions and the following disclaimer in the 18103026Ssobomax * documentation and/or other materials provided with the distribution. 19103026Ssobomax * 20103026Ssobomax * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21103026Ssobomax * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22103026Ssobomax * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23103026Ssobomax * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24103026Ssobomax * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25103026Ssobomax * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26103026Ssobomax * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27103026Ssobomax * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28103026Ssobomax * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29103026Ssobomax * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30103026Ssobomax * POSSIBILITY OF SUCH DAMAGE. 31284066Sae * 32284066Sae * $NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun Exp $ 33103026Ssobomax */ 34103026Ssobomax 35172467Ssilby#include <sys/cdefs.h> 36172467Ssilby__FBSDID("$FreeBSD$"); 37172467Ssilby 38103026Ssobomax#include "opt_inet.h" 39148613Sbz#include "opt_inet6.h" 40103026Ssobomax 41103026Ssobomax#include <sys/param.h> 42103026Ssobomax#include <sys/systm.h> 43103026Ssobomax#include <sys/mbuf.h> 44103026Ssobomax#include <sys/socket.h> 45103026Ssobomax#include <sys/socketvar.h> 46103026Ssobomax#include <sys/protosw.h> 47103026Ssobomax#include <sys/errno.h> 48103026Ssobomax#include <sys/time.h> 49103026Ssobomax#include <sys/kernel.h> 50284066Sae#include <sys/lock.h> 51284066Sae#include <sys/rmlock.h> 52284066Sae#include <sys/sysctl.h> 53103026Ssobomax#include <net/ethernet.h> 54103026Ssobomax#include <net/if.h> 55284066Sae#include <net/if_var.h> 56284066Sae#include <net/vnet.h> 57103026Ssobomax#include <net/raw_cb.h> 58103026Ssobomax 59103026Ssobomax#include <netinet/in.h> 60103026Ssobomax#include <netinet/in_var.h> 61103026Ssobomax#include <netinet/in_systm.h> 62103026Ssobomax#include <netinet/ip.h> 63284066Sae#include <netinet/ip_encap.h> 64103026Ssobomax#include <netinet/ip_var.h> 65103026Ssobomax#include <machine/in_cksum.h> 66103026Ssobomax 67284066Sae#ifdef INET6 68284066Sae#include <netinet/ip6.h> 69103026Ssobomax#endif 70103026Ssobomax 71103026Ssobomax/* Needs IP headers. */ 72103026Ssobomax#include <net/if_gre.h> 73103026Ssobomax#include <machine/stdarg.h> 74103026Ssobomax 75284066Saeextern struct domain inetdomain; 76284066Saestatic void gre_input10(struct mbuf *, int); 77284066Saestatic const struct protosw in_gre_protosw = { 78284066Sae .pr_type = SOCK_RAW, 79284066Sae .pr_domain = &inetdomain, 80284066Sae .pr_protocol = IPPROTO_GRE, 81284066Sae .pr_flags = PR_ATOMIC|PR_ADDR, 82284066Sae .pr_input = gre_input10, 83284066Sae .pr_output = (pr_output_t *)rip_output, 84284066Sae .pr_ctlinput = rip_ctlinput, 85284066Sae .pr_ctloutput = rip_ctloutput, 86284066Sae .pr_usrreqs = &rip_usrreqs 87284066Sae}; 88103026Ssobomax 89284066Sae#define GRE_TTL 30 90284066SaeVNET_DEFINE(int, ip_gre_ttl) = GRE_TTL; 91284066Sae#define V_ip_gre_ttl VNET(ip_gre_ttl) 92284066SaeSYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_RW, 93284066Sae &VNET_NAME(ip_gre_ttl), 0, ""); 94284066Sae 95284066Saestatic void 96284066Saegre_input10(struct mbuf *m, int off) 97103026Ssobomax{ 98158645Sglebius int proto; 99103026Ssobomax 100103026Ssobomax proto = (mtod(m, struct ip *))->ip_p; 101284066Sae gre_input(&m, &off, proto); 102103026Ssobomax} 103103026Ssobomax 104284066Saestatic int 105284066Saein_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 106103026Ssobomax{ 107284066Sae GRE_RLOCK_TRACKER; 108103026Ssobomax struct gre_softc *sc; 109284066Sae struct ip *ip; 110103026Ssobomax 111284066Sae sc = (struct gre_softc *)arg; 112284066Sae if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0) 113284066Sae return (0); 114103026Ssobomax 115284066Sae M_ASSERTPKTHDR(m); 116284066Sae /* 117284066Sae * We expect that payload contains at least IPv4 118284066Sae * or IPv6 packet. 119284066Sae */ 120284066Sae if (m->m_pkthdr.len < sizeof(struct greip) + sizeof(struct ip)) 121284066Sae return (0); 122123992Ssobomax 123284066Sae GRE_RLOCK(sc); 124284066Sae if (sc->gre_family == 0) 125284066Sae goto bad; 126103026Ssobomax 127284066Sae KASSERT(sc->gre_family == AF_INET, 128284066Sae ("wrong gre_family: %d", sc->gre_family)); 129103026Ssobomax 130284066Sae ip = mtod(m, struct ip *); 131284066Sae if (sc->gre_oip.ip_src.s_addr != ip->ip_dst.s_addr || 132284066Sae sc->gre_oip.ip_dst.s_addr != ip->ip_src.s_addr) 133284066Sae goto bad; 134103026Ssobomax 135284066Sae GRE_RUNLOCK(sc); 136284066Sae return (32 * 2); 137284066Saebad: 138284066Sae GRE_RUNLOCK(sc); 139284066Sae return (0); 140103026Ssobomax} 141103026Ssobomax 142284066Saeint 143284066Saein_gre_output(struct mbuf *m, int af, int hlen) 144103026Ssobomax{ 145284066Sae struct greip *gi; 146103026Ssobomax 147284066Sae gi = mtod(m, struct greip *); 148284066Sae switch (af) { 149284066Sae case AF_INET: 150284066Sae /* 151284066Sae * gre_transmit() has used M_PREPEND() that doesn't guarantee 152284066Sae * m_data is contiguous more than hlen bytes. Use m_copydata() 153284066Sae * here to avoid m_pullup(). 154284066Sae */ 155284066Sae m_copydata(m, hlen + offsetof(struct ip, ip_tos), 156284066Sae sizeof(u_char), &gi->gi_ip.ip_tos); 157284066Sae m_copydata(m, hlen + offsetof(struct ip, ip_id), 158284066Sae sizeof(u_short), (caddr_t)&gi->gi_ip.ip_id); 159284066Sae break; 160284066Sae#ifdef INET6 161284066Sae case AF_INET6: 162284066Sae gi->gi_ip.ip_tos = 0; /* XXX */ 163284066Sae gi->gi_ip.ip_id = ip_newid(); 164284066Sae break; 165284066Sae#endif 166103026Ssobomax } 167284066Sae gi->gi_ip.ip_ttl = V_ip_gre_ttl; 168284066Sae gi->gi_ip.ip_len = htons(m->m_pkthdr.len); 169284066Sae return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL)); 170103026Ssobomax} 171103026Ssobomax 172284066Saeint 173284066Saein_gre_attach(struct gre_softc *sc) 174103026Ssobomax{ 175103026Ssobomax 176284066Sae KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL")); 177284066Sae sc->gre_ecookie = encap_attach_func(AF_INET, IPPROTO_GRE, 178284066Sae in_gre_encapcheck, &in_gre_protosw, sc); 179284066Sae if (sc->gre_ecookie == NULL) 180284066Sae return (EEXIST); 181284066Sae return (0); 182103026Ssobomax} 183