summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/ip_reass.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/ip_reass.c')
-rw-r--r--freebsd/sys/netinet/ip_reass.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/freebsd/sys/netinet/ip_reass.c b/freebsd/sys/netinet/ip_reass.c
index 70a6edae..036d19fe 100644
--- a/freebsd/sys/netinet/ip_reass.c
+++ b/freebsd/sys/netinet/ip_reass.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/eventhandler.h>
+#include <sys/kernel.h>
#include <sys/hash.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
@@ -48,7 +49,10 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_var.h>
#include <net/rss_config.h>
#include <net/netisr.h>
#include <net/vnet.h>
@@ -182,6 +186,7 @@ ip_reass(struct mbuf *m)
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;
@@ -242,6 +247,11 @@ ip_reass(struct mbuf *m)
}
/*
+ * 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.
*/
@@ -491,8 +501,11 @@ ip_reass(struct mbuf *m)
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);
@@ -608,6 +621,46 @@ ipreass_drain(void)
}
}
+/*
+ * 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__));
+
+ CURVNET_SET_QUIET(ifp->if_vnet);
+
+ /*
+ * Skip processing if IPv4 reassembly is not initialised or
+ * torn down by ipreass_destroy().
+ */
+ if (V_ipq_zone == NULL) {
+ CURVNET_RESTORE();
+ return;
+ }
+
+ 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.
@@ -618,6 +671,7 @@ ipreass_destroy(void)
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);
}