uipc_mbuf.c revision 10358
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1988, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
331541Srgrimes *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
3410358Sjulian * $Id: uipc_mbuf.c,v 1.10 1995/07/29 11:40:16 bde Exp $
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include <sys/param.h>
381541Srgrimes#include <sys/systm.h>
391541Srgrimes#include <sys/proc.h>
401541Srgrimes#include <sys/malloc.h>
411541Srgrimes#define MBTYPES
421541Srgrimes#include <sys/mbuf.h>
431541Srgrimes#include <sys/kernel.h>
441541Srgrimes#include <sys/syslog.h>
451541Srgrimes#include <sys/domain.h>
461541Srgrimes#include <sys/protosw.h>
471541Srgrimes
481541Srgrimes#include <vm/vm.h>
499759Sbde#include <vm/vm_kern.h>
501541Srgrimes
5110358Sjulian/*
5210358Sjulian * System initialization
5310358Sjulian */
5410358Sjulian
5510358Sjulianstatic void mbinit __P((caddr_t));
5610358SjulianSYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL)
5710358Sjulian
5810358Sjulian
599759Sbdestruct mbuf *mbutl;
601541Srgrimeschar	*mclrefcnt;
619759Sbdestruct mbstat mbstat;
629759Sbdeunion mcluster *mclfree;
639759Sbdeint	max_linkhdr;
649759Sbdeint	max_protohdr;
659759Sbdeint	max_hdr;
669759Sbdeint	max_datalen;
671541Srgrimes
6810358Sjulian/* ARGSUSED*/
6910358Sjulianstatic void
7010358Sjulianmbinit( udata)
7110358Sjuliancaddr_t		udata;		/* not used*/
721541Srgrimes{
731541Srgrimes	int s;
741541Srgrimes
751541Srgrimes#if CLBYTES < 4096
761541Srgrimes#define NCL_INIT	(4096/CLBYTES)
771541Srgrimes#else
781541Srgrimes#define NCL_INIT	1
791541Srgrimes#endif
801541Srgrimes	s = splimp();
811541Srgrimes	if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
821541Srgrimes		goto bad;
831541Srgrimes	splx(s);
841541Srgrimes	return;
851541Srgrimesbad:
861541Srgrimes	panic("mbinit");
871541Srgrimes}
881541Srgrimes
891541Srgrimes/*
901541Srgrimes * Allocate some number of mbuf clusters
911541Srgrimes * and place on cluster free list.
921541Srgrimes * Must be called at splimp.
931541Srgrimes */
941541Srgrimes/* ARGSUSED */
951549Srgrimesint
961541Srgrimesm_clalloc(ncl, nowait)
971541Srgrimes	register int ncl;
981541Srgrimes	int nowait;
991541Srgrimes{
1001541Srgrimes	static int logged;
1011541Srgrimes	register caddr_t p;
1021541Srgrimes	register int i;
1031541Srgrimes	int npg;
1041541Srgrimes
1057066Sdg	/*
1067066Sdg	 * Once we run out of map space, it will be impossible
1077066Sdg	 * to get any more (nothing is ever freed back to the
1087066Sdg	 * map).
1097066Sdg	 */
1107066Sdg	if (mb_map_full)
1117066Sdg		return (0);
1127066Sdg
1131541Srgrimes	npg = ncl * CLSIZE;
1146191Sbde	p = (caddr_t)kmem_malloc(mb_map, ctob(npg),
1156191Sbde				 nowait ? M_NOWAIT : M_WAITOK);
1167066Sdg	/*
1177066Sdg	 * Either the map is now full, or this is nowait and there
1187066Sdg	 * are no pages left.
1197066Sdg	 */
1207066Sdg	if (p == NULL)
1211541Srgrimes		return (0);
1227066Sdg
1231541Srgrimes	ncl = ncl * CLBYTES / MCLBYTES;
1241541Srgrimes	for (i = 0; i < ncl; i++) {
1251541Srgrimes		((union mcluster *)p)->mcl_next = mclfree;
1261541Srgrimes		mclfree = (union mcluster *)p;
1271541Srgrimes		p += MCLBYTES;
1281541Srgrimes		mbstat.m_clfree++;
1291541Srgrimes	}
1301541Srgrimes	mbstat.m_clusters += ncl;
1311541Srgrimes	return (1);
1321541Srgrimes}
1331541Srgrimes
1341541Srgrimes/*
1351541Srgrimes * When MGET failes, ask protocols to free space when short of memory,
1361541Srgrimes * then re-attempt to allocate an mbuf.
1371541Srgrimes */
1381541Srgrimesstruct mbuf *
1391541Srgrimesm_retry(i, t)
1401541Srgrimes	int i, t;
1411541Srgrimes{
1421541Srgrimes	register struct mbuf *m;
1431541Srgrimes
1441541Srgrimes	m_reclaim();
1451541Srgrimes#define m_retry(i, t)	(struct mbuf *)0
1461541Srgrimes	MGET(m, i, t);
1471541Srgrimes#undef m_retry
1486669Sdg	if (m != NULL)
1496669Sdg		mbstat.m_wait++;
1506669Sdg	else
1516669Sdg		mbstat.m_drops++;
1521541Srgrimes	return (m);
1531541Srgrimes}
1541541Srgrimes
1551541Srgrimes/*
1561541Srgrimes * As above; retry an MGETHDR.
1571541Srgrimes */
1581541Srgrimesstruct mbuf *
1591541Srgrimesm_retryhdr(i, t)
1601541Srgrimes	int i, t;
1611541Srgrimes{
1621541Srgrimes	register struct mbuf *m;
1631541Srgrimes
1641541Srgrimes	m_reclaim();
1651541Srgrimes#define m_retryhdr(i, t) (struct mbuf *)0
1661541Srgrimes	MGETHDR(m, i, t);
1671541Srgrimes#undef m_retryhdr
1686669Sdg	if (m != NULL)
1696669Sdg		mbstat.m_wait++;
1706669Sdg	else
1716669Sdg		mbstat.m_drops++;
1721541Srgrimes	return (m);
1731541Srgrimes}
1741541Srgrimes
1751549Srgrimesvoid
1761541Srgrimesm_reclaim()
1771541Srgrimes{
1781541Srgrimes	register struct domain *dp;
1791541Srgrimes	register struct protosw *pr;
1801541Srgrimes	int s = splimp();
1811541Srgrimes
1821541Srgrimes	for (dp = domains; dp; dp = dp->dom_next)
1831541Srgrimes		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
1841541Srgrimes			if (pr->pr_drain)
1851541Srgrimes				(*pr->pr_drain)();
1861541Srgrimes	splx(s);
1871541Srgrimes	mbstat.m_drain++;
1881541Srgrimes}
1891541Srgrimes
1901541Srgrimes/*
1911541Srgrimes * Space allocation routines.
1921541Srgrimes * These are also available as macros
1931541Srgrimes * for critical paths.
1941541Srgrimes */
1951541Srgrimesstruct mbuf *
1961541Srgrimesm_get(nowait, type)
1971541Srgrimes	int nowait, type;
1981541Srgrimes{
1991541Srgrimes	register struct mbuf *m;
2001541Srgrimes
2011541Srgrimes	MGET(m, nowait, type);
2021541Srgrimes	return (m);
2031541Srgrimes}
2041541Srgrimes
2051541Srgrimesstruct mbuf *
2061541Srgrimesm_gethdr(nowait, type)
2071541Srgrimes	int nowait, type;
2081541Srgrimes{
2091541Srgrimes	register struct mbuf *m;
2101541Srgrimes
2111541Srgrimes	MGETHDR(m, nowait, type);
2121541Srgrimes	return (m);
2131541Srgrimes}
2141541Srgrimes
2151541Srgrimesstruct mbuf *
2161541Srgrimesm_getclr(nowait, type)
2171541Srgrimes	int nowait, type;
2181541Srgrimes{
2191541Srgrimes	register struct mbuf *m;
2201541Srgrimes
2211541Srgrimes	MGET(m, nowait, type);
2221541Srgrimes	if (m == 0)
2231541Srgrimes		return (0);
2241541Srgrimes	bzero(mtod(m, caddr_t), MLEN);
2251541Srgrimes	return (m);
2261541Srgrimes}
2271541Srgrimes
2281541Srgrimesstruct mbuf *
2291541Srgrimesm_free(m)
2301541Srgrimes	struct mbuf *m;
2311541Srgrimes{
2321541Srgrimes	register struct mbuf *n;
2331541Srgrimes
2341541Srgrimes	MFREE(m, n);
2351541Srgrimes	return (n);
2361541Srgrimes}
2371541Srgrimes
2381541Srgrimesvoid
2391541Srgrimesm_freem(m)
2401541Srgrimes	register struct mbuf *m;
2411541Srgrimes{
2421541Srgrimes	register struct mbuf *n;
2431541Srgrimes
2441541Srgrimes	if (m == NULL)
2451541Srgrimes		return;
2461541Srgrimes	do {
2471541Srgrimes		MFREE(m, n);
2483308Sphk		m = n;
2493308Sphk	} while (m);
2501541Srgrimes}
2511541Srgrimes
2521541Srgrimes/*
2531541Srgrimes * Mbuffer utility routines.
2541541Srgrimes */
2551541Srgrimes
2561541Srgrimes/*
2571541Srgrimes * Lesser-used path for M_PREPEND:
2581541Srgrimes * allocate new mbuf to prepend to chain,
2591541Srgrimes * copy junk along.
2601541Srgrimes */
2611541Srgrimesstruct mbuf *
2621541Srgrimesm_prepend(m, len, how)
2631541Srgrimes	register struct mbuf *m;
2641541Srgrimes	int len, how;
2651541Srgrimes{
2661541Srgrimes	struct mbuf *mn;
2671541Srgrimes
2681541Srgrimes	MGET(mn, how, m->m_type);
2691541Srgrimes	if (mn == (struct mbuf *)NULL) {
2701541Srgrimes		m_freem(m);
2711541Srgrimes		return ((struct mbuf *)NULL);
2721541Srgrimes	}
2731541Srgrimes	if (m->m_flags & M_PKTHDR) {
2741541Srgrimes		M_COPY_PKTHDR(mn, m);
2751541Srgrimes		m->m_flags &= ~M_PKTHDR;
2761541Srgrimes	}
2771541Srgrimes	mn->m_next = m;
2781541Srgrimes	m = mn;
2791541Srgrimes	if (len < MHLEN)
2801541Srgrimes		MH_ALIGN(m, len);
2811541Srgrimes	m->m_len = len;
2821541Srgrimes	return (m);
2831541Srgrimes}
2841541Srgrimes
2851541Srgrimes/*
2861541Srgrimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
2871541Srgrimes * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
2881541Srgrimes * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
2891541Srgrimes */
2901541Srgrimesint MCFail;
2911541Srgrimes
2921541Srgrimesstruct mbuf *
2931541Srgrimesm_copym(m, off0, len, wait)
2941541Srgrimes	register struct mbuf *m;
2951541Srgrimes	int off0, wait;
2961541Srgrimes	register int len;
2971541Srgrimes{
2981541Srgrimes	register struct mbuf *n, **np;
2991541Srgrimes	register int off = off0;
3001541Srgrimes	struct mbuf *top;
3011541Srgrimes	int copyhdr = 0;
3021541Srgrimes
3031541Srgrimes	if (off < 0 || len < 0)
3041541Srgrimes		panic("m_copym");
3051541Srgrimes	if (off == 0 && m->m_flags & M_PKTHDR)
3061541Srgrimes		copyhdr = 1;
3071541Srgrimes	while (off > 0) {
3081541Srgrimes		if (m == 0)
3091541Srgrimes			panic("m_copym");
3101541Srgrimes		if (off < m->m_len)
3111541Srgrimes			break;
3121541Srgrimes		off -= m->m_len;
3131541Srgrimes		m = m->m_next;
3141541Srgrimes	}
3151541Srgrimes	np = &top;
3161541Srgrimes	top = 0;
3171541Srgrimes	while (len > 0) {
3181541Srgrimes		if (m == 0) {
3191541Srgrimes			if (len != M_COPYALL)
3201541Srgrimes				panic("m_copym");
3211541Srgrimes			break;
3221541Srgrimes		}
3231541Srgrimes		MGET(n, wait, m->m_type);
3241541Srgrimes		*np = n;
3251541Srgrimes		if (n == 0)
3261541Srgrimes			goto nospace;
3271541Srgrimes		if (copyhdr) {
3281541Srgrimes			M_COPY_PKTHDR(n, m);
3291541Srgrimes			if (len == M_COPYALL)
3301541Srgrimes				n->m_pkthdr.len -= off0;
3311541Srgrimes			else
3321541Srgrimes				n->m_pkthdr.len = len;
3331541Srgrimes			copyhdr = 0;
3341541Srgrimes		}
3351541Srgrimes		n->m_len = min(len, m->m_len - off);
3361541Srgrimes		if (m->m_flags & M_EXT) {
3371541Srgrimes			n->m_data = m->m_data + off;
3381541Srgrimes			mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
3391541Srgrimes			n->m_ext = m->m_ext;
3401541Srgrimes			n->m_flags |= M_EXT;
3411541Srgrimes		} else
3421541Srgrimes			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
3431541Srgrimes			    (unsigned)n->m_len);
3441541Srgrimes		if (len != M_COPYALL)
3451541Srgrimes			len -= n->m_len;
3461541Srgrimes		off = 0;
3471541Srgrimes		m = m->m_next;
3481541Srgrimes		np = &n->m_next;
3491541Srgrimes	}
3501541Srgrimes	if (top == 0)
3511541Srgrimes		MCFail++;
3521541Srgrimes	return (top);
3531541Srgrimesnospace:
3541541Srgrimes	m_freem(top);
3551541Srgrimes	MCFail++;
3561541Srgrimes	return (0);
3571541Srgrimes}
3581541Srgrimes
3591541Srgrimes/*
3601541Srgrimes * Copy data from an mbuf chain starting "off" bytes from the beginning,
3611541Srgrimes * continuing for "len" bytes, into the indicated buffer.
3621541Srgrimes */
3631549Srgrimesvoid
3641541Srgrimesm_copydata(m, off, len, cp)
3651541Srgrimes	register struct mbuf *m;
3661541Srgrimes	register int off;
3671541Srgrimes	register int len;
3681541Srgrimes	caddr_t cp;
3691541Srgrimes{
3701541Srgrimes	register unsigned count;
3711541Srgrimes
3721541Srgrimes	if (off < 0 || len < 0)
3731541Srgrimes		panic("m_copydata");
3741541Srgrimes	while (off > 0) {
3751541Srgrimes		if (m == 0)
3761541Srgrimes			panic("m_copydata");
3771541Srgrimes		if (off < m->m_len)
3781541Srgrimes			break;
3791541Srgrimes		off -= m->m_len;
3801541Srgrimes		m = m->m_next;
3811541Srgrimes	}
3821541Srgrimes	while (len > 0) {
3831541Srgrimes		if (m == 0)
3841541Srgrimes			panic("m_copydata");
3851541Srgrimes		count = min(m->m_len - off, len);
3861541Srgrimes		bcopy(mtod(m, caddr_t) + off, cp, count);
3871541Srgrimes		len -= count;
3881541Srgrimes		cp += count;
3891541Srgrimes		off = 0;
3901541Srgrimes		m = m->m_next;
3911541Srgrimes	}
3921541Srgrimes}
3931541Srgrimes
3941541Srgrimes/*
3951541Srgrimes * Concatenate mbuf chain n to m.
3961541Srgrimes * Both chains must be of the same type (e.g. MT_DATA).
3971541Srgrimes * Any m_pkthdr is not updated.
3981541Srgrimes */
3991549Srgrimesvoid
4001541Srgrimesm_cat(m, n)
4011541Srgrimes	register struct mbuf *m, *n;
4021541Srgrimes{
4031541Srgrimes	while (m->m_next)
4041541Srgrimes		m = m->m_next;
4051541Srgrimes	while (n) {
4061541Srgrimes		if (m->m_flags & M_EXT ||
4071541Srgrimes		    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
4081541Srgrimes			/* just join the two chains */
4091541Srgrimes			m->m_next = n;
4101541Srgrimes			return;
4111541Srgrimes		}
4121541Srgrimes		/* splat the data from one into the other */
4131541Srgrimes		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
4141541Srgrimes		    (u_int)n->m_len);
4151541Srgrimes		m->m_len += n->m_len;
4161541Srgrimes		n = m_free(n);
4171541Srgrimes	}
4181541Srgrimes}
4191541Srgrimes
4201549Srgrimesvoid
4211541Srgrimesm_adj(mp, req_len)
4221541Srgrimes	struct mbuf *mp;
4231541Srgrimes	int req_len;
4241541Srgrimes{
4251541Srgrimes	register int len = req_len;
4261541Srgrimes	register struct mbuf *m;
4271541Srgrimes	register count;
4281541Srgrimes
4291541Srgrimes	if ((m = mp) == NULL)
4301541Srgrimes		return;
4311541Srgrimes	if (len >= 0) {
4321541Srgrimes		/*
4331541Srgrimes		 * Trim from head.
4341541Srgrimes		 */
4351541Srgrimes		while (m != NULL && len > 0) {
4361541Srgrimes			if (m->m_len <= len) {
4371541Srgrimes				len -= m->m_len;
4381541Srgrimes				m->m_len = 0;
4391541Srgrimes				m = m->m_next;
4401541Srgrimes			} else {
4411541Srgrimes				m->m_len -= len;
4421541Srgrimes				m->m_data += len;
4431541Srgrimes				len = 0;
4441541Srgrimes			}
4451541Srgrimes		}
4461541Srgrimes		m = mp;
4471541Srgrimes		if (mp->m_flags & M_PKTHDR)
4481541Srgrimes			m->m_pkthdr.len -= (req_len - len);
4491541Srgrimes	} else {
4501541Srgrimes		/*
4511541Srgrimes		 * Trim from tail.  Scan the mbuf chain,
4521541Srgrimes		 * calculating its length and finding the last mbuf.
4531541Srgrimes		 * If the adjustment only affects this mbuf, then just
4541541Srgrimes		 * adjust and return.  Otherwise, rescan and truncate
4551541Srgrimes		 * after the remaining size.
4561541Srgrimes		 */
4571541Srgrimes		len = -len;
4581541Srgrimes		count = 0;
4591541Srgrimes		for (;;) {
4601541Srgrimes			count += m->m_len;
4611541Srgrimes			if (m->m_next == (struct mbuf *)0)
4621541Srgrimes				break;
4631541Srgrimes			m = m->m_next;
4641541Srgrimes		}
4651541Srgrimes		if (m->m_len >= len) {
4661541Srgrimes			m->m_len -= len;
4671541Srgrimes			if (mp->m_flags & M_PKTHDR)
4681541Srgrimes				mp->m_pkthdr.len -= len;
4691541Srgrimes			return;
4701541Srgrimes		}
4711541Srgrimes		count -= len;
4721541Srgrimes		if (count < 0)
4731541Srgrimes			count = 0;
4741541Srgrimes		/*
4751541Srgrimes		 * Correct length for chain is "count".
4761541Srgrimes		 * Find the mbuf with last data, adjust its length,
4771541Srgrimes		 * and toss data from remaining mbufs on chain.
4781541Srgrimes		 */
4791541Srgrimes		m = mp;
4801541Srgrimes		if (m->m_flags & M_PKTHDR)
4811541Srgrimes			m->m_pkthdr.len = count;
4821541Srgrimes		for (; m; m = m->m_next) {
4831541Srgrimes			if (m->m_len >= count) {
4841541Srgrimes				m->m_len = count;
4851541Srgrimes				break;
4861541Srgrimes			}
4871541Srgrimes			count -= m->m_len;
4881541Srgrimes		}
4893308Sphk		while (m->m_next)
4903308Sphk			(m = m->m_next) ->m_len = 0;
4911541Srgrimes	}
4921541Srgrimes}
4931541Srgrimes
4941541Srgrimes/*
4951541Srgrimes * Rearange an mbuf chain so that len bytes are contiguous
4961541Srgrimes * and in the data area of an mbuf (so that mtod and dtom
4971541Srgrimes * will work for a structure of size len).  Returns the resulting
4981541Srgrimes * mbuf chain on success, frees it and returns null on failure.
4991541Srgrimes * If there is room, it will add up to max_protohdr-len extra bytes to the
5001541Srgrimes * contiguous region in an attempt to avoid being called next time.
5011541Srgrimes */
5021541Srgrimesint MPFail;
5031541Srgrimes
5041541Srgrimesstruct mbuf *
5051541Srgrimesm_pullup(n, len)
5061541Srgrimes	register struct mbuf *n;
5071541Srgrimes	int len;
5081541Srgrimes{
5091541Srgrimes	register struct mbuf *m;
5101541Srgrimes	register int count;
5111541Srgrimes	int space;
5121541Srgrimes
5131541Srgrimes	/*
5141541Srgrimes	 * If first mbuf has no cluster, and has room for len bytes
5151541Srgrimes	 * without shifting current data, pullup into it,
5161541Srgrimes	 * otherwise allocate a new mbuf to prepend to the chain.
5171541Srgrimes	 */
5181541Srgrimes	if ((n->m_flags & M_EXT) == 0 &&
5191541Srgrimes	    n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
5201541Srgrimes		if (n->m_len >= len)
5211541Srgrimes			return (n);
5221541Srgrimes		m = n;
5231541Srgrimes		n = n->m_next;
5241541Srgrimes		len -= m->m_len;
5251541Srgrimes	} else {
5261541Srgrimes		if (len > MHLEN)
5271541Srgrimes			goto bad;
5281541Srgrimes		MGET(m, M_DONTWAIT, n->m_type);
5291541Srgrimes		if (m == 0)
5301541Srgrimes			goto bad;
5311541Srgrimes		m->m_len = 0;
5321541Srgrimes		if (n->m_flags & M_PKTHDR) {
5331541Srgrimes			M_COPY_PKTHDR(m, n);
5341541Srgrimes			n->m_flags &= ~M_PKTHDR;
5351541Srgrimes		}
5361541Srgrimes	}
5371541Srgrimes	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
5381541Srgrimes	do {
5391541Srgrimes		count = min(min(max(len, max_protohdr), space), n->m_len);
5401541Srgrimes		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
5411541Srgrimes		  (unsigned)count);
5421541Srgrimes		len -= count;
5431541Srgrimes		m->m_len += count;
5441541Srgrimes		n->m_len -= count;
5451541Srgrimes		space -= count;
5461541Srgrimes		if (n->m_len)
5471541Srgrimes			n->m_data += count;
5481541Srgrimes		else
5491541Srgrimes			n = m_free(n);
5501541Srgrimes	} while (len > 0 && n);
5511541Srgrimes	if (len > 0) {
5521541Srgrimes		(void) m_free(m);
5531541Srgrimes		goto bad;
5541541Srgrimes	}
5551541Srgrimes	m->m_next = n;
5561541Srgrimes	return (m);
5571541Srgrimesbad:
5581541Srgrimes	m_freem(n);
5591541Srgrimes	MPFail++;
5601541Srgrimes	return (0);
5611541Srgrimes}
5621541Srgrimes
5631541Srgrimes/*
5641541Srgrimes * Partition an mbuf chain in two pieces, returning the tail --
5651541Srgrimes * all but the first len0 bytes.  In case of failure, it returns NULL and
5661541Srgrimes * attempts to restore the chain to its original state.
5671541Srgrimes */
5681541Srgrimesstruct mbuf *
5691541Srgrimesm_split(m0, len0, wait)
5701541Srgrimes	register struct mbuf *m0;
5711541Srgrimes	int len0, wait;
5721541Srgrimes{
5731541Srgrimes	register struct mbuf *m, *n;
5741541Srgrimes	unsigned len = len0, remain;
5751541Srgrimes
5761541Srgrimes	for (m = m0; m && len > m->m_len; m = m->m_next)
5771541Srgrimes		len -= m->m_len;
5781541Srgrimes	if (m == 0)
5791541Srgrimes		return (0);
5801541Srgrimes	remain = m->m_len - len;
5811541Srgrimes	if (m0->m_flags & M_PKTHDR) {
5821541Srgrimes		MGETHDR(n, wait, m0->m_type);
5831541Srgrimes		if (n == 0)
5841541Srgrimes			return (0);
5851541Srgrimes		n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
5861541Srgrimes		n->m_pkthdr.len = m0->m_pkthdr.len - len0;
5871541Srgrimes		m0->m_pkthdr.len = len0;
5881541Srgrimes		if (m->m_flags & M_EXT)
5891541Srgrimes			goto extpacket;
5901541Srgrimes		if (remain > MHLEN) {
5911541Srgrimes			/* m can't be the lead packet */
5921541Srgrimes			MH_ALIGN(n, 0);
5931541Srgrimes			n->m_next = m_split(m, len, wait);
5941541Srgrimes			if (n->m_next == 0) {
5951541Srgrimes				(void) m_free(n);
5961541Srgrimes				return (0);
5971541Srgrimes			} else
5981541Srgrimes				return (n);
5991541Srgrimes		} else
6001541Srgrimes			MH_ALIGN(n, remain);
6011541Srgrimes	} else if (remain == 0) {
6021541Srgrimes		n = m->m_next;
6031541Srgrimes		m->m_next = 0;
6041541Srgrimes		return (n);
6051541Srgrimes	} else {
6061541Srgrimes		MGET(n, wait, m->m_type);
6071541Srgrimes		if (n == 0)
6081541Srgrimes			return (0);
6091541Srgrimes		M_ALIGN(n, remain);
6101541Srgrimes	}
6111541Srgrimesextpacket:
6121541Srgrimes	if (m->m_flags & M_EXT) {
6131541Srgrimes		n->m_flags |= M_EXT;
6141541Srgrimes		n->m_ext = m->m_ext;
6151541Srgrimes		mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
6161541Srgrimes		m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
6171541Srgrimes		n->m_data = m->m_data + len;
6181541Srgrimes	} else {
6191541Srgrimes		bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
6201541Srgrimes	}
6211541Srgrimes	n->m_len = remain;
6221541Srgrimes	m->m_len = len;
6231541Srgrimes	n->m_next = m->m_next;
6241541Srgrimes	m->m_next = 0;
6251541Srgrimes	return (n);
6261541Srgrimes}
6271541Srgrimes/*
6281541Srgrimes * Routine to copy from device local memory into mbufs.
6291541Srgrimes */
6301541Srgrimesstruct mbuf *
6311541Srgrimesm_devget(buf, totlen, off0, ifp, copy)
6321541Srgrimes	char *buf;
6331541Srgrimes	int totlen, off0;
6341541Srgrimes	struct ifnet *ifp;
6351541Srgrimes	void (*copy)();
6361541Srgrimes{
6371541Srgrimes	register struct mbuf *m;
6381541Srgrimes	struct mbuf *top = 0, **mp = &top;
6391541Srgrimes	register int off = off0, len;
6401541Srgrimes	register char *cp;
6411541Srgrimes	char *epkt;
6421541Srgrimes
6431541Srgrimes	cp = buf;
6441541Srgrimes	epkt = cp + totlen;
6451541Srgrimes	if (off) {
6461541Srgrimes		cp += off + 2 * sizeof(u_short);
6471541Srgrimes		totlen -= 2 * sizeof(u_short);
6481541Srgrimes	}
6491541Srgrimes	MGETHDR(m, M_DONTWAIT, MT_DATA);
6501541Srgrimes	if (m == 0)
6511541Srgrimes		return (0);
6521541Srgrimes	m->m_pkthdr.rcvif = ifp;
6531541Srgrimes	m->m_pkthdr.len = totlen;
6541541Srgrimes	m->m_len = MHLEN;
6551541Srgrimes
6561541Srgrimes	while (totlen > 0) {
6571541Srgrimes		if (top) {
6581541Srgrimes			MGET(m, M_DONTWAIT, MT_DATA);
6591541Srgrimes			if (m == 0) {
6601541Srgrimes				m_freem(top);
6611541Srgrimes				return (0);
6621541Srgrimes			}
6631541Srgrimes			m->m_len = MLEN;
6641541Srgrimes		}
6651541Srgrimes		len = min(totlen, epkt - cp);
6661541Srgrimes		if (len >= MINCLSIZE) {
6671541Srgrimes			MCLGET(m, M_DONTWAIT);
6681541Srgrimes			if (m->m_flags & M_EXT)
6691541Srgrimes				m->m_len = len = min(len, MCLBYTES);
6701541Srgrimes			else
6711541Srgrimes				len = m->m_len;
6721541Srgrimes		} else {
6731541Srgrimes			/*
6741541Srgrimes			 * Place initial small packet/header at end of mbuf.
6751541Srgrimes			 */
6761541Srgrimes			if (len < m->m_len) {
6771541Srgrimes				if (top == 0 && len + max_linkhdr <= m->m_len)
6781541Srgrimes					m->m_data += max_linkhdr;
6791541Srgrimes				m->m_len = len;
6801541Srgrimes			} else
6811541Srgrimes				len = m->m_len;
6821541Srgrimes		}
6831541Srgrimes		if (copy)
6841541Srgrimes			copy(cp, mtod(m, caddr_t), (unsigned)len);
6851541Srgrimes		else
6861541Srgrimes			bcopy(cp, mtod(m, caddr_t), (unsigned)len);
6871541Srgrimes		cp += len;
6881541Srgrimes		*mp = m;
6891541Srgrimes		mp = &m->m_next;
6901541Srgrimes		totlen -= len;
6911541Srgrimes		if (cp == epkt)
6921541Srgrimes			cp = buf;
6931541Srgrimes	}
6941541Srgrimes	return (top);
6951541Srgrimes}
6963352Sphk
6973352Sphk/*
6983352Sphk * Copy data from a buffer back into the indicated mbuf chain,
6993352Sphk * starting "off" bytes from the beginning, extending the mbuf
7003352Sphk * chain if necessary.
7013352Sphk */
7023352Sphkvoid
7033352Sphkm_copyback(m0, off, len, cp)
7043352Sphk	struct	mbuf *m0;
7053352Sphk	register int off;
7063352Sphk	register int len;
7073352Sphk	caddr_t cp;
7083352Sphk{
7093352Sphk	register int mlen;
7103352Sphk	register struct mbuf *m = m0, *n;
7113352Sphk	int totlen = 0;
7123352Sphk
7133352Sphk	if (m0 == 0)
7143352Sphk		return;
7153352Sphk	while (off > (mlen = m->m_len)) {
7163352Sphk		off -= mlen;
7173352Sphk		totlen += mlen;
7183352Sphk		if (m->m_next == 0) {
7193352Sphk			n = m_getclr(M_DONTWAIT, m->m_type);
7203352Sphk			if (n == 0)
7213352Sphk				goto out;
7223352Sphk			n->m_len = min(MLEN, len + off);
7233352Sphk			m->m_next = n;
7243352Sphk		}
7253352Sphk		m = m->m_next;
7263352Sphk	}
7273352Sphk	while (len > 0) {
7283352Sphk		mlen = min (m->m_len - off, len);
7293352Sphk		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
7303352Sphk		cp += mlen;
7313352Sphk		len -= mlen;
7323352Sphk		mlen += off;
7333352Sphk		off = 0;
7343352Sphk		totlen += mlen;
7353352Sphk		if (len == 0)
7363352Sphk			break;
7373352Sphk		if (m->m_next == 0) {
7383352Sphk			n = m_get(M_DONTWAIT, m->m_type);
7393352Sphk			if (n == 0)
7403352Sphk				break;
7413352Sphk			n->m_len = min(MLEN, len);
7423352Sphk			m->m_next = n;
7433352Sphk		}
7443352Sphk		m = m->m_next;
7453352Sphk	}
7463352Sphkout:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
7473352Sphk		m->m_pkthdr.len = totlen;
7483352Sphk}
749