xref: /freebsd/sys/netinet/tcp_pcap.c (revision bf6c6162c7631b361f81e89b8539154dd738e828)
186a996e6SHiren Panchasara /*-
286a996e6SHiren Panchasara  * Copyright (c) 2015
386a996e6SHiren Panchasara  *	Jonathan Looney. All rights reserved.
486a996e6SHiren Panchasara  *
586a996e6SHiren Panchasara  * Redistribution and use in source and binary forms, with or without
686a996e6SHiren Panchasara  * modification, are permitted provided that the following conditions
786a996e6SHiren Panchasara  * are met:
886a996e6SHiren Panchasara  * 1. Redistributions of source code must retain the above copyright
986a996e6SHiren Panchasara  *    notice, this list of conditions and the following disclaimer.
1086a996e6SHiren Panchasara  * 2. Redistributions in binary form must reproduce the above copyright
1186a996e6SHiren Panchasara  *    notice, this list of conditions and the following disclaimer in the
1286a996e6SHiren Panchasara  *    documentation and/or other materials provided with the distribution.
1386a996e6SHiren Panchasara  *
1486a996e6SHiren Panchasara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1586a996e6SHiren Panchasara  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1686a996e6SHiren Panchasara  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1786a996e6SHiren Panchasara  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1886a996e6SHiren Panchasara  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1986a996e6SHiren Panchasara  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2086a996e6SHiren Panchasara  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2186a996e6SHiren Panchasara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2286a996e6SHiren Panchasara  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2386a996e6SHiren Panchasara  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2486a996e6SHiren Panchasara  * SUCH DAMAGE.
2586a996e6SHiren Panchasara  *
2686a996e6SHiren Panchasara  * $FreeBSD$
2786a996e6SHiren Panchasara  */
2886a996e6SHiren Panchasara 
2986a996e6SHiren Panchasara #include <sys/queue.h>
3086a996e6SHiren Panchasara #include <sys/param.h>
3186a996e6SHiren Panchasara #include <sys/types.h>
3286a996e6SHiren Panchasara #include <sys/socket.h>
3386a996e6SHiren Panchasara #include <sys/socketvar.h>
3486a996e6SHiren Panchasara #include <sys/sysctl.h>
3586a996e6SHiren Panchasara #include <sys/systm.h>
3686a996e6SHiren Panchasara #include <sys/mbuf.h>
3786a996e6SHiren Panchasara #include <sys/eventhandler.h>
3886a996e6SHiren Panchasara #include <machine/atomic.h>
3986a996e6SHiren Panchasara #include <netinet/tcp_var.h>
4086a996e6SHiren Panchasara #include <netinet/tcp_pcap.h>
4186a996e6SHiren Panchasara 
4286a996e6SHiren Panchasara #define M_LEADINGSPACE_NOWRITE(m)					\
4386a996e6SHiren Panchasara 	((m)->m_data - M_START(m))
4486a996e6SHiren Panchasara 
4524b9bb56SJonathan T. Looney int tcp_pcap_aggressive_free = 1;
4686a996e6SHiren Panchasara static int tcp_pcap_clusters_referenced_cur = 0;
4786a996e6SHiren Panchasara static int tcp_pcap_clusters_referenced_max = 0;
4886a996e6SHiren Panchasara 
4924b9bb56SJonathan T. Looney SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_aggressive_free,
5024b9bb56SJonathan T. Looney 	CTLFLAG_RW, &tcp_pcap_aggressive_free, 0,
5124b9bb56SJonathan T. Looney 	"Free saved packets when the memory system comes under pressure");
5286a996e6SHiren Panchasara SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_clusters_referenced_cur,
5386a996e6SHiren Panchasara 	CTLFLAG_RD, &tcp_pcap_clusters_referenced_cur, 0,
5486a996e6SHiren Panchasara 	"Number of clusters currently referenced on TCP PCAP queues");
5586a996e6SHiren Panchasara SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_clusters_referenced_max,
5686a996e6SHiren Panchasara 	CTLFLAG_RW, &tcp_pcap_clusters_referenced_max, 0,
5786a996e6SHiren Panchasara 	"Maximum number of clusters allowed to be referenced on TCP PCAP "
5886a996e6SHiren Panchasara 	"queues");
5986a996e6SHiren Panchasara 
6086a996e6SHiren Panchasara static int tcp_pcap_alloc_reuse_ext = 0;
6186a996e6SHiren Panchasara static int tcp_pcap_alloc_reuse_mbuf = 0;
6286a996e6SHiren Panchasara static int tcp_pcap_alloc_new_mbuf = 0;
6386a996e6SHiren Panchasara SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_alloc_reuse_ext,
6486a996e6SHiren Panchasara 	CTLFLAG_RD, &tcp_pcap_alloc_reuse_ext, 0,
6586a996e6SHiren Panchasara 	"Number of mbufs with external storage reused for the TCP PCAP "
6686a996e6SHiren Panchasara 	"functionality");
6786a996e6SHiren Panchasara SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_alloc_reuse_mbuf,
6886a996e6SHiren Panchasara 	CTLFLAG_RD, &tcp_pcap_alloc_reuse_mbuf, 0,
6986a996e6SHiren Panchasara 	"Number of mbufs with internal storage reused for the TCP PCAP "
7086a996e6SHiren Panchasara 	"functionality");
7186a996e6SHiren Panchasara SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_alloc_new_mbuf,
7286a996e6SHiren Panchasara 	CTLFLAG_RD, &tcp_pcap_alloc_new_mbuf, 0,
7386a996e6SHiren Panchasara 	"Number of new mbufs allocated for the TCP PCAP functionality");
7486a996e6SHiren Panchasara 
7586a996e6SHiren Panchasara VNET_DEFINE(int, tcp_pcap_packets) = 0;
7686a996e6SHiren Panchasara #define V_tcp_pcap_packets	VNET(tcp_pcap_packets)
77962d02b0SBjoern A. Zeeb SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_pcap_packets,
78*bf6c6162SMichael Tuexen 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_pcap_packets), 0,
79962d02b0SBjoern A. Zeeb 	"Default number of packets saved per direction per TCPCB");
8086a996e6SHiren Panchasara 
8186a996e6SHiren Panchasara /* Initialize the values. */
8286a996e6SHiren Panchasara static void
83f87ec781SBjoern A. Zeeb tcp_pcap_max_set(void)
84f87ec781SBjoern A. Zeeb {
85f87ec781SBjoern A. Zeeb 
8686a996e6SHiren Panchasara 	tcp_pcap_clusters_referenced_max = nmbclusters / 4;
8786a996e6SHiren Panchasara }
8886a996e6SHiren Panchasara 
8986a996e6SHiren Panchasara void
90f87ec781SBjoern A. Zeeb tcp_pcap_init(void)
91f87ec781SBjoern A. Zeeb {
92f87ec781SBjoern A. Zeeb 
9386a996e6SHiren Panchasara 	tcp_pcap_max_set();
9486a996e6SHiren Panchasara 	EVENTHANDLER_REGISTER(nmbclusters_change, tcp_pcap_max_set,
9586a996e6SHiren Panchasara 		NULL, EVENTHANDLER_PRI_ANY);
9686a996e6SHiren Panchasara }
9786a996e6SHiren Panchasara 
9886a996e6SHiren Panchasara /*
9986a996e6SHiren Panchasara  * If we are below the maximum allowed cluster references,
10086a996e6SHiren Panchasara  * increment the reference count and return TRUE. Otherwise,
10186a996e6SHiren Panchasara  * leave the reference count alone and return FALSE.
10286a996e6SHiren Panchasara  */
10386a996e6SHiren Panchasara static __inline bool
10486a996e6SHiren Panchasara tcp_pcap_take_cluster_reference(void)
10586a996e6SHiren Panchasara {
10686a996e6SHiren Panchasara 	if (atomic_fetchadd_int(&tcp_pcap_clusters_referenced_cur, 1) >=
10786a996e6SHiren Panchasara 		tcp_pcap_clusters_referenced_max) {
10886a996e6SHiren Panchasara 		atomic_add_int(&tcp_pcap_clusters_referenced_cur, -1);
10986a996e6SHiren Panchasara 		return FALSE;
11086a996e6SHiren Panchasara 	}
11186a996e6SHiren Panchasara 	return TRUE;
11286a996e6SHiren Panchasara }
11386a996e6SHiren Panchasara 
11486a996e6SHiren Panchasara /*
11586a996e6SHiren Panchasara  * For all the external entries in m, apply the given adjustment.
11686a996e6SHiren Panchasara  * This can be used to adjust the counter when an mbuf chain is
11786a996e6SHiren Panchasara  * copied or freed.
11886a996e6SHiren Panchasara  */
11986a996e6SHiren Panchasara static __inline void
12086a996e6SHiren Panchasara tcp_pcap_adj_cluster_reference(struct mbuf *m, int adj)
12186a996e6SHiren Panchasara {
12286a996e6SHiren Panchasara 	while (m) {
12386a996e6SHiren Panchasara 		if (m->m_flags & M_EXT)
12486a996e6SHiren Panchasara 			atomic_add_int(&tcp_pcap_clusters_referenced_cur, adj);
12586a996e6SHiren Panchasara 
12686a996e6SHiren Panchasara 		m = m->m_next;
12786a996e6SHiren Panchasara 	}
12886a996e6SHiren Panchasara }
12986a996e6SHiren Panchasara 
13086a996e6SHiren Panchasara /*
13186a996e6SHiren Panchasara  * Free all mbufs in a chain, decrementing the reference count as
13286a996e6SHiren Panchasara  * necessary.
13386a996e6SHiren Panchasara  *
13486a996e6SHiren Panchasara  * Functions in this file should use this instead of m_freem() when
13586a996e6SHiren Panchasara  * they are freeing mbuf chains that may contain clusters that were
13686a996e6SHiren Panchasara  * already included in tcp_pcap_clusters_referenced_cur.
13786a996e6SHiren Panchasara  */
13886a996e6SHiren Panchasara static void
13986a996e6SHiren Panchasara tcp_pcap_m_freem(struct mbuf *mb)
14086a996e6SHiren Panchasara {
14186a996e6SHiren Panchasara 	while (mb != NULL) {
14286a996e6SHiren Panchasara 		if (mb->m_flags & M_EXT)
14386a996e6SHiren Panchasara 			atomic_subtract_int(&tcp_pcap_clusters_referenced_cur,
14486a996e6SHiren Panchasara 			    1);
14586a996e6SHiren Panchasara 		mb = m_free(mb);
14686a996e6SHiren Panchasara 	}
14786a996e6SHiren Panchasara }
14886a996e6SHiren Panchasara 
14986a996e6SHiren Panchasara /*
15086a996e6SHiren Panchasara  * Copy data from m to n, where n cannot fit all the data we might
15186a996e6SHiren Panchasara  * want from m.
15286a996e6SHiren Panchasara  *
15386a996e6SHiren Panchasara  * Prioritize data like this:
15486a996e6SHiren Panchasara  * 1. TCP header
15586a996e6SHiren Panchasara  * 2. IP header
15686a996e6SHiren Panchasara  * 3. Data
15786a996e6SHiren Panchasara  */
15886a996e6SHiren Panchasara static void
15986a996e6SHiren Panchasara tcp_pcap_copy_bestfit(struct tcphdr *th, struct mbuf *m, struct mbuf *n)
16086a996e6SHiren Panchasara {
16186a996e6SHiren Panchasara 	struct mbuf *m_cur = m;
16286a996e6SHiren Panchasara 	int bytes_to_copy=0, trailing_data, skip=0, tcp_off;
16386a996e6SHiren Panchasara 
16486a996e6SHiren Panchasara 	/* Below, we assume these will be non-NULL. */
16586a996e6SHiren Panchasara 	KASSERT(th, ("%s: called with th == NULL", __func__));
16686a996e6SHiren Panchasara 	KASSERT(m, ("%s: called with m == NULL", __func__));
16786a996e6SHiren Panchasara 	KASSERT(n, ("%s: called with n == NULL", __func__));
16886a996e6SHiren Panchasara 
16986a996e6SHiren Panchasara 	/* We assume this initialization occurred elsewhere. */
17086a996e6SHiren Panchasara 	KASSERT(n->m_len == 0, ("%s: called with n->m_len=%d (expected 0)",
17186a996e6SHiren Panchasara 		__func__, n->m_len));
17286a996e6SHiren Panchasara 	KASSERT(n->m_data == M_START(n),
17386a996e6SHiren Panchasara 		("%s: called with n->m_data != M_START(n)", __func__));
17486a996e6SHiren Panchasara 
17586a996e6SHiren Panchasara 	/*
17686a996e6SHiren Panchasara 	 * Calculate the size of the TCP header. We use this often
17786a996e6SHiren Panchasara 	 * enough that it is worth just calculating at the start.
17886a996e6SHiren Panchasara 	 */
17986a996e6SHiren Panchasara 	tcp_off = th->th_off << 2;
18086a996e6SHiren Panchasara 
18186a996e6SHiren Panchasara 	/* Trim off leading empty mbufs. */
18286a996e6SHiren Panchasara 	while (m && m->m_len == 0)
18386a996e6SHiren Panchasara 		m = m->m_next;
18486a996e6SHiren Panchasara 
18586a996e6SHiren Panchasara 	if (m) {
18686a996e6SHiren Panchasara 		m_cur = m;
18786a996e6SHiren Panchasara 	}
18886a996e6SHiren Panchasara 	else {
18986a996e6SHiren Panchasara 		/*
19086a996e6SHiren Panchasara 		 * No data? Highly unusual. We would expect to at
19186a996e6SHiren Panchasara 		 * least see a TCP header in the mbuf.
19286a996e6SHiren Panchasara 		 * As we have a pointer to the TCP header, I guess
19386a996e6SHiren Panchasara 		 * we should just copy that. (???)
19486a996e6SHiren Panchasara 		 */
19586a996e6SHiren Panchasara fallback:
19686a996e6SHiren Panchasara 		bytes_to_copy = tcp_off;
19786a996e6SHiren Panchasara 		if (bytes_to_copy > M_SIZE(n))
19886a996e6SHiren Panchasara 			bytes_to_copy = M_SIZE(n);
19986a996e6SHiren Panchasara 		bcopy(th, n->m_data, bytes_to_copy);
20086a996e6SHiren Panchasara 		n->m_len = bytes_to_copy;
20186a996e6SHiren Panchasara 		return;
20286a996e6SHiren Panchasara 	}
20386a996e6SHiren Panchasara 
20486a996e6SHiren Panchasara 	/*
20586a996e6SHiren Panchasara 	 * Find TCP header. Record the total number of bytes up to,
20686a996e6SHiren Panchasara 	 * and including, the TCP header.
20786a996e6SHiren Panchasara 	 */
20886a996e6SHiren Panchasara 	while (m_cur) {
20986a996e6SHiren Panchasara 		if ((caddr_t) th >= (caddr_t) m_cur->m_data &&
21086a996e6SHiren Panchasara 			(caddr_t) th < (caddr_t) (m_cur->m_data + m_cur->m_len))
21186a996e6SHiren Panchasara 			break;
21286a996e6SHiren Panchasara 		bytes_to_copy += m_cur->m_len;
21386a996e6SHiren Panchasara 		m_cur = m_cur->m_next;
21486a996e6SHiren Panchasara 	}
21586a996e6SHiren Panchasara 	if (m_cur)
21686a996e6SHiren Panchasara 		bytes_to_copy += (caddr_t) th - (caddr_t) m_cur->m_data;
21786a996e6SHiren Panchasara 	else
21886a996e6SHiren Panchasara 		goto fallback;
21986a996e6SHiren Panchasara 	bytes_to_copy += tcp_off;
22086a996e6SHiren Panchasara 
22186a996e6SHiren Panchasara 	/*
22286a996e6SHiren Panchasara 	 * If we already want to copy more bytes than we can hold
22386a996e6SHiren Panchasara 	 * in the destination mbuf, skip leading bytes and copy
22486a996e6SHiren Panchasara 	 * what we can.
22586a996e6SHiren Panchasara 	 *
22686a996e6SHiren Panchasara 	 * Otherwise, consider trailing data.
22786a996e6SHiren Panchasara 	 */
22886a996e6SHiren Panchasara 	if (bytes_to_copy > M_SIZE(n)) {
22986a996e6SHiren Panchasara 		skip  = bytes_to_copy - M_SIZE(n);
23086a996e6SHiren Panchasara 		bytes_to_copy = M_SIZE(n);
23186a996e6SHiren Panchasara 	}
23286a996e6SHiren Panchasara 	else {
23386a996e6SHiren Panchasara 		/*
23486a996e6SHiren Panchasara 		 * Determine how much trailing data is in the chain.
23586a996e6SHiren Panchasara 		 * We start with the length of this mbuf (the one
23686a996e6SHiren Panchasara 		 * containing th) and subtract the size of the TCP
23786a996e6SHiren Panchasara 		 * header (tcp_off) and the size of the data prior
23886a996e6SHiren Panchasara 		 * to th (th - m_cur->m_data).
23986a996e6SHiren Panchasara 		 *
24086a996e6SHiren Panchasara 		 * This *should not* be negative, as the TCP code
24186a996e6SHiren Panchasara 		 * should put the whole TCP header in a single
24286a996e6SHiren Panchasara 		 * mbuf. But, it isn't a problem if it is. We will
24386a996e6SHiren Panchasara 		 * simple work off our negative balance as we look
24486a996e6SHiren Panchasara 		 * at subsequent mbufs.
24586a996e6SHiren Panchasara 		 */
24686a996e6SHiren Panchasara 		trailing_data = m_cur->m_len - tcp_off;
24786a996e6SHiren Panchasara 		trailing_data -= (caddr_t) th - (caddr_t) m_cur->m_data;
24886a996e6SHiren Panchasara 		m_cur = m_cur->m_next;
24986a996e6SHiren Panchasara 		while (m_cur) {
25086a996e6SHiren Panchasara 			trailing_data += m_cur->m_len;
25186a996e6SHiren Panchasara 			m_cur = m_cur->m_next;
25286a996e6SHiren Panchasara 		}
25386a996e6SHiren Panchasara 		if ((bytes_to_copy + trailing_data) > M_SIZE(n))
25486a996e6SHiren Panchasara 			bytes_to_copy = M_SIZE(n);
25586a996e6SHiren Panchasara 		else
25686a996e6SHiren Panchasara 			bytes_to_copy += trailing_data;
25786a996e6SHiren Panchasara 	}
25886a996e6SHiren Panchasara 
25986a996e6SHiren Panchasara 	m_copydata(m, skip, bytes_to_copy, n->m_data);
26086a996e6SHiren Panchasara 	n->m_len = bytes_to_copy;
26186a996e6SHiren Panchasara }
26286a996e6SHiren Panchasara 
26386a996e6SHiren Panchasara void
26486a996e6SHiren Panchasara tcp_pcap_add(struct tcphdr *th, struct mbuf *m, struct mbufq *queue)
26586a996e6SHiren Panchasara {
26686a996e6SHiren Panchasara 	struct mbuf *n = NULL, *mhead;
26786a996e6SHiren Panchasara 
26886a996e6SHiren Panchasara 	KASSERT(th, ("%s: called with th == NULL", __func__));
26986a996e6SHiren Panchasara 	KASSERT(m, ("%s: called with m == NULL", __func__));
27086a996e6SHiren Panchasara 	KASSERT(queue, ("%s: called with queue == NULL", __func__));
27186a996e6SHiren Panchasara 
27286a996e6SHiren Panchasara 	/* We only care about data packets. */
27386a996e6SHiren Panchasara 	while (m && m->m_type != MT_DATA)
27486a996e6SHiren Panchasara 		m = m->m_next;
27586a996e6SHiren Panchasara 
27686a996e6SHiren Panchasara 	/* We only need to do something if we still have an mbuf. */
27786a996e6SHiren Panchasara 	if (!m)
27886a996e6SHiren Panchasara 		return;
27986a996e6SHiren Panchasara 
28086a996e6SHiren Panchasara 	/* If we are not saving mbufs, return now. */
28186a996e6SHiren Panchasara 	if (queue->mq_maxlen == 0)
28286a996e6SHiren Panchasara 		return;
28386a996e6SHiren Panchasara 
28486a996e6SHiren Panchasara 	/*
28586a996e6SHiren Panchasara 	 * Check to see if we will need to recycle mbufs.
28686a996e6SHiren Panchasara 	 *
28786a996e6SHiren Panchasara 	 * If we need to get rid of mbufs to stay below
28886a996e6SHiren Panchasara 	 * our packet count, try to reuse the mbuf. Once
28986a996e6SHiren Panchasara 	 * we already have a new mbuf (n), then we can
29086a996e6SHiren Panchasara 	 * simply free subsequent mbufs.
29186a996e6SHiren Panchasara 	 *
29286a996e6SHiren Panchasara 	 * Note that most of the logic in here is to deal
29386a996e6SHiren Panchasara 	 * with the reuse. If we are fine with constant
29486a996e6SHiren Panchasara 	 * mbuf allocs/deallocs, we could ditch this logic.
29586a996e6SHiren Panchasara 	 * But, it only seems to make sense to reuse
29686a996e6SHiren Panchasara 	 * mbufs we already have.
29786a996e6SHiren Panchasara 	 */
29886a996e6SHiren Panchasara 	while (mbufq_full(queue)) {
29986a996e6SHiren Panchasara 		mhead = mbufq_dequeue(queue);
30086a996e6SHiren Panchasara 
30186a996e6SHiren Panchasara 		if (n) {
30286a996e6SHiren Panchasara 			tcp_pcap_m_freem(mhead);
30386a996e6SHiren Panchasara 		}
30486a996e6SHiren Panchasara 		else {
30586a996e6SHiren Panchasara 			/*
30686a996e6SHiren Panchasara 			 * If this held an external cluster, try to
30786a996e6SHiren Panchasara 			 * detach the cluster. But, if we held the
30886a996e6SHiren Panchasara 			 * last reference, go through the normal
30986a996e6SHiren Panchasara 			 * free-ing process.
31086a996e6SHiren Panchasara 			 */
31161664ee7SGleb Smirnoff 			if (mhead->m_flags & M_EXTPG) {
31261664ee7SGleb Smirnoff 				/* Don't mess around with these. */
31361664ee7SGleb Smirnoff 				tcp_pcap_m_freem(mhead);
31461664ee7SGleb Smirnoff 				continue;
31561664ee7SGleb Smirnoff 			} else if (mhead->m_flags & M_EXT) {
31686a996e6SHiren Panchasara 				switch (mhead->m_ext.ext_type) {
31786a996e6SHiren Panchasara 				case EXT_SFBUF:
31886a996e6SHiren Panchasara 					/* Don't mess around with these. */
31986a996e6SHiren Panchasara 					tcp_pcap_m_freem(mhead);
32086a996e6SHiren Panchasara 					continue;
32186a996e6SHiren Panchasara 				default:
32286a996e6SHiren Panchasara 					if (atomic_fetchadd_int(
32386a996e6SHiren Panchasara 						mhead->m_ext.ext_cnt, -1) == 1)
32486a996e6SHiren Panchasara 					{
32586a996e6SHiren Panchasara 						/*
32686a996e6SHiren Panchasara 						 * We held the last reference
32786a996e6SHiren Panchasara 						 * on this cluster. Restore
32886a996e6SHiren Panchasara 						 * the reference count and put
32986a996e6SHiren Panchasara 						 * it back in the pool.
33086a996e6SHiren Panchasara 				 		 */
33186a996e6SHiren Panchasara 						*(mhead->m_ext.ext_cnt) = 1;
33286a996e6SHiren Panchasara 						tcp_pcap_m_freem(mhead);
33386a996e6SHiren Panchasara 						continue;
33486a996e6SHiren Panchasara 					}
33586a996e6SHiren Panchasara 					/*
33686a996e6SHiren Panchasara 					 * We were able to cleanly free the
33786a996e6SHiren Panchasara 					 * reference.
33886a996e6SHiren Panchasara 				 	 */
33986a996e6SHiren Panchasara 					atomic_subtract_int(
34086a996e6SHiren Panchasara 					    &tcp_pcap_clusters_referenced_cur,
34186a996e6SHiren Panchasara 					    1);
34286a996e6SHiren Panchasara 					tcp_pcap_alloc_reuse_ext++;
34386a996e6SHiren Panchasara 					break;
34486a996e6SHiren Panchasara 				}
34561664ee7SGleb Smirnoff 			} else {
34686a996e6SHiren Panchasara 				tcp_pcap_alloc_reuse_mbuf++;
34786a996e6SHiren Panchasara 			}
34886a996e6SHiren Panchasara 
34986a996e6SHiren Panchasara 			n = mhead;
35086a996e6SHiren Panchasara 			tcp_pcap_m_freem(n->m_next);
351b4b12e52SGleb Smirnoff 			m_init(n, M_NOWAIT, MT_DATA, 0);
35286a996e6SHiren Panchasara 		}
35386a996e6SHiren Panchasara 	}
35486a996e6SHiren Panchasara 
35586a996e6SHiren Panchasara 	/* Check to see if we need to get a new mbuf. */
35686a996e6SHiren Panchasara 	if (!n) {
35786a996e6SHiren Panchasara 		if (!(n = m_get(M_NOWAIT, MT_DATA)))
35886a996e6SHiren Panchasara 			return;
35986a996e6SHiren Panchasara 		tcp_pcap_alloc_new_mbuf++;
36086a996e6SHiren Panchasara 	}
36186a996e6SHiren Panchasara 
36286a996e6SHiren Panchasara 	/*
36386a996e6SHiren Panchasara 	 * What are we dealing with? If a cluster, attach it. Otherwise,
36486a996e6SHiren Panchasara 	 * try to copy the data from the beginning of the mbuf to the
36586a996e6SHiren Panchasara 	 * end of data. (There may be data between the start of the data
36686a996e6SHiren Panchasara 	 * area and the current data pointer. We want to get this, because
36786a996e6SHiren Panchasara 	 * it may contain header information that is useful.)
36886a996e6SHiren Panchasara 	 * In cases where that isn't possible, settle for what we can
36986a996e6SHiren Panchasara 	 * get.
37086a996e6SHiren Panchasara 	 */
37161664ee7SGleb Smirnoff 	if ((m->m_flags & (M_EXT|M_EXTPG)) &&
37261664ee7SGleb Smirnoff 	    tcp_pcap_take_cluster_reference()) {
37386a996e6SHiren Panchasara 		n->m_data = m->m_data;
37486a996e6SHiren Panchasara 		n->m_len = m->m_len;
37586a996e6SHiren Panchasara 		mb_dupcl(n, m);
37686a996e6SHiren Panchasara 	}
37786a996e6SHiren Panchasara 	else if (((m->m_data + m->m_len) - M_START(m)) <= M_SIZE(n)) {
37886a996e6SHiren Panchasara 		/*
37986a996e6SHiren Panchasara 		 * At this point, n is guaranteed to be a normal mbuf
38086a996e6SHiren Panchasara 		 * with no cluster and no packet header. Because the
38186a996e6SHiren Panchasara 		 * logic in this code block requires this, the assert
38286a996e6SHiren Panchasara 		 * is here to catch any instances where someone
38386a996e6SHiren Panchasara 		 * changes the logic to invalidate that assumption.
38486a996e6SHiren Panchasara 		 */
38586a996e6SHiren Panchasara 		KASSERT((n->m_flags & (M_EXT | M_PKTHDR)) == 0,
38686a996e6SHiren Panchasara 			("%s: Unexpected flags (%#x) for mbuf",
38786a996e6SHiren Panchasara 			__func__, n->m_flags));
38886a996e6SHiren Panchasara 		n->m_data = n->m_dat + M_LEADINGSPACE_NOWRITE(m);
38986a996e6SHiren Panchasara 		n->m_len = m->m_len;
3906edfd179SGleb Smirnoff 		if (m->m_flags & M_EXTPG)
39182334850SJohn Baldwin 			m_copydata(m, 0, m->m_len, n->m_data);
39282334850SJohn Baldwin 		else
39386a996e6SHiren Panchasara 			bcopy(M_START(m), n->m_dat,
39486a996e6SHiren Panchasara 			    m->m_len + M_LEADINGSPACE_NOWRITE(m));
39586a996e6SHiren Panchasara 	}
39686a996e6SHiren Panchasara 	else {
39786a996e6SHiren Panchasara 		/*
39886a996e6SHiren Panchasara 		 * This is the case where we need to "settle for what
39986a996e6SHiren Panchasara 		 * we can get". The most probable way to this code
40086a996e6SHiren Panchasara 		 * path is that we've already taken references to the
40186a996e6SHiren Panchasara 		 * maximum number of mbuf clusters we can, and the data
40286a996e6SHiren Panchasara 		 * is too long to fit in an mbuf's internal storage.
40386a996e6SHiren Panchasara 		 * Try for a "best fit".
40486a996e6SHiren Panchasara 		 */
40586a996e6SHiren Panchasara 		tcp_pcap_copy_bestfit(th, m, n);
40686a996e6SHiren Panchasara 
40786a996e6SHiren Panchasara 		/* Don't try to get additional data. */
40886a996e6SHiren Panchasara 		goto add_to_queue;
40986a996e6SHiren Panchasara 	}
41086a996e6SHiren Panchasara 
41186a996e6SHiren Panchasara 	if (m->m_next) {
41286a996e6SHiren Panchasara 		n->m_next = m_copym(m->m_next, 0, M_COPYALL, M_NOWAIT);
41386a996e6SHiren Panchasara 		tcp_pcap_adj_cluster_reference(n->m_next, 1);
41486a996e6SHiren Panchasara 	}
41586a996e6SHiren Panchasara 
41686a996e6SHiren Panchasara add_to_queue:
41786a996e6SHiren Panchasara 	/* Add the new mbuf to the list. */
41886a996e6SHiren Panchasara 	if (mbufq_enqueue(queue, n)) {
41986a996e6SHiren Panchasara 		/* This shouldn't happen. If INVARIANTS is defined, panic. */
42086a996e6SHiren Panchasara 		KASSERT(0, ("%s: mbufq was unexpectedly full!", __func__));
42186a996e6SHiren Panchasara 		tcp_pcap_m_freem(n);
42286a996e6SHiren Panchasara 	}
42386a996e6SHiren Panchasara }
42486a996e6SHiren Panchasara 
42586a996e6SHiren Panchasara void
42686a996e6SHiren Panchasara tcp_pcap_drain(struct mbufq *queue)
42786a996e6SHiren Panchasara {
42886a996e6SHiren Panchasara 	struct mbuf *m;
42986a996e6SHiren Panchasara 	while ((m = mbufq_dequeue(queue)))
43086a996e6SHiren Panchasara 		tcp_pcap_m_freem(m);
43186a996e6SHiren Panchasara }
43286a996e6SHiren Panchasara 
43386a996e6SHiren Panchasara void
43486a996e6SHiren Panchasara tcp_pcap_tcpcb_init(struct tcpcb *tp)
43586a996e6SHiren Panchasara {
43686a996e6SHiren Panchasara 	mbufq_init(&(tp->t_inpkts), V_tcp_pcap_packets);
43786a996e6SHiren Panchasara 	mbufq_init(&(tp->t_outpkts), V_tcp_pcap_packets);
43886a996e6SHiren Panchasara }
43986a996e6SHiren Panchasara 
44086a996e6SHiren Panchasara void
44186a996e6SHiren Panchasara tcp_pcap_set_sock_max(struct mbufq *queue, int newval)
44286a996e6SHiren Panchasara {
44386a996e6SHiren Panchasara 	queue->mq_maxlen = newval;
44486a996e6SHiren Panchasara 	while (queue->mq_len > queue->mq_maxlen)
44586a996e6SHiren Panchasara 		tcp_pcap_m_freem(mbufq_dequeue(queue));
44686a996e6SHiren Panchasara }
44786a996e6SHiren Panchasara 
44886a996e6SHiren Panchasara int
44986a996e6SHiren Panchasara tcp_pcap_get_sock_max(struct mbufq *queue)
45086a996e6SHiren Panchasara {
45186a996e6SHiren Panchasara 	return queue->mq_maxlen;
45286a996e6SHiren Panchasara }
453