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> 47a5185adeSAndrey V. Elsukov #include <sys/sockio.h> 48a5185adeSAndrey V. Elsukov #include <sys/mbuf.h> 498e96e13eSMaxim Sobolev #include <sys/errno.h> 508e96e13eSMaxim Sobolev #include <sys/kernel.h> 51f325335cSAndrey V. Elsukov #include <sys/sysctl.h> 52a5185adeSAndrey V. Elsukov #include <sys/malloc.h> 536573d758SMatt Macy #include <sys/proc.h> 54a5185adeSAndrey V. Elsukov 558e96e13eSMaxim Sobolev #include <net/if.h> 5676039bc8SGleb Smirnoff #include <net/if_var.h> 57f325335cSAndrey V. Elsukov #include <net/vnet.h> 588e96e13eSMaxim Sobolev 598e96e13eSMaxim Sobolev #include <netinet/in.h> 608e96e13eSMaxim Sobolev #include <netinet/in_var.h> 618e96e13eSMaxim Sobolev #include <netinet/ip.h> 62f325335cSAndrey V. Elsukov #include <netinet/ip_encap.h> 638e96e13eSMaxim Sobolev #include <netinet/ip_var.h> 64f325335cSAndrey V. Elsukov 65f325335cSAndrey V. Elsukov #ifdef INET6 66f325335cSAndrey V. Elsukov #include <netinet/ip6.h> 678e96e13eSMaxim Sobolev #endif 688e96e13eSMaxim Sobolev 698e96e13eSMaxim Sobolev #include <net/if_gre.h> 708e96e13eSMaxim Sobolev 71f325335cSAndrey V. Elsukov #define GRE_TTL 30 72f325335cSAndrey V. Elsukov VNET_DEFINE(int, ip_gre_ttl) = GRE_TTL; 73f325335cSAndrey V. Elsukov #define V_ip_gre_ttl VNET(ip_gre_ttl) 74f325335cSAndrey V. Elsukov SYSCTL_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_VNET | CTLFLAG_RW, 756d8fdfa9SAndrey V. Elsukov &VNET_NAME(ip_gre_ttl), 0, "Default TTL value for encapsulated packets"); 768e96e13eSMaxim Sobolev 775f901c92SAndrew Turner VNET_DEFINE_STATIC(struct gre_list *, ipv4_hashtbl) = NULL; 7819873f47SAndrey V. Elsukov VNET_DEFINE_STATIC(struct gre_list *, ipv4_srchashtbl) = NULL; 79a5185adeSAndrey V. Elsukov #define V_ipv4_hashtbl VNET(ipv4_hashtbl) 8019873f47SAndrey V. Elsukov #define V_ipv4_srchashtbl VNET(ipv4_srchashtbl) 81a5185adeSAndrey V. Elsukov #define GRE_HASH(src, dst) (V_ipv4_hashtbl[\ 82a5185adeSAndrey V. Elsukov in_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)]) 8319873f47SAndrey V. Elsukov #define GRE_SRCHASH(src) (V_ipv4_srchashtbl[\ 8419873f47SAndrey V. Elsukov fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)]) 85a5185adeSAndrey V. Elsukov #define GRE_HASH_SC(sc) GRE_HASH((sc)->gre_oip.ip_src.s_addr,\ 86a5185adeSAndrey V. Elsukov (sc)->gre_oip.ip_dst.s_addr) 878e96e13eSMaxim Sobolev 88a5185adeSAndrey V. Elsukov static uint32_t 89a5185adeSAndrey V. Elsukov in_gre_hashval(in_addr_t src, in_addr_t dst) 90a5185adeSAndrey V. Elsukov { 91a5185adeSAndrey V. Elsukov uint32_t ret; 92a5185adeSAndrey V. Elsukov 93a5185adeSAndrey V. Elsukov ret = fnv_32_buf(&src, sizeof(src), FNV1_32_INIT); 94a5185adeSAndrey V. Elsukov return (fnv_32_buf(&dst, sizeof(dst), ret)); 95a5185adeSAndrey V. Elsukov } 96a5185adeSAndrey V. Elsukov 97a5185adeSAndrey V. Elsukov static int 98a5185adeSAndrey V. Elsukov in_gre_checkdup(const struct gre_softc *sc, in_addr_t src, in_addr_t dst) 99a5185adeSAndrey V. Elsukov { 100a5185adeSAndrey V. Elsukov struct gre_softc *tmp; 101a5185adeSAndrey V. Elsukov 102a5185adeSAndrey V. Elsukov if (sc->gre_family == AF_INET && 103a5185adeSAndrey V. Elsukov sc->gre_oip.ip_src.s_addr == src && 104a5185adeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr == dst) 105a5185adeSAndrey V. Elsukov return (EEXIST); 106a5185adeSAndrey V. Elsukov 107a5185adeSAndrey V. Elsukov CK_LIST_FOREACH(tmp, &GRE_HASH(src, dst), chain) { 108a5185adeSAndrey V. Elsukov if (tmp == sc) 109a5185adeSAndrey V. Elsukov continue; 110a5185adeSAndrey V. Elsukov if (tmp->gre_oip.ip_src.s_addr == src && 111a5185adeSAndrey V. Elsukov tmp->gre_oip.ip_dst.s_addr == dst) 112a5185adeSAndrey V. Elsukov return (EADDRNOTAVAIL); 113a5185adeSAndrey V. Elsukov } 114a5185adeSAndrey V. Elsukov return (0); 115a5185adeSAndrey V. Elsukov } 116a5185adeSAndrey V. Elsukov 117a5185adeSAndrey V. Elsukov static int 118a5185adeSAndrey V. Elsukov in_gre_lookup(const struct mbuf *m, int off, int proto, void **arg) 119a5185adeSAndrey V. Elsukov { 120a5185adeSAndrey V. Elsukov const struct ip *ip; 121a5185adeSAndrey V. Elsukov struct gre_softc *sc; 122a5185adeSAndrey V. Elsukov 1236e081509SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) 1246e081509SAndrey V. Elsukov return (0); 1256e081509SAndrey V. Elsukov 1266573d758SMatt Macy MPASS(in_epoch(net_epoch_preempt)); 127a5185adeSAndrey V. Elsukov ip = mtod(m, const struct ip *); 128a5185adeSAndrey V. Elsukov CK_LIST_FOREACH(sc, &GRE_HASH(ip->ip_dst.s_addr, 129a5185adeSAndrey V. Elsukov ip->ip_src.s_addr), chain) { 130a5185adeSAndrey V. Elsukov /* 131a5185adeSAndrey V. Elsukov * This is an inbound packet, its ip_dst is source address 132a5185adeSAndrey V. Elsukov * in softc. 133a5185adeSAndrey V. Elsukov */ 134a5185adeSAndrey V. Elsukov if (sc->gre_oip.ip_src.s_addr == ip->ip_dst.s_addr && 135a5185adeSAndrey V. Elsukov sc->gre_oip.ip_dst.s_addr == ip->ip_src.s_addr) { 136f325335cSAndrey V. Elsukov if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0) 137f325335cSAndrey V. Elsukov return (0); 138a5185adeSAndrey V. Elsukov *arg = sc; 139a5185adeSAndrey V. Elsukov return (ENCAP_DRV_LOOKUP); 140a5185adeSAndrey V. Elsukov } 141a5185adeSAndrey V. Elsukov } 142f325335cSAndrey V. Elsukov return (0); 1438e96e13eSMaxim Sobolev } 1448e96e13eSMaxim Sobolev 14519873f47SAndrey V. Elsukov /* 14619873f47SAndrey V. Elsukov * Check that ingress address belongs to local host. 14719873f47SAndrey V. Elsukov */ 14819873f47SAndrey V. Elsukov static void 14919873f47SAndrey V. Elsukov in_gre_set_running(struct gre_softc *sc) 15019873f47SAndrey V. Elsukov { 15119873f47SAndrey V. Elsukov 15219873f47SAndrey V. Elsukov if (in_localip(sc->gre_oip.ip_src)) 15319873f47SAndrey V. Elsukov GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; 15419873f47SAndrey V. Elsukov else 15519873f47SAndrey V. Elsukov GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 15619873f47SAndrey V. Elsukov } 15719873f47SAndrey V. Elsukov 15819873f47SAndrey V. Elsukov /* 15919873f47SAndrey V. Elsukov * ifaddr_event handler. 16019873f47SAndrey V. Elsukov * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent 16119873f47SAndrey V. Elsukov * source address spoofing. 16219873f47SAndrey V. Elsukov */ 16319873f47SAndrey V. Elsukov static void 16419873f47SAndrey V. Elsukov in_gre_srcaddr(void *arg __unused, const struct sockaddr *sa, 16519873f47SAndrey V. Elsukov int event __unused) 16619873f47SAndrey V. Elsukov { 16719873f47SAndrey V. Elsukov const struct sockaddr_in *sin; 16819873f47SAndrey V. Elsukov struct gre_softc *sc; 16919873f47SAndrey V. Elsukov 170*8796e291SAndrey V. Elsukov /* Check that VNET is ready */ 171*8796e291SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) 17219873f47SAndrey V. Elsukov return; 17319873f47SAndrey V. Elsukov 17419873f47SAndrey V. Elsukov MPASS(in_epoch(net_epoch_preempt)); 17519873f47SAndrey V. Elsukov sin = (const struct sockaddr_in *)sa; 17619873f47SAndrey V. Elsukov CK_LIST_FOREACH(sc, &GRE_SRCHASH(sin->sin_addr.s_addr), srchash) { 17719873f47SAndrey V. Elsukov if (sc->gre_oip.ip_src.s_addr != sin->sin_addr.s_addr) 17819873f47SAndrey V. Elsukov continue; 17919873f47SAndrey V. Elsukov in_gre_set_running(sc); 18019873f47SAndrey V. Elsukov } 18119873f47SAndrey V. Elsukov } 18219873f47SAndrey V. Elsukov 183a5185adeSAndrey V. Elsukov static void 184a5185adeSAndrey V. Elsukov in_gre_attach(struct gre_softc *sc) 185a5185adeSAndrey V. Elsukov { 186a5185adeSAndrey V. Elsukov 187a5185adeSAndrey V. Elsukov sc->gre_hlen = sizeof(struct greip); 188a5185adeSAndrey V. Elsukov sc->gre_oip.ip_v = IPVERSION; 189a5185adeSAndrey V. Elsukov sc->gre_oip.ip_hl = sizeof(struct ip) >> 2; 190a5185adeSAndrey V. Elsukov sc->gre_oip.ip_p = IPPROTO_GRE; 191a5185adeSAndrey V. Elsukov gre_updatehdr(sc, &sc->gre_gihdr->gi_gre); 192a5185adeSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain); 19319873f47SAndrey V. Elsukov CK_LIST_INSERT_HEAD(&GRE_SRCHASH(sc->gre_oip.ip_src.s_addr), 19419873f47SAndrey V. Elsukov sc, srchash); 195a5185adeSAndrey V. Elsukov } 196a5185adeSAndrey V. Elsukov 197a5185adeSAndrey V. Elsukov void 198a5185adeSAndrey V. Elsukov in_gre_setopts(struct gre_softc *sc, u_long cmd, uint32_t value) 199a5185adeSAndrey V. Elsukov { 200a5185adeSAndrey V. Elsukov 201a5185adeSAndrey V. Elsukov MPASS(cmd == GRESKEY || cmd == GRESOPTS); 202a5185adeSAndrey V. Elsukov 203a5185adeSAndrey V. Elsukov /* NOTE: we are protected with gre_ioctl_sx lock */ 204a5185adeSAndrey V. Elsukov MPASS(sc->gre_family == AF_INET); 205a5185adeSAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 20619873f47SAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 207a5185adeSAndrey V. Elsukov GRE_WAIT(); 208a5185adeSAndrey V. Elsukov if (cmd == GRESKEY) 209a5185adeSAndrey V. Elsukov sc->gre_key = value; 210a5185adeSAndrey V. Elsukov else 211a5185adeSAndrey V. Elsukov sc->gre_options = value; 212a5185adeSAndrey V. Elsukov in_gre_attach(sc); 213a5185adeSAndrey V. Elsukov } 214a5185adeSAndrey V. Elsukov 215a5185adeSAndrey V. Elsukov int 216a5185adeSAndrey V. Elsukov in_gre_ioctl(struct gre_softc *sc, u_long cmd, caddr_t data) 217a5185adeSAndrey V. Elsukov { 218a5185adeSAndrey V. Elsukov struct ifreq *ifr = (struct ifreq *)data; 219a5185adeSAndrey V. Elsukov struct sockaddr_in *dst, *src; 220a5185adeSAndrey V. Elsukov struct ip *ip; 221a5185adeSAndrey V. Elsukov int error; 222a5185adeSAndrey V. Elsukov 223a5185adeSAndrey V. Elsukov /* NOTE: we are protected with gre_ioctl_sx lock */ 224a5185adeSAndrey V. Elsukov error = EINVAL; 225a5185adeSAndrey V. Elsukov switch (cmd) { 226a5185adeSAndrey V. Elsukov case SIOCSIFPHYADDR: 227a5185adeSAndrey V. Elsukov src = &((struct in_aliasreq *)data)->ifra_addr; 228a5185adeSAndrey V. Elsukov dst = &((struct in_aliasreq *)data)->ifra_dstaddr; 229a5185adeSAndrey V. Elsukov 230a5185adeSAndrey V. Elsukov /* sanity checks */ 231a5185adeSAndrey V. Elsukov if (src->sin_family != dst->sin_family || 232a5185adeSAndrey V. Elsukov src->sin_family != AF_INET || 233a5185adeSAndrey V. Elsukov src->sin_len != dst->sin_len || 234a5185adeSAndrey V. Elsukov src->sin_len != sizeof(*src)) 235a5185adeSAndrey V. Elsukov break; 236a5185adeSAndrey V. Elsukov if (src->sin_addr.s_addr == INADDR_ANY || 237a5185adeSAndrey V. Elsukov dst->sin_addr.s_addr == INADDR_ANY) { 238a5185adeSAndrey V. Elsukov error = EADDRNOTAVAIL; 239a5185adeSAndrey V. Elsukov break; 240a5185adeSAndrey V. Elsukov } 24119873f47SAndrey V. Elsukov if (V_ipv4_hashtbl == NULL) { 242a5185adeSAndrey V. Elsukov V_ipv4_hashtbl = gre_hashinit(); 24319873f47SAndrey V. Elsukov V_ipv4_srchashtbl = gre_hashinit(); 24419873f47SAndrey V. Elsukov } 245a5185adeSAndrey V. Elsukov error = in_gre_checkdup(sc, src->sin_addr.s_addr, 246a5185adeSAndrey V. Elsukov dst->sin_addr.s_addr); 247a5185adeSAndrey V. Elsukov if (error == EADDRNOTAVAIL) 248a5185adeSAndrey V. Elsukov break; 249a5185adeSAndrey V. Elsukov if (error == EEXIST) { 250a5185adeSAndrey V. Elsukov /* Addresses are the same. Just return. */ 251a5185adeSAndrey V. Elsukov error = 0; 252a5185adeSAndrey V. Elsukov break; 253a5185adeSAndrey V. Elsukov } 254a5185adeSAndrey V. Elsukov ip = malloc(sizeof(struct greip) + 3 * sizeof(uint32_t), 255a5185adeSAndrey V. Elsukov M_GRE, M_WAITOK | M_ZERO); 256a5185adeSAndrey V. Elsukov ip->ip_src.s_addr = src->sin_addr.s_addr; 257a5185adeSAndrey V. Elsukov ip->ip_dst.s_addr = dst->sin_addr.s_addr; 258a5185adeSAndrey V. Elsukov if (sc->gre_family != 0) { 259a5185adeSAndrey V. Elsukov /* Detach existing tunnel first */ 260a5185adeSAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 26119873f47SAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 262a5185adeSAndrey V. Elsukov GRE_WAIT(); 263a5185adeSAndrey V. Elsukov free(sc->gre_hdr, M_GRE); 264a5185adeSAndrey V. Elsukov /* XXX: should we notify about link state change? */ 265a5185adeSAndrey V. Elsukov } 266a5185adeSAndrey V. Elsukov sc->gre_family = AF_INET; 267a5185adeSAndrey V. Elsukov sc->gre_hdr = ip; 268a5185adeSAndrey V. Elsukov sc->gre_oseq = 0; 269a5185adeSAndrey V. Elsukov sc->gre_iseq = UINT32_MAX; 270a5185adeSAndrey V. Elsukov in_gre_attach(sc); 27119873f47SAndrey V. Elsukov in_gre_set_running(sc); 272a5185adeSAndrey V. Elsukov break; 273a5185adeSAndrey V. Elsukov case SIOCGIFPSRCADDR: 274a5185adeSAndrey V. Elsukov case SIOCGIFPDSTADDR: 275a5185adeSAndrey V. Elsukov if (sc->gre_family != AF_INET) { 276a5185adeSAndrey V. Elsukov error = EADDRNOTAVAIL; 277a5185adeSAndrey V. Elsukov break; 278a5185adeSAndrey V. Elsukov } 279a5185adeSAndrey V. Elsukov src = (struct sockaddr_in *)&ifr->ifr_addr; 280a5185adeSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 281a5185adeSAndrey V. Elsukov src->sin_family = AF_INET; 282a5185adeSAndrey V. Elsukov src->sin_len = sizeof(*src); 283a5185adeSAndrey V. Elsukov src->sin_addr = (cmd == SIOCGIFPSRCADDR) ? 284a5185adeSAndrey V. Elsukov sc->gre_oip.ip_src: sc->gre_oip.ip_dst; 285a5185adeSAndrey V. Elsukov error = prison_if(curthread->td_ucred, (struct sockaddr *)src); 286a5185adeSAndrey V. Elsukov if (error != 0) 287a5185adeSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 288a5185adeSAndrey V. Elsukov break; 289a5185adeSAndrey V. Elsukov } 290a5185adeSAndrey V. Elsukov return (error); 291a5185adeSAndrey V. Elsukov } 292a5185adeSAndrey V. Elsukov 293f325335cSAndrey V. Elsukov int 294f325335cSAndrey V. Elsukov in_gre_output(struct mbuf *m, int af, int hlen) 295f325335cSAndrey V. Elsukov { 296f325335cSAndrey V. Elsukov struct greip *gi; 29773d7ddbcSMaxim Sobolev 298f325335cSAndrey V. Elsukov gi = mtod(m, struct greip *); 299f325335cSAndrey V. Elsukov switch (af) { 300f325335cSAndrey V. Elsukov case AF_INET: 301f325335cSAndrey V. Elsukov /* 302f325335cSAndrey V. Elsukov * gre_transmit() has used M_PREPEND() that doesn't guarantee 303f325335cSAndrey V. Elsukov * m_data is contiguous more than hlen bytes. Use m_copydata() 304f325335cSAndrey V. Elsukov * here to avoid m_pullup(). 305f325335cSAndrey V. Elsukov */ 306f325335cSAndrey V. Elsukov m_copydata(m, hlen + offsetof(struct ip, ip_tos), 307f325335cSAndrey V. Elsukov sizeof(u_char), &gi->gi_ip.ip_tos); 308f325335cSAndrey V. Elsukov m_copydata(m, hlen + offsetof(struct ip, ip_id), 309f325335cSAndrey V. Elsukov sizeof(u_short), (caddr_t)&gi->gi_ip.ip_id); 3108e96e13eSMaxim Sobolev break; 3119e669156SBjoern A. Zeeb #ifdef INET6 312f325335cSAndrey V. Elsukov case AF_INET6: 313f325335cSAndrey V. Elsukov gi->gi_ip.ip_tos = 0; /* XXX */ 3146d947416SGleb Smirnoff ip_fillid(&gi->gi_ip); 3159e669156SBjoern A. Zeeb break; 3169e669156SBjoern A. Zeeb #endif 3178e96e13eSMaxim Sobolev } 318f325335cSAndrey V. Elsukov gi->gi_ip.ip_ttl = V_ip_gre_ttl; 319f325335cSAndrey V. Elsukov gi->gi_ip.ip_len = htons(m->m_pkthdr.len); 320f325335cSAndrey V. Elsukov return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL)); 3218e96e13eSMaxim Sobolev } 3228e96e13eSMaxim Sobolev 32319873f47SAndrey V. Elsukov static const struct srcaddrtab *ipv4_srcaddrtab = NULL; 324a5185adeSAndrey V. Elsukov static const struct encaptab *ecookie = NULL; 3256d8fdfa9SAndrey V. Elsukov static const struct encap_config ipv4_encap_cfg = { 3266d8fdfa9SAndrey V. Elsukov .proto = IPPROTO_GRE, 3276d8fdfa9SAndrey V. Elsukov .min_length = sizeof(struct greip) + sizeof(struct ip), 328a5185adeSAndrey V. Elsukov .exact_match = ENCAP_DRV_LOOKUP, 329a5185adeSAndrey V. Elsukov .lookup = in_gre_lookup, 3306d8fdfa9SAndrey V. Elsukov .input = gre_input 3316d8fdfa9SAndrey V. Elsukov }; 3326d8fdfa9SAndrey V. Elsukov 333a5185adeSAndrey V. Elsukov void 334a5185adeSAndrey V. Elsukov in_gre_init(void) 3358e96e13eSMaxim Sobolev { 3368e96e13eSMaxim Sobolev 337a5185adeSAndrey V. Elsukov if (!IS_DEFAULT_VNET(curvnet)) 338a5185adeSAndrey V. Elsukov return; 33919873f47SAndrey V. Elsukov ipv4_srcaddrtab = ip_encap_register_srcaddr(in_gre_srcaddr, 34019873f47SAndrey V. Elsukov NULL, M_WAITOK); 341a5185adeSAndrey V. Elsukov ecookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK); 342a5185adeSAndrey V. Elsukov } 343a5185adeSAndrey V. Elsukov 344a5185adeSAndrey V. Elsukov void 345a5185adeSAndrey V. Elsukov in_gre_uninit(void) 346a5185adeSAndrey V. Elsukov { 347a5185adeSAndrey V. Elsukov 34819873f47SAndrey V. Elsukov if (IS_DEFAULT_VNET(curvnet)) { 349a5185adeSAndrey V. Elsukov ip_encap_detach(ecookie); 35019873f47SAndrey V. Elsukov ip_encap_unregister_srcaddr(ipv4_srcaddrtab); 35119873f47SAndrey V. Elsukov } 35219873f47SAndrey V. Elsukov if (V_ipv4_hashtbl != NULL) { 353a5185adeSAndrey V. Elsukov gre_hashdestroy(V_ipv4_hashtbl); 354*8796e291SAndrey V. Elsukov V_ipv4_hashtbl = NULL; 355*8796e291SAndrey V. Elsukov GRE_WAIT(); 35619873f47SAndrey V. Elsukov gre_hashdestroy(V_ipv4_srchashtbl); 35719873f47SAndrey V. Elsukov } 3588e96e13eSMaxim Sobolev } 359