1f325335cSAndrey V. Elsukov /*- 2f325335cSAndrey V. Elsukov * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org> 3f325335cSAndrey V. Elsukov * All rights reserved. 4f325335cSAndrey V. Elsukov * 5f325335cSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 6f325335cSAndrey V. Elsukov * modification, are permitted provided that the following conditions 7f325335cSAndrey V. Elsukov * are met: 8f325335cSAndrey V. Elsukov * 9f325335cSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 10f325335cSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 11f325335cSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 12f325335cSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 13f325335cSAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 14f325335cSAndrey V. Elsukov * 15f325335cSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16f325335cSAndrey V. Elsukov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17f325335cSAndrey V. Elsukov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18f325335cSAndrey V. Elsukov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19f325335cSAndrey V. Elsukov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20f325335cSAndrey V. Elsukov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21f325335cSAndrey V. Elsukov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22f325335cSAndrey V. Elsukov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23f325335cSAndrey V. Elsukov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24f325335cSAndrey V. Elsukov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25f325335cSAndrey V. Elsukov */ 26f325335cSAndrey V. Elsukov 27f325335cSAndrey V. Elsukov #include <sys/cdefs.h> 28f325335cSAndrey V. Elsukov __FBSDID("$FreeBSD$"); 29f325335cSAndrey V. Elsukov 30f325335cSAndrey V. Elsukov #include "opt_inet.h" 31f325335cSAndrey V. Elsukov #include "opt_inet6.h" 32f325335cSAndrey V. Elsukov 33f325335cSAndrey V. Elsukov #include <sys/param.h> 34f325335cSAndrey V. Elsukov #include <sys/lock.h> 35f325335cSAndrey V. Elsukov #include <sys/rmlock.h> 36f325335cSAndrey V. Elsukov #include <sys/systm.h> 37f325335cSAndrey V. Elsukov #include <sys/socket.h> 38f325335cSAndrey V. Elsukov #include <sys/sockio.h> 39f325335cSAndrey V. Elsukov #include <sys/mbuf.h> 40f325335cSAndrey V. Elsukov #include <sys/errno.h> 41f325335cSAndrey V. Elsukov #include <sys/kernel.h> 42f325335cSAndrey V. Elsukov #include <sys/queue.h> 43f325335cSAndrey V. Elsukov #include <sys/syslog.h> 44f325335cSAndrey V. Elsukov #include <sys/sysctl.h> 45f325335cSAndrey V. Elsukov #include <sys/malloc.h> 46f325335cSAndrey V. Elsukov 47f325335cSAndrey V. Elsukov #include <net/if.h> 48f325335cSAndrey V. Elsukov #include <net/if_var.h> 49f325335cSAndrey V. Elsukov #include <net/vnet.h> 50f325335cSAndrey V. Elsukov 51f325335cSAndrey V. Elsukov #include <netinet/in.h> 52f325335cSAndrey V. Elsukov #include <netinet/in_systm.h> 53f325335cSAndrey V. Elsukov #ifdef INET 54f325335cSAndrey V. Elsukov #include <net/ethernet.h> 55f325335cSAndrey V. Elsukov #include <netinet/ip.h> 56f325335cSAndrey V. Elsukov #endif 57f325335cSAndrey V. Elsukov #include <netinet/ip_encap.h> 58f325335cSAndrey V. Elsukov #include <netinet/ip6.h> 59f325335cSAndrey V. Elsukov #include <netinet6/ip6_var.h> 60f325335cSAndrey V. Elsukov #include <netinet6/in6_var.h> 61f325335cSAndrey V. Elsukov #include <net/if_gre.h> 62f325335cSAndrey V. Elsukov 63f325335cSAndrey V. Elsukov VNET_DEFINE(int, ip6_gre_hlim) = IPV6_DEFHLIM; 64f325335cSAndrey V. Elsukov #define V_ip6_gre_hlim VNET(ip6_gre_hlim) 65f325335cSAndrey V. Elsukov 66f325335cSAndrey V. Elsukov SYSCTL_DECL(_net_inet6_ip6); 67f325335cSAndrey V. Elsukov SYSCTL_INT(_net_inet6_ip6, OID_AUTO, grehlim, CTLFLAG_VNET | CTLFLAG_RW, 68f325335cSAndrey V. Elsukov &VNET_NAME(ip6_gre_hlim), 0, "Default hop limit for encapsulated packets"); 69f325335cSAndrey V. Elsukov 70f325335cSAndrey V. Elsukov static int 71f325335cSAndrey V. Elsukov in6_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 72f325335cSAndrey V. Elsukov { 73f325335cSAndrey V. Elsukov GRE_RLOCK_TRACKER; 74f325335cSAndrey V. Elsukov struct gre_softc *sc; 75f325335cSAndrey V. Elsukov struct ip6_hdr *ip6; 76f325335cSAndrey V. Elsukov 77f325335cSAndrey V. Elsukov sc = (struct gre_softc *)arg; 78f325335cSAndrey V. Elsukov if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0) 79f325335cSAndrey V. Elsukov return (0); 80f325335cSAndrey V. Elsukov 81f325335cSAndrey V. Elsukov M_ASSERTPKTHDR(m); 82f325335cSAndrey V. Elsukov /* 83f325335cSAndrey V. Elsukov * We expect that payload contains at least IPv4 84f325335cSAndrey V. Elsukov * or IPv6 packet. 85f325335cSAndrey V. Elsukov */ 86f325335cSAndrey V. Elsukov if (m->m_pkthdr.len < sizeof(struct greip6) + 87f325335cSAndrey V. Elsukov #ifdef INET 88f325335cSAndrey V. Elsukov sizeof(struct ip)) 89f325335cSAndrey V. Elsukov #else 90f325335cSAndrey V. Elsukov sizeof(struct ip6_hdr)) 91f325335cSAndrey V. Elsukov #endif 92f325335cSAndrey V. Elsukov return (0); 93f325335cSAndrey V. Elsukov 94f325335cSAndrey V. Elsukov GRE_RLOCK(sc); 95f325335cSAndrey V. Elsukov if (sc->gre_family == 0) 96f325335cSAndrey V. Elsukov goto bad; 97f325335cSAndrey V. Elsukov 98f325335cSAndrey V. Elsukov KASSERT(sc->gre_family == AF_INET6, 99f325335cSAndrey V. Elsukov ("wrong gre_family: %d", sc->gre_family)); 100f325335cSAndrey V. Elsukov 101f325335cSAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 102f325335cSAndrey V. Elsukov if (!IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src, &ip6->ip6_dst) || 103f325335cSAndrey V. Elsukov !IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, &ip6->ip6_src)) 104f325335cSAndrey V. Elsukov goto bad; 105f325335cSAndrey V. Elsukov 106f325335cSAndrey V. Elsukov GRE_RUNLOCK(sc); 107*6d8fdfa9SAndrey V. Elsukov return (128 * 2 + 32); 108f325335cSAndrey V. Elsukov bad: 109f325335cSAndrey V. Elsukov GRE_RUNLOCK(sc); 110f325335cSAndrey V. Elsukov return (0); 111f325335cSAndrey V. Elsukov } 112f325335cSAndrey V. Elsukov 113f325335cSAndrey V. Elsukov int 114f325335cSAndrey V. Elsukov in6_gre_output(struct mbuf *m, int af, int hlen) 115f325335cSAndrey V. Elsukov { 116f325335cSAndrey V. Elsukov struct greip6 *gi6; 117f325335cSAndrey V. Elsukov 118f325335cSAndrey V. Elsukov gi6 = mtod(m, struct greip6 *); 119f325335cSAndrey V. Elsukov gi6->gi6_ip6.ip6_hlim = V_ip6_gre_hlim; 120f325335cSAndrey V. Elsukov return (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, NULL)); 121f325335cSAndrey V. Elsukov } 122f325335cSAndrey V. Elsukov 123*6d8fdfa9SAndrey V. Elsukov static const struct encap_config ipv6_encap_cfg = { 124*6d8fdfa9SAndrey V. Elsukov .proto = IPPROTO_GRE, 125*6d8fdfa9SAndrey V. Elsukov .min_length = sizeof(struct greip6) + sizeof(struct ip), 126*6d8fdfa9SAndrey V. Elsukov .exact_match = (sizeof(struct in6_addr) << 4) + 32, 127*6d8fdfa9SAndrey V. Elsukov .check = in6_gre_encapcheck, 128*6d8fdfa9SAndrey V. Elsukov .input = gre_input 129*6d8fdfa9SAndrey V. Elsukov }; 130*6d8fdfa9SAndrey V. Elsukov 131f325335cSAndrey V. Elsukov int 132f325335cSAndrey V. Elsukov in6_gre_attach(struct gre_softc *sc) 133f325335cSAndrey V. Elsukov { 134f325335cSAndrey V. Elsukov 135f325335cSAndrey V. Elsukov KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL")); 136*6d8fdfa9SAndrey V. Elsukov sc->gre_ecookie = ip6_encap_attach(&ipv6_encap_cfg, sc, M_WAITOK); 137f325335cSAndrey V. Elsukov return (0); 138f325335cSAndrey V. Elsukov } 139