ip6_input.c revision 1.47
11.47Sitojun/* $NetBSD: ip6_input.c,v 1.47 2001/11/02 08:05:48 itojun Exp $ */ 21.40Sitojun/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ 31.3Sthorpej 41.2Sitojun/* 51.2Sitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 61.2Sitojun * All rights reserved. 71.21Sitojun * 81.2Sitojun * Redistribution and use in source and binary forms, with or without 91.2Sitojun * modification, are permitted provided that the following conditions 101.2Sitojun * are met: 111.2Sitojun * 1. Redistributions of source code must retain the above copyright 121.2Sitojun * notice, this list of conditions and the following disclaimer. 131.2Sitojun * 2. Redistributions in binary form must reproduce the above copyright 141.2Sitojun * notice, this list of conditions and the following disclaimer in the 151.2Sitojun * documentation and/or other materials provided with the distribution. 161.2Sitojun * 3. Neither the name of the project nor the names of its contributors 171.2Sitojun * may be used to endorse or promote products derived from this software 181.2Sitojun * without specific prior written permission. 191.21Sitojun * 201.2Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 211.2Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221.2Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231.2Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 241.2Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251.2Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261.2Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271.2Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281.2Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291.2Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301.2Sitojun * SUCH DAMAGE. 311.2Sitojun */ 321.2Sitojun 331.2Sitojun/* 341.2Sitojun * Copyright (c) 1982, 1986, 1988, 1993 351.2Sitojun * The Regents of the University of California. All rights reserved. 361.2Sitojun * 371.2Sitojun * Redistribution and use in source and binary forms, with or without 381.2Sitojun * modification, are permitted provided that the following conditions 391.2Sitojun * are met: 401.2Sitojun * 1. Redistributions of source code must retain the above copyright 411.2Sitojun * notice, this list of conditions and the following disclaimer. 421.2Sitojun * 2. Redistributions in binary form must reproduce the above copyright 431.2Sitojun * notice, this list of conditions and the following disclaimer in the 441.2Sitojun * documentation and/or other materials provided with the distribution. 451.2Sitojun * 3. All advertising materials mentioning features or use of this software 461.2Sitojun * must display the following acknowledgement: 471.2Sitojun * This product includes software developed by the University of 481.2Sitojun * California, Berkeley and its contributors. 491.2Sitojun * 4. Neither the name of the University nor the names of its contributors 501.2Sitojun * may be used to endorse or promote products derived from this software 511.2Sitojun * without specific prior written permission. 521.2Sitojun * 531.2Sitojun * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 541.2Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 551.2Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 561.2Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 571.2Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 581.2Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 591.2Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 601.2Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 611.2Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 621.2Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 631.2Sitojun * SUCH DAMAGE. 641.2Sitojun * 651.2Sitojun * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 661.2Sitojun */ 671.2Sitojun 681.2Sitojun#include "opt_inet.h" 691.4Sthorpej#include "opt_ipsec.h" 701.15Sdarrenr#include "opt_pfil_hooks.h" 711.2Sitojun 721.2Sitojun#include <sys/param.h> 731.2Sitojun#include <sys/systm.h> 741.2Sitojun#include <sys/malloc.h> 751.2Sitojun#include <sys/mbuf.h> 761.2Sitojun#include <sys/domain.h> 771.2Sitojun#include <sys/protosw.h> 781.2Sitojun#include <sys/socket.h> 791.2Sitojun#include <sys/socketvar.h> 801.2Sitojun#include <sys/errno.h> 811.2Sitojun#include <sys/time.h> 821.2Sitojun#include <sys/kernel.h> 831.2Sitojun#include <sys/syslog.h> 841.2Sitojun#include <sys/proc.h> 851.46Ssimonb#include <sys/sysctl.h> 861.2Sitojun 871.2Sitojun#include <net/if.h> 881.2Sitojun#include <net/if_types.h> 891.2Sitojun#include <net/if_dl.h> 901.2Sitojun#include <net/route.h> 911.2Sitojun#include <net/netisr.h> 921.15Sdarrenr#ifdef PFIL_HOOKS 931.15Sdarrenr#include <net/pfil.h> 941.15Sdarrenr#endif 951.2Sitojun 961.2Sitojun#include <netinet/in.h> 971.9Sitojun#include <netinet/in_systm.h> 981.9Sitojun#ifdef INET 991.9Sitojun#include <netinet/ip.h> 1001.9Sitojun#include <netinet/ip_icmp.h> 1011.45Sitojun#endif /* INET */ 1021.14Sitojun#include <netinet/ip6.h> 1031.2Sitojun#include <netinet6/in6_var.h> 1041.11Sitojun#include <netinet6/ip6_var.h> 1051.2Sitojun#include <netinet6/in6_pcb.h> 1061.14Sitojun#include <netinet/icmp6.h> 1071.2Sitojun#include <netinet6/in6_ifattach.h> 1081.2Sitojun#include <netinet6/nd6.h> 1091.9Sitojun#include <netinet6/in6_prefix.h> 1101.2Sitojun 1111.37Sitojun#ifdef IPSEC 1121.37Sitojun#include <netinet6/ipsec.h> 1131.37Sitojun#endif 1141.37Sitojun 1151.2Sitojun#include <netinet6/ip6protosw.h> 1161.2Sitojun 1171.2Sitojun/* we need it for NLOOP. */ 1181.2Sitojun#include "loop.h" 1191.2Sitojun#include "faith.h" 1201.2Sitojun#include "gif.h" 1211.2Sitojun#include "bpfilter.h" 1221.2Sitojun 1231.9Sitojun#include <net/net_osdep.h> 1241.9Sitojun 1251.2Sitojunextern struct domain inet6domain; 1261.2Sitojun 1271.2Sitojunu_char ip6_protox[IPPROTO_MAX]; 1281.2Sitojunstatic int ip6qmaxlen = IFQ_MAXLEN; 1291.2Sitojunstruct in6_ifaddr *in6_ifaddr; 1301.2Sitojunstruct ifqueue ip6intrq; 1311.2Sitojun 1321.2Sitojunextern struct ifnet loif[NLOOP]; 1331.2Sitojunint ip6_forward_srcrt; /* XXX */ 1341.2Sitojunint ip6_sourcecheck; /* XXX */ 1351.2Sitojunint ip6_sourcecheck_interval; /* XXX */ 1361.9Sitojun 1371.29Sthorpej#ifdef PFIL_HOOKS 1381.29Sthorpejstruct pfil_head inet6_pfil_hook; 1391.29Sthorpej#endif 1401.29Sthorpej 1411.2Sitojunstruct ip6stat ip6stat; 1421.2Sitojun 1431.2Sitojunstatic void ip6_init2 __P((void *)); 1441.2Sitojun 1451.5Sitojunstatic int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); 1461.2Sitojun 1471.2Sitojun/* 1481.2Sitojun * IP6 initialization: fill in IP6 protocol switch table. 1491.2Sitojun * All protocols not implemented in kernel go to raw IP6 protocol handler. 1501.2Sitojun */ 1511.2Sitojunvoid 1521.2Sitojunip6_init() 1531.2Sitojun{ 1541.35Sitojun struct ip6protosw *pr; 1551.35Sitojun int i; 1561.2Sitojun struct timeval tv; 1571.2Sitojun 1581.2Sitojun pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); 1591.2Sitojun if (pr == 0) 1601.2Sitojun panic("ip6_init"); 1611.2Sitojun for (i = 0; i < IPPROTO_MAX; i++) 1621.2Sitojun ip6_protox[i] = pr - inet6sw; 1631.2Sitojun for (pr = (struct ip6protosw *)inet6domain.dom_protosw; 1641.2Sitojun pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) 1651.2Sitojun if (pr->pr_domain->dom_family == PF_INET6 && 1661.2Sitojun pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 1671.2Sitojun ip6_protox[pr->pr_protocol] = pr - inet6sw; 1681.2Sitojun ip6intrq.ifq_maxlen = ip6qmaxlen; 1691.2Sitojun nd6_init(); 1701.2Sitojun frag6_init(); 1711.2Sitojun /* 1721.2Sitojun * in many cases, random() here does NOT return random number 1731.2Sitojun * as initialization during bootstrap time occur in fixed order. 1741.2Sitojun */ 1751.2Sitojun microtime(&tv); 1761.2Sitojun ip6_flow_seq = random() ^ tv.tv_usec; 1771.2Sitojun 1781.2Sitojun ip6_init2((void *)0); 1791.29Sthorpej 1801.29Sthorpej#ifdef PFIL_HOOKS 1811.29Sthorpej /* Register our Packet Filter hook. */ 1821.33Sthorpej inet6_pfil_hook.ph_type = PFIL_TYPE_AF; 1831.33Sthorpej inet6_pfil_hook.ph_af = AF_INET6; 1841.29Sthorpej i = pfil_head_register(&inet6_pfil_hook); 1851.29Sthorpej if (i != 0) 1861.29Sthorpej printf("ip6_init: WARNING: unable to register pfil hook, " 1871.29Sthorpej "error %d\n", i); 1881.29Sthorpej#endif /* PFIL_HOOKS */ 1891.2Sitojun} 1901.2Sitojun 1911.2Sitojunstatic void 1921.2Sitojunip6_init2(dummy) 1931.2Sitojun void *dummy; 1941.2Sitojun{ 1951.2Sitojun /* 1961.2Sitojun * to route local address of p2p link to loopback, 1971.21Sitojun * assign loopback address first. 1981.2Sitojun */ 1991.20Sitojun in6_ifattach(&loif[0], NULL); 2001.2Sitojun 2011.2Sitojun /* nd6_timer_init */ 2021.19Sthorpej callout_init(&nd6_timer_ch); 2031.19Sthorpej callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); 2041.9Sitojun /* router renumbering prefix list maintenance */ 2051.19Sthorpej callout_init(&in6_rr_timer_ch); 2061.19Sthorpej callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL); 2071.2Sitojun} 2081.2Sitojun 2091.2Sitojun/* 2101.2Sitojun * IP6 input interrupt handling. Just pass the packet to ip6_input. 2111.2Sitojun */ 2121.2Sitojunvoid 2131.2Sitojunip6intr() 2141.2Sitojun{ 2151.2Sitojun int s; 2161.2Sitojun struct mbuf *m; 2171.2Sitojun 2181.2Sitojun for (;;) { 2191.41Sthorpej s = splnet(); 2201.2Sitojun IF_DEQUEUE(&ip6intrq, m); 2211.2Sitojun splx(s); 2221.2Sitojun if (m == 0) 2231.2Sitojun return; 2241.2Sitojun ip6_input(m); 2251.2Sitojun } 2261.2Sitojun} 2271.2Sitojun 2281.2Sitojunextern struct route_in6 ip6_forward_rt; 2291.2Sitojun 2301.2Sitojunvoid 2311.2Sitojunip6_input(m) 2321.2Sitojun struct mbuf *m; 2331.2Sitojun{ 2341.9Sitojun struct ip6_hdr *ip6; 2351.2Sitojun int off = sizeof(struct ip6_hdr), nest; 2361.2Sitojun u_int32_t plen; 2371.5Sitojun u_int32_t rtalert = ~0; 2381.2Sitojun int nxt, ours = 0; 2391.9Sitojun struct ifnet *deliverifp = NULL; 2401.2Sitojun 2411.2Sitojun#ifdef IPSEC 2421.2Sitojun /* 2431.2Sitojun * should the inner packet be considered authentic? 2441.2Sitojun * see comment in ah4_input(). 2451.2Sitojun */ 2461.2Sitojun if (m) { 2471.2Sitojun m->m_flags &= ~M_AUTHIPHDR; 2481.2Sitojun m->m_flags &= ~M_AUTHIPDGM; 2491.2Sitojun } 2501.2Sitojun#endif 2511.9Sitojun 2521.2Sitojun /* 2531.44Sitojun * mbuf statistics 2541.2Sitojun */ 2551.2Sitojun if (m->m_flags & M_EXT) { 2561.2Sitojun if (m->m_next) 2571.2Sitojun ip6stat.ip6s_mext2m++; 2581.2Sitojun else 2591.2Sitojun ip6stat.ip6s_mext1++; 2601.2Sitojun } else { 2611.40Sitojun#define M2MMAX (sizeof(ip6stat.ip6s_m2m)/sizeof(ip6stat.ip6s_m2m[0])) 2621.2Sitojun if (m->m_next) { 2631.9Sitojun if (m->m_flags & M_LOOP) { 2641.44Sitojun ip6stat.ip6s_m2m[loif[0].if_index]++; /* XXX */ 2651.40Sitojun } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) 2661.2Sitojun ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; 2671.2Sitojun else 2681.2Sitojun ip6stat.ip6s_m2m[0]++; 2691.2Sitojun } else 2701.2Sitojun ip6stat.ip6s_m1++; 2711.40Sitojun#undef M2MMAX 2721.2Sitojun } 2731.2Sitojun 2741.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); 2751.9Sitojun ip6stat.ip6s_total++; 2761.9Sitojun 2771.9Sitojun#ifndef PULLDOWN_TEST 2781.9Sitojun /* XXX is the line really necessary? */ 2791.2Sitojun IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); 2801.9Sitojun#endif 2811.2Sitojun 2821.9Sitojun if (m->m_len < sizeof(struct ip6_hdr)) { 2831.9Sitojun struct ifnet *inifp; 2841.9Sitojun inifp = m->m_pkthdr.rcvif; 2851.9Sitojun if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) { 2861.9Sitojun ip6stat.ip6s_toosmall++; 2871.9Sitojun in6_ifstat_inc(inifp, ifs6_in_hdrerr); 2881.9Sitojun return; 2891.9Sitojun } 2901.2Sitojun } 2911.2Sitojun 2921.2Sitojun ip6 = mtod(m, struct ip6_hdr *); 2931.2Sitojun 2941.2Sitojun if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 2951.2Sitojun ip6stat.ip6s_badvers++; 2961.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 2971.2Sitojun goto bad; 2981.2Sitojun } 2991.15Sdarrenr 3001.15Sdarrenr#ifdef PFIL_HOOKS 3011.15Sdarrenr /* 3021.15Sdarrenr * Run through list of hooks for input packets. If there are any 3031.15Sdarrenr * filters which require that additional packets in the flow are 3041.15Sdarrenr * not fast-forwarded, they must clear the M_CANFASTFWD flag. 3051.15Sdarrenr * Note that filters must _never_ set this flag, as another filter 3061.15Sdarrenr * in the list may have previously cleared it. 3071.15Sdarrenr */ 3081.39Sitojun /* 3091.39Sitojun * let ipfilter look at packet on the wire, 3101.39Sitojun * not the decapsulated packet. 3111.39Sitojun */ 3121.39Sitojun#ifdef IPSEC 3131.42Sitojun if (!ipsec_getnhist(m)) 3141.39Sitojun#else 3151.39Sitojun if (1) 3161.39Sitojun#endif 3171.39Sitojun { 3181.39Sitojun if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, 3191.39Sitojun PFIL_IN) != 0) 3201.39Sitojun return; 3211.39Sitojun if (m == NULL) 3221.39Sitojun return; 3231.39Sitojun ip6 = mtod(m, struct ip6_hdr *); 3241.39Sitojun } 3251.15Sdarrenr#endif /* PFIL_HOOKS */ 3261.15Sdarrenr 3271.2Sitojun ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; 3281.2Sitojun 3291.30Sthorpej#ifdef ALTQ 3301.30Sthorpej if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { 3311.30Sthorpej /* packet is dropped by traffic conditioner */ 3321.30Sthorpej return; 3331.9Sitojun } 3341.9Sitojun#endif 3351.9Sitojun 3361.2Sitojun /* 3371.44Sitojun * Check against address spoofing/corruption. 3381.2Sitojun */ 3391.2Sitojun if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || 3401.2Sitojun IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { 3411.2Sitojun ip6stat.ip6s_badscope++; 3421.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 3431.2Sitojun goto bad; 3441.2Sitojun } 3451.13Sitojun /* 3461.44Sitojun * The following check is not documented in specs. A malicious 3471.44Sitojun * party may be able to use IPv4 mapped addr to confuse tcp/udp stack 3481.44Sitojun * and bypass security checks (act as if it was from 127.0.0.1 by using 3491.44Sitojun * IPv6 src ::ffff:127.0.0.1). Be cautious. 3501.35Sitojun * 3511.44Sitojun * This check chokes if we are in an SIIT cloud. As none of BSDs 3521.44Sitojun * support IPv4-less kernel compilation, we cannot support SIIT 3531.44Sitojun * environment at all. So, it makes more sense for us to reject any 3541.44Sitojun * malicious packets for non-SIIT environment, than try to do a 3551.44Sitojun * partical support for SIIT environment. 3561.13Sitojun */ 3571.13Sitojun if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 3581.13Sitojun IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 3591.13Sitojun ip6stat.ip6s_badscope++; 3601.13Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 3611.13Sitojun goto bad; 3621.13Sitojun } 3631.17Sitojun#if 0 3641.13Sitojun /* 3651.17Sitojun * Reject packets with IPv4 compatible addresses (auto tunnel). 3661.17Sitojun * 3671.17Sitojun * The code forbids auto tunnel relay case in RFC1933 (the check is 3681.17Sitojun * stronger than RFC1933). We may want to re-enable it if mech-xx 3691.17Sitojun * is revised to forbid relaying case. 3701.13Sitojun */ 3711.13Sitojun if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || 3721.13Sitojun IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { 3731.13Sitojun ip6stat.ip6s_badscope++; 3741.13Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 3751.13Sitojun goto bad; 3761.13Sitojun } 3771.13Sitojun#endif 3781.35Sitojun 3791.2Sitojun if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || 3801.2Sitojun IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { 3811.2Sitojun if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { 3821.2Sitojun ours = 1; 3831.9Sitojun deliverifp = m->m_pkthdr.rcvif; 3841.2Sitojun goto hbhcheck; 3851.2Sitojun } else { 3861.2Sitojun ip6stat.ip6s_badscope++; 3871.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 3881.2Sitojun goto bad; 3891.2Sitojun } 3901.2Sitojun } 3911.2Sitojun 3921.38Sitojun /* drop packets if interface ID portion is already filled */ 3931.38Sitojun if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 3941.38Sitojun if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) && 3951.38Sitojun ip6->ip6_src.s6_addr16[1]) { 3961.38Sitojun ip6stat.ip6s_badscope++; 3971.38Sitojun goto bad; 3981.38Sitojun } 3991.38Sitojun if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst) && 4001.38Sitojun ip6->ip6_dst.s6_addr16[1]) { 4011.38Sitojun ip6stat.ip6s_badscope++; 4021.38Sitojun goto bad; 4031.38Sitojun } 4041.38Sitojun } 4051.2Sitojun 4061.40Sitojun if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 4071.40Sitojun ip6->ip6_src.s6_addr16[1] 4081.40Sitojun = htons(m->m_pkthdr.rcvif->if_index); 4091.40Sitojun if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 4101.40Sitojun ip6->ip6_dst.s6_addr16[1] 4111.40Sitojun = htons(m->m_pkthdr.rcvif->if_index); 4121.40Sitojun 4131.40Sitojun /* 4141.40Sitojun * We use rt->rt_ifp to determine if the address is ours or not. 4151.40Sitojun * If rt_ifp is lo0, the address is ours. 4161.40Sitojun * The problem here is, rt->rt_ifp for fe80::%lo0/64 is set to lo0, 4171.40Sitojun * so any address under fe80::%lo0/64 will be mistakenly considered 4181.40Sitojun * local. The special case is supplied to handle the case properly 4191.40Sitojun * by actually looking at interface addresses 4201.40Sitojun * (using in6ifa_ifpwithaddr). 4211.40Sitojun */ 4221.40Sitojun if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0 && 4231.40Sitojun IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { 4241.40Sitojun if (!in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, &ip6->ip6_dst)) { 4251.40Sitojun icmp6_error(m, ICMP6_DST_UNREACH, 4261.40Sitojun ICMP6_DST_UNREACH_ADDR, 0); 4271.40Sitojun /* m is already freed */ 4281.40Sitojun return; 4291.21Sitojun } 4301.40Sitojun 4311.40Sitojun ours = 1; 4321.40Sitojun deliverifp = m->m_pkthdr.rcvif; 4331.40Sitojun goto hbhcheck; 4341.9Sitojun } 4351.9Sitojun 4361.2Sitojun /* 4371.2Sitojun * Multicast check 4381.2Sitojun */ 4391.2Sitojun if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 4401.2Sitojun struct in6_multi *in6m = 0; 4411.9Sitojun 4421.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); 4431.2Sitojun /* 4441.2Sitojun * See if we belong to the destination multicast group on the 4451.2Sitojun * arrival interface. 4461.2Sitojun */ 4471.2Sitojun IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m); 4481.2Sitojun if (in6m) 4491.2Sitojun ours = 1; 4501.2Sitojun else if (!ip6_mrouter) { 4511.2Sitojun ip6stat.ip6s_notmember++; 4521.2Sitojun ip6stat.ip6s_cantforward++; 4531.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 4541.2Sitojun goto bad; 4551.2Sitojun } 4561.9Sitojun deliverifp = m->m_pkthdr.rcvif; 4571.2Sitojun goto hbhcheck; 4581.2Sitojun } 4591.2Sitojun 4601.2Sitojun /* 4611.2Sitojun * Unicast check 4621.2Sitojun */ 4631.22Sitojun if (ip6_forward_rt.ro_rt != NULL && 4641.22Sitojun (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && 4651.22Sitojun IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 4661.35Sitojun &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr)) 4671.25Sitojun ip6stat.ip6s_forward_cachehit++; 4681.22Sitojun else { 4691.35Sitojun struct sockaddr_in6 *dst6; 4701.35Sitojun 4711.2Sitojun if (ip6_forward_rt.ro_rt) { 4721.22Sitojun /* route is down or destination is different */ 4731.25Sitojun ip6stat.ip6s_forward_cachemiss++; 4741.2Sitojun RTFREE(ip6_forward_rt.ro_rt); 4751.2Sitojun ip6_forward_rt.ro_rt = 0; 4761.2Sitojun } 4771.22Sitojun 4781.2Sitojun bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6)); 4791.35Sitojun dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst; 4801.35Sitojun dst6->sin6_len = sizeof(struct sockaddr_in6); 4811.35Sitojun dst6->sin6_family = AF_INET6; 4821.35Sitojun dst6->sin6_addr = ip6->ip6_dst; 4831.2Sitojun 4841.9Sitojun rtalloc((struct route *)&ip6_forward_rt); 4851.2Sitojun } 4861.2Sitojun 4871.2Sitojun#define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) 4881.2Sitojun 4891.2Sitojun /* 4901.2Sitojun * Accept the packet if the forwarding interface to the destination 4911.2Sitojun * according to the routing table is the loopback interface, 4921.2Sitojun * unless the associated route has a gateway. 4931.2Sitojun * Note that this approach causes to accept a packet if there is a 4941.2Sitojun * route to the loopback interface for the destination of the packet. 4951.2Sitojun * But we think it's even useful in some situations, e.g. when using 4961.2Sitojun * a special daemon which wants to intercept the packet. 4971.2Sitojun */ 4981.2Sitojun if (ip6_forward_rt.ro_rt && 4991.2Sitojun (ip6_forward_rt.ro_rt->rt_flags & 5001.2Sitojun (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && 5011.2Sitojun#if 0 5021.2Sitojun /* 5031.2Sitojun * The check below is redundant since the comparison of 5041.2Sitojun * the destination and the key of the rtentry has 5051.2Sitojun * already done through looking up the routing table. 5061.2Sitojun */ 5071.2Sitojun IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 5081.2Sitojun &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && 5091.2Sitojun#endif 5101.9Sitojun ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { 5111.2Sitojun struct in6_ifaddr *ia6 = 5121.2Sitojun (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa; 5131.2Sitojun if (ia6->ia6_flags & IN6_IFF_ANYCAST) 5141.2Sitojun m->m_flags |= M_ANYCAST6; 5151.24Sitojun /* 5161.24Sitojun * packets to a tentative, duplicated, or somehow invalid 5171.24Sitojun * address must not be accepted. 5181.24Sitojun */ 5191.2Sitojun if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { 5201.24Sitojun /* this address is ready */ 5211.2Sitojun ours = 1; 5221.9Sitojun deliverifp = ia6->ia_ifp; /* correct? */ 5231.2Sitojun goto hbhcheck; 5241.2Sitojun } else { 5251.24Sitojun /* address is not ready, so discard the packet. */ 5261.34Sitojun nd6log((LOG_INFO, 5271.27Sitojun "ip6_input: packet to an unready address %s->%s\n", 5281.24Sitojun ip6_sprintf(&ip6->ip6_src), 5291.34Sitojun ip6_sprintf(&ip6->ip6_dst))); 5301.24Sitojun 5311.24Sitojun goto bad; 5321.2Sitojun } 5331.2Sitojun } 5341.2Sitojun 5351.2Sitojun /* 5361.2Sitojun * FAITH(Firewall Aided Internet Translator) 5371.2Sitojun */ 5381.2Sitojun#if defined(NFAITH) && 0 < NFAITH 5391.2Sitojun if (ip6_keepfaith) { 5401.2Sitojun if (ip6_forward_rt.ro_rt && ip6_forward_rt.ro_rt->rt_ifp 5411.2Sitojun && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) { 5421.2Sitojun /* XXX do we need more sanity checks? */ 5431.2Sitojun ours = 1; 5441.45Sitojun deliverifp = ip6_forward_rt.ro_rt->rt_ifp; /* faith */ 5451.9Sitojun goto hbhcheck; 5461.9Sitojun } 5471.9Sitojun } 5481.9Sitojun#endif 5491.9Sitojun 5501.9Sitojun#if 0 5511.9Sitojun { 5521.9Sitojun /* 5531.9Sitojun * Last resort: check in6_ifaddr for incoming interface. 5541.9Sitojun * The code is here until I update the "goto ours hack" code above 5551.9Sitojun * working right. 5561.9Sitojun */ 5571.9Sitojun struct ifaddr *ifa; 5581.9Sitojun for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first; 5591.9Sitojun ifa; 5601.9Sitojun ifa = ifa->ifa_list.tqe_next) { 5611.9Sitojun if (ifa->ifa_addr == NULL) 5621.9Sitojun continue; /* just for safety */ 5631.9Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 5641.9Sitojun continue; 5651.9Sitojun if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) { 5661.9Sitojun ours = 1; 5671.9Sitojun deliverifp = ifa->ifa_ifp; 5681.2Sitojun goto hbhcheck; 5691.2Sitojun } 5701.2Sitojun } 5711.9Sitojun } 5721.2Sitojun#endif 5731.2Sitojun 5741.2Sitojun /* 5751.2Sitojun * Now there is no reason to process the packet if it's not our own 5761.2Sitojun * and we're not a router. 5771.2Sitojun */ 5781.2Sitojun if (!ip6_forwarding) { 5791.2Sitojun ip6stat.ip6s_cantforward++; 5801.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 5811.2Sitojun goto bad; 5821.2Sitojun } 5831.2Sitojun 5841.2Sitojun hbhcheck: 5851.2Sitojun /* 5861.2Sitojun * Process Hop-by-Hop options header if it's contained. 5871.2Sitojun * m may be modified in ip6_hopopts_input(). 5881.2Sitojun * If a JumboPayload option is included, plen will also be modified. 5891.2Sitojun */ 5901.2Sitojun plen = (u_int32_t)ntohs(ip6->ip6_plen); 5911.2Sitojun if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { 5921.9Sitojun struct ip6_hbh *hbh; 5931.9Sitojun 5941.9Sitojun if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) { 5951.9Sitojun#if 0 /*touches NULL pointer*/ 5961.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 5971.9Sitojun#endif 5981.2Sitojun return; /* m have already been freed */ 5991.9Sitojun } 6001.22Sitojun 6011.2Sitojun /* adjust pointer */ 6021.2Sitojun ip6 = mtod(m, struct ip6_hdr *); 6031.22Sitojun 6041.22Sitojun /* 6051.22Sitojun * if the payload length field is 0 and the next header field 6061.22Sitojun * indicates Hop-by-Hop Options header, then a Jumbo Payload 6071.22Sitojun * option MUST be included. 6081.22Sitojun */ 6091.22Sitojun if (ip6->ip6_plen == 0 && plen == 0) { 6101.22Sitojun /* 6111.22Sitojun * Note that if a valid jumbo payload option is 6121.22Sitojun * contained, ip6_hoptops_input() must set a valid 6131.22Sitojun * (non-zero) payload length to the variable plen. 6141.22Sitojun */ 6151.22Sitojun ip6stat.ip6s_badoptions++; 6161.22Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 6171.22Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 6181.22Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 6191.22Sitojun ICMP6_PARAMPROB_HEADER, 6201.22Sitojun (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); 6211.22Sitojun return; 6221.22Sitojun } 6231.9Sitojun#ifndef PULLDOWN_TEST 6241.9Sitojun /* ip6_hopopts_input() ensures that mbuf is contiguous */ 6251.9Sitojun hbh = (struct ip6_hbh *)(ip6 + 1); 6261.9Sitojun#else 6271.9Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), 6281.9Sitojun sizeof(struct ip6_hbh)); 6291.9Sitojun if (hbh == NULL) { 6301.9Sitojun ip6stat.ip6s_tooshort++; 6311.9Sitojun return; 6321.9Sitojun } 6331.9Sitojun#endif 6341.9Sitojun nxt = hbh->ip6h_nxt; 6351.2Sitojun 6361.2Sitojun /* 6371.2Sitojun * accept the packet if a router alert option is included 6381.2Sitojun * and we act as an IPv6 router. 6391.2Sitojun */ 6401.5Sitojun if (rtalert != ~0 && ip6_forwarding) 6411.2Sitojun ours = 1; 6421.2Sitojun } else 6431.2Sitojun nxt = ip6->ip6_nxt; 6441.2Sitojun 6451.2Sitojun /* 6461.2Sitojun * Check that the amount of data in the buffers 6471.2Sitojun * is as at least much as the IPv6 header would have us expect. 6481.2Sitojun * Trim mbufs if longer than we expect. 6491.2Sitojun * Drop packet if shorter than we expect. 6501.2Sitojun */ 6511.2Sitojun if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { 6521.2Sitojun ip6stat.ip6s_tooshort++; 6531.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 6541.2Sitojun goto bad; 6551.2Sitojun } 6561.2Sitojun if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { 6571.2Sitojun if (m->m_len == m->m_pkthdr.len) { 6581.2Sitojun m->m_len = sizeof(struct ip6_hdr) + plen; 6591.2Sitojun m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; 6601.2Sitojun } else 6611.2Sitojun m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); 6621.2Sitojun } 6631.2Sitojun 6641.2Sitojun /* 6651.2Sitojun * Forward if desirable. 6661.2Sitojun */ 6671.2Sitojun if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 6681.2Sitojun /* 6691.2Sitojun * If we are acting as a multicast router, all 6701.2Sitojun * incoming multicast packets are passed to the 6711.2Sitojun * kernel-level multicast forwarding function. 6721.2Sitojun * The packet is returned (relatively) intact; if 6731.2Sitojun * ip6_mforward() returns a non-zero value, the packet 6741.2Sitojun * must be discarded, else it may be accepted below. 6751.2Sitojun */ 6761.2Sitojun if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { 6771.2Sitojun ip6stat.ip6s_cantforward++; 6781.2Sitojun m_freem(m); 6791.2Sitojun return; 6801.2Sitojun } 6811.2Sitojun if (!ours) { 6821.2Sitojun m_freem(m); 6831.2Sitojun return; 6841.2Sitojun } 6851.22Sitojun } else if (!ours) { 6861.2Sitojun ip6_forward(m, 0); 6871.2Sitojun return; 6881.2Sitojun } 6891.25Sitojun 6901.25Sitojun ip6 = mtod(m, struct ip6_hdr *); 6911.25Sitojun 6921.25Sitojun /* 6931.25Sitojun * Malicious party may be able to use IPv4 mapped addr to confuse 6941.25Sitojun * tcp/udp stack and bypass security checks (act as if it was from 6951.25Sitojun * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious. 6961.25Sitojun * 6971.25Sitojun * For SIIT end node behavior, you may want to disable the check. 6981.25Sitojun * However, you will become vulnerable to attacks using IPv4 mapped 6991.25Sitojun * source. 7001.25Sitojun */ 7011.25Sitojun if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 7021.25Sitojun IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 7031.25Sitojun ip6stat.ip6s_badscope++; 7041.25Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 7051.25Sitojun goto bad; 7061.25Sitojun } 7071.2Sitojun 7081.2Sitojun /* 7091.2Sitojun * Tell launch routine the next header 7101.2Sitojun */ 7111.12Sitojun#ifdef IFA_STATS 7121.28Sitojun if (deliverifp != NULL) { 7131.9Sitojun struct in6_ifaddr *ia6; 7141.9Sitojun ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); 7151.9Sitojun if (ia6) 7161.9Sitojun ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len; 7171.9Sitojun } 7181.9Sitojun#endif 7191.2Sitojun ip6stat.ip6s_delivered++; 7201.9Sitojun in6_ifstat_inc(deliverifp, ifs6_in_deliver); 7211.2Sitojun nest = 0; 7221.40Sitojun 7231.2Sitojun while (nxt != IPPROTO_DONE) { 7241.2Sitojun if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { 7251.2Sitojun ip6stat.ip6s_toomanyhdr++; 7261.2Sitojun goto bad; 7271.2Sitojun } 7281.8Sitojun 7291.8Sitojun /* 7301.8Sitojun * protection against faulty packet - there should be 7311.8Sitojun * more sanity checks in header chain processing. 7321.8Sitojun */ 7331.8Sitojun if (m->m_pkthdr.len < off) { 7341.8Sitojun ip6stat.ip6s_tooshort++; 7351.9Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 7361.8Sitojun goto bad; 7371.8Sitojun } 7381.8Sitojun 7391.37Sitojun#ifdef IPSEC 7401.37Sitojun /* 7411.37Sitojun * enforce IPsec policy checking if we are seeing last header. 7421.37Sitojun * note that we do not visit this with protocols with pcb layer 7431.37Sitojun * code - like udp/tcp/raw ip. 7441.37Sitojun */ 7451.37Sitojun if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 7461.37Sitojun ipsec6_in_reject(m, NULL)) { 7471.37Sitojun ipsec6stat.in_polvio++; 7481.37Sitojun goto bad; 7491.37Sitojun } 7501.37Sitojun#endif 7511.37Sitojun 7521.2Sitojun nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); 7531.2Sitojun } 7541.2Sitojun return; 7551.2Sitojun bad: 7561.2Sitojun m_freem(m); 7571.2Sitojun} 7581.2Sitojun 7591.2Sitojun/* 7601.2Sitojun * Hop-by-Hop options header processing. If a valid jumbo payload option is 7611.2Sitojun * included, the real payload length will be stored in plenp. 7621.2Sitojun */ 7631.2Sitojunstatic int 7641.2Sitojunip6_hopopts_input(plenp, rtalertp, mp, offp) 7651.2Sitojun u_int32_t *plenp; 7661.5Sitojun u_int32_t *rtalertp; /* XXX: should be stored more smart way */ 7671.2Sitojun struct mbuf **mp; 7681.2Sitojun int *offp; 7691.2Sitojun{ 7701.35Sitojun struct mbuf *m = *mp; 7711.2Sitojun int off = *offp, hbhlen; 7721.2Sitojun struct ip6_hbh *hbh; 7731.2Sitojun u_int8_t *opt; 7741.2Sitojun 7751.2Sitojun /* validation of the length of the header */ 7761.9Sitojun#ifndef PULLDOWN_TEST 7771.2Sitojun IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); 7781.2Sitojun hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); 7791.2Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 7801.2Sitojun 7811.2Sitojun IP6_EXTHDR_CHECK(m, off, hbhlen, -1); 7821.2Sitojun hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); 7831.9Sitojun#else 7841.9Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, 7851.9Sitojun sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); 7861.9Sitojun if (hbh == NULL) { 7871.9Sitojun ip6stat.ip6s_tooshort++; 7881.9Sitojun return -1; 7891.9Sitojun } 7901.9Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 7911.9Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), 7921.9Sitojun hbhlen); 7931.9Sitojun if (hbh == NULL) { 7941.9Sitojun ip6stat.ip6s_tooshort++; 7951.9Sitojun return -1; 7961.9Sitojun } 7971.9Sitojun#endif 7981.2Sitojun off += hbhlen; 7991.2Sitojun hbhlen -= sizeof(struct ip6_hbh); 8001.2Sitojun opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh); 8011.2Sitojun 8021.2Sitojun if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), 8031.2Sitojun hbhlen, rtalertp, plenp) < 0) 8041.2Sitojun return(-1); 8051.2Sitojun 8061.2Sitojun *offp = off; 8071.2Sitojun *mp = m; 8081.2Sitojun return(0); 8091.2Sitojun} 8101.2Sitojun 8111.2Sitojun/* 8121.2Sitojun * Search header for all Hop-by-hop options and process each option. 8131.2Sitojun * This function is separate from ip6_hopopts_input() in order to 8141.2Sitojun * handle a case where the sending node itself process its hop-by-hop 8151.2Sitojun * options header. In such a case, the function is called from ip6_output(). 8161.2Sitojun */ 8171.2Sitojunint 8181.2Sitojunip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) 8191.2Sitojun struct mbuf *m; 8201.2Sitojun u_int8_t *opthead; 8211.2Sitojun int hbhlen; 8221.5Sitojun u_int32_t *rtalertp; 8231.2Sitojun u_int32_t *plenp; 8241.2Sitojun{ 8251.2Sitojun struct ip6_hdr *ip6; 8261.2Sitojun int optlen = 0; 8271.2Sitojun u_int8_t *opt = opthead; 8281.2Sitojun u_int16_t rtalert_val; 8291.22Sitojun u_int32_t jumboplen; 8301.2Sitojun 8311.2Sitojun for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { 8321.35Sitojun switch (*opt) { 8331.35Sitojun case IP6OPT_PAD1: 8341.35Sitojun optlen = 1; 8351.35Sitojun break; 8361.35Sitojun case IP6OPT_PADN: 8371.35Sitojun if (hbhlen < IP6OPT_MINLEN) { 8381.35Sitojun ip6stat.ip6s_toosmall++; 8391.35Sitojun goto bad; 8401.35Sitojun } 8411.35Sitojun optlen = *(opt + 1) + 2; 8421.35Sitojun break; 8431.35Sitojun case IP6OPT_RTALERT: 8441.35Sitojun /* XXX may need check for alignment */ 8451.35Sitojun if (hbhlen < IP6OPT_RTALERT_LEN) { 8461.35Sitojun ip6stat.ip6s_toosmall++; 8471.35Sitojun goto bad; 8481.35Sitojun } 8491.35Sitojun if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { 8501.35Sitojun /* XXX: should we discard the packet? */ 8511.35Sitojun log(LOG_ERR, "length of router alert opt is inconsitent(%d)", 8521.35Sitojun *(opt + 1)); 8531.35Sitojun } 8541.35Sitojun optlen = IP6OPT_RTALERT_LEN; 8551.35Sitojun bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); 8561.35Sitojun *rtalertp = ntohs(rtalert_val); 8571.35Sitojun break; 8581.35Sitojun case IP6OPT_JUMBO: 8591.22Sitojun /* XXX may need check for alignment */ 8601.22Sitojun if (hbhlen < IP6OPT_JUMBO_LEN) { 8611.22Sitojun ip6stat.ip6s_toosmall++; 8621.22Sitojun goto bad; 8631.22Sitojun } 8641.35Sitojun if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { 8651.35Sitojun /* XXX: should we discard the packet? */ 8661.22Sitojun log(LOG_ERR, "length of jumbopayload opt " 8671.27Sitojun "is inconsistent(%d)\n", 8681.22Sitojun *(opt + 1)); 8691.35Sitojun } 8701.22Sitojun optlen = IP6OPT_JUMBO_LEN; 8711.22Sitojun 8721.22Sitojun /* 8731.22Sitojun * IPv6 packets that have non 0 payload length 8741.35Sitojun * must not contain a jumbo payload option. 8751.22Sitojun */ 8761.22Sitojun ip6 = mtod(m, struct ip6_hdr *); 8771.22Sitojun if (ip6->ip6_plen) { 8781.22Sitojun ip6stat.ip6s_badoptions++; 8791.22Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 8801.22Sitojun ICMP6_PARAMPROB_HEADER, 8811.22Sitojun sizeof(struct ip6_hdr) + 8821.22Sitojun sizeof(struct ip6_hbh) + 8831.22Sitojun opt - opthead); 8841.22Sitojun return(-1); 8851.22Sitojun } 8861.2Sitojun 8871.22Sitojun /* 8881.22Sitojun * We may see jumbolen in unaligned location, so 8891.22Sitojun * we'd need to perform bcopy(). 8901.22Sitojun */ 8911.22Sitojun bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); 8921.22Sitojun jumboplen = (u_int32_t)htonl(jumboplen); 8931.22Sitojun 8941.22Sitojun#if 1 8951.22Sitojun /* 8961.22Sitojun * if there are multiple jumbo payload options, 8971.22Sitojun * *plenp will be non-zero and the packet will be 8981.22Sitojun * rejected. 8991.22Sitojun * the behavior may need some debate in ipngwg - 9001.22Sitojun * multiple options does not make sense, however, 9011.22Sitojun * there's no explicit mention in specification. 9021.22Sitojun */ 9031.22Sitojun if (*plenp != 0) { 9041.22Sitojun ip6stat.ip6s_badoptions++; 9051.22Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 9061.22Sitojun ICMP6_PARAMPROB_HEADER, 9071.22Sitojun sizeof(struct ip6_hdr) + 9081.22Sitojun sizeof(struct ip6_hbh) + 9091.22Sitojun opt + 2 - opthead); 9101.22Sitojun return(-1); 9111.22Sitojun } 9121.8Sitojun#endif 9131.2Sitojun 9141.22Sitojun /* 9151.22Sitojun * jumbo payload length must be larger than 65535. 9161.22Sitojun */ 9171.22Sitojun if (jumboplen <= IPV6_MAXPACKET) { 9181.22Sitojun ip6stat.ip6s_badoptions++; 9191.22Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 9201.22Sitojun ICMP6_PARAMPROB_HEADER, 9211.22Sitojun sizeof(struct ip6_hdr) + 9221.22Sitojun sizeof(struct ip6_hbh) + 9231.22Sitojun opt + 2 - opthead); 9241.22Sitojun return(-1); 9251.22Sitojun } 9261.22Sitojun *plenp = jumboplen; 9271.22Sitojun 9281.22Sitojun break; 9291.35Sitojun default: /* unknown option */ 9301.35Sitojun if (hbhlen < IP6OPT_MINLEN) { 9311.35Sitojun ip6stat.ip6s_toosmall++; 9321.35Sitojun goto bad; 9331.35Sitojun } 9341.35Sitojun if ((optlen = ip6_unknown_opt(opt, m, 9351.35Sitojun sizeof(struct ip6_hdr) + 9361.35Sitojun sizeof(struct ip6_hbh) + 9371.35Sitojun opt - opthead)) == -1) 9381.35Sitojun return(-1); 9391.35Sitojun optlen += 2; 9401.35Sitojun break; 9411.2Sitojun } 9421.2Sitojun } 9431.2Sitojun 9441.2Sitojun return(0); 9451.2Sitojun 9461.2Sitojun bad: 9471.2Sitojun m_freem(m); 9481.2Sitojun return(-1); 9491.2Sitojun} 9501.2Sitojun 9511.2Sitojun/* 9521.2Sitojun * Unknown option processing. 9531.2Sitojun * The third argument `off' is the offset from the IPv6 header to the option, 9541.2Sitojun * which is necessary if the IPv6 header the and option header and IPv6 header 9551.2Sitojun * is not continuous in order to return an ICMPv6 error. 9561.2Sitojun */ 9571.2Sitojunint 9581.2Sitojunip6_unknown_opt(optp, m, off) 9591.2Sitojun u_int8_t *optp; 9601.2Sitojun struct mbuf *m; 9611.2Sitojun int off; 9621.2Sitojun{ 9631.2Sitojun struct ip6_hdr *ip6; 9641.2Sitojun 9651.35Sitojun switch (IP6OPT_TYPE(*optp)) { 9661.35Sitojun case IP6OPT_TYPE_SKIP: /* ignore the option */ 9671.35Sitojun return((int)*(optp + 1)); 9681.35Sitojun case IP6OPT_TYPE_DISCARD: /* silently discard */ 9691.35Sitojun m_freem(m); 9701.35Sitojun return(-1); 9711.35Sitojun case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ 9721.35Sitojun ip6stat.ip6s_badoptions++; 9731.35Sitojun icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); 9741.35Sitojun return(-1); 9751.35Sitojun case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ 9761.35Sitojun ip6stat.ip6s_badoptions++; 9771.35Sitojun ip6 = mtod(m, struct ip6_hdr *); 9781.35Sitojun if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || 9791.35Sitojun (m->m_flags & (M_BCAST|M_MCAST))) 9801.35Sitojun m_freem(m); 9811.35Sitojun else 9821.35Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 9831.35Sitojun ICMP6_PARAMPROB_OPTION, off); 9841.35Sitojun return(-1); 9851.2Sitojun } 9861.2Sitojun 9871.2Sitojun m_freem(m); /* XXX: NOTREACHED */ 9881.2Sitojun return(-1); 9891.2Sitojun} 9901.2Sitojun 9911.2Sitojun/* 9921.9Sitojun * Create the "control" list for this pcb. 9931.9Sitojun * 9941.9Sitojun * The routine will be called from upper layer handlers like tcp6_input(). 9951.9Sitojun * Thus the routine assumes that the caller (tcp6_input) have already 9961.9Sitojun * called IP6_EXTHDR_CHECK() and all the extension headers are located in the 9971.9Sitojun * very first mbuf on the mbuf chain. 9981.9Sitojun * We may want to add some infinite loop prevention or sanity checks for safety. 9991.9Sitojun * (This applies only when you are using KAME mbuf chain restriction, i.e. 10001.9Sitojun * you are using IP6_EXTHDR_CHECK() not m_pulldown()) 10011.2Sitojun */ 10021.2Sitojunvoid 10031.2Sitojunip6_savecontrol(in6p, mp, ip6, m) 10041.35Sitojun struct in6pcb *in6p; 10051.35Sitojun struct mbuf **mp; 10061.35Sitojun struct ip6_hdr *ip6; 10071.35Sitojun struct mbuf *m; 10081.2Sitojun{ 10091.2Sitojun struct proc *p = curproc; /* XXX */ 10101.9Sitojun int privileged; 10111.2Sitojun 10121.9Sitojun privileged = 0; 10131.9Sitojun if (p && !suser(p->p_ucred, &p->p_acflag)) 10141.9Sitojun privileged++; 10151.9Sitojun 10161.9Sitojun#ifdef SO_TIMESTAMP 10171.2Sitojun if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { 10181.2Sitojun struct timeval tv; 10191.2Sitojun 10201.2Sitojun microtime(&tv); 10211.2Sitojun *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 10221.2Sitojun SCM_TIMESTAMP, SOL_SOCKET); 10231.2Sitojun if (*mp) 10241.2Sitojun mp = &(*mp)->m_next; 10251.2Sitojun } 10261.9Sitojun#endif 10271.2Sitojun if (in6p->in6p_flags & IN6P_RECVDSTADDR) { 10281.2Sitojun *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst, 10291.2Sitojun sizeof(struct in6_addr), IPV6_RECVDSTADDR, 10301.2Sitojun IPPROTO_IPV6); 10311.2Sitojun if (*mp) 10321.2Sitojun mp = &(*mp)->m_next; 10331.2Sitojun } 10341.2Sitojun 10351.2Sitojun#ifdef noyet 10361.2Sitojun /* options were tossed above */ 10371.2Sitojun if (in6p->in6p_flags & IN6P_RECVOPTS) 10381.2Sitojun /* broken */ 10391.2Sitojun /* ip6_srcroute doesn't do what we want here, need to fix */ 10401.2Sitojun if (in6p->in6p_flags & IPV6P_RECVRETOPTS) 10411.2Sitojun /* broken */ 10421.2Sitojun#endif 10431.2Sitojun 10441.2Sitojun /* RFC 2292 sec. 5 */ 10451.35Sitojun if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) { 10461.2Sitojun struct in6_pktinfo pi6; 10471.2Sitojun bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); 10481.2Sitojun if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr)) 10491.2Sitojun pi6.ipi6_addr.s6_addr16[1] = 0; 10501.2Sitojun pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif) 10511.2Sitojun ? m->m_pkthdr.rcvif->if_index 10521.2Sitojun : 0; 10531.2Sitojun *mp = sbcreatecontrol((caddr_t) &pi6, 10541.2Sitojun sizeof(struct in6_pktinfo), IPV6_PKTINFO, 10551.2Sitojun IPPROTO_IPV6); 10561.2Sitojun if (*mp) 10571.2Sitojun mp = &(*mp)->m_next; 10581.2Sitojun } 10591.2Sitojun if (in6p->in6p_flags & IN6P_HOPLIMIT) { 10601.2Sitojun int hlim = ip6->ip6_hlim & 0xff; 10611.2Sitojun *mp = sbcreatecontrol((caddr_t) &hlim, 10621.2Sitojun sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6); 10631.2Sitojun if (*mp) 10641.2Sitojun mp = &(*mp)->m_next; 10651.2Sitojun } 10661.2Sitojun /* IN6P_NEXTHOP - for outgoing packet only */ 10671.2Sitojun 10681.2Sitojun /* 10691.2Sitojun * IPV6_HOPOPTS socket option. We require super-user privilege 10701.2Sitojun * for the option, but it might be too strict, since there might 10711.2Sitojun * be some hop-by-hop options which can be returned to normal user. 10721.2Sitojun * See RFC 2292 section 6. 10731.2Sitojun */ 10741.35Sitojun if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) { 10751.2Sitojun /* 10761.2Sitojun * Check if a hop-by-hop options header is contatined in the 10771.2Sitojun * received packet, and if so, store the options as ancillary 10781.2Sitojun * data. Note that a hop-by-hop options header must be 10791.2Sitojun * just after the IPv6 header, which fact is assured through 10801.2Sitojun * the IPv6 input processing. 10811.2Sitojun */ 10821.2Sitojun struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 10831.2Sitojun if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { 10841.9Sitojun struct ip6_hbh *hbh; 10851.9Sitojun int hbhlen; 10861.9Sitojun 10871.9Sitojun#ifndef PULLDOWN_TEST 10881.9Sitojun hbh = (struct ip6_hbh *)(ip6 + 1); 10891.9Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 10901.9Sitojun#else 10911.9Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, 10921.9Sitojun sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); 10931.9Sitojun if (hbh == NULL) { 10941.9Sitojun ip6stat.ip6s_tooshort++; 10951.9Sitojun return; 10961.9Sitojun } 10971.9Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 10981.9Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, 10991.9Sitojun sizeof(struct ip6_hdr), hbhlen); 11001.9Sitojun if (hbh == NULL) { 11011.9Sitojun ip6stat.ip6s_tooshort++; 11021.9Sitojun return; 11031.9Sitojun } 11041.9Sitojun#endif 11051.2Sitojun 11061.2Sitojun /* 11071.2Sitojun * XXX: We copy whole the header even if a jumbo 11081.2Sitojun * payload option is included, which option is to 11091.2Sitojun * be removed before returning in the RFC 2292. 11101.2Sitojun * But it's too painful operation... 11111.2Sitojun */ 11121.9Sitojun *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, 11131.2Sitojun IPV6_HOPOPTS, IPPROTO_IPV6); 11141.2Sitojun if (*mp) 11151.2Sitojun mp = &(*mp)->m_next; 11161.2Sitojun } 11171.2Sitojun } 11181.2Sitojun 11191.2Sitojun /* IPV6_DSTOPTS and IPV6_RTHDR socket options */ 11201.2Sitojun if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) { 11211.2Sitojun struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 11221.2Sitojun int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);; 11231.2Sitojun 11241.2Sitojun /* 11251.2Sitojun * Search for destination options headers or routing 11261.2Sitojun * header(s) through the header chain, and stores each 11271.2Sitojun * header as ancillary data. 11281.2Sitojun * Note that the order of the headers remains in 11291.2Sitojun * the chain of ancillary data. 11301.2Sitojun */ 11311.35Sitojun while (1) { /* is explicit loop prevention necessary? */ 11321.9Sitojun struct ip6_ext *ip6e; 11331.9Sitojun int elen; 11341.9Sitojun 11351.9Sitojun#ifndef PULLDOWN_TEST 11361.9Sitojun ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); 11371.9Sitojun if (nxt == IPPROTO_AH) 11381.9Sitojun elen = (ip6e->ip6e_len + 2) << 2; 11391.9Sitojun else 11401.9Sitojun elen = (ip6e->ip6e_len + 1) << 3; 11411.9Sitojun#else 11421.9Sitojun IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, 11431.9Sitojun sizeof(struct ip6_ext)); 11441.9Sitojun if (ip6e == NULL) { 11451.9Sitojun ip6stat.ip6s_tooshort++; 11461.9Sitojun return; 11471.9Sitojun } 11481.9Sitojun if (nxt == IPPROTO_AH) 11491.9Sitojun elen = (ip6e->ip6e_len + 2) << 2; 11501.9Sitojun else 11511.9Sitojun elen = (ip6e->ip6e_len + 1) << 3; 11521.9Sitojun IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen); 11531.9Sitojun if (ip6e == NULL) { 11541.9Sitojun ip6stat.ip6s_tooshort++; 11551.9Sitojun return; 11561.9Sitojun } 11571.9Sitojun#endif 11581.2Sitojun 11591.35Sitojun switch (nxt) { 11601.35Sitojun case IPPROTO_DSTOPTS: 11611.35Sitojun if (!in6p->in6p_flags & IN6P_DSTOPTS) 11621.35Sitojun break; 11631.35Sitojun 11641.35Sitojun /* 11651.35Sitojun * We also require super-user privilege for 11661.35Sitojun * the option. 11671.35Sitojun * See the comments on IN6_HOPOPTS. 11681.35Sitojun */ 11691.35Sitojun if (!privileged) 11701.35Sitojun break; 11711.35Sitojun 11721.35Sitojun *mp = sbcreatecontrol((caddr_t)ip6e, elen, 11731.35Sitojun IPV6_DSTOPTS, 11741.35Sitojun IPPROTO_IPV6); 11751.35Sitojun if (*mp) 11761.35Sitojun mp = &(*mp)->m_next; 11771.35Sitojun break; 11781.35Sitojun 11791.35Sitojun case IPPROTO_ROUTING: 11801.35Sitojun if (!in6p->in6p_flags & IN6P_RTHDR) 11811.35Sitojun break; 11821.35Sitojun 11831.35Sitojun *mp = sbcreatecontrol((caddr_t)ip6e, elen, 11841.35Sitojun IPV6_RTHDR, 11851.35Sitojun IPPROTO_IPV6); 11861.35Sitojun if (*mp) 11871.35Sitojun mp = &(*mp)->m_next; 11881.35Sitojun break; 11891.35Sitojun 11901.35Sitojun case IPPROTO_UDP: 11911.35Sitojun case IPPROTO_TCP: 11921.35Sitojun case IPPROTO_ICMPV6: 11931.35Sitojun default: 11941.35Sitojun /* 11951.35Sitojun * stop search if we encounter an upper 11961.35Sitojun * layer protocol headers. 11971.35Sitojun */ 11981.35Sitojun goto loopend; 11991.35Sitojun 12001.35Sitojun case IPPROTO_HOPOPTS: 12011.35Sitojun case IPPROTO_AH: /* is it possible? */ 12021.35Sitojun break; 12031.2Sitojun } 12041.2Sitojun 12051.2Sitojun /* proceed with the next header. */ 12061.9Sitojun off += elen; 12071.2Sitojun nxt = ip6e->ip6e_nxt; 12081.2Sitojun } 12091.2Sitojun loopend: 12101.36Scgd ; 12111.2Sitojun } 12121.9Sitojun if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { 12131.2Sitojun /* to be done */ 12141.2Sitojun } 12151.9Sitojun if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) { 12161.2Sitojun /* to be done */ 12171.2Sitojun } 12181.2Sitojun /* IN6P_RTHDR - to be done */ 12191.2Sitojun 12201.2Sitojun} 12211.2Sitojun 12221.2Sitojun/* 12231.2Sitojun * Get pointer to the previous header followed by the header 12241.2Sitojun * currently processed. 12251.2Sitojun * XXX: This function supposes that 12261.2Sitojun * M includes all headers, 12271.2Sitojun * the next header field and the header length field of each header 12281.2Sitojun * are valid, and 12291.2Sitojun * the sum of each header length equals to OFF. 12301.2Sitojun * Because of these assumptions, this function must be called very 12311.2Sitojun * carefully. Moreover, it will not be used in the near future when 12321.2Sitojun * we develop `neater' mechanism to process extension headers. 12331.2Sitojun */ 12341.2Sitojunchar * 12351.2Sitojunip6_get_prevhdr(m, off) 12361.2Sitojun struct mbuf *m; 12371.2Sitojun int off; 12381.2Sitojun{ 12391.2Sitojun struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12401.2Sitojun 12411.2Sitojun if (off == sizeof(struct ip6_hdr)) 12421.2Sitojun return(&ip6->ip6_nxt); 12431.2Sitojun else { 12441.2Sitojun int len, nxt; 12451.2Sitojun struct ip6_ext *ip6e = NULL; 12461.2Sitojun 12471.2Sitojun nxt = ip6->ip6_nxt; 12481.2Sitojun len = sizeof(struct ip6_hdr); 12491.2Sitojun while (len < off) { 12501.2Sitojun ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); 12511.2Sitojun 12521.35Sitojun switch (nxt) { 12531.2Sitojun case IPPROTO_FRAGMENT: 12541.2Sitojun len += sizeof(struct ip6_frag); 12551.2Sitojun break; 12561.2Sitojun case IPPROTO_AH: 12571.2Sitojun len += (ip6e->ip6e_len + 2) << 2; 12581.2Sitojun break; 12591.2Sitojun default: 12601.2Sitojun len += (ip6e->ip6e_len + 1) << 3; 12611.2Sitojun break; 12621.2Sitojun } 12631.2Sitojun nxt = ip6e->ip6e_nxt; 12641.2Sitojun } 12651.2Sitojun if (ip6e) 12661.2Sitojun return(&ip6e->ip6e_nxt); 12671.2Sitojun else 12681.2Sitojun return NULL; 12691.18Sitojun } 12701.18Sitojun} 12711.18Sitojun 12721.18Sitojun/* 12731.18Sitojun * get next header offset. m will be retained. 12741.18Sitojun */ 12751.18Sitojunint 12761.18Sitojunip6_nexthdr(m, off, proto, nxtp) 12771.18Sitojun struct mbuf *m; 12781.18Sitojun int off; 12791.18Sitojun int proto; 12801.18Sitojun int *nxtp; 12811.18Sitojun{ 12821.18Sitojun struct ip6_hdr ip6; 12831.18Sitojun struct ip6_ext ip6e; 12841.18Sitojun struct ip6_frag fh; 12851.18Sitojun 12861.18Sitojun /* just in case */ 12871.18Sitojun if (m == NULL) 12881.18Sitojun panic("ip6_nexthdr: m == NULL"); 12891.18Sitojun if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) 12901.18Sitojun return -1; 12911.18Sitojun 12921.18Sitojun switch (proto) { 12931.18Sitojun case IPPROTO_IPV6: 12941.18Sitojun if (m->m_pkthdr.len < off + sizeof(ip6)) 12951.18Sitojun return -1; 12961.18Sitojun m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); 12971.18Sitojun if (nxtp) 12981.18Sitojun *nxtp = ip6.ip6_nxt; 12991.18Sitojun off += sizeof(ip6); 13001.18Sitojun return off; 13011.18Sitojun 13021.18Sitojun case IPPROTO_FRAGMENT: 13031.18Sitojun /* 13041.18Sitojun * terminate parsing if it is not the first fragment, 13051.18Sitojun * it does not make sense to parse through it. 13061.18Sitojun */ 13071.18Sitojun if (m->m_pkthdr.len < off + sizeof(fh)) 13081.18Sitojun return -1; 13091.18Sitojun m_copydata(m, off, sizeof(fh), (caddr_t)&fh); 13101.18Sitojun if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0) 13111.18Sitojun return -1; 13121.18Sitojun if (nxtp) 13131.18Sitojun *nxtp = fh.ip6f_nxt; 13141.18Sitojun off += sizeof(struct ip6_frag); 13151.18Sitojun return off; 13161.18Sitojun 13171.18Sitojun case IPPROTO_AH: 13181.18Sitojun if (m->m_pkthdr.len < off + sizeof(ip6e)) 13191.18Sitojun return -1; 13201.18Sitojun m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 13211.18Sitojun if (nxtp) 13221.18Sitojun *nxtp = ip6e.ip6e_nxt; 13231.18Sitojun off += (ip6e.ip6e_len + 2) << 2; 13241.47Sitojun if (m->m_pkthdr.len < off) 13251.47Sitojun return -1; 13261.18Sitojun return off; 13271.18Sitojun 13281.18Sitojun case IPPROTO_HOPOPTS: 13291.18Sitojun case IPPROTO_ROUTING: 13301.18Sitojun case IPPROTO_DSTOPTS: 13311.18Sitojun if (m->m_pkthdr.len < off + sizeof(ip6e)) 13321.18Sitojun return -1; 13331.18Sitojun m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 13341.18Sitojun if (nxtp) 13351.18Sitojun *nxtp = ip6e.ip6e_nxt; 13361.18Sitojun off += (ip6e.ip6e_len + 1) << 3; 13371.47Sitojun if (m->m_pkthdr.len < off) 13381.47Sitojun return -1; 13391.18Sitojun return off; 13401.18Sitojun 13411.18Sitojun case IPPROTO_NONE: 13421.18Sitojun case IPPROTO_ESP: 13431.18Sitojun case IPPROTO_IPCOMP: 13441.18Sitojun /* give up */ 13451.18Sitojun return -1; 13461.18Sitojun 13471.18Sitojun default: 13481.18Sitojun return -1; 13491.18Sitojun } 13501.18Sitojun 13511.18Sitojun return -1; 13521.18Sitojun} 13531.18Sitojun 13541.18Sitojun/* 13551.18Sitojun * get offset for the last header in the chain. m will be kept untainted. 13561.18Sitojun */ 13571.18Sitojunint 13581.18Sitojunip6_lasthdr(m, off, proto, nxtp) 13591.18Sitojun struct mbuf *m; 13601.18Sitojun int off; 13611.18Sitojun int proto; 13621.18Sitojun int *nxtp; 13631.18Sitojun{ 13641.18Sitojun int newoff; 13651.18Sitojun int nxt; 13661.18Sitojun 13671.18Sitojun if (!nxtp) { 13681.18Sitojun nxt = -1; 13691.18Sitojun nxtp = &nxt; 13701.18Sitojun } 13711.18Sitojun while (1) { 13721.18Sitojun newoff = ip6_nexthdr(m, off, proto, nxtp); 13731.18Sitojun if (newoff < 0) 13741.18Sitojun return off; 13751.18Sitojun else if (newoff < off) 13761.18Sitojun return -1; /* invalid */ 13771.18Sitojun else if (newoff == off) 13781.18Sitojun return newoff; 13791.18Sitojun 13801.18Sitojun off = newoff; 13811.18Sitojun proto = *nxtp; 13821.2Sitojun } 13831.2Sitojun} 13841.2Sitojun 13851.2Sitojun/* 13861.2Sitojun * System control for IP6 13871.2Sitojun */ 13881.2Sitojun 13891.2Sitojunu_char inet6ctlerrmap[PRC_NCMDS] = { 13901.2Sitojun 0, 0, 0, 0, 13911.2Sitojun 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 13921.2Sitojun EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 13931.2Sitojun EMSGSIZE, EHOSTUNREACH, 0, 0, 13941.2Sitojun 0, 0, 0, 0, 13951.2Sitojun ENOPROTOOPT 13961.2Sitojun}; 13971.2Sitojun 13981.2Sitojunint 13991.2Sitojunip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 14001.2Sitojun int *name; 14011.2Sitojun u_int namelen; 14021.2Sitojun void *oldp; 14031.2Sitojun size_t *oldlenp; 14041.2Sitojun void *newp; 14051.2Sitojun size_t newlen; 14061.2Sitojun{ 14071.26Sitojun int old, error; 14081.26Sitojun 14091.2Sitojun /* All sysctl names at this level are terminal. */ 14101.2Sitojun if (namelen != 1) 14111.2Sitojun return ENOTDIR; 14121.2Sitojun 14131.2Sitojun switch (name[0]) { 14141.2Sitojun 14151.2Sitojun case IPV6CTL_FORWARDING: 14161.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14171.2Sitojun &ip6_forwarding); 14181.2Sitojun case IPV6CTL_SENDREDIRECTS: 14191.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14201.2Sitojun &ip6_sendredirects); 14211.2Sitojun case IPV6CTL_DEFHLIM: 14221.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_defhlim); 14231.2Sitojun case IPV6CTL_MAXFRAGPACKETS: 14241.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14251.2Sitojun &ip6_maxfragpackets); 14261.2Sitojun case IPV6CTL_ACCEPT_RTADV: 14271.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14281.2Sitojun &ip6_accept_rtadv); 14291.2Sitojun case IPV6CTL_KEEPFAITH: 14301.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_keepfaith); 14311.2Sitojun case IPV6CTL_LOG_INTERVAL: 14321.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14331.2Sitojun &ip6_log_interval); 14341.2Sitojun case IPV6CTL_HDRNESTLIMIT: 14351.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14361.2Sitojun &ip6_hdrnestlimit); 14371.2Sitojun case IPV6CTL_DAD_COUNT: 14381.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_dad_count); 14391.2Sitojun case IPV6CTL_AUTO_FLOWLABEL: 14401.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14411.2Sitojun &ip6_auto_flowlabel); 14421.2Sitojun case IPV6CTL_DEFMCASTHLIM: 14431.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14441.2Sitojun &ip6_defmcasthlim); 14451.2Sitojun case IPV6CTL_GIF_HLIM: 14461.2Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14471.2Sitojun &ip6_gif_hlim); 14481.2Sitojun case IPV6CTL_KAME_VERSION: 14491.2Sitojun return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); 14501.9Sitojun case IPV6CTL_USE_DEPRECATED: 14511.9Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, 14521.9Sitojun &ip6_use_deprecated); 14531.10Sitojun case IPV6CTL_RR_PRUNE: 14541.10Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune); 14551.43Sitojun case IPV6CTL_V6ONLY: 14561.43Sitojun#ifdef INET6_BINDV6ONLY 14571.43Sitojun return sysctl_rdint(oldp, oldlenp, newp, ip6_v6only); 14581.43Sitojun#else 14591.43Sitojun return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_v6only); 14601.26Sitojun#endif 14611.26Sitojun case IPV6CTL_ANONPORTMIN: 14621.26Sitojun old = ip6_anonportmin; 14631.26Sitojun error = sysctl_int(oldp, oldlenp, newp, newlen, 14641.26Sitojun &ip6_anonportmin); 14651.26Sitojun if (ip6_anonportmin >= ip6_anonportmax || ip6_anonportmin < 0 || 14661.26Sitojun ip6_anonportmin > 65535 14671.26Sitojun#ifndef IPNOPRIVPORTS 14681.26Sitojun || ip6_anonportmin < IPV6PORT_RESERVED 14691.26Sitojun#endif 14701.26Sitojun ) { 14711.26Sitojun ip6_anonportmin = old; 14721.26Sitojun return (EINVAL); 14731.26Sitojun } 14741.26Sitojun return (error); 14751.26Sitojun case IPV6CTL_ANONPORTMAX: 14761.26Sitojun old = ip6_anonportmax; 14771.26Sitojun error = sysctl_int(oldp, oldlenp, newp, newlen, 14781.26Sitojun &ip6_anonportmax); 14791.26Sitojun if (ip6_anonportmin >= ip6_anonportmax || ip6_anonportmax < 0 || 14801.26Sitojun ip6_anonportmax > 65535 14811.26Sitojun#ifndef IPNOPRIVPORTS 14821.26Sitojun || ip6_anonportmax < IPV6PORT_RESERVED 14831.26Sitojun#endif 14841.26Sitojun ) { 14851.26Sitojun ip6_anonportmax = old; 14861.26Sitojun return (EINVAL); 14871.26Sitojun } 14881.26Sitojun return (error); 14891.26Sitojun#ifndef IPNOPRIVPORTS 14901.26Sitojun case IPV6CTL_LOWPORTMIN: 14911.26Sitojun old = ip6_lowportmin; 14921.26Sitojun error = sysctl_int(oldp, oldlenp, newp, newlen, 14931.26Sitojun &ip6_lowportmin); 14941.26Sitojun if (ip6_lowportmin >= ip6_lowportmax || 14951.26Sitojun ip6_lowportmin > IPV6PORT_RESERVEDMAX || 14961.26Sitojun ip6_lowportmin < IPV6PORT_RESERVEDMIN) { 14971.26Sitojun ip6_lowportmin = old; 14981.26Sitojun return (EINVAL); 14991.26Sitojun } 15001.26Sitojun return (error); 15011.26Sitojun case IPV6CTL_LOWPORTMAX: 15021.26Sitojun old = ip6_lowportmax; 15031.26Sitojun error = sysctl_int(oldp, oldlenp, newp, newlen, 15041.26Sitojun &ip6_lowportmax); 15051.26Sitojun if (ip6_lowportmin >= ip6_lowportmax || 15061.26Sitojun ip6_lowportmax > IPV6PORT_RESERVEDMAX || 15071.26Sitojun ip6_lowportmax < IPV6PORT_RESERVEDMIN) { 15081.26Sitojun ip6_lowportmax = old; 15091.26Sitojun return (EINVAL); 15101.26Sitojun } 15111.26Sitojun return (error); 15121.11Sitojun#endif 15131.2Sitojun default: 15141.2Sitojun return EOPNOTSUPP; 15151.2Sitojun } 15161.2Sitojun /* NOTREACHED */ 15171.2Sitojun} 1518