<commit_before>/*	$FreeBSD$	*/

/*
 * IPsec-specific mbuf routines.
 */

#include "opt_param.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>

#include <net/route.h>
#include <netinet/in.h>

#include <netipsec/ipsec.h>

extern	struct mbuf *m_getptr(struct mbuf *, int, int *);

/*
 * Create a writable copy of the mbuf chain.  While doing this
 * we compact the chain with a goal of producing a chain with
 * at most two mbufs.  The second mbuf in this chain is likely
 * to be a cluster.  The primary purpose of this work is to create
 * a writable packet for encryption, compression, etc.  The
 * secondary goal is to linearize the data so the data can be
 * passed to crypto hardware in the most efficient manner possible.
 */
struct mbuf *
m_clone(struct mbuf *m0)
{
	struct mbuf *m, *mprev;

	KASSERT(m0 != NULL, ("m_clone: null mbuf"));

	mprev = NULL;
	for (m = m0; m != NULL; m = mprev->m_next) {
		/*
		 * Regular mbufs are ignored unless there's a cluster
		 * in front of it that we can use to coalesce.  We do
		 * the latter mainly so later clusters can be coalesced
		 * also w/o having to handle them specially (i.e. convert
		 * mbuf+cluster -> cluster).  This optimization is heavily
		 * influenced by the assumption that we're running over
		 * Ethernet where MCBYTES is large enough that the max
		 * packet size will permit lots of coalescing into a
		 * single cluster.  This in turn permits efficient
		 * crypto operations, especially when using hardware.
		 */
		if ((m->m_flags & M_EXT) == 0) {
			if (mprev && (mprev->m_flags & M_EXT) &&
			    m->m_len <= M_TRAILINGSPACE(mprev)) {
				/* XXX: this ignores mbuf types */
				memcpy(mtod(mprev, caddr_t) + mprev->m_len,
				       mtod(m, caddr_t), m->m_len);
				mprev->m_len += m->m_len;
				mprev->m_next = m->m_next;	/* unlink from chain */
				m_free(m);			/* reclaim mbuf */
				newipsecstat.ips_mbcoalesced++;
			} else {
				mprev = m;
			}
			continue;
		}
		/*
		 * Cluster'd mbufs are left alone (for now).
		 */
		if (!MEXT_IS_REF(m)) {
			mprev = m;
			continue;
		}
		/*
		 * Not writable, replace with a copy or coalesce with
		 * the previous mbuf if possible (since we have to copy
		 * it anyway, we try to reduce the number of mbufs and
		 * clusters so that future work is easier).
		 */
		/* XXX why can M_PKTHDR be set past the first mbuf? */
		KASSERT(m->m_flags & M_EXT,
			("m_clone: m_flags 0x%x", m->m_flags));
		/* NB: we only coalesce into a cluster */
		if (mprev == NULL || (mprev->m_flags & M_EXT) == 0 ||
		    m->m_len > M_TRAILINGSPACE(mprev)) {
			struct mbuf *n;

			/*
			 * Allocate a new page, copy the data to the front
			 * and release the reference to the old page.
			 */
			n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags);
			if (n == NULL) {
				m_freem(m0);
				return (NULL);
			}
			if (mprev == NULL && (m->m_flags & M_PKTHDR))
				M_COPY_PKTHDR(n, m);
			memcpy(mtod(n, caddr_t), mtod(m, caddr_t), m->m_len);
			n->m_len = m->m_len;
			n->m_next = m->m_next;
			if (mprev == NULL)
				m0 = n;			/* new head of chain */
			else
				mprev->m_next = n;	/* replace old mbuf */
			m_free(m);			/* release old mbuf */
			mprev = n;
			newipsecstat.ips_clcopied++;
		} else {
			/* XXX: this ignores mbuf types */
			memcpy(mtod(mprev, caddr_t) + mprev->m_len,
			       mtod(m, caddr_t), m->m_len);
			mprev->m_len += m->m_len;
			mprev->m_next = m->m_next;	/* unlink from chain */
			m_free(m);			/* reclaim mbuf */
			newipsecstat.ips_clcoalesced++;
		}
	}
	return (m0);
}

