Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.140.2.4 retrieving revision 1.149.2.2 diff -u -p -r1.140.2.4 -r1.149.2.2 --- src/sys/netinet6/ip6_input.c 2017/12/03 11:39:04 1.140.2.4 +++ src/sys/netinet6/ip6_input.c 2018/01/30 18:28:45 1.149.2.2 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.140.2.4 2017/12/03 11:39:04 jdolecek Exp $ */ +/* $NetBSD: ip6_input.c,v 1.149.2.2 2018/01/30 18:28:45 martin Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -62,18 +62,17 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.140.2.4 2017/12/03 11:39:04 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.149.2.2 2018/01/30 18:28:45 martin Exp $"); -#ifdef _KERNEL_OPT #include "opt_gateway.h" #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" -#include "opt_net_mpsafe.h" -#endif +#include "opt_compat_netbsd.h" #include #include +#include #include #include #include @@ -86,7 +85,6 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include #include -#include #include #include @@ -119,17 +117,30 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #endif /* IPSEC */ +#ifdef COMPAT_50 +#include +#include +#endif + #include #include "faith.h" +#include "gif.h" + +#if NGIF > 0 +#include +#endif #include extern struct domain inet6domain; u_char ip6_protox[IPPROTO_MAX]; +struct in6_ifaddr *in6_ifaddr; pktqueue_t *ip6_pktq __read_mostly; +extern callout_t in6_tmpaddrtimer_ch; + int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ @@ -138,9 +149,7 @@ pfil_head_t *inet6_pfil_hook; percpu_t *ip6stat_percpu; -percpu_t *ip6_forward_rt_percpu __cacheline_aligned; - -static void ip6_init2(void); +static void ip6_init2(void *); static void ip6intr(void *); static struct m_tag *ip6_setdstifaddr(struct mbuf *, const struct in6_ifaddr *); @@ -149,14 +158,6 @@ static int ip6_process_hopopts(struct mb static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); static void sysctl_net_inet6_ip6_setup(struct sysctllog **); -#ifdef NET_MPSAFE -#define SOFTNET_LOCK() mutex_enter(softnet_lock) -#define SOFTNET_UNLOCK() mutex_exit(softnet_lock) -#else -#define SOFTNET_LOCK() KASSERT(mutex_owned(softnet_lock)) -#define SOFTNET_UNLOCK() KASSERT(mutex_owned(softnet_lock)) -#endif - /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. @@ -167,8 +168,6 @@ ip6_init(void) const struct ip6protosw *pr; int i; - in6_init(); - sysctl_net_inet6_ip6_setup(NULL); pr = (const struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == 0) @@ -190,7 +189,7 @@ ip6_init(void) frag6_init(); ip6_desync_factor = cprng_fast32() % MAX_TEMP_DESYNC_FACTOR; - ip6_init2(); + ip6_init2(NULL); #ifdef GATEWAY ip6flow_init(ip6_hashsize); #endif @@ -199,13 +198,16 @@ ip6_init(void) KASSERT(inet6_pfil_hook != NULL); ip6stat_percpu = percpu_alloc(sizeof(uint64_t) * IP6_NSTATS); - ip6_forward_rt_percpu = percpu_alloc(sizeof(struct route)); } static void -ip6_init2(void) +ip6_init2(void *dummy) { + /* nd6_timer_init */ + callout_init(&nd6_timer_ch, CALLOUT_MPSAFE); + callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); + /* timer for regeneranation of temporary addresses randomize ID */ callout_init(&in6_tmpaddrtimer_ch, CALLOUT_MPSAFE); callout_reset(&in6_tmpaddrtimer_ch, @@ -222,31 +224,26 @@ ip6intr(void *arg __unused) { struct mbuf *m; - SOFTNET_LOCK_UNLESS_NET_MPSAFE(); + mutex_enter(softnet_lock); while ((m = pktq_dequeue(ip6_pktq)) != NULL) { - struct psref psref; - struct ifnet *rcvif = m_get_rcvif_psref(m, &psref); + const ifnet_t *ifp = m->m_pkthdr.rcvif; - if (rcvif == NULL) { - m_freem(m); - continue; - } /* * Drop the packet if IPv6 is disabled on the interface. */ - if ((ND_IFINFO(rcvif)->flags & ND6_IFF_IFDISABLED)) { - m_put_rcvif_psref(rcvif, &psref); + if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { m_freem(m); continue; } - ip6_input(m, rcvif); - m_put_rcvif_psref(rcvif, &psref); + ip6_input(m); } - SOFTNET_UNLOCK_UNLESS_NET_MPSAFE(); + mutex_exit(softnet_lock); } +extern struct route ip6_forward_rt; + void -ip6_input(struct mbuf *m, struct ifnet *rcvif) +ip6_input(struct mbuf *m) { struct ip6_hdr *ip6; int hit, off = sizeof(struct ip6_hdr), nest; @@ -255,12 +252,11 @@ ip6_input(struct mbuf *m, struct ifnet * int nxt, ours = 0, rh_present = 0; struct ifnet *deliverifp = NULL; int srcrt = 0; - struct rtentry *rt = NULL; + const struct rtentry *rt; union { struct sockaddr dst; struct sockaddr_in6 dst6; } u; - struct route *ro; /* * make sure we don't have onion peering information into m_tag. @@ -278,18 +274,19 @@ ip6_input(struct mbuf *m, struct ifnet * } else { #define M2MMAX 32 if (m->m_next) { - if (m->m_flags & M_LOOP) + if (m->m_flags & M_LOOP) { /*XXX*/ IP6_STATINC(IP6_STAT_M2M + lo0ifp->if_index); - else if (rcvif->if_index < M2MMAX) - IP6_STATINC(IP6_STAT_M2M + rcvif->if_index); - else + } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) { + IP6_STATINC(IP6_STAT_M2M + + m->m_pkthdr.rcvif->if_index); + } else IP6_STATINC(IP6_STAT_M2M); } else IP6_STATINC(IP6_STAT_M1); #undef M2MMAX } - in6_ifstat_inc(rcvif, ifs6_in_receive); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); IP6_STATINC(IP6_STAT_TOTAL); /* @@ -299,17 +296,19 @@ ip6_input(struct mbuf *m, struct ifnet * * IPv6 header is in the first mbuf of the chain. */ if (IP6_HDR_ALIGNED_P(mtod(m, void *)) == 0) { + struct ifnet *inifp = m->m_pkthdr.rcvif; if ((m = m_copyup(m, sizeof(struct ip6_hdr), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ IP6_STATINC(IP6_STAT_TOOSMALL); - in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(inifp, ifs6_in_hdrerr); return; } } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { + struct ifnet *inifp = m->m_pkthdr.rcvif; if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { IP6_STATINC(IP6_STAT_TOOSMALL); - in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(inifp, ifs6_in_hdrerr); return; } } @@ -318,7 +317,7 @@ ip6_input(struct mbuf *m, struct ifnet * if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { IP6_STATINC(IP6_STAT_BADVERS); - in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } @@ -348,7 +347,8 @@ ip6_input(struct mbuf *m, struct ifnet * struct in6_addr odst; odst = ip6->ip6_dst; - if (pfil_run_hooks(inet6_pfil_hook, &m, rcvif, PFIL_IN) != 0) + if (pfil_run_hooks(inet6_pfil_hook, &m, m->m_pkthdr.rcvif, + PFIL_IN) != 0) return; if (m == NULL) return; @@ -359,14 +359,9 @@ ip6_input(struct mbuf *m, struct ifnet * IP6_STATINC(IP6_STAT_NXTHIST + ip6->ip6_nxt); #ifdef ALTQ - if (altq_input != NULL) { - SOFTNET_LOCK(); - if ((*altq_input)(m, AF_INET6) == 0) { - SOFTNET_UNLOCK(); - /* packet is dropped by traffic conditioner */ - return; - } - SOFTNET_UNLOCK(); + if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { + /* packet is dropped by traffic conditioner */ + return; } #endif @@ -379,7 +374,7 @@ ip6_input(struct mbuf *m, struct ifnet * * XXX: "badscope" is not very suitable for a multicast source. */ IP6_STATINC(IP6_STAT_BADSCOPE); - in6_ifstat_inc(rcvif, ifs6_in_addrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } /* @@ -397,7 +392,7 @@ ip6_input(struct mbuf *m, struct ifnet * if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6_STATINC(IP6_STAT_BADSCOPE); - in6_ifstat_inc(rcvif, ifs6_in_addrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } #if 0 @@ -411,7 +406,7 @@ ip6_input(struct mbuf *m, struct ifnet * if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { IP6_STATINC(IP6_STAT_BADSCOPE); - in6_ifstat_inc(rcvif, ifs6_in_addrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } #endif @@ -434,36 +429,35 @@ ip6_input(struct mbuf *m, struct ifnet * IP6_STATINC(IP6_STAT_BADSCOPE); /* XXX */ goto bad; } - if (in6_setscope(&ip6->ip6_src, rcvif, NULL) || - in6_setscope(&ip6->ip6_dst, rcvif, NULL)) { + if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || + in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { IP6_STATINC(IP6_STAT_BADSCOPE); goto bad; } - ro = percpu_getref(ip6_forward_rt_percpu); /* * Multicast check */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - bool ingroup; + struct in6_multi *in6m = 0; - in6_ifstat_inc(rcvif, ifs6_in_mcast); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); /* * See if we belong to the destination multicast group on the * arrival interface. */ - ingroup = in6_multi_group(&ip6->ip6_dst, rcvif); - if (ingroup) + IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m); + if (in6m) ours = 1; else if (!ip6_mrouter) { uint64_t *ip6s = IP6_STAT_GETREF(); ip6s[IP6_STAT_NOTMEMBER]++; ip6s[IP6_STAT_CANTFORWARD]++; IP6_STAT_PUTREF(); - in6_ifstat_inc(rcvif, ifs6_in_discard); - goto bad_unref; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); + goto bad; } - deliverifp = rcvif; + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } @@ -472,7 +466,7 @@ ip6_input(struct mbuf *m, struct ifnet * /* * Unicast check */ - rt = rtcache_lookup2(ro, &u.dst, 1, &hit); + rt = rtcache_lookup2(&ip6_forward_rt, &u.dst, 1, &hit); if (hit) IP6_STATINC(IP6_STAT_FORWARD_CACHEHIT); else @@ -491,6 +485,7 @@ ip6_input(struct mbuf *m, struct ifnet * */ if (rt != NULL && (rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && + !(rt->rt_flags & RTF_CLONED) && #if 0 /* * The check below is redundant since the comparison of @@ -501,46 +496,25 @@ ip6_input(struct mbuf *m, struct ifnet * #endif rt->rt_ifp->if_type == IFT_LOOP) { struct in6_ifaddr *ia6 = (struct in6_ifaddr *)rt->rt_ifa; - int addrok; - if (ia6->ia6_flags & IN6_IFF_ANYCAST) m->m_flags |= M_ANYCAST6; /* * packets to a tentative, duplicated, or somehow invalid * address must not be accepted. */ - if (ia6->ia6_flags & IN6_IFF_NOTREADY) - addrok = 0; - else if (ia6->ia6_flags & IN6_IFF_DETACHED && - !IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) - { - /* Allow internal traffic to DETACHED addresses */ - struct sockaddr_in6 sin6; - int s; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(sin6); - sin6.sin6_addr = ip6->ip6_src; - s = pserialize_read_enter(); - addrok = (ifa_ifwithaddr(sin6tosa(&sin6)) != NULL); - pserialize_read_exit(s); - } else - addrok = 1; - if (addrok) { + if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { /* this address is ready */ ours = 1; deliverifp = ia6->ia_ifp; /* correct? */ goto hbhcheck; } else { /* address is not ready, so discard the packet. */ - char ip6bufs[INET6_ADDRSTRLEN]; - char ip6bufd[INET6_ADDRSTRLEN]; - nd6log(LOG_INFO, "packet to an unready address %s->%s\n", - IN6_PRINT(ip6bufs, &ip6->ip6_src), - IN6_PRINT(ip6bufd, &ip6->ip6_dst)); + nd6log((LOG_INFO, + "ip6_input: packet to an unready address %s->%s\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&ip6->ip6_dst))); - goto bad_unref; + goto bad; } } @@ -567,7 +541,9 @@ ip6_input(struct mbuf *m, struct ifnet * * working right. */ struct ifaddr *ifa; - IFADDR_READER_FOREACH(ifa, rcvif) { + IFADDR_FOREACH(ifa, m->m_pkthdr.rcvif) { + if (ifa->ifa_addr == NULL) + continue; /* just for safety */ if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) { @@ -585,8 +561,8 @@ ip6_input(struct mbuf *m, struct ifnet * */ if (!ip6_forwarding) { IP6_STATINC(IP6_STAT_CANTFORWARD); - in6_ifstat_inc(rcvif, ifs6_in_discard); - goto bad_unref; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); + goto bad; } hbhcheck: @@ -598,10 +574,8 @@ ip6_input(struct mbuf *m, struct ifnet * */ if (deliverifp && ip6_getdstifaddr(m) == NULL) { struct in6_ifaddr *ia6; - int s = pserialize_read_enter(); ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); - /* Depends on ip6_setdstifaddr never sleep */ if (ia6 != NULL && ip6_setdstifaddr(m, ia6) == NULL) { /* * XXX maybe we should drop the packet here, @@ -609,7 +583,6 @@ ip6_input(struct mbuf *m, struct ifnet * * to the upper layers. */ } - pserialize_read_exit(s); } /* @@ -623,10 +596,8 @@ ip6_input(struct mbuf *m, struct ifnet * if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) { #if 0 /*touches NULL pointer*/ - in6_ifstat_inc(rcvif, ifs6_in_discard); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); #endif - rtcache_unref(rt, ro); - percpu_putref(ip6_forward_rt_percpu); return; /* m have already been freed */ } @@ -645,21 +616,17 @@ ip6_input(struct mbuf *m, struct ifnet * * (non-zero) payload length to the variable plen. */ IP6_STATINC(IP6_STAT_BADOPTIONS); - in6_ifstat_inc(rcvif, ifs6_in_discard); - in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, (char *)&ip6->ip6_plen - (char *)ip6); - rtcache_unref(rt, ro); - percpu_putref(ip6_forward_rt_percpu); return; } IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { IP6_STATINC(IP6_STAT_TOOSHORT); - rtcache_unref(rt, ro); - percpu_putref(ip6_forward_rt_percpu); return; } KASSERT(IP6_HDR_ALIGNED_P(hbh)); @@ -682,8 +649,8 @@ ip6_input(struct mbuf *m, struct ifnet * */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { IP6_STATINC(IP6_STAT_TOOSHORT); - in6_ifstat_inc(rcvif, ifs6_in_truncated); - goto bad_unref; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); + goto bad; } if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { if (m->m_len == m->m_pkthdr.len) { @@ -705,25 +672,16 @@ ip6_input(struct mbuf *m, struct ifnet * * ip6_mforward() returns a non-zero value, the packet * must be discarded, else it may be accepted below. */ - if (ip6_mrouter != NULL) { - int error; - - SOFTNET_LOCK(); - error = ip6_mforward(ip6, rcvif, m); - SOFTNET_UNLOCK(); - - if (error != 0) { - rtcache_unref(rt, ro); - percpu_putref(ip6_forward_rt_percpu); - IP6_STATINC(IP6_STAT_CANTFORWARD); - goto bad; - } + if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { + IP6_STATINC(IP6_STAT_CANTFORWARD); + m_freem(m); + return; + } + if (!ours) { + m_freem(m); + return; } - if (!ours) - goto bad_unref; } else if (!ours) { - rtcache_unref(rt, ro); - percpu_putref(ip6_forward_rt_percpu); ip6_forward(m, srcrt); return; } @@ -742,8 +700,8 @@ ip6_input(struct mbuf *m, struct ifnet * if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6_STATINC(IP6_STAT_BADSCOPE); - in6_ifstat_inc(rcvif, ifs6_in_addrerr); - goto bad_unref; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; } /* @@ -752,28 +710,20 @@ ip6_input(struct mbuf *m, struct ifnet * #ifdef IFA_STATS if (deliverifp != NULL) { struct in6_ifaddr *ia6; - int s = pserialize_read_enter(); ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); if (ia6) ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len; - pserialize_read_exit(s); } #endif IP6_STATINC(IP6_STAT_DELIVERED); in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; - if (rt != NULL) { - rtcache_unref(rt, ro); - rt = NULL; - } - percpu_putref(ip6_forward_rt_percpu); - rh_present = 0; while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { IP6_STATINC(IP6_STAT_TOOMANYHDR); - in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } @@ -783,13 +733,14 @@ ip6_input(struct mbuf *m, struct ifnet * */ if (m->m_pkthdr.len < off) { IP6_STATINC(IP6_STAT_TOOSHORT); - in6_ifstat_inc(rcvif, ifs6_in_truncated); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } if (nxt == IPPROTO_ROUTING) { if (rh_present++) { - in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(m->m_pkthdr.rcvif, + ifs6_in_hdrerr); IP6_STATINC(IP6_STAT_BADOPTIONS); goto bad; } @@ -797,6 +748,11 @@ ip6_input(struct mbuf *m, struct ifnet * #ifdef IPSEC if (ipsec_used) { + struct m_tag *mtag; + struct tdb_ident *tdbi; + struct secpolicy *sp; + int s, error; + /* * enforce IPsec policy checking if we are seeing last * header. note that we do not visit this with @@ -804,9 +760,39 @@ ip6_input(struct mbuf *m, struct ifnet * */ if ((inet6sw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0) { - int error; - - error = ipsec6_input(m); + /* + * Check if the packet has already had IPsec + * processing done. If so, then just pass it + * along. This tag gets set during AH, ESP, + * etc. input handling, before the packet is + * returned to the ip input queue for delivery. + */ + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, + NULL); + s = splsoftnet(); + if (mtag != NULL) { + tdbi = (struct tdb_ident *)(mtag + 1); + sp = ipsec_getpolicy(tdbi, + IPSEC_DIR_INBOUND); + } else { + sp = ipsec_getpolicybyaddr(m, + IPSEC_DIR_INBOUND, IP_FORWARDING, + &error); + } + if (sp != NULL) { + /* + * Check security policy against packet + * attributes. + */ + error = ipsec_in_reject(sp, m); + KEY_FREESP(&sp); + } else { + /* XXX error stat??? */ + error = EINVAL; + DPRINTF(("ip6_input: no SP, packet" + " discarded\n"));/*XXX*/ + } + splx(s); if (error) goto bad; } @@ -816,13 +802,8 @@ ip6_input(struct mbuf *m, struct ifnet * nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; - - bad_unref: - rtcache_unref(rt, ro); - percpu_putref(ip6_forward_rt_percpu); bad: m_freem(m); - return; } /* @@ -1091,15 +1072,33 @@ void ip6_savecontrol(struct in6pcb *in6p, struct mbuf **mp, struct ip6_hdr *ip6, struct mbuf *m) { - struct socket *so = in6p->in6p_socket; #ifdef RFC2292 #define IS2292(x, y) ((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y)) #else #define IS2292(x, y) (y) #endif - if (SOOPT_TIMESTAMP(so->so_options)) - mp = sbsavetimestamp(so->so_options, m, mp); + if (in6p->in6p_socket->so_options & SO_TIMESTAMP +#ifdef SO_OTIMESTAMP + || in6p->in6p_socket->so_options & SO_OTIMESTAMP +#endif + ) { + struct timeval tv; + + microtime(&tv); +#ifdef SO_OTIMESTAMP + if (in6p->in6p_socket->so_options & SO_OTIMESTAMP) { + struct timeval50 tv50; + timeval_to_timeval50(&tv, &tv50); + *mp = sbcreatecontrol((void *) &tv50, sizeof(tv50), + SCM_OTIMESTAMP, SOL_SOCKET); + } else +#endif + *mp = sbcreatecontrol((void *) &tv, sizeof(tv), + SCM_TIMESTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } /* some OSes call this logic with IPv4 packet, for SO_TIMESTAMP */ if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) @@ -1111,8 +1110,10 @@ ip6_savecontrol(struct in6pcb *in6p, str memcpy(&pi6.ipi6_addr, &ip6->ip6_dst, sizeof(struct in6_addr)); in6_clearscope(&pi6.ipi6_addr); /* XXX */ - pi6.ipi6_ifindex = m->m_pkthdr.rcvif_index; - *mp = sbcreatecontrol(&pi6, sizeof(pi6), + pi6.ipi6_ifindex = m->m_pkthdr.rcvif ? + m->m_pkthdr.rcvif->if_index : 0; + *mp = sbcreatecontrol((void *) &pi6, + sizeof(struct in6_pktinfo), IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; @@ -1121,7 +1122,7 @@ ip6_savecontrol(struct in6pcb *in6p, str if (in6p->in6p_flags & IN6P_HOPLIMIT) { int hlim = ip6->ip6_hlim & 0xff; - *mp = sbcreatecontrol(&hlim, sizeof(hlim), + *mp = sbcreatecontrol((void *) &hlim, sizeof(int), IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; @@ -1135,7 +1136,7 @@ ip6_savecontrol(struct in6pcb *in6p, str flowinfo >>= 20; tclass = flowinfo & 0xff; - *mp = sbcreatecontrol(&tclass, sizeof(tclass), + *mp = sbcreatecontrol((void *)&tclass, sizeof(tclass), IPV6_TCLASS, IPPROTO_IPV6); if (*mp) @@ -1183,7 +1184,7 @@ ip6_savecontrol(struct in6pcb *in6p, str * be removed before returning in the RFC 2292. * Note: this constraint is removed in RFC3542. */ - *mp = sbcreatecontrol(hbh, hbhlen, + *mp = sbcreatecontrol((void *)hbh, hbhlen, IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS), IPPROTO_IPV6); if (*mp) @@ -1245,7 +1246,7 @@ ip6_savecontrol(struct in6pcb *in6p, str if (!(in6p->in6p_flags & IN6P_DSTOPTS)) break; - *mp = sbcreatecontrol(ip6e, elen, + *mp = sbcreatecontrol((void *)ip6e, elen, IS2292(IPV6_2292DSTOPTS, IPV6_DSTOPTS), IPPROTO_IPV6); if (*mp) @@ -1256,7 +1257,7 @@ ip6_savecontrol(struct in6pcb *in6p, str if (!(in6p->in6p_flags & IN6P_RTHDR)) break; - *mp = sbcreatecontrol(ip6e, elen, + *mp = sbcreatecontrol((void *)ip6e, elen, IS2292(IPV6_2292RTHDR, IPV6_RTHDR), IPPROTO_IPV6); if (*mp) @@ -1306,7 +1307,10 @@ ip6_notify_pmtu(struct in6pcb *in6p, con if (mtu == NULL) return; - KASSERT(so != NULL); +#ifdef DIAGNOSTIC + if (so == NULL) /* I believe this is impossible */ + panic("ip6_notify_pmtu: socket is NULL"); +#endif memset(&mtuctl, 0, sizeof(mtuctl)); /* zero-clear for safety */ mtuctl.ip6m_mtu = *mtu; @@ -1314,7 +1318,7 @@ ip6_notify_pmtu(struct in6pcb *in6p, con if (sa6_recoverscope(&mtuctl.ip6m_addr)) return; - if ((m_mtu = sbcreatecontrol(&mtuctl, sizeof(mtuctl), + if ((m_mtu = sbcreatecontrol((void *)&mtuctl, sizeof(mtuctl), IPV6_PATHMTU, IPPROTO_IPV6)) == NULL) return; @@ -1380,50 +1384,44 @@ ip6_pullexthdr(struct mbuf *m, size_t of } /* - * Get pointer to the previous header followed by the header + * Get offset to the previous header followed by the header * currently processed. - * XXX: This function supposes that - * M includes all headers, - * the next header field and the header length field of each header - * are valid, and - * the sum of each header length equals to OFF. - * Because of these assumptions, this function must be called very - * carefully. Moreover, it will not be used in the near future when - * we develop `neater' mechanism to process extension headers. */ -u_int8_t * +int ip6_get_prevhdr(struct mbuf *m, int off) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - if (off == sizeof(struct ip6_hdr)) - return (&ip6->ip6_nxt); - else { - int len, nxt; - struct ip6_ext *ip6e = NULL; + if (off == sizeof(struct ip6_hdr)) { + return offsetof(struct ip6_hdr, ip6_nxt); + } else if (off < sizeof(struct ip6_hdr)) { + panic("%s: off < sizeof(struct ip6_hdr)", __func__); + } else { + int len, nlen, nxt; + struct ip6_ext ip6e; nxt = ip6->ip6_nxt; len = sizeof(struct ip6_hdr); + nlen = 0; while (len < off) { - ip6e = (struct ip6_ext *)(mtod(m, char *) + len); + m_copydata(m, len, sizeof(ip6e), &ip6e); switch (nxt) { case IPPROTO_FRAGMENT: - len += sizeof(struct ip6_frag); + nlen = sizeof(struct ip6_frag); break; case IPPROTO_AH: - len += (ip6e->ip6e_len + 2) << 2; + nlen = (ip6e.ip6e_len + 2) << 2; break; default: - len += (ip6e->ip6e_len + 1) << 3; + nlen = (ip6e.ip6e_len + 1) << 3; break; } - nxt = ip6e->ip6e_nxt; + len += nlen; + nxt = ip6e.ip6e_nxt; } - if (ip6e) - return (&ip6e->ip6e_nxt); - else - return NULL; + + return (len - nlen); } } @@ -1569,6 +1567,66 @@ ip6_delaux(struct mbuf *m) m_tag_delete(m, mtag); } +#ifdef GATEWAY +/* + * sysctl helper routine for net.inet.ip6.maxflows. Since + * we could reduce this value, call ip6flow_reap(); + */ +static int +sysctl_net_inet6_ip6_maxflows(SYSCTLFN_ARGS) +{ + int error; + + error = sysctl_lookup(SYSCTLFN_CALL(rnode)); + if (error || newp == NULL) + return (error); + + mutex_enter(softnet_lock); + KERNEL_LOCK(1, NULL); + + ip6flow_reap(0); + + KERNEL_UNLOCK_ONE(NULL); + mutex_exit(softnet_lock); + + return (0); +} + +static int +sysctl_net_inet6_ip6_hashsize(SYSCTLFN_ARGS) +{ + int error, tmp; + struct sysctlnode node; + + node = *rnode; + tmp = ip6_hashsize; + node.sysctl_data = &tmp; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return (error); + + if ((tmp & (tmp - 1)) == 0 && tmp != 0) { + /* + * Can only fail due to malloc() + */ + mutex_enter(softnet_lock); + KERNEL_LOCK(1, NULL); + + error = ip6flow_invalidate_all(tmp); + + KERNEL_UNLOCK_ONE(NULL); + mutex_exit(softnet_lock); + } else { + /* + * EINVAL if not a power of 2 + */ + error = EINVAL; + } + + return error; +} +#endif /* GATEWAY */ + /* * System control for IP6 */ @@ -1582,8 +1640,6 @@ const u_char inet6ctlerrmap[PRC_NCMDS] = ENOPROTOOPT }; -extern int sysctl_net_inet6_addrctlpolicy(SYSCTLFN_ARGS); - static int sysctl_net_inet6_ip6_stats(SYSCTLFN_ARGS) { @@ -1749,6 +1805,15 @@ sysctl_net_inet6_ip6_setup(struct sysctl NULL, 0, &ip6_defmcasthlim, 0, CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFMCASTHLIM, CTL_EOL); +#if NGIF > 0 + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "gifhlim", + SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"), + NULL, 0, &ip6_gif_hlim, 0, + CTL_NET, PF_INET6, IPPROTO_IPV6, + IPV6CTL_GIF_HLIM, CTL_EOL); +#endif /* NGIF */ sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT, CTLTYPE_STRING, "kame_version", @@ -1783,6 +1848,15 @@ sysctl_net_inet6_ip6_setup(struct sysctl IPV6CTL_V6ONLY, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "auto_linklocal", + SYSCTL_DESCR("Default value of per-interface flag for " + "adding an IPv6 link-local address to " + "interfaces when attached"), + NULL, 0, &ip6_auto_linklocal, 0, + CTL_NET, PF_INET6, IPPROTO_IPV6, + IPV6CTL_AUTO_LINKLOCAL, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "anonportmin", SYSCTL_DESCR("Lowest ephemeral port number to assign"), sysctl_net_inet_ip_ports, 0, &ip6_anonportmin, 0, @@ -1815,23 +1889,6 @@ sysctl_net_inet6_ip6_setup(struct sysctl #endif /* IPNOPRIVPORTS */ sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "auto_linklocal", - SYSCTL_DESCR("Default value of per-interface flag for " - "adding an IPv6 link-local address to " - "interfaces when attached"), - NULL, 0, &ip6_auto_linklocal, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - IPV6CTL_AUTO_LINKLOCAL, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READONLY, - CTLTYPE_STRUCT, "addctlpolicy", - SYSCTL_DESCR("Return the current address control" - " policy"), - sysctl_net_inet6_addrctlpolicy, 0, NULL, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - IPV6CTL_ADDRCTLPOLICY, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "use_tempaddr", SYSCTL_DESCR("Use temporary address"), NULL, 0, &ip6_use_tempaddr, 0, @@ -1887,6 +1944,22 @@ sysctl_net_inet6_ip6_setup(struct sysctl NULL, 0, &ip6_mcast_pmtu, 0, CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_CREATE, CTL_EOL); +#ifdef GATEWAY + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "maxflows", + SYSCTL_DESCR("Number of flows for fast forwarding (IPv6)"), + sysctl_net_inet6_ip6_maxflows, 0, &ip6_maxflows, 0, + CTL_NET, PF_INET6, IPPROTO_IPV6, + CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "hashsize", + SYSCTL_DESCR("Size of hash table for fast forwarding (IPv6)"), + sysctl_net_inet6_ip6_hashsize, 0, &ip6_hashsize, 0, + CTL_NET, PF_INET6, IPPROTO_IPV6, + CTL_CREATE, CTL_EOL); +#endif /* anonportalgo RFC6056 subtree */ const struct sysctlnode *portalgo_node; sysctl_createv(clog, 0, NULL, &portalgo_node,