diff options
Diffstat (limited to 'freebsd/sys/netinet6/frag6.c')
-rw-r--r-- | freebsd/sys/netinet6/frag6.c | 109 |
1 files changed, 69 insertions, 40 deletions
diff --git a/freebsd/sys/netinet6/frag6.c b/freebsd/sys/netinet6/frag6.c index 511c8601..4cbd3000 100644 --- a/freebsd/sys/netinet6/frag6.c +++ b/freebsd/sys/netinet6/frag6.c @@ -34,11 +34,14 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <rtems/bsd/local/opt_rss.h> + #include <rtems/bsd/sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/domain.h> +#include <sys/eventhandler.h> #include <sys/protosw.h> #include <sys/socket.h> #include <rtems/bsd/sys/errno.h> @@ -47,6 +50,8 @@ __FBSDID("$FreeBSD$"); #include <sys/syslog.h> #include <net/if.h> +#include <net/if_var.h> +#include <net/netisr.h> #include <net/route.h> #include <net/vnet.h> @@ -60,13 +65,6 @@ __FBSDID("$FreeBSD$"); #include <security/mac/mac_framework.h> -/* - * Define it to get a correct behavior on per-interface statistics. - * You will need to perform an extra routing table lookup, per fragment, - * to do it. This may, or may not be, a performance hit. - */ -#define IN6_IFSTAT_STRICT - static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *); static void frag6_deq(struct ip6asfrag *); static void frag6_insque(struct ip6q *, struct ip6q *); @@ -139,7 +137,7 @@ frag6_init(void) * fragment's Fragment header. * -> should grab it from the first fragment only * - * The following note also contradicts with fragment rule - noone is going to + * The following note also contradicts with fragment rule - no one is going to * send different fragment with different next header field. * * additional note (p22): @@ -161,14 +159,17 @@ frag6_input(struct mbuf **mp, int *offp, int proto) struct ip6_frag *ip6f; struct ip6q *q6; struct ip6asfrag *af6, *ip6af, *af6dwn; -#ifdef IN6_IFSTAT_STRICT struct in6_ifaddr *ia; -#endif int offset = *offp, nxt, i, next; int first_frag = 0; int fragoff, frgpartlen; /* must be larger than u_int16_t */ struct ifnet *dstifp; u_int8_t ecn, ecn0; +#ifdef RSS + struct m_tag *mtag; + struct ip6_direct_ctx *ip6dc; +#endif + #if 0 char ip6buf[INET6_ADDRSTRLEN]; #endif @@ -184,18 +185,12 @@ frag6_input(struct mbuf **mp, int *offp, int proto) #endif dstifp = NULL; -#ifdef IN6_IFSTAT_STRICT /* find the destination interface of the packet. */ - if ((ia = ip6_getdstifaddr(m)) != NULL) { + ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); + if (ia != NULL) { dstifp = ia->ia_ifp; ifa_free(&ia->ia_ifa); } -#else - /* we are violating the spec, this is not the destination interface */ - if ((m->m_flags & M_PKTHDR) != 0) - dstifp = m->m_pkthdr.rcvif; -#endif - /* jumbo payload can't contain a fragment header */ if (ip6->ip6_plen == 0) { icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); @@ -539,8 +534,8 @@ insert: frag6_deq(af6); while (t->m_next) t = t->m_next; - t->m_next = IP6_REASS_MBUF(af6); - m_adj(t->m_next, af6->ip6af_offset); + m_adj(IP6_REASS_MBUF(af6), af6->ip6af_offset); + m_cat(t, IP6_REASS_MBUF(af6)); free(af6, M_FTABLE); af6 = af6dwn; } @@ -557,27 +552,16 @@ insert: *q6->ip6q_nxtp = (u_char)(nxt & 0xff); #endif - /* Delete frag6 header */ - if (m->m_len >= offset + sizeof(struct ip6_frag)) { - /* This is the only possible case with !PULLDOWN_TEST */ - ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag), - offset); - m->m_data += sizeof(struct ip6_frag); - m->m_len -= sizeof(struct ip6_frag); - } else { - /* this comes with no copy if the boundary is on cluster */ - if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) { - frag6_remque(q6); - V_frag6_nfrags -= q6->ip6q_nfrag; + if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0) { + frag6_remque(q6); + V_frag6_nfrags -= q6->ip6q_nfrag; #ifdef MAC - mac_ip6q_destroy(q6); + mac_ip6q_destroy(q6); #endif - free(q6, M_FTABLE); - V_frag6_nfragpackets--; - goto dropfrag; - } - m_adj(t, sizeof(struct ip6_frag)); - m_cat(m, t); + free(q6, M_FTABLE); + V_frag6_nfragpackets--; + + goto dropfrag; } /* @@ -604,9 +588,31 @@ insert: m->m_pkthdr.len = plen; } +#ifdef RSS + mtag = m_tag_alloc(MTAG_ABI_IPV6, IPV6_TAG_DIRECT, sizeof(*ip6dc), + M_NOWAIT); + if (mtag == NULL) + goto dropfrag; + + ip6dc = (struct ip6_direct_ctx *)(mtag + 1); + ip6dc->ip6dc_nxt = nxt; + ip6dc->ip6dc_off = offset; + + m_tag_prepend(m, mtag); +#endif + + IP6Q_UNLOCK(); IP6STAT_INC(ip6s_reassembled); in6_ifstat_inc(dstifp, ifs6_reass_ok); +#ifdef RSS + /* + * Queue/dispatch for reprocessing. + */ + netisr_dispatch(NETISR_IPV6_DIRECT, m); + return IPPROTO_DONE; +#endif + /* * Tell launch routine the next header */ @@ -614,7 +620,6 @@ insert: *mp = m; *offp = offset; - IP6Q_UNLOCK(); return nxt; dropfrag: @@ -791,3 +796,27 @@ frag6_drain(void) IP6Q_UNLOCK(); VNET_LIST_RUNLOCK_NOSLEEP(); } + +int +ip6_deletefraghdr(struct mbuf *m, int offset, int wait) +{ + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct mbuf *t; + + /* Delete frag6 header. */ + if (m->m_len >= offset + sizeof(struct ip6_frag)) { + /* This is the only possible case with !PULLDOWN_TEST. */ + bcopy(ip6, (char *)ip6 + sizeof(struct ip6_frag), + offset); + m->m_data += sizeof(struct ip6_frag); + m->m_len -= sizeof(struct ip6_frag); + } else { + /* This comes with no copy if the boundary is on cluster. */ + if ((t = m_split(m, offset, wait)) == NULL) + return (ENOMEM); + m_adj(t, sizeof(struct ip6_frag)); + m_cat(m, t); + } + + return (0); +} |