xref: /netbsd-src/sys/netipsec/ipsec_mbuf.c (revision b1305a6d636e789c2b4b3c4a94601d0fe674a6ae)
1*b1305a6dSmaxv /*	$NetBSD: ipsec_mbuf.c,v 1.30 2018/12/22 13:11:38 maxv Exp $	*/
216a6b570Smaxv 
316a6b570Smaxv /*
4c82e44fcSthorpej  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5c82e44fcSthorpej  * All rights reserved.
6c82e44fcSthorpej  *
7c82e44fcSthorpej  * Redistribution and use in source and binary forms, with or without
8c82e44fcSthorpej  * modification, are permitted provided that the following conditions
9c82e44fcSthorpej  * are met:
10c82e44fcSthorpej  * 1. Redistributions of source code must retain the above copyright
11c82e44fcSthorpej  *    notice, this list of conditions and the following disclaimer.
12c82e44fcSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
13c82e44fcSthorpej  *    notice, this list of conditions and the following disclaimer in the
14c82e44fcSthorpej  *    documentation and/or other materials provided with the distribution.
15c82e44fcSthorpej  *
16c82e44fcSthorpej  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17c82e44fcSthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c82e44fcSthorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c82e44fcSthorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20c82e44fcSthorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c82e44fcSthorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c82e44fcSthorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c82e44fcSthorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c82e44fcSthorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c82e44fcSthorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c82e44fcSthorpej  * SUCH DAMAGE.
27c82e44fcSthorpej  *
28e2c8a664Smaxv  * $FreeBSD: sys/netipsec/ipsec_mbuf.c,v 1.5.2.2 2003/03/28 20:32:53 sam Exp $
29c82e44fcSthorpej  */
3074029031Sjonathan 
3174029031Sjonathan #include <sys/cdefs.h>
32*b1305a6dSmaxv __KERNEL_RCSID(0, "$NetBSD: ipsec_mbuf.c,v 1.30 2018/12/22 13:11:38 maxv Exp $");
3374029031Sjonathan 
3474029031Sjonathan /*
3574029031Sjonathan  * IPsec-specific mbuf routines.
3674029031Sjonathan  */
3774029031Sjonathan 
3874029031Sjonathan #include <sys/param.h>
3974029031Sjonathan #include <sys/systm.h>
4074029031Sjonathan #include <sys/mbuf.h>
4174029031Sjonathan 
4274029031Sjonathan #include <netipsec/ipsec.h>
4385b3ba5bSjonathan #include <netipsec/ipsec_var.h>
44caf49ea5Sthorpej #include <netipsec/ipsec_private.h>
4574029031Sjonathan 
4674029031Sjonathan /*
4774029031Sjonathan  * Create a writable copy of the mbuf chain.  While doing this
4874029031Sjonathan  * we compact the chain with a goal of producing a chain with
4974029031Sjonathan  * at most two mbufs.  The second mbuf in this chain is likely
5074029031Sjonathan  * to be a cluster.  The primary purpose of this work is to create
5174029031Sjonathan  * a writable packet for encryption, compression, etc.  The
5274029031Sjonathan  * secondary goal is to linearize the data so the data can be
5374029031Sjonathan  * passed to crypto hardware in the most efficient manner possible.
5474029031Sjonathan  */
5574029031Sjonathan struct mbuf *
m_clone(struct mbuf * m0)5674029031Sjonathan m_clone(struct mbuf *m0)
5774029031Sjonathan {
5874029031Sjonathan 	struct mbuf *m, *mprev;
5974029031Sjonathan 	struct mbuf *n, *mfirst, *mlast;
6074029031Sjonathan 	int len, off;
6174029031Sjonathan 
622620e166Sozaki-r 	KASSERT(m0 != NULL);
6374029031Sjonathan 
6474029031Sjonathan 	mprev = NULL;
6574029031Sjonathan 	for (m = m0; m != NULL; m = mprev->m_next) {
6674029031Sjonathan 		/*
6774029031Sjonathan 		 * Regular mbufs are ignored unless there's a cluster
6848df35d3Smaxv 		 * in front of it that we can use to coalesce.
6974029031Sjonathan 		 */
7074029031Sjonathan 		if ((m->m_flags & M_EXT) == 0) {
7174029031Sjonathan 			if (mprev && (mprev->m_flags & M_EXT) &&
7274029031Sjonathan 			    m->m_len <= M_TRAILINGSPACE(mprev)) {
73c252f603Sdegroote 				memcpy(mtod(mprev, char *) + mprev->m_len,
74c252f603Sdegroote 				    mtod(m, char *), m->m_len);
7574029031Sjonathan 				mprev->m_len += m->m_len;
7648df35d3Smaxv 				mprev->m_next = m_free(m);
77caf49ea5Sthorpej 				IPSEC_STATINC(IPSEC_STAT_MBCOALESCED);
7874029031Sjonathan 			} else {
7974029031Sjonathan 				mprev = m;
8074029031Sjonathan 			}
8174029031Sjonathan 			continue;
8274029031Sjonathan 		}
830ad30c0fSmaxv 
8474029031Sjonathan 		/*
8548df35d3Smaxv 		 * Writable mbufs are left alone.
8674029031Sjonathan 		 */
87f193022cSmaxv 		if (!M_READONLY(m)) {
8874029031Sjonathan 			mprev = m;
8974029031Sjonathan 			continue;
9074029031Sjonathan 		}
9174029031Sjonathan 
9274029031Sjonathan 		/*
9374029031Sjonathan 		 * Not writable, replace with a copy or coalesce with
9474029031Sjonathan 		 * the previous mbuf if possible (since we have to copy
9574029031Sjonathan 		 * it anyway, we try to reduce the number of mbufs and
9674029031Sjonathan 		 * clusters so that future work is easier).
9774029031Sjonathan 		 */
9848df35d3Smaxv 
9948df35d3Smaxv 		/* We only coalesce into a cluster. */
10074029031Sjonathan 		if (mprev != NULL && (mprev->m_flags & M_EXT) &&
10174029031Sjonathan 		    m->m_len <= M_TRAILINGSPACE(mprev)) {
102c252f603Sdegroote 			memcpy(mtod(mprev, char *) + mprev->m_len,
103c252f603Sdegroote 			    mtod(m, char *), m->m_len);
10474029031Sjonathan 			mprev->m_len += m->m_len;
10548df35d3Smaxv 			mprev->m_next = m_free(m);
106caf49ea5Sthorpej 			IPSEC_STATINC(IPSEC_STAT_CLCOALESCED);
10774029031Sjonathan 			continue;
10874029031Sjonathan 		}
10974029031Sjonathan 
11074029031Sjonathan 		/*
11174029031Sjonathan 		 * Allocate new space to hold the copy...
11274029031Sjonathan 		 */
11374029031Sjonathan 		if (mprev == NULL && (m->m_flags & M_PKTHDR)) {
11474029031Sjonathan 			MGETHDR(n, M_DONTWAIT, m->m_type);
11574029031Sjonathan 			if (n == NULL) {
11674029031Sjonathan 				m_freem(m0);
1170ad30c0fSmaxv 				return NULL;
11874029031Sjonathan 			}
119*b1305a6dSmaxv 			m_move_pkthdr(n, m);
12074029031Sjonathan 			MCLGET(n, M_DONTWAIT);
12174029031Sjonathan 			if ((n->m_flags & M_EXT) == 0) {
12274029031Sjonathan 				m_free(n);
12374029031Sjonathan 				m_freem(m0);
1240ad30c0fSmaxv 				return NULL;
12574029031Sjonathan 			}
12674029031Sjonathan 		} else {
12774029031Sjonathan 			n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags);
12874029031Sjonathan 			if (n == NULL) {
12974029031Sjonathan 				m_freem(m0);
1300ad30c0fSmaxv 				return NULL;
13174029031Sjonathan 			}
13274029031Sjonathan 		}
1330ad30c0fSmaxv 
13474029031Sjonathan 		/*
13574029031Sjonathan 		 * ... and copy the data.  We deal with jumbo mbufs
13674029031Sjonathan 		 * (i.e. m_len > MCLBYTES) by splitting them into
13774029031Sjonathan 		 * clusters.  We could just malloc a buffer and make
13874029031Sjonathan 		 * it external but too many device drivers don't know
13974029031Sjonathan 		 * how to break up the non-contiguous memory when
14074029031Sjonathan 		 * doing DMA.
14174029031Sjonathan 		 */
14274029031Sjonathan 		len = m->m_len;
14374029031Sjonathan 		off = 0;
14474029031Sjonathan 		mfirst = n;
14574029031Sjonathan 		mlast = NULL;
14674029031Sjonathan 		for (;;) {
147d1579b2dSriastradh 			const int cc = uimin(len, MCLBYTES);
148c252f603Sdegroote 			memcpy(mtod(n, char *), mtod(m, char *) + off, cc);
14974029031Sjonathan 			n->m_len = cc;
15074029031Sjonathan 			if (mlast != NULL)
15174029031Sjonathan 				mlast->m_next = n;
15274029031Sjonathan 			mlast = n;
153caf49ea5Sthorpej 			IPSEC_STATINC(IPSEC_STAT_CLCOPIED);
15474029031Sjonathan 
15574029031Sjonathan 			len -= cc;
15674029031Sjonathan 			if (len <= 0)
15774029031Sjonathan 				break;
15874029031Sjonathan 			off += cc;
15974029031Sjonathan 
16074029031Sjonathan 			n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags);
16174029031Sjonathan 			if (n == NULL) {
16274029031Sjonathan 				m_freem(mfirst);
16374029031Sjonathan 				m_freem(m0);
1640ad30c0fSmaxv 				return NULL;
16574029031Sjonathan 			}
16674029031Sjonathan 		}
16774029031Sjonathan 		n->m_next = m->m_next;
16874029031Sjonathan 		if (mprev == NULL)
16974029031Sjonathan 			m0 = mfirst;		/* new head of chain */
17074029031Sjonathan 		else
17174029031Sjonathan 			mprev->m_next = mfirst;	/* replace old mbuf */
17274029031Sjonathan 		m_free(m);			/* release old mbuf */
17374029031Sjonathan 		mprev = mfirst;
17474029031Sjonathan 	}
1750ad30c0fSmaxv 
1760ad30c0fSmaxv 	return m0;
17774029031Sjonathan }
17874029031Sjonathan 
17974029031Sjonathan /*
18074029031Sjonathan  * Make space for a new header of length hlen at skip bytes
18174029031Sjonathan  * into the packet.  When doing this we allocate new mbufs only
18274029031Sjonathan  * when absolutely necessary.  The mbuf where the new header
18374029031Sjonathan  * is to go is returned together with an offset into the mbuf.
18474029031Sjonathan  * If NULL is returned then the mbuf chain may have been modified;
18574029031Sjonathan  * the caller is assumed to always free the chain.
18674029031Sjonathan  */
18774029031Sjonathan struct mbuf *
m_makespace(struct mbuf * m0,int skip,int hlen,int * off)18874029031Sjonathan m_makespace(struct mbuf *m0, int skip, int hlen, int *off)
18974029031Sjonathan {
19074029031Sjonathan 	struct mbuf *m;
19174029031Sjonathan 	unsigned remain;
19274029031Sjonathan 
1932620e166Sozaki-r 	KASSERT(m0 != NULL);
1947ddcc8beSmaxv 	KASSERT(m0->m_flags & M_PKTHDR);
1952620e166Sozaki-r 	KASSERTMSG(hlen < MHLEN, "hlen too big: %u", hlen);
19674029031Sjonathan 
19774029031Sjonathan 	for (m = m0; m && skip > m->m_len; m = m->m_next)
19874029031Sjonathan 		skip -= m->m_len;
19974029031Sjonathan 	if (m == NULL)
2000ad30c0fSmaxv 		return NULL;
2010ad30c0fSmaxv 
20274029031Sjonathan 	/*
20374029031Sjonathan 	 * At this point skip is the offset into the mbuf m
20474029031Sjonathan 	 * where the new header should be placed.  Figure out
20574029031Sjonathan 	 * if there's space to insert the new header.  If so,
20616a6b570Smaxv 	 * and copying the remainder makes sense then do so.
20774029031Sjonathan 	 * Otherwise insert a new mbuf in the chain, splitting
20874029031Sjonathan 	 * the contents of m as needed.
20974029031Sjonathan 	 */
21074029031Sjonathan 	remain = m->m_len - skip;		/* data to move */
21174029031Sjonathan 	if (hlen > M_TRAILINGSPACE(m)) {
21282a49e73Sseanb 		struct mbuf *n0, *n, **np;
21382a49e73Sseanb 		int todo, len, done, alloc;
21474029031Sjonathan 
21582a49e73Sseanb 		n0 = NULL;
21682a49e73Sseanb 		np = &n0;
21782a49e73Sseanb 		alloc = 0;
21882a49e73Sseanb 		done = 0;
21982a49e73Sseanb 		todo = remain;
22082a49e73Sseanb 		while (todo > 0) {
22182a49e73Sseanb 			if (todo > MHLEN) {
22282a49e73Sseanb 				n = m_getcl(M_DONTWAIT, m->m_type, 0);
22382a49e73Sseanb 				len = MCLBYTES;
22416a6b570Smaxv 			} else {
22582a49e73Sseanb 				n = m_get(M_DONTWAIT, m->m_type);
22682a49e73Sseanb 				len = MHLEN;
22782a49e73Sseanb 			}
22882a49e73Sseanb 			if (n == NULL) {
22982a49e73Sseanb 				m_freem(n0);
23082a49e73Sseanb 				return NULL;
23182a49e73Sseanb 			}
23282a49e73Sseanb 			*np = n;
23382a49e73Sseanb 			np = &n->m_next;
23482a49e73Sseanb 			alloc++;
235d1579b2dSriastradh 			len = uimin(todo, len);
23682a49e73Sseanb 			memcpy(n->m_data, mtod(m, char *) + skip + done, len);
23782a49e73Sseanb 			n->m_len = len;
23882a49e73Sseanb 			done += len;
23982a49e73Sseanb 			todo -= len;
24082a49e73Sseanb 		}
24182a49e73Sseanb 
24274029031Sjonathan 		if (hlen <= M_TRAILINGSPACE(m) + remain) {
24374029031Sjonathan 			m->m_len = skip + hlen;
24474029031Sjonathan 			*off = skip;
24582a49e73Sseanb 			if (n0 != NULL) {
24682a49e73Sseanb 				*np = m->m_next;
24782a49e73Sseanb 				m->m_next = n0;
24874029031Sjonathan 			}
24916a6b570Smaxv 		} else {
25082a49e73Sseanb 			n = m_get(M_DONTWAIT, m->m_type);
25182a49e73Sseanb 			if (n == NULL) {
25282a49e73Sseanb 				m_freem(n0);
25382a49e73Sseanb 				return NULL;
25482a49e73Sseanb 			}
25582a49e73Sseanb 			alloc++;
25682a49e73Sseanb 
25782a49e73Sseanb 			if ((n->m_next = n0) == NULL)
25882a49e73Sseanb 				np = &n->m_next;
25982a49e73Sseanb 			n0 = n;
26082a49e73Sseanb 
26182a49e73Sseanb 			*np = m->m_next;
26282a49e73Sseanb 			m->m_next = n0;
26382a49e73Sseanb 
26482a49e73Sseanb 			n->m_len = hlen;
26582a49e73Sseanb 			m->m_len = skip;
26682a49e73Sseanb 
26774029031Sjonathan 			m = n;			/* header is at front ... */
26874029031Sjonathan 			*off = 0;		/* ... of new mbuf */
26974029031Sjonathan 		}
27082a49e73Sseanb 
271caf49ea5Sthorpej 		IPSEC_STATADD(IPSEC_STAT_MBINSERTED, alloc);
27274029031Sjonathan 	} else {
27374029031Sjonathan 		/*
27474029031Sjonathan 		 * Copy the remainder to the back of the mbuf
27574029031Sjonathan 		 * so there's space to write the new header.
27674029031Sjonathan 		 */
27774029031Sjonathan 		/* XXX can this be memcpy? does it handle overlap? */
27829fe0b74Smaxv 		memmove(mtod(m, char *) + skip + hlen,
27929fe0b74Smaxv 			mtod(m, char *) + skip, remain);
28074029031Sjonathan 		m->m_len += hlen;
28174029031Sjonathan 		*off = skip;
28274029031Sjonathan 	}
2830ad30c0fSmaxv 
28474029031Sjonathan 	m0->m_pkthdr.len += hlen;		/* adjust packet length */
28574029031Sjonathan 	return m;
28674029031Sjonathan }
28774029031Sjonathan 
28874029031Sjonathan /*
28974029031Sjonathan  * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
29074029031Sjonathan  * length is updated, and a pointer to the first byte of the padding
29174029031Sjonathan  * (which is guaranteed to be all in one mbuf) is returned.
29274029031Sjonathan  */
29353524e44Schristos void *
m_pad(struct mbuf * m,int n)29474029031Sjonathan m_pad(struct mbuf *m, int n)
29574029031Sjonathan {
29674029031Sjonathan 	register struct mbuf *m0, *m1;
29774029031Sjonathan 	register int len, pad;
29853524e44Schristos 	void *retval;
29974029031Sjonathan 
300f2110e85Smaxv 	if (__predict_false(n > MLEN)) {
301f2110e85Smaxv 		panic("%s: %d > MLEN", __func__, n);
30274029031Sjonathan 	}
3037ddcc8beSmaxv 	KASSERT(m->m_flags & M_PKTHDR);
30474029031Sjonathan 
30574029031Sjonathan 	len = m->m_pkthdr.len;
30674029031Sjonathan 	pad = n;
30774029031Sjonathan 	m0 = m;
30874029031Sjonathan 
30974029031Sjonathan 	while (m0->m_len < len) {
3102620e166Sozaki-r 		KASSERTMSG(m0->m_next != NULL,
311f2110e85Smaxv 		    "m0 null, len %u m_len %u", len, m0->m_len);
31274029031Sjonathan 		len -= m0->m_len;
31374029031Sjonathan 		m0 = m0->m_next;
31474029031Sjonathan 	}
31574029031Sjonathan 
31674029031Sjonathan 	if (m0->m_len != len) {
317290dc492Sozaki-r 		IPSECLOG(LOG_DEBUG,
318290dc492Sozaki-r 		    "length mismatch (should be %d instead of %d)\n",
319290dc492Sozaki-r 		    m->m_pkthdr.len, m->m_pkthdr.len + m0->m_len - len);
32074029031Sjonathan 		m_freem(m);
32174029031Sjonathan 		return NULL;
32274029031Sjonathan 	}
32374029031Sjonathan 
32474029031Sjonathan 	/* Check for zero-length trailing mbufs, and find the last one. */
32574029031Sjonathan 	for (m1 = m0; m1->m_next; m1 = m1->m_next) {
32674029031Sjonathan 		if (m1->m_next->m_len != 0) {
327290dc492Sozaki-r 			IPSECLOG(LOG_DEBUG,
328290dc492Sozaki-r 			    "length mismatch (should be %d instead of %d)\n",
32974029031Sjonathan 			    m->m_pkthdr.len,
330290dc492Sozaki-r 			    m->m_pkthdr.len + m1->m_next->m_len);
33174029031Sjonathan 			m_freem(m);
33274029031Sjonathan 			return NULL;
33374029031Sjonathan 		}
33474029031Sjonathan 
33574029031Sjonathan 		m0 = m1->m_next;
33674029031Sjonathan 	}
33774029031Sjonathan 
33874029031Sjonathan 	if (pad > M_TRAILINGSPACE(m0)) {
33974029031Sjonathan 		/* Add an mbuf to the chain. */
34074029031Sjonathan 		MGET(m1, M_DONTWAIT, MT_DATA);
341f2110e85Smaxv 		if (m1 == NULL) {
342f2110e85Smaxv 			m_freem(m);
343290dc492Sozaki-r 			IPSECLOG(LOG_DEBUG, "unable to get extra mbuf\n");
34474029031Sjonathan 			return NULL;
34574029031Sjonathan 		}
34674029031Sjonathan 
34774029031Sjonathan 		m0->m_next = m1;
34874029031Sjonathan 		m0 = m1;
34974029031Sjonathan 		m0->m_len = 0;
35074029031Sjonathan 	}
35174029031Sjonathan 
35274029031Sjonathan 	retval = m0->m_data + m0->m_len;
35374029031Sjonathan 	m0->m_len += pad;
35474029031Sjonathan 	m->m_pkthdr.len += pad;
35574029031Sjonathan 
35674029031Sjonathan 	return retval;
35774029031Sjonathan }
35874029031Sjonathan 
35974029031Sjonathan /*
36074029031Sjonathan  * Remove hlen data at offset skip in the packet.  This is used by
36174029031Sjonathan  * the protocols strip protocol headers and associated data (e.g. IV,
36274029031Sjonathan  * authenticator) on input.
36374029031Sjonathan  */
36474029031Sjonathan int
m_striphdr(struct mbuf * m,int skip,int hlen)36574029031Sjonathan m_striphdr(struct mbuf *m, int skip, int hlen)
36674029031Sjonathan {
36774029031Sjonathan 	struct mbuf *m1;
36874029031Sjonathan 	int roff;
36974029031Sjonathan 
3707ddcc8beSmaxv 	KASSERT(m->m_flags & M_PKTHDR);
3717ddcc8beSmaxv 
37274029031Sjonathan 	/* Find beginning of header */
37374029031Sjonathan 	m1 = m_getptr(m, skip, &roff);
37474029031Sjonathan 	if (m1 == NULL)
3750ad30c0fSmaxv 		return EINVAL;
37674029031Sjonathan 
37774029031Sjonathan 	/* Remove the header and associated data from the mbuf. */
37874029031Sjonathan 	if (roff == 0) {
37974029031Sjonathan 		/* The header was at the beginning of the mbuf */
380caf49ea5Sthorpej 		IPSEC_STATINC(IPSEC_STAT_INPUT_FRONT);
38174029031Sjonathan 		m_adj(m1, hlen);
382cc059e55Smaxv 		if (m1 != m)
38374029031Sjonathan 			m->m_pkthdr.len -= hlen;
38474029031Sjonathan 	} else if (roff + hlen >= m1->m_len) {
38574029031Sjonathan 		struct mbuf *mo;
38603bb22c3Smaxv 		int adjlen;
38774029031Sjonathan 
38874029031Sjonathan 		/*
38974029031Sjonathan 		 * Part or all of the header is at the end of this mbuf,
39074029031Sjonathan 		 * so first let's remove the remainder of the header from
39174029031Sjonathan 		 * the beginning of the remainder of the mbuf chain, if any.
39274029031Sjonathan 		 */
393caf49ea5Sthorpej 		IPSEC_STATINC(IPSEC_STAT_INPUT_END);
39474029031Sjonathan 		if (roff + hlen > m1->m_len) {
39503bb22c3Smaxv 			adjlen = roff + hlen - m1->m_len;
39603bb22c3Smaxv 
39774029031Sjonathan 			/* Adjust the next mbuf by the remainder */
39803bb22c3Smaxv 			m_adj(m1->m_next, adjlen);
39974029031Sjonathan 
40074029031Sjonathan 			/* The second mbuf is guaranteed not to have a pkthdr... */
40103bb22c3Smaxv 			m->m_pkthdr.len -= adjlen;
40274029031Sjonathan 		}
40374029031Sjonathan 
40474029031Sjonathan 		/* Now, let's unlink the mbuf chain for a second...*/
40574029031Sjonathan 		mo = m1->m_next;
40674029031Sjonathan 		m1->m_next = NULL;
40774029031Sjonathan 
40874029031Sjonathan 		/* ...and trim the end of the first part of the chain...sick */
40903bb22c3Smaxv 		adjlen = m1->m_len - roff;
41003bb22c3Smaxv 		m_adj(m1, -adjlen);
411cc059e55Smaxv 		if (m1 != m)
41203bb22c3Smaxv 			m->m_pkthdr.len -= adjlen;
41374029031Sjonathan 
41474029031Sjonathan 		/* Finally, let's relink */
41574029031Sjonathan 		m1->m_next = mo;
41674029031Sjonathan 	} else {
41774029031Sjonathan 		/*
41874029031Sjonathan 		 * The header lies in the "middle" of the mbuf; copy
41974029031Sjonathan 		 * the remainder of the mbuf down over the header.
42074029031Sjonathan 		 */
421caf49ea5Sthorpej 		IPSEC_STATINC(IPSEC_STAT_INPUT_MIDDLE);
42229fe0b74Smaxv 		memmove(mtod(m1, u_char *) + roff,
42329fe0b74Smaxv 		      mtod(m1, u_char *) + roff + hlen,
42474029031Sjonathan 		      m1->m_len - (roff + hlen));
42574029031Sjonathan 		m1->m_len -= hlen;
42674029031Sjonathan 		m->m_pkthdr.len -= hlen;
42774029031Sjonathan 	}
4280ad30c0fSmaxv 
4290ad30c0fSmaxv 	return 0;
43074029031Sjonathan }
431