ip6_input.c revision 121143
162587Sitojun/* $FreeBSD: head/sys/netinet6/ip6_input.c 121143 2003-10-16 18:57:45Z sam $ */ 295023Ssuz/* $KAME: ip6_input.c,v 1.259 2002/01/21 04:58:09 jinmei Exp $ */ 362587Sitojun 453541Sshin/* 553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 653541Sshin * All rights reserved. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. Neither the name of the project nor the names of its contributors 1753541Sshin * may be used to endorse or promote products derived from this software 1853541Sshin * without specific prior written permission. 1953541Sshin * 2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2353541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3053541Sshin * SUCH DAMAGE. 3153541Sshin */ 3253541Sshin 3353541Sshin/* 3453541Sshin * Copyright (c) 1982, 1986, 1988, 1993 3553541Sshin * The Regents of the University of California. All rights reserved. 3653541Sshin * 3753541Sshin * Redistribution and use in source and binary forms, with or without 3853541Sshin * modification, are permitted provided that the following conditions 3953541Sshin * are met: 4053541Sshin * 1. Redistributions of source code must retain the above copyright 4153541Sshin * notice, this list of conditions and the following disclaimer. 4253541Sshin * 2. Redistributions in binary form must reproduce the above copyright 4353541Sshin * notice, this list of conditions and the following disclaimer in the 4453541Sshin * documentation and/or other materials provided with the distribution. 4553541Sshin * 3. All advertising materials mentioning features or use of this software 4653541Sshin * must display the following acknowledgement: 4753541Sshin * This product includes software developed by the University of 4853541Sshin * California, Berkeley and its contributors. 4953541Sshin * 4. Neither the name of the University nor the names of its contributors 5053541Sshin * may be used to endorse or promote products derived from this software 5153541Sshin * without specific prior written permission. 5253541Sshin * 5353541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5453541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5553541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5653541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5753541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5853541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5953541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6053541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6153541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6253541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6353541Sshin * SUCH DAMAGE. 6453541Sshin * 6553541Sshin * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 6653541Sshin */ 6753541Sshin 6862587Sitojun#include "opt_ip6fw.h" 6962587Sitojun#include "opt_inet.h" 7062587Sitojun#include "opt_inet6.h" 7155009Sshin#include "opt_ipsec.h" 7264060Sdarrenr#include "opt_pfil_hooks.h" 73120649Sume#include "opt_random_ip_id.h" 7455009Sshin 7553541Sshin#include <sys/param.h> 7653541Sshin#include <sys/systm.h> 7778064Sume#include <sys/malloc.h> 7853541Sshin#include <sys/mbuf.h> 7983366Sjulian#include <sys/proc.h> 8053541Sshin#include <sys/domain.h> 8153541Sshin#include <sys/protosw.h> 8253541Sshin#include <sys/socket.h> 8353541Sshin#include <sys/socketvar.h> 8453541Sshin#include <sys/errno.h> 8553541Sshin#include <sys/time.h> 8653541Sshin#include <sys/kernel.h> 8753541Sshin#include <sys/syslog.h> 8853541Sshin 8953541Sshin#include <net/if.h> 9053541Sshin#include <net/if_types.h> 9153541Sshin#include <net/if_dl.h> 9253541Sshin#include <net/route.h> 9353541Sshin#include <net/netisr.h> 9464060Sdarrenr#ifdef PFIL_HOOKS 9564060Sdarrenr#include <net/pfil.h> 9664060Sdarrenr#endif 9753541Sshin 9853541Sshin#include <netinet/in.h> 9953541Sshin#include <netinet/in_systm.h> 10062587Sitojun#ifdef INET 10153541Sshin#include <netinet/ip.h> 10253541Sshin#include <netinet/ip_icmp.h> 10395023Ssuz#endif /* INET */ 10462587Sitojun#include <netinet/ip6.h> 10553541Sshin#include <netinet6/in6_var.h> 10653541Sshin#include <netinet6/ip6_var.h> 10762587Sitojun#include <netinet/in_pcb.h> 10862587Sitojun#include <netinet/icmp6.h> 10953541Sshin#include <netinet6/in6_ifattach.h> 11053541Sshin#include <netinet6/nd6.h> 11153541Sshin#include <netinet6/in6_prefix.h> 11253541Sshin 11378064Sume#ifdef IPSEC 11478064Sume#include <netinet6/ipsec.h> 11578064Sume#ifdef INET6 11678064Sume#include <netinet6/ipsec6.h> 11778064Sume#endif 11878064Sume#endif 11978064Sume 120105199Ssam#ifdef FAST_IPSEC 121105199Ssam#include <netipsec/ipsec.h> 122105199Ssam#include <netipsec/ipsec6.h> 123105199Ssam#define IPSEC 124105199Ssam#endif /* FAST_IPSEC */ 125105199Ssam 12653541Sshin#include <netinet6/ip6_fw.h> 12753541Sshin 12853541Sshin#include <netinet6/ip6protosw.h> 12953541Sshin 13053541Sshin#include <net/net_osdep.h> 13153541Sshin 13262587Sitojunextern struct domain inet6domain; 13353541Sshin 13462587Sitojunu_char ip6_protox[IPPROTO_MAX]; 135111888Sjlemonstatic struct ifqueue ip6intrq; 13662587Sitojunstatic int ip6qmaxlen = IFQ_MAXLEN; 13762587Sitojunstruct in6_ifaddr *in6_ifaddr; 13853541Sshin 13978064Sumeextern struct callout in6_tmpaddrtimer_ch; 14078064Sume 14162587Sitojunint ip6_forward_srcrt; /* XXX */ 14262587Sitojunint ip6_sourcecheck; /* XXX */ 14362587Sitojunint ip6_sourcecheck_interval; /* XXX */ 14453541Sshin 14578064Sumeint ip6_ours_check_algorithm; 14678064Sume 147120386Ssam#ifdef PFIL_HOOKS 148120386Ssamstruct pfil_head inet6_pfil_hook; 149120386Ssam#endif 15078064Sume 15153541Sshin/* firewall hooks */ 15262587Sitojunip6_fw_chk_t *ip6_fw_chk_ptr; 15362587Sitojunip6_fw_ctl_t *ip6_fw_ctl_ptr; 15466303Sumeint ip6_fw_enable = 1; 15553541Sshin 15662587Sitojunstruct ip6stat ip6stat; 15753541Sshin 15862587Sitojunstatic void ip6_init2 __P((void *)); 159105194Ssamstatic struct ip6aux *ip6_setdstifaddr __P((struct mbuf *, struct in6_ifaddr *)); 16062587Sitojunstatic int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); 16162587Sitojun#ifdef PULLDOWN_TEST 16262587Sitojunstatic struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int)); 16353541Sshin#endif 16453541Sshin 16553541Sshin/* 16653541Sshin * IP6 initialization: fill in IP6 protocol switch table. 16753541Sshin * All protocols not implemented in kernel go to raw IP6 protocol handler. 16853541Sshin */ 16953541Sshinvoid 17053541Sshinip6_init() 17153541Sshin{ 17278064Sume struct ip6protosw *pr; 17378064Sume int i; 17453541Sshin 17578064Sume#ifdef DIAGNOSTIC 17678064Sume if (sizeof(struct protosw) != sizeof(struct ip6protosw)) 17778064Sume panic("sizeof(protosw) != sizeof(ip6protosw)"); 17878064Sume#endif 17953541Sshin pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); 18053541Sshin if (pr == 0) 18153541Sshin panic("ip6_init"); 18253541Sshin for (i = 0; i < IPPROTO_MAX; i++) 18353541Sshin ip6_protox[i] = pr - inet6sw; 18453541Sshin for (pr = (struct ip6protosw *)inet6domain.dom_protosw; 18553541Sshin pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) 18653541Sshin if (pr->pr_domain->dom_family == PF_INET6 && 18753541Sshin pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 18853541Sshin ip6_protox[pr->pr_protocol] = pr - inet6sw; 189120386Ssam#ifdef PFIL_HOOKS 190120386Ssam inet6_pfil_hook.ph_type = PFIL_TYPE_AF; 191120386Ssam inet6_pfil_hook.ph_af = AF_INET6; 192120386Ssam if ((i = pfil_head_register(&inet6_pfil_hook)) != 0) 193120386Ssam printf("%s: WARNING: unable to register pfil hook, " 194120386Ssam "error %d\n", __func__, i); 195120386Ssam#endif /* PFIL_HOOKS */ 19653541Sshin ip6intrq.ifq_maxlen = ip6qmaxlen; 19793818Sjhb mtx_init(&ip6intrq.ifq_mtx, "ip6_inq", NULL, MTX_DEF); 198111888Sjlemon netisr_register(NETISR_IPV6, ip6_input, &ip6intrq); 19953541Sshin nd6_init(); 20053541Sshin frag6_init(); 201120649Sume#ifndef RANDOM_IP_ID 202120648Sume ip6_flow_seq = arc4random(); 203120649Sume#endif 204120648Sume ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR; 20553541Sshin} 20653541Sshin 20753541Sshinstatic void 20853541Sshinip6_init2(dummy) 20953541Sshin void *dummy; 21053541Sshin{ 21153541Sshin 21253541Sshin /* 21353541Sshin * to route local address of p2p link to loopback, 21453541Sshin * assign loopback address first. 21553541Sshin */ 21662587Sitojun in6_ifattach(&loif[0], NULL); 21753541Sshin 21853541Sshin /* nd6_timer_init */ 21978064Sume callout_init(&nd6_timer_ch, 0); 22078064Sume callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); 22178064Sume 22253541Sshin /* router renumbering prefix list maintenance */ 22378064Sume callout_init(&in6_rr_timer_ch, 0); 22478064Sume callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL); 22578064Sume 22678064Sume /* timer for regeneranation of temporary addresses randomize ID */ 22778064Sume callout_reset(&in6_tmpaddrtimer_ch, 22878064Sume (ip6_temp_preferred_lifetime - ip6_desync_factor - 22978064Sume ip6_temp_regen_advance) * hz, 23078064Sume in6_tmpaddrtimer, NULL); 23153541Sshin} 23253541Sshin 23353541Sshin/* cheat */ 23455009Sshin/* This must be after route_init(), which is now SI_ORDER_THIRD */ 23555009SshinSYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL); 23653541Sshin 23753541Sshinextern struct route_in6 ip6_forward_rt; 23853541Sshin 23953541Sshinvoid 24053541Sshinip6_input(m) 24153541Sshin struct mbuf *m; 24253541Sshin{ 24353541Sshin struct ip6_hdr *ip6; 24453541Sshin int off = sizeof(struct ip6_hdr), nest; 24553541Sshin u_int32_t plen; 24653541Sshin u_int32_t rtalert = ~0; 24753541Sshin int nxt, ours = 0; 24853541Sshin struct ifnet *deliverifp = NULL; 24953541Sshin 250121143Ssam#ifdef PFIL_HOOKS 251121143Ssam struct in6_addr odst; 252121143Ssam#endif 253121143Ssam int srcrt = 0; 25453541Sshin#ifdef IPSEC 25553541Sshin /* 25653541Sshin * should the inner packet be considered authentic? 25753541Sshin * see comment in ah4_input(). 25853541Sshin */ 25953541Sshin if (m) { 26053541Sshin m->m_flags &= ~M_AUTHIPHDR; 26153541Sshin m->m_flags &= ~M_AUTHIPDGM; 26253541Sshin } 26353541Sshin#endif 26453541Sshin 26553541Sshin /* 26678064Sume * make sure we don't have onion peering information into m_aux. 26778064Sume */ 26878064Sume ip6_delaux(m); 26978064Sume 27078064Sume /* 27195023Ssuz * mbuf statistics 27253541Sshin */ 27353541Sshin if (m->m_flags & M_EXT) { 27453541Sshin if (m->m_next) 27553541Sshin ip6stat.ip6s_mext2m++; 27653541Sshin else 27753541Sshin ip6stat.ip6s_mext1++; 27853541Sshin } else { 27978064Sume#define M2MMAX (sizeof(ip6stat.ip6s_m2m)/sizeof(ip6stat.ip6s_m2m[0])) 28053541Sshin if (m->m_next) { 28153541Sshin if (m->m_flags & M_LOOP) { 282120913Sume ip6stat.ip6s_m2m[loif[0].if_index]++; /* XXX */ 28378064Sume } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) 28453541Sshin ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; 28553541Sshin else 28653541Sshin ip6stat.ip6s_m2m[0]++; 28753541Sshin } else 28853541Sshin ip6stat.ip6s_m1++; 28978064Sume#undef M2MMAX 29053541Sshin } 29153541Sshin 29253541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); 29353541Sshin ip6stat.ip6s_total++; 29453541Sshin 29562587Sitojun#ifndef PULLDOWN_TEST 29674336Skuriyama /* 29774336Skuriyama * L2 bridge code and some other code can return mbuf chain 29874336Skuriyama * that does not conform to KAME requirement. too bad. 29974336Skuriyama * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? 30074336Skuriyama */ 30174336Skuriyama if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { 30274336Skuriyama struct mbuf *n; 30374336Skuriyama 304111119Simp MGETHDR(n, M_DONTWAIT, MT_HEADER); 30577003Sume if (n) 306108466Ssam M_MOVE_PKTHDR(n, m); 307108825Ssam if (n && n->m_pkthdr.len > MHLEN) { 308111119Simp MCLGET(n, M_DONTWAIT); 30974336Skuriyama if ((n->m_flags & M_EXT) == 0) { 31074336Skuriyama m_freem(n); 31174336Skuriyama n = NULL; 31274336Skuriyama } 31374336Skuriyama } 31495023Ssuz if (n == NULL) { 31577003Sume m_freem(m); 316120913Sume return; /* ENOBUFS */ 31777003Sume } 31874336Skuriyama 319108825Ssam m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); 320108825Ssam n->m_len = n->m_pkthdr.len; 32174336Skuriyama m_freem(m); 32274336Skuriyama m = n; 32374336Skuriyama } 324120913Sume IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */); 32562587Sitojun#endif 32653541Sshin 32753541Sshin if (m->m_len < sizeof(struct ip6_hdr)) { 32853541Sshin struct ifnet *inifp; 32953541Sshin inifp = m->m_pkthdr.rcvif; 330120913Sume if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 33153541Sshin ip6stat.ip6s_toosmall++; 33253541Sshin in6_ifstat_inc(inifp, ifs6_in_hdrerr); 33353541Sshin return; 33453541Sshin } 33553541Sshin } 33653541Sshin 33753541Sshin ip6 = mtod(m, struct ip6_hdr *); 33853541Sshin 33953541Sshin if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 34053541Sshin ip6stat.ip6s_badvers++; 34153541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 34253541Sshin goto bad; 34353541Sshin } 34453541Sshin 34564060Sdarrenr#ifdef PFIL_HOOKS 34664060Sdarrenr /* 347120386Ssam * Run through list of hooks for input packets. 34864060Sdarrenr */ 349120386Ssam if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN)) 350120386Ssam return; 351120386Ssam if (m == NULL) /* consumed by filter */ 352120386Ssam return; 353121143Ssam * 354121143Ssam * NB: Beware of the destination address changing 355121143Ssam * (e.g. by NAT rewriting). When this happens, 356121143Ssam * tell ip6_forward to do the right thing. 357120386Ssam ip6 = mtod(m, struct ip6_hdr *); 358121143Ssam odst = ip6->ip6_dst; 35964060Sdarrenr#endif /* PFIL_HOOKS */ 36064060Sdarrenr 36153541Sshin ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; 36253541Sshin 36353541Sshin /* 36453541Sshin * Check with the firewall... 36553541Sshin */ 36666303Sume if (ip6_fw_enable && ip6_fw_chk_ptr) { 36753541Sshin u_short port = 0; 368121143Ssam srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); 36953541Sshin /* If ipfw says divert, we have to just drop packet */ 37053541Sshin /* use port as a dummy argument */ 37153541Sshin if ((*ip6_fw_chk_ptr)(&ip6, NULL, &port, &m)) { 37253541Sshin m_freem(m); 37353541Sshin m = NULL; 37453541Sshin } 37553541Sshin if (!m) 37653541Sshin return; 37753541Sshin } 37853541Sshin 37953541Sshin /* 38078064Sume * Check against address spoofing/corruption. 38153541Sshin */ 38253541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || 38353541Sshin IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { 38478064Sume /* 38578064Sume * XXX: "badscope" is not very suitable for a multicast source. 38678064Sume */ 38753541Sshin ip6stat.ip6s_badscope++; 38853541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 38953541Sshin goto bad; 39053541Sshin } 39178064Sume if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || 39278064Sume IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) && 39378064Sume (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 39478064Sume ip6stat.ip6s_badscope++; 39578064Sume in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 39678064Sume goto bad; 39778064Sume } 39895023Ssuz 39962587Sitojun /* 40078064Sume * The following check is not documented in specs. A malicious 40178064Sume * party may be able to use IPv4 mapped addr to confuse tcp/udp stack 40278064Sume * and bypass security checks (act as if it was from 127.0.0.1 by using 403120913Sume * IPv6 src ::ffff:127.0.0.1). Be cautious. 40478064Sume * 40578064Sume * This check chokes if we are in an SIIT cloud. As none of BSDs 40678064Sume * support IPv4-less kernel compilation, we cannot support SIIT 40778064Sume * environment at all. So, it makes more sense for us to reject any 40878064Sume * malicious packets for non-SIIT environment, than try to do a 409120913Sume * partial support for SIIT environment. 41062587Sitojun */ 41178064Sume if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 41278064Sume IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 41378064Sume ip6stat.ip6s_badscope++; 41478064Sume in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 41578064Sume goto bad; 41678064Sume } 41762587Sitojun#if 0 41862587Sitojun /* 41962587Sitojun * Reject packets with IPv4 compatible addresses (auto tunnel). 42062587Sitojun * 42162587Sitojun * The code forbids auto tunnel relay case in RFC1933 (the check is 42262587Sitojun * stronger than RFC1933). We may want to re-enable it if mech-xx 42362587Sitojun * is revised to forbid relaying case. 42462587Sitojun */ 42562587Sitojun if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || 42662587Sitojun IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { 42762587Sitojun ip6stat.ip6s_badscope++; 42862587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 42962587Sitojun goto bad; 43062587Sitojun } 43162587Sitojun#endif 43275246Sume 43378064Sume /* drop packets if interface ID portion is already filled */ 43478064Sume if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 43578064Sume if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) && 43678064Sume ip6->ip6_src.s6_addr16[1]) { 43753541Sshin ip6stat.ip6s_badscope++; 43853541Sshin goto bad; 43953541Sshin } 44078064Sume if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst) && 44178064Sume ip6->ip6_dst.s6_addr16[1]) { 44278064Sume ip6stat.ip6s_badscope++; 44378064Sume goto bad; 44478064Sume } 44553541Sshin } 44653541Sshin 44778064Sume if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 44878064Sume ip6->ip6_src.s6_addr16[1] 44978064Sume = htons(m->m_pkthdr.rcvif->if_index); 45078064Sume if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 45178064Sume ip6->ip6_dst.s6_addr16[1] 45278064Sume = htons(m->m_pkthdr.rcvif->if_index); 45353541Sshin 45453541Sshin /* 45553541Sshin * Multicast check 45653541Sshin */ 45753541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 458120913Sume struct in6_multi *in6m = 0; 45953541Sshin 46053541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); 46153541Sshin /* 46253541Sshin * See if we belong to the destination multicast group on the 46353541Sshin * arrival interface. 46453541Sshin */ 46553541Sshin IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m); 46653541Sshin if (in6m) 46753541Sshin ours = 1; 46856723Sshin else if (!ip6_mrouter) { 46953541Sshin ip6stat.ip6s_notmember++; 47053541Sshin ip6stat.ip6s_cantforward++; 47153541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 47253541Sshin goto bad; 47353541Sshin } 47453541Sshin deliverifp = m->m_pkthdr.rcvif; 47553541Sshin goto hbhcheck; 47653541Sshin } 47753541Sshin 47853541Sshin /* 47953541Sshin * Unicast check 48053541Sshin */ 48162587Sitojun if (ip6_forward_rt.ro_rt != NULL && 482120913Sume (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && 48362587Sitojun IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 484120913Sume &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr)) 48562587Sitojun ip6stat.ip6s_forward_cachehit++; 48662587Sitojun else { 48778064Sume struct sockaddr_in6 *dst6; 48878064Sume 48953541Sshin if (ip6_forward_rt.ro_rt) { 49062587Sitojun /* route is down or destination is different */ 49162587Sitojun ip6stat.ip6s_forward_cachemiss++; 49253541Sshin RTFREE(ip6_forward_rt.ro_rt); 49353541Sshin ip6_forward_rt.ro_rt = 0; 49453541Sshin } 49562587Sitojun 49653541Sshin bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6)); 49778064Sume dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst; 49878064Sume dst6->sin6_len = sizeof(struct sockaddr_in6); 49978064Sume dst6->sin6_family = AF_INET6; 50078064Sume dst6->sin6_addr = ip6->ip6_dst; 50153541Sshin 50253541Sshin rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); 50353541Sshin } 50453541Sshin 50553541Sshin#define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) 50653541Sshin 50753541Sshin /* 50853541Sshin * Accept the packet if the forwarding interface to the destination 50953541Sshin * according to the routing table is the loopback interface, 51053541Sshin * unless the associated route has a gateway. 51153541Sshin * Note that this approach causes to accept a packet if there is a 51253541Sshin * route to the loopback interface for the destination of the packet. 51353541Sshin * But we think it's even useful in some situations, e.g. when using 51453541Sshin * a special daemon which wants to intercept the packet. 51578064Sume * 51678064Sume * XXX: some OSes automatically make a cloned route for the destination 51778064Sume * of an outgoing packet. If the outgoing interface of the packet 51878064Sume * is a loopback one, the kernel would consider the packet to be 51978064Sume * accepted, even if we have no such address assinged on the interface. 52078064Sume * We check the cloned flag of the route entry to reject such cases, 52178064Sume * assuming that route entries for our own addresses are not made by 52278064Sume * cloning (it should be true because in6_addloop explicitly installs 52378064Sume * the host route). However, we might have to do an explicit check 52478064Sume * while it would be less efficient. Or, should we rather install a 52578064Sume * reject route for such a case? 52653541Sshin */ 52753541Sshin if (ip6_forward_rt.ro_rt && 52853541Sshin (ip6_forward_rt.ro_rt->rt_flags & 52953541Sshin (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && 53078064Sume#ifdef RTF_WASCLONED 53178064Sume !(ip6_forward_rt.ro_rt->rt_flags & RTF_WASCLONED) && 53278064Sume#endif 53378064Sume#ifdef RTF_CLONED 53478064Sume !(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) && 53578064Sume#endif 53662587Sitojun#if 0 53753541Sshin /* 53862587Sitojun * The check below is redundant since the comparison of 53962587Sitojun * the destination and the key of the rtentry has 54062587Sitojun * already done through looking up the routing table. 54153541Sshin */ 54262587Sitojun IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 543120913Sume &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) 54462587Sitojun#endif 54553541Sshin ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { 54653541Sshin struct in6_ifaddr *ia6 = 54753541Sshin (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa; 54878064Sume 54962587Sitojun /* 55078064Sume * record address information into m_aux. 55178064Sume */ 55278064Sume (void)ip6_setdstifaddr(m, ia6); 55378064Sume 55478064Sume /* 55562587Sitojun * packets to a tentative, duplicated, or somehow invalid 55662587Sitojun * address must not be accepted. 55762587Sitojun */ 55853541Sshin if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { 55962587Sitojun /* this address is ready */ 56053541Sshin ours = 1; 56153541Sshin deliverifp = ia6->ia_ifp; /* correct? */ 56267334Sjoe /* Count the packet in the ip address stats */ 56367334Sjoe ia6->ia_ifa.if_ipackets++; 56467334Sjoe ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; 56553541Sshin goto hbhcheck; 56653541Sshin } else { 56762587Sitojun /* address is not ready, so discard the packet. */ 56878064Sume nd6log((LOG_INFO, 56978064Sume "ip6_input: packet to an unready address %s->%s\n", 57062587Sitojun ip6_sprintf(&ip6->ip6_src), 57178064Sume ip6_sprintf(&ip6->ip6_dst))); 57262587Sitojun 57362587Sitojun goto bad; 57453541Sshin } 57553541Sshin } 57653541Sshin 57753541Sshin /* 578120913Sume * FAITH (Firewall Aided Internet Translator) 57953541Sshin */ 58053541Sshin if (ip6_keepfaith) { 58153541Sshin if (ip6_forward_rt.ro_rt && ip6_forward_rt.ro_rt->rt_ifp 58253541Sshin && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) { 58353541Sshin /* XXX do we need more sanity checks? */ 58453541Sshin ours = 1; 58595023Ssuz deliverifp = ip6_forward_rt.ro_rt->rt_ifp; /* faith */ 58653541Sshin goto hbhcheck; 58753541Sshin } 58853541Sshin } 58953541Sshin 59053541Sshin /* 59153541Sshin * Now there is no reason to process the packet if it's not our own 59253541Sshin * and we're not a router. 59353541Sshin */ 59453541Sshin if (!ip6_forwarding) { 59553541Sshin ip6stat.ip6s_cantforward++; 59653541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 59753541Sshin goto bad; 59853541Sshin } 59953541Sshin 60053541Sshin hbhcheck: 60153541Sshin /* 60278064Sume * record address information into m_aux, if we don't have one yet. 60378064Sume * note that we are unable to record it, if the address is not listed 60478064Sume * as our interface address (e.g. multicast addresses, addresses 60578064Sume * within FAITH prefixes and such). 60678064Sume */ 60778064Sume if (deliverifp && !ip6_getdstifaddr(m)) { 60878064Sume struct in6_ifaddr *ia6; 60978064Sume 61078064Sume ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); 61178064Sume if (ia6) { 61278064Sume if (!ip6_setdstifaddr(m, ia6)) { 61378064Sume /* 61478064Sume * XXX maybe we should drop the packet here, 61578064Sume * as we could not provide enough information 61678064Sume * to the upper layers. 61778064Sume */ 61878064Sume } 61978064Sume } 62078064Sume } 62178064Sume 62278064Sume /* 62353541Sshin * Process Hop-by-Hop options header if it's contained. 62453541Sshin * m may be modified in ip6_hopopts_input(). 62553541Sshin * If a JumboPayload option is included, plen will also be modified. 62653541Sshin */ 62753541Sshin plen = (u_int32_t)ntohs(ip6->ip6_plen); 62853541Sshin if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { 62962587Sitojun struct ip6_hbh *hbh; 63062587Sitojun 63153541Sshin if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) { 63262587Sitojun#if 0 /*touches NULL pointer*/ 63353541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 63462587Sitojun#endif 63553541Sshin return; /* m have already been freed */ 63653541Sshin } 63762587Sitojun 63853541Sshin /* adjust pointer */ 63953541Sshin ip6 = mtod(m, struct ip6_hdr *); 64053541Sshin 64153541Sshin /* 64295023Ssuz * if the payload length field is 0 and the next header field 64362587Sitojun * indicates Hop-by-Hop Options header, then a Jumbo Payload 64462587Sitojun * option MUST be included. 64562587Sitojun */ 64662587Sitojun if (ip6->ip6_plen == 0 && plen == 0) { 64762587Sitojun /* 64862587Sitojun * Note that if a valid jumbo payload option is 649120913Sume * contained, ip6_hopopts_input() must set a valid 650120913Sume * (non-zero) payload length to the variable plen. 65162587Sitojun */ 65262587Sitojun ip6stat.ip6s_badoptions++; 65362587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 65462587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 65562587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 65662587Sitojun ICMP6_PARAMPROB_HEADER, 65762587Sitojun (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); 65862587Sitojun return; 65962587Sitojun } 66062587Sitojun#ifndef PULLDOWN_TEST 66162587Sitojun /* ip6_hopopts_input() ensures that mbuf is contiguous */ 66262587Sitojun hbh = (struct ip6_hbh *)(ip6 + 1); 66362587Sitojun#else 66462587Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), 66562587Sitojun sizeof(struct ip6_hbh)); 66662587Sitojun if (hbh == NULL) { 66762587Sitojun ip6stat.ip6s_tooshort++; 66862587Sitojun return; 66962587Sitojun } 67062587Sitojun#endif 67162587Sitojun nxt = hbh->ip6h_nxt; 67262587Sitojun 67362587Sitojun /* 67453541Sshin * accept the packet if a router alert option is included 67553541Sshin * and we act as an IPv6 router. 67653541Sshin */ 67753541Sshin if (rtalert != ~0 && ip6_forwarding) 67853541Sshin ours = 1; 67953541Sshin } else 68053541Sshin nxt = ip6->ip6_nxt; 68153541Sshin 68253541Sshin /* 68353541Sshin * Check that the amount of data in the buffers 68453541Sshin * is as at least much as the IPv6 header would have us expect. 68553541Sshin * Trim mbufs if longer than we expect. 68653541Sshin * Drop packet if shorter than we expect. 68753541Sshin */ 68853541Sshin if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { 68953541Sshin ip6stat.ip6s_tooshort++; 69053541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 69153541Sshin goto bad; 69253541Sshin } 69353541Sshin if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { 69453541Sshin if (m->m_len == m->m_pkthdr.len) { 69553541Sshin m->m_len = sizeof(struct ip6_hdr) + plen; 69653541Sshin m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; 69753541Sshin } else 69853541Sshin m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); 69953541Sshin } 70053541Sshin 70153541Sshin /* 70253541Sshin * Forward if desirable. 70353541Sshin */ 70453541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 70556723Sshin /* 70656723Sshin * If we are acting as a multicast router, all 70756723Sshin * incoming multicast packets are passed to the 70856723Sshin * kernel-level multicast forwarding function. 70956723Sshin * The packet is returned (relatively) intact; if 71056723Sshin * ip6_mforward() returns a non-zero value, the packet 71156723Sshin * must be discarded, else it may be accepted below. 71256723Sshin */ 71356723Sshin if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { 71456723Sshin ip6stat.ip6s_cantforward++; 71556723Sshin m_freem(m); 71656723Sshin return; 71756723Sshin } 71853541Sshin if (!ours) { 71953541Sshin m_freem(m); 72053541Sshin return; 72153541Sshin } 72253541Sshin } else if (!ours) { 723121143Ssam ip6_forward(m, srcrt); 72453541Sshin return; 72553541Sshin } 72653541Sshin 72762587Sitojun ip6 = mtod(m, struct ip6_hdr *); 72862587Sitojun 72953541Sshin /* 73062587Sitojun * Malicious party may be able to use IPv4 mapped addr to confuse 73162587Sitojun * tcp/udp stack and bypass security checks (act as if it was from 73262587Sitojun * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious. 73362587Sitojun * 73462587Sitojun * For SIIT end node behavior, you may want to disable the check. 73562587Sitojun * However, you will become vulnerable to attacks using IPv4 mapped 73662587Sitojun * source. 73762587Sitojun */ 73862587Sitojun if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 73962587Sitojun IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 74062587Sitojun ip6stat.ip6s_badscope++; 74162587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 74262587Sitojun goto bad; 74362587Sitojun } 74462587Sitojun 74562587Sitojun /* 74653541Sshin * Tell launch routine the next header 74753541Sshin */ 74853541Sshin ip6stat.ip6s_delivered++; 74953541Sshin in6_ifstat_inc(deliverifp, ifs6_in_deliver); 75053541Sshin nest = 0; 75178064Sume 75253541Sshin while (nxt != IPPROTO_DONE) { 75353541Sshin if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { 75453541Sshin ip6stat.ip6s_toomanyhdr++; 75553541Sshin goto bad; 75653541Sshin } 75753541Sshin 75853541Sshin /* 75953541Sshin * protection against faulty packet - there should be 76053541Sshin * more sanity checks in header chain processing. 76153541Sshin */ 76253541Sshin if (m->m_pkthdr.len < off) { 76353541Sshin ip6stat.ip6s_tooshort++; 76453541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 76553541Sshin goto bad; 76653541Sshin } 76753541Sshin 76878064Sume#if 0 76978064Sume /* 77078064Sume * do we need to do it for every header? yeah, other 77178064Sume * functions can play with it (like re-allocate and copy). 77278064Sume */ 77378064Sume mhist = ip6_addaux(m); 77478064Sume if (mhist && M_TRAILINGSPACE(mhist) >= sizeof(nxt)) { 77578064Sume hist = mtod(mhist, caddr_t) + mhist->m_len; 77678064Sume bcopy(&nxt, hist, sizeof(nxt)); 77778064Sume mhist->m_len += sizeof(nxt); 77878064Sume } else { 77978064Sume ip6stat.ip6s_toomanyhdr++; 78078064Sume goto bad; 78178064Sume } 78278064Sume#endif 78378064Sume 78478064Sume#ifdef IPSEC 78578064Sume /* 78678064Sume * enforce IPsec policy checking if we are seeing last header. 78778064Sume * note that we do not visit this with protocols with pcb layer 78878064Sume * code - like udp/tcp/raw ip. 78978064Sume */ 79078064Sume if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 79178064Sume ipsec6_in_reject(m, NULL)) { 79278064Sume ipsec6stat.in_polvio++; 79378064Sume goto bad; 79478064Sume } 79578064Sume#endif 79653541Sshin nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); 79753541Sshin } 79853541Sshin return; 79953541Sshin bad: 80053541Sshin m_freem(m); 80153541Sshin} 80253541Sshin 80353541Sshin/* 80478064Sume * set/grab in6_ifaddr correspond to IPv6 destination address. 80578064Sume * XXX backward compatibility wrapper 80678064Sume */ 807105194Ssamstatic struct ip6aux * 80878064Sumeip6_setdstifaddr(m, ia6) 80978064Sume struct mbuf *m; 81078064Sume struct in6_ifaddr *ia6; 81178064Sume{ 812105194Ssam struct ip6aux *n; 81378064Sume 81478064Sume n = ip6_addaux(m); 81578064Sume if (n) 816105194Ssam n->ip6a_dstia6 = ia6; 81778064Sume return n; /* NULL if failed to set */ 81878064Sume} 81978064Sume 82078064Sumestruct in6_ifaddr * 82178064Sumeip6_getdstifaddr(m) 82278064Sume struct mbuf *m; 82378064Sume{ 824105194Ssam struct ip6aux *n; 82578064Sume 82678064Sume n = ip6_findaux(m); 82778064Sume if (n) 828105194Ssam return n->ip6a_dstia6; 82978064Sume else 83078064Sume return NULL; 83178064Sume} 83278064Sume 83378064Sume/* 83453541Sshin * Hop-by-Hop options header processing. If a valid jumbo payload option is 83553541Sshin * included, the real payload length will be stored in plenp. 83653541Sshin */ 83753541Sshinstatic int 83853541Sshinip6_hopopts_input(plenp, rtalertp, mp, offp) 83953541Sshin u_int32_t *plenp; 84053541Sshin u_int32_t *rtalertp; /* XXX: should be stored more smart way */ 84153541Sshin struct mbuf **mp; 84253541Sshin int *offp; 84353541Sshin{ 84478064Sume struct mbuf *m = *mp; 84553541Sshin int off = *offp, hbhlen; 84653541Sshin struct ip6_hbh *hbh; 84753541Sshin u_int8_t *opt; 84853541Sshin 84953541Sshin /* validation of the length of the header */ 85062587Sitojun#ifndef PULLDOWN_TEST 85153541Sshin IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); 85253541Sshin hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); 85353541Sshin hbhlen = (hbh->ip6h_len + 1) << 3; 85453541Sshin 85553541Sshin IP6_EXTHDR_CHECK(m, off, hbhlen, -1); 85653541Sshin hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); 85762587Sitojun#else 85862587Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, 85962587Sitojun sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); 86062587Sitojun if (hbh == NULL) { 86162587Sitojun ip6stat.ip6s_tooshort++; 86262587Sitojun return -1; 86362587Sitojun } 86462587Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 86562587Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), 86662587Sitojun hbhlen); 86762587Sitojun if (hbh == NULL) { 86862587Sitojun ip6stat.ip6s_tooshort++; 86962587Sitojun return -1; 87062587Sitojun } 87162587Sitojun#endif 87253541Sshin off += hbhlen; 87353541Sshin hbhlen -= sizeof(struct ip6_hbh); 87453541Sshin opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh); 87553541Sshin 87653541Sshin if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), 87753541Sshin hbhlen, rtalertp, plenp) < 0) 878120856Sume return (-1); 87953541Sshin 88053541Sshin *offp = off; 88153541Sshin *mp = m; 882120856Sume return (0); 88353541Sshin} 88453541Sshin 88553541Sshin/* 88653541Sshin * Search header for all Hop-by-hop options and process each option. 88753541Sshin * This function is separate from ip6_hopopts_input() in order to 88853541Sshin * handle a case where the sending node itself process its hop-by-hop 88953541Sshin * options header. In such a case, the function is called from ip6_output(). 89078064Sume * 89178064Sume * The function assumes that hbh header is located right after the IPv6 header 89278064Sume * (RFC2460 p7), opthead is pointer into data content in m, and opthead to 89378064Sume * opthead + hbhlen is located in continuous memory region. 89453541Sshin */ 89553541Sshinint 89653541Sshinip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) 89753541Sshin struct mbuf *m; 89853541Sshin u_int8_t *opthead; 89953541Sshin int hbhlen; 90053541Sshin u_int32_t *rtalertp; 90153541Sshin u_int32_t *plenp; 90253541Sshin{ 90353541Sshin struct ip6_hdr *ip6; 90453541Sshin int optlen = 0; 90553541Sshin u_int8_t *opt = opthead; 90653541Sshin u_int16_t rtalert_val; 90762587Sitojun u_int32_t jumboplen; 90878064Sume const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); 90953541Sshin 91053541Sshin for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { 91178064Sume switch (*opt) { 91278064Sume case IP6OPT_PAD1: 91378064Sume optlen = 1; 91478064Sume break; 91578064Sume case IP6OPT_PADN: 91678064Sume if (hbhlen < IP6OPT_MINLEN) { 91778064Sume ip6stat.ip6s_toosmall++; 91878064Sume goto bad; 91978064Sume } 92078064Sume optlen = *(opt + 1) + 2; 92178064Sume break; 92278064Sume case IP6OPT_RTALERT: 92362587Sitojun /* XXX may need check for alignment */ 92478064Sume if (hbhlen < IP6OPT_RTALERT_LEN) { 92578064Sume ip6stat.ip6s_toosmall++; 92678064Sume goto bad; 92778064Sume } 92878064Sume if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { 92978064Sume /* XXX stat */ 93078064Sume icmp6_error(m, ICMP6_PARAM_PROB, 931120913Sume ICMP6_PARAMPROB_HEADER, 932120913Sume erroff + opt + 1 - opthead); 933120856Sume return (-1); 93478064Sume } 93578064Sume optlen = IP6OPT_RTALERT_LEN; 93678064Sume bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); 93778064Sume *rtalertp = ntohs(rtalert_val); 93878064Sume break; 93978064Sume case IP6OPT_JUMBO: 94078064Sume /* XXX may need check for alignment */ 94162587Sitojun if (hbhlen < IP6OPT_JUMBO_LEN) { 94262587Sitojun ip6stat.ip6s_toosmall++; 94362587Sitojun goto bad; 94462587Sitojun } 94578064Sume if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { 94678064Sume /* XXX stat */ 94778064Sume icmp6_error(m, ICMP6_PARAM_PROB, 948120913Sume ICMP6_PARAMPROB_HEADER, 949120913Sume erroff + opt + 1 - opthead); 950120856Sume return (-1); 95178064Sume } 95262587Sitojun optlen = IP6OPT_JUMBO_LEN; 95353541Sshin 95462587Sitojun /* 95562587Sitojun * IPv6 packets that have non 0 payload length 95678064Sume * must not contain a jumbo payload option. 95762587Sitojun */ 95862587Sitojun ip6 = mtod(m, struct ip6_hdr *); 95962587Sitojun if (ip6->ip6_plen) { 96062587Sitojun ip6stat.ip6s_badoptions++; 96162587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 962120913Sume ICMP6_PARAMPROB_HEADER, 963120913Sume erroff + opt - opthead); 964120856Sume return (-1); 96562587Sitojun } 96653541Sshin 96762587Sitojun /* 96862587Sitojun * We may see jumbolen in unaligned location, so 96962587Sitojun * we'd need to perform bcopy(). 97062587Sitojun */ 97162587Sitojun bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); 97262587Sitojun jumboplen = (u_int32_t)htonl(jumboplen); 97362587Sitojun 97462587Sitojun#if 1 97562587Sitojun /* 97662587Sitojun * if there are multiple jumbo payload options, 97762587Sitojun * *plenp will be non-zero and the packet will be 97862587Sitojun * rejected. 97962587Sitojun * the behavior may need some debate in ipngwg - 98062587Sitojun * multiple options does not make sense, however, 98162587Sitojun * there's no explicit mention in specification. 98262587Sitojun */ 98362587Sitojun if (*plenp != 0) { 98462587Sitojun ip6stat.ip6s_badoptions++; 98562587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 986120913Sume ICMP6_PARAMPROB_HEADER, 987120913Sume erroff + opt + 2 - opthead); 988120856Sume return (-1); 98962587Sitojun } 99062587Sitojun#endif 99162587Sitojun 99262587Sitojun /* 99362587Sitojun * jumbo payload length must be larger than 65535. 99462587Sitojun */ 99562587Sitojun if (jumboplen <= IPV6_MAXPACKET) { 99662587Sitojun ip6stat.ip6s_badoptions++; 99762587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 998120913Sume ICMP6_PARAMPROB_HEADER, 999120913Sume erroff + opt + 2 - opthead); 1000120856Sume return (-1); 100162587Sitojun } 100262587Sitojun *plenp = jumboplen; 100362587Sitojun 100462587Sitojun break; 100578064Sume default: /* unknown option */ 100678064Sume if (hbhlen < IP6OPT_MINLEN) { 100778064Sume ip6stat.ip6s_toosmall++; 100878064Sume goto bad; 100978064Sume } 101078064Sume optlen = ip6_unknown_opt(opt, m, 101178064Sume erroff + opt - opthead); 101278064Sume if (optlen == -1) 1013120856Sume return (-1); 101478064Sume optlen += 2; 101578064Sume break; 101653541Sshin } 101753541Sshin } 101853541Sshin 1019120856Sume return (0); 102053541Sshin 102153541Sshin bad: 102253541Sshin m_freem(m); 1023120856Sume return (-1); 102453541Sshin} 102553541Sshin 102653541Sshin/* 102753541Sshin * Unknown option processing. 102853541Sshin * The third argument `off' is the offset from the IPv6 header to the option, 102953541Sshin * which is necessary if the IPv6 header the and option header and IPv6 header 103053541Sshin * is not continuous in order to return an ICMPv6 error. 103153541Sshin */ 103253541Sshinint 103353541Sshinip6_unknown_opt(optp, m, off) 103453541Sshin u_int8_t *optp; 103553541Sshin struct mbuf *m; 103653541Sshin int off; 103753541Sshin{ 103853541Sshin struct ip6_hdr *ip6; 103953541Sshin 104078064Sume switch (IP6OPT_TYPE(*optp)) { 104178064Sume case IP6OPT_TYPE_SKIP: /* ignore the option */ 1042120856Sume return ((int)*(optp + 1)); 104378064Sume case IP6OPT_TYPE_DISCARD: /* silently discard */ 104478064Sume m_freem(m); 1045120856Sume return (-1); 104678064Sume case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ 104778064Sume ip6stat.ip6s_badoptions++; 104878064Sume icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); 1049120856Sume return (-1); 105078064Sume case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ 105178064Sume ip6stat.ip6s_badoptions++; 105278064Sume ip6 = mtod(m, struct ip6_hdr *); 105378064Sume if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || 105478064Sume (m->m_flags & (M_BCAST|M_MCAST))) 105578064Sume m_freem(m); 105678064Sume else 105778064Sume icmp6_error(m, ICMP6_PARAM_PROB, 105878064Sume ICMP6_PARAMPROB_OPTION, off); 1059120856Sume return (-1); 106053541Sshin } 106153541Sshin 106253541Sshin m_freem(m); /* XXX: NOTREACHED */ 1063120856Sume return (-1); 106453541Sshin} 106553541Sshin 106653541Sshin/* 106762587Sitojun * Create the "control" list for this pcb. 106878064Sume * The function will not modify mbuf chain at all. 106962587Sitojun * 107078064Sume * with KAME mbuf chain restriction: 107162587Sitojun * The routine will be called from upper layer handlers like tcp6_input(). 107262587Sitojun * Thus the routine assumes that the caller (tcp6_input) have already 107362587Sitojun * called IP6_EXTHDR_CHECK() and all the extension headers are located in the 107462587Sitojun * very first mbuf on the mbuf chain. 107553541Sshin */ 107653541Sshinvoid 107753541Sshinip6_savecontrol(in6p, mp, ip6, m) 107878064Sume struct inpcb *in6p; 107978064Sume struct mbuf **mp; 108078064Sume struct ip6_hdr *ip6; 108178064Sume struct mbuf *m; 108253541Sshin{ 108397676Sume#if __FreeBSD_version >= 500000 108493593Sjhb struct thread *td = curthread; /* XXX */ 108593593Sjhb#else 108693593Sjhb struct proc *td = curproc; /* XXX */ 108793593Sjhb#endif 108878064Sume int privileged = 0; 108978064Sume int rthdr_exist = 0; 109053541Sshin 109178064Sume 109293593Sjhb if (td && !suser(td)) 1093120913Sume privileged++; 109453541Sshin 109578064Sume#ifdef SO_TIMESTAMP 109678064Sume if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) { 109753541Sshin struct timeval tv; 109853541Sshin 109953541Sshin microtime(&tv); 110053541Sshin *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 1101120913Sume SCM_TIMESTAMP, SOL_SOCKET); 110278064Sume if (*mp) { 110353541Sshin mp = &(*mp)->m_next; 110478064Sume } 110597658Stanimura } 110662587Sitojun#endif 110762587Sitojun 110853541Sshin /* RFC 2292 sec. 5 */ 110978064Sume if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) { 111053541Sshin struct in6_pktinfo pi6; 1111120913Sume 111253541Sshin bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); 111353541Sshin if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr)) 111453541Sshin pi6.ipi6_addr.s6_addr16[1] = 0; 1115120913Sume pi6.ipi6_ifindex = 1116120913Sume (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; 1117120913Sume 111853541Sshin *mp = sbcreatecontrol((caddr_t) &pi6, 1119120913Sume sizeof(struct in6_pktinfo), 1120120913Sume IPV6_PKTINFO, IPPROTO_IPV6); 1121120913Sume if (*mp) { 112253541Sshin mp = &(*mp)->m_next; 1123120913Sume } 112453541Sshin } 112578064Sume 112678064Sume if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) { 112753541Sshin int hlim = ip6->ip6_hlim & 0xff; 1128120913Sume 1129120913Sume *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), 1130120913Sume IPV6_HOPLIMIT, IPPROTO_IPV6); 1131120913Sume if (*mp) { 113253541Sshin mp = &(*mp)->m_next; 1133120913Sume } 113453541Sshin } 113553541Sshin 113653541Sshin /* 113753541Sshin * IPV6_HOPOPTS socket option. We require super-user privilege 113853541Sshin * for the option, but it might be too strict, since there might 113953541Sshin * be some hop-by-hop options which can be returned to normal user. 114053541Sshin * See RFC 2292 section 6. 114153541Sshin */ 114278064Sume if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) { 114353541Sshin /* 114453541Sshin * Check if a hop-by-hop options header is contatined in the 114553541Sshin * received packet, and if so, store the options as ancillary 114653541Sshin * data. Note that a hop-by-hop options header must be 1147120913Sume * just after the IPv6 header, which is assured through the 1148120913Sume * IPv6 input processing. 114953541Sshin */ 115053541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 115153541Sshin if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { 115262587Sitojun struct ip6_hbh *hbh; 115378064Sume int hbhlen = 0; 115478064Sume#ifdef PULLDOWN_TEST 115578064Sume struct mbuf *ext; 115678064Sume#endif 115753541Sshin 115862587Sitojun#ifndef PULLDOWN_TEST 115962587Sitojun hbh = (struct ip6_hbh *)(ip6 + 1); 116062587Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 116162587Sitojun#else 116278064Sume ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), 116378064Sume ip6->ip6_nxt); 116478064Sume if (ext == NULL) { 116562587Sitojun ip6stat.ip6s_tooshort++; 116662587Sitojun return; 116762587Sitojun } 116878064Sume hbh = mtod(ext, struct ip6_hbh *); 116962587Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 117078064Sume if (hbhlen != ext->m_len) { 117178064Sume m_freem(ext); 117262587Sitojun ip6stat.ip6s_tooshort++; 117362587Sitojun return; 117462587Sitojun } 117562587Sitojun#endif 117662587Sitojun 117753541Sshin /* 1178120913Sume * XXX: We copy the whole header even if a 1179120913Sume * jumbo payload option is included, the option which 1180120913Sume * is to be removed before returning according to 1181120913Sume * RFC2292. 118278064Sume * Note: this constraint is removed in 2292bis. 118353541Sshin */ 118462587Sitojun *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, 1185120913Sume IPV6_HOPOPTS, IPPROTO_IPV6); 1186120913Sume if (*mp) { 118753541Sshin mp = &(*mp)->m_next; 1188120913Sume } 118978064Sume#ifdef PULLDOWN_TEST 119078064Sume m_freem(ext); 119178064Sume#endif 119253541Sshin } 119353541Sshin } 119453541Sshin 119553541Sshin /* IPV6_DSTOPTS and IPV6_RTHDR socket options */ 119678064Sume if ((in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) { 119778064Sume int proto, off, nxt; 119878064Sume 119978064Sume /* 120078064Sume * go through the header chain to see if a routing header is 120178064Sume * contained in the packet. We need this information to store 120278064Sume * destination options headers (if any) properly. 120378064Sume * XXX: performance issue. We should record this info when 120478064Sume * processing extension headers in incoming routine. 120578064Sume * (todo) use m_aux? 120678064Sume */ 120778064Sume proto = IPPROTO_IPV6; 120878064Sume off = 0; 120978064Sume nxt = -1; 121078064Sume while (1) { 121178064Sume int newoff; 121278064Sume 121378064Sume newoff = ip6_nexthdr(m, off, proto, &nxt); 121478064Sume if (newoff < 0) 121578064Sume break; 121678064Sume if (newoff < off) /* invalid, check for safety */ 121778064Sume break; 121878064Sume if ((proto = nxt) == IPPROTO_ROUTING) { 121978064Sume rthdr_exist = 1; 122078064Sume break; 122178064Sume } 122278064Sume off = newoff; 122378064Sume } 122478064Sume } 122578064Sume 122678064Sume if ((in6p->in6p_flags & 122778064Sume (IN6P_RTHDR | IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) { 122853541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 122978064Sume int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); 123053541Sshin 123153541Sshin /* 123253541Sshin * Search for destination options headers or routing 123353541Sshin * header(s) through the header chain, and stores each 123453541Sshin * header as ancillary data. 123553541Sshin * Note that the order of the headers remains in 123653541Sshin * the chain of ancillary data. 123753541Sshin */ 123878064Sume while (1) { /* is explicit loop prevention necessary? */ 123978064Sume struct ip6_ext *ip6e = NULL; 124062587Sitojun int elen; 124178064Sume#ifdef PULLDOWN_TEST 124278064Sume struct mbuf *ext = NULL; 124378064Sume#endif 124453541Sshin 124578064Sume /* 124678064Sume * if it is not an extension header, don't try to 124778064Sume * pull it from the chain. 124878064Sume */ 124978064Sume switch (nxt) { 125078064Sume case IPPROTO_DSTOPTS: 125178064Sume case IPPROTO_ROUTING: 125278064Sume case IPPROTO_HOPOPTS: 125378064Sume case IPPROTO_AH: /* is it possible? */ 125478064Sume break; 125578064Sume default: 125678064Sume goto loopend; 125778064Sume } 125878064Sume 125962587Sitojun#ifndef PULLDOWN_TEST 126078064Sume if (off + sizeof(*ip6e) > m->m_len) 126178064Sume goto loopend; 126262587Sitojun ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); 126362587Sitojun if (nxt == IPPROTO_AH) 126462587Sitojun elen = (ip6e->ip6e_len + 2) << 2; 126562587Sitojun else 126662587Sitojun elen = (ip6e->ip6e_len + 1) << 3; 126778064Sume if (off + elen > m->m_len) 126878064Sume goto loopend; 126962587Sitojun#else 127078064Sume ext = ip6_pullexthdr(m, off, nxt); 127178064Sume if (ext == NULL) { 127262587Sitojun ip6stat.ip6s_tooshort++; 127362587Sitojun return; 127462587Sitojun } 127578064Sume ip6e = mtod(ext, struct ip6_ext *); 127662587Sitojun if (nxt == IPPROTO_AH) 127762587Sitojun elen = (ip6e->ip6e_len + 2) << 2; 127862587Sitojun else 127962587Sitojun elen = (ip6e->ip6e_len + 1) << 3; 128078064Sume if (elen != ext->m_len) { 128178064Sume m_freem(ext); 128262587Sitojun ip6stat.ip6s_tooshort++; 128362587Sitojun return; 128462587Sitojun } 128562587Sitojun#endif 128662587Sitojun 128778064Sume switch (nxt) { 128878064Sume case IPPROTO_DSTOPTS: 1289120913Sume if (!(in6p->in6p_flags & IN6P_DSTOPTS)) 129078064Sume break; 129153541Sshin 129278064Sume /* 129378064Sume * We also require super-user privilege for 1294120913Sume * the option. See comments on IN6_HOPOPTS. 129578064Sume */ 129678064Sume if (!privileged) 129778064Sume break; 129853541Sshin 129978064Sume *mp = sbcreatecontrol((caddr_t)ip6e, elen, 1300120913Sume IPV6_DSTOPTS, 1301120913Sume IPPROTO_IPV6); 130278064Sume if (*mp) 130378064Sume mp = &(*mp)->m_next; 130478064Sume break; 130578064Sume case IPPROTO_ROUTING: 130678064Sume if (!in6p->in6p_flags & IN6P_RTHDR) 130778064Sume break; 130853541Sshin 130978064Sume *mp = sbcreatecontrol((caddr_t)ip6e, elen, 1310120913Sume IPV6_RTHDR, 1311120913Sume IPPROTO_IPV6); 131278064Sume if (*mp) 131378064Sume mp = &(*mp)->m_next; 131478064Sume break; 131578064Sume case IPPROTO_HOPOPTS: 131678064Sume case IPPROTO_AH: /* is it possible? */ 131778064Sume break; 131853541Sshin 131978064Sume default: 132078064Sume /* 132178064Sume * other cases have been filtered in the above. 132278064Sume * none will visit this case. here we supply 132378064Sume * the code just in case (nxt overwritten or 132478064Sume * other cases). 132578064Sume */ 132678064Sume#ifdef PULLDOWN_TEST 132778064Sume m_freem(ext); 132878064Sume#endif 132978064Sume goto loopend; 133053541Sshin 133153541Sshin } 133253541Sshin 133353541Sshin /* proceed with the next header. */ 133462587Sitojun off += elen; 133553541Sshin nxt = ip6e->ip6e_nxt; 133678064Sume ip6e = NULL; 133778064Sume#ifdef PULLDOWN_TEST 133878064Sume m_freem(ext); 133978064Sume ext = NULL; 134078064Sume#endif 134153541Sshin } 134253541Sshin loopend: 134378064Sume ; 134453541Sshin } 134578064Sume 134678064Sume} 134778064Sume 134878064Sume#ifdef PULLDOWN_TEST 134978064Sume/* 135078064Sume * pull single extension header from mbuf chain. returns single mbuf that 135178064Sume * contains the result, or NULL on error. 135278064Sume */ 135378064Sumestatic struct mbuf * 135478064Sumeip6_pullexthdr(m, off, nxt) 135578064Sume struct mbuf *m; 135678064Sume size_t off; 135778064Sume int nxt; 135878064Sume{ 135978064Sume struct ip6_ext ip6e; 136078064Sume size_t elen; 136178064Sume struct mbuf *n; 136278064Sume 136378064Sume#ifdef DIAGNOSTIC 136478064Sume switch (nxt) { 136578064Sume case IPPROTO_DSTOPTS: 136678064Sume case IPPROTO_ROUTING: 136778064Sume case IPPROTO_HOPOPTS: 136878064Sume case IPPROTO_AH: /* is it possible? */ 136978064Sume break; 137078064Sume default: 137178064Sume printf("ip6_pullexthdr: invalid nxt=%d\n", nxt); 137253541Sshin } 137378064Sume#endif 137478064Sume 137578064Sume m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 137678064Sume if (nxt == IPPROTO_AH) 137778064Sume elen = (ip6e.ip6e_len + 2) << 2; 137878064Sume else 137978064Sume elen = (ip6e.ip6e_len + 1) << 3; 138078064Sume 1381111119Simp MGET(n, M_DONTWAIT, MT_DATA); 138278064Sume if (n && elen >= MLEN) { 1383111119Simp MCLGET(n, M_DONTWAIT); 138478064Sume if ((n->m_flags & M_EXT) == 0) { 138578064Sume m_free(n); 138678064Sume n = NULL; 138778064Sume } 138853541Sshin } 138978064Sume if (!n) 139078064Sume return NULL; 139162587Sitojun 139278064Sume n->m_len = 0; 139378064Sume if (elen >= M_TRAILINGSPACE(n)) { 139478064Sume m_free(n); 139578064Sume return NULL; 139678064Sume } 139778064Sume 139878064Sume m_copydata(m, off, elen, mtod(n, caddr_t)); 139978064Sume n->m_len = elen; 140078064Sume return n; 140153541Sshin} 140278064Sume#endif 140353541Sshin 140453541Sshin/* 140553541Sshin * Get pointer to the previous header followed by the header 140653541Sshin * currently processed. 140753541Sshin * XXX: This function supposes that 140853541Sshin * M includes all headers, 140953541Sshin * the next header field and the header length field of each header 141053541Sshin * are valid, and 141153541Sshin * the sum of each header length equals to OFF. 141253541Sshin * Because of these assumptions, this function must be called very 141353541Sshin * carefully. Moreover, it will not be used in the near future when 141453541Sshin * we develop `neater' mechanism to process extension headers. 141553541Sshin */ 141653541Sshinchar * 141753541Sshinip6_get_prevhdr(m, off) 141853541Sshin struct mbuf *m; 141953541Sshin int off; 142053541Sshin{ 142153541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 142253541Sshin 142353541Sshin if (off == sizeof(struct ip6_hdr)) 1424120856Sume return (&ip6->ip6_nxt); 142553541Sshin else { 142653541Sshin int len, nxt; 142753541Sshin struct ip6_ext *ip6e = NULL; 142853541Sshin 142953541Sshin nxt = ip6->ip6_nxt; 143053541Sshin len = sizeof(struct ip6_hdr); 143153541Sshin while (len < off) { 143253541Sshin ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); 143353541Sshin 143478064Sume switch (nxt) { 143553541Sshin case IPPROTO_FRAGMENT: 143653541Sshin len += sizeof(struct ip6_frag); 143753541Sshin break; 143853541Sshin case IPPROTO_AH: 143953541Sshin len += (ip6e->ip6e_len + 2) << 2; 144053541Sshin break; 144153541Sshin default: 144253541Sshin len += (ip6e->ip6e_len + 1) << 3; 144353541Sshin break; 144453541Sshin } 144553541Sshin nxt = ip6e->ip6e_nxt; 144653541Sshin } 144753541Sshin if (ip6e) 1448120856Sume return (&ip6e->ip6e_nxt); 144953541Sshin else 145053541Sshin return NULL; 145153541Sshin } 145253541Sshin} 145353541Sshin 145453541Sshin/* 145562587Sitojun * get next header offset. m will be retained. 145662587Sitojun */ 145762587Sitojunint 145862587Sitojunip6_nexthdr(m, off, proto, nxtp) 145962587Sitojun struct mbuf *m; 146062587Sitojun int off; 146162587Sitojun int proto; 146262587Sitojun int *nxtp; 146362587Sitojun{ 146462587Sitojun struct ip6_hdr ip6; 146562587Sitojun struct ip6_ext ip6e; 146662587Sitojun struct ip6_frag fh; 146762587Sitojun 146862587Sitojun /* just in case */ 146962587Sitojun if (m == NULL) 147062587Sitojun panic("ip6_nexthdr: m == NULL"); 147162587Sitojun if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) 147262587Sitojun return -1; 147362587Sitojun 147462587Sitojun switch (proto) { 147562587Sitojun case IPPROTO_IPV6: 147662587Sitojun if (m->m_pkthdr.len < off + sizeof(ip6)) 147762587Sitojun return -1; 147862587Sitojun m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); 147962587Sitojun if (nxtp) 148062587Sitojun *nxtp = ip6.ip6_nxt; 148162587Sitojun off += sizeof(ip6); 148262587Sitojun return off; 148362587Sitojun 148462587Sitojun case IPPROTO_FRAGMENT: 148562587Sitojun /* 148662587Sitojun * terminate parsing if it is not the first fragment, 148762587Sitojun * it does not make sense to parse through it. 148862587Sitojun */ 148962587Sitojun if (m->m_pkthdr.len < off + sizeof(fh)) 149062587Sitojun return -1; 149162587Sitojun m_copydata(m, off, sizeof(fh), (caddr_t)&fh); 1492120978Sume /* IP6F_OFF_MASK = 0xfff8(BigEndian), 0xf8ff(LittleEndian) */ 1493120978Sume if (fh.ip6f_offlg & IP6F_OFF_MASK) 149462587Sitojun return -1; 149562587Sitojun if (nxtp) 149662587Sitojun *nxtp = fh.ip6f_nxt; 149762587Sitojun off += sizeof(struct ip6_frag); 149862587Sitojun return off; 149962587Sitojun 150062587Sitojun case IPPROTO_AH: 150162587Sitojun if (m->m_pkthdr.len < off + sizeof(ip6e)) 150262587Sitojun return -1; 150362587Sitojun m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 150462587Sitojun if (nxtp) 150562587Sitojun *nxtp = ip6e.ip6e_nxt; 150662587Sitojun off += (ip6e.ip6e_len + 2) << 2; 150762587Sitojun return off; 150862587Sitojun 150962587Sitojun case IPPROTO_HOPOPTS: 151062587Sitojun case IPPROTO_ROUTING: 151162587Sitojun case IPPROTO_DSTOPTS: 151262587Sitojun if (m->m_pkthdr.len < off + sizeof(ip6e)) 151362587Sitojun return -1; 151462587Sitojun m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 151562587Sitojun if (nxtp) 151662587Sitojun *nxtp = ip6e.ip6e_nxt; 151762587Sitojun off += (ip6e.ip6e_len + 1) << 3; 151862587Sitojun return off; 151962587Sitojun 152062587Sitojun case IPPROTO_NONE: 152162587Sitojun case IPPROTO_ESP: 152262587Sitojun case IPPROTO_IPCOMP: 152362587Sitojun /* give up */ 152462587Sitojun return -1; 152562587Sitojun 152662587Sitojun default: 152762587Sitojun return -1; 152862587Sitojun } 152962587Sitojun 153062587Sitojun return -1; 153162587Sitojun} 153262587Sitojun 153362587Sitojun/* 153462587Sitojun * get offset for the last header in the chain. m will be kept untainted. 153562587Sitojun */ 153662587Sitojunint 153762587Sitojunip6_lasthdr(m, off, proto, nxtp) 153862587Sitojun struct mbuf *m; 153962587Sitojun int off; 154062587Sitojun int proto; 154162587Sitojun int *nxtp; 154262587Sitojun{ 154362587Sitojun int newoff; 154462587Sitojun int nxt; 154562587Sitojun 154662587Sitojun if (!nxtp) { 154762587Sitojun nxt = -1; 154862587Sitojun nxtp = &nxt; 154962587Sitojun } 155062587Sitojun while (1) { 155162587Sitojun newoff = ip6_nexthdr(m, off, proto, nxtp); 155262587Sitojun if (newoff < 0) 155362587Sitojun return off; 155462587Sitojun else if (newoff < off) 155562587Sitojun return -1; /* invalid */ 155662587Sitojun else if (newoff == off) 155762587Sitojun return newoff; 155862587Sitojun 155962587Sitojun off = newoff; 156062587Sitojun proto = *nxtp; 156162587Sitojun } 156262587Sitojun} 156362587Sitojun 1564105194Ssamstruct ip6aux * 156578064Sumeip6_addaux(m) 156678064Sume struct mbuf *m; 156778064Sume{ 1568120913Sume struct m_tag *mtag; 1569120913Sume 1570120913Sume mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); 1571120913Sume if (!mtag) { 1572120913Sume mtag = m_tag_get(PACKET_TAG_IPV6_INPUT, sizeof(struct ip6aux), 1573120913Sume M_NOWAIT); 1574120913Sume if (mtag) 1575120913Sume m_tag_prepend(m, mtag); 157678064Sume } 1577120913Sume if (mtag) 1578120913Sume bzero(mtag+1, sizeof (struct ip6aux)); 1579120913Sume return mtag ? (struct ip6aux*)(mtag+1) : NULL; 158078064Sume} 158178064Sume 1582105194Ssamstruct ip6aux * 158378064Sumeip6_findaux(m) 158478064Sume struct mbuf *m; 158578064Sume{ 1586120913Sume struct m_tag *mtag; 1587120913Sume 1588120913Sume mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); 1589120913Sume return mtag ? (struct ip6aux*)(mtag+1) : NULL; 159078064Sume} 159178064Sume 159278064Sumevoid 159378064Sumeip6_delaux(m) 159478064Sume struct mbuf *m; 159578064Sume{ 1596120913Sume struct m_tag *mtag; 1597120913Sume 1598120913Sume mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); 1599120913Sume if (mtag) 1600120913Sume m_tag_delete(m, mtag); 160178064Sume} 160278064Sume 160362587Sitojun/* 160453541Sshin * System control for IP6 160553541Sshin */ 160653541Sshin 160753541Sshinu_char inet6ctlerrmap[PRC_NCMDS] = { 160853541Sshin 0, 0, 0, 0, 160953541Sshin 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 161053541Sshin EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 161153541Sshin EMSGSIZE, EHOSTUNREACH, 0, 0, 161253541Sshin 0, 0, 0, 0, 161353541Sshin ENOPROTOOPT 161453541Sshin}; 1615