if_stf.c revision 62587
1285163Sdim/* $FreeBSD: head/sys/net/if_stf.c 62587 2000-07-04 16:35:15Z itojun $ */ 2285163Sdim/* $KAME: if_stf.c,v 1.40 2000/06/20 19:44:42 itojun Exp $ */ 3285163Sdim 4285163Sdim/* 5285163Sdim * Copyright (C) 2000 WIDE Project. 6285163Sdim * All rights reserved. 7285163Sdim * 8285163Sdim * Redistribution and use in source and binary forms, with or without 9285163Sdim * modification, are permitted provided that the following conditions 10285163Sdim * are met: 11285163Sdim * 1. Redistributions of source code must retain the above copyright 12285163Sdim * notice, this list of conditions and the following disclaimer. 13285163Sdim * 2. Redistributions in binary form must reproduce the above copyright 14285163Sdim * notice, this list of conditions and the following disclaimer in the 15296417Sdim * documentation and/or other materials provided with the distribution. 16286684Sdim * 3. Neither the name of the project nor the names of its contributors 17285163Sdim * may be used to endorse or promote products derived from this software 18285163Sdim * without specific prior written permission. 19285163Sdim * 20285163Sdim * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21285163Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22285163Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23285163Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24285163Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25285163Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26285163Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27285163Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28285163Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29285163Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30285163Sdim * SUCH DAMAGE. 31285163Sdim */ 32285163Sdim 33285163Sdim/* 34285163Sdim * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt. 35285163Sdim * 36285163Sdim * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting. 37285163Sdim * There is no address mapping defined from IPv6 multicast address to IPv4 38285163Sdim * address. Therefore, we do not have IFF_MULTICAST on the interface. 39285163Sdim * 40285163Sdim * Due to the lack of address mapping for link-local addresses, we cannot 41285163Sdim * throw packets toward link-local addresses (fe80::x). Also, we cannot throw 42285163Sdim * packets to link-local multicast addresses (ff02::x). 43285163Sdim * 44285163Sdim * Here are interesting symptoms due to the lack of link-local address: 45285163Sdim * 46285163Sdim * Unicast routing exchange: 47285163Sdim * - RIPng: Impossible. Uses link-local multicast packet toward ff02::9, 48285163Sdim * and link-local addresses as nexthop. 49285163Sdim * - OSPFv6: Impossible. OSPFv6 assumes that there's link-local address 50285163Sdim * assigned to the link, and makes use of them. Also, HELLO packets use 51285163Sdim * link-local multicast addresses (ff02::5 and ff02::6). 52285163Sdim * - BGP4+: Maybe. You can only use global address as nexthop, and global 53285163Sdim * address as TCP endpoint address. 54285163Sdim * 55285163Sdim * Multicast routing protocols: 56285163Sdim * - PIM: Hello packet cannot be used to discover adjacent PIM routers. 57285163Sdim * Adjacent PIM routers must be configured manually (is it really spec-wise 58296417Sdim * correct thing to do?). 59296417Sdim * 60296417Sdim * ICMPv6: 61296417Sdim * - Redirects cannot be used due to the lack of link-local address. 62296417Sdim * 63296417Sdim * Starting from 04 draft, the specification suggests how to construct 64296417Sdim * link-local address for 6to4 interface. 65296417Sdim * However, it seems to have no real use and does not help the above symptom 66296417Sdim * much. Even if we assign link-locals to interface, we cannot really 67296417Sdim * use link-local unicast/multicast on top of 6to4 cloud, and the above 68296417Sdim * analysis does not change. 69296417Sdim * 70296417Sdim * 6to4 interface has security issues. Refer to 71296417Sdim * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt 72296417Sdim * for details. The code tries to filter out some of malicious packets. 73296417Sdim * Note that there is no way to be 100% secure. 74296417Sdim */ 75296417Sdim 76296417Sdim#include "opt_inet.h" 77296417Sdim#include "opt_inet6.h" 78296417Sdim 79296417Sdim#include <sys/param.h> 80285163Sdim#include <sys/systm.h> 81285163Sdim#include <sys/socket.h> 82296417Sdim#include <sys/sockio.h> 83285163Sdim#include <sys/mbuf.h> 84285163Sdim#include <sys/errno.h> 85285163Sdim#include <sys/protosw.h> 86285163Sdim#include <sys/kernel.h> 87296417Sdim#include <machine/cpu.h> 88296417Sdim 89296417Sdim#include <sys/malloc.h> 90296417Sdim 91296417Sdim#include <net/if.h> 92296417Sdim#include <net/route.h> 93296417Sdim#include <net/netisr.h> 94296417Sdim#include <net/if_types.h> 95296417Sdim#include <net/if_stf.h> 96296417Sdim 97296417Sdim#include <netinet/in.h> 98296417Sdim#include <netinet/in_systm.h> 99296417Sdim#include <netinet/ip.h> 100285163Sdim#include <netinet/ip_var.h> 101296417Sdim#include <netinet/in_var.h> 102296417Sdim 103285163Sdim#include <netinet/ip6.h> 104285163Sdim#include <netinet6/ip6_var.h> 105296417Sdim#include <netinet6/in6_gif.h> 106296417Sdim#include <netinet6/in6_var.h> 107296417Sdim#include <netinet/ip_ecn.h> 108296417Sdim 109296417Sdim#include <netinet/ip_encap.h> 110296417Sdim 111296417Sdim#include <machine/stdarg.h> 112296417Sdim 113296417Sdim#include <net/net_osdep.h> 114296417Sdim 115296417Sdim#include "bpf.h" 116296417Sdim#define NBPFILTER NBPF 117296417Sdim#include "stf.h" 118296417Sdim#include "gif.h" /*XXX*/ 119296417Sdim 120296417Sdim#if NBPFILTER > 0 121296417Sdim#include <net/bpf.h> 122296417Sdim#endif 123296417Sdim 124296417Sdim#if NGIF > 0 125296417Sdim#include <net/if_gif.h> 126296417Sdim#endif 127296417Sdim 128296417Sdim#if NSTF > 0 129296417Sdim#if NSTF != 1 130296417Sdim# error only single stf interface allowed 131296417Sdim#endif 132296417Sdim 133296417Sdim#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002) 134296417Sdim#define GET_V4(x) ((struct in_addr *)(&(x)->s6_addr16[1])) 135296417Sdim 136296417Sdimstruct stf_softc { 137296417Sdim struct ifnet sc_if; /* common area */ 138296417Sdim union { 139296417Sdim struct route __sc_ro4; 140296417Sdim struct route_in6 __sc_ro6; /* just for safety */ 141296417Sdim } __sc_ro46; 142296417Sdim#define sc_ro __sc_ro46.__sc_ro4 143296417Sdim const struct encaptab *encap_cookie; 144296417Sdim}; 145296417Sdim 146296417Sdimstatic struct stf_softc *stf; 147296417Sdimstatic int nstf; 148296417Sdim 149296417Sdim#if NGIF > 0 150296417Sdimextern int ip_gif_ttl; /*XXX*/ 151296417Sdim#else 152296417Sdimstatic int ip_gif_ttl = 40; /*XXX*/ 153296417Sdim#endif 154296417Sdim 155296417Sdimextern struct protosw in_stf_protosw; 156296417Sdim 157296417Sdimvoid stfattach __P((void *)); 158296417Sdimstatic int stf_encapcheck __P((const struct mbuf *, int, int, void *)); 159296417Sdimstatic struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *)); 160296417Sdimstatic int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, 161296417Sdim struct rtentry *)); 162296417Sdimstatic int stf_checkaddr4 __P((struct in_addr *, struct ifnet *)); 163296417Sdimstatic int stf_checkaddr6 __P((struct in6_addr *, struct ifnet *)); 164296417Sdimstatic void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *)); 165296417Sdimstatic int stf_ioctl __P((struct ifnet *, u_long, caddr_t)); 166296417Sdim 167296417Sdimvoid 168296417Sdimstfattach(dummy) 169296417Sdim void *dummy; 170296417Sdim{ 171296417Sdim struct stf_softc *sc; 172296417Sdim int i; 173296417Sdim const struct encaptab *p; 174296417Sdim 175296417Sdim nstf = NSTF; 176296417Sdim stf = malloc(nstf * sizeof(struct stf_softc), M_DEVBUF, M_WAIT); 177296417Sdim bzero(stf, nstf * sizeof(struct stf_softc)); 178296417Sdim sc = stf; 179296417Sdim 180296417Sdim /* XXX just in case... */ 181296417Sdim for (i = 0; i < nstf; i++) { 182296417Sdim sc = &stf[i]; 183296417Sdim bzero(sc, sizeof(*sc)); 184296417Sdim sc->sc_if.if_name = "stf"; 185296417Sdim sc->sc_if.if_unit = i; 186286684Sdim 187286684Sdim p = encap_attach_func(AF_INET, IPPROTO_IPV6, stf_encapcheck, 188286684Sdim &in_stf_protosw, sc); 189286684Sdim if (p == NULL) { 190286684Sdim printf("%s: attach failed\n", if_name(&sc->sc_if)); 191296417Sdim continue; 192286684Sdim } 193286684Sdim sc->encap_cookie = p; 194286684Sdim 195296417Sdim sc->sc_if.if_mtu = IPV6_MMTU; 196296417Sdim sc->sc_if.if_flags = 0; 197296417Sdim sc->sc_if.if_ioctl = stf_ioctl; 198296417Sdim sc->sc_if.if_output = stf_output; 199296417Sdim sc->sc_if.if_type = IFT_STF; 200296417Sdim sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 201296417Sdim if_attach(&sc->sc_if); 202296417Sdim#if NBPFILTER > 0 203296417Sdim#ifdef HAVE_OLD_BPF 204296417Sdim bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int)); 205296417Sdim#else 206296417Sdim bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int)); 207296417Sdim#endif 208296417Sdim#endif 209296417Sdim } 210296417Sdim} 211296417Sdim 212296417SdimPSEUDO_SET(stfattach, if_stf); 213296417Sdim 214296417Sdimstatic int 215296417Sdimstf_encapcheck(m, off, proto, arg) 216296417Sdim const struct mbuf *m; 217296417Sdim int off; 218296417Sdim int proto; 219296417Sdim void *arg; 220296417Sdim{ 221296417Sdim struct ip ip; 222296417Sdim struct in6_ifaddr *ia6; 223296417Sdim struct stf_softc *sc; 224296417Sdim struct in_addr a, b; 225296417Sdim 226296417Sdim sc = (struct stf_softc *)arg; 227296417Sdim if (sc == NULL) 228296417Sdim return 0; 229286684Sdim 230286684Sdim if ((sc->sc_if.if_flags & IFF_UP) == 0) 231286684Sdim return 0; 232285163Sdim 233296417Sdim if (proto != IPPROTO_IPV6) 234285163Sdim return 0; 235285163Sdim 236285163Sdim /* LINTED const cast */ 237285163Sdim m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); 238285163Sdim 239296417Sdim if (ip.ip_v != 4) 240296417Sdim return 0; 241285163Sdim 242285163Sdim ia6 = stf_getsrcifa6(&sc->sc_if); 243285163Sdim if (ia6 == NULL) 244285163Sdim return 0; 245285163Sdim 246285163Sdim /* 247296417Sdim * check if IPv4 dst matches the IPv4 address derived from the 248296417Sdim * local 6to4 address. 249285163Sdim * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:... 250285163Sdim */ 251296417Sdim if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst, 252296417Sdim sizeof(ip.ip_dst)) != 0) 253285163Sdim return 0; 254296417Sdim 255285163Sdim /* 256285163Sdim * check if IPv4 src matches the IPv4 address derived from the 257285163Sdim * local 6to4 address masked by prefixmask. 258285163Sdim * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24 259285163Sdim * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24 260285163Sdim */ 261285163Sdim bzero(&a, sizeof(a)); 262296417Sdim a.s_addr = GET_V4(&ia6->ia_addr.sin6_addr)->s_addr; 263285163Sdim a.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr; 264285163Sdim b = ip.ip_src; 265285163Sdim b.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr; 266285163Sdim if (a.s_addr != b.s_addr) 267285163Sdim return 0; 268285163Sdim 269296417Sdim /* stf interface makes single side match only */ 270296417Sdim return 32; 271296417Sdim} 272296417Sdim 273296417Sdimstatic struct in6_ifaddr * 274285163Sdimstf_getsrcifa6(ifp) 275285163Sdim struct ifnet *ifp; 276285163Sdim{ 277296417Sdim struct ifaddr *ia; 278296417Sdim struct in_ifaddr *ia4; 279296417Sdim struct sockaddr_in6 *sin6; 280296417Sdim struct in_addr in; 281296417Sdim 282296417Sdim for (ia = ifp->if_addrlist.tqh_first; 283296417Sdim ia; 284296417Sdim ia = ia->ifa_list.tqe_next) 285296417Sdim { 286296417Sdim if (ia->ifa_addr == NULL) 287296417Sdim continue; 288296417Sdim if (ia->ifa_addr->sa_family != AF_INET6) 289296417Sdim continue; 290296417Sdim sin6 = (struct sockaddr_in6 *)ia->ifa_addr; 291296417Sdim if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) 292296417Sdim continue; 293296417Sdim 294296417Sdim bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in)); 295296417Sdim for (ia4 = TAILQ_FIRST(&in_ifaddrhead); 296296417Sdim ia4; 297296417Sdim ia4 = TAILQ_NEXT(ia4, ia_link)) 298296417Sdim { 299296417Sdim if (ia4->ia_addr.sin_addr.s_addr == in.s_addr) 300296417Sdim break; 301296417Sdim } 302296417Sdim if (ia4 == NULL) 303296417Sdim continue; 304296417Sdim 305296417Sdim return (struct in6_ifaddr *)ia; 306296417Sdim } 307296417Sdim 308296417Sdim return NULL; 309296417Sdim} 310296417Sdim 311296417Sdim#ifndef offsetof 312296417Sdim#define offsetof(s, e) ((int)&((s *)0)->e) 313296417Sdim#endif 314296417Sdim 315296417Sdimstatic int 316296417Sdimstf_output(ifp, m, dst, rt) 317296417Sdim struct ifnet *ifp; 318296417Sdim struct mbuf *m; 319296417Sdim struct sockaddr *dst; 320296417Sdim struct rtentry *rt; 321296417Sdim{ 322296417Sdim struct stf_softc *sc; 323296417Sdim struct sockaddr_in6 *dst6; 324296417Sdim struct sockaddr_in *dst4; 325296417Sdim u_int8_t tos; 326296417Sdim struct ip *ip; 327296417Sdim struct ip6_hdr *ip6; 328296417Sdim struct in6_ifaddr *ia6; 329296417Sdim 330296417Sdim sc = (struct stf_softc*)ifp; 331296417Sdim dst6 = (struct sockaddr_in6 *)dst; 332296417Sdim 333296417Sdim /* just in case */ 334296417Sdim if ((ifp->if_flags & IFF_UP) == 0) { 335296417Sdim m_freem(m); 336296417Sdim return ENETDOWN; 337296417Sdim } 338296417Sdim 339296417Sdim /* 340296417Sdim * If we don't have an ip4 address that match my inner ip6 address, 341296417Sdim * we shouldn't generate output. Without this check, we'll end up 342296417Sdim * using wrong IPv4 source. 343296417Sdim */ 344296417Sdim ia6 = stf_getsrcifa6(ifp); 345296417Sdim if (ia6 == NULL) { 346296417Sdim m_freem(m); 347296417Sdim return ENETDOWN; 348296417Sdim } 349296417Sdim 350296417Sdim if (m->m_len < sizeof(*ip6)) { 351286684Sdim m = m_pullup(m, sizeof(*ip6)); 352286684Sdim if (!m) 353286684Sdim return ENOBUFS; 354286684Sdim } 355286684Sdim ip6 = mtod(m, struct ip6_hdr *); 356286684Sdim tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 357296417Sdim 358296417Sdim M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 359286684Sdim if (m && m->m_len < sizeof(struct ip)) 360286684Sdim m = m_pullup(m, sizeof(struct ip)); 361286684Sdim if (m == NULL) 362285163Sdim return ENOBUFS; 363285163Sdim ip = mtod(m, struct ip *); 364285163Sdim 365286684Sdim bzero(ip, sizeof(*ip)); 366286684Sdim 367285163Sdim bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr), 368285163Sdim &ip->ip_src, sizeof(ip->ip_src)); 369285163Sdim bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst)); 370285163Sdim ip->ip_p = IPPROTO_IPV6; 371296417Sdim ip->ip_ttl = ip_gif_ttl; /*XXX*/ 372296417Sdim ip->ip_len = m->m_pkthdr.len; /*host order*/ 373285163Sdim if (ifp->if_flags & IFF_LINK1) 374285163Sdim ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos); 375285163Sdim 376296417Sdim dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst; 377296417Sdim if (dst4->sin_family != AF_INET || 378296417Sdim bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) { 379285163Sdim /* cache route doesn't match */ 380285163Sdim dst4->sin_family = AF_INET; 381296417Sdim dst4->sin_len = sizeof(struct sockaddr_in); 382296417Sdim bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr)); 383296417Sdim if (sc->sc_ro.ro_rt) { 384285163Sdim RTFREE(sc->sc_ro.ro_rt); 385296417Sdim sc->sc_ro.ro_rt = NULL; 386285163Sdim } 387285163Sdim } 388285163Sdim 389296417Sdim if (sc->sc_ro.ro_rt == NULL) { 390296417Sdim rtalloc(&sc->sc_ro); 391285163Sdim if (sc->sc_ro.ro_rt == NULL) { 392285163Sdim m_freem(m); 393285163Sdim return ENETUNREACH; 394296417Sdim } 395296417Sdim } 396296417Sdim 397296417Sdim return ip_output(m, NULL, &sc->sc_ro, 0, NULL); 398296417Sdim} 399296417Sdim 400296417Sdimstatic int 401296417Sdimstf_checkaddr4(in, ifp) 402296417Sdim struct in_addr *in; 403296417Sdim struct ifnet *ifp; /* incoming interface */ 404296417Sdim{ 405296417Sdim struct in_ifaddr *ia4; 406296417Sdim 407296417Sdim /* 408296417Sdim * reject packets with the following address: 409296417Sdim * 224.0.0.0/4 0.0.0.0/8 127.0.0.0/8 255.0.0.0/8 410296417Sdim */ 411296417Sdim if (IN_MULTICAST(in->s_addr)) 412296417Sdim return -1; 413296417Sdim switch ((ntohl(in->s_addr) & 0xff000000) >> 24) { 414296417Sdim case 0: case 127: case 255: 415296417Sdim return -1; 416296417Sdim } 417296417Sdim 418296417Sdim /* 419296417Sdim * reject packets with broadcast 420296417Sdim */ 421296417Sdim for (ia4 = TAILQ_FIRST(&in_ifaddrhead); 422296417Sdim ia4; 423296417Sdim ia4 = TAILQ_NEXT(ia4, ia_link)) 424296417Sdim { 425296417Sdim if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 426296417Sdim continue; 427296417Sdim if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) 428296417Sdim return -1; 429296417Sdim } 430296417Sdim 431296417Sdim /* 432296417Sdim * perform ingress filter 433296417Sdim */ 434296417Sdim if (ifp) { 435296417Sdim struct sockaddr_in sin; 436296417Sdim struct rtentry *rt; 437285163Sdim 438285163Sdim bzero(&sin, sizeof(sin)); 439285163Sdim sin.sin_family = AF_INET; 440285163Sdim sin.sin_len = sizeof(struct sockaddr_in); 441285163Sdim sin.sin_addr = *in; 442285163Sdim rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 443296417Sdim if (!rt) 444296417Sdim return -1; 445285163Sdim if (rt->rt_ifp != ifp) { 446296417Sdim rtfree(rt); 447285163Sdim return -1; 448285163Sdim } 449285163Sdim rtfree(rt); 450296417Sdim } 451296417Sdim 452296417Sdim return 0; 453296417Sdim} 454296417Sdim 455296417Sdimstatic int 456296417Sdimstf_checkaddr6(in6, ifp) 457296417Sdim struct in6_addr *in6; 458296417Sdim struct ifnet *ifp; /* incoming interface */ 459296417Sdim{ 460296417Sdim /* 461296417Sdim * check 6to4 addresses 462296417Sdim */ 463296417Sdim if (IN6_IS_ADDR_6TO4(in6)) 464296417Sdim return stf_checkaddr4(GET_V4(in6), ifp); 465296417Sdim 466296417Sdim /* 467296417Sdim * reject anything that look suspicious. the test is implemented 468296417Sdim * in ip6_input too, but we check here as well to 469296417Sdim * (1) reject bad packets earlier, and 470296417Sdim * (2) to be safe against future ip6_input change. 471296417Sdim */ 472296417Sdim if (IN6_IS_ADDR_V4COMPAT(in6) || IN6_IS_ADDR_V4MAPPED(in6)) 473296417Sdim return -1; 474296417Sdim 475296417Sdim return 0; 476296417Sdim} 477296417Sdim 478296417Sdimvoid 479296417Sdim#if __STDC__ 480285163Sdimin_stf_input(struct mbuf *m, ...) 481285163Sdim#else 482285163Sdimin_stf_input(m, va_alist) 483285163Sdim register struct mbuf *m; 484285163Sdim#endif 485285163Sdim{ 486286684Sdim int off, proto; 487286684Sdim struct stf_softc *sc; 488296417Sdim struct ip *ip; 489296417Sdim struct ip6_hdr *ip6; 490296417Sdim u_int8_t otos, itos; 491296417Sdim int s, isr; 492296417Sdim struct ifqueue *ifq = NULL; 493296417Sdim struct ifnet *ifp; 494296417Sdim va_list ap; 495296417Sdim 496296417Sdim va_start(ap, m); 497296417Sdim off = va_arg(ap, int); 498296417Sdim proto = va_arg(ap, int); 499296417Sdim va_end(ap); 500285163Sdim 501285163Sdim if (proto != IPPROTO_IPV6) { 502285163Sdim m_freem(m); 503285163Sdim return; 504285163Sdim } 505285163Sdim 506296417Sdim ip = mtod(m, struct ip *); 507296417Sdim 508296417Sdim sc = (struct stf_softc *)encap_getarg(m); 509296417Sdim 510296417Sdim if (sc == NULL || (sc->sc_if.if_flags & IFF_UP) == 0) { 511296417Sdim m_freem(m); 512296417Sdim return; 513285163Sdim } 514285163Sdim 515285163Sdim ifp = &sc->sc_if; 516296417Sdim 517296417Sdim /* 518296417Sdim * perform sanity check against outer src/dst. 519296417Sdim * for source, perform ingress filter as well. 520296417Sdim */ 521296417Sdim if (stf_checkaddr4(&ip->ip_dst, NULL) < 0 || 522296417Sdim stf_checkaddr4(&ip->ip_src, m->m_pkthdr.rcvif) < 0) { 523296417Sdim m_freem(m); 524296417Sdim return; 525285163Sdim } 526296417Sdim 527285163Sdim otos = ip->ip_tos; 528285163Sdim m_adj(m, off); 529285163Sdim 530296417Sdim if (m->m_len < sizeof(*ip6)) { 531296417Sdim m = m_pullup(m, sizeof(*ip6)); 532296417Sdim if (!m) 533296417Sdim return; 534296417Sdim } 535296417Sdim ip6 = mtod(m, struct ip6_hdr *); 536296417Sdim 537296417Sdim /* 538296417Sdim * perform sanity check against inner src/dst. 539296417Sdim * for source, perform ingress filter as well. 540296417Sdim */ 541296417Sdim if (stf_checkaddr6(&ip6->ip6_dst, NULL) < 0 || 542296417Sdim stf_checkaddr6(&ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { 543296417Sdim m_freem(m); 544296417Sdim return; 545296417Sdim } 546296417Sdim 547296417Sdim itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 548296417Sdim if ((ifp->if_flags & IFF_LINK1) != 0) 549296417Sdim ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 550296417Sdim ip6->ip6_flow &= ~htonl(0xff << 20); 551296417Sdim ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 552296417Sdim 553296417Sdim m->m_pkthdr.rcvif = ifp; 554285163Sdim 555285163Sdim#if NBPFILTER > 0 556285163Sdim if (ifp->if_bpf) { 557296417Sdim /* 558285163Sdim * We need to prepend the address family as 559296417Sdim * a four byte field. Cons up a dummy header 560285163Sdim * to pacify bpf. This is safe because bpf 561285163Sdim * will only read from the mbuf (i.e., it won't 562285163Sdim * try to free it or keep a pointer a to it). 563296417Sdim */ 564285163Sdim struct mbuf m0; 565285163Sdim u_int af = AF_INET6; 566285163Sdim 567296417Sdim m0.m_next = m; 568296417Sdim m0.m_len = 4; 569296417Sdim m0.m_data = (char *)⁡ 570296417Sdim 571296417Sdim#ifdef HAVE_OLD_BPF 572296417Sdim bpf_mtap(ifp, &m0); 573296417Sdim#else 574296417Sdim bpf_mtap(ifp->if_bpf, &m0); 575296417Sdim#endif 576296417Sdim } 577296417Sdim#endif /*NBPFILTER > 0*/ 578296417Sdim 579296417Sdim /* 580296417Sdim * Put the packet to the network layer input queue according to the 581285163Sdim * specified address family. 582285163Sdim * See net/if_gif.c for possible issues with packet processing 583296417Sdim * reorder due to extra queueing. 584285163Sdim */ 585296417Sdim ifq = &ip6intrq; 586285163Sdim isr = NETISR_IPV6; 587296417Sdim 588296417Sdim s = splimp(); 589296417Sdim if (IF_QFULL(ifq)) { 590296417Sdim IF_DROP(ifq); /* update statistics */ 591296417Sdim m_freem(m); 592296417Sdim splx(s); 593285163Sdim return; 594285163Sdim } 595296417Sdim IF_ENQUEUE(ifq, m); 596296417Sdim schednetisr(isr); 597296417Sdim ifp->if_ipackets++; 598296417Sdim ifp->if_ibytes += m->m_pkthdr.len; 599285163Sdim splx(s); 600296417Sdim} 601285163Sdim 602285163Sdim/* ARGSUSED */ 603285163Sdimstatic void 604285163Sdimstf_rtrequest(cmd, rt, sa) 605 int cmd; 606 struct rtentry *rt; 607#if defined(__bsdi__) && _BSDI_VERSION >= 199802 608 struct rt_addrinfo *sa; 609#else 610 struct sockaddr *sa; 611#endif 612{ 613 614 if (rt) 615 rt->rt_rmx.rmx_mtu = IPV6_MMTU; 616} 617 618static int 619stf_ioctl(ifp, cmd, data) 620 struct ifnet *ifp; 621 u_long cmd; 622 caddr_t data; 623{ 624 struct ifaddr *ifa; 625 struct ifreq *ifr; 626 struct sockaddr_in6 *sin6; 627 int error; 628 629 error = 0; 630 switch (cmd) { 631 case SIOCSIFADDR: 632 ifa = (struct ifaddr *)data; 633 if (ifa == NULL || ifa->ifa_addr->sa_family != AF_INET6) { 634 error = EAFNOSUPPORT; 635 break; 636 } 637 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 638 if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) { 639 ifa->ifa_rtrequest = stf_rtrequest; 640 ifp->if_flags |= IFF_UP; 641 } else 642 error = EINVAL; 643 break; 644 645 case SIOCADDMULTI: 646 case SIOCDELMULTI: 647 ifr = (struct ifreq *)data; 648 if (ifr && ifr->ifr_addr.sa_family == AF_INET6) 649 ; 650 else 651 error = EAFNOSUPPORT; 652 break; 653 654 default: 655 error = EINVAL; 656 break; 657 } 658 659 return error; 660} 661 662#endif /* NSTF > 0 */ 663