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: if_gre.c,v 1.49 2003/12/11 00:22:29 itojun Exp $ 33103026Ssobomax */ 34103026Ssobomax 35284066Sae#include <sys/cdefs.h> 36284066Sae__FBSDID("$FreeBSD$"); 37103026Ssobomax 38103026Ssobomax#include "opt_inet.h" 39122699Sbms#include "opt_inet6.h" 40103026Ssobomax 41103026Ssobomax#include <sys/param.h> 42219206Sbz#include <sys/jail.h> 43103026Ssobomax#include <sys/kernel.h> 44284066Sae#include <sys/lock.h> 45223223Sbz#include <sys/libkern.h> 46103026Ssobomax#include <sys/malloc.h> 47129880Sphk#include <sys/module.h> 48103026Ssobomax#include <sys/mbuf.h> 49164033Srwatson#include <sys/priv.h> 50178888Sjulian#include <sys/proc.h> 51103026Ssobomax#include <sys/protosw.h> 52284066Sae#include <sys/rmlock.h> 53103026Ssobomax#include <sys/socket.h> 54103026Ssobomax#include <sys/sockio.h> 55284066Sae#include <sys/sx.h> 56103026Ssobomax#include <sys/sysctl.h> 57284066Sae#include <sys/syslog.h> 58103344Sbde#include <sys/systm.h> 59103026Ssobomax 60103026Ssobomax#include <net/ethernet.h> 61103026Ssobomax#include <net/if.h> 62130933Sbrooks#include <net/if_clone.h> 63284066Sae#include <net/if_var.h> 64103026Ssobomax#include <net/if_types.h> 65284066Sae#include <net/netisr.h> 66196019Srwatson#include <net/vnet.h> 67284074Sae#include <net/route.h> 68103026Ssobomax 69284066Sae#include <netinet/in.h> 70103026Ssobomax#ifdef INET 71103026Ssobomax#include <netinet/in_systm.h> 72103026Ssobomax#include <netinet/in_var.h> 73103026Ssobomax#include <netinet/ip.h> 74103026Ssobomax#include <netinet/ip_var.h> 75103026Ssobomax#endif 76103026Ssobomax 77284066Sae#ifdef INET6 78284066Sae#include <netinet/ip6.h> 79284066Sae#include <netinet6/in6_var.h> 80284066Sae#include <netinet6/ip6_var.h> 81284066Sae#include <netinet6/scope6_var.h> 82284066Sae#endif 83284066Sae 84284066Sae#include <netinet/ip_encap.h> 85103026Ssobomax#include <net/bpf.h> 86103026Ssobomax#include <net/if_gre.h> 87103026Ssobomax 88284066Sae#include <machine/in_cksum.h> 89103026Ssobomax 90284066Sae#include <security/mac/mac_framework.h> 91284066Sae#define GREMTU 1500 92241610Sglebiusstatic const char grename[] = "gre"; 93241610Sglebiusstatic MALLOC_DEFINE(M_GRE, grename, "Generic Routing Encapsulation"); 94284066Saestatic VNET_DEFINE(struct mtx, gre_mtx); 95284066Sae#define V_gre_mtx VNET(gre_mtx) 96284066Sae#define GRE_LIST_LOCK_INIT(x) mtx_init(&V_gre_mtx, "gre_mtx", NULL, \ 97284066Sae MTX_DEF) 98284066Sae#define GRE_LIST_LOCK_DESTROY(x) mtx_destroy(&V_gre_mtx) 99284066Sae#define GRE_LIST_LOCK(x) mtx_lock(&V_gre_mtx) 100284066Sae#define GRE_LIST_UNLOCK(x) mtx_unlock(&V_gre_mtx) 101103026Ssobomax 102284066Saestatic VNET_DEFINE(LIST_HEAD(, gre_softc), gre_softc_list); 103284066Sae#define V_gre_softc_list VNET(gre_softc_list) 104284066Saestatic struct sx gre_ioctl_sx; 105284066SaeSX_SYSINIT(gre_ioctl_sx, &gre_ioctl_sx, "gre_ioctl"); 106284066Sae 107160195Ssamstatic int gre_clone_create(struct if_clone *, int, caddr_t); 108105300Salfredstatic void gre_clone_destroy(struct ifnet *); 109284018Saestatic VNET_DEFINE(struct if_clone *, gre_cloner); 110284018Sae#define V_gre_cloner VNET(gre_cloner) 111241610Sglebius 112284066Saestatic void gre_qflush(struct ifnet *); 113284066Saestatic int gre_transmit(struct ifnet *, struct mbuf *); 114103032Ssobomaxstatic int gre_ioctl(struct ifnet *, u_long, caddr_t); 115249925Sglebiusstatic int gre_output(struct ifnet *, struct mbuf *, 116249925Sglebius const struct sockaddr *, struct route *); 117103026Ssobomax 118284066Saestatic void gre_updatehdr(struct gre_softc *); 119284066Saestatic int gre_set_tunnel(struct ifnet *, struct sockaddr *, 120284066Sae struct sockaddr *); 121284066Saestatic void gre_delete_tunnel(struct ifnet *); 122103026Ssobomax 123103026SsobomaxSYSCTL_DECL(_net_link); 124227309Sedstatic SYSCTL_NODE(_net_link, IFT_TUNNEL, gre, CTLFLAG_RW, 0, 125103026Ssobomax "Generic Routing Encapsulation"); 126103026Ssobomax#ifndef MAX_GRE_NEST 127103026Ssobomax/* 128103026Ssobomax * This macro controls the default upper limitation on nesting of gre tunnels. 129103026Ssobomax * Since, setting a large value to this macro with a careless configuration 130103026Ssobomax * may introduce system crash, we don't allow any nestings by default. 131103026Ssobomax * If you need to configure nested gre tunnels, you can define this macro 132103026Ssobomax * in your kernel configuration file. However, if you do so, please be 133103026Ssobomax * careful to configure the tunnels so that it won't make a loop. 134103026Ssobomax */ 135103026Ssobomax#define MAX_GRE_NEST 1 136103026Ssobomax#endif 137284066Sae 138284018Saestatic VNET_DEFINE(int, max_gre_nesting) = MAX_GRE_NEST; 139284018Sae#define V_max_gre_nesting VNET(max_gre_nesting) 140284018SaeSYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET, 141284018Sae &VNET_NAME(max_gre_nesting), 0, "Max nested tunnels"); 142103026Ssobomax 143103032Ssobomaxstatic void 144284018Saevnet_gre_init(const void *unused __unused) 145103026Ssobomax{ 146284018Sae LIST_INIT(&V_gre_softc_list); 147284018Sae GRE_LIST_LOCK_INIT(); 148284018Sae V_gre_cloner = if_clone_simple(grename, gre_clone_create, 149241610Sglebius gre_clone_destroy, 0); 150103026Ssobomax} 151284018SaeVNET_SYSINIT(vnet_gre_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 152284018Sae vnet_gre_init, NULL); 153103026Ssobomax 154284018Saestatic void 155284018Saevnet_gre_uninit(const void *unused __unused) 156284018Sae{ 157284018Sae 158284018Sae if_clone_detach(V_gre_cloner); 159284018Sae GRE_LIST_LOCK_DESTROY(); 160284018Sae} 161284018SaeVNET_SYSUNINIT(vnet_gre_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 162284018Sae vnet_gre_uninit, NULL); 163284018Sae 164103032Ssobomaxstatic int 165284018Saegre_clone_create(struct if_clone *ifc, int unit, caddr_t params) 166103026Ssobomax{ 167103026Ssobomax struct gre_softc *sc; 168103026Ssobomax 169131673Sbms sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK | M_ZERO); 170284066Sae sc->gre_fibnum = curthread->td_proc->p_fibnum; 171147643Sbz GRE2IFP(sc) = if_alloc(IFT_TUNNEL); 172284066Sae GRE_LOCK_INIT(sc); 173147643Sbz GRE2IFP(sc)->if_softc = sc; 174241610Sglebius if_initname(GRE2IFP(sc), grename, unit); 175147643Sbz 176284066Sae GRE2IFP(sc)->if_mtu = sc->gre_mtu = GREMTU; 177147256Sbrooks GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; 178147256Sbrooks GRE2IFP(sc)->if_output = gre_output; 179147256Sbrooks GRE2IFP(sc)->if_ioctl = gre_ioctl; 180284066Sae GRE2IFP(sc)->if_transmit = gre_transmit; 181284066Sae GRE2IFP(sc)->if_qflush = gre_qflush; 182290347Shrs GRE2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE; 183290347Shrs GRE2IFP(sc)->if_capenable |= IFCAP_LINKSTATE; 184147256Sbrooks if_attach(GRE2IFP(sc)); 185147256Sbrooks bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 186284018Sae GRE_LIST_LOCK(); 187284066Sae LIST_INSERT_HEAD(&V_gre_softc_list, sc, gre_list); 188284018Sae GRE_LIST_UNLOCK(); 189103026Ssobomax return (0); 190103026Ssobomax} 191103026Ssobomax 192103032Ssobomaxstatic void 193284018Saegre_clone_destroy(struct ifnet *ifp) 194127307Srwatson{ 195284066Sae struct gre_softc *sc; 196127307Srwatson 197284066Sae sx_xlock(&gre_ioctl_sx); 198284066Sae sc = ifp->if_softc; 199284066Sae gre_delete_tunnel(ifp); 200284018Sae GRE_LIST_LOCK(); 201284066Sae LIST_REMOVE(sc, gre_list); 202284018Sae GRE_LIST_UNLOCK(); 203151266Sthompsa bpfdetach(ifp); 204151266Sthompsa if_detach(ifp); 205284066Sae ifp->if_softc = NULL; 206284066Sae sx_xunlock(&gre_ioctl_sx); 207284066Sae 208151266Sthompsa if_free(ifp); 209284066Sae GRE_LOCK_DESTROY(sc); 210151266Sthompsa free(sc, M_GRE); 211127307Srwatson} 212127307Srwatson 213103032Ssobomaxstatic int 214284066Saegre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 215103026Ssobomax{ 216284066Sae GRE_RLOCK_TRACKER; 217284066Sae struct ifreq *ifr = (struct ifreq *)data; 218284066Sae struct sockaddr *src, *dst; 219284066Sae struct gre_softc *sc; 220284066Sae#ifdef INET 221284066Sae struct sockaddr_in *sin = NULL; 222284066Sae#endif 223284066Sae#ifdef INET6 224284066Sae struct sockaddr_in6 *sin6 = NULL; 225284066Sae#endif 226284066Sae uint32_t opt; 227284066Sae int error; 228103026Ssobomax 229284066Sae switch (cmd) { 230284066Sae case SIOCSIFMTU: 231284066Sae /* XXX: */ 232284066Sae if (ifr->ifr_mtu < 576) 233284066Sae return (EINVAL); 234284066Sae break; 235284066Sae case SIOCSIFADDR: 236284066Sae ifp->if_flags |= IFF_UP; 237284066Sae case SIOCSIFFLAGS: 238284066Sae case SIOCADDMULTI: 239284066Sae case SIOCDELMULTI: 240284066Sae return (0); 241284066Sae case GRESADDRS: 242284066Sae case GRESADDRD: 243284066Sae case GREGADDRS: 244284066Sae case GREGADDRD: 245284066Sae case GRESPROTO: 246284066Sae case GREGPROTO: 247284066Sae return (EOPNOTSUPP); 248103026Ssobomax } 249284066Sae src = dst = NULL; 250284066Sae sx_xlock(&gre_ioctl_sx); 251284066Sae sc = ifp->if_softc; 252284066Sae if (sc == NULL) { 253284066Sae error = ENXIO; 254103026Ssobomax goto end; 255103026Ssobomax } 256284066Sae error = 0; 257284066Sae switch (cmd) { 258284066Sae case SIOCSIFMTU: 259284066Sae GRE_WLOCK(sc); 260284066Sae sc->gre_mtu = ifr->ifr_mtu; 261284066Sae gre_updatehdr(sc); 262284066Sae GRE_WUNLOCK(sc); 263250523Shrs goto end; 264284066Sae case SIOCSIFPHYADDR: 265148613Sbz#ifdef INET6 266284066Sae case SIOCSIFPHYADDR_IN6: 267284066Sae#endif 268284066Sae error = EINVAL; 269284066Sae switch (cmd) { 270284066Sae#ifdef INET 271284066Sae case SIOCSIFPHYADDR: 272284066Sae src = (struct sockaddr *) 273284066Sae &(((struct in_aliasreq *)data)->ifra_addr); 274284066Sae dst = (struct sockaddr *) 275284066Sae &(((struct in_aliasreq *)data)->ifra_dstaddr); 276148613Sbz break; 277148613Sbz#endif 278284066Sae#ifdef INET6 279284066Sae case SIOCSIFPHYADDR_IN6: 280284066Sae src = (struct sockaddr *) 281284066Sae &(((struct in6_aliasreq *)data)->ifra_addr); 282284066Sae dst = (struct sockaddr *) 283284066Sae &(((struct in6_aliasreq *)data)->ifra_dstaddr); 284103026Ssobomax break; 285103026Ssobomax#endif 286103026Ssobomax default: 287103026Ssobomax error = EAFNOSUPPORT; 288103026Ssobomax goto end; 289103026Ssobomax } 290284066Sae /* sa_family must be equal */ 291284066Sae if (src->sa_family != dst->sa_family || 292284066Sae src->sa_len != dst->sa_len) 293284066Sae goto end; 294103026Ssobomax 295284066Sae /* validate sa_len */ 296284066Sae switch (src->sa_family) { 297164033Srwatson#ifdef INET 298164033Srwatson case AF_INET: 299284066Sae if (src->sa_len != sizeof(struct sockaddr_in)) 300284066Sae goto end; 301164033Srwatson break; 302164033Srwatson#endif 303164033Srwatson#ifdef INET6 304164033Srwatson case AF_INET6: 305284066Sae if (src->sa_len != sizeof(struct sockaddr_in6)) 306284066Sae goto end; 307164033Srwatson break; 308164033Srwatson#endif 309164033Srwatson default: 310164033Srwatson error = EAFNOSUPPORT; 311284066Sae goto end; 312164033Srwatson } 313284066Sae /* check sa_family looks sane for the cmd */ 314284066Sae error = EAFNOSUPPORT; 315284066Sae switch (cmd) { 316284066Sae#ifdef INET 317284066Sae case SIOCSIFPHYADDR: 318284066Sae if (src->sa_family == AF_INET) 319284066Sae break; 320284066Sae goto end; 321284066Sae#endif 322284066Sae#ifdef INET6 323284066Sae case SIOCSIFPHYADDR_IN6: 324284066Sae if (src->sa_family == AF_INET6) 325284066Sae break; 326284066Sae goto end; 327284066Sae#endif 328103026Ssobomax } 329284066Sae error = EADDRNOTAVAIL; 330284066Sae switch (src->sa_family) { 331103026Ssobomax#ifdef INET 332103026Ssobomax case AF_INET: 333284066Sae if (satosin(src)->sin_addr.s_addr == INADDR_ANY || 334284066Sae satosin(dst)->sin_addr.s_addr == INADDR_ANY) 335284066Sae goto end; 336103026Ssobomax break; 337103026Ssobomax#endif 338148613Sbz#ifdef INET6 339148613Sbz case AF_INET6: 340284066Sae if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr) 341284066Sae || 342284066Sae IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr)) 343284066Sae goto end; 344284066Sae /* 345284066Sae * Check validity of the scope zone ID of the 346284066Sae * addresses, and convert it into the kernel 347284066Sae * internal form if necessary. 348284066Sae */ 349284066Sae error = sa6_embedscope(satosin6(src), 0); 350284066Sae if (error != 0) 351284066Sae goto end; 352284066Sae error = sa6_embedscope(satosin6(dst), 0); 353284066Sae if (error != 0) 354284066Sae goto end; 355148613Sbz#endif 356284066Sae }; 357284066Sae error = gre_set_tunnel(ifp, src, dst); 358284066Sae break; 359284066Sae case SIOCDIFPHYADDR: 360284066Sae gre_delete_tunnel(ifp); 361284066Sae break; 362284066Sae case SIOCGIFPSRCADDR: 363284066Sae case SIOCGIFPDSTADDR: 364284066Sae#ifdef INET6 365284066Sae case SIOCGIFPSRCADDR_IN6: 366284066Sae case SIOCGIFPDSTADDR_IN6: 367284066Sae#endif 368284066Sae if (sc->gre_family == 0) { 369284066Sae error = EADDRNOTAVAIL; 370103026Ssobomax break; 371103026Ssobomax } 372284066Sae GRE_RLOCK(sc); 373284066Sae switch (cmd) { 374284066Sae#ifdef INET 375284066Sae case SIOCGIFPSRCADDR: 376284066Sae case SIOCGIFPDSTADDR: 377284066Sae if (sc->gre_family != AF_INET) { 378284066Sae error = EADDRNOTAVAIL; 379284066Sae break; 380284066Sae } 381284066Sae sin = (struct sockaddr_in *)&ifr->ifr_addr; 382284066Sae memset(sin, 0, sizeof(*sin)); 383284066Sae sin->sin_family = AF_INET; 384284066Sae sin->sin_len = sizeof(*sin); 385103026Ssobomax break; 386284066Sae#endif 387284066Sae#ifdef INET6 388284066Sae case SIOCGIFPSRCADDR_IN6: 389284066Sae case SIOCGIFPDSTADDR_IN6: 390284066Sae if (sc->gre_family != AF_INET6) { 391284066Sae error = EADDRNOTAVAIL; 392284066Sae break; 393284066Sae } 394284066Sae sin6 = (struct sockaddr_in6 *) 395284066Sae &(((struct in6_ifreq *)data)->ifr_addr); 396284066Sae memset(sin6, 0, sizeof(*sin6)); 397284066Sae sin6->sin6_family = AF_INET6; 398284066Sae sin6->sin6_len = sizeof(*sin6); 399103026Ssobomax break; 400284066Sae#endif 401103026Ssobomax } 402284066Sae if (error == 0) { 403284066Sae switch (cmd) { 404103026Ssobomax#ifdef INET 405284066Sae case SIOCGIFPSRCADDR: 406284066Sae sin->sin_addr = sc->gre_oip.ip_src; 407284066Sae break; 408284066Sae case SIOCGIFPDSTADDR: 409284066Sae sin->sin_addr = sc->gre_oip.ip_dst; 410284066Sae break; 411103026Ssobomax#endif 412284066Sae#ifdef INET6 413284066Sae case SIOCGIFPSRCADDR_IN6: 414284066Sae sin6->sin6_addr = sc->gre_oip6.ip6_src; 415284066Sae break; 416284066Sae case SIOCGIFPDSTADDR_IN6: 417284066Sae sin6->sin6_addr = sc->gre_oip6.ip6_dst; 418284066Sae break; 419103026Ssobomax#endif 420284066Sae } 421103026Ssobomax } 422284066Sae GRE_RUNLOCK(sc); 423219206Sbz if (error != 0) 424219206Sbz break; 425284066Sae switch (cmd) { 426284066Sae#ifdef INET 427284066Sae case SIOCGIFPSRCADDR: 428284066Sae case SIOCGIFPDSTADDR: 429284066Sae error = prison_if(curthread->td_ucred, 430284066Sae (struct sockaddr *)sin); 431284066Sae if (error != 0) 432284066Sae memset(sin, 0, sizeof(*sin)); 433219206Sbz break; 434284066Sae#endif 435284066Sae#ifdef INET6 436284066Sae case SIOCGIFPSRCADDR_IN6: 437284066Sae case SIOCGIFPDSTADDR_IN6: 438284066Sae error = prison_if(curthread->td_ucred, 439284066Sae (struct sockaddr *)sin6); 440284066Sae if (error == 0) 441284066Sae error = sa6_recoverscope(sin6); 442284066Sae if (error != 0) 443284066Sae memset(sin6, 0, sizeof(*sin6)); 444284066Sae#endif 445284066Sae } 446103026Ssobomax break; 447284074Sae case SIOCGTUNFIB: 448284074Sae ifr->ifr_fib = sc->gre_fibnum; 449284074Sae break; 450284074Sae case SIOCSTUNFIB: 451284074Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 452284074Sae break; 453284074Sae if (ifr->ifr_fib >= rt_numfibs) 454284074Sae error = EINVAL; 455284074Sae else 456284074Sae sc->gre_fibnum = ifr->ifr_fib; 457284074Sae break; 458284066Sae case GRESKEY: 459284066Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 460103026Ssobomax break; 461284066Sae if ((error = copyin(ifr->ifr_data, &opt, sizeof(opt))) != 0) 462103026Ssobomax break; 463284066Sae if (sc->gre_key != opt) { 464284066Sae GRE_WLOCK(sc); 465284066Sae sc->gre_key = opt; 466284066Sae gre_updatehdr(sc); 467284066Sae GRE_WUNLOCK(sc); 468103026Ssobomax } 469284066Sae break; 470284066Sae case GREGKEY: 471284074Sae error = copyout(&sc->gre_key, ifr->ifr_data, 472284074Sae sizeof(sc->gre_key)); 473284066Sae break; 474284066Sae case GRESOPTS: 475284066Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 476103026Ssobomax break; 477284066Sae if ((error = copyin(ifr->ifr_data, &opt, sizeof(opt))) != 0) 478103026Ssobomax break; 479284066Sae if (opt & ~GRE_OPTMASK) 480103026Ssobomax error = EINVAL; 481284066Sae else { 482284066Sae if (sc->gre_options != opt) { 483284066Sae GRE_WLOCK(sc); 484284066Sae sc->gre_options = opt; 485284066Sae gre_updatehdr(sc); 486284066Sae GRE_WUNLOCK(sc); 487284066Sae } 488103026Ssobomax } 489103026Ssobomax break; 490284066Sae 491284066Sae case GREGOPTS: 492284066Sae error = copyout(&sc->gre_options, ifr->ifr_data, 493284066Sae sizeof(sc->gre_options)); 494284066Sae break; 495284066Sae default: 496284066Sae error = EINVAL; 497284066Sae break; 498284066Sae } 499284066Saeend: 500284066Sae sx_xunlock(&gre_ioctl_sx); 501284066Sae return (error); 502284066Sae} 503284066Sae 504284066Saestatic void 505284066Saegre_updatehdr(struct gre_softc *sc) 506284066Sae{ 507284066Sae struct grehdr *gh = NULL; 508284066Sae uint32_t *opts; 509284066Sae uint16_t flags; 510284066Sae 511284066Sae GRE_WLOCK_ASSERT(sc); 512284066Sae switch (sc->gre_family) { 513284066Sae#ifdef INET 514284066Sae case AF_INET: 515284066Sae sc->gre_hlen = sizeof(struct greip); 516284066Sae sc->gre_oip.ip_v = IPPROTO_IPV4; 517284066Sae sc->gre_oip.ip_hl = sizeof(struct ip) >> 2; 518284066Sae sc->gre_oip.ip_p = IPPROTO_GRE; 519284066Sae gh = &sc->gre_gihdr->gi_gre; 520284066Sae break; 521284066Sae#endif 522122699Sbms#ifdef INET6 523284066Sae case AF_INET6: 524284066Sae sc->gre_hlen = sizeof(struct greip6); 525284066Sae sc->gre_oip6.ip6_vfc = IPV6_VERSION; 526284066Sae sc->gre_oip6.ip6_nxt = IPPROTO_GRE; 527284066Sae gh = &sc->gre_gi6hdr->gi6_gre; 528284066Sae break; 529122699Sbms#endif 530284066Sae default: 531284066Sae return; 532284066Sae } 533284066Sae flags = 0; 534284066Sae opts = gh->gre_opts; 535284066Sae if (sc->gre_options & GRE_ENABLE_CSUM) { 536284066Sae flags |= GRE_FLAGS_CP; 537284066Sae sc->gre_hlen += 2 * sizeof(uint16_t); 538284066Sae *opts++ = 0; 539284066Sae } 540284066Sae if (sc->gre_key != 0) { 541284066Sae flags |= GRE_FLAGS_KP; 542284066Sae sc->gre_hlen += sizeof(uint32_t); 543284066Sae *opts++ = htonl(sc->gre_key); 544284066Sae } 545284066Sae if (sc->gre_options & GRE_ENABLE_SEQ) { 546284066Sae flags |= GRE_FLAGS_SP; 547284066Sae sc->gre_hlen += sizeof(uint32_t); 548284066Sae *opts++ = 0; 549284066Sae } else 550284066Sae sc->gre_oseq = 0; 551284066Sae gh->gre_flags = htons(flags); 552284066Sae GRE2IFP(sc)->if_mtu = sc->gre_mtu - sc->gre_hlen; 553284066Sae} 554284066Sae 555284066Saestatic void 556284066Saegre_detach(struct gre_softc *sc) 557284066Sae{ 558284066Sae 559284066Sae sx_assert(&gre_ioctl_sx, SA_XLOCKED); 560284066Sae if (sc->gre_ecookie != NULL) 561284066Sae encap_detach(sc->gre_ecookie); 562284066Sae sc->gre_ecookie = NULL; 563284066Sae} 564284066Sae 565284066Saestatic int 566284066Saegre_set_tunnel(struct ifnet *ifp, struct sockaddr *src, 567284066Sae struct sockaddr *dst) 568284066Sae{ 569284066Sae struct gre_softc *sc, *tsc; 570284066Sae#ifdef INET6 571284066Sae struct ip6_hdr *ip6; 572284066Sae#endif 573284066Sae#ifdef INET 574284066Sae struct ip *ip; 575284066Sae#endif 576284066Sae void *hdr; 577284066Sae int error; 578284066Sae 579284066Sae sx_assert(&gre_ioctl_sx, SA_XLOCKED); 580284066Sae GRE_LIST_LOCK(); 581284066Sae sc = ifp->if_softc; 582284066Sae LIST_FOREACH(tsc, &V_gre_softc_list, gre_list) { 583284066Sae if (tsc == sc || tsc->gre_family != src->sa_family) 584284066Sae continue; 585284066Sae#ifdef INET 586284066Sae if (tsc->gre_family == AF_INET && 587284066Sae tsc->gre_oip.ip_src.s_addr == 588284066Sae satosin(src)->sin_addr.s_addr && 589284066Sae tsc->gre_oip.ip_dst.s_addr == 590284066Sae satosin(dst)->sin_addr.s_addr) { 591284066Sae GRE_LIST_UNLOCK(); 592284066Sae return (EADDRNOTAVAIL); 593103026Ssobomax } 594284066Sae#endif 595122699Sbms#ifdef INET6 596284066Sae if (tsc->gre_family == AF_INET6 && 597284066Sae IN6_ARE_ADDR_EQUAL(&tsc->gre_oip6.ip6_src, 598284066Sae &satosin6(src)->sin6_addr) && 599284066Sae IN6_ARE_ADDR_EQUAL(&tsc->gre_oip6.ip6_dst, 600284066Sae &satosin6(dst)->sin6_addr)) { 601284066Sae GRE_LIST_UNLOCK(); 602284066Sae return (EADDRNOTAVAIL); 603284066Sae } 604122699Sbms#endif 605284066Sae } 606284066Sae GRE_LIST_UNLOCK(); 607179894Sthompsa 608284066Sae error = 0; 609284066Sae switch (src->sa_family) { 610284066Sae#ifdef INET 611284066Sae case AF_INET: 612284066Sae hdr = ip = malloc(sizeof(struct greip) + 613284066Sae 3 * sizeof(uint32_t), M_GRE, M_WAITOK | M_ZERO); 614284066Sae ip->ip_src = satosin(src)->sin_addr; 615284066Sae ip->ip_dst = satosin(dst)->sin_addr; 616179894Sthompsa break; 617284066Sae#endif 618284066Sae#ifdef INET6 619284066Sae case AF_INET6: 620284066Sae hdr = ip6 = malloc(sizeof(struct greip6) + 621284066Sae 3 * sizeof(uint32_t), M_GRE, M_WAITOK | M_ZERO); 622284066Sae ip6->ip6_src = satosin6(src)->sin6_addr; 623284066Sae ip6->ip6_dst = satosin6(dst)->sin6_addr; 624179894Sthompsa break; 625284066Sae#endif 626284066Sae default: 627284066Sae return (EAFNOSUPPORT); 628284066Sae } 629289169Sae if (sc->gre_family != 0) 630284066Sae gre_detach(sc); 631284066Sae GRE_WLOCK(sc); 632284066Sae if (sc->gre_family != 0) 633284066Sae free(sc->gre_hdr, M_GRE); 634284066Sae sc->gre_family = src->sa_family; 635284066Sae sc->gre_hdr = hdr; 636284066Sae sc->gre_oseq = 0; 637284066Sae sc->gre_iseq = UINT32_MAX; 638284066Sae gre_updatehdr(sc); 639284066Sae GRE_WUNLOCK(sc); 640179894Sthompsa 641284066Sae switch (src->sa_family) { 642284066Sae#ifdef INET 643284066Sae case AF_INET: 644284066Sae error = in_gre_attach(sc); 645103026Ssobomax break; 646284066Sae#endif 647284066Sae#ifdef INET6 648284066Sae case AF_INET6: 649284066Sae error = in6_gre_attach(sc); 650284066Sae break; 651284066Sae#endif 652103026Ssobomax } 653290347Shrs if (error == 0) { 654284066Sae ifp->if_drv_flags |= IFF_DRV_RUNNING; 655290347Shrs if_link_state_change(ifp, LINK_STATE_UP); 656290347Shrs } 657103026Ssobomax return (error); 658103026Ssobomax} 659103026Ssobomax 660284066Saestatic void 661284066Saegre_delete_tunnel(struct ifnet *ifp) 662103026Ssobomax{ 663284066Sae struct gre_softc *sc = ifp->if_softc; 664284066Sae int family; 665103026Ssobomax 666284066Sae GRE_WLOCK(sc); 667284066Sae family = sc->gre_family; 668284066Sae sc->gre_family = 0; 669284066Sae GRE_WUNLOCK(sc); 670284066Sae if (family != 0) { 671284066Sae gre_detach(sc); 672284066Sae free(sc->gre_hdr, M_GRE); 673284066Sae } 674284066Sae ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 675290347Shrs if_link_state_change(ifp, LINK_STATE_DOWN); 676284066Sae} 677103026Ssobomax 678284066Saeint 679284066Saegre_input(struct mbuf **mp, int *offp, int proto) 680284066Sae{ 681284066Sae struct gre_softc *sc; 682284066Sae struct grehdr *gh; 683284066Sae struct ifnet *ifp; 684284066Sae struct mbuf *m; 685293410Saraujo uint32_t *opts; 686293410Saraujo#ifdef notyet 687293410Saraujo uint32_t key; 688293410Saraujo#endif 689284066Sae uint16_t flags; 690284066Sae int hlen, isr, af; 691103026Ssobomax 692284066Sae m = *mp; 693284066Sae sc = encap_getarg(m); 694284066Sae KASSERT(sc != NULL, ("encap_getarg returned NULL")); 695284066Sae 696284066Sae ifp = GRE2IFP(sc); 697290360Sae hlen = *offp + sizeof(struct grehdr) + 4 * sizeof(uint32_t); 698290360Sae if (m->m_pkthdr.len < hlen) 699290360Sae goto drop; 700290360Sae if (m->m_len < hlen) { 701290360Sae m = m_pullup(m, hlen); 702290360Sae if (m == NULL) 703290360Sae goto drop; 704290360Sae } 705284066Sae gh = (struct grehdr *)mtodo(m, *offp); 706284066Sae flags = ntohs(gh->gre_flags); 707284066Sae if (flags & ~GRE_FLAGS_MASK) 708284066Sae goto drop; 709284066Sae opts = gh->gre_opts; 710284066Sae hlen = 2 * sizeof(uint16_t); 711284066Sae if (flags & GRE_FLAGS_CP) { 712284066Sae /* reserved1 field must be zero */ 713284066Sae if (((uint16_t *)opts)[1] != 0) 714284066Sae goto drop; 715284066Sae if (in_cksum_skip(m, m->m_pkthdr.len, *offp) != 0) 716284066Sae goto drop; 717284066Sae hlen += 2 * sizeof(uint16_t); 718284066Sae opts++; 719284066Sae } 720284066Sae if (flags & GRE_FLAGS_KP) { 721293410Saraujo#ifdef notyet 722293410Saraujo /* 723293410Saraujo * XXX: The current implementation uses the key only for outgoing 724293410Saraujo * packets. But we can check the key value here, or even in the 725293410Saraujo * encapcheck function. 726293410Saraujo */ 727284066Sae key = ntohl(*opts); 728293410Saraujo#endif 729284066Sae hlen += sizeof(uint32_t); 730284066Sae opts++; 731293410Saraujo } 732293410Saraujo#ifdef notyet 733284066Sae } else 734284066Sae key = 0; 735284066Sae if (sc->gre_key != 0 && (key != sc->gre_key || key != 0)) 736284066Sae goto drop; 737293410Saraujo#endif 738284066Sae if (flags & GRE_FLAGS_SP) { 739293410Saraujo#ifdef notyet 740293410Saraujo seq = ntohl(*opts); 741293410Saraujo#endif 742284066Sae hlen += sizeof(uint32_t); 743103026Ssobomax } 744284066Sae switch (ntohs(gh->gre_proto)) { 745284066Sae case ETHERTYPE_WCCP: 746284066Sae /* 747284066Sae * For WCCP skip an additional 4 bytes if after GRE header 748284066Sae * doesn't follow an IP header. 749284066Sae */ 750284066Sae if (flags == 0 && (*(uint8_t *)gh->gre_opts & 0xF0) != 0x40) 751284066Sae hlen += sizeof(uint32_t); 752284066Sae /* FALLTHROUGH */ 753284066Sae case ETHERTYPE_IP: 754284066Sae isr = NETISR_IP; 755284066Sae af = AF_INET; 756284066Sae break; 757284066Sae case ETHERTYPE_IPV6: 758284066Sae isr = NETISR_IPV6; 759284066Sae af = AF_INET6; 760284066Sae break; 761284066Sae default: 762284066Sae goto drop; 763284066Sae } 764284066Sae m_adj(m, *offp + hlen); 765284066Sae m_clrprotoflags(m); 766284066Sae m->m_pkthdr.rcvif = ifp; 767284074Sae M_SETFIB(m, ifp->if_fib); 768284066Sae#ifdef MAC 769284066Sae mac_ifnet_create_mbuf(ifp, m); 770103026Ssobomax#endif 771284066Sae BPF_MTAP2(ifp, &af, sizeof(af), m); 772284066Sae ifp->if_ipackets++; 773284066Sae ifp->if_ibytes += m->m_pkthdr.len; 774284066Sae if ((ifp->if_flags & IFF_MONITOR) != 0) 775284066Sae m_freem(m); 776284066Sae else 777284066Sae netisr_dispatch(isr, m); 778284066Sae return (IPPROTO_DONE); 779284066Saedrop: 780284066Sae ifp->if_ierrors++; 781284066Sae m_freem(m); 782284066Sae return (IPPROTO_DONE); 783284066Sae} 784103026Ssobomax 785284066Sae#define MTAG_GRE 1307983903 786284066Saestatic int 787284066Saegre_check_nesting(struct ifnet *ifp, struct mbuf *m) 788284066Sae{ 789284066Sae struct m_tag *mtag; 790284066Sae int count; 791103026Ssobomax 792284066Sae count = 1; 793284066Sae mtag = NULL; 794284066Sae while ((mtag = m_tag_locate(m, MTAG_GRE, 0, mtag)) != NULL) { 795284066Sae if (*(struct ifnet **)(mtag + 1) == ifp) { 796284066Sae log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname); 797284066Sae return (EIO); 798284066Sae } 799284066Sae count++; 800103026Ssobomax } 801284066Sae if (count > V_max_gre_nesting) { 802284066Sae log(LOG_NOTICE, 803284066Sae "%s: if_output recursively called too many times(%d)\n", 804284066Sae ifp->if_xname, count); 805284066Sae return (EIO); 806284066Sae } 807284066Sae mtag = m_tag_alloc(MTAG_GRE, 0, sizeof(struct ifnet *), M_NOWAIT); 808284066Sae if (mtag == NULL) 809284066Sae return (ENOMEM); 810284066Sae *(struct ifnet **)(mtag + 1) = ifp; 811284066Sae m_tag_prepend(m, mtag); 812284066Sae return (0); 813284066Sae} 814103026Ssobomax 815284066Saestatic int 816284066Saegre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 817284066Sae struct route *ro) 818284066Sae{ 819284066Sae uint32_t af; 820284066Sae int error; 821103026Ssobomax 822284066Sae#ifdef MAC 823284066Sae error = mac_ifnet_check_transmit(ifp, m); 824284066Sae if (error != 0) 825284066Sae goto drop; 826103026Ssobomax#endif 827284066Sae if ((ifp->if_flags & IFF_MONITOR) != 0 || 828284066Sae (ifp->if_flags & IFF_UP) == 0) { 829284066Sae error = ENETDOWN; 830284066Sae goto drop; 831284066Sae } 832103026Ssobomax 833284066Sae error = gre_check_nesting(ifp, m); 834284066Sae if (error != 0) 835284066Sae goto drop; 836284066Sae 837284066Sae m->m_flags &= ~(M_BCAST|M_MCAST); 838284066Sae if (dst->sa_family == AF_UNSPEC) 839284066Sae bcopy(dst->sa_data, &af, sizeof(af)); 840284066Sae else 841284066Sae af = dst->sa_family; 842284066Sae BPF_MTAP2(ifp, &af, sizeof(af), m); 843284066Sae m->m_pkthdr.csum_data = af; /* save af for if_transmit */ 844284066Sae return (ifp->if_transmit(ifp, m)); 845284066Saedrop: 846284066Sae m_freem(m); 847284066Sae ifp->if_oerrors++; 848284066Sae return (error); 849103026Ssobomax} 850103026Ssobomax 851284066Saestatic void 852284066Saegre_setseqn(struct grehdr *gh, uint32_t seq) 853103026Ssobomax{ 854284066Sae uint32_t *opts; 855284066Sae uint16_t flags; 856103026Ssobomax 857284066Sae opts = gh->gre_opts; 858284066Sae flags = ntohs(gh->gre_flags); 859284066Sae KASSERT((flags & GRE_FLAGS_SP) != 0, 860284066Sae ("gre_setseqn called, but GRE_FLAGS_SP isn't set ")); 861284066Sae if (flags & GRE_FLAGS_CP) 862284066Sae opts++; 863284066Sae if (flags & GRE_FLAGS_KP) 864284066Sae opts++; 865284066Sae *opts = htonl(seq); 866284066Sae} 867103026Ssobomax 868284066Saestatic int 869284066Saegre_transmit(struct ifnet *ifp, struct mbuf *m) 870284066Sae{ 871284066Sae GRE_RLOCK_TRACKER; 872284066Sae struct gre_softc *sc; 873284066Sae struct grehdr *gh; 874284066Sae uint32_t iaf, oaf, oseq; 875284066Sae int error, hlen, olen, plen; 876284066Sae int want_seq, want_csum; 877284066Sae 878284066Sae plen = 0; 879284066Sae sc = ifp->if_softc; 880284066Sae if (sc == NULL) { 881284066Sae error = ENETDOWN; 882284066Sae m_freem(m); 883284066Sae goto drop; 884103026Ssobomax } 885284066Sae GRE_RLOCK(sc); 886284066Sae if (sc->gre_family == 0) { 887284066Sae GRE_RUNLOCK(sc); 888284066Sae error = ENETDOWN; 889284066Sae m_freem(m); 890284066Sae goto drop; 891284066Sae } 892284066Sae iaf = m->m_pkthdr.csum_data; 893284066Sae oaf = sc->gre_family; 894284066Sae hlen = sc->gre_hlen; 895284066Sae want_seq = (sc->gre_options & GRE_ENABLE_SEQ) != 0; 896284066Sae if (want_seq) 897284066Sae oseq = sc->gre_oseq++; 898284066Sae else 899284066Sae oseq = 0; /* Make compiler happy. */ 900284066Sae want_csum = (sc->gre_options & GRE_ENABLE_CSUM) != 0; 901284066Sae M_SETFIB(m, sc->gre_fibnum); 902284066Sae M_PREPEND(m, hlen, M_NOWAIT); 903284066Sae if (m == NULL) { 904284066Sae GRE_RUNLOCK(sc); 905284066Sae error = ENOBUFS; 906284066Sae goto drop; 907284066Sae } 908284066Sae bcopy(sc->gre_hdr, mtod(m, void *), hlen); 909284066Sae GRE_RUNLOCK(sc); 910284066Sae switch (oaf) { 911284066Sae#ifdef INET 912284066Sae case AF_INET: 913284066Sae olen = sizeof(struct ip); 914284066Sae break; 915284066Sae#endif 916284066Sae#ifdef INET6 917284066Sae case AF_INET6: 918284066Sae olen = sizeof(struct ip6_hdr); 919284066Sae break; 920284066Sae#endif 921284066Sae default: 922284066Sae error = ENETDOWN; 923284066Sae goto drop; 924284066Sae } 925284066Sae gh = (struct grehdr *)mtodo(m, olen); 926284066Sae switch (iaf) { 927284066Sae#ifdef INET 928284066Sae case AF_INET: 929284066Sae gh->gre_proto = htons(ETHERTYPE_IP); 930284066Sae break; 931284066Sae#endif 932284066Sae#ifdef INET6 933284066Sae case AF_INET6: 934284066Sae gh->gre_proto = htons(ETHERTYPE_IPV6); 935284066Sae break; 936284066Sae#endif 937284066Sae default: 938284066Sae error = ENETDOWN; 939284066Sae goto drop; 940284066Sae } 941284066Sae if (want_seq) 942284066Sae gre_setseqn(gh, oseq); 943284066Sae if (want_csum) { 944284066Sae *(uint16_t *)gh->gre_opts = in_cksum_skip(m, 945284066Sae m->m_pkthdr.len, olen); 946284066Sae } 947284066Sae plen = m->m_pkthdr.len - hlen; 948284066Sae switch (oaf) { 949284066Sae#ifdef INET 950284066Sae case AF_INET: 951284066Sae error = in_gre_output(m, iaf, hlen); 952284066Sae break; 953284066Sae#endif 954284066Sae#ifdef INET6 955284066Sae case AF_INET6: 956284066Sae error = in6_gre_output(m, iaf, hlen); 957284066Sae break; 958284066Sae#endif 959284066Sae default: 960284066Sae m_freem(m); 961284066Sae error = ENETDOWN; 962284066Sae }; 963284066Saedrop: 964284066Sae if (error) 965284066Sae ifp->if_oerrors++; 966284066Sae else { 967284066Sae ifp->if_opackets++; 968284066Sae ifp->if_obytes += plen; 969284066Sae } 970284066Sae return (error); 971284066Sae} 972103026Ssobomax 973284066Saestatic void 974284066Saegre_qflush(struct ifnet *ifp __unused) 975284066Sae{ 976284066Sae 977103026Ssobomax} 978103026Ssobomax 979103026Ssobomaxstatic int 980103026Ssobomaxgremodevent(module_t mod, int type, void *data) 981103026Ssobomax{ 982103026Ssobomax 983103026Ssobomax switch (type) { 984103026Ssobomax case MOD_LOAD: 985103026Ssobomax case MOD_UNLOAD: 986103026Ssobomax break; 987132199Sphk default: 988284018Sae return (EOPNOTSUPP); 989103026Ssobomax } 990284018Sae return (0); 991103026Ssobomax} 992103026Ssobomax 993103026Ssobomaxstatic moduledata_t gre_mod = { 994103026Ssobomax "if_gre", 995103026Ssobomax gremodevent, 996241394Skevlo 0 997103026Ssobomax}; 998103026Ssobomax 999103026SsobomaxDECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1000103026SsobomaxMODULE_VERSION(if_gre, 1); 1001