Home | History | Annotate | Line # | Download | only in kern
uipc_mbuf.c revision 1.11
      1 /*	$NetBSD: uipc_mbuf.c,v 1.11 1994/09/19 08:07:17 mycroft Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1988, 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
     36  */
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/proc.h>
     41 #include <sys/malloc.h>
     42 #include <sys/map.h>
     43 #define MBTYPES
     44 #include <sys/mbuf.h>
     45 #include <sys/kernel.h>
     46 #include <sys/syslog.h>
     47 #include <sys/domain.h>
     48 #include <sys/protosw.h>
     49 
     50 #include <vm/vm.h>
     51 
     52 extern	vm_map_t mb_map;
     53 struct	mbuf *mbutl;
     54 char	*mclrefcnt;
     55 
     56 void
     57 mbinit()
     58 {
     59 	int s;
     60 
     61 #if CLBYTES < 4096
     62 #define NCL_INIT	(4096/CLBYTES)
     63 #else
     64 #define NCL_INIT	1
     65 #endif
     66 	s = splimp();
     67 	if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
     68 		goto bad;
     69 	splx(s);
     70 	return;
     71 bad:
     72 	panic("mbinit");
     73 }
     74 
     75 /*
     76  * Allocate some number of mbuf clusters
     77  * and place on cluster free list.
     78  * Must be called at splimp.
     79  */
     80 /* ARGSUSED */
     81 m_clalloc(ncl, nowait)
     82 	register int ncl;
     83 	int nowait;
     84 {
     85 	static int logged;
     86 	register caddr_t p;
     87 	register int i;
     88 	int npg;
     89 
     90 	npg = ncl * CLSIZE;
     91 	p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !nowait);
     92 	if (p == NULL) {
     93 		if (logged == 0) {
     94 			logged++;
     95 			log(LOG_ERR, "mb_map full\n");
     96 		}
     97 		return (0);
     98 	}
     99 	ncl = ncl * CLBYTES / MCLBYTES;
    100 	for (i = 0; i < ncl; i++) {
    101 		((union mcluster *)p)->mcl_next = mclfree;
    102 		mclfree = (union mcluster *)p;
    103 		p += MCLBYTES;
    104 		mbstat.m_clfree++;
    105 	}
    106 	mbstat.m_clusters += ncl;
    107 	return (1);
    108 }
    109 
    110 /*
    111  * When MGET failes, ask protocols to free space when short of memory,
    112  * then re-attempt to allocate an mbuf.
    113  */
    114 struct mbuf *
    115 m_retry(i, t)
    116 	int i, t;
    117 {
    118 	register struct mbuf *m;
    119 
    120 	m_reclaim();
    121 #define m_retry(i, t)	(struct mbuf *)0
    122 	MGET(m, i, t);
    123 #undef m_retry
    124 	return (m);
    125 }
    126 
    127 /*
    128  * As above; retry an MGETHDR.
    129  */
    130 struct mbuf *
    131 m_retryhdr(i, t)
    132 	int i, t;
    133 {
    134 	register struct mbuf *m;
    135 
    136 	m_reclaim();
    137 #define m_retryhdr(i, t) (struct mbuf *)0
    138 	MGETHDR(m, i, t);
    139 #undef m_retryhdr
    140 	return (m);
    141 }
    142 
    143 m_reclaim()
    144 {
    145 	register struct domain *dp;
    146 	register struct protosw *pr;
    147 	int s = splimp();
    148 
    149 	for (dp = domains; dp; dp = dp->dom_next)
    150 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
    151 			if (pr->pr_drain)
    152 				(*pr->pr_drain)();
    153 	splx(s);
    154 	mbstat.m_drain++;
    155 }
    156 
    157 /*
    158  * Space allocation routines.
    159  * These are also available as macros
    160  * for critical paths.
    161  */
    162 struct mbuf *
    163 m_get(nowait, type)
    164 	int nowait, type;
    165 {
    166 	register struct mbuf *m;
    167 
    168 	MGET(m, nowait, type);
    169 	return (m);
    170 }
    171 
    172 struct mbuf *
    173 m_gethdr(nowait, type)
    174 	int nowait, type;
    175 {
    176 	register struct mbuf *m;
    177 
    178 	MGETHDR(m, nowait, type);
    179 	return (m);
    180 }
    181 
    182 struct mbuf *
    183 m_getclr(nowait, type)
    184 	int nowait, type;
    185 {
    186 	register struct mbuf *m;
    187 
    188 	MGET(m, nowait, type);
    189 	if (m == 0)
    190 		return (0);
    191 	bzero(mtod(m, caddr_t), MLEN);
    192 	return (m);
    193 }
    194 
    195 struct mbuf *
    196 m_free(m)
    197 	struct mbuf *m;
    198 {
    199 	register struct mbuf *n;
    200 
    201 	MFREE(m, n);
    202 	return (n);
    203 }
    204 
    205 void
    206 m_freem(m)
    207 	register struct mbuf *m;
    208 {
    209 	register struct mbuf *n;
    210 
    211 	if (m == NULL)
    212 		return;
    213 	do {
    214 		MFREE(m, n);
    215 	} while (m = n);
    216 }
    217 
    218 /*
    219  * Mbuffer utility routines.
    220  */
    221 
    222 /*
    223  * Lesser-used path for M_PREPEND:
    224  * allocate new mbuf to prepend to chain,
    225  * copy junk along.
    226  */
    227 struct mbuf *
    228 m_prepend(m, len, how)
    229 	register struct mbuf *m;
    230 	int len, how;
    231 {
    232 	struct mbuf *mn;
    233 
    234 	MGET(mn, how, m->m_type);
    235 	if (mn == (struct mbuf *)NULL) {
    236 		m_freem(m);
    237 		return ((struct mbuf *)NULL);
    238 	}
    239 	if (m->m_flags & M_PKTHDR) {
    240 		M_COPY_PKTHDR(mn, m);
    241 		m->m_flags &= ~M_PKTHDR;
    242 	}
    243 	mn->m_next = m;
    244 	m = mn;
    245 	if (len < MHLEN)
    246 		MH_ALIGN(m, len);
    247 	m->m_len = len;
    248 	return (m);
    249 }
    250 
    251 /*
    252  * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
    253  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
    254  * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
    255  */
    256 int MCFail;
    257 
    258 struct mbuf *
    259 m_copym(m, off0, len, wait)
    260 	register struct mbuf *m;
    261 	int off0, wait;
    262 	register int len;
    263 {
    264 	register struct mbuf *n, **np;
    265 	register int off = off0;
    266 	struct mbuf *top;
    267 	int copyhdr = 0;
    268 
    269 	if (off < 0 || len < 0)
    270 		panic("m_copym");
    271 	if (off == 0 && m->m_flags & M_PKTHDR)
    272 		copyhdr = 1;
    273 	while (off > 0) {
    274 		if (m == 0)
    275 			panic("m_copym");
    276 		if (off < m->m_len)
    277 			break;
    278 		off -= m->m_len;
    279 		m = m->m_next;
    280 	}
    281 	np = &top;
    282 	top = 0;
    283 	while (len > 0) {
    284 		if (m == 0) {
    285 			if (len != M_COPYALL)
    286 				panic("m_copym");
    287 			break;
    288 		}
    289 		MGET(n, wait, m->m_type);
    290 		*np = n;
    291 		if (n == 0)
    292 			goto nospace;
    293 		if (copyhdr) {
    294 			M_COPY_PKTHDR(n, m);
    295 			if (len == M_COPYALL)
    296 				n->m_pkthdr.len -= off0;
    297 			else
    298 				n->m_pkthdr.len = len;
    299 			copyhdr = 0;
    300 		}
    301 		n->m_len = min(len, m->m_len - off);
    302 		if (m->m_flags & M_EXT) {
    303 			n->m_data = m->m_data + off;
    304 			mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
    305 			n->m_ext = m->m_ext;
    306 			n->m_flags |= M_EXT;
    307 		} else
    308 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
    309 			    (unsigned)n->m_len);
    310 		if (len != M_COPYALL)
    311 			len -= n->m_len;
    312 		off = 0;
    313 		m = m->m_next;
    314 		np = &n->m_next;
    315 	}
    316 	if (top == 0)
    317 		MCFail++;
    318 	return (top);
    319 nospace:
    320 	m_freem(top);
    321 	MCFail++;
    322 	return (0);
    323 }
    324 
    325 /*
    326  * Copy data from an mbuf chain starting "off" bytes from the beginning,
    327  * continuing for "len" bytes, into the indicated buffer.
    328  */
    329 m_copydata(m, off, len, cp)
    330 	register struct mbuf *m;
    331 	register int off;
    332 	register int len;
    333 	caddr_t cp;
    334 {
    335 	register unsigned count;
    336 
    337 	if (off < 0 || len < 0)
    338 		panic("m_copydata");
    339 	while (off > 0) {
    340 		if (m == 0)
    341 			panic("m_copydata");
    342 		if (off < m->m_len)
    343 			break;
    344 		off -= m->m_len;
    345 		m = m->m_next;
    346 	}
    347 	while (len > 0) {
    348 		if (m == 0)
    349 			panic("m_copydata");
    350 		count = min(m->m_len - off, len);
    351 		bcopy(mtod(m, caddr_t) + off, cp, count);
    352 		len -= count;
    353 		cp += count;
    354 		off = 0;
    355 		m = m->m_next;
    356 	}
    357 }
    358 
    359 /*
    360  * Concatenate mbuf chain n to m.
    361  * Both chains must be of the same type (e.g. MT_DATA).
    362  * Any m_pkthdr is not updated.
    363  */
    364 m_cat(m, n)
    365 	register struct mbuf *m, *n;
    366 {
    367 	while (m->m_next)
    368 		m = m->m_next;
    369 	while (n) {
    370 		if (m->m_flags & M_EXT ||
    371 		    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
    372 			/* just join the two chains */
    373 			m->m_next = n;
    374 			return;
    375 		}
    376 		/* splat the data from one into the other */
    377 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
    378 		    (u_int)n->m_len);
    379 		m->m_len += n->m_len;
    380 		n = m_free(n);
    381 	}
    382 }
    383 
    384 void
    385 m_adj(mp, req_len)
    386 	struct mbuf *mp;
    387 	int req_len;
    388 {
    389 	register int len = req_len;
    390 	register struct mbuf *m;
    391 	register count;
    392 
    393 	if ((m = mp) == NULL)
    394 		return;
    395 	if (len >= 0) {
    396 		/*
    397 		 * Trim from head.
    398 		 */
    399 		while (m != NULL && len > 0) {
    400 			if (m->m_len <= len) {
    401 				len -= m->m_len;
    402 				m->m_len = 0;
    403 				m = m->m_next;
    404 			} else {
    405 				m->m_len -= len;
    406 				m->m_data += len;
    407 				len = 0;
    408 			}
    409 		}
    410 		m = mp;
    411 		if (mp->m_flags & M_PKTHDR)
    412 			m->m_pkthdr.len -= (req_len - len);
    413 	} else {
    414 		/*
    415 		 * Trim from tail.  Scan the mbuf chain,
    416 		 * calculating its length and finding the last mbuf.
    417 		 * If the adjustment only affects this mbuf, then just
    418 		 * adjust and return.  Otherwise, rescan and truncate
    419 		 * after the remaining size.
    420 		 */
    421 		len = -len;
    422 		count = 0;
    423 		for (;;) {
    424 			count += m->m_len;
    425 			if (m->m_next == (struct mbuf *)0)
    426 				break;
    427 			m = m->m_next;
    428 		}
    429 		if (m->m_len >= len) {
    430 			m->m_len -= len;
    431 			if (mp->m_flags & M_PKTHDR)
    432 				mp->m_pkthdr.len -= len;
    433 			return;
    434 		}
    435 		count -= len;
    436 		if (count < 0)
    437 			count = 0;
    438 		/*
    439 		 * Correct length for chain is "count".
    440 		 * Find the mbuf with last data, adjust its length,
    441 		 * and toss data from remaining mbufs on chain.
    442 		 */
    443 		m = mp;
    444 		if (m->m_flags & M_PKTHDR)
    445 			m->m_pkthdr.len = count;
    446 		for (; m; m = m->m_next) {
    447 			if (m->m_len >= count) {
    448 				m->m_len = count;
    449 				break;
    450 			}
    451 			count -= m->m_len;
    452 		}
    453 		while (m = m->m_next)
    454 			m->m_len = 0;
    455 	}
    456 }
    457 
    458 /*
    459  * Rearange an mbuf chain so that len bytes are contiguous
    460  * and in the data area of an mbuf (so that mtod and dtom
    461  * will work for a structure of size len).  Returns the resulting
    462  * mbuf chain on success, frees it and returns null on failure.
    463  * If there is room, it will add up to max_protohdr-len extra bytes to the
    464  * contiguous region in an attempt to avoid being called next time.
    465  */
    466 int MPFail;
    467 
    468 struct mbuf *
    469 m_pullup(n, len)
    470 	register struct mbuf *n;
    471 	int len;
    472 {
    473 	register struct mbuf *m;
    474 	register int count;
    475 	int space;
    476 
    477 	/*
    478 	 * If first mbuf has no cluster, and has room for len bytes
    479 	 * without shifting current data, pullup into it,
    480 	 * otherwise allocate a new mbuf to prepend to the chain.
    481 	 */
    482 	if ((n->m_flags & M_EXT) == 0 &&
    483 	    n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
    484 		if (n->m_len >= len)
    485 			return (n);
    486 		m = n;
    487 		n = n->m_next;
    488 		len -= m->m_len;
    489 	} else {
    490 		if (len > MHLEN)
    491 			goto bad;
    492 		MGET(m, M_DONTWAIT, n->m_type);
    493 		if (m == 0)
    494 			goto bad;
    495 		m->m_len = 0;
    496 		if (n->m_flags & M_PKTHDR) {
    497 			M_COPY_PKTHDR(m, n);
    498 			n->m_flags &= ~M_PKTHDR;
    499 		}
    500 	}
    501 	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
    502 	do {
    503 		count = min(min(max(len, max_protohdr), space), n->m_len);
    504 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
    505 		  (unsigned)count);
    506 		len -= count;
    507 		m->m_len += count;
    508 		n->m_len -= count;
    509 		space -= count;
    510 		if (n->m_len)
    511 			n->m_data += count;
    512 		else
    513 			n = m_free(n);
    514 	} while (len > 0 && n);
    515 	if (len > 0) {
    516 		(void) m_free(m);
    517 		goto bad;
    518 	}
    519 	m->m_next = n;
    520 	return (m);
    521 bad:
    522 	m_freem(n);
    523 	MPFail++;
    524 	return (0);
    525 }
    526 
    527 /*
    528  * Partition an mbuf chain in two pieces, returning the tail --
    529  * all but the first len0 bytes.  In case of failure, it returns NULL and
    530  * attempts to restore the chain to its original state.
    531  */
    532 struct mbuf *
    533 m_split(m0, len0, wait)
    534 	register struct mbuf *m0;
    535 	int len0, wait;
    536 {
    537 	register struct mbuf *m, *n;
    538 	unsigned len = len0, remain;
    539 
    540 	for (m = m0; m && len > m->m_len; m = m->m_next)
    541 		len -= m->m_len;
    542 	if (m == 0)
    543 		return (0);
    544 	remain = m->m_len - len;
    545 	if (m0->m_flags & M_PKTHDR) {
    546 		MGETHDR(n, wait, m0->m_type);
    547 		if (n == 0)
    548 			return (0);
    549 		n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
    550 		n->m_pkthdr.len = m0->m_pkthdr.len - len0;
    551 		m0->m_pkthdr.len = len0;
    552 		if (m->m_flags & M_EXT)
    553 			goto extpacket;
    554 		if (remain > MHLEN) {
    555 			/* m can't be the lead packet */
    556 			MH_ALIGN(n, 0);
    557 			n->m_next = m_split(m, len, wait);
    558 			if (n->m_next == 0) {
    559 				(void) m_free(n);
    560 				return (0);
    561 			} else
    562 				return (n);
    563 		} else
    564 			MH_ALIGN(n, remain);
    565 	} else if (remain == 0) {
    566 		n = m->m_next;
    567 		m->m_next = 0;
    568 		return (n);
    569 	} else {
    570 		MGET(n, wait, m->m_type);
    571 		if (n == 0)
    572 			return (0);
    573 		M_ALIGN(n, remain);
    574 	}
    575 extpacket:
    576 	if (m->m_flags & M_EXT) {
    577 		n->m_flags |= M_EXT;
    578 		n->m_ext = m->m_ext;
    579 		mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
    580 		m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
    581 		n->m_data = m->m_data + len;
    582 	} else {
    583 		bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
    584 	}
    585 	n->m_len = remain;
    586 	m->m_len = len;
    587 	n->m_next = m->m_next;
    588 	m->m_next = 0;
    589 	return (n);
    590 }
    591 /*
    592  * Routine to copy from device local memory into mbufs.
    593  */
    594 struct mbuf *
    595 m_devget(buf, totlen, off0, ifp, copy)
    596 	char *buf;
    597 	int totlen, off0;
    598 	struct ifnet *ifp;
    599 	void (*copy)();
    600 {
    601 	register struct mbuf *m;
    602 	struct mbuf *top = 0, **mp = &top;
    603 	register int off = off0, len;
    604 	register char *cp;
    605 	char *epkt;
    606 
    607 	cp = buf;
    608 	epkt = cp + totlen;
    609 	if (off) {
    610 		cp += off + 2 * sizeof(u_short);
    611 		totlen -= 2 * sizeof(u_short);
    612 	}
    613 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    614 	if (m == 0)
    615 		return (0);
    616 	m->m_pkthdr.rcvif = ifp;
    617 	m->m_pkthdr.len = totlen;
    618 	m->m_len = MHLEN;
    619 
    620 	while (totlen > 0) {
    621 		if (top) {
    622 			MGET(m, M_DONTWAIT, MT_DATA);
    623 			if (m == 0) {
    624 				m_freem(top);
    625 				return (0);
    626 			}
    627 			m->m_len = MLEN;
    628 		}
    629 		len = min(totlen, epkt - cp);
    630 		if (len >= MINCLSIZE) {
    631 			MCLGET(m, M_DONTWAIT);
    632 			if (m->m_flags & M_EXT)
    633 				m->m_len = len = min(len, MCLBYTES);
    634 			else
    635 				len = m->m_len;
    636 		} else {
    637 			/*
    638 			 * Place initial small packet/header at end of mbuf.
    639 			 */
    640 			if (len < m->m_len) {
    641 				if (top == 0 && len + max_linkhdr <= m->m_len)
    642 					m->m_data += max_linkhdr;
    643 				m->m_len = len;
    644 			} else
    645 				len = m->m_len;
    646 		}
    647 		if (copy)
    648 			copy(cp, mtod(m, caddr_t), (unsigned)len);
    649 		else
    650 			bcopy(cp, mtod(m, caddr_t), (unsigned)len);
    651 		cp += len;
    652 		*mp = m;
    653 		mp = &m->m_next;
    654 		totlen -= len;
    655 		if (cp == epkt)
    656 			cp = buf;
    657 	}
    658 	return (top);
    659 }
    660