/*
 * Make space for a new header of length hlen at offset off
 * in the packet.  When doing this we allocate new mbufs only
 * when absolutely necessary.  The mbuf where the new header
 * is to go is returned together with an offset into the mbuf.
 * If NULL is returned then the mbuf chain may have been modified;
 * the caller is assumed to always free the chain.
 */
struct mbuf *
m_makespace(struct mbuf *m0, int skip, int hlen, int *off)
{
	struct mbuf *m;
	unsigned remain;

	KASSERT(m0 != NULL, ("m_dmakespace: null mbuf"));
	KASSERT(hlen < MHLEN, ("m_makespace: hlen too big: %u", hlen));

	for (m = m0; m && skip > m->m_len; m = m->m_next)
		skip -= m->m_len;
	if (m == NULL)
		return (NULL);
	/*
	 * At this point skip is the offset into the mbuf m
	 * where the new header should be placed.  Figure out
	 * if there's space to insert the new header.  If so,
	 * and copying the remainder makese sense then do so.
	 * Otherwise insert a new mbuf in the chain, splitting
	 * the contents of m as needed.
	 */
	remain = m->m_len - skip;		/* data to move */
	/* XXX code doesn't handle clusters XXX */
	KASSERT(remain < MLEN, ("m_makespace: remainder too big: %u", remain));
	if (hlen > M_TRAILINGSPACE(m)) {
		struct mbuf *n;

		/*
		 * Not enough space in m, split the contents
		 * of m, inserting new mbufs as required.
		 *
		 * NB: this ignores mbuf types.
		 */
		MGET(n, M_DONTWAIT, MT_DATA);
		if (n == NULL)<commit_msg>o cannot use M_COPY_PKTHDR on an mbuf that has a cluster; if we need to   do this avoid m_getcl so we can copy the packet header to a clean mbuf   before adding the cluster o move an assert to the right place<commit_after>/*	$FreeBSD$	*/

/*
 * IPsec-specific mbuf routines.
 */

#include "opt_param.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>

#include <net/route.h>
#include <netinet/in.h>

#include <netipsec/ipsec.h>

extern	struct mbuf *m_getptr(struct mbuf *, int, int *);

/*
 * Create a writable copy of the mbuf chain.  While doing this
 * we compact the chain with a goal of producing a chain with
 * at most two mbufs.  The second mbuf in this chain is likely
 * to be a cluster.  The primary purpose of this work is to create
 * a writable packet for encryption, compression, etc.  The
 * secondary goal is to linearize the data so the data can be
 * passed to crypto hardware in the most efficient manner possible.
 */
struct mbuf *
m_clone(struct mbuf *m0)
{
	struct mbuf *m, *mprev;

	KASSERT(m0 != NULL, ("m_clone: null mbuf"));

	mprev = NULL;
	for (m = m0; m != NULL; m = mprev->m_next) {
		/*
		 * Regular mbufs are ignored unless there's a cluster
		 * in front of it that we can use to coalesce.  We do
		 * the latter mainly so later clusters can be coalesced
		 * also w/o having to handle them specially (i.e. convert
		 * mbuf+cluster -> cluster).  This optimization is heavily
		 * influenced by the assumption that we're running over
		 * Ethernet where MCBYTES is large enough that the max
		 * packet size will permit lots of coalescing into a
		 * single cluster.  This in turn permits efficient
		 * crypto operations, especially when using hardware.
		 */
		if ((m->m_flags & M_EXT) == 0) {
			if (mprev && (mprev->m_flags & M_EXT) &&
			    m->m_len <= M_TRAILINGSPACE(mprev)) {
				/* XXX: this ignores mbuf types */
				memcpy(mtod(mprev, caddr_t) + mprev->m_len,
				       mtod(m, caddr_t), m->m_len);
				mprev->m_len += m->m_len;
				mprev->m_next = m->m_next;	/* unlink from chain */
				m_free(m);			/* reclaim mbuf */
				newipsecstat.ips_mbcoalesced++;
			} else {
				mprev = m;
			}
			continue;
		}
		/*
		 * Cluster'd mbufs are left alone (for now).
		 */
		if (!MEXT_IS_REF(m)) {
			mprev = m;
			continue;
		}
		/*
		 * Not writable, replace with a copy or coalesce with
		 * the previous mbuf if possible (since we have to copy
		 * it anyway, we try to reduce the number of mbufs and
		 * clusters so that future work is easier).
		 */
		/* XXX why can M_PKTHDR be set past the first mbuf? */
		KASSERT(m->m_flags & M_EXT,
			("m_clone: m_flags 0x%x", m->m_flags));
		/* NB: we only coalesce into a cluster */
		if (mprev == NULL || (mprev->m_flags & M_EXT) == 0 ||
		    m->m_len > M_TRAILINGSPACE(mprev)) {
			struct mbuf *n;

			/*
			 * Allocate a new page, copy the data to the front
			 * and release the reference to the old page.
			 */
			if (mprev == NULL && (m->m_flags & M_PKTHDR)) {
				/*
				 * NB: if a packet header is present we
				 * must allocate the mbuf separately from
				 * the cluster 'cuz M_COPY_PKTHDR will
				 * smash the data pointer and drop the
				 * M_EXT marker.
				 */
				MGETHDR(n, M_DONTWAIT, m->m_type);
				if (n == NULL) {
					m_freem(m0);
					return (NULL);
				}
				M_COPY_PKTHDR(n, m);
				MCLGET(n, M_DONTWAIT);
				if ((n->m_flags & M_EXT) == 0) {
					m_free(n);
					m_freem(m0);
					return (NULL);
				}
			} else {
				n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags);
				if (n == NULL) {
					m_freem(m0);
					return (NULL);
				}
			}
			memcpy(mtod(n, caddr_t), mtod(m, caddr_t), m->m_len);
			n->m_len = m->m_len;
			n->m_next = m->m_next;
			if (mprev == NULL)
				m0 = n;			/* new head of chain */
			else
				mprev->m_next = n;	/* replace old mbuf */
			m_free(m);			/* release old mbuf */
			mprev = n;
			newipsecstat.ips_clcopied++;
		} else {
			/* XXX: this ignores mbuf types */
			memcpy(mtod(mprev, caddr_t) + mprev->m_len,
			       mtod(m, caddr_t), m->m_len);
			mprev->m_len += m->m_len;
			mprev->m_next = m->m_next;	/* unlink from chain */
			m_free(m);			/* reclaim mbuf */
			newipsecstat.ips_clcoalesced++;
		}
	}
	return (m0);
}

/*
 * Make space for a new header of length hlen at offset off
 * in the packet.  When doing this we allocate new mbufs only
 * when absolutely necessary.  The mbuf where the new header
 * is to go is returned together with an offset into the mbuf.
 * If NULL is returned then the mbuf chain may have been modified;
 * the caller is assumed to always free the chain.
 */
struct mbuf *
m_makespace(struct mbuf *m0, int skip, int hlen, int *off)
{
	struct mbuf *m;
	unsigned remain;

	KASSERT(m0 != NULL, ("m_dmakespace: null mbuf"));
	KASSERT(hlen < MHLEN, ("m_makespace: hlen too big: %u", hlen));

	for (m = m0; m && skip > m->m_len; m = m->m_next)
		skip -= m->m_len;
	if (m == NULL)
		return (NULL);
	/*
	 * At this point skip is the offset into the mbuf m
	 * where the new header should be placed.  Figure out
	 * if there's space to insert the new header.  If so,
	 * and copying the remainder makese sense then do so.
	 * Otherwise insert a new mbuf in the chain, splitting
	 * the contents of m as needed.
	 */
	remain = m->m_len - skip;		/* data to move */
	if (hlen > M_TRAILINGSPACE(m)) {
		struct mbuf *n;

		/* XXX code doesn't handle clusters XXX */
		KASSERT(remain < MLEN,
			("m_makespace: remainder too big: %u", remain));
		/*
		 * Not enough space in m, split the contents
		 * of m, inserting new mbufs as required.
		 *
		 * NB: this ignores mbuf types.
		 */
		MGET(n, M_DONTWAIT, MT_DATA);
		if (n == NULL)
{'fraction_non_alphanumeric': 0.12156567557395559, 'fraction_numerical': 0.002540459164471208, 'mean_word_length': 2.806948424068768, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '632076', 'n_tokens_mistral': 4300, 'n_tokens_neox': 3771, 'n_words': 1363}