Index: head/sys/netinet/ip_reass.c =================================================================== --- head/sys/netinet/ip_reass.c +++ head/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,6 +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__)); + + /* + * Skip processing if IPv4 reassembly is not initialised or + * torn down by ipreass_destroy(). + */ + if (V_ipq_zone == NULL) + return; + + 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. @@ -617,6 +666,7 @@ ipreass_drain(); uma_zdestroy(V_ipq_zone); + V_ipq_zone = NULL; for (int i = 0; i < IPREASS_NHASH; i++) mtx_destroy(&V_ipq[i].lock); } Index: head/sys/netinet6/frag6.c =================================================================== --- head/sys/netinet6/frag6.c +++ head/sys/netinet6/frag6.c @@ -246,7 +246,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) { /* Adjust pointer. */ ip6 = mtod(m, struct ip6_hdr *); @@ -272,6 +272,43 @@ } /* + * 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__)); + + 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); + +/* * Like in RFC2460, in RFC8200, fragment and reassembly rules 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, @@ -307,6 +344,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto) { struct ifnet *dstifp; + struct ifnet *srcifp; struct in6_ifaddr *ia6; struct ip6_hdr *ip6; struct ip6_frag *ip6f; @@ -338,6 +376,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. */ ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); @@ -534,6 +577,9 @@ frag6_deq(af6, bucket); free(af6, M_FRAG6); + /* Set a valid receive interface pointer. */ + merr->m_pkthdr.rcvif = srcifp; + /* Adjust pointer. */ ip6err = mtod(merr, struct ip6_hdr *); @@ -720,6 +766,8 @@ for (t = m; t; t = t->m_next) plen += t->m_len; m->m_pkthdr.len = plen; + /* Set a valid receive interface pointer. */ + m->m_pkthdr.rcvif = srcifp; } #ifdef RSS