diff options
| author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2019-04-22 07:27:24 +0000 |
|---|---|---|
| committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2019-04-22 07:27:24 +0000 |
| commit | 40eb389666a27530ba4b3c961616a822f9907282 (patch) | |
| tree | e5b670ccb20b016ac7f8d2a515cd470b940b3f67 /sys | |
| parent | 83efd2885e904627f979ae37dc61e85680881e40 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/netinet/ip_reass.c | 34 | ||||
| -rw-r--r-- | sys/netinet6/frag6.c | 57 |
2 files changed, 82 insertions, 9 deletions
diff --git a/sys/netinet/ip_reass.c b/sys/netinet/ip_reass.c index bb97b8b07d7d5..65825dedfd71e 100644 --- a/sys/netinet/ip_reass.c +++ b/sys/netinet/ip_reass.c @@ -46,7 +46,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> @@ -606,6 +609,37 @@ 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); + 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) { + if (m->m_pkthdr.rcvif == ifp) { + ipq_drop(&V_ipq[i], fp); + break; + } + } + } + IPQ_UNLOCK(i); + } + CURVNET_RESTORE(); +} +EVENTHANDLER_DEFINE(ifnet_departure_event, ipreass_cleanup, NULL, 0); + #ifdef VIMAGE /* * Destroy IP reassembly structures. diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index 3ba12d3496c86..fb8021d3e6420 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -81,7 +81,7 @@ static void frag6_deq(struct ip6asfrag *, uint32_t bucket __unused); static void frag6_insque_head(struct ip6q *, struct ip6q *, uint32_t bucket); static void frag6_remque(struct ip6q *, uint32_t bucket); -static void frag6_freef(struct ip6q *, uint32_t bucket); +static void frag6_freef(struct ip6q *, uint32_t bucket, bool send_icmp); struct ip6qbucket { struct ip6q ip6q; @@ -594,7 +594,7 @@ insert: if (af6->ip6af_off != next) { if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); - frag6_freef(q6, hash); + frag6_freef(q6, hash, true); } IP6Q_UNLOCK(hash); return IPPROTO_DONE; @@ -604,7 +604,7 @@ insert: if (af6->ip6af_up->ip6af_mff) { if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); - frag6_freef(q6, hash); + frag6_freef(q6, hash, true); } IP6Q_UNLOCK(hash); return IPPROTO_DONE; @@ -731,7 +731,7 @@ insert: * associated datagrams. */ static void -frag6_freef(struct ip6q *q6, uint32_t bucket) +frag6_freef(struct ip6q *q6, uint32_t bucket, bool send_icmp) { struct ip6asfrag *af6, *down6; @@ -748,7 +748,7 @@ frag6_freef(struct ip6q *q6, uint32_t bucket) * Return ICMP time exceeded error for the 1st fragment. * Just free other fragments. */ - if (af6->ip6af_off == 0) { + if (af6->ip6af_off == 0 && send_icmp != false) { struct ip6_hdr *ip6; /* adjust pointer */ @@ -864,7 +864,7 @@ frag6_slowtimo(void) IP6STAT_ADD(ip6s_fragtimeout, q6->ip6q_prev->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(q6->ip6q_prev, i); + frag6_freef(q6->ip6q_prev, i, true); } } /* @@ -883,7 +883,7 @@ frag6_slowtimo(void) IP6STAT_ADD(ip6s_fragoverflow, q6->ip6q_prev->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(head->ip6q_prev, i); + frag6_freef(head->ip6q_prev, i, true); } IP6Q_UNLOCK(i); } @@ -901,7 +901,7 @@ frag6_slowtimo(void) IP6STAT_ADD(ip6s_fragoverflow, q6->ip6q_prev->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(head->ip6q_prev, i); + frag6_freef(head->ip6q_prev, i, true); } IP6Q_UNLOCK(i); i = (i + 1) % IP6REASS_NHASH; @@ -931,7 +931,7 @@ frag6_drain(void) while (head->ip6q_next != head) { IP6STAT_INC(ip6s_fragdropped); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(head->ip6q_next, i); + frag6_freef(head->ip6q_next, i, true); } IP6Q_UNLOCK(i); } @@ -940,6 +940,45 @@ frag6_drain(void) VNET_LIST_RUNLOCK_NOSLEEP(); } +/* + * 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++) { + IP6Q_LOCK(i); + head = IP6Q_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); + + if (m->m_pkthdr.rcvif == ifp) { + IP6STAT_INC(ip6s_fragdropped); + frag6_freef(q6, i, false); + break; + } + } + } + IP6Q_UNLOCK(i); + } + CURVNET_RESTORE(); +} +EVENTHANDLER_DEFINE(ifnet_departure_event, frag6_cleanup, NULL, 0); + int ip6_deletefraghdr(struct mbuf *m, int offset, int wait) { |
