Index: sys/netinet/ip_reass.c =================================================================== --- sys/netinet/ip_reass.c +++ sys/netinet/ip_reass.c @@ -47,7 +47,10 @@ #include #include #include +#include +#include +#include #include #include #include @@ -181,6 +184,7 @@ struct ip *ip; struct mbuf *p, *q, *nq, *t; struct ipq *fp; + struct ifnet *srcifp; struct ipqhead *head; int i, hlen, next, tmpmax; u_int8_t ecn, ecn0; @@ -241,6 +245,11 @@ } /* + * Store receive network interface pointer for later. + */ + srcifp = m->m_pkthdr.rcvif; + + /* * Attempt reassembly; if it succeeds, proceed. * ip_reass() will return a different mbuf. */ @@ -490,8 +499,11 @@ m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); /* some debugging cruft by sklower, below, will go away soon */ - if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */ + if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ m_fixhdr(m); + /* set valid receive interface pointer */ + m->m_pkthdr.rcvif = srcifp; + } IPSTAT_INC(ips_reassembled); IPQ_UNLOCK(hash); @@ -607,7 +619,43 @@ } } +/* + * Drain off all datagram fragments belonging to + * the given network interface. + */ +static void +ipreass_cleanup(void *arg __unused, struct ifnet *ifp) +{ + struct ipq *fp, *temp; + struct mbuf *m; + int i; + + KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); + #ifdef VIMAGE + if (!vnet_is_running(ifp->if_vnet)) { + /* the IPv4 reassembly hash is destroyed */ + return; + } +#endif + CURVNET_SET_QUIET(ifp->if_vnet); + for (i = 0; i < IPREASS_NHASH; i++) { + IPQ_LOCK(i); + /* Scan fragment list. */ + TAILQ_FOREACH_SAFE(fp, &V_ipq[i].head, ipq_list, temp) { + for (m = fp->ipq_frags; m != NULL; m = m->m_nextpkt) { + /* clear no longer valid rcvif pointer */ + if (m->m_pkthdr.rcvif == ifp) + m->m_pkthdr.rcvif = NULL; + } + } + IPQ_UNLOCK(i); + } + CURVNET_RESTORE(); +} +EVENTHANDLER_DEFINE(ifnet_departure_event, ipreass_cleanup, NULL, 0); + +#ifdef VIMAGE /* * Destroy IP reassembly structures. */ Index: sys/netinet6/frag6.c =================================================================== --- sys/netinet6/frag6.c +++ sys/netinet6/frag6.c @@ -232,7 +232,7 @@ * Return ICMP time exceeded error for the 1st fragment. * Just free other fragments. */ - if (af6->ip6af_off == 0) { + if (af6->ip6af_off == 0 && m->m_pkthdr.rcvif != NULL) { struct ip6_hdr *ip6; /* adjust pointer */ @@ -258,6 +258,49 @@ } /* + * Drain off all datagram fragments belonging to + * the given network interface. + */ +static void +frag6_cleanup(void *arg __unused, struct ifnet *ifp) +{ + struct ip6q *q6, *q6n, *head; + struct ip6asfrag *af6; + struct mbuf *m; + int i; + + KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); + +#ifdef VIMAGE + if (!vnet_is_running(ifp->if_vnet)) { + /* the IPv6 reassembly hash is destroyed */ + return; + } +#endif + CURVNET_SET_QUIET(ifp->if_vnet); + for (i = 0; i < IP6REASS_NHASH; i++) { + IP6QB_LOCK(i); + head = IP6QB_HEAD(i); + /* Scan fragment list. */ + for (q6 = head->ip6q_next; q6 != head; q6 = q6n) { + q6n = q6->ip6q_next; + + for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; + af6 = af6->ip6af_down) { + m = IP6_REASS_MBUF(af6); + + /* clear no longer valid rcvif pointer */ + if (m->m_pkthdr.rcvif == ifp) + m->m_pkthdr.rcvif = NULL; + } + } + IP6QB_UNLOCK(i); + } + CURVNET_RESTORE(); +} +EVENTHANDLER_DEFINE(ifnet_departure_event, frag6_cleanup, NULL, 0); + +/* * In RFC2460, fragment and reassembly rule do not agree with each other, * in terms of next header field handling in fragment header. * While the sender will use the same value for all of the fragmented packets, @@ -305,6 +348,7 @@ sizeof(ip6f->ip6f_ident)) / sizeof(uint32_t)]; uint32_t bucket, *hashkeyp; struct ifnet *dstifp; + struct ifnet *srcifp; u_int8_t ecn, ecn0; #ifdef RSS struct m_tag *mtag; @@ -321,6 +365,11 @@ return (IPPROTO_DONE); #endif + /* + * Store receive network interface pointer for later. + */ + srcifp = m->m_pkthdr.rcvif; + dstifp = NULL; /* find the destination interface of the packet. */ ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); @@ -509,6 +558,9 @@ frag6_deq(af6, bucket); free(af6, M_FRAG6); + /* set valid receive interface pointer */ + merr->m_pkthdr.rcvif = srcifp; + /* adjust pointer. */ ip6err = mtod(merr, struct ip6_hdr *); @@ -703,6 +755,8 @@ for (t = m; t; t = t->m_next) plen += t->m_len; m->m_pkthdr.len = plen; + /* set valid receive interface pointer */ + m->m_pkthdr.rcvif = srcifp; } #ifdef RSS