133841545SHajimu UMEMOTO /* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ 2686cdd19SJun-ichiro itojun Hagino 3c398230bSWarner Losh /*- 4cfa1ca9dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5cfa1ca9dSYoshinobu Inoue * All rights reserved. 6cfa1ca9dSYoshinobu Inoue * 7cfa1ca9dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 8cfa1ca9dSYoshinobu Inoue * modification, are permitted provided that the following conditions 9cfa1ca9dSYoshinobu Inoue * are met: 10cfa1ca9dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 11cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 12cfa1ca9dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 13cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 14cfa1ca9dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 15cfa1ca9dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 16cfa1ca9dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 17cfa1ca9dSYoshinobu Inoue * without specific prior written permission. 18cfa1ca9dSYoshinobu Inoue * 19cfa1ca9dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20cfa1ca9dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21cfa1ca9dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22cfa1ca9dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23cfa1ca9dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24cfa1ca9dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25cfa1ca9dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26cfa1ca9dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27cfa1ca9dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28cfa1ca9dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29cfa1ca9dSYoshinobu Inoue * SUCH DAMAGE. 30cfa1ca9dSYoshinobu Inoue */ 31cfa1ca9dSYoshinobu Inoue 324b421e2dSMike Silbersack #include <sys/cdefs.h> 334b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 344b421e2dSMike Silbersack 35cfa1ca9dSYoshinobu Inoue #include "opt_mrouting.h" 36686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 37cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 38cfa1ca9dSYoshinobu Inoue 39cfa1ca9dSYoshinobu Inoue #include <sys/param.h> 40cfa1ca9dSYoshinobu Inoue #include <sys/systm.h> 41cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h> 479426aedfSHajimu UMEMOTO #include <sys/protosw.h> 48686cdd19SJun-ichiro itojun Hagino #include <sys/malloc.h> 49cfa1ca9dSYoshinobu Inoue 50cfa1ca9dSYoshinobu Inoue #include <net/if.h> 51*76039bc8SGleb Smirnoff #include <net/if_var.h> 52cfa1ca9dSYoshinobu Inoue #include <net/route.h> 53530c0060SRobert Watson #include <net/vnet.h> 54cfa1ca9dSYoshinobu Inoue 55cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 56cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 57cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 586a800098SYoshinobu Inoue #include <netinet/ip_var.h> 596a800098SYoshinobu Inoue #include <netinet/in_gif.h> 60686cdd19SJun-ichiro itojun Hagino #include <netinet/in_var.h> 61686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 626a800098SYoshinobu Inoue #include <netinet/ip_ecn.h> 63686cdd19SJun-ichiro itojun Hagino 646a800098SYoshinobu Inoue #ifdef INET6 65686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 666a800098SYoshinobu Inoue #endif 67cfa1ca9dSYoshinobu Inoue 68cfa1ca9dSYoshinobu Inoue #ifdef MROUTING 69cfa1ca9dSYoshinobu Inoue #include <netinet/ip_mroute.h> 70cfa1ca9dSYoshinobu Inoue #endif /* MROUTING */ 71cfa1ca9dSYoshinobu Inoue 72cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 73cfa1ca9dSYoshinobu Inoue 749426aedfSHajimu UMEMOTO static int gif_validate4(const struct ip *, struct gif_softc *, 759426aedfSHajimu UMEMOTO struct ifnet *); 769426aedfSHajimu UMEMOTO 779426aedfSHajimu UMEMOTO extern struct domain inetdomain; 78303989a2SRuslan Ermilov struct protosw in_gif_protosw = { 79303989a2SRuslan Ermilov .pr_type = SOCK_RAW, 80303989a2SRuslan Ermilov .pr_domain = &inetdomain, 81303989a2SRuslan Ermilov .pr_protocol = 0/* IPPROTO_IPV[46] */, 82303989a2SRuslan Ermilov .pr_flags = PR_ATOMIC|PR_ADDR, 83303989a2SRuslan Ermilov .pr_input = in_gif_input, 84303989a2SRuslan Ermilov .pr_output = (pr_output_t*)rip_output, 85303989a2SRuslan Ermilov .pr_ctloutput = rip_ctloutput, 86303989a2SRuslan Ermilov .pr_usrreqs = &rip_usrreqs 879426aedfSHajimu UMEMOTO }; 889426aedfSHajimu UMEMOTO 8982cea7e6SBjoern A. Zeeb VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 9082cea7e6SBjoern A. Zeeb #define V_ip_gif_ttl VNET(ip_gif_ttl) 91eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 92eddfbb76SRobert Watson &VNET_NAME(ip_gif_ttl), 0, ""); 93cfa1ca9dSYoshinobu Inoue 94cfa1ca9dSYoshinobu Inoue int 95f2565d68SRobert Watson in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) 96cfa1ca9dSYoshinobu Inoue { 97fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 98cfa1ca9dSYoshinobu Inoue struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; 99cfa1ca9dSYoshinobu Inoue struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; 100cfa1ca9dSYoshinobu Inoue struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; 101cfa1ca9dSYoshinobu Inoue struct ip iphdr; /* capsule IP header, host byte ordered */ 10273ff045cSAndrew Thompson struct etherip_header eiphdr; 103c89c8a10SMarius Strobl int error, len, proto; 104cfa1ca9dSYoshinobu Inoue u_int8_t tos; 105cfa1ca9dSYoshinobu Inoue 10625af0bb5SGleb Smirnoff GIF_LOCK_ASSERT(sc); 10725af0bb5SGleb Smirnoff 108cfa1ca9dSYoshinobu Inoue if (sin_src == NULL || sin_dst == NULL || 109cfa1ca9dSYoshinobu Inoue sin_src->sin_family != AF_INET || 110cfa1ca9dSYoshinobu Inoue sin_dst->sin_family != AF_INET) { 111cfa1ca9dSYoshinobu Inoue m_freem(m); 112cfa1ca9dSYoshinobu Inoue return EAFNOSUPPORT; 113cfa1ca9dSYoshinobu Inoue } 114cfa1ca9dSYoshinobu Inoue 115cfa1ca9dSYoshinobu Inoue switch (family) { 116686cdd19SJun-ichiro itojun Hagino #ifdef INET 117cfa1ca9dSYoshinobu Inoue case AF_INET: 118cfa1ca9dSYoshinobu Inoue { 119cfa1ca9dSYoshinobu Inoue struct ip *ip; 120cfa1ca9dSYoshinobu Inoue 121cfa1ca9dSYoshinobu Inoue proto = IPPROTO_IPV4; 122cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip)) { 123cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip)); 124cfa1ca9dSYoshinobu Inoue if (!m) 125cfa1ca9dSYoshinobu Inoue return ENOBUFS; 126cfa1ca9dSYoshinobu Inoue } 127cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 128cfa1ca9dSYoshinobu Inoue tos = ip->ip_tos; 129cfa1ca9dSYoshinobu Inoue break; 130cfa1ca9dSYoshinobu Inoue } 131686cdd19SJun-ichiro itojun Hagino #endif /* INET */ 132cfa1ca9dSYoshinobu Inoue #ifdef INET6 133cfa1ca9dSYoshinobu Inoue case AF_INET6: 134cfa1ca9dSYoshinobu Inoue { 135686cdd19SJun-ichiro itojun Hagino struct ip6_hdr *ip6; 136cfa1ca9dSYoshinobu Inoue proto = IPPROTO_IPV6; 137cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip6)) { 138cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip6)); 139cfa1ca9dSYoshinobu Inoue if (!m) 140cfa1ca9dSYoshinobu Inoue return ENOBUFS; 141cfa1ca9dSYoshinobu Inoue } 142cfa1ca9dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 143cfa1ca9dSYoshinobu Inoue tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 144cfa1ca9dSYoshinobu Inoue break; 145cfa1ca9dSYoshinobu Inoue } 146cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 14773ff045cSAndrew Thompson case AF_LINK: 14873ff045cSAndrew Thompson proto = IPPROTO_ETHERIP; 149dbe59260SHiroki Sato 150dbe59260SHiroki Sato /* 151dbe59260SHiroki Sato * GIF_SEND_REVETHIP (disabled by default) intentionally 152dbe59260SHiroki Sato * sends an EtherIP packet with revered version field in 153dbe59260SHiroki Sato * the header. This is a knob for backward compatibility 154dbe59260SHiroki Sato * with FreeBSD 7.2R or prior. 155dbe59260SHiroki Sato */ 156dbe59260SHiroki Sato if ((sc->gif_options & GIF_SEND_REVETHIP)) { 157dbe59260SHiroki Sato eiphdr.eip_ver = 0; 158dbe59260SHiroki Sato eiphdr.eip_resvl = ETHERIP_VERSION; 159dbe59260SHiroki Sato eiphdr.eip_resvh = 0; 160dbe59260SHiroki Sato } else { 161dbe59260SHiroki Sato eiphdr.eip_ver = ETHERIP_VERSION; 162dbe59260SHiroki Sato eiphdr.eip_resvl = 0; 163dbe59260SHiroki Sato eiphdr.eip_resvh = 0; 164dbe59260SHiroki Sato } 16573ff045cSAndrew Thompson /* prepend Ethernet-in-IP header */ 166eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT); 16773ff045cSAndrew Thompson if (m && m->m_len < sizeof(struct etherip_header)) 16873ff045cSAndrew Thompson m = m_pullup(m, sizeof(struct etherip_header)); 16973ff045cSAndrew Thompson if (m == NULL) 17073ff045cSAndrew Thompson return ENOBUFS; 17173ff045cSAndrew Thompson bcopy(&eiphdr, mtod(m, struct etherip_header *), 17273ff045cSAndrew Thompson sizeof(struct etherip_header)); 17373ff045cSAndrew Thompson break; 17473ff045cSAndrew Thompson 175cfa1ca9dSYoshinobu Inoue default: 176686cdd19SJun-ichiro itojun Hagino #ifdef DEBUG 177cfa1ca9dSYoshinobu Inoue printf("in_gif_output: warning: unknown family %d passed\n", 178cfa1ca9dSYoshinobu Inoue family); 179cfa1ca9dSYoshinobu Inoue #endif 180cfa1ca9dSYoshinobu Inoue m_freem(m); 181cfa1ca9dSYoshinobu Inoue return EAFNOSUPPORT; 182cfa1ca9dSYoshinobu Inoue } 183cfa1ca9dSYoshinobu Inoue 184cfa1ca9dSYoshinobu Inoue bzero(&iphdr, sizeof(iphdr)); 185cfa1ca9dSYoshinobu Inoue iphdr.ip_src = sin_src->sin_addr; 186cfa1ca9dSYoshinobu Inoue /* bidirectional configured tunnel mode */ 187cfa1ca9dSYoshinobu Inoue if (sin_dst->sin_addr.s_addr != INADDR_ANY) 188cfa1ca9dSYoshinobu Inoue iphdr.ip_dst = sin_dst->sin_addr; 189cfa1ca9dSYoshinobu Inoue else { 190cfa1ca9dSYoshinobu Inoue m_freem(m); 191cfa1ca9dSYoshinobu Inoue return ENETUNREACH; 192cfa1ca9dSYoshinobu Inoue } 193cfa1ca9dSYoshinobu Inoue iphdr.ip_p = proto; 194cfa1ca9dSYoshinobu Inoue /* version will be set in ip_output() */ 195603724d3SBjoern A. Zeeb iphdr.ip_ttl = V_ip_gif_ttl; 1968f134647SGleb Smirnoff iphdr.ip_len = htons(m->m_pkthdr.len + sizeof(struct ip)); 19759dfcba4SHajimu UMEMOTO ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, 19859dfcba4SHajimu UMEMOTO &iphdr.ip_tos, &tos); 199cfa1ca9dSYoshinobu Inoue 200cfa1ca9dSYoshinobu Inoue /* prepend new IP header */ 201c89c8a10SMarius Strobl len = sizeof(struct ip); 202c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 203c89c8a10SMarius Strobl if (family == AF_LINK) 204c89c8a10SMarius Strobl len += ETHERIP_ALIGN; 205c89c8a10SMarius Strobl #endif 206eb1b1807SGleb Smirnoff M_PREPEND(m, len, M_NOWAIT); 207c89c8a10SMarius Strobl if (m != NULL && m->m_len < len) 208c89c8a10SMarius Strobl m = m_pullup(m, len); 209cfa1ca9dSYoshinobu Inoue if (m == NULL) { 210cfa1ca9dSYoshinobu Inoue printf("ENOBUFS in in_gif_output %d\n", __LINE__); 211cfa1ca9dSYoshinobu Inoue return ENOBUFS; 212cfa1ca9dSYoshinobu Inoue } 213c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 214c89c8a10SMarius Strobl if (family == AF_LINK) { 215c89c8a10SMarius Strobl len = mtod(m, vm_offset_t) & 3; 216c89c8a10SMarius Strobl KASSERT(len == 0 || len == ETHERIP_ALIGN, 217c89c8a10SMarius Strobl ("in_gif_output: unexpected misalignment")); 218c89c8a10SMarius Strobl m->m_data += len; 219c89c8a10SMarius Strobl m->m_len -= ETHERIP_ALIGN; 220c89c8a10SMarius Strobl } 221c89c8a10SMarius Strobl #endif 222686cdd19SJun-ichiro itojun Hagino bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 223cfa1ca9dSYoshinobu Inoue 2248b07e49aSJulian Elischer M_SETFIB(m, sc->gif_fibnum); 2258b07e49aSJulian Elischer 226cfa1ca9dSYoshinobu Inoue if (dst->sin_family != sin_dst->sin_family || 227cfa1ca9dSYoshinobu Inoue dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { 228cfa1ca9dSYoshinobu Inoue /* cache route doesn't match */ 22927de0135SBruce M Simpson bzero(dst, sizeof(*dst)); 230cfa1ca9dSYoshinobu Inoue dst->sin_family = sin_dst->sin_family; 231cfa1ca9dSYoshinobu Inoue dst->sin_len = sizeof(struct sockaddr_in); 232cfa1ca9dSYoshinobu Inoue dst->sin_addr = sin_dst->sin_addr; 233cfa1ca9dSYoshinobu Inoue if (sc->gif_ro.ro_rt) { 234cfa1ca9dSYoshinobu Inoue RTFREE(sc->gif_ro.ro_rt); 235cfa1ca9dSYoshinobu Inoue sc->gif_ro.ro_rt = NULL; 236cfa1ca9dSYoshinobu Inoue } 237686cdd19SJun-ichiro itojun Hagino #if 0 238fc74a9f9SBrooks Davis GIF2IFP(sc)->if_mtu = GIF_MTU; 239686cdd19SJun-ichiro itojun Hagino #endif 240cfa1ca9dSYoshinobu Inoue } 241cfa1ca9dSYoshinobu Inoue 242cfa1ca9dSYoshinobu Inoue if (sc->gif_ro.ro_rt == NULL) { 2438b07e49aSJulian Elischer in_rtalloc_ign(&sc->gif_ro, 0, sc->gif_fibnum); 244cfa1ca9dSYoshinobu Inoue if (sc->gif_ro.ro_rt == NULL) { 245cfa1ca9dSYoshinobu Inoue m_freem(m); 246cfa1ca9dSYoshinobu Inoue return ENETUNREACH; 247cfa1ca9dSYoshinobu Inoue } 248686cdd19SJun-ichiro itojun Hagino 249686cdd19SJun-ichiro itojun Hagino /* if it constitutes infinite encapsulation, punt. */ 250686cdd19SJun-ichiro itojun Hagino if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 251686cdd19SJun-ichiro itojun Hagino m_freem(m); 252686cdd19SJun-ichiro itojun Hagino return ENETUNREACH; /* XXX */ 253686cdd19SJun-ichiro itojun Hagino } 254686cdd19SJun-ichiro itojun Hagino #if 0 255686cdd19SJun-ichiro itojun Hagino ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 256686cdd19SJun-ichiro itojun Hagino - sizeof(struct ip); 257686cdd19SJun-ichiro itojun Hagino #endif 258cfa1ca9dSYoshinobu Inoue } 259cfa1ca9dSYoshinobu Inoue 2605d846453SSam Leffler error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); 26198335aa9SGleb Smirnoff 262fc74a9f9SBrooks Davis if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && 2635e5da865SGleb Smirnoff sc->gif_ro.ro_rt != NULL) { 26498335aa9SGleb Smirnoff RTFREE(sc->gif_ro.ro_rt); 26598335aa9SGleb Smirnoff sc->gif_ro.ro_rt = NULL; 26698335aa9SGleb Smirnoff } 26798335aa9SGleb Smirnoff 268cfa1ca9dSYoshinobu Inoue return (error); 269cfa1ca9dSYoshinobu Inoue } 270cfa1ca9dSYoshinobu Inoue 271cfa1ca9dSYoshinobu Inoue void 272f2565d68SRobert Watson in_gif_input(struct mbuf *m, int off) 273cfa1ca9dSYoshinobu Inoue { 274cfa1ca9dSYoshinobu Inoue struct ifnet *gifp = NULL; 27567df9f38SBjoern A. Zeeb struct gif_softc *sc; 276cfa1ca9dSYoshinobu Inoue struct ip *ip; 277686cdd19SJun-ichiro itojun Hagino int af; 2786a800098SYoshinobu Inoue u_int8_t otos; 279f0ffb944SJulian Elischer int proto; 280cfa1ca9dSYoshinobu Inoue 281cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 282f0ffb944SJulian Elischer proto = ip->ip_p; 283cfa1ca9dSYoshinobu Inoue 28467df9f38SBjoern A. Zeeb sc = (struct gif_softc *)encap_getarg(m); 28567df9f38SBjoern A. Zeeb if (sc == NULL) { 28667df9f38SBjoern A. Zeeb m_freem(m); 287315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 28867df9f38SBjoern A. Zeeb return; 28967df9f38SBjoern A. Zeeb } 290cfa1ca9dSYoshinobu Inoue 29167df9f38SBjoern A. Zeeb gifp = GIF2IFP(sc); 292686cdd19SJun-ichiro itojun Hagino if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 293cfa1ca9dSYoshinobu Inoue m_freem(m); 294315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 295cfa1ca9dSYoshinobu Inoue return; 296cfa1ca9dSYoshinobu Inoue } 297cfa1ca9dSYoshinobu Inoue 2986a800098SYoshinobu Inoue otos = ip->ip_tos; 299cfa1ca9dSYoshinobu Inoue m_adj(m, off); 300cfa1ca9dSYoshinobu Inoue 301cfa1ca9dSYoshinobu Inoue switch (proto) { 302686cdd19SJun-ichiro itojun Hagino #ifdef INET 303cfa1ca9dSYoshinobu Inoue case IPPROTO_IPV4: 304cfa1ca9dSYoshinobu Inoue { 305cfa1ca9dSYoshinobu Inoue struct ip *ip; 306cfa1ca9dSYoshinobu Inoue af = AF_INET; 307cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip)) { 308cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip)); 309cfa1ca9dSYoshinobu Inoue if (!m) 310cfa1ca9dSYoshinobu Inoue return; 311cfa1ca9dSYoshinobu Inoue } 312cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 31359dfcba4SHajimu UMEMOTO if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 31459dfcba4SHajimu UMEMOTO ECN_ALLOWED : ECN_NOCARE, 31559dfcba4SHajimu UMEMOTO &otos, &ip->ip_tos) == 0) { 31659dfcba4SHajimu UMEMOTO m_freem(m); 31759dfcba4SHajimu UMEMOTO return; 31859dfcba4SHajimu UMEMOTO } 319cfa1ca9dSYoshinobu Inoue break; 320cfa1ca9dSYoshinobu Inoue } 321686cdd19SJun-ichiro itojun Hagino #endif 322cfa1ca9dSYoshinobu Inoue #ifdef INET6 323cfa1ca9dSYoshinobu Inoue case IPPROTO_IPV6: 324cfa1ca9dSYoshinobu Inoue { 325cfa1ca9dSYoshinobu Inoue struct ip6_hdr *ip6; 32659dfcba4SHajimu UMEMOTO u_int8_t itos, oitos; 32759dfcba4SHajimu UMEMOTO 328cfa1ca9dSYoshinobu Inoue af = AF_INET6; 329cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip6)) { 330cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip6)); 331cfa1ca9dSYoshinobu Inoue if (!m) 332cfa1ca9dSYoshinobu Inoue return; 333cfa1ca9dSYoshinobu Inoue } 334cfa1ca9dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 33559dfcba4SHajimu UMEMOTO itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 33659dfcba4SHajimu UMEMOTO if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 33759dfcba4SHajimu UMEMOTO ECN_ALLOWED : ECN_NOCARE, 33859dfcba4SHajimu UMEMOTO &otos, &itos) == 0) { 33959dfcba4SHajimu UMEMOTO m_freem(m); 34059dfcba4SHajimu UMEMOTO return; 34159dfcba4SHajimu UMEMOTO } 34259dfcba4SHajimu UMEMOTO if (itos != oitos) { 343cfa1ca9dSYoshinobu Inoue ip6->ip6_flow &= ~htonl(0xff << 20); 3446a800098SYoshinobu Inoue ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 34559dfcba4SHajimu UMEMOTO } 346cfa1ca9dSYoshinobu Inoue break; 347cfa1ca9dSYoshinobu Inoue } 348cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 34973ff045cSAndrew Thompson case IPPROTO_ETHERIP: 35073ff045cSAndrew Thompson af = AF_LINK; 35173ff045cSAndrew Thompson break; 35273ff045cSAndrew Thompson 353cfa1ca9dSYoshinobu Inoue default: 354315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 355cfa1ca9dSYoshinobu Inoue m_freem(m); 356cfa1ca9dSYoshinobu Inoue return; 357cfa1ca9dSYoshinobu Inoue } 358cfa1ca9dSYoshinobu Inoue gif_input(m, af, gifp); 359cfa1ca9dSYoshinobu Inoue return; 360cfa1ca9dSYoshinobu Inoue } 361686cdd19SJun-ichiro itojun Hagino 362686cdd19SJun-ichiro itojun Hagino /* 3639426aedfSHajimu UMEMOTO * validate outer address. 364686cdd19SJun-ichiro itojun Hagino */ 3659426aedfSHajimu UMEMOTO static int 366f2565d68SRobert Watson gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) 3679426aedfSHajimu UMEMOTO { 368686cdd19SJun-ichiro itojun Hagino struct sockaddr_in *src, *dst; 369686cdd19SJun-ichiro itojun Hagino struct in_ifaddr *ia4; 370686cdd19SJun-ichiro itojun Hagino 371686cdd19SJun-ichiro itojun Hagino src = (struct sockaddr_in *)sc->gif_psrc; 372686cdd19SJun-ichiro itojun Hagino dst = (struct sockaddr_in *)sc->gif_pdst; 373686cdd19SJun-ichiro itojun Hagino 374686cdd19SJun-ichiro itojun Hagino /* check for address match */ 3759426aedfSHajimu UMEMOTO if (src->sin_addr.s_addr != ip->ip_dst.s_addr || 3769426aedfSHajimu UMEMOTO dst->sin_addr.s_addr != ip->ip_src.s_addr) 377686cdd19SJun-ichiro itojun Hagino return 0; 378686cdd19SJun-ichiro itojun Hagino 379686cdd19SJun-ichiro itojun Hagino /* martian filters on outer source - NOT done in ip_input! */ 3809426aedfSHajimu UMEMOTO if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 381686cdd19SJun-ichiro itojun Hagino return 0; 3829426aedfSHajimu UMEMOTO switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 383686cdd19SJun-ichiro itojun Hagino case 0: case 127: case 255: 384686cdd19SJun-ichiro itojun Hagino return 0; 385686cdd19SJun-ichiro itojun Hagino } 3862d9cfabaSRobert Watson 387686cdd19SJun-ichiro itojun Hagino /* reject packets with broadcast on source */ 3882d9cfabaSRobert Watson /* XXXRW: should use hash lists? */ 3892d9cfabaSRobert Watson IN_IFADDR_RLOCK(); 390603724d3SBjoern A. Zeeb TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { 391686cdd19SJun-ichiro itojun Hagino if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 392686cdd19SJun-ichiro itojun Hagino continue; 3932d9cfabaSRobert Watson if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { 3942d9cfabaSRobert Watson IN_IFADDR_RUNLOCK(); 395686cdd19SJun-ichiro itojun Hagino return 0; 396686cdd19SJun-ichiro itojun Hagino } 3972d9cfabaSRobert Watson } 3982d9cfabaSRobert Watson IN_IFADDR_RUNLOCK(); 399686cdd19SJun-ichiro itojun Hagino 400686cdd19SJun-ichiro itojun Hagino /* ingress filters on outer source */ 401fc74a9f9SBrooks Davis if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 402686cdd19SJun-ichiro itojun Hagino struct sockaddr_in sin; 403686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 404686cdd19SJun-ichiro itojun Hagino 405686cdd19SJun-ichiro itojun Hagino bzero(&sin, sizeof(sin)); 406686cdd19SJun-ichiro itojun Hagino sin.sin_family = AF_INET; 407686cdd19SJun-ichiro itojun Hagino sin.sin_len = sizeof(struct sockaddr_in); 4089426aedfSHajimu UMEMOTO sin.sin_addr = ip->ip_src; 4098b07e49aSJulian Elischer /* XXX MRT check for the interface we would use on output */ 4108b07e49aSJulian Elischer rt = in_rtalloc1((struct sockaddr *)&sin, 0, 4118b07e49aSJulian Elischer 0UL, sc->gif_fibnum); 4129426aedfSHajimu UMEMOTO if (!rt || rt->rt_ifp != ifp) { 41333841545SHajimu UMEMOTO #if 0 41433841545SHajimu UMEMOTO log(LOG_WARNING, "%s: packet from 0x%x dropped " 415fc74a9f9SBrooks Davis "due to ingress filter\n", if_name(GIF2IFP(sc)), 41633841545SHajimu UMEMOTO (u_int32_t)ntohl(sin.sin_addr.s_addr)); 41733841545SHajimu UMEMOTO #endif 41833841545SHajimu UMEMOTO if (rt) 419bc60490aSChristian S.J. Peron RTFREE_LOCKED(rt); 420686cdd19SJun-ichiro itojun Hagino return 0; 421686cdd19SJun-ichiro itojun Hagino } 422bc60490aSChristian S.J. Peron RTFREE_LOCKED(rt); 423686cdd19SJun-ichiro itojun Hagino } 424686cdd19SJun-ichiro itojun Hagino 42533841545SHajimu UMEMOTO return 32 * 2; 426686cdd19SJun-ichiro itojun Hagino } 4279426aedfSHajimu UMEMOTO 4289426aedfSHajimu UMEMOTO /* 4299426aedfSHajimu UMEMOTO * we know that we are in IFF_UP, outer address available, and outer family 4309426aedfSHajimu UMEMOTO * matched the physical addr family. see gif_encapcheck(). 4319426aedfSHajimu UMEMOTO */ 4329426aedfSHajimu UMEMOTO int 433f2565d68SRobert Watson gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg) 4349426aedfSHajimu UMEMOTO { 4359426aedfSHajimu UMEMOTO struct ip ip; 4369426aedfSHajimu UMEMOTO struct gif_softc *sc; 4379426aedfSHajimu UMEMOTO struct ifnet *ifp; 4389426aedfSHajimu UMEMOTO 4399426aedfSHajimu UMEMOTO /* sanity check done in caller */ 4409426aedfSHajimu UMEMOTO sc = (struct gif_softc *)arg; 4419426aedfSHajimu UMEMOTO 4429426aedfSHajimu UMEMOTO /* LINTED const cast */ 4439426aedfSHajimu UMEMOTO m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 4449426aedfSHajimu UMEMOTO ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 4459426aedfSHajimu UMEMOTO 4469426aedfSHajimu UMEMOTO return gif_validate4(&ip, sc, ifp); 4479426aedfSHajimu UMEMOTO } 4489426aedfSHajimu UMEMOTO 4499426aedfSHajimu UMEMOTO int 450f2565d68SRobert Watson in_gif_attach(struct gif_softc *sc) 4519426aedfSHajimu UMEMOTO { 4529426aedfSHajimu UMEMOTO sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, 4539426aedfSHajimu UMEMOTO &in_gif_protosw, sc); 4549426aedfSHajimu UMEMOTO if (sc->encap_cookie4 == NULL) 4559426aedfSHajimu UMEMOTO return EEXIST; 4569426aedfSHajimu UMEMOTO return 0; 4579426aedfSHajimu UMEMOTO } 4589426aedfSHajimu UMEMOTO 4599426aedfSHajimu UMEMOTO int 460f2565d68SRobert Watson in_gif_detach(struct gif_softc *sc) 4619426aedfSHajimu UMEMOTO { 4629426aedfSHajimu UMEMOTO int error; 4639426aedfSHajimu UMEMOTO 4649426aedfSHajimu UMEMOTO error = encap_detach(sc->encap_cookie4); 4659426aedfSHajimu UMEMOTO if (error == 0) 4669426aedfSHajimu UMEMOTO sc->encap_cookie4 = NULL; 4679426aedfSHajimu UMEMOTO return error; 4689426aedfSHajimu UMEMOTO } 469