1139823Simp/*- 2103026Ssobomax * Copyright (c) 1998 The NetBSD Foundation, Inc. 3274246Sae * 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. 31274246Sae * 32274246Sae * $NetBSD: if_gre.c,v 1.49 2003/12/11 00:22:29 itojun Exp $ 33103026Ssobomax */ 34103026Ssobomax 35274246Sae#include <sys/cdefs.h> 36274246Sae__FBSDID("$FreeBSD: stable/11/sys/net/if_gre.c 332288 2018-04-08 16:54:07Z brooks $"); 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> 44274246Sae#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> 52274246Sae#include <sys/rmlock.h> 53103026Ssobomax#include <sys/socket.h> 54103026Ssobomax#include <sys/sockio.h> 55274246Sae#include <sys/sx.h> 56103026Ssobomax#include <sys/sysctl.h> 57274246Sae#include <sys/syslog.h> 58103344Sbde#include <sys/systm.h> 59103026Ssobomax 60103026Ssobomax#include <net/ethernet.h> 61103026Ssobomax#include <net/if.h> 62257176Sglebius#include <net/if_var.h> 63130933Sbrooks#include <net/if_clone.h> 64103026Ssobomax#include <net/if_types.h> 65274246Sae#include <net/netisr.h> 66196019Srwatson#include <net/vnet.h> 67282809Sae#include <net/route.h> 68103026Ssobomax 69274246Sae#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 77274246Sae#ifdef INET6 78274246Sae#include <netinet/ip6.h> 79274246Sae#include <netinet6/in6_var.h> 80274246Sae#include <netinet6/ip6_var.h> 81274246Sae#include <netinet6/scope6_var.h> 82274246Sae#endif 83274246Sae 84274246Sae#include <netinet/ip_encap.h> 85103026Ssobomax#include <net/bpf.h> 86103026Ssobomax#include <net/if_gre.h> 87103026Ssobomax 88274246Sae#include <machine/in_cksum.h> 89274246Sae#include <security/mac/mac_framework.h> 90103026Ssobomax 91317403Sae#define GREMTU 1476 92241610Sglebiusstatic const char grename[] = "gre"; 93241610Sglebiusstatic MALLOC_DEFINE(M_GRE, grename, "Generic Routing Encapsulation"); 94274246Saestatic VNET_DEFINE(struct mtx, gre_mtx); 95274246Sae#define V_gre_mtx VNET(gre_mtx) 96274246Sae#define GRE_LIST_LOCK_INIT(x) mtx_init(&V_gre_mtx, "gre_mtx", NULL, \ 97274246Sae MTX_DEF) 98274246Sae#define GRE_LIST_LOCK_DESTROY(x) mtx_destroy(&V_gre_mtx) 99274246Sae#define GRE_LIST_LOCK(x) mtx_lock(&V_gre_mtx) 100274246Sae#define GRE_LIST_UNLOCK(x) mtx_unlock(&V_gre_mtx) 101103026Ssobomax 102274246Saestatic VNET_DEFINE(LIST_HEAD(, gre_softc), gre_softc_list); 103274246Sae#define V_gre_softc_list VNET(gre_softc_list) 104274246Saestatic struct sx gre_ioctl_sx; 105274246SaeSX_SYSINIT(gre_ioctl_sx, &gre_ioctl_sx, "gre_ioctl"); 106274246Sae 107160195Ssamstatic int gre_clone_create(struct if_clone *, int, caddr_t); 108105300Salfredstatic void gre_clone_destroy(struct ifnet *); 109271918Shrsstatic VNET_DEFINE(struct if_clone *, gre_cloner); 110271918Shrs#define V_gre_cloner VNET(gre_cloner) 111241610Sglebius 112274246Saestatic void gre_qflush(struct ifnet *); 113274246Saestatic 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 118274246Saestatic void gre_updatehdr(struct gre_softc *); 119274246Saestatic int gre_set_tunnel(struct ifnet *, struct sockaddr *, 120274246Sae struct sockaddr *); 121274246Saestatic 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 137274246Sae 138271918Shrsstatic VNET_DEFINE(int, max_gre_nesting) = MAX_GRE_NEST; 139271918Shrs#define V_max_gre_nesting VNET(max_gre_nesting) 140271918ShrsSYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET, 141271918Shrs &VNET_NAME(max_gre_nesting), 0, "Max nested tunnels"); 142103026Ssobomax 143103032Ssobomaxstatic void 144271918Shrsvnet_gre_init(const void *unused __unused) 145103026Ssobomax{ 146271918Shrs LIST_INIT(&V_gre_softc_list); 147271918Shrs GRE_LIST_LOCK_INIT(); 148271918Shrs V_gre_cloner = if_clone_simple(grename, gre_clone_create, 149241610Sglebius gre_clone_destroy, 0); 150103026Ssobomax} 151271918ShrsVNET_SYSINIT(vnet_gre_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 152271918Shrs vnet_gre_init, NULL); 153103026Ssobomax 154271918Shrsstatic void 155271918Shrsvnet_gre_uninit(const void *unused __unused) 156271918Shrs{ 157271918Shrs 158271918Shrs if_clone_detach(V_gre_cloner); 159271918Shrs GRE_LIST_LOCK_DESTROY(); 160271918Shrs} 161271918ShrsVNET_SYSUNINIT(vnet_gre_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 162271918Shrs vnet_gre_uninit, NULL); 163271918Shrs 164103032Ssobomaxstatic int 165271918Shrsgre_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); 170274246Sae sc->gre_fibnum = curthread->td_proc->p_fibnum; 171147643Sbz GRE2IFP(sc) = if_alloc(IFT_TUNNEL); 172274246Sae GRE_LOCK_INIT(sc); 173147643Sbz GRE2IFP(sc)->if_softc = sc; 174241610Sglebius if_initname(GRE2IFP(sc), grename, unit); 175147643Sbz 176317403Sae GRE2IFP(sc)->if_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; 180274246Sae GRE2IFP(sc)->if_transmit = gre_transmit; 181274246Sae GRE2IFP(sc)->if_qflush = gre_qflush; 182288575Shrs GRE2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE; 183288575Shrs GRE2IFP(sc)->if_capenable |= IFCAP_LINKSTATE; 184147256Sbrooks if_attach(GRE2IFP(sc)); 185147256Sbrooks bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 186271918Shrs GRE_LIST_LOCK(); 187274246Sae LIST_INSERT_HEAD(&V_gre_softc_list, sc, gre_list); 188271918Shrs GRE_LIST_UNLOCK(); 189103026Ssobomax return (0); 190103026Ssobomax} 191103026Ssobomax 192103032Ssobomaxstatic void 193271918Shrsgre_clone_destroy(struct ifnet *ifp) 194127307Srwatson{ 195274246Sae struct gre_softc *sc; 196127307Srwatson 197274246Sae sx_xlock(&gre_ioctl_sx); 198274246Sae sc = ifp->if_softc; 199274246Sae gre_delete_tunnel(ifp); 200271918Shrs GRE_LIST_LOCK(); 201274246Sae LIST_REMOVE(sc, gre_list); 202271918Shrs GRE_LIST_UNLOCK(); 203151266Sthompsa bpfdetach(ifp); 204151266Sthompsa if_detach(ifp); 205274246Sae ifp->if_softc = NULL; 206274246Sae sx_xunlock(&gre_ioctl_sx); 207274246Sae 208151266Sthompsa if_free(ifp); 209274246Sae GRE_LOCK_DESTROY(sc); 210151266Sthompsa free(sc, M_GRE); 211127307Srwatson} 212127307Srwatson 213103032Ssobomaxstatic int 214274246Saegre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 215103026Ssobomax{ 216274246Sae GRE_RLOCK_TRACKER; 217274246Sae struct ifreq *ifr = (struct ifreq *)data; 218274246Sae struct sockaddr *src, *dst; 219274246Sae struct gre_softc *sc; 220274246Sae#ifdef INET 221274246Sae struct sockaddr_in *sin = NULL; 222274246Sae#endif 223274246Sae#ifdef INET6 224274246Sae struct sockaddr_in6 *sin6 = NULL; 225274246Sae#endif 226274246Sae uint32_t opt; 227274246Sae int error; 228103026Ssobomax 229274246Sae switch (cmd) { 230274246Sae case SIOCSIFMTU: 231274246Sae /* XXX: */ 232274246Sae if (ifr->ifr_mtu < 576) 233274246Sae return (EINVAL); 234317403Sae ifp->if_mtu = ifr->ifr_mtu; 235317403Sae return (0); 236274246Sae case SIOCSIFADDR: 237274246Sae ifp->if_flags |= IFF_UP; 238274246Sae case SIOCSIFFLAGS: 239274246Sae case SIOCADDMULTI: 240274246Sae case SIOCDELMULTI: 241274246Sae return (0); 242274246Sae case GRESADDRS: 243274246Sae case GRESADDRD: 244274246Sae case GREGADDRS: 245274246Sae case GREGADDRD: 246274246Sae case GRESPROTO: 247274246Sae case GREGPROTO: 248274246Sae return (EOPNOTSUPP); 249103026Ssobomax } 250274246Sae src = dst = NULL; 251274246Sae sx_xlock(&gre_ioctl_sx); 252274246Sae sc = ifp->if_softc; 253274246Sae if (sc == NULL) { 254274246Sae error = ENXIO; 255103026Ssobomax goto end; 256103026Ssobomax } 257274246Sae error = 0; 258274246Sae switch (cmd) { 259274246Sae case SIOCSIFPHYADDR: 260274246Sae#ifdef INET6 261274246Sae case SIOCSIFPHYADDR_IN6: 262274246Sae#endif 263274246Sae error = EINVAL; 264274246Sae switch (cmd) { 265274246Sae#ifdef INET 266274246Sae case SIOCSIFPHYADDR: 267274246Sae src = (struct sockaddr *) 268274246Sae &(((struct in_aliasreq *)data)->ifra_addr); 269274246Sae dst = (struct sockaddr *) 270274246Sae &(((struct in_aliasreq *)data)->ifra_dstaddr); 271103026Ssobomax break; 272274246Sae#endif 273148613Sbz#ifdef INET6 274274246Sae case SIOCSIFPHYADDR_IN6: 275274246Sae src = (struct sockaddr *) 276274246Sae &(((struct in6_aliasreq *)data)->ifra_addr); 277274246Sae dst = (struct sockaddr *) 278274246Sae &(((struct in6_aliasreq *)data)->ifra_dstaddr); 279148613Sbz break; 280148613Sbz#endif 281103026Ssobomax default: 282103026Ssobomax error = EAFNOSUPPORT; 283103026Ssobomax goto end; 284103026Ssobomax } 285274246Sae /* sa_family must be equal */ 286274246Sae if (src->sa_family != dst->sa_family || 287274246Sae src->sa_len != dst->sa_len) 288274246Sae goto end; 289103026Ssobomax 290274246Sae /* validate sa_len */ 291274246Sae switch (src->sa_family) { 292164033Srwatson#ifdef INET 293164033Srwatson case AF_INET: 294274246Sae if (src->sa_len != sizeof(struct sockaddr_in)) 295274246Sae goto end; 296164033Srwatson break; 297164033Srwatson#endif 298164033Srwatson#ifdef INET6 299164033Srwatson case AF_INET6: 300274246Sae if (src->sa_len != sizeof(struct sockaddr_in6)) 301274246Sae goto end; 302164033Srwatson break; 303164033Srwatson#endif 304164033Srwatson default: 305164033Srwatson error = EAFNOSUPPORT; 306274246Sae goto end; 307164033Srwatson } 308274246Sae /* check sa_family looks sane for the cmd */ 309274246Sae error = EAFNOSUPPORT; 310274246Sae switch (cmd) { 311274246Sae#ifdef INET 312274246Sae case SIOCSIFPHYADDR: 313274246Sae if (src->sa_family == AF_INET) 314274246Sae break; 315274246Sae goto end; 316274246Sae#endif 317274246Sae#ifdef INET6 318274246Sae case SIOCSIFPHYADDR_IN6: 319274246Sae if (src->sa_family == AF_INET6) 320274246Sae break; 321274246Sae goto end; 322274246Sae#endif 323103026Ssobomax } 324274246Sae error = EADDRNOTAVAIL; 325274246Sae switch (src->sa_family) { 326103026Ssobomax#ifdef INET 327103026Ssobomax case AF_INET: 328274246Sae if (satosin(src)->sin_addr.s_addr == INADDR_ANY || 329274246Sae satosin(dst)->sin_addr.s_addr == INADDR_ANY) 330274246Sae goto end; 331103026Ssobomax break; 332103026Ssobomax#endif 333148613Sbz#ifdef INET6 334148613Sbz case AF_INET6: 335274246Sae if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr) 336274246Sae || 337274246Sae IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr)) 338274246Sae goto end; 339274246Sae /* 340274246Sae * Check validity of the scope zone ID of the 341274246Sae * addresses, and convert it into the kernel 342274246Sae * internal form if necessary. 343274246Sae */ 344274246Sae error = sa6_embedscope(satosin6(src), 0); 345274246Sae if (error != 0) 346274246Sae goto end; 347274246Sae error = sa6_embedscope(satosin6(dst), 0); 348274246Sae if (error != 0) 349274246Sae goto end; 350148613Sbz#endif 351297793Spfg } 352274246Sae error = gre_set_tunnel(ifp, src, dst); 353274246Sae break; 354274246Sae case SIOCDIFPHYADDR: 355274246Sae gre_delete_tunnel(ifp); 356274246Sae break; 357274246Sae case SIOCGIFPSRCADDR: 358274246Sae case SIOCGIFPDSTADDR: 359274246Sae#ifdef INET6 360274246Sae case SIOCGIFPSRCADDR_IN6: 361274246Sae case SIOCGIFPDSTADDR_IN6: 362274246Sae#endif 363274246Sae if (sc->gre_family == 0) { 364274246Sae error = EADDRNOTAVAIL; 365103026Ssobomax break; 366103026Ssobomax } 367274246Sae GRE_RLOCK(sc); 368274246Sae switch (cmd) { 369274246Sae#ifdef INET 370274246Sae case SIOCGIFPSRCADDR: 371274246Sae case SIOCGIFPDSTADDR: 372274246Sae if (sc->gre_family != AF_INET) { 373274246Sae error = EADDRNOTAVAIL; 374274246Sae break; 375274246Sae } 376274246Sae sin = (struct sockaddr_in *)&ifr->ifr_addr; 377274246Sae memset(sin, 0, sizeof(*sin)); 378274246Sae sin->sin_family = AF_INET; 379274246Sae sin->sin_len = sizeof(*sin); 380103026Ssobomax break; 381274246Sae#endif 382274246Sae#ifdef INET6 383274246Sae case SIOCGIFPSRCADDR_IN6: 384274246Sae case SIOCGIFPDSTADDR_IN6: 385274246Sae if (sc->gre_family != AF_INET6) { 386274246Sae error = EADDRNOTAVAIL; 387274246Sae break; 388274246Sae } 389274246Sae sin6 = (struct sockaddr_in6 *) 390274246Sae &(((struct in6_ifreq *)data)->ifr_addr); 391274246Sae memset(sin6, 0, sizeof(*sin6)); 392274246Sae sin6->sin6_family = AF_INET6; 393274246Sae sin6->sin6_len = sizeof(*sin6); 394103026Ssobomax break; 395274246Sae#endif 396103026Ssobomax } 397274246Sae if (error == 0) { 398274246Sae switch (cmd) { 399103026Ssobomax#ifdef INET 400274246Sae case SIOCGIFPSRCADDR: 401274246Sae sin->sin_addr = sc->gre_oip.ip_src; 402274246Sae break; 403274246Sae case SIOCGIFPDSTADDR: 404274246Sae sin->sin_addr = sc->gre_oip.ip_dst; 405274246Sae break; 406103026Ssobomax#endif 407274246Sae#ifdef INET6 408274246Sae case SIOCGIFPSRCADDR_IN6: 409274246Sae sin6->sin6_addr = sc->gre_oip6.ip6_src; 410274246Sae break; 411274246Sae case SIOCGIFPDSTADDR_IN6: 412274246Sae sin6->sin6_addr = sc->gre_oip6.ip6_dst; 413274246Sae break; 414103026Ssobomax#endif 415274246Sae } 416103026Ssobomax } 417274246Sae GRE_RUNLOCK(sc); 418219206Sbz if (error != 0) 419219206Sbz break; 420274246Sae switch (cmd) { 421274246Sae#ifdef INET 422274246Sae case SIOCGIFPSRCADDR: 423274246Sae case SIOCGIFPDSTADDR: 424274246Sae error = prison_if(curthread->td_ucred, 425274246Sae (struct sockaddr *)sin); 426274246Sae if (error != 0) 427274246Sae memset(sin, 0, sizeof(*sin)); 428219206Sbz break; 429274246Sae#endif 430122699Sbms#ifdef INET6 431274246Sae case SIOCGIFPSRCADDR_IN6: 432274246Sae case SIOCGIFPDSTADDR_IN6: 433274246Sae error = prison_if(curthread->td_ucred, 434274246Sae (struct sockaddr *)sin6); 435274246Sae if (error == 0) 436274246Sae error = sa6_recoverscope(sin6); 437274246Sae if (error != 0) 438274246Sae memset(sin6, 0, sizeof(*sin6)); 439122699Sbms#endif 440103026Ssobomax } 441103026Ssobomax break; 442282809Sae case SIOCGTUNFIB: 443282809Sae ifr->ifr_fib = sc->gre_fibnum; 444282809Sae break; 445282809Sae case SIOCSTUNFIB: 446282809Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 447282809Sae break; 448282809Sae if (ifr->ifr_fib >= rt_numfibs) 449282809Sae error = EINVAL; 450282809Sae else 451282809Sae sc->gre_fibnum = ifr->ifr_fib; 452282809Sae break; 453274246Sae case GRESKEY: 454274246Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 455103026Ssobomax break; 456332288Sbrooks if ((error = copyin(ifr_data_get_ptr(ifr), &opt, 457332288Sbrooks sizeof(opt))) != 0) 458274246Sae break; 459274246Sae if (sc->gre_key != opt) { 460274246Sae GRE_WLOCK(sc); 461274246Sae sc->gre_key = opt; 462274246Sae gre_updatehdr(sc); 463274246Sae GRE_WUNLOCK(sc); 464103026Ssobomax } 465103026Ssobomax break; 466274246Sae case GREGKEY: 467332288Sbrooks error = copyout(&sc->gre_key, ifr_data_get_ptr(ifr), 468282809Sae sizeof(sc->gre_key)); 469274246Sae break; 470274246Sae case GRESOPTS: 471274246Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 472179894Sthompsa break; 473332288Sbrooks if ((error = copyin(ifr_data_get_ptr(ifr), &opt, 474332288Sbrooks sizeof(opt))) != 0) 475179894Sthompsa break; 476274246Sae if (opt & ~GRE_OPTMASK) 477179894Sthompsa error = EINVAL; 478274246Sae else { 479274246Sae if (sc->gre_options != opt) { 480274246Sae GRE_WLOCK(sc); 481274246Sae sc->gre_options = opt; 482274246Sae gre_updatehdr(sc); 483274246Sae GRE_WUNLOCK(sc); 484274246Sae } 485179894Sthompsa } 486179894Sthompsa break; 487274246Sae 488274246Sae case GREGOPTS: 489332288Sbrooks error = copyout(&sc->gre_options, ifr_data_get_ptr(ifr), 490274246Sae sizeof(sc->gre_options)); 491179894Sthompsa break; 492103026Ssobomax default: 493103026Ssobomax error = EINVAL; 494103026Ssobomax break; 495103026Ssobomax } 496274246Saeend: 497274246Sae sx_xunlock(&gre_ioctl_sx); 498103026Ssobomax return (error); 499103026Ssobomax} 500103026Ssobomax 501274246Saestatic void 502274246Saegre_updatehdr(struct gre_softc *sc) 503103026Ssobomax{ 504274246Sae struct grehdr *gh = NULL; 505274246Sae uint32_t *opts; 506274246Sae uint16_t flags; 507103026Ssobomax 508274246Sae GRE_WLOCK_ASSERT(sc); 509274246Sae switch (sc->gre_family) { 510274246Sae#ifdef INET 511274246Sae case AF_INET: 512274246Sae sc->gre_hlen = sizeof(struct greip); 513274246Sae sc->gre_oip.ip_v = IPPROTO_IPV4; 514274246Sae sc->gre_oip.ip_hl = sizeof(struct ip) >> 2; 515274246Sae sc->gre_oip.ip_p = IPPROTO_GRE; 516274246Sae gh = &sc->gre_gihdr->gi_gre; 517274246Sae break; 518274246Sae#endif 519274246Sae#ifdef INET6 520274246Sae case AF_INET6: 521274246Sae sc->gre_hlen = sizeof(struct greip6); 522274246Sae sc->gre_oip6.ip6_vfc = IPV6_VERSION; 523274246Sae sc->gre_oip6.ip6_nxt = IPPROTO_GRE; 524274246Sae gh = &sc->gre_gi6hdr->gi6_gre; 525274246Sae break; 526274246Sae#endif 527274246Sae default: 528274246Sae return; 529274246Sae } 530274246Sae flags = 0; 531274246Sae opts = gh->gre_opts; 532274246Sae if (sc->gre_options & GRE_ENABLE_CSUM) { 533274246Sae flags |= GRE_FLAGS_CP; 534274246Sae sc->gre_hlen += 2 * sizeof(uint16_t); 535274246Sae *opts++ = 0; 536274246Sae } 537274246Sae if (sc->gre_key != 0) { 538274246Sae flags |= GRE_FLAGS_KP; 539274246Sae sc->gre_hlen += sizeof(uint32_t); 540274246Sae *opts++ = htonl(sc->gre_key); 541274246Sae } 542274246Sae if (sc->gre_options & GRE_ENABLE_SEQ) { 543274246Sae flags |= GRE_FLAGS_SP; 544274246Sae sc->gre_hlen += sizeof(uint32_t); 545274246Sae *opts++ = 0; 546274246Sae } else 547274246Sae sc->gre_oseq = 0; 548274246Sae gh->gre_flags = htons(flags); 549274246Sae} 550103026Ssobomax 551274246Saestatic void 552274246Saegre_detach(struct gre_softc *sc) 553274246Sae{ 554103026Ssobomax 555274246Sae sx_assert(&gre_ioctl_sx, SA_XLOCKED); 556274246Sae if (sc->gre_ecookie != NULL) 557274246Sae encap_detach(sc->gre_ecookie); 558274246Sae sc->gre_ecookie = NULL; 559274246Sae} 560274246Sae 561274246Saestatic int 562274246Saegre_set_tunnel(struct ifnet *ifp, struct sockaddr *src, 563274246Sae struct sockaddr *dst) 564274246Sae{ 565274246Sae struct gre_softc *sc, *tsc; 566274246Sae#ifdef INET6 567274246Sae struct ip6_hdr *ip6; 568274246Sae#endif 569274246Sae#ifdef INET 570274246Sae struct ip *ip; 571274246Sae#endif 572274246Sae void *hdr; 573274246Sae int error; 574274246Sae 575274246Sae sx_assert(&gre_ioctl_sx, SA_XLOCKED); 576274246Sae GRE_LIST_LOCK(); 577274246Sae sc = ifp->if_softc; 578274246Sae LIST_FOREACH(tsc, &V_gre_softc_list, gre_list) { 579274246Sae if (tsc == sc || tsc->gre_family != src->sa_family) 580274246Sae continue; 581274246Sae#ifdef INET 582274246Sae if (tsc->gre_family == AF_INET && 583274246Sae tsc->gre_oip.ip_src.s_addr == 584274246Sae satosin(src)->sin_addr.s_addr && 585274246Sae tsc->gre_oip.ip_dst.s_addr == 586274246Sae satosin(dst)->sin_addr.s_addr) { 587274246Sae GRE_LIST_UNLOCK(); 588274246Sae return (EADDRNOTAVAIL); 589274246Sae } 590274246Sae#endif 591274246Sae#ifdef INET6 592274246Sae if (tsc->gre_family == AF_INET6 && 593274246Sae IN6_ARE_ADDR_EQUAL(&tsc->gre_oip6.ip6_src, 594274246Sae &satosin6(src)->sin6_addr) && 595274246Sae IN6_ARE_ADDR_EQUAL(&tsc->gre_oip6.ip6_dst, 596274246Sae &satosin6(dst)->sin6_addr)) { 597274246Sae GRE_LIST_UNLOCK(); 598274246Sae return (EADDRNOTAVAIL); 599274246Sae } 600274246Sae#endif 601103026Ssobomax } 602274246Sae GRE_LIST_UNLOCK(); 603103026Ssobomax 604274246Sae switch (src->sa_family) { 605274246Sae#ifdef INET 606274246Sae case AF_INET: 607274246Sae hdr = ip = malloc(sizeof(struct greip) + 608274246Sae 3 * sizeof(uint32_t), M_GRE, M_WAITOK | M_ZERO); 609274246Sae ip->ip_src = satosin(src)->sin_addr; 610274246Sae ip->ip_dst = satosin(dst)->sin_addr; 611274246Sae break; 612103026Ssobomax#endif 613274246Sae#ifdef INET6 614274246Sae case AF_INET6: 615274246Sae hdr = ip6 = malloc(sizeof(struct greip6) + 616274246Sae 3 * sizeof(uint32_t), M_GRE, M_WAITOK | M_ZERO); 617274246Sae ip6->ip6_src = satosin6(src)->sin6_addr; 618274246Sae ip6->ip6_dst = satosin6(dst)->sin6_addr; 619274246Sae break; 620274246Sae#endif 621274246Sae default: 622274246Sae return (EAFNOSUPPORT); 623274246Sae } 624288529Sae if (sc->gre_family != 0) 625274246Sae gre_detach(sc); 626274246Sae GRE_WLOCK(sc); 627274246Sae if (sc->gre_family != 0) 628274246Sae free(sc->gre_hdr, M_GRE); 629274246Sae sc->gre_family = src->sa_family; 630274246Sae sc->gre_hdr = hdr; 631274246Sae sc->gre_oseq = 0; 632274246Sae sc->gre_iseq = UINT32_MAX; 633274246Sae gre_updatehdr(sc); 634274246Sae GRE_WUNLOCK(sc); 635103026Ssobomax 636274289Sbz error = 0; 637274246Sae switch (src->sa_family) { 638274246Sae#ifdef INET 639274246Sae case AF_INET: 640274246Sae error = in_gre_attach(sc); 641274246Sae break; 642274246Sae#endif 643274246Sae#ifdef INET6 644274246Sae case AF_INET6: 645274246Sae error = in6_gre_attach(sc); 646274246Sae break; 647274246Sae#endif 648274246Sae } 649288575Shrs if (error == 0) { 650274246Sae ifp->if_drv_flags |= IFF_DRV_RUNNING; 651288575Shrs if_link_state_change(ifp, LINK_STATE_UP); 652288575Shrs } 653274246Sae return (error); 654274246Sae} 655103026Ssobomax 656274246Saestatic void 657274246Saegre_delete_tunnel(struct ifnet *ifp) 658274246Sae{ 659274246Sae struct gre_softc *sc = ifp->if_softc; 660274246Sae int family; 661274246Sae 662274246Sae GRE_WLOCK(sc); 663274246Sae family = sc->gre_family; 664274246Sae sc->gre_family = 0; 665274246Sae GRE_WUNLOCK(sc); 666274246Sae if (family != 0) { 667274246Sae gre_detach(sc); 668274246Sae free(sc->gre_hdr, M_GRE); 669274246Sae } 670274246Sae ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 671288575Shrs if_link_state_change(ifp, LINK_STATE_DOWN); 672274246Sae} 673274246Sae 674274246Saeint 675274246Saegre_input(struct mbuf **mp, int *offp, int proto) 676274246Sae{ 677274246Sae struct gre_softc *sc; 678274246Sae struct grehdr *gh; 679274246Sae struct ifnet *ifp; 680274246Sae struct mbuf *m; 681292972Saraujo uint32_t *opts; 682292972Saraujo#ifdef notyet 683292972Saraujo uint32_t key; 684292972Saraujo#endif 685274246Sae uint16_t flags; 686274246Sae int hlen, isr, af; 687274246Sae 688274246Sae m = *mp; 689274246Sae sc = encap_getarg(m); 690274246Sae KASSERT(sc != NULL, ("encap_getarg returned NULL")); 691274246Sae 692274246Sae ifp = GRE2IFP(sc); 693290116Sae hlen = *offp + sizeof(struct grehdr) + 4 * sizeof(uint32_t); 694290116Sae if (m->m_pkthdr.len < hlen) 695290116Sae goto drop; 696290116Sae if (m->m_len < hlen) { 697290116Sae m = m_pullup(m, hlen); 698290116Sae if (m == NULL) 699290116Sae goto drop; 700290116Sae } 701274246Sae gh = (struct grehdr *)mtodo(m, *offp); 702274246Sae flags = ntohs(gh->gre_flags); 703274246Sae if (flags & ~GRE_FLAGS_MASK) 704274246Sae goto drop; 705274246Sae opts = gh->gre_opts; 706274246Sae hlen = 2 * sizeof(uint16_t); 707274246Sae if (flags & GRE_FLAGS_CP) { 708274246Sae /* reserved1 field must be zero */ 709274246Sae if (((uint16_t *)opts)[1] != 0) 710274246Sae goto drop; 711274246Sae if (in_cksum_skip(m, m->m_pkthdr.len, *offp) != 0) 712274246Sae goto drop; 713274246Sae hlen += 2 * sizeof(uint16_t); 714274246Sae opts++; 715274246Sae } 716274246Sae if (flags & GRE_FLAGS_KP) { 717292972Saraujo#ifdef notyet 718292972Saraujo /* 719292972Saraujo * XXX: The current implementation uses the key only for outgoing 720292972Saraujo * packets. But we can check the key value here, or even in the 721292972Saraujo * encapcheck function. 722292972Saraujo */ 723274246Sae key = ntohl(*opts); 724292972Saraujo#endif 725274246Sae hlen += sizeof(uint32_t); 726274246Sae opts++; 727292972Saraujo } 728292972Saraujo#ifdef notyet 729274246Sae } else 730274246Sae key = 0; 731292972Saraujo 732274246Sae if (sc->gre_key != 0 && (key != sc->gre_key || key != 0)) 733274246Sae goto drop; 734292972Saraujo#endif 735274246Sae if (flags & GRE_FLAGS_SP) { 736292972Saraujo#ifdef notyet 737292972Saraujo seq = ntohl(*opts); 738292972Saraujo#endif 739274246Sae hlen += sizeof(uint32_t); 740274246Sae } 741274246Sae switch (ntohs(gh->gre_proto)) { 742274246Sae case ETHERTYPE_WCCP: 743274246Sae /* 744274246Sae * For WCCP skip an additional 4 bytes if after GRE header 745274246Sae * doesn't follow an IP header. 746274246Sae */ 747274246Sae if (flags == 0 && (*(uint8_t *)gh->gre_opts & 0xF0) != 0x40) 748274246Sae hlen += sizeof(uint32_t); 749274246Sae /* FALLTHROUGH */ 750274246Sae case ETHERTYPE_IP: 751274246Sae isr = NETISR_IP; 752274246Sae af = AF_INET; 753274246Sae break; 754274246Sae case ETHERTYPE_IPV6: 755274246Sae isr = NETISR_IPV6; 756274246Sae af = AF_INET6; 757274246Sae break; 758274246Sae default: 759274246Sae goto drop; 760274246Sae } 761274246Sae m_adj(m, *offp + hlen); 762274246Sae m_clrprotoflags(m); 763274246Sae m->m_pkthdr.rcvif = ifp; 764282809Sae M_SETFIB(m, ifp->if_fib); 765274246Sae#ifdef MAC 766274246Sae mac_ifnet_create_mbuf(ifp, m); 767103026Ssobomax#endif 768274246Sae BPF_MTAP2(ifp, &af, sizeof(af), m); 769274246Sae if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 770274246Sae if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 771274246Sae if ((ifp->if_flags & IFF_MONITOR) != 0) 772274246Sae m_freem(m); 773274246Sae else 774274246Sae netisr_dispatch(isr, m); 775274246Sae return (IPPROTO_DONE); 776274246Saedrop: 777274246Sae if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 778274246Sae m_freem(m); 779274246Sae return (IPPROTO_DONE); 780274246Sae} 781274246Sae 782274246Sae#define MTAG_GRE 1307983903 783274246Saestatic int 784274246Saegre_check_nesting(struct ifnet *ifp, struct mbuf *m) 785274246Sae{ 786274246Sae struct m_tag *mtag; 787274246Sae int count; 788274246Sae 789274246Sae count = 1; 790274246Sae mtag = NULL; 791276902Sae while ((mtag = m_tag_locate(m, MTAG_GRE, 0, mtag)) != NULL) { 792274246Sae if (*(struct ifnet **)(mtag + 1) == ifp) { 793274246Sae log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname); 794274246Sae return (EIO); 795274246Sae } 796274246Sae count++; 797103026Ssobomax } 798274246Sae if (count > V_max_gre_nesting) { 799274246Sae log(LOG_NOTICE, 800274246Sae "%s: if_output recursively called too many times(%d)\n", 801274246Sae ifp->if_xname, count); 802274246Sae return (EIO); 803274246Sae } 804274246Sae mtag = m_tag_alloc(MTAG_GRE, 0, sizeof(struct ifnet *), M_NOWAIT); 805274246Sae if (mtag == NULL) 806274246Sae return (ENOMEM); 807274246Sae *(struct ifnet **)(mtag + 1) = ifp; 808274246Sae m_tag_prepend(m, mtag); 809274246Sae return (0); 810274246Sae} 811103026Ssobomax 812274246Saestatic int 813274246Saegre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 814274246Sae struct route *ro) 815274246Sae{ 816274246Sae uint32_t af; 817274246Sae int error; 818103026Ssobomax 819274246Sae#ifdef MAC 820274246Sae error = mac_ifnet_check_transmit(ifp, m); 821274246Sae if (error != 0) 822274246Sae goto drop; 823103026Ssobomax#endif 824274246Sae if ((ifp->if_flags & IFF_MONITOR) != 0 || 825274246Sae (ifp->if_flags & IFF_UP) == 0) { 826274246Sae error = ENETDOWN; 827274246Sae goto drop; 828274246Sae } 829103026Ssobomax 830274246Sae error = gre_check_nesting(ifp, m); 831274246Sae if (error != 0) 832274246Sae goto drop; 833274246Sae 834274246Sae m->m_flags &= ~(M_BCAST|M_MCAST); 835274246Sae if (dst->sa_family == AF_UNSPEC) 836274246Sae bcopy(dst->sa_data, &af, sizeof(af)); 837274246Sae else 838274246Sae af = dst->sa_family; 839274246Sae BPF_MTAP2(ifp, &af, sizeof(af), m); 840274246Sae m->m_pkthdr.csum_data = af; /* save af for if_transmit */ 841274246Sae return (ifp->if_transmit(ifp, m)); 842274246Saedrop: 843274246Sae m_freem(m); 844274246Sae if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 845274246Sae return (error); 846103026Ssobomax} 847103026Ssobomax 848274246Saestatic void 849274246Saegre_setseqn(struct grehdr *gh, uint32_t seq) 850103026Ssobomax{ 851274246Sae uint32_t *opts; 852274246Sae uint16_t flags; 853103026Ssobomax 854274246Sae opts = gh->gre_opts; 855274246Sae flags = ntohs(gh->gre_flags); 856274246Sae KASSERT((flags & GRE_FLAGS_SP) != 0, 857274246Sae ("gre_setseqn called, but GRE_FLAGS_SP isn't set ")); 858274246Sae if (flags & GRE_FLAGS_CP) 859274246Sae opts++; 860274246Sae if (flags & GRE_FLAGS_KP) 861274246Sae opts++; 862274246Sae *opts = htonl(seq); 863274246Sae} 864103026Ssobomax 865274246Saestatic int 866274246Saegre_transmit(struct ifnet *ifp, struct mbuf *m) 867274246Sae{ 868274246Sae GRE_RLOCK_TRACKER; 869274246Sae struct gre_softc *sc; 870274246Sae struct grehdr *gh; 871274246Sae uint32_t iaf, oaf, oseq; 872274246Sae int error, hlen, olen, plen; 873274246Sae int want_seq, want_csum; 874274246Sae 875274246Sae plen = 0; 876274246Sae sc = ifp->if_softc; 877274246Sae if (sc == NULL) { 878274246Sae error = ENETDOWN; 879274246Sae m_freem(m); 880274246Sae goto drop; 881103026Ssobomax } 882274246Sae GRE_RLOCK(sc); 883274246Sae if (sc->gre_family == 0) { 884274246Sae GRE_RUNLOCK(sc); 885274246Sae error = ENETDOWN; 886274246Sae m_freem(m); 887274246Sae goto drop; 888274246Sae } 889274246Sae iaf = m->m_pkthdr.csum_data; 890274246Sae oaf = sc->gre_family; 891274246Sae hlen = sc->gre_hlen; 892274246Sae want_seq = (sc->gre_options & GRE_ENABLE_SEQ) != 0; 893274246Sae if (want_seq) 894274246Sae oseq = sc->gre_oseq++; /* XXX */ 895274289Sbz else 896274289Sbz oseq = 0; /* Make compiler happy. */ 897274246Sae want_csum = (sc->gre_options & GRE_ENABLE_CSUM) != 0; 898274246Sae M_SETFIB(m, sc->gre_fibnum); 899274246Sae M_PREPEND(m, hlen, M_NOWAIT); 900274246Sae if (m == NULL) { 901274246Sae GRE_RUNLOCK(sc); 902274246Sae error = ENOBUFS; 903274246Sae goto drop; 904274246Sae } 905274246Sae bcopy(sc->gre_hdr, mtod(m, void *), hlen); 906274246Sae GRE_RUNLOCK(sc); 907274246Sae switch (oaf) { 908274246Sae#ifdef INET 909274246Sae case AF_INET: 910274246Sae olen = sizeof(struct ip); 911274246Sae break; 912274246Sae#endif 913274246Sae#ifdef INET6 914274246Sae case AF_INET6: 915274246Sae olen = sizeof(struct ip6_hdr); 916274246Sae break; 917274246Sae#endif 918274246Sae default: 919274246Sae error = ENETDOWN; 920274246Sae goto drop; 921274246Sae } 922274246Sae gh = (struct grehdr *)mtodo(m, olen); 923274246Sae switch (iaf) { 924274246Sae#ifdef INET 925274246Sae case AF_INET: 926274246Sae gh->gre_proto = htons(ETHERTYPE_IP); 927274246Sae break; 928274246Sae#endif 929274246Sae#ifdef INET6 930274246Sae case AF_INET6: 931274246Sae gh->gre_proto = htons(ETHERTYPE_IPV6); 932274246Sae break; 933274246Sae#endif 934274246Sae default: 935274246Sae error = ENETDOWN; 936274246Sae goto drop; 937274246Sae } 938274246Sae if (want_seq) 939274246Sae gre_setseqn(gh, oseq); 940274246Sae if (want_csum) { 941274246Sae *(uint16_t *)gh->gre_opts = in_cksum_skip(m, 942274246Sae m->m_pkthdr.len, olen); 943274246Sae } 944274246Sae plen = m->m_pkthdr.len - hlen; 945274246Sae switch (oaf) { 946274246Sae#ifdef INET 947274246Sae case AF_INET: 948274246Sae error = in_gre_output(m, iaf, hlen); 949274246Sae break; 950274246Sae#endif 951274246Sae#ifdef INET6 952274246Sae case AF_INET6: 953274246Sae error = in6_gre_output(m, iaf, hlen); 954274246Sae break; 955274246Sae#endif 956274246Sae default: 957274246Sae m_freem(m); 958274246Sae error = ENETDOWN; 959297793Spfg } 960274246Saedrop: 961274246Sae if (error) 962274246Sae if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 963274246Sae else { 964274246Sae if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 965274246Sae if_inc_counter(ifp, IFCOUNTER_OBYTES, plen); 966274246Sae } 967274246Sae return (error); 968274246Sae} 969103026Ssobomax 970274246Saestatic void 971274246Saegre_qflush(struct ifnet *ifp __unused) 972274246Sae{ 973274246Sae 974103026Ssobomax} 975103026Ssobomax 976103026Ssobomaxstatic int 977103026Ssobomaxgremodevent(module_t mod, int type, void *data) 978103026Ssobomax{ 979103026Ssobomax 980103026Ssobomax switch (type) { 981103026Ssobomax case MOD_LOAD: 982103026Ssobomax case MOD_UNLOAD: 983103026Ssobomax break; 984132199Sphk default: 985271918Shrs return (EOPNOTSUPP); 986103026Ssobomax } 987271918Shrs return (0); 988103026Ssobomax} 989103026Ssobomax 990103026Ssobomaxstatic moduledata_t gre_mod = { 991103026Ssobomax "if_gre", 992103026Ssobomax gremodevent, 993241394Skevlo 0 994103026Ssobomax}; 995103026Ssobomax 996103026SsobomaxDECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 997103026SsobomaxMODULE_VERSION(if_gre, 1); 998