197403Sobrien/*- 297403Sobrien * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org> 3117397Skan * All rights reserved. 497403Sobrien * 5103447Skan * Redistribution and use in source and binary forms, with or without 6103447Skan * modification, are permitted provided that the following conditions 7103447Skan * are met: 8103447Skan * 997403Sobrien * 1. Redistributions of source code must retain the above copyright 10103447Skan * notice, this list of conditions and the following disclaimer. 11103447Skan * 2. Redistributions in binary form must reproduce the above copyright 1297403Sobrien * notice, this list of conditions and the following disclaimer in the 1397403Sobrien * documentation and/or other materials provided with the distribution. 1497403Sobrien * 1597403Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16103447Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17103447Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18169691Skan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19103447Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20103447Skan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2197403Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2297403Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2397403Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2497403Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2597403Sobrien */ 2697403Sobrien 2797403Sobrien#include <sys/cdefs.h> 2897403Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/netinet6/ip6_gre.c 284072 2015-06-06 13:26:13Z ae $"); 2997403Sobrien 3097403Sobrien#include "opt_inet.h" 3197403Sobrien#include "opt_inet6.h" 3297403Sobrien 3397403Sobrien#include <sys/param.h> 3497403Sobrien#include <sys/lock.h> 3597403Sobrien#include <sys/rmlock.h> 3697403Sobrien#include <sys/systm.h> 3797403Sobrien#include <sys/socket.h> 3897403Sobrien#include <sys/sockio.h> 39132720Skan#include <sys/mbuf.h> 4097403Sobrien#include <sys/errno.h> 4197403Sobrien#include <sys/kernel.h> 42117397Skan#include <sys/queue.h> 4397403Sobrien#include <sys/syslog.h> 4497403Sobrien#include <sys/sysctl.h> 4597403Sobrien#include <sys/protosw.h> 4697403Sobrien#include <sys/malloc.h> 47169691Skan 48169691Skan#include <net/if.h> 4997403Sobrien#include <net/if_var.h> 5097403Sobrien#include <net/vnet.h> 5197403Sobrien 5297403Sobrien#include <netinet/in.h> 5397403Sobrien#include <netinet/in_systm.h> 5497403Sobrien#ifdef INET 5597403Sobrien#include <net/ethernet.h> 5697403Sobrien#include <netinet/ip.h> 57132720Skan#endif 5897403Sobrien#include <netinet/ip_encap.h> 5997403Sobrien#include <netinet/ip6.h> 6097403Sobrien#include <netinet6/ip6protosw.h> 6197403Sobrien#include <netinet6/ip6_var.h> 6297403Sobrien#include <netinet6/in6_var.h> 6397403Sobrien#include <net/if_gre.h> 6497403Sobrien 6597403Sobrienextern struct domain inet6domain; 6697403Sobrienstruct ip6protosw in6_gre_protosw = { 6797403Sobrien .pr_type = SOCK_RAW, 6897403Sobrien .pr_domain = &inet6domain, 6997403Sobrien .pr_protocol = IPPROTO_GRE, 7097403Sobrien .pr_flags = PR_ATOMIC|PR_ADDR, 7197403Sobrien .pr_input = gre_input, 7297403Sobrien .pr_output = rip6_output, 7397403Sobrien .pr_ctloutput = rip6_ctloutput, 7497403Sobrien .pr_usrreqs = &rip6_usrreqs 7597403Sobrien}; 7697403Sobrien 7797403SobrienVNET_DEFINE(int, ip6_gre_hlim) = IPV6_DEFHLIM; 78132720Skan#define V_ip6_gre_hlim VNET(ip6_gre_hlim) 7997403Sobrien 8097403SobrienSYSCTL_DECL(_net_inet6_ip6); 8197403SobrienSYSCTL_INT(_net_inet6_ip6, OID_AUTO, grehlim, CTLFLAG_VNET | CTLFLAG_RW, 8297403Sobrien &VNET_NAME(ip6_gre_hlim), 0, "Default hop limit for encapsulated packets"); 8397403Sobrien 8497403Sobrienstatic int 8597403Sobrienin6_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 8697403Sobrien{ 8797403Sobrien GRE_RLOCK_TRACKER; 8897403Sobrien struct gre_softc *sc; 8997403Sobrien struct ip6_hdr *ip6; 9097403Sobrien 9197403Sobrien sc = (struct gre_softc *)arg; 9297403Sobrien if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0) 93132720Skan return (0); 9497403Sobrien 9597403Sobrien M_ASSERTPKTHDR(m); 9697403Sobrien /* 9797403Sobrien * We expect that payload contains at least IPv4 9897403Sobrien * or IPv6 packet. 9997403Sobrien */ 10097403Sobrien if (m->m_pkthdr.len < sizeof(struct greip6) + 10197403Sobrien#ifdef INET 10297403Sobrien sizeof(struct ip)) 10397403Sobrien#else 10497403Sobrien sizeof(struct ip6_hdr)) 10597403Sobrien#endif 10697403Sobrien return (0); 10797403Sobrien 10897403Sobrien GRE_RLOCK(sc); 109169691Skan if (sc->gre_family == 0) 110169691Skan goto bad; 11197403Sobrien 11297403Sobrien KASSERT(sc->gre_family == AF_INET6, 11397403Sobrien ("wrong gre_family: %d", sc->gre_family)); 114 115 ip6 = mtod(m, struct ip6_hdr *); 116 if (!IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src, &ip6->ip6_dst) || 117 !IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, &ip6->ip6_src)) 118 goto bad; 119 120 GRE_RUNLOCK(sc); 121 return (128 * 2); 122bad: 123 GRE_RUNLOCK(sc); 124 return (0); 125} 126 127int 128in6_gre_output(struct mbuf *m, int af, int hlen) 129{ 130 struct greip6 *gi6; 131 132 gi6 = mtod(m, struct greip6 *); 133 gi6->gi6_ip6.ip6_hlim = V_ip6_gre_hlim; 134 return (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, NULL)); 135} 136 137int 138in6_gre_attach(struct gre_softc *sc) 139{ 140 141 KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL")); 142 sc->gre_ecookie = encap_attach_func(AF_INET6, IPPROTO_GRE, 143 in6_gre_encapcheck, (void *)&in6_gre_protosw, sc); 144 if (sc->gre_ecookie == NULL) 145 return (EEXIST); 146 return (0); 147} 148