uipc_mbuf.c revision 3352
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
343352Sphk * $Id: uipc_mbuf.c,v 1.4 1994/10/02 17:35:31 phk Exp $
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include <sys/param.h>
381541Srgrimes#include <sys/systm.h>
391541Srgrimes#include <sys/proc.h>
401541Srgrimes#include <sys/malloc.h>
411541Srgrimes#include <sys/map.h>
421541Srgrimes#define MBTYPES
431541Srgrimes#include <sys/mbuf.h>
441541Srgrimes#include <sys/kernel.h>
451541Srgrimes#include <sys/syslog.h>
461541Srgrimes#include <sys/domain.h>
471541Srgrimes#include <sys/protosw.h>
481541Srgrimes
491541Srgrimes#include <vm/vm.h>
501541Srgrimes
511541Srgrimesextern	vm_map_t mb_map;
521541Srgrimesstruct	mbuf *mbutl;
531541Srgrimeschar	*mclrefcnt;
541541Srgrimes
551549Srgrimesvoid
561541Srgrimesmbinit()
571541Srgrimes{
581541Srgrimes	int s;
591541Srgrimes
601541Srgrimes#if CLBYTES < 4096
611541Srgrimes#define NCL_INIT	(4096/CLBYTES)
621541Srgrimes#else
631541Srgrimes#define NCL_INIT	1
641541Srgrimes#endif
651541Srgrimes	s = splimp();
661541Srgrimes	if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
671541Srgrimes		goto bad;
681541Srgrimes	splx(s);
691541Srgrimes	return;
701541Srgrimesbad:
711541Srgrimes	panic("mbinit");
721541Srgrimes}
731541Srgrimes
741541Srgrimes/*
751541Srgrimes * Allocate some number of mbuf clusters
761541Srgrimes * and place on cluster free list.
771541Srgrimes * Must be called at splimp.
781541Srgrimes */
791541Srgrimes/* ARGSUSED */
801549Srgrimesint
811541Srgrimesm_clalloc(ncl, nowait)
821541Srgrimes	register int ncl;
831541Srgrimes	int nowait;
841541Srgrimes{
851541Srgrimes	static int logged;
861541Srgrimes	register caddr_t p;
871541Srgrimes	register int i;
881541Srgrimes	int npg;
891541Srgrimes
901541Srgrimes	npg = ncl * CLSIZE;
911541Srgrimes	p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !nowait);
921541Srgrimes	if (p == NULL) {
931541Srgrimes		if (logged == 0) {
941541Srgrimes			logged++;
951541Srgrimes			log(LOG_ERR, "mb_map full\n");
961541Srgrimes		}
971541Srgrimes		return (0);
981541Srgrimes	}
991541Srgrimes	ncl = ncl * CLBYTES / MCLBYTES;
1001541Srgrimes	for (i = 0; i < ncl; i++) {
1011541Srgrimes		((union mcluster *)p)->mcl_next = mclfree;
1021541Srgrimes		mclfree = (union mcluster *)p;
1031541Srgrimes		p += MCLBYTES;
1041541Srgrimes		mbstat.m_clfree++;
1051541Srgrimes	}
1061541Srgrimes	mbstat.m_clusters += ncl;
1071541Srgrimes	return (1);
1081541Srgrimes}
1091541Srgrimes
1101541Srgrimes/*
1111541Srgrimes * When MGET failes, ask protocols to free space when short of memory,
1121541Srgrimes * then re-attempt to allocate an mbuf.
1131541Srgrimes */
1141541Srgrimesstruct mbuf *
1151541Srgrimesm_retry(i, t)
1161541Srgrimes	int i, t;
1171541Srgrimes{
1181541Srgrimes	register struct mbuf *m;
1191541Srgrimes
1201541Srgrimes	m_reclaim();
1211541Srgrimes#define m_retry(i, t)	(struct mbuf *)0
1221541Srgrimes	MGET(m, i, t);
1231541Srgrimes#undef m_retry
1241541Srgrimes	return (m);
1251541Srgrimes}
1261541Srgrimes
1271541Srgrimes/*
1281541Srgrimes * As above; retry an MGETHDR.
1291541Srgrimes */
1301541Srgrimesstruct mbuf *
1311541Srgrimesm_retryhdr(i, t)
1321541Srgrimes	int i, t;
1331541Srgrimes{
1341541Srgrimes	register struct mbuf *m;
1351541Srgrimes
1361541Srgrimes	m_reclaim();
1371541Srgrimes#define m_retryhdr(i, t) (struct mbuf *)0
1381541Srgrimes	MGETHDR(m, i, t);
1391541Srgrimes#undef m_retryhdr
1401541Srgrimes	return (m);
1411541Srgrimes}
1421541Srgrimes
1431549Srgrimesvoid
1441541Srgrimesm_reclaim()
1451541Srgrimes{
1461541Srgrimes	register struct domain *dp;
1471541Srgrimes	register struct protosw *pr;
1481541Srgrimes	int s = splimp();
1491541Srgrimes
1501541Srgrimes	for (dp = domains; dp; dp = dp->dom_next)
1511541Srgrimes		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
1521541Srgrimes			if (pr->pr_drain)
1531541Srgrimes				(*pr->pr_drain)();
1541541Srgrimes	splx(s);
1551541Srgrimes	mbstat.m_drain++;
1561541Srgrimes}
1571541Srgrimes
1581541Srgrimes/*
1591541Srgrimes * Space allocation routines.
1601541Srgrimes * These are also available as macros
1611541Srgrimes * for critical paths.
1621541Srgrimes */
1631541Srgrimesstruct mbuf *
1641541Srgrimesm_get(nowait, type)
1651541Srgrimes	int nowait, type;
1661541Srgrimes{
1671541Srgrimes	register struct mbuf *m;
1681541Srgrimes
1691541Srgrimes	MGET(m, nowait, type);
1701541Srgrimes	return (m);
1711541Srgrimes}
1721541Srgrimes
1731541Srgrimesstruct mbuf *
1741541Srgrimesm_gethdr(nowait, type)
1751541Srgrimes	int nowait, type;
1761541Srgrimes{
1771541Srgrimes	register struct mbuf *m;
1781541Srgrimes
1791541Srgrimes	MGETHDR(m, nowait, type);
1801541Srgrimes	return (m);
1811541Srgrimes}
1821541Srgrimes
1831541Srgrimesstruct mbuf *
1841541Srgrimesm_getclr(nowait, type)
1851541Srgrimes	int nowait, type;
1861541Srgrimes{
1871541Srgrimes	register struct mbuf *m;
1881541Srgrimes
1891541Srgrimes	MGET(m, nowait, type);
1901541Srgrimes	if (m == 0)
1911541Srgrimes		return (0);
1921541Srgrimes	bzero(mtod(m, caddr_t), MLEN);
1931541Srgrimes	return (m);
1941541Srgrimes}
1951541Srgrimes
1961541Srgrimesstruct mbuf *
1971541Srgrimesm_free(m)
1981541Srgrimes	struct mbuf *m;
1991541Srgrimes{
2001541Srgrimes	register struct mbuf *n;
2011541Srgrimes
2021541Srgrimes	MFREE(m, n);
2031541Srgrimes	return (n);
2041541Srgrimes}
2051541Srgrimes
2061541Srgrimesvoid
2071541Srgrimesm_freem(m)
2081541Srgrimes	register struct mbuf *m;
2091541Srgrimes{
2101541Srgrimes	register struct mbuf *n;
2111541Srgrimes
2121541Srgrimes	if (m == NULL)
2131541Srgrimes		return;
2141541Srgrimes	do {
2151541Srgrimes		MFREE(m, n);
2163308Sphk		m = n;
2173308Sphk	} while (m);
2181541Srgrimes}
2191541Srgrimes
2201541Srgrimes/*
2211541Srgrimes * Mbuffer utility routines.
2221541Srgrimes */
2231541Srgrimes
2241541Srgrimes/*
2251541Srgrimes * Lesser-used path for M_PREPEND:
2261541Srgrimes * allocate new mbuf to prepend to chain,
2271541Srgrimes * copy junk along.
2281541Srgrimes */
2291541Srgrimesstruct mbuf *
2301541Srgrimesm_prepend(m, len, how)
2311541Srgrimes	register struct mbuf *m;
2321541Srgrimes	int len, how;
2331541Srgrimes{
2341541Srgrimes	struct mbuf *mn;
2351541Srgrimes
2361541Srgrimes	MGET(mn, how, m->m_type);
2371541Srgrimes	if (mn == (struct mbuf *)NULL) {
2381541Srgrimes		m_freem(m);
2391541Srgrimes		return ((struct mbuf *)NULL);
2401541Srgrimes	}
2411541Srgrimes	if (m->m_flags & M_PKTHDR) {
2421541Srgrimes		M_COPY_PKTHDR(mn, m);
2431541Srgrimes		m->m_flags &= ~M_PKTHDR;
2441541Srgrimes	}
2451541Srgrimes	mn->m_next = m;
2461541Srgrimes	m = mn;
2471541Srgrimes	if (len < MHLEN)
2481541Srgrimes		MH_ALIGN(m, len);
2491541Srgrimes	m->m_len = len;
2501541Srgrimes	return (m);
2511541Srgrimes}
2521541Srgrimes
2531541Srgrimes/*
2541541Srgrimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
2551541Srgrimes * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
2561541Srgrimes * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
2571541Srgrimes */
2581541Srgrimesint MCFail;
2591541Srgrimes
2601541Srgrimesstruct mbuf *
2611541Srgrimesm_copym(m, off0, len, wait)
2621541Srgrimes	register struct mbuf *m;
2631541Srgrimes	int off0, wait;
2641541Srgrimes	register int len;
2651541Srgrimes{
2661541Srgrimes	register struct mbuf *n, **np;
2671541Srgrimes	register int off = off0;
2681541Srgrimes	struct mbuf *top;
2691541Srgrimes	int copyhdr = 0;
2701541Srgrimes
2711541Srgrimes	if (off < 0 || len < 0)
2721541Srgrimes		panic("m_copym");
2731541Srgrimes	if (off == 0 && m->m_flags & M_PKTHDR)
2741541Srgrimes		copyhdr = 1;
2751541Srgrimes	while (off > 0) {
2761541Srgrimes		if (m == 0)
2771541Srgrimes			panic("m_copym");
2781541Srgrimes		if (off < m->m_len)
2791541Srgrimes			break;
2801541Srgrimes		off -= m->m_len;
2811541Srgrimes		m = m->m_next;
2821541Srgrimes	}
2831541Srgrimes	np = &top;
2841541Srgrimes	top = 0;
2851541Srgrimes	while (len > 0) {
2861541Srgrimes		if (m == 0) {
2871541Srgrimes			if (len != M_COPYALL)
2881541Srgrimes				panic("m_copym");
2891541Srgrimes			break;
2901541Srgrimes		}
2911541Srgrimes		MGET(n, wait, m->m_type);
2921541Srgrimes		*np = n;
2931541Srgrimes		if (n == 0)
2941541Srgrimes			goto nospace;
2951541Srgrimes		if (copyhdr) {
2961541Srgrimes			M_COPY_PKTHDR(n, m);
2971541Srgrimes			if (len == M_COPYALL)
2981541Srgrimes				n->m_pkthdr.len -= off0;
2991541Srgrimes			else
3001541Srgrimes				n->m_pkthdr.len = len;
3011541Srgrimes			copyhdr = 0;
3021541Srgrimes		}
3031541Srgrimes		n->m_len = min(len, m->m_len - off);
3041541Srgrimes		if (m->m_flags & M_EXT) {
3051541Srgrimes			n->m_data = m->m_data + off;
3061541Srgrimes			mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
3071541Srgrimes			n->m_ext = m->m_ext;
3081541Srgrimes			n->m_flags |= M_EXT;
3091541Srgrimes		} else
3101541Srgrimes			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
3111541Srgrimes			    (unsigned)n->m_len);
3121541Srgrimes		if (len != M_COPYALL)
3131541Srgrimes			len -= n->m_len;
3141541Srgrimes		off = 0;
3151541Srgrimes		m = m->m_next;
3161541Srgrimes		np = &n->m_next;
3171541Srgrimes	}
3181541Srgrimes	if (top == 0)
3191541Srgrimes		MCFail++;
3201541Srgrimes	return (top);
3211541Srgrimesnospace:
3221541Srgrimes	m_freem(top);
3231541Srgrimes	MCFail++;
3241541Srgrimes	return (0);
3251541Srgrimes}
3261541Srgrimes
3271541Srgrimes/*
3281541Srgrimes * Copy data from an mbuf chain starting "off" bytes from the beginning,
3291541Srgrimes * continuing for "len" bytes, into the indicated buffer.
3301541Srgrimes */
3311549Srgrimesvoid
3321541Srgrimesm_copydata(m, off, len, cp)
3331541Srgrimes	register struct mbuf *m;
3341541Srgrimes	register int off;
3351541Srgrimes	register int len;
3361541Srgrimes	caddr_t cp;
3371541Srgrimes{
3381541Srgrimes	register unsigned count;
3391541Srgrimes
3401541Srgrimes	if (off < 0 || len < 0)
3411541Srgrimes		panic("m_copydata");
3421541Srgrimes	while (off > 0) {
3431541Srgrimes		if (m == 0)
3441541Srgrimes			panic("m_copydata");
3451541Srgrimes		if (off < m->m_len)
3461541Srgrimes			break;
3471541Srgrimes		off -= m->m_len;
3481541Srgrimes		m = m->m_next;
3491541Srgrimes	}
3501541Srgrimes	while (len > 0) {
3511541Srgrimes		if (m == 0)
3521541Srgrimes			panic("m_copydata");
3531541Srgrimes		count = min(m->m_len - off, len);
3541541Srgrimes		bcopy(mtod(m, caddr_t) + off, cp, count);
3551541Srgrimes		len -= count;
3561541Srgrimes		cp += count;
3571541Srgrimes		off = 0;
3581541Srgrimes		m = m->m_next;
3591541Srgrimes	}
3601541Srgrimes}
3611541Srgrimes
3621541Srgrimes/*
3631541Srgrimes * Concatenate mbuf chain n to m.
3641541Srgrimes * Both chains must be of the same type (e.g. MT_DATA).
3651541Srgrimes * Any m_pkthdr is not updated.
3661541Srgrimes */
3671549Srgrimesvoid
3681541Srgrimesm_cat(m, n)
3691541Srgrimes	register struct mbuf *m, *n;
3701541Srgrimes{
3711541Srgrimes	while (m->m_next)
3721541Srgrimes		m = m->m_next;
3731541Srgrimes	while (n) {
3741541Srgrimes		if (m->m_flags & M_EXT ||
3751541Srgrimes		    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
3761541Srgrimes			/* just join the two chains */
3771541Srgrimes			m->m_next = n;
3781541Srgrimes			return;
3791541Srgrimes		}
3801541Srgrimes		/* splat the data from one into the other */
3811541Srgrimes		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
3821541Srgrimes		    (u_int)n->m_len);
3831541Srgrimes		m->m_len += n->m_len;
3841541Srgrimes		n = m_free(n);
3851541Srgrimes	}
3861541Srgrimes}
3871541Srgrimes
3881549Srgrimesvoid
3891541Srgrimesm_adj(mp, req_len)
3901541Srgrimes	struct mbuf *mp;
3911541Srgrimes	int req_len;
3921541Srgrimes{
3931541Srgrimes	register int len = req_len;
3941541Srgrimes	register struct mbuf *m;
3951541Srgrimes	register count;
3961541Srgrimes
3971541Srgrimes	if ((m = mp) == NULL)
3981541Srgrimes		return;
3991541Srgrimes	if (len >= 0) {
4001541Srgrimes		/*
4011541Srgrimes		 * Trim from head.
4021541Srgrimes		 */
4031541Srgrimes		while (m != NULL && len > 0) {
4041541Srgrimes			if (m->m_len <= len) {
4051541Srgrimes				len -= m->m_len;
4061541Srgrimes				m->m_len = 0;
4071541Srgrimes				m = m->m_next;
4081541Srgrimes			} else {
4091541Srgrimes				m->m_len -= len;
4101541Srgrimes				m->m_data += len;
4111541Srgrimes				len = 0;
4121541Srgrimes			}
4131541Srgrimes		}
4141541Srgrimes		m = mp;
4151541Srgrimes		if (mp->m_flags & M_PKTHDR)
4161541Srgrimes			m->m_pkthdr.len -= (req_len - len);
4171541Srgrimes	} else {
4181541Srgrimes		/*
4191541Srgrimes		 * Trim from tail.  Scan the mbuf chain,
4201541Srgrimes		 * calculating its length and finding the last mbuf.
4211541Srgrimes		 * If the adjustment only affects this mbuf, then just
4221541Srgrimes		 * adjust and return.  Otherwise, rescan and truncate
4231541Srgrimes		 * after the remaining size.
4241541Srgrimes		 */
4251541Srgrimes		len = -len;
4261541Srgrimes		count = 0;
4271541Srgrimes		for (;;) {
4281541Srgrimes			count += m->m_len;
4291541Srgrimes			if (m->m_next == (struct mbuf *)0)
4301541Srgrimes				break;
4311541Srgrimes			m = m->m_next;
4321541Srgrimes		}
4331541Srgrimes		if (m->m_len >= len) {
4341541Srgrimes			m->m_len -= len;
4351541Srgrimes			if (mp->m_flags & M_PKTHDR)
4361541Srgrimes				mp->m_pkthdr.len -= len;
4371541Srgrimes			return;
4381541Srgrimes		}
4391541Srgrimes		count -= len;
4401541Srgrimes		if (count < 0)
4411541Srgrimes			count = 0;
4421541Srgrimes		/*
4431541Srgrimes		 * Correct length for chain is "count".
4441541Srgrimes		 * Find the mbuf with last data, adjust its length,
4451541Srgrimes		 * and toss data from remaining mbufs on chain.
4461541Srgrimes		 */
4471541Srgrimes		m = mp;
4481541Srgrimes		if (m->m_flags & M_PKTHDR)
4491541Srgrimes			m->m_pkthdr.len = count;
4501541Srgrimes		for (; m; m = m->m_next) {
4511541Srgrimes			if (m->m_len >= count) {
4521541Srgrimes				m->m_len = count;
4531541Srgrimes				break;
4541541Srgrimes			}
4551541Srgrimes			count -= m->m_len;
4561541Srgrimes		}
4573308Sphk		while (m->m_next)
4583308Sphk			(m = m->m_next) ->m_len = 0;
4591541Srgrimes	}
4601541Srgrimes}
4611541Srgrimes
4621541Srgrimes/*
4631541Srgrimes * Rearange an mbuf chain so that len bytes are contiguous
4641541Srgrimes * and in the data area of an mbuf (so that mtod and dtom
4651541Srgrimes * will work for a structure of size len).  Returns the resulting
4661541Srgrimes * mbuf chain on success, frees it and returns null on failure.
4671541Srgrimes * If there is room, it will add up to max_protohdr-len extra bytes to the
4681541Srgrimes * contiguous region in an attempt to avoid being called next time.
4691541Srgrimes */
4701541Srgrimesint MPFail;
4711541Srgrimes
4721541Srgrimesstruct mbuf *
4731541Srgrimesm_pullup(n, len)
4741541Srgrimes	register struct mbuf *n;
4751541Srgrimes	int len;
4761541Srgrimes{
4771541Srgrimes	register struct mbuf *m;
4781541Srgrimes	register int count;
4791541Srgrimes	int space;
4801541Srgrimes
4811541Srgrimes	/*
4821541Srgrimes	 * If first mbuf has no cluster, and has room for len bytes
4831541Srgrimes	 * without shifting current data, pullup into it,
4841541Srgrimes	 * otherwise allocate a new mbuf to prepend to the chain.
4851541Srgrimes	 */
4861541Srgrimes	if ((n->m_flags & M_EXT) == 0 &&
4871541Srgrimes	    n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
4881541Srgrimes		if (n->m_len >= len)
4891541Srgrimes			return (n);
4901541Srgrimes		m = n;
4911541Srgrimes		n = n->m_next;
4921541Srgrimes		len -= m->m_len;
4931541Srgrimes	} else {
4941541Srgrimes		if (len > MHLEN)
4951541Srgrimes			goto bad;
4961541Srgrimes		MGET(m, M_DONTWAIT, n->m_type);
4971541Srgrimes		if (m == 0)
4981541Srgrimes			goto bad;
4991541Srgrimes		m->m_len = 0;
5001541Srgrimes		if (n->m_flags & M_PKTHDR) {
5011541Srgrimes			M_COPY_PKTHDR(m, n);
5021541Srgrimes			n->m_flags &= ~M_PKTHDR;
5031541Srgrimes		}
5041541Srgrimes	}
5051541Srgrimes	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
5061541Srgrimes	do {
5071541Srgrimes		count = min(min(max(len, max_protohdr), space), n->m_len);
5081541Srgrimes		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
5091541Srgrimes		  (unsigned)count);
5101541Srgrimes		len -= count;
5111541Srgrimes		m->m_len += count;
5121541Srgrimes		n->m_len -= count;
5131541Srgrimes		space -= count;
5141541Srgrimes		if (n->m_len)
5151541Srgrimes			n->m_data += count;
5161541Srgrimes		else
5171541Srgrimes			n = m_free(n);
5181541Srgrimes	} while (len > 0 && n);
5191541Srgrimes	if (len > 0) {
5201541Srgrimes		(void) m_free(m);
5211541Srgrimes		goto bad;
5221541Srgrimes	}
5231541Srgrimes	m->m_next = n;
5241541Srgrimes	return (m);
5251541Srgrimesbad:
5261541Srgrimes	m_freem(n);
5271541Srgrimes	MPFail++;
5281541Srgrimes	return (0);
5291541Srgrimes}
5301541Srgrimes
5311541Srgrimes/*
5321541Srgrimes * Partition an mbuf chain in two pieces, returning the tail --
5331541Srgrimes * all but the first len0 bytes.  In case of failure, it returns NULL and
5341541Srgrimes * attempts to restore the chain to its original state.
5351541Srgrimes */
5361541Srgrimesstruct mbuf *
5371541Srgrimesm_split(m0, len0, wait)
5381541Srgrimes	register struct mbuf *m0;
5391541Srgrimes	int len0, wait;
5401541Srgrimes{
5411541Srgrimes	register struct mbuf *m, *n;
5421541Srgrimes	unsigned len = len0, remain;
5431541Srgrimes
5441541Srgrimes	for (m = m0; m && len > m->m_len; m = m->m_next)
5451541Srgrimes		len -= m->m_len;
5461541Srgrimes	if (m == 0)
5471541Srgrimes		return (0);
5481541Srgrimes	remain = m->m_len - len;
5491541Srgrimes	if (m0->m_flags & M_PKTHDR) {
5501541Srgrimes		MGETHDR(n, wait, m0->m_type);
5511541Srgrimes		if (n == 0)
5521541Srgrimes			return (0);
5531541Srgrimes		n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
5541541Srgrimes		n->m_pkthdr.len = m0->m_pkthdr.len - len0;
5551541Srgrimes		m0->m_pkthdr.len = len0;
5561541Srgrimes		if (m->m_flags & M_EXT)
5571541Srgrimes			goto extpacket;
5581541Srgrimes		if (remain > MHLEN) {
5591541Srgrimes			/* m can't be the lead packet */
5601541Srgrimes			MH_ALIGN(n, 0);
5611541Srgrimes			n->m_next = m_split(m, len, wait);
5621541Srgrimes			if (n->m_next == 0) {
5631541Srgrimes				(void) m_free(n);
5641541Srgrimes				return (0);
5651541Srgrimes			} else
5661541Srgrimes				return (n);
5671541Srgrimes		} else
5681541Srgrimes			MH_ALIGN(n, remain);
5691541Srgrimes	} else if (remain == 0) {
5701541Srgrimes		n = m->m_next;
5711541Srgrimes		m->m_next = 0;
5721541Srgrimes		return (n);
5731541Srgrimes	} else {
5741541Srgrimes		MGET(n, wait, m->m_type);
5751541Srgrimes		if (n == 0)
5761541Srgrimes			return (0);
5771541Srgrimes		M_ALIGN(n, remain);
5781541Srgrimes	}
5791541Srgrimesextpacket:
5801541Srgrimes	if (m->m_flags & M_EXT) {
5811541Srgrimes		n->m_flags |= M_EXT;
5821541Srgrimes		n->m_ext = m->m_ext;
5831541Srgrimes		mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
5841541Srgrimes		m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
5851541Srgrimes		n->m_data = m->m_data + len;
5861541Srgrimes	} else {
5871541Srgrimes		bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
5881541Srgrimes	}
5891541Srgrimes	n->m_len = remain;
5901541Srgrimes	m->m_len = len;
5911541Srgrimes	n->m_next = m->m_next;
5921541Srgrimes	m->m_next = 0;
5931541Srgrimes	return (n);
5941541Srgrimes}
5951541Srgrimes/*
5961541Srgrimes * Routine to copy from device local memory into mbufs.
5971541Srgrimes */
5981541Srgrimesstruct mbuf *
5991541Srgrimesm_devget(buf, totlen, off0, ifp, copy)
6001541Srgrimes	char *buf;
6011541Srgrimes	int totlen, off0;
6021541Srgrimes	struct ifnet *ifp;
6031541Srgrimes	void (*copy)();
6041541Srgrimes{
6051541Srgrimes	register struct mbuf *m;
6061541Srgrimes	struct mbuf *top = 0, **mp = &top;
6071541Srgrimes	register int off = off0, len;
6081541Srgrimes	register char *cp;
6091541Srgrimes	char *epkt;
6101541Srgrimes
6111541Srgrimes	cp = buf;
6121541Srgrimes	epkt = cp + totlen;
6131541Srgrimes	if (off) {
6141541Srgrimes		cp += off + 2 * sizeof(u_short);
6151541Srgrimes		totlen -= 2 * sizeof(u_short);
6161541Srgrimes	}
6171541Srgrimes	MGETHDR(m, M_DONTWAIT, MT_DATA);
6181541Srgrimes	if (m == 0)
6191541Srgrimes		return (0);
6201541Srgrimes	m->m_pkthdr.rcvif = ifp;
6211541Srgrimes	m->m_pkthdr.len = totlen;
6221541Srgrimes	m->m_len = MHLEN;
6231541Srgrimes
6241541Srgrimes	while (totlen > 0) {
6251541Srgrimes		if (top) {
6261541Srgrimes			MGET(m, M_DONTWAIT, MT_DATA);
6271541Srgrimes			if (m == 0) {
6281541Srgrimes				m_freem(top);
6291541Srgrimes				return (0);
6301541Srgrimes			}
6311541Srgrimes			m->m_len = MLEN;
6321541Srgrimes		}
6331541Srgrimes		len = min(totlen, epkt - cp);
6341541Srgrimes		if (len >= MINCLSIZE) {
6351541Srgrimes			MCLGET(m, M_DONTWAIT);
6361541Srgrimes			if (m->m_flags & M_EXT)
6371541Srgrimes				m->m_len = len = min(len, MCLBYTES);
6381541Srgrimes			else
6391541Srgrimes				len = m->m_len;
6401541Srgrimes		} else {
6411541Srgrimes			/*
6421541Srgrimes			 * Place initial small packet/header at end of mbuf.
6431541Srgrimes			 */
6441541Srgrimes			if (len < m->m_len) {
6451541Srgrimes				if (top == 0 && len + max_linkhdr <= m->m_len)
6461541Srgrimes					m->m_data += max_linkhdr;
6471541Srgrimes				m->m_len = len;
6481541Srgrimes			} else
6491541Srgrimes				len = m->m_len;
6501541Srgrimes		}
6511541Srgrimes		if (copy)
6521541Srgrimes			copy(cp, mtod(m, caddr_t), (unsigned)len);
6531541Srgrimes		else
6541541Srgrimes			bcopy(cp, mtod(m, caddr_t), (unsigned)len);
6551541Srgrimes		cp += len;
6561541Srgrimes		*mp = m;
6571541Srgrimes		mp = &m->m_next;
6581541Srgrimes		totlen -= len;
6591541Srgrimes		if (cp == epkt)
6601541Srgrimes			cp = buf;
6611541Srgrimes	}
6621541Srgrimes	return (top);
6631541Srgrimes}
6643352Sphk
6653352Sphk/*
6663352Sphk * Copy data from a buffer back into the indicated mbuf chain,
6673352Sphk * starting "off" bytes from the beginning, extending the mbuf
6683352Sphk * chain if necessary.
6693352Sphk */
6703352Sphkvoid
6713352Sphkm_copyback(m0, off, len, cp)
6723352Sphk	struct	mbuf *m0;
6733352Sphk	register int off;
6743352Sphk	register int len;
6753352Sphk	caddr_t cp;
6763352Sphk{
6773352Sphk	register int mlen;
6783352Sphk	register struct mbuf *m = m0, *n;
6793352Sphk	int totlen = 0;
6803352Sphk
6813352Sphk	if (m0 == 0)
6823352Sphk		return;
6833352Sphk	while (off > (mlen = m->m_len)) {
6843352Sphk		off -= mlen;
6853352Sphk		totlen += mlen;
6863352Sphk		if (m->m_next == 0) {
6873352Sphk			n = m_getclr(M_DONTWAIT, m->m_type);
6883352Sphk			if (n == 0)
6893352Sphk				goto out;
6903352Sphk			n->m_len = min(MLEN, len + off);
6913352Sphk			m->m_next = n;
6923352Sphk		}
6933352Sphk		m = m->m_next;
6943352Sphk	}
6953352Sphk	while (len > 0) {
6963352Sphk		mlen = min (m->m_len - off, len);
6973352Sphk		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
6983352Sphk		cp += mlen;
6993352Sphk		len -= mlen;
7003352Sphk		mlen += off;
7013352Sphk		off = 0;
7023352Sphk		totlen += mlen;
7033352Sphk		if (len == 0)
7043352Sphk			break;
7053352Sphk		if (m->m_next == 0) {
7063352Sphk			n = m_get(M_DONTWAIT, m->m_type);
7073352Sphk			if (n == 0)
7083352Sphk				break;
7093352Sphk			n->m_len = min(MLEN, len);
7103352Sphk			m->m_next = n;
7113352Sphk		}
7123352Sphk		m = m->m_next;
7133352Sphk	}
7143352Sphkout:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
7153352Sphk		m->m_pkthdr.len = totlen;
7163352Sphk}
717