Index: sys/netinet6/frag6.c =================================================================== --- sys/netinet6/frag6.c +++ sys/netinet6/frag6.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -204,21 +205,42 @@ IP6STAT_INC(ip6s_fragments); in6_ifstat_inc(dstifp, ifs6_reass_reqd); - /* offset now points to data portion */ - offset += sizeof(struct ip6_frag); - /* * RFC 6946: Handle "atomic" fragments (offset and m bit set to 0) * upfront, unrelated to any reassembly. Just skip the fragment header. */ if ((ip6f->ip6f_offlg & ~IP6F_RESERVED_MASK) == 0) { + nxt = ip6f->ip6f_nxt; + + if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0) { + IP6STAT_INC(ip6s_fragdropped); + in6_ifstat_inc(dstifp, ifs6_reass_fail); + m_freem(m); + return IPPROTO_DONE; + } + + m->m_pkthdr.len -= sizeof(struct ip6_frag); + + /* + * Store NXT to the original. + */ + { + char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */ + *prvnxtp = nxt; + } + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - + sizeof(struct ip6_frag)); + /* XXX-BZ we want dedicated counters for this. */ IP6STAT_INC(ip6s_reassembled); in6_ifstat_inc(dstifp, ifs6_reass_ok); - *offp = offset; - return (ip6f->ip6f_nxt); + goto dispatch; } + /* offset now points to data portion */ + offset += sizeof(struct ip6_frag); + IP6Q_LOCK(); /* @@ -577,18 +599,20 @@ m->m_pkthdr.len = plen; } + IP6Q_UNLOCK(); IP6STAT_INC(ip6s_reassembled); in6_ifstat_inc(dstifp, ifs6_reass_ok); + dispatch: + m->m_pkthdr.PH_loc.thirtytwo[0] = nxt; + m->m_pkthdr.PH_loc.thirtytwo[1] = offset; + /* - * Tell launch routine the next header + * Queue/dispatch for reprocessing. */ + netisr_dispatch(NETISR_IPV6_DIRECT, m); - *mp = m; - *offp = offset; - - IP6Q_UNLOCK(); - return nxt; + return IPPROTO_DONE; dropfrag: IP6Q_UNLOCK(); Index: sys/netinet6/ip6_input.c =================================================================== --- sys/netinet6/ip6_input.c +++ sys/netinet6/ip6_input.c @@ -144,6 +144,24 @@ #endif }; +#ifdef RSS +/* + * Directly dispatched frames are currently assumed + * to have a flowid already calculated. + * + * It should likely have something that assert it + * actually has valid flow details. + */ +static struct netisr_handler ip6_direct_nh = { + .nh_name = "ip6_direct", + .nh_handler = ip6_direct_input, + .nh_proto = NETISR_IPV6_DIRECT, + .nh_m2cpuid = rss_soft_m2cpuid_v6, + .nh_policy = NETISR_POLICY_CPU, + .nh_dispatch = NETISR_DISPATCH_HYBRID, +}; +#endif + VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch); #define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) @@ -222,6 +240,9 @@ } netisr_register(&ip6_nh); +#ifdef RSS + netisr_register(&ip6_direct_nh); +#endif } /* @@ -403,6 +424,61 @@ return (1); } +#ifdef RSS +/* + * IPv6 direct input routine. + * + * This is called when reinjecting completed fragments where + * all of the previous checking and book-keeping has been done. + */ +void +ip6_direct_input(struct mbuf *m) +{ + int nest; + int off, nxt; + + nxt = m->m_pkthdr.PH_loc.thirtytwo[0]; + off = m->m_pkthdr.PH_loc.thirtytwo[1]; + + nest = 0; + + while (nxt != IPPROTO_DONE) { + if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { + IP6STAT_INC(ip6s_toomanyhdr); + goto bad; + } + + /* + * protection against faulty packet - there should be + * more sanity checks in header chain processing. + */ + if (m->m_pkthdr.len < off) { + IP6STAT_INC(ip6s_tooshort); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); + goto bad; + } + +#ifdef IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if (ip6_ipsec_input(m, nxt)) + goto bad; +#endif /* IPSEC */ + + if (nxt == IPPROTO_FRAGMENT) + goto bad; + + nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); + } + return; +bad: + m_freem(m); +} +#endif + void ip6_input(struct mbuf *m) { @@ -713,6 +789,13 @@ nxt = ip6->ip6_nxt; /* + * Use mbuf flags to propagate Router Alert option to + * ICMPv6 layer, as hop-by-hop options have been stripped. + */ + if (rtalert != ~0) + m->m_flags |= M_RTALERT_MLD; + + /* * Check that the amount of data in the buffers * is as at least much as the IPv6 header would have us expect. * Trim mbufs if longer than we expect. @@ -809,13 +892,6 @@ goto bad; #endif /* IPSEC */ - /* - * Use mbuf flags to propagate Router Alert option to - * ICMPv6 layer, as hop-by-hop options have been stripped. - */ - if (nxt == IPPROTO_ICMPV6 && rtalert != ~0) - m->m_flags |= M_RTALERT_MLD; - nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; Index: sys/netinet6/ip6_var.h =================================================================== --- sys/netinet6/ip6_var.h +++ sys/netinet6/ip6_var.h @@ -353,6 +353,7 @@ int ip6proto_unregister(short); void ip6_input(struct mbuf *); +void ip6_direct_input(struct mbuf *); void ip6_freepcbopts(struct ip6_pktopts *); int ip6_unknown_opt(u_int8_t *, struct mbuf *, int);