ip6_input.c revision 190787
1139826Simp/*- 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 28174510Sobrien * 29174510Sobrien * $KAME: ip6_input.c,v 1.259 2002/01/21 04:58:09 jinmei Exp $ 3053541Sshin */ 3153541Sshin 32139826Simp/*- 3353541Sshin * Copyright (c) 1982, 1986, 1988, 1993 3453541Sshin * The Regents of the University of California. All rights reserved. 3553541Sshin * 3653541Sshin * Redistribution and use in source and binary forms, with or without 3753541Sshin * modification, are permitted provided that the following conditions 3853541Sshin * are met: 3953541Sshin * 1. Redistributions of source code must retain the above copyright 4053541Sshin * notice, this list of conditions and the following disclaimer. 4153541Sshin * 2. Redistributions in binary form must reproduce the above copyright 4253541Sshin * notice, this list of conditions and the following disclaimer in the 4353541Sshin * documentation and/or other materials provided with the distribution. 4453541Sshin * 4. Neither the name of the University nor the names of its contributors 4553541Sshin * may be used to endorse or promote products derived from this software 4653541Sshin * without specific prior written permission. 4753541Sshin * 4853541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4953541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5053541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5153541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5253541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5353541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5453541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5553541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5653541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5753541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5853541Sshin * SUCH DAMAGE. 5953541Sshin * 6053541Sshin * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 6153541Sshin */ 6253541Sshin 63174510Sobrien#include <sys/cdefs.h> 64174510Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/ip6_input.c 190787 2009-04-06 22:29:41Z zec $"); 65174510Sobrien 6662587Sitojun#include "opt_inet.h" 6762587Sitojun#include "opt_inet6.h" 6855009Sshin#include "opt_ipsec.h" 69189106Sbz#include "opt_route.h" 7055009Sshin 7153541Sshin#include <sys/param.h> 7253541Sshin#include <sys/systm.h> 7378064Sume#include <sys/malloc.h> 7453541Sshin#include <sys/mbuf.h> 7583366Sjulian#include <sys/proc.h> 7653541Sshin#include <sys/domain.h> 7753541Sshin#include <sys/protosw.h> 7853541Sshin#include <sys/socket.h> 7953541Sshin#include <sys/socketvar.h> 8053541Sshin#include <sys/errno.h> 8153541Sshin#include <sys/time.h> 8253541Sshin#include <sys/kernel.h> 8353541Sshin#include <sys/syslog.h> 84181803Sbz#include <sys/vimage.h> 8553541Sshin 8653541Sshin#include <net/if.h> 8753541Sshin#include <net/if_types.h> 8853541Sshin#include <net/if_dl.h> 8953541Sshin#include <net/route.h> 9053541Sshin#include <net/netisr.h> 9164060Sdarrenr#include <net/pfil.h> 92185571Sbz#include <net/vnet.h> 9353541Sshin 9453541Sshin#include <netinet/in.h> 9553541Sshin#include <netinet/in_systm.h> 96186119Sqingli#include <net/if_llatbl.h> 9762587Sitojun#ifdef INET 9853541Sshin#include <netinet/ip.h> 9953541Sshin#include <netinet/ip_icmp.h> 100185571Sbz#include <netinet/vinet.h> 10195023Ssuz#endif /* INET */ 10262587Sitojun#include <netinet/ip6.h> 10353541Sshin#include <netinet6/in6_var.h> 10453541Sshin#include <netinet6/ip6_var.h> 10562587Sitojun#include <netinet/in_pcb.h> 10662587Sitojun#include <netinet/icmp6.h> 107121161Sume#include <netinet6/scope6_var.h> 10853541Sshin#include <netinet6/in6_ifattach.h> 10953541Sshin#include <netinet6/nd6.h> 110185571Sbz#include <netinet6/vinet6.h> 11153541Sshin 112171167Sgnn#ifdef IPSEC 113105199Ssam#include <netipsec/ipsec.h> 114171133Sgnn#include <netinet6/ip6_ipsec.h> 115105199Ssam#include <netipsec/ipsec6.h> 116171167Sgnn#endif /* IPSEC */ 117105199Ssam 11853541Sshin#include <netinet6/ip6protosw.h> 11953541Sshin 12062587Sitojunextern struct domain inet6domain; 12153541Sshin 12262587Sitojunu_char ip6_protox[IPPROTO_MAX]; 123111888Sjlemonstatic struct ifqueue ip6intrq; 124185088Szec 125185895Szec#ifndef VIMAGE 126185895Szec#ifndef VIMAGE_GLOBALS 127185895Szecstruct vnet_inet6 vnet_inet6_0; 128185895Szec#endif 129185895Szec#endif 130185895Szec 131185088Szec#ifdef VIMAGE_GLOBALS 132185088Szecstatic int ip6qmaxlen; 13362587Sitojunstruct in6_ifaddr *in6_ifaddr; 134185088Szecstruct ip6stat ip6stat; 13553541Sshin 13678064Sumeextern struct callout in6_tmpaddrtimer_ch; 13778064Sume 138185088Szecextern int dad_init; 139185088Szecextern int pmtu_expire; 140185088Szecextern int pmtu_probe; 141185088Szecextern u_long rip6_sendspace; 142185088Szecextern u_long rip6_recvspace; 143185088Szecextern int icmp6errppslim; 144185088Szecextern int icmp6_nodeinfo; 145185088Szecextern int udp6_sendspace; 146185088Szecextern int udp6_recvspace; 147185088Szec#endif 14878064Sume 149120386Ssamstruct pfil_head inet6_pfil_hook; 15078064Sume 151175162Sobrienstatic void ip6_init2(void *); 152175162Sobrienstatic struct ip6aux *ip6_setdstifaddr(struct mbuf *, struct in6_ifaddr *); 153175162Sobrienstatic int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); 15462587Sitojun#ifdef PULLDOWN_TEST 155175162Sobrienstatic struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); 15653541Sshin#endif 15753541Sshin 15853541Sshin/* 15953541Sshin * IP6 initialization: fill in IP6 protocol switch table. 16053541Sshin * All protocols not implemented in kernel go to raw IP6 protocol handler. 16153541Sshin */ 16253541Sshinvoid 163171259Sdelphijip6_init(void) 16453541Sshin{ 165183550Szec INIT_VNET_INET6(curvnet); 16678064Sume struct ip6protosw *pr; 16778064Sume int i; 16853541Sshin 169185088Szec V_ip6qmaxlen = IFQ_MAXLEN; 170185088Szec V_in6_maxmtu = 0; 171185088Szec#ifdef IP6_AUTO_LINKLOCAL 172185088Szec V_ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; 173185088Szec#else 174185088Szec V_ip6_auto_linklocal = 1; /* enable by default */ 175185088Szec#endif 176185895Szec TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal", 177185895Szec &V_ip6_auto_linklocal); 178185088Szec 179185088Szec#ifndef IPV6FORWARDING 180185088Szec#ifdef GATEWAY6 181185088Szec#define IPV6FORWARDING 1 /* forward IP6 packets not for us */ 182185088Szec#else 183185088Szec#define IPV6FORWARDING 0 /* don't forward IP6 packets not for us */ 184185088Szec#endif /* GATEWAY6 */ 185185088Szec#endif /* !IPV6FORWARDING */ 186185088Szec 187185088Szec#ifndef IPV6_SENDREDIRECTS 188185088Szec#define IPV6_SENDREDIRECTS 1 189185088Szec#endif 190185088Szec 191185088Szec V_ip6_forwarding = IPV6FORWARDING; /* act as router? */ 192185088Szec V_ip6_sendredirects = IPV6_SENDREDIRECTS; 193185088Szec V_ip6_defhlim = IPV6_DEFHLIM; 194185088Szec V_ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS; 195185088Szec V_ip6_accept_rtadv = 0; /* "IPV6FORWARDING ? 0 : 1" is dangerous */ 196185088Szec V_ip6_log_interval = 5; 197185088Szec V_ip6_hdrnestlimit = 15; /* How many header options will we process? */ 198185088Szec V_ip6_dad_count = 1; /* DupAddrDetectionTransmits */ 199185088Szec V_ip6_auto_flowlabel = 1; 200185088Szec V_ip6_use_deprecated = 1;/* allow deprecated addr (RFC2462 5.5.4) */ 201185088Szec V_ip6_rr_prune = 5; /* router renumbering prefix 202185088Szec * walk list every 5 sec. */ 203185088Szec V_ip6_mcast_pmtu = 0; /* enable pMTU discovery for multicast? */ 204185088Szec V_ip6_v6only = 1; 205185088Szec V_ip6_keepfaith = 0; 206185088Szec V_ip6_log_time = (time_t)0L; 207185088Szec#ifdef IPSTEALTH 208185088Szec V_ip6stealth = 0; 209185088Szec#endif 210185088Szec V_nd6_onlink_ns_rfc4861 = 0; /* allow 'on-link' nd6 NS (RFC 4861) */ 211185088Szec 212185088Szec V_pmtu_expire = 60*10; 213185088Szec V_pmtu_probe = 60*2; 214185088Szec 215185088Szec /* raw IP6 parameters */ 216185088Szec /* 217185088Szec * Nominal space allocated to a raw ip socket. 218185088Szec */ 219185088Szec#define RIPV6SNDQ 8192 220185088Szec#define RIPV6RCVQ 8192 221185088Szec V_rip6_sendspace = RIPV6SNDQ; 222185088Szec V_rip6_recvspace = RIPV6RCVQ; 223185088Szec 224185088Szec /* ICMPV6 parameters */ 225185088Szec V_icmp6_rediraccept = 1; /* accept and process redirects */ 226185088Szec V_icmp6_redirtimeout = 10 * 60; /* 10 minutes */ 227185088Szec V_icmp6errppslim = 100; /* 100pps */ 228185088Szec /* control how to respond to NI queries */ 229185088Szec V_icmp6_nodeinfo = (ICMP6_NODEINFO_FQDNOK|ICMP6_NODEINFO_NODEADDROK); 230185088Szec 231185088Szec /* UDP on IP6 parameters */ 232185088Szec V_udp6_sendspace = 9216; /* really max datagram size */ 233185088Szec V_udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6)); 234185088Szec /* 40 1K datagrams */ 235185088Szec V_dad_init = 0; 236185088Szec 237190787Szec scope6_init(); 238190787Szec addrsel_policy_init(); 239190787Szec nd6_init(); 240190787Szec frag6_init(); 241190787Szec 242190787Szec V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR; 243190787Szec 244190787Szec /* Skip global initialization stuff for non-default instances. */ 245190787Szec if (!IS_DEFAULT_VNET(curvnet)) 246190787Szec return; 247190787Szec 24878064Sume#ifdef DIAGNOSTIC 24978064Sume if (sizeof(struct protosw) != sizeof(struct ip6protosw)) 25078064Sume panic("sizeof(protosw) != sizeof(ip6protosw)"); 25178064Sume#endif 25253541Sshin pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); 25353541Sshin if (pr == 0) 25453541Sshin panic("ip6_init"); 255136689Sandre 256186393Sbz /* Initialize the entire ip6_protox[] array to IPPROTO_RAW. */ 25753541Sshin for (i = 0; i < IPPROTO_MAX; i++) 25853541Sshin ip6_protox[i] = pr - inet6sw; 259136689Sandre /* 260136689Sandre * Cycle through IP protocols and put them into the appropriate place 261136689Sandre * in ip6_protox[]. 262136689Sandre */ 26353541Sshin for (pr = (struct ip6protosw *)inet6domain.dom_protosw; 26453541Sshin pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) 26553541Sshin if (pr->pr_domain->dom_family == PF_INET6 && 266136689Sandre pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { 267136689Sandre /* Be careful to only index valid IP protocols. */ 268143675Ssam if (pr->pr_protocol < IPPROTO_MAX) 269136689Sandre ip6_protox[pr->pr_protocol] = pr - inet6sw; 270136689Sandre } 271134383Sandre 272134383Sandre /* Initialize packet filter hooks. */ 273120386Ssam inet6_pfil_hook.ph_type = PFIL_TYPE_AF; 274120386Ssam inet6_pfil_hook.ph_af = AF_INET6; 275120386Ssam if ((i = pfil_head_register(&inet6_pfil_hook)) != 0) 276120386Ssam printf("%s: WARNING: unable to register pfil hook, " 277120386Ssam "error %d\n", __func__, i); 278134383Sandre 279190787Szec ip6intrq.ifq_maxlen = V_ip6qmaxlen; /* XXX */ 28093818Sjhb mtx_init(&ip6intrq.ifq_mtx, "ip6_inq", NULL, MTX_DEF); 281180239Srwatson netisr_register(NETISR_IPV6, ip6_input, &ip6intrq, 0); 28253541Sshin} 28353541Sshin 284190787Szecstatic int 285190787Szecip6_init2_vnet(const void *unused __unused) 28653541Sshin{ 287183550Szec INIT_VNET_INET6(curvnet); 28853541Sshin 28953541Sshin /* nd6_timer_init */ 290181803Sbz callout_init(&V_nd6_timer_ch, 0); 291181803Sbz callout_reset(&V_nd6_timer_ch, hz, nd6_timer, NULL); 29278064Sume 29378064Sume /* timer for regeneranation of temporary addresses randomize ID */ 294181803Sbz callout_init(&V_in6_tmpaddrtimer_ch, 0); 295181803Sbz callout_reset(&V_in6_tmpaddrtimer_ch, 296181803Sbz (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor - 297181803Sbz V_ip6_temp_regen_advance) * hz, 29878064Sume in6_tmpaddrtimer, NULL); 299190787Szec 300190787Szec return (0); 30153541Sshin} 30253541Sshin 303190787Szecstatic void 304190787Szecip6_init2(void *dummy) 305190787Szec{ 306190787Szec 307190787Szec ip6_init2_vnet(NULL); 308190787Szec} 309190787Szec 31053541Sshin/* cheat */ 31155009Sshin/* This must be after route_init(), which is now SI_ORDER_THIRD */ 31255009SshinSYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL); 31353541Sshin 31453541Sshinvoid 315171259Sdelphijip6_input(struct mbuf *m) 31653541Sshin{ 317183550Szec INIT_VNET_NET(curvnet); 318183550Szec INIT_VNET_INET6(curvnet); 31953541Sshin struct ip6_hdr *ip6; 32053541Sshin int off = sizeof(struct ip6_hdr), nest; 32153541Sshin u_int32_t plen; 32253541Sshin u_int32_t rtalert = ~0; 32353541Sshin int nxt, ours = 0; 324186119Sqingli struct ifnet *deliverifp = NULL, *ifp = NULL; 325121143Ssam struct in6_addr odst; 326187989Sbz struct route_in6 rin6; 327121143Ssam int srcrt = 0; 328186119Sqingli struct llentry *lle = NULL; 329187989Sbz struct sockaddr_in6 dst6, *dst; 330121144Ssam 331187989Sbz bzero(&rin6, sizeof(struct route_in6)); 332171167Sgnn#ifdef IPSEC 33353541Sshin /* 33453541Sshin * should the inner packet be considered authentic? 33553541Sshin * see comment in ah4_input(). 336171133Sgnn * NB: m cannot be NULL when passed to the input routine 33753541Sshin */ 33853541Sshin 339171133Sgnn m->m_flags &= ~M_AUTHIPHDR; 340171133Sgnn m->m_flags &= ~M_AUTHIPDGM; 341171133Sgnn 342171167Sgnn#endif /* IPSEC */ 343171133Sgnn 34453541Sshin /* 345121630Sume * make sure we don't have onion peering information into m_tag. 34678064Sume */ 34778064Sume ip6_delaux(m); 34878064Sume 34978064Sume /* 35095023Ssuz * mbuf statistics 35153541Sshin */ 35253541Sshin if (m->m_flags & M_EXT) { 35353541Sshin if (m->m_next) 354181803Sbz V_ip6stat.ip6s_mext2m++; 35553541Sshin else 356181803Sbz V_ip6stat.ip6s_mext1++; 35753541Sshin } else { 358181803Sbz#define M2MMAX (sizeof(V_ip6stat.ip6s_m2m)/sizeof(V_ip6stat.ip6s_m2m[0])) 35953541Sshin if (m->m_next) { 36053541Sshin if (m->m_flags & M_LOOP) { 361181803Sbz V_ip6stat.ip6s_m2m[V_loif[0].if_index]++; /* XXX */ 36278064Sume } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) 363181803Sbz V_ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; 36453541Sshin else 365181803Sbz V_ip6stat.ip6s_m2m[0]++; 36653541Sshin } else 367181803Sbz V_ip6stat.ip6s_m1++; 36878064Sume#undef M2MMAX 36953541Sshin } 37053541Sshin 371151474Ssuz /* drop the packet if IPv6 operation is disabled on the IF */ 372151474Ssuz if ((ND_IFINFO(m->m_pkthdr.rcvif)->flags & ND6_IFF_IFDISABLED)) { 373151474Ssuz m_freem(m); 374151474Ssuz return; 375151474Ssuz } 376151474Ssuz 37753541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); 378181803Sbz V_ip6stat.ip6s_total++; 37953541Sshin 38062587Sitojun#ifndef PULLDOWN_TEST 38174336Skuriyama /* 38274336Skuriyama * L2 bridge code and some other code can return mbuf chain 38374336Skuriyama * that does not conform to KAME requirement. too bad. 38474336Skuriyama * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? 38574336Skuriyama */ 38674336Skuriyama if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { 38774336Skuriyama struct mbuf *n; 38874336Skuriyama 389111119Simp MGETHDR(n, M_DONTWAIT, MT_HEADER); 39077003Sume if (n) 391108466Ssam M_MOVE_PKTHDR(n, m); 392108825Ssam if (n && n->m_pkthdr.len > MHLEN) { 393111119Simp MCLGET(n, M_DONTWAIT); 39474336Skuriyama if ((n->m_flags & M_EXT) == 0) { 39574336Skuriyama m_freem(n); 39674336Skuriyama n = NULL; 39774336Skuriyama } 39874336Skuriyama } 39995023Ssuz if (n == NULL) { 40077003Sume m_freem(m); 401120913Sume return; /* ENOBUFS */ 40277003Sume } 40374336Skuriyama 404108825Ssam m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); 405108825Ssam n->m_len = n->m_pkthdr.len; 40674336Skuriyama m_freem(m); 40774336Skuriyama m = n; 40874336Skuriyama } 409120913Sume IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */); 41062587Sitojun#endif 41153541Sshin 41253541Sshin if (m->m_len < sizeof(struct ip6_hdr)) { 41353541Sshin struct ifnet *inifp; 41453541Sshin inifp = m->m_pkthdr.rcvif; 415120913Sume if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { 416181803Sbz V_ip6stat.ip6s_toosmall++; 41753541Sshin in6_ifstat_inc(inifp, ifs6_in_hdrerr); 41853541Sshin return; 41953541Sshin } 42053541Sshin } 42153541Sshin 42253541Sshin ip6 = mtod(m, struct ip6_hdr *); 42353541Sshin 42453541Sshin if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 425181803Sbz V_ip6stat.ip6s_badvers++; 42653541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 42753541Sshin goto bad; 42853541Sshin } 42953541Sshin 430181803Sbz V_ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; 43153541Sshin 43253541Sshin /* 43378064Sume * Check against address spoofing/corruption. 43453541Sshin */ 43553541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || 43653541Sshin IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { 43778064Sume /* 43878064Sume * XXX: "badscope" is not very suitable for a multicast source. 43978064Sume */ 440181803Sbz V_ip6stat.ip6s_badscope++; 44153541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 44253541Sshin goto bad; 44353541Sshin } 444126444Sume if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) && 445126444Sume !(m->m_flags & M_LOOP)) { 446126444Sume /* 447126444Sume * In this case, the packet should come from the loopback 448126444Sume * interface. However, we cannot just check the if_flags, 449126444Sume * because ip6_mloopback() passes the "actual" interface 450126444Sume * as the outgoing/incoming interface. 451126444Sume */ 452181803Sbz V_ip6stat.ip6s_badscope++; 45378064Sume in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 45478064Sume goto bad; 45578064Sume } 45695023Ssuz 457130416Smlaier#ifdef ALTQ 458130416Smlaier if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { 459130416Smlaier /* packet is dropped by traffic conditioner */ 460130416Smlaier return; 461130416Smlaier } 462130416Smlaier#endif 46362587Sitojun /* 46478064Sume * The following check is not documented in specs. A malicious 46578064Sume * party may be able to use IPv4 mapped addr to confuse tcp/udp stack 46678064Sume * and bypass security checks (act as if it was from 127.0.0.1 by using 467120913Sume * IPv6 src ::ffff:127.0.0.1). Be cautious. 46878064Sume * 46978064Sume * This check chokes if we are in an SIIT cloud. As none of BSDs 47078064Sume * support IPv4-less kernel compilation, we cannot support SIIT 47178064Sume * environment at all. So, it makes more sense for us to reject any 47278064Sume * malicious packets for non-SIIT environment, than try to do a 473120913Sume * partial support for SIIT environment. 47462587Sitojun */ 47578064Sume if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 47678064Sume IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 477181803Sbz V_ip6stat.ip6s_badscope++; 47878064Sume in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 47978064Sume goto bad; 48078064Sume } 48162587Sitojun#if 0 48262587Sitojun /* 48362587Sitojun * Reject packets with IPv4 compatible addresses (auto tunnel). 48462587Sitojun * 48562587Sitojun * The code forbids auto tunnel relay case in RFC1933 (the check is 48662587Sitojun * stronger than RFC1933). We may want to re-enable it if mech-xx 48762587Sitojun * is revised to forbid relaying case. 48862587Sitojun */ 48962587Sitojun if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || 49062587Sitojun IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { 491181803Sbz V_ip6stat.ip6s_badscope++; 49262587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 49362587Sitojun goto bad; 49462587Sitojun } 49562587Sitojun#endif 49675246Sume 497126444Sume /* 498126508Smlaier * Run through list of hooks for input packets. 499126508Smlaier * 500126508Smlaier * NB: Beware of the destination address changing 501126508Smlaier * (e.g. by NAT rewriting). When this happens, 502126508Smlaier * tell ip6_forward to do the right thing. 503126508Smlaier */ 504126508Smlaier odst = ip6->ip6_dst; 505134383Sandre 506134383Sandre /* Jump over all PFIL processing if hooks are not active. */ 507155201Scsjp if (!PFIL_HOOKED(&inet6_pfil_hook)) 508134383Sandre goto passin; 509134383Sandre 510135920Smlaier if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL)) 511126508Smlaier return; 512126508Smlaier if (m == NULL) /* consumed by filter */ 513126508Smlaier return; 514126508Smlaier ip6 = mtod(m, struct ip6_hdr *); 515126508Smlaier srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); 516126508Smlaier 517134383Sandrepassin: 518126508Smlaier /* 519154804Sume * Disambiguate address scope zones (if there is ambiguity). 520154804Sume * We first make sure that the original source or destination address 521154804Sume * is not in our internal form for scoped addresses. Such addresses 522154804Sume * are not necessarily invalid spec-wise, but we cannot accept them due 523154804Sume * to the usage conflict. 524154804Sume * in6_setscope() then also checks and rejects the cases where src or 525154804Sume * dst are the loopback address and the receiving interface 526154804Sume * is not loopback. 527154804Sume */ 528154804Sume if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { 529181803Sbz V_ip6stat.ip6s_badscope++; /* XXX */ 530154804Sume goto bad; 531154804Sume } 532154804Sume if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || 533154804Sume in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { 534181803Sbz V_ip6stat.ip6s_badscope++; 535154804Sume goto bad; 536154804Sume } 537154804Sume 538154804Sume /* 53953541Sshin * Multicast check 54053541Sshin */ 54153541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 542171260Sdelphij struct in6_multi *in6m = 0; 54353541Sshin 54453541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); 54553541Sshin /* 54653541Sshin * See if we belong to the destination multicast group on the 54753541Sshin * arrival interface. 54853541Sshin */ 54953541Sshin IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m); 55053541Sshin if (in6m) 55153541Sshin ours = 1; 55256723Sshin else if (!ip6_mrouter) { 553181803Sbz V_ip6stat.ip6s_notmember++; 554181803Sbz V_ip6stat.ip6s_cantforward++; 55553541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 55653541Sshin goto bad; 55753541Sshin } 55853541Sshin deliverifp = m->m_pkthdr.rcvif; 55953541Sshin goto hbhcheck; 56053541Sshin } 56153541Sshin 56253541Sshin /* 56353541Sshin * Unicast check 56453541Sshin */ 565186119Sqingli 566186119Sqingli bzero(&dst6, sizeof(dst6)); 567186119Sqingli dst6.sin6_family = AF_INET6; 568186119Sqingli dst6.sin6_len = sizeof(struct sockaddr_in6); 569186119Sqingli dst6.sin6_addr = ip6->ip6_dst; 570186119Sqingli ifp = m->m_pkthdr.rcvif; 571186119Sqingli IF_AFDATA_LOCK(ifp); 572186119Sqingli lle = lla_lookup(LLTABLE6(ifp), 0, 573186119Sqingli (struct sockaddr *)&dst6); 574186119Sqingli IF_AFDATA_UNLOCK(ifp); 575186119Sqingli if ((lle != NULL) && (lle->la_flags & LLE_IFADDR)) { 576186119Sqingli ours = 1; 577186119Sqingli deliverifp = ifp; 578186119Sqingli LLE_RUNLOCK(lle); 579186119Sqingli goto hbhcheck; 580186119Sqingli } 581186293Sbz if (lle != NULL) 582186293Sbz LLE_RUNLOCK(lle); 583186119Sqingli 584187989Sbz dst = &rin6.ro_dst; 585187989Sbz dst->sin6_len = sizeof(struct sockaddr_in6); 586187989Sbz dst->sin6_family = AF_INET6; 587187989Sbz dst->sin6_addr = ip6->ip6_dst; 588187989Sbz rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0); 589187989Sbz if (rin6.ro_rt) 590187989Sbz RT_UNLOCK(rin6.ro_rt); 59178064Sume 59253541Sshin#define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) 59353541Sshin 59453541Sshin /* 59553541Sshin * Accept the packet if the forwarding interface to the destination 59653541Sshin * according to the routing table is the loopback interface, 59753541Sshin * unless the associated route has a gateway. 59853541Sshin * Note that this approach causes to accept a packet if there is a 59953541Sshin * route to the loopback interface for the destination of the packet. 60053541Sshin * But we think it's even useful in some situations, e.g. when using 60153541Sshin * a special daemon which wants to intercept the packet. 60278064Sume * 60378064Sume * XXX: some OSes automatically make a cloned route for the destination 60478064Sume * of an outgoing packet. If the outgoing interface of the packet 60578064Sume * is a loopback one, the kernel would consider the packet to be 60678064Sume * accepted, even if we have no such address assinged on the interface. 60778064Sume * We check the cloned flag of the route entry to reject such cases, 60878064Sume * assuming that route entries for our own addresses are not made by 60978064Sume * cloning (it should be true because in6_addloop explicitly installs 61078064Sume * the host route). However, we might have to do an explicit check 61178064Sume * while it would be less efficient. Or, should we rather install a 61278064Sume * reject route for such a case? 61353541Sshin */ 614187989Sbz if (rin6.ro_rt && 615187989Sbz (rin6.ro_rt->rt_flags & 61653541Sshin (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && 61778064Sume#ifdef RTF_WASCLONED 618187989Sbz !(rin6.ro_rt->rt_flags & RTF_WASCLONED) && 61978064Sume#endif 62078064Sume#ifdef RTF_CLONED 621187989Sbz !(rin6.ro_rt->rt_flags & RTF_CLONED) && 62278064Sume#endif 62362587Sitojun#if 0 62453541Sshin /* 62562587Sitojun * The check below is redundant since the comparison of 62662587Sitojun * the destination and the key of the rtentry has 62762587Sitojun * already done through looking up the routing table. 62853541Sshin */ 62962587Sitojun IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 630187989Sbz &rt6_key(rin6.ro_rt)->sin6_addr) 63162587Sitojun#endif 632187989Sbz rin6.ro_rt->rt_ifp->if_type == IFT_LOOP) { 63353541Sshin struct in6_ifaddr *ia6 = 634187989Sbz (struct in6_ifaddr *)rin6.ro_rt->rt_ifa; 63578064Sume 63662587Sitojun /* 637121630Sume * record address information into m_tag. 63878064Sume */ 63978064Sume (void)ip6_setdstifaddr(m, ia6); 64078064Sume 64178064Sume /* 64262587Sitojun * packets to a tentative, duplicated, or somehow invalid 64362587Sitojun * address must not be accepted. 64462587Sitojun */ 64553541Sshin if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { 64662587Sitojun /* this address is ready */ 64753541Sshin ours = 1; 64853541Sshin deliverifp = ia6->ia_ifp; /* correct? */ 64967334Sjoe /* Count the packet in the ip address stats */ 65067334Sjoe ia6->ia_ifa.if_ipackets++; 65167334Sjoe ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; 65253541Sshin goto hbhcheck; 65353541Sshin } else { 654165118Sbz char ip6bufs[INET6_ADDRSTRLEN]; 655165118Sbz char ip6bufd[INET6_ADDRSTRLEN]; 65662587Sitojun /* address is not ready, so discard the packet. */ 65778064Sume nd6log((LOG_INFO, 65878064Sume "ip6_input: packet to an unready address %s->%s\n", 659165118Sbz ip6_sprintf(ip6bufs, &ip6->ip6_src), 660165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst))); 66162587Sitojun 66262587Sitojun goto bad; 66353541Sshin } 66453541Sshin } 66553541Sshin 66653541Sshin /* 667120913Sume * FAITH (Firewall Aided Internet Translator) 66853541Sshin */ 669181803Sbz if (V_ip6_keepfaith) { 670187989Sbz if (rin6.ro_rt && rin6.ro_rt->rt_ifp && 671187989Sbz rin6.ro_rt->rt_ifp->if_type == IFT_FAITH) { 67253541Sshin /* XXX do we need more sanity checks? */ 67353541Sshin ours = 1; 674187989Sbz deliverifp = rin6.ro_rt->rt_ifp; /* faith */ 67553541Sshin goto hbhcheck; 67653541Sshin } 67753541Sshin } 67853541Sshin 67953541Sshin /* 68053541Sshin * Now there is no reason to process the packet if it's not our own 68153541Sshin * and we're not a router. 68253541Sshin */ 683181803Sbz if (!V_ip6_forwarding) { 684181803Sbz V_ip6stat.ip6s_cantforward++; 68553541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 68653541Sshin goto bad; 68753541Sshin } 68853541Sshin 68953541Sshin hbhcheck: 69053541Sshin /* 691121630Sume * record address information into m_tag, if we don't have one yet. 69278064Sume * note that we are unable to record it, if the address is not listed 69378064Sume * as our interface address (e.g. multicast addresses, addresses 69478064Sume * within FAITH prefixes and such). 69578064Sume */ 69678064Sume if (deliverifp && !ip6_getdstifaddr(m)) { 69778064Sume struct in6_ifaddr *ia6; 69878064Sume 69978064Sume ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); 70078064Sume if (ia6) { 70178064Sume if (!ip6_setdstifaddr(m, ia6)) { 70278064Sume /* 70378064Sume * XXX maybe we should drop the packet here, 70478064Sume * as we could not provide enough information 70578064Sume * to the upper layers. 70678064Sume */ 70778064Sume } 70878064Sume } 70978064Sume } 71078064Sume 71178064Sume /* 71253541Sshin * Process Hop-by-Hop options header if it's contained. 71353541Sshin * m may be modified in ip6_hopopts_input(). 71453541Sshin * If a JumboPayload option is included, plen will also be modified. 71553541Sshin */ 71653541Sshin plen = (u_int32_t)ntohs(ip6->ip6_plen); 71753541Sshin if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { 71862587Sitojun struct ip6_hbh *hbh; 71962587Sitojun 72053541Sshin if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) { 72162587Sitojun#if 0 /*touches NULL pointer*/ 72253541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 72362587Sitojun#endif 724187989Sbz goto out; /* m have already been freed */ 72553541Sshin } 72662587Sitojun 72753541Sshin /* adjust pointer */ 72853541Sshin ip6 = mtod(m, struct ip6_hdr *); 72953541Sshin 73053541Sshin /* 73195023Ssuz * if the payload length field is 0 and the next header field 73262587Sitojun * indicates Hop-by-Hop Options header, then a Jumbo Payload 73362587Sitojun * option MUST be included. 73462587Sitojun */ 73562587Sitojun if (ip6->ip6_plen == 0 && plen == 0) { 73662587Sitojun /* 73762587Sitojun * Note that if a valid jumbo payload option is 738120913Sume * contained, ip6_hopopts_input() must set a valid 739120913Sume * (non-zero) payload length to the variable plen. 74062587Sitojun */ 741181803Sbz V_ip6stat.ip6s_badoptions++; 74262587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); 74362587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); 74462587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 74562587Sitojun ICMP6_PARAMPROB_HEADER, 74662587Sitojun (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); 747187989Sbz goto out; 74862587Sitojun } 74962587Sitojun#ifndef PULLDOWN_TEST 75062587Sitojun /* ip6_hopopts_input() ensures that mbuf is contiguous */ 75162587Sitojun hbh = (struct ip6_hbh *)(ip6 + 1); 75262587Sitojun#else 75362587Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), 75462587Sitojun sizeof(struct ip6_hbh)); 75562587Sitojun if (hbh == NULL) { 756181803Sbz V_ip6stat.ip6s_tooshort++; 757187989Sbz goto out; 75862587Sitojun } 75962587Sitojun#endif 76062587Sitojun nxt = hbh->ip6h_nxt; 76162587Sitojun 76262587Sitojun /* 763169557Sjinmei * If we are acting as a router and the packet contains a 764169557Sjinmei * router alert option, see if we know the option value. 765169557Sjinmei * Currently, we only support the option value for MLD, in which 766169557Sjinmei * case we should pass the packet to the multicast routing 767169557Sjinmei * daemon. 76853541Sshin */ 769181803Sbz if (rtalert != ~0 && V_ip6_forwarding) { 770169557Sjinmei switch (rtalert) { 771169557Sjinmei case IP6OPT_RTALERT_MLD: 772169557Sjinmei ours = 1; 773169557Sjinmei break; 774169557Sjinmei default: 775169557Sjinmei /* 776169557Sjinmei * RFC2711 requires unrecognized values must be 777169557Sjinmei * silently ignored. 778169557Sjinmei */ 779169557Sjinmei break; 780169557Sjinmei } 781169557Sjinmei } 78253541Sshin } else 78353541Sshin nxt = ip6->ip6_nxt; 78453541Sshin 78553541Sshin /* 78653541Sshin * Check that the amount of data in the buffers 78753541Sshin * is as at least much as the IPv6 header would have us expect. 78853541Sshin * Trim mbufs if longer than we expect. 78953541Sshin * Drop packet if shorter than we expect. 79053541Sshin */ 79153541Sshin if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { 792181803Sbz V_ip6stat.ip6s_tooshort++; 79353541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 79453541Sshin goto bad; 79553541Sshin } 79653541Sshin if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { 79753541Sshin if (m->m_len == m->m_pkthdr.len) { 79853541Sshin m->m_len = sizeof(struct ip6_hdr) + plen; 79953541Sshin m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; 80053541Sshin } else 80153541Sshin m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); 80253541Sshin } 80353541Sshin 80453541Sshin /* 80553541Sshin * Forward if desirable. 80653541Sshin */ 80753541Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 80856723Sshin /* 80956723Sshin * If we are acting as a multicast router, all 81056723Sshin * incoming multicast packets are passed to the 81156723Sshin * kernel-level multicast forwarding function. 81256723Sshin * The packet is returned (relatively) intact; if 81356723Sshin * ip6_mforward() returns a non-zero value, the packet 81456723Sshin * must be discarded, else it may be accepted below. 81556723Sshin */ 816166938Sbms if (ip6_mrouter && ip6_mforward && 817166938Sbms ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { 818181803Sbz V_ip6stat.ip6s_cantforward++; 819187989Sbz goto bad; 82056723Sshin } 821187989Sbz if (!ours) 822187989Sbz goto bad; 82353541Sshin } else if (!ours) { 824121143Ssam ip6_forward(m, srcrt); 825187989Sbz goto out; 826121673Sume } 82753541Sshin 82862587Sitojun ip6 = mtod(m, struct ip6_hdr *); 82962587Sitojun 83053541Sshin /* 83162587Sitojun * Malicious party may be able to use IPv4 mapped addr to confuse 83262587Sitojun * tcp/udp stack and bypass security checks (act as if it was from 83362587Sitojun * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious. 83462587Sitojun * 83562587Sitojun * For SIIT end node behavior, you may want to disable the check. 83662587Sitojun * However, you will become vulnerable to attacks using IPv4 mapped 83762587Sitojun * source. 83862587Sitojun */ 83962587Sitojun if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || 84062587Sitojun IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { 841181803Sbz V_ip6stat.ip6s_badscope++; 84262587Sitojun in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); 84362587Sitojun goto bad; 84462587Sitojun } 84562587Sitojun 84662587Sitojun /* 84753541Sshin * Tell launch routine the next header 84853541Sshin */ 849181803Sbz V_ip6stat.ip6s_delivered++; 85053541Sshin in6_ifstat_inc(deliverifp, ifs6_in_deliver); 85153541Sshin nest = 0; 85278064Sume 85353541Sshin while (nxt != IPPROTO_DONE) { 854181803Sbz if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { 855181803Sbz V_ip6stat.ip6s_toomanyhdr++; 85653541Sshin goto bad; 85753541Sshin } 85853541Sshin 85953541Sshin /* 86053541Sshin * protection against faulty packet - there should be 86153541Sshin * more sanity checks in header chain processing. 86253541Sshin */ 86353541Sshin if (m->m_pkthdr.len < off) { 864181803Sbz V_ip6stat.ip6s_tooshort++; 86553541Sshin in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); 86653541Sshin goto bad; 86753541Sshin } 86853541Sshin 869171167Sgnn#ifdef IPSEC 87078064Sume /* 87178064Sume * enforce IPsec policy checking if we are seeing last header. 87278064Sume * note that we do not visit this with protocols with pcb layer 87378064Sume * code - like udp/tcp/raw ip. 87478064Sume */ 875171133Sgnn if (ip6_ipsec_input(m, nxt)) 87678064Sume goto bad; 877171167Sgnn#endif /* IPSEC */ 87853541Sshin nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); 87953541Sshin } 880187989Sbz goto out; 881187989Sbzbad: 88253541Sshin m_freem(m); 883187989Sbzout: 884187989Sbz if (rin6.ro_rt) 885187989Sbz RTFREE(rin6.ro_rt); 88653541Sshin} 88753541Sshin 88853541Sshin/* 88978064Sume * set/grab in6_ifaddr correspond to IPv6 destination address. 89078064Sume * XXX backward compatibility wrapper 89178064Sume */ 892121673Sumestatic struct ip6aux * 893171259Sdelphijip6_setdstifaddr(struct mbuf *m, struct in6_ifaddr *ia6) 89478064Sume{ 895121673Sume struct ip6aux *ip6a; 89678064Sume 897121673Sume ip6a = ip6_addaux(m); 898121673Sume if (ip6a) 899121673Sume ip6a->ip6a_dstia6 = ia6; 900121673Sume return ip6a; /* NULL if failed to set */ 90178064Sume} 90278064Sume 90378064Sumestruct in6_ifaddr * 904171259Sdelphijip6_getdstifaddr(struct mbuf *m) 90578064Sume{ 906121673Sume struct ip6aux *ip6a; 90778064Sume 908121673Sume ip6a = ip6_findaux(m); 909121673Sume if (ip6a) 910121673Sume return ip6a->ip6a_dstia6; 91178064Sume else 91278064Sume return NULL; 91378064Sume} 91478064Sume 91578064Sume/* 91653541Sshin * Hop-by-Hop options header processing. If a valid jumbo payload option is 91753541Sshin * included, the real payload length will be stored in plenp. 918171259Sdelphij * 919171259Sdelphij * rtalertp - XXX: should be stored more smart way 92053541Sshin */ 92153541Sshinstatic int 922171259Sdelphijip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, 923171259Sdelphij struct mbuf **mp, int *offp) 92453541Sshin{ 925183550Szec INIT_VNET_INET6(curvnet); 92678064Sume struct mbuf *m = *mp; 92753541Sshin int off = *offp, hbhlen; 92853541Sshin struct ip6_hbh *hbh; 92953541Sshin u_int8_t *opt; 93053541Sshin 93153541Sshin /* validation of the length of the header */ 93262587Sitojun#ifndef PULLDOWN_TEST 93353541Sshin IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); 93453541Sshin hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); 93553541Sshin hbhlen = (hbh->ip6h_len + 1) << 3; 93653541Sshin 93753541Sshin IP6_EXTHDR_CHECK(m, off, hbhlen, -1); 93853541Sshin hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); 93962587Sitojun#else 94062587Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, 94162587Sitojun sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); 94262587Sitojun if (hbh == NULL) { 943181803Sbz V_ip6stat.ip6s_tooshort++; 94462587Sitojun return -1; 94562587Sitojun } 94662587Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 94762587Sitojun IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), 94862587Sitojun hbhlen); 94962587Sitojun if (hbh == NULL) { 950181803Sbz V_ip6stat.ip6s_tooshort++; 95162587Sitojun return -1; 95262587Sitojun } 95362587Sitojun#endif 95453541Sshin off += hbhlen; 95553541Sshin hbhlen -= sizeof(struct ip6_hbh); 95653541Sshin opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh); 95753541Sshin 95853541Sshin if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), 95953541Sshin hbhlen, rtalertp, plenp) < 0) 960120856Sume return (-1); 96153541Sshin 96253541Sshin *offp = off; 96353541Sshin *mp = m; 964120856Sume return (0); 96553541Sshin} 96653541Sshin 96753541Sshin/* 96853541Sshin * Search header for all Hop-by-hop options and process each option. 96953541Sshin * This function is separate from ip6_hopopts_input() in order to 97053541Sshin * handle a case where the sending node itself process its hop-by-hop 97153541Sshin * options header. In such a case, the function is called from ip6_output(). 97278064Sume * 97378064Sume * The function assumes that hbh header is located right after the IPv6 header 97478064Sume * (RFC2460 p7), opthead is pointer into data content in m, and opthead to 97578064Sume * opthead + hbhlen is located in continuous memory region. 97653541Sshin */ 97753541Sshinint 978171259Sdelphijip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, 979171259Sdelphij u_int32_t *rtalertp, u_int32_t *plenp) 98053541Sshin{ 981183550Szec INIT_VNET_INET6(curvnet); 98253541Sshin struct ip6_hdr *ip6; 98353541Sshin int optlen = 0; 98453541Sshin u_int8_t *opt = opthead; 98553541Sshin u_int16_t rtalert_val; 98662587Sitojun u_int32_t jumboplen; 98778064Sume const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); 98853541Sshin 98953541Sshin for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { 99078064Sume switch (*opt) { 99178064Sume case IP6OPT_PAD1: 99278064Sume optlen = 1; 99378064Sume break; 99478064Sume case IP6OPT_PADN: 99578064Sume if (hbhlen < IP6OPT_MINLEN) { 996181803Sbz V_ip6stat.ip6s_toosmall++; 99778064Sume goto bad; 99878064Sume } 99978064Sume optlen = *(opt + 1) + 2; 100078064Sume break; 1001121472Sume case IP6OPT_ROUTER_ALERT: 100262587Sitojun /* XXX may need check for alignment */ 100378064Sume if (hbhlen < IP6OPT_RTALERT_LEN) { 1004181803Sbz V_ip6stat.ip6s_toosmall++; 100578064Sume goto bad; 100678064Sume } 100778064Sume if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { 100878064Sume /* XXX stat */ 100978064Sume icmp6_error(m, ICMP6_PARAM_PROB, 1010120913Sume ICMP6_PARAMPROB_HEADER, 1011120913Sume erroff + opt + 1 - opthead); 1012120856Sume return (-1); 101378064Sume } 101478064Sume optlen = IP6OPT_RTALERT_LEN; 101578064Sume bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); 101678064Sume *rtalertp = ntohs(rtalert_val); 101778064Sume break; 101878064Sume case IP6OPT_JUMBO: 101978064Sume /* XXX may need check for alignment */ 102062587Sitojun if (hbhlen < IP6OPT_JUMBO_LEN) { 1021181803Sbz V_ip6stat.ip6s_toosmall++; 102262587Sitojun goto bad; 102362587Sitojun } 102478064Sume if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { 102578064Sume /* XXX stat */ 102678064Sume icmp6_error(m, ICMP6_PARAM_PROB, 1027120913Sume ICMP6_PARAMPROB_HEADER, 1028120913Sume erroff + opt + 1 - opthead); 1029120856Sume return (-1); 103078064Sume } 103162587Sitojun optlen = IP6OPT_JUMBO_LEN; 103253541Sshin 103362587Sitojun /* 103462587Sitojun * IPv6 packets that have non 0 payload length 103578064Sume * must not contain a jumbo payload option. 103662587Sitojun */ 103762587Sitojun ip6 = mtod(m, struct ip6_hdr *); 103862587Sitojun if (ip6->ip6_plen) { 1039181803Sbz V_ip6stat.ip6s_badoptions++; 104062587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 1041120913Sume ICMP6_PARAMPROB_HEADER, 1042120913Sume erroff + opt - opthead); 1043120856Sume return (-1); 104462587Sitojun } 104553541Sshin 104662587Sitojun /* 104762587Sitojun * We may see jumbolen in unaligned location, so 104862587Sitojun * we'd need to perform bcopy(). 104962587Sitojun */ 105062587Sitojun bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); 105162587Sitojun jumboplen = (u_int32_t)htonl(jumboplen); 105262587Sitojun 105362587Sitojun#if 1 105462587Sitojun /* 105562587Sitojun * if there are multiple jumbo payload options, 105662587Sitojun * *plenp will be non-zero and the packet will be 105762587Sitojun * rejected. 105862587Sitojun * the behavior may need some debate in ipngwg - 105962587Sitojun * multiple options does not make sense, however, 106062587Sitojun * there's no explicit mention in specification. 106162587Sitojun */ 106262587Sitojun if (*plenp != 0) { 1063181803Sbz V_ip6stat.ip6s_badoptions++; 106462587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 1065120913Sume ICMP6_PARAMPROB_HEADER, 1066120913Sume erroff + opt + 2 - opthead); 1067120856Sume return (-1); 106862587Sitojun } 106962587Sitojun#endif 107062587Sitojun 107162587Sitojun /* 107262587Sitojun * jumbo payload length must be larger than 65535. 107362587Sitojun */ 107462587Sitojun if (jumboplen <= IPV6_MAXPACKET) { 1075181803Sbz V_ip6stat.ip6s_badoptions++; 107662587Sitojun icmp6_error(m, ICMP6_PARAM_PROB, 1077120913Sume ICMP6_PARAMPROB_HEADER, 1078120913Sume erroff + opt + 2 - opthead); 1079120856Sume return (-1); 108062587Sitojun } 108162587Sitojun *plenp = jumboplen; 108262587Sitojun 108362587Sitojun break; 108478064Sume default: /* unknown option */ 108578064Sume if (hbhlen < IP6OPT_MINLEN) { 1086181803Sbz V_ip6stat.ip6s_toosmall++; 108778064Sume goto bad; 108878064Sume } 108978064Sume optlen = ip6_unknown_opt(opt, m, 109078064Sume erroff + opt - opthead); 109178064Sume if (optlen == -1) 1092120856Sume return (-1); 109378064Sume optlen += 2; 109478064Sume break; 109553541Sshin } 109653541Sshin } 109753541Sshin 1098120856Sume return (0); 109953541Sshin 110053541Sshin bad: 110153541Sshin m_freem(m); 1102120856Sume return (-1); 110353541Sshin} 110453541Sshin 110553541Sshin/* 110653541Sshin * Unknown option processing. 110753541Sshin * The third argument `off' is the offset from the IPv6 header to the option, 110853541Sshin * which is necessary if the IPv6 header the and option header and IPv6 header 110953541Sshin * is not continuous in order to return an ICMPv6 error. 111053541Sshin */ 111153541Sshinint 1112171259Sdelphijip6_unknown_opt(u_int8_t *optp, struct mbuf *m, int off) 111353541Sshin{ 1114183550Szec INIT_VNET_INET6(curvnet); 111553541Sshin struct ip6_hdr *ip6; 111653541Sshin 111778064Sume switch (IP6OPT_TYPE(*optp)) { 111878064Sume case IP6OPT_TYPE_SKIP: /* ignore the option */ 1119120856Sume return ((int)*(optp + 1)); 112078064Sume case IP6OPT_TYPE_DISCARD: /* silently discard */ 112178064Sume m_freem(m); 1122120856Sume return (-1); 112378064Sume case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ 1124181803Sbz V_ip6stat.ip6s_badoptions++; 112578064Sume icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); 1126120856Sume return (-1); 112778064Sume case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ 1128181803Sbz V_ip6stat.ip6s_badoptions++; 112978064Sume ip6 = mtod(m, struct ip6_hdr *); 113078064Sume if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || 113178064Sume (m->m_flags & (M_BCAST|M_MCAST))) 113278064Sume m_freem(m); 113378064Sume else 113478064Sume icmp6_error(m, ICMP6_PARAM_PROB, 113578064Sume ICMP6_PARAMPROB_OPTION, off); 1136120856Sume return (-1); 113753541Sshin } 113853541Sshin 113953541Sshin m_freem(m); /* XXX: NOTREACHED */ 1140120856Sume return (-1); 114153541Sshin} 114253541Sshin 114353541Sshin/* 114462587Sitojun * Create the "control" list for this pcb. 1145179289Sbz * These functions will not modify mbuf chain at all. 114662587Sitojun * 1147179289Sbz * With KAME mbuf chain restriction: 114862587Sitojun * The routine will be called from upper layer handlers like tcp6_input(). 114962587Sitojun * Thus the routine assumes that the caller (tcp6_input) have already 115062587Sitojun * called IP6_EXTHDR_CHECK() and all the extension headers are located in the 115162587Sitojun * very first mbuf on the mbuf chain. 1152179289Sbz * 1153179289Sbz * ip6_savecontrol_v4 will handle those options that are possible to be 1154179289Sbz * set on a v4-mapped socket. 1155179289Sbz * ip6_savecontrol will directly call ip6_savecontrol_v4 to handle those 1156179289Sbz * options and handle the v6-only ones itself. 115753541Sshin */ 1158181782Sbzstruct mbuf ** 1159181782Sbzip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp, 1160181782Sbz int *v4only) 116153541Sshin{ 1162121674Sume struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 116353541Sshin 116478064Sume#ifdef SO_TIMESTAMP 1165179289Sbz if ((inp->inp_socket->so_options & SO_TIMESTAMP) != 0) { 116653541Sshin struct timeval tv; 116753541Sshin 116853541Sshin microtime(&tv); 116953541Sshin *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 1170120913Sume SCM_TIMESTAMP, SOL_SOCKET); 1171121472Sume if (*mp) 117253541Sshin mp = &(*mp)->m_next; 117397658Stanimura } 117462587Sitojun#endif 117562587Sitojun 1176181782Sbz if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 1177181782Sbz if (v4only != NULL) 1178181782Sbz *v4only = 1; 1179181782Sbz return (mp); 1180181782Sbz } 1181121631Sume 1182179289Sbz#define IS2292(inp, x, y) (((inp)->inp_flags & IN6P_RFC2292) ? (x) : (y)) 118353541Sshin /* RFC 2292 sec. 5 */ 1184179289Sbz if ((inp->inp_flags & IN6P_PKTINFO) != 0) { 118553541Sshin struct in6_pktinfo pi6; 1186120913Sume 118753541Sshin bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); 1188121315Sume in6_clearscope(&pi6.ipi6_addr); /* XXX */ 1189120913Sume pi6.ipi6_ifindex = 1190120913Sume (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; 1191120913Sume 119253541Sshin *mp = sbcreatecontrol((caddr_t) &pi6, 1193120913Sume sizeof(struct in6_pktinfo), 1194179289Sbz IS2292(inp, IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6); 1195121472Sume if (*mp) 119653541Sshin mp = &(*mp)->m_next; 119753541Sshin } 119878064Sume 1199179289Sbz if ((inp->inp_flags & IN6P_HOPLIMIT) != 0) { 120053541Sshin int hlim = ip6->ip6_hlim & 0xff; 1201120913Sume 1202120913Sume *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), 1203179289Sbz IS2292(inp, IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), 1204179289Sbz IPPROTO_IPV6); 1205121472Sume if (*mp) 120653541Sshin mp = &(*mp)->m_next; 120753541Sshin } 120853541Sshin 1209181782Sbz if (v4only != NULL) 1210181782Sbz *v4only = 0; 1211181782Sbz return (mp); 1212179289Sbz} 1213179289Sbz 1214179289Sbzvoid 1215179289Sbzip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) 1216179289Sbz{ 1217179289Sbz struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1218181782Sbz int v4only = 0; 1219179289Sbz 1220181782Sbz mp = ip6_savecontrol_v4(in6p, m, mp, &v4only); 1221181782Sbz if (v4only) 1222179289Sbz return; 1223179289Sbz 1224186141Sbz if ((in6p->inp_flags & IN6P_TCLASS) != 0) { 1225121472Sume u_int32_t flowinfo; 1226121472Sume int tclass; 1227121472Sume 1228121472Sume flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK); 1229121472Sume flowinfo >>= 20; 1230121472Sume 1231121472Sume tclass = flowinfo & 0xff; 1232121472Sume *mp = sbcreatecontrol((caddr_t) &tclass, sizeof(tclass), 1233121472Sume IPV6_TCLASS, IPPROTO_IPV6); 1234121472Sume if (*mp) 1235121472Sume mp = &(*mp)->m_next; 1236121472Sume } 1237121472Sume 123853541Sshin /* 1239130002Sume * IPV6_HOPOPTS socket option. Recall that we required super-user 1240130002Sume * privilege for the option (see ip6_ctloutput), but it might be too 1241130002Sume * strict, since there might be some hop-by-hop options which can be 1242130002Sume * returned to normal user. 1243130002Sume * See also RFC 2292 section 6 (or RFC 3542 section 8). 124453541Sshin */ 1245186141Sbz if ((in6p->inp_flags & IN6P_HOPOPTS) != 0) { 124653541Sshin /* 124753541Sshin * Check if a hop-by-hop options header is contatined in the 124853541Sshin * received packet, and if so, store the options as ancillary 124953541Sshin * data. Note that a hop-by-hop options header must be 1250120913Sume * just after the IPv6 header, which is assured through the 1251120913Sume * IPv6 input processing. 125253541Sshin */ 125353541Sshin if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { 125462587Sitojun struct ip6_hbh *hbh; 125578064Sume int hbhlen = 0; 125678064Sume#ifdef PULLDOWN_TEST 125778064Sume struct mbuf *ext; 125878064Sume#endif 125953541Sshin 126062587Sitojun#ifndef PULLDOWN_TEST 126162587Sitojun hbh = (struct ip6_hbh *)(ip6 + 1); 126262587Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 126362587Sitojun#else 126478064Sume ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), 126578064Sume ip6->ip6_nxt); 126678064Sume if (ext == NULL) { 1267181803Sbz V_ip6stat.ip6s_tooshort++; 126862587Sitojun return; 126962587Sitojun } 127078064Sume hbh = mtod(ext, struct ip6_hbh *); 127162587Sitojun hbhlen = (hbh->ip6h_len + 1) << 3; 127278064Sume if (hbhlen != ext->m_len) { 127378064Sume m_freem(ext); 1274181803Sbz V_ip6stat.ip6s_tooshort++; 127562587Sitojun return; 127662587Sitojun } 127762587Sitojun#endif 127862587Sitojun 127953541Sshin /* 1280120913Sume * XXX: We copy the whole header even if a 1281120913Sume * jumbo payload option is included, the option which 1282120913Sume * is to be removed before returning according to 1283120913Sume * RFC2292. 1284148169Sume * Note: this constraint is removed in RFC3542 128553541Sshin */ 128662587Sitojun *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, 1287179289Sbz IS2292(in6p, IPV6_2292HOPOPTS, IPV6_HOPOPTS), 1288121472Sume IPPROTO_IPV6); 1289121472Sume if (*mp) 129053541Sshin mp = &(*mp)->m_next; 129178064Sume#ifdef PULLDOWN_TEST 129278064Sume m_freem(ext); 129378064Sume#endif 129453541Sshin } 129553541Sshin } 129653541Sshin 1297186141Sbz if ((in6p->inp_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) { 129878064Sume int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); 129953541Sshin 130053541Sshin /* 130153541Sshin * Search for destination options headers or routing 130253541Sshin * header(s) through the header chain, and stores each 130353541Sshin * header as ancillary data. 130453541Sshin * Note that the order of the headers remains in 130553541Sshin * the chain of ancillary data. 130653541Sshin */ 130778064Sume while (1) { /* is explicit loop prevention necessary? */ 130878064Sume struct ip6_ext *ip6e = NULL; 130962587Sitojun int elen; 131078064Sume#ifdef PULLDOWN_TEST 131178064Sume struct mbuf *ext = NULL; 131278064Sume#endif 131353541Sshin 131478064Sume /* 131578064Sume * if it is not an extension header, don't try to 131678064Sume * pull it from the chain. 131778064Sume */ 131878064Sume switch (nxt) { 131978064Sume case IPPROTO_DSTOPTS: 132078064Sume case IPPROTO_ROUTING: 132178064Sume case IPPROTO_HOPOPTS: 132278064Sume case IPPROTO_AH: /* is it possible? */ 132378064Sume break; 132478064Sume default: 132578064Sume goto loopend; 132678064Sume } 132778064Sume 132862587Sitojun#ifndef PULLDOWN_TEST 132978064Sume if (off + sizeof(*ip6e) > m->m_len) 133078064Sume goto loopend; 133162587Sitojun ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); 133262587Sitojun if (nxt == IPPROTO_AH) 133362587Sitojun elen = (ip6e->ip6e_len + 2) << 2; 133462587Sitojun else 133562587Sitojun elen = (ip6e->ip6e_len + 1) << 3; 133678064Sume if (off + elen > m->m_len) 133778064Sume goto loopend; 133862587Sitojun#else 133978064Sume ext = ip6_pullexthdr(m, off, nxt); 134078064Sume if (ext == NULL) { 1341181803Sbz V_ip6stat.ip6s_tooshort++; 134262587Sitojun return; 134362587Sitojun } 134478064Sume ip6e = mtod(ext, struct ip6_ext *); 134562587Sitojun if (nxt == IPPROTO_AH) 134662587Sitojun elen = (ip6e->ip6e_len + 2) << 2; 134762587Sitojun else 134862587Sitojun elen = (ip6e->ip6e_len + 1) << 3; 134978064Sume if (elen != ext->m_len) { 135078064Sume m_freem(ext); 1351181803Sbz V_ip6stat.ip6s_tooshort++; 135262587Sitojun return; 135362587Sitojun } 135462587Sitojun#endif 135562587Sitojun 135678064Sume switch (nxt) { 135778064Sume case IPPROTO_DSTOPTS: 1358186141Sbz if (!(in6p->inp_flags & IN6P_DSTOPTS)) 135978064Sume break; 136053541Sshin 136178064Sume *mp = sbcreatecontrol((caddr_t)ip6e, elen, 1362179289Sbz IS2292(in6p, 1363179289Sbz IPV6_2292DSTOPTS, IPV6_DSTOPTS), 1364120913Sume IPPROTO_IPV6); 136578064Sume if (*mp) 136678064Sume mp = &(*mp)->m_next; 136778064Sume break; 136878064Sume case IPPROTO_ROUTING: 1369186141Sbz if (!in6p->inp_flags & IN6P_RTHDR) 137078064Sume break; 137153541Sshin 137278064Sume *mp = sbcreatecontrol((caddr_t)ip6e, elen, 1373179289Sbz IS2292(in6p, IPV6_2292RTHDR, IPV6_RTHDR), 1374120913Sume IPPROTO_IPV6); 137578064Sume if (*mp) 137678064Sume mp = &(*mp)->m_next; 137778064Sume break; 137878064Sume case IPPROTO_HOPOPTS: 137978064Sume case IPPROTO_AH: /* is it possible? */ 138078064Sume break; 138153541Sshin 138278064Sume default: 138378064Sume /* 1384171260Sdelphij * other cases have been filtered in the above. 138578064Sume * none will visit this case. here we supply 138678064Sume * the code just in case (nxt overwritten or 138778064Sume * other cases). 138878064Sume */ 138978064Sume#ifdef PULLDOWN_TEST 139078064Sume m_freem(ext); 139178064Sume#endif 139278064Sume goto loopend; 139353541Sshin 139453541Sshin } 139553541Sshin 139653541Sshin /* proceed with the next header. */ 139762587Sitojun off += elen; 139853541Sshin nxt = ip6e->ip6e_nxt; 139978064Sume ip6e = NULL; 140078064Sume#ifdef PULLDOWN_TEST 140178064Sume m_freem(ext); 140278064Sume ext = NULL; 140378064Sume#endif 140453541Sshin } 140553541Sshin loopend: 140678064Sume ; 140753541Sshin } 1408179289Sbz} 1409121472Sume#undef IS2292 141078064Sume 1411125776Sumevoid 1412171259Sdelphijip6_notify_pmtu(struct inpcb *in6p, struct sockaddr_in6 *dst, u_int32_t *mtu) 1413125776Sume{ 1414125776Sume struct socket *so; 1415125776Sume struct mbuf *m_mtu; 1416125776Sume struct ip6_mtuinfo mtuctl; 1417125776Sume 1418125776Sume so = in6p->inp_socket; 1419125776Sume 1420125776Sume if (mtu == NULL) 1421125776Sume return; 1422125776Sume 1423125776Sume#ifdef DIAGNOSTIC 1424125776Sume if (so == NULL) /* I believe this is impossible */ 1425125776Sume panic("ip6_notify_pmtu: socket is NULL"); 1426125776Sume#endif 1427125776Sume 1428125776Sume bzero(&mtuctl, sizeof(mtuctl)); /* zero-clear for safety */ 1429125776Sume mtuctl.ip6m_mtu = *mtu; 1430125776Sume mtuctl.ip6m_addr = *dst; 1431148385Sume if (sa6_recoverscope(&mtuctl.ip6m_addr)) 1432148385Sume return; 1433125776Sume 1434125776Sume if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl), 1435125776Sume IPV6_PATHMTU, IPPROTO_IPV6)) == NULL) 1436125776Sume return; 1437125776Sume 1438125776Sume if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu) 1439125776Sume == 0) { 1440125776Sume m_freem(m_mtu); 1441125776Sume /* XXX: should count statistics */ 1442125776Sume } else 1443125776Sume sorwakeup(so); 1444125776Sume 1445125776Sume return; 1446125776Sume} 1447125776Sume 144878064Sume#ifdef PULLDOWN_TEST 144978064Sume/* 145078064Sume * pull single extension header from mbuf chain. returns single mbuf that 145178064Sume * contains the result, or NULL on error. 145278064Sume */ 145378064Sumestatic struct mbuf * 1454171259Sdelphijip6_pullexthdr(struct mbuf *m, size_t off, int nxt) 145578064Sume{ 145678064Sume struct ip6_ext ip6e; 145778064Sume size_t elen; 145878064Sume struct mbuf *n; 145978064Sume 146078064Sume#ifdef DIAGNOSTIC 146178064Sume switch (nxt) { 146278064Sume case IPPROTO_DSTOPTS: 146378064Sume case IPPROTO_ROUTING: 146478064Sume case IPPROTO_HOPOPTS: 146578064Sume case IPPROTO_AH: /* is it possible? */ 146678064Sume break; 146778064Sume default: 146878064Sume printf("ip6_pullexthdr: invalid nxt=%d\n", nxt); 146953541Sshin } 147078064Sume#endif 147178064Sume 147278064Sume m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 147378064Sume if (nxt == IPPROTO_AH) 147478064Sume elen = (ip6e.ip6e_len + 2) << 2; 147578064Sume else 147678064Sume elen = (ip6e.ip6e_len + 1) << 3; 147778064Sume 1478111119Simp MGET(n, M_DONTWAIT, MT_DATA); 147978064Sume if (n && elen >= MLEN) { 1480111119Simp MCLGET(n, M_DONTWAIT); 148178064Sume if ((n->m_flags & M_EXT) == 0) { 148278064Sume m_free(n); 148378064Sume n = NULL; 148478064Sume } 148553541Sshin } 148678064Sume if (!n) 148778064Sume return NULL; 148862587Sitojun 148978064Sume n->m_len = 0; 149078064Sume if (elen >= M_TRAILINGSPACE(n)) { 149178064Sume m_free(n); 149278064Sume return NULL; 149378064Sume } 149478064Sume 149578064Sume m_copydata(m, off, elen, mtod(n, caddr_t)); 149678064Sume n->m_len = elen; 149778064Sume return n; 149853541Sshin} 149978064Sume#endif 150053541Sshin 150153541Sshin/* 150253541Sshin * Get pointer to the previous header followed by the header 150353541Sshin * currently processed. 150453541Sshin * XXX: This function supposes that 150553541Sshin * M includes all headers, 150653541Sshin * the next header field and the header length field of each header 150753541Sshin * are valid, and 150853541Sshin * the sum of each header length equals to OFF. 150953541Sshin * Because of these assumptions, this function must be called very 151053541Sshin * carefully. Moreover, it will not be used in the near future when 151153541Sshin * we develop `neater' mechanism to process extension headers. 151253541Sshin */ 151353541Sshinchar * 1514171259Sdelphijip6_get_prevhdr(struct mbuf *m, int off) 151553541Sshin{ 151653541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 151753541Sshin 151853541Sshin if (off == sizeof(struct ip6_hdr)) 1519120856Sume return (&ip6->ip6_nxt); 152053541Sshin else { 152153541Sshin int len, nxt; 152253541Sshin struct ip6_ext *ip6e = NULL; 152353541Sshin 152453541Sshin nxt = ip6->ip6_nxt; 152553541Sshin len = sizeof(struct ip6_hdr); 152653541Sshin while (len < off) { 152753541Sshin ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); 152853541Sshin 152978064Sume switch (nxt) { 153053541Sshin case IPPROTO_FRAGMENT: 153153541Sshin len += sizeof(struct ip6_frag); 153253541Sshin break; 153353541Sshin case IPPROTO_AH: 153453541Sshin len += (ip6e->ip6e_len + 2) << 2; 153553541Sshin break; 153653541Sshin default: 153753541Sshin len += (ip6e->ip6e_len + 1) << 3; 153853541Sshin break; 153953541Sshin } 154053541Sshin nxt = ip6e->ip6e_nxt; 154153541Sshin } 154253541Sshin if (ip6e) 1543120856Sume return (&ip6e->ip6e_nxt); 154453541Sshin else 154553541Sshin return NULL; 154653541Sshin } 154753541Sshin} 154853541Sshin 154953541Sshin/* 155062587Sitojun * get next header offset. m will be retained. 155162587Sitojun */ 155262587Sitojunint 1553171259Sdelphijip6_nexthdr(struct mbuf *m, int off, int proto, int *nxtp) 155462587Sitojun{ 155562587Sitojun struct ip6_hdr ip6; 155662587Sitojun struct ip6_ext ip6e; 155762587Sitojun struct ip6_frag fh; 155862587Sitojun 155962587Sitojun /* just in case */ 156062587Sitojun if (m == NULL) 156162587Sitojun panic("ip6_nexthdr: m == NULL"); 156262587Sitojun if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) 156362587Sitojun return -1; 156462587Sitojun 156562587Sitojun switch (proto) { 156662587Sitojun case IPPROTO_IPV6: 156762587Sitojun if (m->m_pkthdr.len < off + sizeof(ip6)) 156862587Sitojun return -1; 156962587Sitojun m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); 157062587Sitojun if (nxtp) 157162587Sitojun *nxtp = ip6.ip6_nxt; 157262587Sitojun off += sizeof(ip6); 157362587Sitojun return off; 157462587Sitojun 157562587Sitojun case IPPROTO_FRAGMENT: 157662587Sitojun /* 157762587Sitojun * terminate parsing if it is not the first fragment, 157862587Sitojun * it does not make sense to parse through it. 157962587Sitojun */ 158062587Sitojun if (m->m_pkthdr.len < off + sizeof(fh)) 158162587Sitojun return -1; 158262587Sitojun m_copydata(m, off, sizeof(fh), (caddr_t)&fh); 1583120978Sume /* IP6F_OFF_MASK = 0xfff8(BigEndian), 0xf8ff(LittleEndian) */ 1584120978Sume if (fh.ip6f_offlg & IP6F_OFF_MASK) 158562587Sitojun return -1; 158662587Sitojun if (nxtp) 158762587Sitojun *nxtp = fh.ip6f_nxt; 158862587Sitojun off += sizeof(struct ip6_frag); 158962587Sitojun return off; 159062587Sitojun 159162587Sitojun case IPPROTO_AH: 159262587Sitojun if (m->m_pkthdr.len < off + sizeof(ip6e)) 159362587Sitojun return -1; 159462587Sitojun m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 159562587Sitojun if (nxtp) 159662587Sitojun *nxtp = ip6e.ip6e_nxt; 159762587Sitojun off += (ip6e.ip6e_len + 2) << 2; 159862587Sitojun return off; 159962587Sitojun 160062587Sitojun case IPPROTO_HOPOPTS: 160162587Sitojun case IPPROTO_ROUTING: 160262587Sitojun case IPPROTO_DSTOPTS: 160362587Sitojun if (m->m_pkthdr.len < off + sizeof(ip6e)) 160462587Sitojun return -1; 160562587Sitojun m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); 160662587Sitojun if (nxtp) 160762587Sitojun *nxtp = ip6e.ip6e_nxt; 160862587Sitojun off += (ip6e.ip6e_len + 1) << 3; 160962587Sitojun return off; 161062587Sitojun 161162587Sitojun case IPPROTO_NONE: 161262587Sitojun case IPPROTO_ESP: 161362587Sitojun case IPPROTO_IPCOMP: 161462587Sitojun /* give up */ 161562587Sitojun return -1; 161662587Sitojun 161762587Sitojun default: 161862587Sitojun return -1; 161962587Sitojun } 162062587Sitojun 162162587Sitojun return -1; 162262587Sitojun} 162362587Sitojun 162462587Sitojun/* 162562587Sitojun * get offset for the last header in the chain. m will be kept untainted. 162662587Sitojun */ 162762587Sitojunint 1628171259Sdelphijip6_lasthdr(struct mbuf *m, int off, int proto, int *nxtp) 162962587Sitojun{ 163062587Sitojun int newoff; 163162587Sitojun int nxt; 163262587Sitojun 163362587Sitojun if (!nxtp) { 163462587Sitojun nxt = -1; 163562587Sitojun nxtp = &nxt; 163662587Sitojun } 163762587Sitojun while (1) { 163862587Sitojun newoff = ip6_nexthdr(m, off, proto, nxtp); 163962587Sitojun if (newoff < 0) 164062587Sitojun return off; 164162587Sitojun else if (newoff < off) 164262587Sitojun return -1; /* invalid */ 164362587Sitojun else if (newoff == off) 164462587Sitojun return newoff; 164562587Sitojun 164662587Sitojun off = newoff; 164762587Sitojun proto = *nxtp; 164862587Sitojun } 164962587Sitojun} 165062587Sitojun 1651121673Sumestruct ip6aux * 1652171259Sdelphijip6_addaux(struct mbuf *m) 165378064Sume{ 1654120913Sume struct m_tag *mtag; 1655120913Sume 1656120913Sume mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); 1657120913Sume if (!mtag) { 1658120913Sume mtag = m_tag_get(PACKET_TAG_IPV6_INPUT, sizeof(struct ip6aux), 1659120913Sume M_NOWAIT); 1660121630Sume if (mtag) { 1661120913Sume m_tag_prepend(m, mtag); 1662121630Sume bzero(mtag + 1, sizeof(struct ip6aux)); 1663121630Sume } 166478064Sume } 1665121673Sume return mtag ? (struct ip6aux *)(mtag + 1) : NULL; 166678064Sume} 166778064Sume 1668121673Sumestruct ip6aux * 1669171259Sdelphijip6_findaux(struct mbuf *m) 167078064Sume{ 1671120913Sume struct m_tag *mtag; 1672120913Sume 1673120913Sume mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); 1674121673Sume return mtag ? (struct ip6aux *)(mtag + 1) : NULL; 167578064Sume} 167678064Sume 167778064Sumevoid 1678171259Sdelphijip6_delaux(struct mbuf *m) 167978064Sume{ 1680120913Sume struct m_tag *mtag; 1681120913Sume 1682120913Sume mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); 1683120913Sume if (mtag) 1684120913Sume m_tag_delete(m, mtag); 168578064Sume} 168678064Sume 168762587Sitojun/* 168853541Sshin * System control for IP6 168953541Sshin */ 169053541Sshin 169153541Sshinu_char inet6ctlerrmap[PRC_NCMDS] = { 169253541Sshin 0, 0, 0, 0, 169353541Sshin 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 169453541Sshin EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 169553541Sshin EMSGSIZE, EHOSTUNREACH, 0, 0, 169653541Sshin 0, 0, 0, 0, 169753541Sshin ENOPROTOOPT 169853541Sshin}; 1699