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> 58*3d0d5b21SJustin Hibbits #include <net/if_private.h> 59f325335cSAndrey V. Elsukov #include <net/vnet.h> 608e96e13eSMaxim Sobolev 618e96e13eSMaxim Sobolev #include <netinet/in.h> 628e96e13eSMaxim Sobolev #include <netinet/in_var.h> 63aee793eeSAndrey V. Elsukov #include <netinet/in_pcb.h> 648e96e13eSMaxim Sobolev #include <netinet/ip.h> 65f325335cSAndrey V. Elsukov #include <netinet/ip_encap.h> 668e96e13eSMaxim Sobolev #include <netinet/ip_var.h> 67aee793eeSAndrey V. Elsukov #include <netinet/udp.h> 68aee793eeSAndrey V. Elsukov #include <netinet/udp_var.h> 69f325335cSAndrey V. Elsukov 70f325335cSAndrey V. Elsukov #ifdef INET6 71f325335cSAndrey V. Elsukov #include <netinet/ip6.h> 728e96e13eSMaxim Sobolev #endif 738e96e13eSMaxim Sobolev 748e96e13eSMaxim Sobolev #include <net/if_gre.h> 75aee793eeSAndrey V. Elsukov #include <machine/in_cksum.h> 768e96e13eSMaxim Sobolev 77f325335cSAndrey V. Elsukov #define GRE_TTL 30 78f325335cSAndrey V. Elsukov VNET_DEFINE(int, ip_gre_ttl) = GRE_TTL; 79f325335cSAndrey V. Elsukov #define V_ip_gre_ttl VNET(ip_gre_ttl) 80f325335cSAndrey V. Elsukov SYSCTL_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_VNET | CTLFLAG_RW, 816d8fdfa9SAndrey V. Elsukov &VNET_NAME(ip_gre_ttl), 0, "Default TTL value for encapsulated packets"); 828e96e13eSMaxim Sobolev 83aee793eeSAndrey V. Elsukov struct in_gre_socket { 84aee793eeSAndrey V. Elsukov struct gre_socket base; 85aee793eeSAndrey V. Elsukov in_addr_t addr; 86aee793eeSAndrey V. Elsukov }; 87aee793eeSAndrey V. Elsukov VNET_DEFINE_STATIC(struct gre_sockets *, ipv4_sockets) = NULL; 885f901c92SAndrew Turner VNET_DEFINE_STATIC(struct gre_list *, ipv4_hashtbl) = NULL; 8919873f47SAndrey V. Elsukov VNET_DEFINE_STATIC(struct gre_list *, ipv4_srchashtbl) = NULL; 90aee793eeSAndrey V. Elsukov #define V_ipv4_sockets VNET(ipv4_sockets) 91a5185adeSAndrey V. Elsukov #define V_ipv4_hashtbl VNET(ipv4_hashtbl) 9219873f47SAndrey V. Elsukov #define V_ipv4_srchashtbl VNET(ipv4_srchashtbl) 93a5185adeSAndrey V. Elsukov #define GRE_HASH(src, dst) (V_ipv4_hashtbl[\ 94a5185adeSAndrey V. Elsukov in_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)]) 9519873f47SAndrey V. Elsukov #define GRE_SRCHASH(src) (V_ipv4_srchashtbl[\ 9619873f47SAndrey V. Elsukov fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)]) 97aee793eeSAndrey V. Elsukov #define GRE_SOCKHASH(src) (V_ipv4_sockets[\ 98aee793eeSAndrey V. Elsukov fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)]) 99a5185adeSAndrey V. Elsukov #define GRE_HASH_SC(sc) GRE_HASH((sc)->gre_oip.ip_src.s_addr,\ 100a5185adeSAndrey V. Elsukov (sc)->gre_oip.ip_dst.s_addr) 1018e96e13eSMaxim Sobolev 102a5185adeSAndrey V. Elsukov static uint32_t 103a5185adeSAndrey V. Elsukov in_gre_hashval(in_addr_t src, in_addr_t dst) 104a5185adeSAndrey V. Elsukov { 105a5185adeSAndrey V. Elsukov uint32_t ret; 106a5185adeSAndrey V. Elsukov 107a5185adeSAndrey V. Elsukov ret = fnv_32_buf(&src, sizeof(src), FNV1_32_INIT); 108a5185adeSAndrey V. Elsukov return (fnv_32_buf(&dst, sizeof(dst), ret)); 109a5185adeSAndrey V. Elsukov } 110a5185adeSAndrey V. Elsukov 111aee793eeSAndrey V. Elsukov static struct gre_socket* 112aee793eeSAndrey V. Elsukov in_gre_lookup_socket(in_addr_t addr) 113a5185adeSAndrey V. Elsukov { 114aee793eeSAndrey V. Elsukov struct gre_socket *gs; 115aee793eeSAndrey V. Elsukov struct in_gre_socket *s; 116aee793eeSAndrey V. Elsukov 117aee793eeSAndrey V. Elsukov CK_LIST_FOREACH(gs, &GRE_SOCKHASH(addr), chain) { 118aee793eeSAndrey V. Elsukov s = __containerof(gs, struct in_gre_socket, base); 119aee793eeSAndrey V. Elsukov if (s->addr == addr) 120aee793eeSAndrey V. Elsukov break; 121aee793eeSAndrey V. Elsukov } 122aee793eeSAndrey V. Elsukov return (gs); 123aee793eeSAndrey V. Elsukov } 124aee793eeSAndrey V. Elsukov 125aee793eeSAndrey V. Elsukov static int 126aee793eeSAndrey V. Elsukov in_gre_checkdup(const struct gre_softc *sc, in_addr_t src, in_addr_t dst, 127aee793eeSAndrey V. Elsukov uint32_t opts) 128aee793eeSAndrey V. Elsukov { 129aee793eeSAndrey V. Elsukov struct gre_list *head; 130a5185adeSAndrey V. Elsukov struct gre_softc *tmp; 131aee793eeSAndrey V. Elsukov struct gre_socket *gs; 132a5185adeSAndrey V. Elsukov 133a5185adeSAndrey V. Elsukov if (sc->gre_family == AF_INET && 134a5185adeSAndrey V. Elsukov sc->gre_oip.ip_src.s_addr == src && 135aee793eeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr == dst && 136aee793eeSAndrey V. Elsukov (sc->gre_options & GRE_UDPENCAP) == (opts & GRE_UDPENCAP)) 137a5185adeSAndrey V. Elsukov return (EEXIST); 138a5185adeSAndrey V. Elsukov 139aee793eeSAndrey V. Elsukov if (opts & GRE_UDPENCAP) { 140aee793eeSAndrey V. Elsukov gs = in_gre_lookup_socket(src); 141aee793eeSAndrey V. Elsukov if (gs == NULL) 142aee793eeSAndrey V. Elsukov return (0); 143aee793eeSAndrey V. Elsukov head = &gs->list; 144aee793eeSAndrey V. Elsukov } else 145aee793eeSAndrey V. Elsukov head = &GRE_HASH(src, dst); 146aee793eeSAndrey V. Elsukov 147aee793eeSAndrey V. Elsukov CK_LIST_FOREACH(tmp, head, chain) { 148a5185adeSAndrey V. Elsukov if (tmp == sc) 149a5185adeSAndrey V. Elsukov continue; 150a5185adeSAndrey V. Elsukov if (tmp->gre_oip.ip_src.s_addr == src && 151a5185adeSAndrey V. Elsukov tmp->gre_oip.ip_dst.s_addr == dst) 152a5185adeSAndrey V. Elsukov return (EADDRNOTAVAIL); 153a5185adeSAndrey V. Elsukov } 154a5185adeSAndrey V. Elsukov return (0); 155a5185adeSAndrey V. Elsukov } 156a5185adeSAndrey V. Elsukov 157a5185adeSAndrey V. Elsukov static int 158a5185adeSAndrey V. Elsukov in_gre_lookup(const struct mbuf *m, int off, int proto, void **arg) 159a5185adeSAndrey V. Elsukov { 160a5185adeSAndrey V. Elsukov const struct ip *ip; 161a5185adeSAndrey V. Elsukov struct gre_softc *sc; 162a5185adeSAndrey V. Elsukov 1636e081509SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) 1646e081509SAndrey V. Elsukov return (0); 1656e081509SAndrey V. Elsukov 16697168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 167a5185adeSAndrey V. Elsukov ip = mtod(m, const struct ip *); 168a5185adeSAndrey V. Elsukov CK_LIST_FOREACH(sc, &GRE_HASH(ip->ip_dst.s_addr, 169a5185adeSAndrey V. Elsukov ip->ip_src.s_addr), chain) { 170a5185adeSAndrey V. Elsukov /* 171a5185adeSAndrey V. Elsukov * This is an inbound packet, its ip_dst is source address 172a5185adeSAndrey V. Elsukov * in softc. 173a5185adeSAndrey V. Elsukov */ 174a5185adeSAndrey V. Elsukov if (sc->gre_oip.ip_src.s_addr == ip->ip_dst.s_addr && 175a5185adeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr == ip->ip_src.s_addr) { 176f325335cSAndrey V. Elsukov if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0) 177f325335cSAndrey V. Elsukov return (0); 178a5185adeSAndrey V. Elsukov *arg = sc; 179a5185adeSAndrey V. Elsukov return (ENCAP_DRV_LOOKUP); 180a5185adeSAndrey V. Elsukov } 181a5185adeSAndrey V. Elsukov } 182f325335cSAndrey V. Elsukov return (0); 1838e96e13eSMaxim Sobolev } 1848e96e13eSMaxim Sobolev 18519873f47SAndrey V. Elsukov /* 18619873f47SAndrey V. Elsukov * Check that ingress address belongs to local host. 18719873f47SAndrey V. Elsukov */ 18819873f47SAndrey V. Elsukov static void 18919873f47SAndrey V. Elsukov in_gre_set_running(struct gre_softc *sc) 19019873f47SAndrey V. Elsukov { 19119873f47SAndrey V. Elsukov 19219873f47SAndrey V. Elsukov if (in_localip(sc->gre_oip.ip_src)) 19319873f47SAndrey V. Elsukov GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; 19419873f47SAndrey V. Elsukov else 19519873f47SAndrey V. Elsukov GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 19619873f47SAndrey V. Elsukov } 19719873f47SAndrey V. Elsukov 19819873f47SAndrey V. Elsukov /* 19919873f47SAndrey V. Elsukov * ifaddr_event handler. 20019873f47SAndrey V. Elsukov * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent 20119873f47SAndrey V. Elsukov * source address spoofing. 20219873f47SAndrey V. Elsukov */ 20319873f47SAndrey V. Elsukov static void 20419873f47SAndrey V. Elsukov in_gre_srcaddr(void *arg __unused, const struct sockaddr *sa, 20519873f47SAndrey V. Elsukov int event __unused) 20619873f47SAndrey V. Elsukov { 20719873f47SAndrey V. Elsukov const struct sockaddr_in *sin; 20819873f47SAndrey V. Elsukov struct gre_softc *sc; 20919873f47SAndrey V. Elsukov 2108796e291SAndrey V. Elsukov /* Check that VNET is ready */ 2118796e291SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) 21219873f47SAndrey V. Elsukov return; 21319873f47SAndrey V. Elsukov 21497168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 21519873f47SAndrey V. Elsukov sin = (const struct sockaddr_in *)sa; 21619873f47SAndrey V. Elsukov CK_LIST_FOREACH(sc, &GRE_SRCHASH(sin->sin_addr.s_addr), srchash) { 21719873f47SAndrey V. Elsukov if (sc->gre_oip.ip_src.s_addr != sin->sin_addr.s_addr) 21819873f47SAndrey V. Elsukov continue; 21919873f47SAndrey V. Elsukov in_gre_set_running(sc); 22019873f47SAndrey V. Elsukov } 22119873f47SAndrey V. Elsukov } 22219873f47SAndrey V. Elsukov 223742e7210SKristof Provost static bool 224aee793eeSAndrey V. Elsukov in_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, 225aee793eeSAndrey V. Elsukov const struct sockaddr *sa, void *ctx) 226aee793eeSAndrey V. Elsukov { 227aee793eeSAndrey V. Elsukov struct gre_socket *gs; 228aee793eeSAndrey V. Elsukov struct gre_softc *sc; 229aee793eeSAndrey V. Elsukov in_addr_t dst; 230aee793eeSAndrey V. Elsukov 231db0ac6deSCy Schubert NET_EPOCH_ASSERT(); 232aee793eeSAndrey V. Elsukov 233aee793eeSAndrey V. Elsukov gs = (struct gre_socket *)ctx; 234aee793eeSAndrey V. Elsukov dst = ((const struct sockaddr_in *)sa)->sin_addr.s_addr; 235aee793eeSAndrey V. Elsukov CK_LIST_FOREACH(sc, &gs->list, chain) { 236aee793eeSAndrey V. Elsukov if (sc->gre_oip.ip_dst.s_addr == dst) 237aee793eeSAndrey V. Elsukov break; 238aee793eeSAndrey V. Elsukov } 239aee793eeSAndrey V. Elsukov if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){ 240aee793eeSAndrey V. Elsukov gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc); 241742e7210SKristof Provost return (true); 242aee793eeSAndrey V. Elsukov } 243aee793eeSAndrey V. Elsukov m_freem(m); 244742e7210SKristof Provost 245742e7210SKristof Provost return (true); 246aee793eeSAndrey V. Elsukov } 247aee793eeSAndrey V. Elsukov 248aee793eeSAndrey V. Elsukov static int 249aee793eeSAndrey V. Elsukov in_gre_setup_socket(struct gre_softc *sc) 250aee793eeSAndrey V. Elsukov { 251aee793eeSAndrey V. Elsukov struct sockopt sopt; 252aee793eeSAndrey V. Elsukov struct sockaddr_in sin; 253aee793eeSAndrey V. Elsukov struct in_gre_socket *s; 254aee793eeSAndrey V. Elsukov struct gre_socket *gs; 255aee793eeSAndrey V. Elsukov in_addr_t addr; 256aee793eeSAndrey V. Elsukov int error, value; 257aee793eeSAndrey V. Elsukov 258aee793eeSAndrey V. Elsukov /* 259aee793eeSAndrey V. Elsukov * NOTE: we are protected with gre_ioctl_sx lock. 260aee793eeSAndrey V. Elsukov * 261aee793eeSAndrey V. Elsukov * First check that socket is already configured. 262fa7de6dcSGordon Bergling * If so, check that source address was not changed. 263aee793eeSAndrey V. Elsukov * If address is different, check that there are no other tunnels 264aee793eeSAndrey V. Elsukov * and close socket. 265aee793eeSAndrey V. Elsukov */ 266aee793eeSAndrey V. Elsukov addr = sc->gre_oip.ip_src.s_addr; 267aee793eeSAndrey V. Elsukov gs = sc->gre_so; 268aee793eeSAndrey V. Elsukov if (gs != NULL) { 269aee793eeSAndrey V. Elsukov s = __containerof(gs, struct in_gre_socket, base); 270aee793eeSAndrey V. Elsukov if (s->addr != addr) { 271aee793eeSAndrey V. Elsukov if (CK_LIST_EMPTY(&gs->list)) { 272aee793eeSAndrey V. Elsukov CK_LIST_REMOVE(gs, chain); 273aee793eeSAndrey V. Elsukov soclose(gs->so); 2742a4bd982SGleb Smirnoff NET_EPOCH_CALL(gre_sofree, &gs->epoch_ctx); 275aee793eeSAndrey V. Elsukov } 276aee793eeSAndrey V. Elsukov gs = sc->gre_so = NULL; 277aee793eeSAndrey V. Elsukov } 278aee793eeSAndrey V. Elsukov } 279aee793eeSAndrey V. Elsukov 280aee793eeSAndrey V. Elsukov if (gs == NULL) { 281aee793eeSAndrey V. Elsukov /* 282aee793eeSAndrey V. Elsukov * Check that socket for given address is already 283aee793eeSAndrey V. Elsukov * configured. 284aee793eeSAndrey V. Elsukov */ 285aee793eeSAndrey V. Elsukov gs = in_gre_lookup_socket(addr); 286aee793eeSAndrey V. Elsukov if (gs == NULL) { 287aee793eeSAndrey V. Elsukov s = malloc(sizeof(*s), M_GRE, M_WAITOK | M_ZERO); 288aee793eeSAndrey V. Elsukov s->addr = addr; 289aee793eeSAndrey V. Elsukov gs = &s->base; 290aee793eeSAndrey V. Elsukov 291aee793eeSAndrey V. Elsukov error = socreate(sc->gre_family, &gs->so, 292aee793eeSAndrey V. Elsukov SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, 293aee793eeSAndrey V. Elsukov curthread); 294aee793eeSAndrey V. Elsukov if (error != 0) { 295aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 296aee793eeSAndrey V. Elsukov "cannot create socket: %d\n", error); 297aee793eeSAndrey V. Elsukov free(s, M_GRE); 298aee793eeSAndrey V. Elsukov return (error); 299aee793eeSAndrey V. Elsukov } 300aee793eeSAndrey V. Elsukov 301aee793eeSAndrey V. Elsukov error = udp_set_kernel_tunneling(gs->so, 302aee793eeSAndrey V. Elsukov in_gre_udp_input, NULL, gs); 303aee793eeSAndrey V. Elsukov if (error != 0) { 304aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 305aee793eeSAndrey V. Elsukov "cannot set UDP tunneling: %d\n", error); 306aee793eeSAndrey V. Elsukov goto fail; 307aee793eeSAndrey V. Elsukov } 308aee793eeSAndrey V. Elsukov 309aee793eeSAndrey V. Elsukov memset(&sopt, 0, sizeof(sopt)); 310aee793eeSAndrey V. Elsukov sopt.sopt_dir = SOPT_SET; 311aee793eeSAndrey V. Elsukov sopt.sopt_level = IPPROTO_IP; 312aee793eeSAndrey V. Elsukov sopt.sopt_name = IP_BINDANY; 313aee793eeSAndrey V. Elsukov sopt.sopt_val = &value; 314aee793eeSAndrey V. Elsukov sopt.sopt_valsize = sizeof(value); 315aee793eeSAndrey V. Elsukov value = 1; 316aee793eeSAndrey V. Elsukov error = sosetopt(gs->so, &sopt); 317aee793eeSAndrey V. Elsukov if (error != 0) { 318aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 319aee793eeSAndrey V. Elsukov "cannot set IP_BINDANY opt: %d\n", error); 320aee793eeSAndrey V. Elsukov goto fail; 321aee793eeSAndrey V. Elsukov } 322aee793eeSAndrey V. Elsukov 323aee793eeSAndrey V. Elsukov memset(&sin, 0, sizeof(sin)); 324aee793eeSAndrey V. Elsukov sin.sin_family = AF_INET; 325aee793eeSAndrey V. Elsukov sin.sin_len = sizeof(sin); 326aee793eeSAndrey V. Elsukov sin.sin_addr.s_addr = addr; 327aee793eeSAndrey V. Elsukov sin.sin_port = htons(GRE_UDPPORT); 328aee793eeSAndrey V. Elsukov error = sobind(gs->so, (struct sockaddr *)&sin, 329aee793eeSAndrey V. Elsukov curthread); 330aee793eeSAndrey V. Elsukov if (error != 0) { 331aee793eeSAndrey V. Elsukov if_printf(GRE2IFP(sc), 332aee793eeSAndrey V. Elsukov "cannot bind socket: %d\n", error); 333aee793eeSAndrey V. Elsukov goto fail; 334aee793eeSAndrey V. Elsukov } 335aee793eeSAndrey V. Elsukov /* Add socket to the chain */ 336aee793eeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_SOCKHASH(addr), gs, chain); 337aee793eeSAndrey V. Elsukov } 338aee793eeSAndrey V. Elsukov } 339aee793eeSAndrey V. Elsukov 340aee793eeSAndrey V. Elsukov /* Add softc to the socket's list */ 341aee793eeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&gs->list, sc, chain); 342aee793eeSAndrey V. Elsukov sc->gre_so = gs; 343aee793eeSAndrey V. Elsukov return (0); 344aee793eeSAndrey V. Elsukov fail: 345aee793eeSAndrey V. Elsukov soclose(gs->so); 346aee793eeSAndrey V. Elsukov free(s, M_GRE); 347aee793eeSAndrey V. Elsukov return (error); 348aee793eeSAndrey V. Elsukov } 349aee793eeSAndrey V. Elsukov 350aee793eeSAndrey V. Elsukov static int 351a5185adeSAndrey V. Elsukov in_gre_attach(struct gre_softc *sc) 352a5185adeSAndrey V. Elsukov { 353c8ee75f2SGleb Smirnoff struct epoch_tracker et; 354aee793eeSAndrey V. Elsukov struct grehdr *gh; 355aee793eeSAndrey V. Elsukov int error; 356a5185adeSAndrey V. Elsukov 357aee793eeSAndrey V. Elsukov if (sc->gre_options & GRE_UDPENCAP) { 358aee793eeSAndrey V. Elsukov sc->gre_csumflags = CSUM_UDP; 359aee793eeSAndrey V. Elsukov sc->gre_hlen = sizeof(struct greudp); 360aee793eeSAndrey V. Elsukov sc->gre_oip.ip_p = IPPROTO_UDP; 361aee793eeSAndrey V. Elsukov gh = &sc->gre_udphdr->gi_gre; 362aee793eeSAndrey V. Elsukov gre_update_udphdr(sc, &sc->gre_udp, 363aee793eeSAndrey V. Elsukov in_pseudo(sc->gre_oip.ip_src.s_addr, 364aee793eeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr, 0)); 365aee793eeSAndrey V. Elsukov } else { 366a5185adeSAndrey V. Elsukov sc->gre_hlen = sizeof(struct greip); 367aee793eeSAndrey V. Elsukov sc->gre_oip.ip_p = IPPROTO_GRE; 368aee793eeSAndrey V. Elsukov gh = &sc->gre_iphdr->gi_gre; 369aee793eeSAndrey V. Elsukov } 370a5185adeSAndrey V. Elsukov sc->gre_oip.ip_v = IPVERSION; 371a5185adeSAndrey V. Elsukov sc->gre_oip.ip_hl = sizeof(struct ip) >> 2; 372aee793eeSAndrey V. Elsukov gre_update_hdr(sc, gh); 373aee793eeSAndrey V. Elsukov 374aee793eeSAndrey V. Elsukov /* 375aee793eeSAndrey V. Elsukov * If we return error, this means that sc is not linked, 376aee793eeSAndrey V. Elsukov * and caller should reset gre_family and free(sc->gre_hdr). 377aee793eeSAndrey V. Elsukov */ 378aee793eeSAndrey V. Elsukov if (sc->gre_options & GRE_UDPENCAP) { 379aee793eeSAndrey V. Elsukov error = in_gre_setup_socket(sc); 380aee793eeSAndrey V. Elsukov if (error != 0) 381aee793eeSAndrey V. Elsukov return (error); 382aee793eeSAndrey V. Elsukov } else 383a5185adeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain); 38419873f47SAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_SRCHASH(sc->gre_oip.ip_src.s_addr), 38519873f47SAndrey V. Elsukov sc, srchash); 386aee793eeSAndrey V. Elsukov 387aee793eeSAndrey V. Elsukov /* Set IFF_DRV_RUNNING if interface is ready */ 388c8ee75f2SGleb Smirnoff NET_EPOCH_ENTER(et); 389aee793eeSAndrey V. Elsukov in_gre_set_running(sc); 390c8ee75f2SGleb Smirnoff NET_EPOCH_EXIT(et); 391aee793eeSAndrey V. Elsukov return (0); 392a5185adeSAndrey V. Elsukov } 393a5185adeSAndrey V. Elsukov 394aee793eeSAndrey V. Elsukov int 395a5185adeSAndrey V. Elsukov in_gre_setopts(struct gre_softc *sc, u_long cmd, uint32_t value) 396a5185adeSAndrey V. Elsukov { 397aee793eeSAndrey V. Elsukov int error; 398a5185adeSAndrey V. Elsukov 399a5185adeSAndrey V. Elsukov /* NOTE: we are protected with gre_ioctl_sx lock */ 400aee793eeSAndrey V. Elsukov MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT); 401a5185adeSAndrey V. Elsukov MPASS(sc->gre_family == AF_INET); 402aee793eeSAndrey V. Elsukov 403aee793eeSAndrey V. Elsukov /* 404aee793eeSAndrey V. Elsukov * If we are going to change encapsulation protocol, do check 405aee793eeSAndrey V. Elsukov * for duplicate tunnels. Return EEXIST here to do not confuse 406aee793eeSAndrey V. Elsukov * user. 407aee793eeSAndrey V. Elsukov */ 408aee793eeSAndrey V. Elsukov if (cmd == GRESOPTS && 409aee793eeSAndrey V. Elsukov (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) && 410aee793eeSAndrey V. Elsukov in_gre_checkdup(sc, sc->gre_oip.ip_src.s_addr, 411aee793eeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr, value) == EADDRNOTAVAIL) 412aee793eeSAndrey V. Elsukov return (EEXIST); 413aee793eeSAndrey V. Elsukov 414a5185adeSAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 41519873f47SAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 416a5185adeSAndrey V. Elsukov GRE_WAIT(); 417aee793eeSAndrey V. Elsukov switch (cmd) { 418aee793eeSAndrey V. Elsukov case GRESKEY: 419a5185adeSAndrey V. Elsukov sc->gre_key = value; 420aee793eeSAndrey V. Elsukov break; 421aee793eeSAndrey V. Elsukov case GRESOPTS: 422a5185adeSAndrey V. Elsukov sc->gre_options = value; 423aee793eeSAndrey V. Elsukov break; 424aee793eeSAndrey V. Elsukov case GRESPORT: 425aee793eeSAndrey V. Elsukov sc->gre_port = value; 426aee793eeSAndrey V. Elsukov break; 427aee793eeSAndrey V. Elsukov } 428aee793eeSAndrey V. Elsukov error = in_gre_attach(sc); 429aee793eeSAndrey V. Elsukov if (error != 0) { 430aee793eeSAndrey V. Elsukov sc->gre_family = 0; 431aee793eeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 432aee793eeSAndrey V. Elsukov } 433aee793eeSAndrey V. Elsukov return (error); 434a5185adeSAndrey V. Elsukov } 435a5185adeSAndrey V. Elsukov 436a5185adeSAndrey V. Elsukov int 437a5185adeSAndrey V. Elsukov in_gre_ioctl(struct gre_softc *sc, u_long cmd, caddr_t data) 438a5185adeSAndrey V. Elsukov { 439a5185adeSAndrey V. Elsukov struct ifreq *ifr = (struct ifreq *)data; 440a5185adeSAndrey V. Elsukov struct sockaddr_in *dst, *src; 441a5185adeSAndrey V. Elsukov struct ip *ip; 442a5185adeSAndrey V. Elsukov int error; 443a5185adeSAndrey V. Elsukov 444a5185adeSAndrey V. Elsukov /* NOTE: we are protected with gre_ioctl_sx lock */ 445a5185adeSAndrey V. Elsukov error = EINVAL; 446a5185adeSAndrey V. Elsukov switch (cmd) { 447a5185adeSAndrey V. Elsukov case SIOCSIFPHYADDR: 448a5185adeSAndrey V. Elsukov src = &((struct in_aliasreq *)data)->ifra_addr; 449a5185adeSAndrey V. Elsukov dst = &((struct in_aliasreq *)data)->ifra_dstaddr; 450a5185adeSAndrey V. Elsukov 451a5185adeSAndrey V. Elsukov /* sanity checks */ 452a5185adeSAndrey V. Elsukov if (src->sin_family != dst->sin_family || 453a5185adeSAndrey V. Elsukov src->sin_family != AF_INET || 454a5185adeSAndrey V. Elsukov src->sin_len != dst->sin_len || 455a5185adeSAndrey V. Elsukov src->sin_len != sizeof(*src)) 456a5185adeSAndrey V. Elsukov break; 457a5185adeSAndrey V. Elsukov if (src->sin_addr.s_addr == INADDR_ANY || 458a5185adeSAndrey V. Elsukov dst->sin_addr.s_addr == INADDR_ANY) { 459a5185adeSAndrey V. Elsukov error = EADDRNOTAVAIL; 460a5185adeSAndrey V. Elsukov break; 461a5185adeSAndrey V. Elsukov } 46219873f47SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) { 463a5185adeSAndrey V. Elsukov V_ipv4_hashtbl = gre_hashinit(); 46419873f47SAndrey V. Elsukov V_ipv4_srchashtbl = gre_hashinit(); 465aee793eeSAndrey V. Elsukov V_ipv4_sockets = (struct gre_sockets *)gre_hashinit(); 46619873f47SAndrey V. Elsukov } 467a5185adeSAndrey V. Elsukov error = in_gre_checkdup(sc, src->sin_addr.s_addr, 468aee793eeSAndrey V. Elsukov dst->sin_addr.s_addr, sc->gre_options); 469a5185adeSAndrey V. Elsukov if (error == EADDRNOTAVAIL) 470a5185adeSAndrey V. Elsukov break; 471a5185adeSAndrey V. Elsukov if (error == EEXIST) { 472a5185adeSAndrey V. Elsukov /* Addresses are the same. Just return. */ 473a5185adeSAndrey V. Elsukov error = 0; 474a5185adeSAndrey V. Elsukov break; 475a5185adeSAndrey V. Elsukov } 476aee793eeSAndrey V. Elsukov ip = malloc(sizeof(struct greudp) + 3 * sizeof(uint32_t), 477a5185adeSAndrey V. Elsukov M_GRE, M_WAITOK | M_ZERO); 478a5185adeSAndrey V. Elsukov ip->ip_src.s_addr = src->sin_addr.s_addr; 479a5185adeSAndrey V. Elsukov ip->ip_dst.s_addr = dst->sin_addr.s_addr; 480a5185adeSAndrey V. Elsukov if (sc->gre_family != 0) { 481a5185adeSAndrey V. Elsukov /* Detach existing tunnel first */ 482a5185adeSAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 48319873f47SAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 484a5185adeSAndrey V. Elsukov GRE_WAIT(); 485a5185adeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 486a5185adeSAndrey V. Elsukov /* XXX: should we notify about link state change? */ 487a5185adeSAndrey V. Elsukov } 488a5185adeSAndrey V. Elsukov sc->gre_family = AF_INET; 489a5185adeSAndrey V. Elsukov sc->gre_hdr = ip; 490a5185adeSAndrey V. Elsukov sc->gre_oseq = 0; 491a5185adeSAndrey V. Elsukov sc->gre_iseq = UINT32_MAX; 492aee793eeSAndrey V. Elsukov error = in_gre_attach(sc); 493aee793eeSAndrey V. Elsukov if (error != 0) { 494aee793eeSAndrey V. Elsukov sc->gre_family = 0; 495aee793eeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 496aee793eeSAndrey V. Elsukov } 497a5185adeSAndrey V. Elsukov break; 498a5185adeSAndrey V. Elsukov case SIOCGIFPSRCADDR: 499a5185adeSAndrey V. Elsukov case SIOCGIFPDSTADDR: 500a5185adeSAndrey V. Elsukov if (sc->gre_family != AF_INET) { 501a5185adeSAndrey V. Elsukov error = EADDRNOTAVAIL; 502a5185adeSAndrey V. Elsukov break; 503a5185adeSAndrey V. Elsukov } 504a5185adeSAndrey V. Elsukov src = (struct sockaddr_in *)&ifr->ifr_addr; 505a5185adeSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 506a5185adeSAndrey V. Elsukov src->sin_family = AF_INET; 507a5185adeSAndrey V. Elsukov src->sin_len = sizeof(*src); 508a5185adeSAndrey V. Elsukov src->sin_addr = (cmd == SIOCGIFPSRCADDR) ? 509a5185adeSAndrey V. Elsukov sc->gre_oip.ip_src: sc->gre_oip.ip_dst; 510a5185adeSAndrey V. Elsukov error = prison_if(curthread->td_ucred, (struct sockaddr *)src); 511a5185adeSAndrey V. Elsukov if (error != 0) 512a5185adeSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 513a5185adeSAndrey V. Elsukov break; 514a5185adeSAndrey V. Elsukov } 515a5185adeSAndrey V. Elsukov return (error); 516a5185adeSAndrey V. Elsukov } 517a5185adeSAndrey V. Elsukov 518f325335cSAndrey V. Elsukov int 519f325335cSAndrey V. Elsukov in_gre_output(struct mbuf *m, int af, int hlen) 520f325335cSAndrey V. Elsukov { 521f325335cSAndrey V. Elsukov struct greip *gi; 52273d7ddbcSMaxim Sobolev 523f325335cSAndrey V. Elsukov gi = mtod(m, struct greip *); 524f325335cSAndrey V. Elsukov switch (af) { 525f325335cSAndrey V. Elsukov case AF_INET: 526f325335cSAndrey V. Elsukov /* 527f325335cSAndrey V. Elsukov * gre_transmit() has used M_PREPEND() that doesn't guarantee 528f325335cSAndrey V. Elsukov * m_data is contiguous more than hlen bytes. Use m_copydata() 529f325335cSAndrey V. Elsukov * here to avoid m_pullup(). 530f325335cSAndrey V. Elsukov */ 531f325335cSAndrey V. Elsukov m_copydata(m, hlen + offsetof(struct ip, ip_tos), 532f325335cSAndrey V. Elsukov sizeof(u_char), &gi->gi_ip.ip_tos); 533f325335cSAndrey V. Elsukov m_copydata(m, hlen + offsetof(struct ip, ip_id), 534f325335cSAndrey V. Elsukov sizeof(u_short), (caddr_t)&gi->gi_ip.ip_id); 5358e96e13eSMaxim Sobolev break; 5369e669156SBjoern A. Zeeb #ifdef INET6 537f325335cSAndrey V. Elsukov case AF_INET6: 538f325335cSAndrey V. Elsukov gi->gi_ip.ip_tos = 0; /* XXX */ 5396d947416SGleb Smirnoff ip_fillid(&gi->gi_ip); 5409e669156SBjoern A. Zeeb break; 5419e669156SBjoern A. Zeeb #endif 5428e96e13eSMaxim Sobolev } 543f325335cSAndrey V. Elsukov gi->gi_ip.ip_ttl = V_ip_gre_ttl; 544f325335cSAndrey V. Elsukov gi->gi_ip.ip_len = htons(m->m_pkthdr.len); 545f325335cSAndrey V. Elsukov return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL)); 5468e96e13eSMaxim Sobolev } 5478e96e13eSMaxim Sobolev 54819873f47SAndrey V. Elsukov static const struct srcaddrtab *ipv4_srcaddrtab = NULL; 549a5185adeSAndrey V. Elsukov static const struct encaptab *ecookie = NULL; 5506d8fdfa9SAndrey V. Elsukov static const struct encap_config ipv4_encap_cfg = { 5516d8fdfa9SAndrey V. Elsukov .proto = IPPROTO_GRE, 5526d8fdfa9SAndrey V. Elsukov .min_length = sizeof(struct greip) + sizeof(struct ip), 553a5185adeSAndrey V. Elsukov .exact_match = ENCAP_DRV_LOOKUP, 554a5185adeSAndrey V. Elsukov .lookup = in_gre_lookup, 5556d8fdfa9SAndrey V. Elsukov .input = gre_input 5566d8fdfa9SAndrey V. Elsukov }; 5576d8fdfa9SAndrey V. Elsukov 558a5185adeSAndrey V. Elsukov void 559a5185adeSAndrey V. Elsukov in_gre_init(void) 5608e96e13eSMaxim Sobolev { 5618e96e13eSMaxim Sobolev 562a5185adeSAndrey V. Elsukov if (!IS_DEFAULT_VNET(curvnet)) 563a5185adeSAndrey V. Elsukov return; 56419873f47SAndrey V. Elsukov ipv4_srcaddrtab = ip_encap_register_srcaddr(in_gre_srcaddr, 56519873f47SAndrey V. Elsukov NULL, M_WAITOK); 566a5185adeSAndrey V. Elsukov ecookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK); 567a5185adeSAndrey V. Elsukov } 568a5185adeSAndrey V. Elsukov 569a5185adeSAndrey V. Elsukov void 570a5185adeSAndrey V. Elsukov in_gre_uninit(void) 571a5185adeSAndrey V. Elsukov { 572a5185adeSAndrey V. Elsukov 57319873f47SAndrey V. Elsukov if (IS_DEFAULT_VNET(curvnet)) { 574a5185adeSAndrey V. Elsukov ip_encap_detach(ecookie); 57519873f47SAndrey V. Elsukov ip_encap_unregister_srcaddr(ipv4_srcaddrtab); 57619873f47SAndrey V. Elsukov } 57719873f47SAndrey V. Elsukov if (V_ipv4_hashtbl != NULL) { 578a5185adeSAndrey V. Elsukov gre_hashdestroy(V_ipv4_hashtbl); 5798796e291SAndrey V. Elsukov V_ipv4_hashtbl = NULL; 5808796e291SAndrey V. Elsukov GRE_WAIT(); 58119873f47SAndrey V. Elsukov gre_hashdestroy(V_ipv4_srchashtbl); 582aee793eeSAndrey V. Elsukov gre_hashdestroy((struct gre_list *)V_ipv4_sockets); 58319873f47SAndrey V. Elsukov } 5848e96e13eSMaxim Sobolev } 585