1c398230bSWarner Losh /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-NetBSD 3fe267a55SPedro F. Giffuni * 48e96e13eSMaxim Sobolev * Copyright (c) 1998 The NetBSD Foundation, Inc. 5a5185adeSAndrey V. Elsukov * Copyright (c) 2014, 2018 Andrey V. Elsukov <ae@FreeBSD.org> 68e96e13eSMaxim Sobolev * All rights reserved. 78e96e13eSMaxim Sobolev * 88e96e13eSMaxim Sobolev * This code is derived from software contributed to The NetBSD Foundation 98e96e13eSMaxim Sobolev * by Heiko W.Rupp <hwr@pilhuhn.de> 108e96e13eSMaxim Sobolev * 119e669156SBjoern A. Zeeb * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de> 129e669156SBjoern A. Zeeb * 138e96e13eSMaxim Sobolev * Redistribution and use in source and binary forms, with or without 148e96e13eSMaxim Sobolev * modification, are permitted provided that the following conditions 158e96e13eSMaxim Sobolev * are met: 168e96e13eSMaxim Sobolev * 1. Redistributions of source code must retain the above copyright 178e96e13eSMaxim Sobolev * notice, this list of conditions and the following disclaimer. 188e96e13eSMaxim Sobolev * 2. Redistributions in binary form must reproduce the above copyright 198e96e13eSMaxim Sobolev * notice, this list of conditions and the following disclaimer in the 208e96e13eSMaxim Sobolev * documentation and/or other materials provided with the distribution. 218e96e13eSMaxim Sobolev * 228e96e13eSMaxim Sobolev * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 238e96e13eSMaxim Sobolev * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 248e96e13eSMaxim Sobolev * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 258e96e13eSMaxim Sobolev * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 268e96e13eSMaxim Sobolev * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 278e96e13eSMaxim Sobolev * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 288e96e13eSMaxim Sobolev * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 298e96e13eSMaxim Sobolev * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 308e96e13eSMaxim Sobolev * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 318e96e13eSMaxim Sobolev * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 328e96e13eSMaxim Sobolev * POSSIBILITY OF SUCH DAMAGE. 33f325335cSAndrey V. Elsukov * 34f325335cSAndrey V. Elsukov * $NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun Exp $ 358e96e13eSMaxim Sobolev */ 368e96e13eSMaxim Sobolev 374b421e2dSMike Silbersack #include <sys/cdefs.h> 384b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 394b421e2dSMike Silbersack 408e96e13eSMaxim Sobolev #include "opt_inet.h" 419e669156SBjoern A. Zeeb #include "opt_inet6.h" 428e96e13eSMaxim Sobolev 438e96e13eSMaxim Sobolev #include <sys/param.h> 44a5185adeSAndrey V. Elsukov #include <sys/jail.h> 458e96e13eSMaxim Sobolev #include <sys/systm.h> 468e96e13eSMaxim Sobolev #include <sys/socket.h> 47aee793eeSAndrey V. Elsukov #include <sys/socketvar.h> 48a5185adeSAndrey V. Elsukov #include <sys/sockio.h> 49a5185adeSAndrey V. Elsukov #include <sys/mbuf.h> 508e96e13eSMaxim Sobolev #include <sys/errno.h> 518e96e13eSMaxim Sobolev #include <sys/kernel.h> 52f325335cSAndrey V. Elsukov #include <sys/sysctl.h> 53a5185adeSAndrey V. Elsukov #include <sys/malloc.h> 546573d758SMatt Macy #include <sys/proc.h> 55a5185adeSAndrey V. Elsukov 568e96e13eSMaxim Sobolev #include <net/if.h> 5776039bc8SGleb Smirnoff #include <net/if_var.h> 58f325335cSAndrey V. Elsukov #include <net/vnet.h> 598e96e13eSMaxim Sobolev 608e96e13eSMaxim Sobolev #include <netinet/in.h> 618e96e13eSMaxim Sobolev #include <netinet/in_var.h> 62aee793eeSAndrey V. Elsukov #include <netinet/in_pcb.h> 638e96e13eSMaxim Sobolev #include <netinet/ip.h> 64f325335cSAndrey V. Elsukov #include <netinet/ip_encap.h> 658e96e13eSMaxim Sobolev #include <netinet/ip_var.h> 66aee793eeSAndrey V. Elsukov #include <netinet/udp.h> 67aee793eeSAndrey V. Elsukov #include <netinet/udp_var.h> 68f325335cSAndrey V. Elsukov 69f325335cSAndrey V. Elsukov #ifdef INET6 70f325335cSAndrey V. Elsukov #include <netinet/ip6.h> 718e96e13eSMaxim Sobolev #endif 728e96e13eSMaxim Sobolev 738e96e13eSMaxim Sobolev #include <net/if_gre.h> 74aee793eeSAndrey V. Elsukov #include <machine/in_cksum.h> 758e96e13eSMaxim Sobolev 76f325335cSAndrey V. Elsukov #define GRE_TTL 30 77f325335cSAndrey V. Elsukov VNET_DEFINE(int, ip_gre_ttl) = GRE_TTL; 78f325335cSAndrey V. Elsukov #define V_ip_gre_ttl VNET(ip_gre_ttl) 79f325335cSAndrey V. Elsukov SYSCTL_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_VNET | CTLFLAG_RW, 806d8fdfa9SAndrey V. Elsukov &VNET_NAME(ip_gre_ttl), 0, "Default TTL value for encapsulated packets"); 818e96e13eSMaxim Sobolev 82aee793eeSAndrey V. Elsukov struct in_gre_socket { 83aee793eeSAndrey V. Elsukov struct gre_socket base; 84aee793eeSAndrey V. Elsukov in_addr_t addr; 85aee793eeSAndrey V. Elsukov }; 86aee793eeSAndrey V. Elsukov VNET_DEFINE_STATIC(struct gre_sockets *, ipv4_sockets) = NULL; 875f901c92SAndrew Turner VNET_DEFINE_STATIC(struct gre_list *, ipv4_hashtbl) = NULL; 8819873f47SAndrey V. Elsukov VNET_DEFINE_STATIC(struct gre_list *, ipv4_srchashtbl) = NULL; 89aee793eeSAndrey V. Elsukov #define V_ipv4_sockets VNET(ipv4_sockets) 90a5185adeSAndrey V. Elsukov #define V_ipv4_hashtbl VNET(ipv4_hashtbl) 9119873f47SAndrey V. Elsukov #define V_ipv4_srchashtbl VNET(ipv4_srchashtbl) 92a5185adeSAndrey V. Elsukov #define GRE_HASH(src, dst) (V_ipv4_hashtbl[\ 93a5185adeSAndrey V. Elsukov in_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)]) 9419873f47SAndrey V. Elsukov #define GRE_SRCHASH(src) (V_ipv4_srchashtbl[\ 9519873f47SAndrey V. Elsukov fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)]) 96aee793eeSAndrey V. Elsukov #define GRE_SOCKHASH(src) (V_ipv4_sockets[\ 97aee793eeSAndrey V. Elsukov fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)]) 98a5185adeSAndrey V. Elsukov #define GRE_HASH_SC(sc) GRE_HASH((sc)->gre_oip.ip_src.s_addr,\ 99a5185adeSAndrey V. Elsukov (sc)->gre_oip.ip_dst.s_addr) 1008e96e13eSMaxim Sobolev 101a5185adeSAndrey V. Elsukov static uint32_t 102a5185adeSAndrey V. Elsukov in_gre_hashval(in_addr_t src, in_addr_t dst) 103a5185adeSAndrey V. Elsukov { 104a5185adeSAndrey V. Elsukov uint32_t ret; 105a5185adeSAndrey V. Elsukov 106a5185adeSAndrey V. Elsukov ret = fnv_32_buf(&src, sizeof(src), FNV1_32_INIT); 107a5185adeSAndrey V. Elsukov return (fnv_32_buf(&dst, sizeof(dst), ret)); 108a5185adeSAndrey V. Elsukov } 109a5185adeSAndrey V. Elsukov 110aee793eeSAndrey V. Elsukov static struct gre_socket* 111aee793eeSAndrey V. Elsukov in_gre_lookup_socket(in_addr_t addr) 112a5185adeSAndrey V. Elsukov { 113aee793eeSAndrey V. Elsukov struct gre_socket *gs; 114aee793eeSAndrey V. Elsukov struct in_gre_socket *s; 115aee793eeSAndrey V. Elsukov 116aee793eeSAndrey V. Elsukov CK_LIST_FOREACH(gs, &GRE_SOCKHASH(addr), chain) { 117aee793eeSAndrey V. Elsukov s = __containerof(gs, struct in_gre_socket, base); 118aee793eeSAndrey V. Elsukov if (s->addr == addr) 119aee793eeSAndrey V. Elsukov break; 120aee793eeSAndrey V. Elsukov } 121aee793eeSAndrey V. Elsukov return (gs); 122aee793eeSAndrey V. Elsukov } 123aee793eeSAndrey V. Elsukov 124aee793eeSAndrey V. Elsukov static int 125aee793eeSAndrey V. Elsukov in_gre_checkdup(const struct gre_softc *sc, in_addr_t src, in_addr_t dst, 126aee793eeSAndrey V. Elsukov uint32_t opts) 127aee793eeSAndrey V. Elsukov { 128aee793eeSAndrey V. Elsukov struct gre_list *head; 129a5185adeSAndrey V. Elsukov struct gre_softc *tmp; 130aee793eeSAndrey V. Elsukov struct gre_socket *gs; 131a5185adeSAndrey V. Elsukov 132a5185adeSAndrey V. Elsukov if (sc->gre_family == AF_INET && 133a5185adeSAndrey V. Elsukov sc->gre_oip.ip_src.s_addr == src && 134aee793eeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr == dst && 135aee793eeSAndrey V. Elsukov (sc->gre_options & GRE_UDPENCAP) == (opts & GRE_UDPENCAP)) 136a5185adeSAndrey V. Elsukov return (EEXIST); 137a5185adeSAndrey V. Elsukov 138aee793eeSAndrey V. Elsukov if (opts & GRE_UDPENCAP) { 139aee793eeSAndrey V. Elsukov gs = in_gre_lookup_socket(src); 140aee793eeSAndrey V. Elsukov if (gs == NULL) 141aee793eeSAndrey V. Elsukov return (0); 142aee793eeSAndrey V. Elsukov head = &gs->list; 143aee793eeSAndrey V. Elsukov } else 144aee793eeSAndrey V. Elsukov head = &GRE_HASH(src, dst); 145aee793eeSAndrey V. Elsukov 146aee793eeSAndrey V. Elsukov CK_LIST_FOREACH(tmp, head, chain) { 147a5185adeSAndrey V. Elsukov if (tmp == sc) 148a5185adeSAndrey V. Elsukov continue; 149a5185adeSAndrey V. Elsukov if (tmp->gre_oip.ip_src.s_addr == src && 150a5185adeSAndrey V. Elsukov tmp->gre_oip.ip_dst.s_addr == dst) 151a5185adeSAndrey V. Elsukov return (EADDRNOTAVAIL); 152a5185adeSAndrey V. Elsukov } 153a5185adeSAndrey V. Elsukov return (0); 154a5185adeSAndrey V. Elsukov } 155a5185adeSAndrey V. Elsukov 156a5185adeSAndrey V. Elsukov static int 157a5185adeSAndrey V. Elsukov in_gre_lookup(const struct mbuf *m, int off, int proto, void **arg) 158a5185adeSAndrey V. Elsukov { 159a5185adeSAndrey V. Elsukov const struct ip *ip; 160a5185adeSAndrey V. Elsukov struct gre_softc *sc; 161a5185adeSAndrey V. Elsukov 1626e081509SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) 1636e081509SAndrey V. Elsukov return (0); 1646e081509SAndrey V. Elsukov 16597168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 166a5185adeSAndrey V. Elsukov ip = mtod(m, const struct ip *); 167a5185adeSAndrey V. Elsukov CK_LIST_FOREACH(sc, &GRE_HASH(ip->ip_dst.s_addr, 168a5185adeSAndrey V. Elsukov ip->ip_src.s_addr), chain) { 169a5185adeSAndrey V. Elsukov /* 170a5185adeSAndrey V. Elsukov * This is an inbound packet, its ip_dst is source address 171a5185adeSAndrey V. Elsukov * in softc. 172a5185adeSAndrey V. Elsukov */ 173a5185adeSAndrey V. Elsukov if (sc->gre_oip.ip_src.s_addr == ip->ip_dst.s_addr && 174a5185adeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr == ip->ip_src.s_addr) { 175f325335cSAndrey V. Elsukov if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0) 176f325335cSAndrey V. Elsukov return (0); 177a5185adeSAndrey V. Elsukov *arg = sc; 178a5185adeSAndrey V. Elsukov return (ENCAP_DRV_LOOKUP); 179a5185adeSAndrey V. Elsukov } 180a5185adeSAndrey V. Elsukov } 181f325335cSAndrey V. Elsukov return (0); 1828e96e13eSMaxim Sobolev } 1838e96e13eSMaxim Sobolev 18419873f47SAndrey V. Elsukov /* 18519873f47SAndrey V. Elsukov * Check that ingress address belongs to local host. 18619873f47SAndrey V. Elsukov */ 18719873f47SAndrey V. Elsukov static void 18819873f47SAndrey V. Elsukov in_gre_set_running(struct gre_softc *sc) 18919873f47SAndrey V. Elsukov { 19019873f47SAndrey V. Elsukov 19119873f47SAndrey V. Elsukov if (in_localip(sc->gre_oip.ip_src)) 19219873f47SAndrey V. Elsukov GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; 19319873f47SAndrey V. Elsukov else 19419873f47SAndrey V. Elsukov GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 19519873f47SAndrey V. Elsukov } 19619873f47SAndrey V. Elsukov 19719873f47SAndrey V. Elsukov /* 19819873f47SAndrey V. Elsukov * ifaddr_event handler. 19919873f47SAndrey V. Elsukov * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent 20019873f47SAndrey V. Elsukov * source address spoofing. 20119873f47SAndrey V. Elsukov */ 20219873f47SAndrey V. Elsukov static void 20319873f47SAndrey V. Elsukov in_gre_srcaddr(void *arg __unused, const struct sockaddr *sa, 20419873f47SAndrey V. Elsukov int event __unused) 20519873f47SAndrey V. Elsukov { 20619873f47SAndrey V. Elsukov const struct sockaddr_in *sin; 20719873f47SAndrey V. Elsukov struct gre_softc *sc; 20819873f47SAndrey V. Elsukov 2098796e291SAndrey V. Elsukov /* Check that VNET is ready */ 2108796e291SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) 21119873f47SAndrey V. Elsukov return; 21219873f47SAndrey V. Elsukov 21397168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 21419873f47SAndrey V. Elsukov sin = (const struct sockaddr_in *)sa; 21519873f47SAndrey V. Elsukov CK_LIST_FOREACH(sc, &GRE_SRCHASH(sin->sin_addr.s_addr), srchash) { 21619873f47SAndrey V. Elsukov if (sc->gre_oip.ip_src.s_addr != sin->sin_addr.s_addr) 21719873f47SAndrey V. Elsukov continue; 21819873f47SAndrey V. Elsukov in_gre_set_running(sc); 21919873f47SAndrey V. Elsukov } 22019873f47SAndrey V. Elsukov } 22119873f47SAndrey V. Elsukov 222742e7210SKristof Provost static bool 223aee793eeSAndrey V. Elsukov in_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, 224aee793eeSAndrey V. Elsukov const struct sockaddr *sa, void *ctx) 225aee793eeSAndrey V. Elsukov { 226aee793eeSAndrey V. Elsukov struct gre_socket *gs; 227aee793eeSAndrey V. Elsukov struct gre_softc *sc; 228aee793eeSAndrey V. Elsukov in_addr_t dst; 229aee793eeSAndrey V. Elsukov 230db0ac6deSCy Schubert NET_EPOCH_ASSERT(); 231aee793eeSAndrey V. Elsukov 232aee793eeSAndrey V. Elsukov gs = (struct gre_socket *)ctx; 233aee793eeSAndrey V. Elsukov dst = ((const struct sockaddr_in *)sa)->sin_addr.s_addr; 234aee793eeSAndrey V. Elsukov CK_LIST_FOREACH(sc, &gs->list, chain) { 235aee793eeSAndrey V. Elsukov if (sc->gre_oip.ip_dst.s_addr == dst) 236aee793eeSAndrey V. Elsukov break; 237aee793eeSAndrey V. Elsukov } 238aee793eeSAndrey V. Elsukov if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){ 239aee793eeSAndrey V. Elsukov gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc); 240742e7210SKristof Provost return (true); 241aee793eeSAndrey V. Elsukov } 242aee793eeSAndrey V. Elsukov m_freem(m); 243742e7210SKristof Provost 244742e7210SKristof Provost return (true); 245aee793eeSAndrey V. Elsukov } 246aee793eeSAndrey V. Elsukov 247aee793eeSAndrey V. Elsukov static int 248aee793eeSAndrey V. Elsukov in_gre_setup_socket(struct gre_softc *sc) 249aee793eeSAndrey V. Elsukov { 250aee793eeSAndrey V. Elsukov struct sockopt sopt; 251aee793eeSAndrey V. Elsukov struct sockaddr_in sin; 252aee793eeSAndrey V. Elsukov struct in_gre_socket *s; 253aee793eeSAndrey V. Elsukov struct gre_socket *gs; 254aee793eeSAndrey V. Elsukov in_addr_t addr; 255aee793eeSAndrey V. Elsukov int error, value; 256aee793eeSAndrey V. Elsukov 257aee793eeSAndrey V. Elsukov /* 258aee793eeSAndrey V. Elsukov * NOTE: we are protected with gre_ioctl_sx lock. 259aee793eeSAndrey V. Elsukov * 260aee793eeSAndrey V. Elsukov * First check that socket is already configured. 261*fa7de6dcSGordon Bergling * If so, check that source address was not changed. 262aee793eeSAndrey V. Elsukov * If address is different, check that there are no other tunnels 263aee793eeSAndrey V. Elsukov * and close socket. 264aee793eeSAndrey V. Elsukov */ 265aee793eeSAndrey V. Elsukov addr = sc->gre_oip.ip_src.s_addr; 266aee793eeSAndrey V. Elsukov gs = sc->gre_so; 267aee793eeSAndrey V. Elsukov if (gs != NULL) { 268aee793eeSAndrey V. Elsukov s = __containerof(gs, struct in_gre_socket, base); 269aee793eeSAndrey V. Elsukov if (s->addr != addr) { 270aee793eeSAndrey V. Elsukov if (CK_LIST_EMPTY(&gs->list)) { 271aee793eeSAndrey V. Elsukov CK_LIST_REMOVE(gs, chain); 272aee793eeSAndrey V. Elsukov soclose(gs->so); 2732a4bd982SGleb Smirnoff NET_EPOCH_CALL(gre_sofree, &gs->epoch_ctx); 274aee793eeSAndrey V. Elsukov } 275aee793eeSAndrey V. Elsukov gs = sc->gre_so = NULL; 276aee793eeSAndrey V. Elsukov } 277aee793eeSAndrey V. Elsukov } 278aee793eeSAndrey V. Elsukov 279aee793eeSAndrey V. Elsukov if (gs == NULL) { 280aee793eeSAndrey V. Elsukov /* 281aee793eeSAndrey V. Elsukov * Check that socket for given address is already 282aee793eeSAndrey V. Elsukov * configured. 283aee793eeSAndrey V. Elsukov */ 284aee793eeSAndrey V. Elsukov gs = in_gre_lookup_socket(addr); 285aee793eeSAndrey V. Elsukov if (gs == NULL) { 286aee793eeSAndrey V. Elsukov s = malloc(sizeof(*s), M_GRE, M_WAITOK | M_ZERO); 287aee793eeSAndrey V. Elsukov s->addr = addr; 288aee793eeSAndrey V. Elsukov gs = &s->base; 289aee793eeSAndrey V. Elsukov 290aee793eeSAndrey V. Elsukov error = socreate(sc->gre_family, &gs->so, 291aee793eeSAndrey V. Elsukov SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, 292aee793eeSAndrey V. Elsukov curthread); 293aee793eeSAndrey V. Elsukov if (error != 0) { 294aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 295aee793eeSAndrey V. Elsukov "cannot create socket: %d\n", error); 296aee793eeSAndrey V. Elsukov free(s, M_GRE); 297aee793eeSAndrey V. Elsukov return (error); 298aee793eeSAndrey V. Elsukov } 299aee793eeSAndrey V. Elsukov 300aee793eeSAndrey V. Elsukov error = udp_set_kernel_tunneling(gs->so, 301aee793eeSAndrey V. Elsukov in_gre_udp_input, NULL, gs); 302aee793eeSAndrey V. Elsukov if (error != 0) { 303aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 304aee793eeSAndrey V. Elsukov "cannot set UDP tunneling: %d\n", error); 305aee793eeSAndrey V. Elsukov goto fail; 306aee793eeSAndrey V. Elsukov } 307aee793eeSAndrey V. Elsukov 308aee793eeSAndrey V. Elsukov memset(&sopt, 0, sizeof(sopt)); 309aee793eeSAndrey V. Elsukov sopt.sopt_dir = SOPT_SET; 310aee793eeSAndrey V. Elsukov sopt.sopt_level = IPPROTO_IP; 311aee793eeSAndrey V. Elsukov sopt.sopt_name = IP_BINDANY; 312aee793eeSAndrey V. Elsukov sopt.sopt_val = &value; 313aee793eeSAndrey V. Elsukov sopt.sopt_valsize = sizeof(value); 314aee793eeSAndrey V. Elsukov value = 1; 315aee793eeSAndrey V. Elsukov error = sosetopt(gs->so, &sopt); 316aee793eeSAndrey V. Elsukov if (error != 0) { 317aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 318aee793eeSAndrey V. Elsukov "cannot set IP_BINDANY opt: %d\n", error); 319aee793eeSAndrey V. Elsukov goto fail; 320aee793eeSAndrey V. Elsukov } 321aee793eeSAndrey V. Elsukov 322aee793eeSAndrey V. Elsukov memset(&sin, 0, sizeof(sin)); 323aee793eeSAndrey V. Elsukov sin.sin_family = AF_INET; 324aee793eeSAndrey V. Elsukov sin.sin_len = sizeof(sin); 325aee793eeSAndrey V. Elsukov sin.sin_addr.s_addr = addr; 326aee793eeSAndrey V. Elsukov sin.sin_port = htons(GRE_UDPPORT); 327aee793eeSAndrey V. Elsukov error = sobind(gs->so, (struct sockaddr *)&sin, 328aee793eeSAndrey V. Elsukov curthread); 329aee793eeSAndrey V. Elsukov if (error != 0) { 330aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 331aee793eeSAndrey V. Elsukov "cannot bind socket: %d\n", error); 332aee793eeSAndrey V. Elsukov goto fail; 333aee793eeSAndrey V. Elsukov } 334aee793eeSAndrey V. Elsukov /* Add socket to the chain */ 335aee793eeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_SOCKHASH(addr), gs, chain); 336aee793eeSAndrey V. Elsukov } 337aee793eeSAndrey V. Elsukov } 338aee793eeSAndrey V. Elsukov 339aee793eeSAndrey V. Elsukov /* Add softc to the socket's list */ 340aee793eeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&gs->list, sc, chain); 341aee793eeSAndrey V. Elsukov sc->gre_so = gs; 342aee793eeSAndrey V. Elsukov return (0); 343aee793eeSAndrey V. Elsukov fail: 344aee793eeSAndrey V. Elsukov soclose(gs->so); 345aee793eeSAndrey V. Elsukov free(s, M_GRE); 346aee793eeSAndrey V. Elsukov return (error); 347aee793eeSAndrey V. Elsukov } 348aee793eeSAndrey V. Elsukov 349aee793eeSAndrey V. Elsukov static int 350a5185adeSAndrey V. Elsukov in_gre_attach(struct gre_softc *sc) 351a5185adeSAndrey V. Elsukov { 352c8ee75f2SGleb Smirnoff struct epoch_tracker et; 353aee793eeSAndrey V. Elsukov struct grehdr *gh; 354aee793eeSAndrey V. Elsukov int error; 355a5185adeSAndrey V. Elsukov 356aee793eeSAndrey V. Elsukov if (sc->gre_options & GRE_UDPENCAP) { 357aee793eeSAndrey V. Elsukov sc->gre_csumflags = CSUM_UDP; 358aee793eeSAndrey V. Elsukov sc->gre_hlen = sizeof(struct greudp); 359aee793eeSAndrey V. Elsukov sc->gre_oip.ip_p = IPPROTO_UDP; 360aee793eeSAndrey V. Elsukov gh = &sc->gre_udphdr->gi_gre; 361aee793eeSAndrey V. Elsukov gre_update_udphdr(sc, &sc->gre_udp, 362aee793eeSAndrey V. Elsukov in_pseudo(sc->gre_oip.ip_src.s_addr, 363aee793eeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr, 0)); 364aee793eeSAndrey V. Elsukov } else { 365a5185adeSAndrey V. Elsukov sc->gre_hlen = sizeof(struct greip); 366aee793eeSAndrey V. Elsukov sc->gre_oip.ip_p = IPPROTO_GRE; 367aee793eeSAndrey V. Elsukov gh = &sc->gre_iphdr->gi_gre; 368aee793eeSAndrey V. Elsukov } 369a5185adeSAndrey V. Elsukov sc->gre_oip.ip_v = IPVERSION; 370a5185adeSAndrey V. Elsukov sc->gre_oip.ip_hl = sizeof(struct ip) >> 2; 371aee793eeSAndrey V. Elsukov gre_update_hdr(sc, gh); 372aee793eeSAndrey V. Elsukov 373aee793eeSAndrey V. Elsukov /* 374aee793eeSAndrey V. Elsukov * If we return error, this means that sc is not linked, 375aee793eeSAndrey V. Elsukov * and caller should reset gre_family and free(sc->gre_hdr). 376aee793eeSAndrey V. Elsukov */ 377aee793eeSAndrey V. Elsukov if (sc->gre_options & GRE_UDPENCAP) { 378aee793eeSAndrey V. Elsukov error = in_gre_setup_socket(sc); 379aee793eeSAndrey V. Elsukov if (error != 0) 380aee793eeSAndrey V. Elsukov return (error); 381aee793eeSAndrey V. Elsukov } else 382a5185adeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain); 38319873f47SAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_SRCHASH(sc->gre_oip.ip_src.s_addr), 38419873f47SAndrey V. Elsukov sc, srchash); 385aee793eeSAndrey V. Elsukov 386aee793eeSAndrey V. Elsukov /* Set IFF_DRV_RUNNING if interface is ready */ 387c8ee75f2SGleb Smirnoff NET_EPOCH_ENTER(et); 388aee793eeSAndrey V. Elsukov in_gre_set_running(sc); 389c8ee75f2SGleb Smirnoff NET_EPOCH_EXIT(et); 390aee793eeSAndrey V. Elsukov return (0); 391a5185adeSAndrey V. Elsukov } 392a5185adeSAndrey V. Elsukov 393aee793eeSAndrey V. Elsukov int 394a5185adeSAndrey V. Elsukov in_gre_setopts(struct gre_softc *sc, u_long cmd, uint32_t value) 395a5185adeSAndrey V. Elsukov { 396aee793eeSAndrey V. Elsukov int error; 397a5185adeSAndrey V. Elsukov 398a5185adeSAndrey V. Elsukov /* NOTE: we are protected with gre_ioctl_sx lock */ 399aee793eeSAndrey V. Elsukov MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT); 400a5185adeSAndrey V. Elsukov MPASS(sc->gre_family == AF_INET); 401aee793eeSAndrey V. Elsukov 402aee793eeSAndrey V. Elsukov /* 403aee793eeSAndrey V. Elsukov * If we are going to change encapsulation protocol, do check 404aee793eeSAndrey V. Elsukov * for duplicate tunnels. Return EEXIST here to do not confuse 405aee793eeSAndrey V. Elsukov * user. 406aee793eeSAndrey V. Elsukov */ 407aee793eeSAndrey V. Elsukov if (cmd == GRESOPTS && 408aee793eeSAndrey V. Elsukov (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) && 409aee793eeSAndrey V. Elsukov in_gre_checkdup(sc, sc->gre_oip.ip_src.s_addr, 410aee793eeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr, value) == EADDRNOTAVAIL) 411aee793eeSAndrey V. Elsukov return (EEXIST); 412aee793eeSAndrey V. Elsukov 413a5185adeSAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 41419873f47SAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 415a5185adeSAndrey V. Elsukov GRE_WAIT(); 416aee793eeSAndrey V. Elsukov switch (cmd) { 417aee793eeSAndrey V. Elsukov case GRESKEY: 418a5185adeSAndrey V. Elsukov sc->gre_key = value; 419aee793eeSAndrey V. Elsukov break; 420aee793eeSAndrey V. Elsukov case GRESOPTS: 421a5185adeSAndrey V. Elsukov sc->gre_options = value; 422aee793eeSAndrey V. Elsukov break; 423aee793eeSAndrey V. Elsukov case GRESPORT: 424aee793eeSAndrey V. Elsukov sc->gre_port = value; 425aee793eeSAndrey V. Elsukov break; 426aee793eeSAndrey V. Elsukov } 427aee793eeSAndrey V. Elsukov error = in_gre_attach(sc); 428aee793eeSAndrey V. Elsukov if (error != 0) { 429aee793eeSAndrey V. Elsukov sc->gre_family = 0; 430aee793eeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 431aee793eeSAndrey V. Elsukov } 432aee793eeSAndrey V. Elsukov return (error); 433a5185adeSAndrey V. Elsukov } 434a5185adeSAndrey V. Elsukov 435a5185adeSAndrey V. Elsukov int 436a5185adeSAndrey V. Elsukov in_gre_ioctl(struct gre_softc *sc, u_long cmd, caddr_t data) 437a5185adeSAndrey V. Elsukov { 438a5185adeSAndrey V. Elsukov struct ifreq *ifr = (struct ifreq *)data; 439a5185adeSAndrey V. Elsukov struct sockaddr_in *dst, *src; 440a5185adeSAndrey V. Elsukov struct ip *ip; 441a5185adeSAndrey V. Elsukov int error; 442a5185adeSAndrey V. Elsukov 443a5185adeSAndrey V. Elsukov /* NOTE: we are protected with gre_ioctl_sx lock */ 444a5185adeSAndrey V. Elsukov error = EINVAL; 445a5185adeSAndrey V. Elsukov switch (cmd) { 446a5185adeSAndrey V. Elsukov case SIOCSIFPHYADDR: 447a5185adeSAndrey V. Elsukov src = &((struct in_aliasreq *)data)->ifra_addr; 448a5185adeSAndrey V. Elsukov dst = &((struct in_aliasreq *)data)->ifra_dstaddr; 449a5185adeSAndrey V. Elsukov 450a5185adeSAndrey V. Elsukov /* sanity checks */ 451a5185adeSAndrey V. Elsukov if (src->sin_family != dst->sin_family || 452a5185adeSAndrey V. Elsukov src->sin_family != AF_INET || 453a5185adeSAndrey V. Elsukov src->sin_len != dst->sin_len || 454a5185adeSAndrey V. Elsukov src->sin_len != sizeof(*src)) 455a5185adeSAndrey V. Elsukov break; 456a5185adeSAndrey V. Elsukov if (src->sin_addr.s_addr == INADDR_ANY || 457a5185adeSAndrey V. Elsukov dst->sin_addr.s_addr == INADDR_ANY) { 458a5185adeSAndrey V. Elsukov error = EADDRNOTAVAIL; 459a5185adeSAndrey V. Elsukov break; 460a5185adeSAndrey V. Elsukov } 46119873f47SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) { 462a5185adeSAndrey V. Elsukov V_ipv4_hashtbl = gre_hashinit(); 46319873f47SAndrey V. Elsukov V_ipv4_srchashtbl = gre_hashinit(); 464aee793eeSAndrey V. Elsukov V_ipv4_sockets = (struct gre_sockets *)gre_hashinit(); 46519873f47SAndrey V. Elsukov } 466a5185adeSAndrey V. Elsukov error = in_gre_checkdup(sc, src->sin_addr.s_addr, 467aee793eeSAndrey V. Elsukov dst->sin_addr.s_addr, sc->gre_options); 468a5185adeSAndrey V. Elsukov if (error == EADDRNOTAVAIL) 469a5185adeSAndrey V. Elsukov break; 470a5185adeSAndrey V. Elsukov if (error == EEXIST) { 471a5185adeSAndrey V. Elsukov /* Addresses are the same. Just return. */ 472a5185adeSAndrey V. Elsukov error = 0; 473a5185adeSAndrey V. Elsukov break; 474a5185adeSAndrey V. Elsukov } 475aee793eeSAndrey V. Elsukov ip = malloc(sizeof(struct greudp) + 3 * sizeof(uint32_t), 476a5185adeSAndrey V. Elsukov M_GRE, M_WAITOK | M_ZERO); 477a5185adeSAndrey V. Elsukov ip->ip_src.s_addr = src->sin_addr.s_addr; 478a5185adeSAndrey V. Elsukov ip->ip_dst.s_addr = dst->sin_addr.s_addr; 479a5185adeSAndrey V. Elsukov if (sc->gre_family != 0) { 480a5185adeSAndrey V. Elsukov /* Detach existing tunnel first */ 481a5185adeSAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 48219873f47SAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 483a5185adeSAndrey V. Elsukov GRE_WAIT(); 484a5185adeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 485a5185adeSAndrey V. Elsukov /* XXX: should we notify about link state change? */ 486a5185adeSAndrey V. Elsukov } 487a5185adeSAndrey V. Elsukov sc->gre_family = AF_INET; 488a5185adeSAndrey V. Elsukov sc->gre_hdr = ip; 489a5185adeSAndrey V. Elsukov sc->gre_oseq = 0; 490a5185adeSAndrey V. Elsukov sc->gre_iseq = UINT32_MAX; 491aee793eeSAndrey V. Elsukov error = in_gre_attach(sc); 492aee793eeSAndrey V. Elsukov if (error != 0) { 493aee793eeSAndrey V. Elsukov sc->gre_family = 0; 494aee793eeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 495aee793eeSAndrey V. Elsukov } 496a5185adeSAndrey V. Elsukov break; 497a5185adeSAndrey V. Elsukov case SIOCGIFPSRCADDR: 498a5185adeSAndrey V. Elsukov case SIOCGIFPDSTADDR: 499a5185adeSAndrey V. Elsukov if (sc->gre_family != AF_INET) { 500a5185adeSAndrey V. Elsukov error = EADDRNOTAVAIL; 501a5185adeSAndrey V. Elsukov break; 502a5185adeSAndrey V. Elsukov } 503a5185adeSAndrey V. Elsukov src = (struct sockaddr_in *)&ifr->ifr_addr; 504a5185adeSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 505a5185adeSAndrey V. Elsukov src->sin_family = AF_INET; 506a5185adeSAndrey V. Elsukov src->sin_len = sizeof(*src); 507a5185adeSAndrey V. Elsukov src->sin_addr = (cmd == SIOCGIFPSRCADDR) ? 508a5185adeSAndrey V. Elsukov sc->gre_oip.ip_src: sc->gre_oip.ip_dst; 509a5185adeSAndrey V. Elsukov error = prison_if(curthread->td_ucred, (struct sockaddr *)src); 510a5185adeSAndrey V. Elsukov if (error != 0) 511a5185adeSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 512a5185adeSAndrey V. Elsukov break; 513a5185adeSAndrey V. Elsukov } 514a5185adeSAndrey V. Elsukov return (error); 515a5185adeSAndrey V. Elsukov } 516a5185adeSAndrey V. Elsukov 517f325335cSAndrey V. Elsukov int 518f325335cSAndrey V. Elsukov in_gre_output(struct mbuf *m, int af, int hlen) 519f325335cSAndrey V. Elsukov { 520f325335cSAndrey V. Elsukov struct greip *gi; 52173d7ddbcSMaxim Sobolev 522f325335cSAndrey V. Elsukov gi = mtod(m, struct greip *); 523f325335cSAndrey V. Elsukov switch (af) { 524f325335cSAndrey V. Elsukov case AF_INET: 525f325335cSAndrey V. Elsukov /* 526f325335cSAndrey V. Elsukov * gre_transmit() has used M_PREPEND() that doesn't guarantee 527f325335cSAndrey V. Elsukov * m_data is contiguous more than hlen bytes. Use m_copydata() 528f325335cSAndrey V. Elsukov * here to avoid m_pullup(). 529f325335cSAndrey V. Elsukov */ 530f325335cSAndrey V. Elsukov m_copydata(m, hlen + offsetof(struct ip, ip_tos), 531f325335cSAndrey V. Elsukov sizeof(u_char), &gi->gi_ip.ip_tos); 532f325335cSAndrey V. Elsukov m_copydata(m, hlen + offsetof(struct ip, ip_id), 533f325335cSAndrey V. Elsukov sizeof(u_short), (caddr_t)&gi->gi_ip.ip_id); 5348e96e13eSMaxim Sobolev break; 5359e669156SBjoern A. Zeeb #ifdef INET6 536f325335cSAndrey V. Elsukov case AF_INET6: 537f325335cSAndrey V. Elsukov gi->gi_ip.ip_tos = 0; /* XXX */ 5386d947416SGleb Smirnoff ip_fillid(&gi->gi_ip); 5399e669156SBjoern A. Zeeb break; 5409e669156SBjoern A. Zeeb #endif 5418e96e13eSMaxim Sobolev } 542f325335cSAndrey V. Elsukov gi->gi_ip.ip_ttl = V_ip_gre_ttl; 543f325335cSAndrey V. Elsukov gi->gi_ip.ip_len = htons(m->m_pkthdr.len); 544f325335cSAndrey V. Elsukov return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL)); 5458e96e13eSMaxim Sobolev } 5468e96e13eSMaxim Sobolev 54719873f47SAndrey V. Elsukov static const struct srcaddrtab *ipv4_srcaddrtab = NULL; 548a5185adeSAndrey V. Elsukov static const struct encaptab *ecookie = NULL; 5496d8fdfa9SAndrey V. Elsukov static const struct encap_config ipv4_encap_cfg = { 5506d8fdfa9SAndrey V. Elsukov .proto = IPPROTO_GRE, 5516d8fdfa9SAndrey V. Elsukov .min_length = sizeof(struct greip) + sizeof(struct ip), 552a5185adeSAndrey V. Elsukov .exact_match = ENCAP_DRV_LOOKUP, 553a5185adeSAndrey V. Elsukov .lookup = in_gre_lookup, 5546d8fdfa9SAndrey V. Elsukov .input = gre_input 5556d8fdfa9SAndrey V. Elsukov }; 5566d8fdfa9SAndrey V. Elsukov 557a5185adeSAndrey V. Elsukov void 558a5185adeSAndrey V. Elsukov in_gre_init(void) 5598e96e13eSMaxim Sobolev { 5608e96e13eSMaxim Sobolev 561a5185adeSAndrey V. Elsukov if (!IS_DEFAULT_VNET(curvnet)) 562a5185adeSAndrey V. Elsukov return; 56319873f47SAndrey V. Elsukov ipv4_srcaddrtab = ip_encap_register_srcaddr(in_gre_srcaddr, 56419873f47SAndrey V. Elsukov NULL, M_WAITOK); 565a5185adeSAndrey V. Elsukov ecookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK); 566a5185adeSAndrey V. Elsukov } 567a5185adeSAndrey V. Elsukov 568a5185adeSAndrey V. Elsukov void 569a5185adeSAndrey V. Elsukov in_gre_uninit(void) 570a5185adeSAndrey V. Elsukov { 571a5185adeSAndrey V. Elsukov 57219873f47SAndrey V. Elsukov if (IS_DEFAULT_VNET(curvnet)) { 573a5185adeSAndrey V. Elsukov ip_encap_detach(ecookie); 57419873f47SAndrey V. Elsukov ip_encap_unregister_srcaddr(ipv4_srcaddrtab); 57519873f47SAndrey V. Elsukov } 57619873f47SAndrey V. Elsukov if (V_ipv4_hashtbl != NULL) { 577a5185adeSAndrey V. Elsukov gre_hashdestroy(V_ipv4_hashtbl); 5788796e291SAndrey V. Elsukov V_ipv4_hashtbl = NULL; 5798796e291SAndrey V. Elsukov GRE_WAIT(); 58019873f47SAndrey V. Elsukov gre_hashdestroy(V_ipv4_srchashtbl); 581aee793eeSAndrey V. Elsukov gre_hashdestroy((struct gre_list *)V_ipv4_sockets); 58219873f47SAndrey V. Elsukov } 5838e96e13eSMaxim Sobolev } 584