1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37134c934cSMike Smith #include "opt_param.h" 38df8bae1dSRodney W. Grimes #include <sys/param.h> 39df8bae1dSRodney W. Grimes #include <sys/systm.h> 40fb919e4dSMark Murray #include <sys/condvar.h> 41fb919e4dSMark Murray #include <sys/kernel.h> 42fb919e4dSMark Murray #include <sys/lock.h> 4364cfdf46SBruce Evans #include <sys/malloc.h> 44df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 4535e0e5b3SJohn Baldwin #include <sys/mutex.h> 46639acc13SGarrett Wollman #include <sys/sysctl.h> 47df8bae1dSRodney W. Grimes #include <sys/domain.h> 48df8bae1dSRodney W. Grimes #include <sys/protosw.h> 49fb919e4dSMark Murray 50df8bae1dSRodney W. Grimes #include <vm/vm.h> 5128f8db14SBruce Evans #include <vm/vm_kern.h> 52efeaf95aSDavid Greenman #include <vm/vm_extern.h> 53f48b807fSBrian Feldman 54122a814aSBosko Milekic static void mbinit(void *); 552b14f991SJulian Elischer SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) 562b14f991SJulian Elischer 57df8bae1dSRodney W. Grimes struct mbuf *mbutl; 5828f8db14SBruce Evans struct mbstat mbstat; 59af0e6bcdSAlfred Perlstein u_long mbtypes[MT_NTYPES]; 6028f8db14SBruce Evans int max_linkhdr; 6128f8db14SBruce Evans int max_protohdr; 6228f8db14SBruce Evans int max_hdr; 6328f8db14SBruce Evans int max_datalen; 64134c934cSMike Smith int nmbclusters; 65134c934cSMike Smith int nmbufs; 66181d2a15SBosko Milekic int nmbcnt; 677d032714SBosko Milekic u_long m_mballoc_wid = 0; 687d032714SBosko Milekic u_long m_clalloc_wid = 0; 69df8bae1dSRodney W. Grimes 707d032714SBosko Milekic /* 717d032714SBosko Milekic * freelist header structures... 727d032714SBosko Milekic * mbffree_lst, mclfree_lst, mcntfree_lst 737d032714SBosko Milekic */ 747d032714SBosko Milekic struct mbffree_lst mmbfree; 757d032714SBosko Milekic struct mclfree_lst mclfree; 767d032714SBosko Milekic struct mcntfree_lst mcntfree; 775ea487f3SAlfred Perlstein struct mtx mbuf_mtx; 787d032714SBosko Milekic 797d032714SBosko Milekic /* 807d032714SBosko Milekic * sysctl(8) exported objects 817d032714SBosko Milekic */ 82ce02431fSDoug Rabson SYSCTL_DECL(_kern_ipc); 83639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_LINKHDR, max_linkhdr, CTLFLAG_RW, 84639acc13SGarrett Wollman &max_linkhdr, 0, ""); 85639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_PROTOHDR, max_protohdr, CTLFLAG_RW, 86639acc13SGarrett Wollman &max_protohdr, 0, ""); 87639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RW, &max_hdr, 0, ""); 88639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RW, 89639acc13SGarrett Wollman &max_datalen, 0, ""); 90f48b807fSBrian Feldman SYSCTL_INT(_kern_ipc, OID_AUTO, mbuf_wait, CTLFLAG_RW, 91f48b807fSBrian Feldman &mbuf_wait, 0, ""); 929ad48853SAlfred Perlstein SYSCTL_STRUCT(_kern_ipc, KIPC_MBSTAT, mbstat, CTLFLAG_RD, &mbstat, mbstat, ""); 93af0e6bcdSAlfred Perlstein SYSCTL_OPAQUE(_kern_ipc, OID_AUTO, mbtypes, CTLFLAG_RD, mbtypes, 94af0e6bcdSAlfred Perlstein sizeof(mbtypes), "LU", ""); 95134c934cSMike Smith SYSCTL_INT(_kern_ipc, KIPC_NMBCLUSTERS, nmbclusters, CTLFLAG_RD, 96736e4b67SMike Smith &nmbclusters, 0, "Maximum number of mbuf clusters available"); 97736e4b67SMike Smith SYSCTL_INT(_kern_ipc, OID_AUTO, nmbufs, CTLFLAG_RD, &nmbufs, 0, 98736e4b67SMike Smith "Maximum number of mbufs available"); 99181d2a15SBosko Milekic SYSCTL_INT(_kern_ipc, OID_AUTO, nmbcnt, CTLFLAG_RD, &nmbcnt, 0, 100181d2a15SBosko Milekic "Maximum number of ext_buf counters available"); 1014b8ae40aSBosko Milekic 102134c934cSMike Smith #ifndef NMBCLUSTERS 103134c934cSMike Smith #define NMBCLUSTERS (512 + MAXUSERS * 16) 104134c934cSMike Smith #endif 1054b8ae40aSBosko Milekic 106134c934cSMike Smith TUNABLE_INT_DECL("kern.ipc.nmbclusters", NMBCLUSTERS, nmbclusters); 107736e4b67SMike Smith TUNABLE_INT_DECL("kern.ipc.nmbufs", NMBCLUSTERS * 4, nmbufs); 108181d2a15SBosko Milekic TUNABLE_INT_DECL("kern.ipc.nmbcnt", EXT_COUNTERS, nmbcnt); 109639acc13SGarrett Wollman 110122a814aSBosko Milekic static void m_reclaim(void); 11187b6de2bSPoul-Henning Kamp 1127d032714SBosko Milekic /* Initial allocation numbers */ 113a5c4836dSDavid Malone #define NCL_INIT 2 1147642f474SPoul-Henning Kamp #define NMB_INIT 16 1157d032714SBosko Milekic #define REF_INIT NMBCLUSTERS 1167642f474SPoul-Henning Kamp 1177d032714SBosko Milekic /* 1187d032714SBosko Milekic * Full mbuf subsystem initialization done here. 1197d032714SBosko Milekic * 1207d032714SBosko Milekic * XXX: If ever we have system specific map setups to do, then move them to 1217d032714SBosko Milekic * machdep.c - for now, there is no reason for this stuff to go there. 1227d032714SBosko Milekic */ 1232b14f991SJulian Elischer static void 124122a814aSBosko Milekic mbinit(void *dummy) 125df8bae1dSRodney W. Grimes { 126d04d50d1SBosko Milekic vm_offset_t maxaddr; 127d04d50d1SBosko Milekic vm_size_t mb_map_size; 128df8bae1dSRodney W. Grimes 1297d032714SBosko Milekic /* 1307d032714SBosko Milekic * Setup the mb_map, allocate requested VM space. 1317d032714SBosko Milekic */ 132d04d50d1SBosko Milekic mb_map_size = (vm_size_t)(nmbufs * MSIZE + nmbclusters * MCLBYTES + 133d04d50d1SBosko Milekic nmbcnt * sizeof(union mext_refcnt)); 134d04d50d1SBosko Milekic mb_map_size = rounddown(mb_map_size, PAGE_SIZE); 1357d032714SBosko Milekic mb_map = kmem_suballoc(kmem_map, (vm_offset_t *)&mbutl, &maxaddr, 1367d032714SBosko Milekic mb_map_size); 137122a814aSBosko Milekic /* XXX XXX XXX: mb_map->system_map = 1; */ 138a5c4836dSDavid Malone 1397d032714SBosko Milekic /* 1407d032714SBosko Milekic * Initialize the free list headers, and setup locks for lists. 1417d032714SBosko Milekic */ 1427d032714SBosko Milekic mmbfree.m_head = NULL; 1437d032714SBosko Milekic mclfree.m_head = NULL; 1447d032714SBosko Milekic mcntfree.m_head = NULL; 1455ea487f3SAlfred Perlstein mtx_init(&mbuf_mtx, "mbuf free list lock", MTX_DEF); 1464b8ae40aSBosko Milekic cv_init(&mmbfree.m_starved, "mbuf free list starved cv"); 1474b8ae40aSBosko Milekic cv_init(&mclfree.m_starved, "mbuf cluster free list starved cv"); 1487d032714SBosko Milekic 1497d032714SBosko Milekic /* 1507d032714SBosko Milekic * Initialize mbuf subsystem (sysctl exported) statistics structure. 1517d032714SBosko Milekic */ 152639acc13SGarrett Wollman mbstat.m_msize = MSIZE; 153639acc13SGarrett Wollman mbstat.m_mclbytes = MCLBYTES; 154639acc13SGarrett Wollman mbstat.m_minclsize = MINCLSIZE; 155639acc13SGarrett Wollman mbstat.m_mlen = MLEN; 156639acc13SGarrett Wollman mbstat.m_mhlen = MHLEN; 157639acc13SGarrett Wollman 1587d032714SBosko Milekic /* 1597d032714SBosko Milekic * Perform some initial allocations. 1607d032714SBosko Milekic */ 1615ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 1627d032714SBosko Milekic if (m_alloc_ref(REF_INIT, M_DONTWAIT) == 0) 163a5c4836dSDavid Malone goto bad; 1646a06dea0SGarrett Wollman if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0) 1656a06dea0SGarrett Wollman goto bad; 166df8bae1dSRodney W. Grimes if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 167df8bae1dSRodney W. Grimes goto bad; 1685ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 1697d032714SBosko Milekic 170df8bae1dSRodney W. Grimes return; 171df8bae1dSRodney W. Grimes bad: 172a5c4836dSDavid Malone panic("mbinit: failed to initialize mbuf subsystem!"); 173a5c4836dSDavid Malone } 174a5c4836dSDavid Malone 175a5c4836dSDavid Malone /* 176a5c4836dSDavid Malone * Allocate at least nmb reference count structs and place them 177a5c4836dSDavid Malone * on the ref cnt free list. 1787d032714SBosko Milekic * 1797d032714SBosko Milekic * Must be called with the mcntfree lock held. 180a5c4836dSDavid Malone */ 181a5c4836dSDavid Malone int 182122a814aSBosko Milekic m_alloc_ref(u_int nmb, int how) 183a5c4836dSDavid Malone { 184a5c4836dSDavid Malone caddr_t p; 185a5c4836dSDavid Malone u_int nbytes; 186a5c4836dSDavid Malone int i; 187a5c4836dSDavid Malone 188a5c4836dSDavid Malone /* 189a5c4836dSDavid Malone * We don't cap the amount of memory that can be used 190a5c4836dSDavid Malone * by the reference counters, like we do for mbufs and 1917d032714SBosko Milekic * mbuf clusters. In fact, we're absolutely sure that we 1927d032714SBosko Milekic * won't ever be going over our allocated space. We keep enough 1937d032714SBosko Milekic * space in mb_map to accomodate maximum values of allocatable 1947d032714SBosko Milekic * external buffers including, but not limited to, clusters. 1957d032714SBosko Milekic * (That's also why we won't have to have wait routines for 1967d032714SBosko Milekic * counters). 1977d032714SBosko Milekic * 1987d032714SBosko Milekic * If we're in here, we're absolutely certain to be returning 1997d032714SBosko Milekic * succesfully, as long as there is physical memory to accomodate 2007d032714SBosko Milekic * us. And if there isn't, but we're willing to wait, then 2017d032714SBosko Milekic * kmem_malloc() will do the only waiting needed. 202a5c4836dSDavid Malone */ 203a5c4836dSDavid Malone 204a5c4836dSDavid Malone nbytes = round_page(nmb * sizeof(union mext_refcnt)); 2055ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2065ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 2072a0c503eSBosko Milekic if ((p = (caddr_t)kmem_malloc(mb_map, nbytes, how == M_TRYWAIT ? 2082a0c503eSBosko Milekic M_WAITOK : M_NOWAIT)) == NULL) { 2095ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2105ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 211a5c4836dSDavid Malone return (0); 2127d032714SBosko Milekic } 213a5c4836dSDavid Malone nmb = nbytes / sizeof(union mext_refcnt); 214a5c4836dSDavid Malone 2157d032714SBosko Milekic /* 2167d032714SBosko Milekic * We don't let go of the mutex in order to avoid a race. 2177d032714SBosko Milekic * It is up to the caller to let go of the mutex. 2187d032714SBosko Milekic */ 2195ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2205ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 221a5c4836dSDavid Malone for (i = 0; i < nmb; i++) { 2227d032714SBosko Milekic ((union mext_refcnt *)p)->next_ref = mcntfree.m_head; 2237d032714SBosko Milekic mcntfree.m_head = (union mext_refcnt *)p; 224a5c4836dSDavid Malone p += sizeof(union mext_refcnt); 225a5c4836dSDavid Malone mbstat.m_refree++; 226a5c4836dSDavid Malone } 227a5c4836dSDavid Malone mbstat.m_refcnt += nmb; 228a5c4836dSDavid Malone 229a5c4836dSDavid Malone return (1); 230df8bae1dSRodney W. Grimes } 231df8bae1dSRodney W. Grimes 232df8bae1dSRodney W. Grimes /* 2336a06dea0SGarrett Wollman * Allocate at least nmb mbufs and place on mbuf free list. 2347d032714SBosko Milekic * 2357d032714SBosko Milekic * Must be called with the mmbfree lock held. 2366a06dea0SGarrett Wollman */ 2376a06dea0SGarrett Wollman int 238122a814aSBosko Milekic m_mballoc(int nmb, int how) 2396a06dea0SGarrett Wollman { 240122a814aSBosko Milekic caddr_t p; 241122a814aSBosko Milekic int i; 2426a06dea0SGarrett Wollman int nbytes; 2436a06dea0SGarrett Wollman 2449612101eSBosko Milekic nbytes = round_page(nmb * MSIZE); 2459612101eSBosko Milekic nmb = nbytes / MSIZE; 2469612101eSBosko Milekic 247f48b807fSBrian Feldman /* 2487d032714SBosko Milekic * If we've hit the mbuf limit, stop allocating from mb_map. 2497d032714SBosko Milekic * Also, once we run out of map space, it will be impossible to 2507d032714SBosko Milekic * get any more (nothing is ever freed back to the map). 251736e4b67SMike Smith */ 2522ba1a895SBosko Milekic if (mb_map_full || ((nmb + mbstat.m_mbufs) > nmbufs)) 2536a06dea0SGarrett Wollman return (0); 254d8392c6cSGarrett Wollman 2555ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2565ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 2575ea487f3SAlfred Perlstein p = (caddr_t)kmem_malloc(mb_map, nbytes, how == M_TRYWAIT ? 2585ea487f3SAlfred Perlstein M_WAITOK : M_NOWAIT); 2595ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) { 2605ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 2615ea487f3SAlfred Perlstein if (p == NULL) 2625ea487f3SAlfred Perlstein mbstat.m_wait++; 2637d032714SBosko Milekic } 2647d032714SBosko Milekic 2656a06dea0SGarrett Wollman /* 2667d032714SBosko Milekic * Either the map is now full, or `how' is M_DONTWAIT and there 2676a06dea0SGarrett Wollman * are no pages left. 2686a06dea0SGarrett Wollman */ 2696a06dea0SGarrett Wollman if (p == NULL) 2706a06dea0SGarrett Wollman return (0); 2716a06dea0SGarrett Wollman 2727d032714SBosko Milekic /* 2737d032714SBosko Milekic * We don't let go of the mutex in order to avoid a race. 2747d032714SBosko Milekic * It is up to the caller to let go of the mutex when done 2757d032714SBosko Milekic * with grabbing the mbuf from the free list. 2767d032714SBosko Milekic */ 2776a06dea0SGarrett Wollman for (i = 0; i < nmb; i++) { 2787d032714SBosko Milekic ((struct mbuf *)p)->m_next = mmbfree.m_head; 2797d032714SBosko Milekic mmbfree.m_head = (struct mbuf *)p; 2806a06dea0SGarrett Wollman p += MSIZE; 2816a06dea0SGarrett Wollman } 2826a06dea0SGarrett Wollman mbstat.m_mbufs += nmb; 283af0e6bcdSAlfred Perlstein mbtypes[MT_FREE] += nmb; 2846a06dea0SGarrett Wollman return (1); 2856a06dea0SGarrett Wollman } 2866a06dea0SGarrett Wollman 287f48b807fSBrian Feldman /* 288f48b807fSBrian Feldman * Once the mb_map has been exhausted and if the call to the allocation macros 2892a0c503eSBosko Milekic * (or, in some cases, functions) is with M_TRYWAIT, then it is necessary to 2902a0c503eSBosko Milekic * rely solely on reclaimed mbufs. 2917d032714SBosko Milekic * 2927d032714SBosko Milekic * Here we request for the protocols to free up some resources and, if we 2937d032714SBosko Milekic * still cannot get anything, then we wait for an mbuf to be freed for a 2944b8ae40aSBosko Milekic * designated (mbuf_wait) time, at most. 2957d032714SBosko Milekic * 296d113d385SBosko Milekic * Must be called with the mmbfree mutex held. 297f48b807fSBrian Feldman */ 298f48b807fSBrian Feldman struct mbuf * 2997d032714SBosko Milekic m_mballoc_wait(void) 300f48b807fSBrian Feldman { 3017d032714SBosko Milekic struct mbuf *p = NULL; 302f48b807fSBrian Feldman 303f48b807fSBrian Feldman /* 3047d032714SBosko Milekic * See if we can drain some resources out of the protocols. 305d113d385SBosko Milekic * We drop the mmbfree mutex to avoid recursing into it in some of 306d113d385SBosko Milekic * the drain routines. Clearly, we're faced with a race here because 307d113d385SBosko Milekic * once something is freed during the drain, it may be grabbed right 308d113d385SBosko Milekic * from under us by some other thread. But we accept this possibility 309d113d385SBosko Milekic * in order to avoid a potentially large lock recursion and, more 310d113d385SBosko Milekic * importantly, to avoid a potential lock order reversal which may 311d113d385SBosko Milekic * result in deadlock (See comment above m_reclaim()). 312f48b807fSBrian Feldman */ 3135ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 3147d032714SBosko Milekic m_reclaim(); 315d113d385SBosko Milekic 3165ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 3177d032714SBosko Milekic _MGET(p, M_DONTWAIT); 3187d032714SBosko Milekic 3197d032714SBosko Milekic if (p == NULL) { 3204b8ae40aSBosko Milekic int retval; 3214b8ae40aSBosko Milekic 3227d032714SBosko Milekic m_mballoc_wid++; 3234b8ae40aSBosko Milekic retval = cv_timedwait(&mmbfree.m_starved, &mbuf_mtx, 32456acb799SBosko Milekic mbuf_wait); 3257d032714SBosko Milekic m_mballoc_wid--; 3267d032714SBosko Milekic 3277d032714SBosko Milekic /* 3284b8ae40aSBosko Milekic * If we got signaled (i.e. didn't time out), allocate. 3297d032714SBosko Milekic */ 3304b8ae40aSBosko Milekic if (retval == 0) 3317d032714SBosko Milekic _MGET(p, M_DONTWAIT); 332f48b807fSBrian Feldman } 333f48b807fSBrian Feldman 3347d032714SBosko Milekic if (p != NULL) { 3355ea487f3SAlfred Perlstein mbstat.m_wait++; 3367d032714SBosko Milekic if (mmbfree.m_head != NULL) 3374b8ae40aSBosko Milekic MBWAKEUP(m_mballoc_wid, &mmbfree.m_starved); 3382ba1a895SBosko Milekic } 3397d032714SBosko Milekic 340f48b807fSBrian Feldman return (p); 341f48b807fSBrian Feldman } 342f48b807fSBrian Feldman 3436a06dea0SGarrett Wollman /* 344df8bae1dSRodney W. Grimes * Allocate some number of mbuf clusters 345df8bae1dSRodney W. Grimes * and place on cluster free list. 3467d032714SBosko Milekic * 3477d032714SBosko Milekic * Must be called with the mclfree lock held. 348df8bae1dSRodney W. Grimes */ 34926f9a767SRodney W. Grimes int 350122a814aSBosko Milekic m_clalloc(int ncl, int how) 351df8bae1dSRodney W. Grimes { 352122a814aSBosko Milekic caddr_t p; 353122a814aSBosko Milekic int i; 3549612101eSBosko Milekic int npg_sz; 3559612101eSBosko Milekic 3569612101eSBosko Milekic npg_sz = round_page(ncl * MCLBYTES); 3579612101eSBosko Milekic ncl = npg_sz / MCLBYTES; 358df8bae1dSRodney W. Grimes 3595eb7d0cdSDavid Greenman /* 3607d032714SBosko Milekic * If the map is now full (nothing will ever be freed to it). 361736e4b67SMike Smith * If we've hit the mcluster number limit, stop allocating from 3627d032714SBosko Milekic * mb_map. 363736e4b67SMike Smith */ 3642ba1a895SBosko Milekic if (mb_map_full || ((ncl + mbstat.m_clusters) > nmbclusters)) 365736e4b67SMike Smith return (0); 366736e4b67SMike Smith 3675ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 3685ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 3699612101eSBosko Milekic p = (caddr_t)kmem_malloc(mb_map, npg_sz, 3702a0c503eSBosko Milekic how == M_TRYWAIT ? M_WAITOK : M_NOWAIT); 3715ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 3725ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 3737d032714SBosko Milekic 3745eb7d0cdSDavid Greenman /* 3757d032714SBosko Milekic * Either the map is now full, or `how' is M_DONTWAIT and there 3765eb7d0cdSDavid Greenman * are no pages left. 3775eb7d0cdSDavid Greenman */ 3782ba1a895SBosko Milekic if (p == NULL) 379df8bae1dSRodney W. Grimes return (0); 3805eb7d0cdSDavid Greenman 381df8bae1dSRodney W. Grimes for (i = 0; i < ncl; i++) { 3827d032714SBosko Milekic ((union mcluster *)p)->mcl_next = mclfree.m_head; 3837d032714SBosko Milekic mclfree.m_head = (union mcluster *)p; 384df8bae1dSRodney W. Grimes p += MCLBYTES; 385df8bae1dSRodney W. Grimes mbstat.m_clfree++; 386df8bae1dSRodney W. Grimes } 387df8bae1dSRodney W. Grimes mbstat.m_clusters += ncl; 388df8bae1dSRodney W. Grimes return (1); 389df8bae1dSRodney W. Grimes } 390df8bae1dSRodney W. Grimes 391df8bae1dSRodney W. Grimes /* 392f48b807fSBrian Feldman * Once the mb_map submap has been exhausted and the allocation is called with 3932a0c503eSBosko Milekic * M_TRYWAIT, we rely on the mclfree list. If nothing is free, we will 3944b8ae40aSBosko Milekic * block on a cv for a designated amount of time (mbuf_wait) or until we're 3954b8ae40aSBosko Milekic * signaled due to sudden mcluster availability. 3967d032714SBosko Milekic * 3977d032714SBosko Milekic * Must be called with the mclfree lock held. 398f48b807fSBrian Feldman */ 399f48b807fSBrian Feldman caddr_t 400f48b807fSBrian Feldman m_clalloc_wait(void) 401f48b807fSBrian Feldman { 4027d032714SBosko Milekic caddr_t p = NULL; 4034b8ae40aSBosko Milekic int retval; 404f48b807fSBrian Feldman 405f48b807fSBrian Feldman m_clalloc_wid++; 4064b8ae40aSBosko Milekic retval = cv_timedwait(&mclfree.m_starved, &mbuf_mtx, mbuf_wait); 407f48b807fSBrian Feldman m_clalloc_wid--; 408f48b807fSBrian Feldman 409f48b807fSBrian Feldman /* 4107d032714SBosko Milekic * Now that we (think) that we've got something, try again. 411f48b807fSBrian Feldman */ 4124b8ae40aSBosko Milekic if (retval == 0) 413a5c4836dSDavid Malone _MCLALLOC(p, M_DONTWAIT); 414f48b807fSBrian Feldman 4157d032714SBosko Milekic if (p != NULL) { 4165ea487f3SAlfred Perlstein mbstat.m_wait++; 4177d032714SBosko Milekic if (mclfree.m_head != NULL) 4184b8ae40aSBosko Milekic MBWAKEUP(m_clalloc_wid, &mclfree.m_starved); 4192ba1a895SBosko Milekic } 420f48b807fSBrian Feldman 421f48b807fSBrian Feldman return (p); 422f48b807fSBrian Feldman } 423f48b807fSBrian Feldman 424f48b807fSBrian Feldman /* 4257d032714SBosko Milekic * m_reclaim: drain protocols in hopes to free up some resources... 4267d032714SBosko Milekic * 427d113d385SBosko Milekic * XXX: No locks should be held going in here. The drain routines have 428d113d385SBosko Milekic * to presently acquire some locks which raises the possibility of lock 429d113d385SBosko Milekic * order violation if we're holding any mutex if that mutex is acquired in 430d113d385SBosko Milekic * reverse order relative to one of the locks in the drain routines. 431df8bae1dSRodney W. Grimes */ 43287b6de2bSPoul-Henning Kamp static void 433122a814aSBosko Milekic m_reclaim(void) 434df8bae1dSRodney W. Grimes { 435122a814aSBosko Milekic struct domain *dp; 436122a814aSBosko Milekic struct protosw *pr; 437df8bae1dSRodney W. Grimes 43835c05ac6SBosko Milekic #ifdef WITNESS 4394b8ae40aSBosko Milekic KASSERT(witness_list(curproc) == 0, 44035c05ac6SBosko Milekic ("m_reclaim called with locks held")); 44135c05ac6SBosko Milekic #endif 44235c05ac6SBosko Milekic 443df8bae1dSRodney W. Grimes for (dp = domains; dp; dp = dp->dom_next) 444df8bae1dSRodney W. Grimes for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 445df8bae1dSRodney W. Grimes if (pr->pr_drain) 446df8bae1dSRodney W. Grimes (*pr->pr_drain)(); 447df8bae1dSRodney W. Grimes mbstat.m_drain++; 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes 450df8bae1dSRodney W. Grimes /* 451df8bae1dSRodney W. Grimes * Space allocation routines. 452fffd12bdSBosko Milekic * Some of these are also available as macros 453df8bae1dSRodney W. Grimes * for critical paths. 454df8bae1dSRodney W. Grimes */ 455df8bae1dSRodney W. Grimes struct mbuf * 456122a814aSBosko Milekic m_get(int how, int type) 457df8bae1dSRodney W. Grimes { 458122a814aSBosko Milekic struct mbuf *m; 459df8bae1dSRodney W. Grimes 46064cfdf46SBruce Evans MGET(m, how, type); 461df8bae1dSRodney W. Grimes return (m); 462df8bae1dSRodney W. Grimes } 463df8bae1dSRodney W. Grimes 464df8bae1dSRodney W. Grimes struct mbuf * 465122a814aSBosko Milekic m_gethdr(int how, int type) 466df8bae1dSRodney W. Grimes { 467122a814aSBosko Milekic struct mbuf *m; 468df8bae1dSRodney W. Grimes 46964cfdf46SBruce Evans MGETHDR(m, how, type); 470df8bae1dSRodney W. Grimes return (m); 471df8bae1dSRodney W. Grimes } 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes struct mbuf * 474122a814aSBosko Milekic m_getclr(int how, int type) 475df8bae1dSRodney W. Grimes { 476122a814aSBosko Milekic struct mbuf *m; 477df8bae1dSRodney W. Grimes 47864cfdf46SBruce Evans MGET(m, how, type); 4795ea487f3SAlfred Perlstein if (m != NULL) 480df8bae1dSRodney W. Grimes bzero(mtod(m, caddr_t), MLEN); 481df8bae1dSRodney W. Grimes return (m); 482df8bae1dSRodney W. Grimes } 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes struct mbuf * 485122a814aSBosko Milekic m_free(struct mbuf *m) 486df8bae1dSRodney W. Grimes { 487122a814aSBosko Milekic struct mbuf *n; 488df8bae1dSRodney W. Grimes 489df8bae1dSRodney W. Grimes MFREE(m, n); 490df8bae1dSRodney W. Grimes return (n); 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes 493fffd12bdSBosko Milekic /* 494fffd12bdSBosko Milekic * struct mbuf * 495fffd12bdSBosko Milekic * m_getm(m, len, how, type) 496fffd12bdSBosko Milekic * 497fffd12bdSBosko Milekic * This will allocate len-worth of mbufs and/or mbuf clusters (whatever fits 498fffd12bdSBosko Milekic * best) and return a pointer to the top of the allocated chain. If m is 499fffd12bdSBosko Milekic * non-null, then we assume that it is a single mbuf or an mbuf chain to 500fffd12bdSBosko Milekic * which we want len bytes worth of mbufs and/or clusters attached, and so 501fffd12bdSBosko Milekic * if we succeed in allocating it, we will just return a pointer to m. 502fffd12bdSBosko Milekic * 503fffd12bdSBosko Milekic * If we happen to fail at any point during the allocation, we will free 504fffd12bdSBosko Milekic * up everything we have already allocated and return NULL. 505fffd12bdSBosko Milekic * 506fffd12bdSBosko Milekic */ 507fffd12bdSBosko Milekic struct mbuf * 508fffd12bdSBosko Milekic m_getm(struct mbuf *m, int len, int how, int type) 509fffd12bdSBosko Milekic { 510fffd12bdSBosko Milekic struct mbuf *top, *tail, *mp, *mtail = NULL; 511fffd12bdSBosko Milekic 512fffd12bdSBosko Milekic KASSERT(len >= 0, ("len is < 0 in m_getm")); 513fffd12bdSBosko Milekic 51403137ec8SBoris Popov MGET(mp, how, type); 515fffd12bdSBosko Milekic if (mp == NULL) 516fffd12bdSBosko Milekic return (NULL); 517fffd12bdSBosko Milekic else if (len > MINCLSIZE) { 518fffd12bdSBosko Milekic MCLGET(mp, how); 519fffd12bdSBosko Milekic if ((mp->m_flags & M_EXT) == 0) { 520fffd12bdSBosko Milekic m_free(mp); 521fffd12bdSBosko Milekic return (NULL); 522fffd12bdSBosko Milekic } 523fffd12bdSBosko Milekic } 524fffd12bdSBosko Milekic mp->m_len = 0; 525fffd12bdSBosko Milekic len -= M_TRAILINGSPACE(mp); 526fffd12bdSBosko Milekic 527fffd12bdSBosko Milekic if (m != NULL) 528fffd12bdSBosko Milekic for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next); 529fffd12bdSBosko Milekic else 530fffd12bdSBosko Milekic m = mp; 531fffd12bdSBosko Milekic 532fffd12bdSBosko Milekic top = tail = mp; 533fffd12bdSBosko Milekic while (len > 0) { 53403137ec8SBoris Popov MGET(mp, how, type); 535fffd12bdSBosko Milekic if (mp == NULL) 536fffd12bdSBosko Milekic goto failed; 537fffd12bdSBosko Milekic 538fffd12bdSBosko Milekic tail->m_next = mp; 539fffd12bdSBosko Milekic tail = mp; 540fffd12bdSBosko Milekic if (len > MINCLSIZE) { 541fffd12bdSBosko Milekic MCLGET(mp, how); 542fffd12bdSBosko Milekic if ((mp->m_flags & M_EXT) == 0) 543fffd12bdSBosko Milekic goto failed; 544fffd12bdSBosko Milekic } 545fffd12bdSBosko Milekic 546fffd12bdSBosko Milekic mp->m_len = 0; 547fffd12bdSBosko Milekic len -= M_TRAILINGSPACE(mp); 548fffd12bdSBosko Milekic } 549fffd12bdSBosko Milekic 550fffd12bdSBosko Milekic if (mtail != NULL) 551fffd12bdSBosko Milekic mtail->m_next = top; 552fffd12bdSBosko Milekic return (m); 553fffd12bdSBosko Milekic 554fffd12bdSBosko Milekic failed: 555fffd12bdSBosko Milekic m_freem(top); 556fffd12bdSBosko Milekic return (NULL); 557fffd12bdSBosko Milekic } 558fffd12bdSBosko Milekic 559df8bae1dSRodney W. Grimes void 560122a814aSBosko Milekic m_freem(struct mbuf *m) 561df8bae1dSRodney W. Grimes { 562122a814aSBosko Milekic struct mbuf *n; 563df8bae1dSRodney W. Grimes 564df8bae1dSRodney W. Grimes if (m == NULL) 565df8bae1dSRodney W. Grimes return; 566df8bae1dSRodney W. Grimes do { 567686cdd19SJun-ichiro itojun Hagino /* 568686cdd19SJun-ichiro itojun Hagino * we do need to check non-first mbuf, since some of existing 569686cdd19SJun-ichiro itojun Hagino * code does not call M_PREPEND properly. 570686cdd19SJun-ichiro itojun Hagino * (example: call to bpf_mtap from drivers) 571686cdd19SJun-ichiro itojun Hagino */ 572686cdd19SJun-ichiro itojun Hagino if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.aux) { 573686cdd19SJun-ichiro itojun Hagino m_freem(m->m_pkthdr.aux); 574686cdd19SJun-ichiro itojun Hagino m->m_pkthdr.aux = NULL; 575686cdd19SJun-ichiro itojun Hagino } 576df8bae1dSRodney W. Grimes MFREE(m, n); 577797f2d22SPoul-Henning Kamp m = n; 578797f2d22SPoul-Henning Kamp } while (m); 579df8bae1dSRodney W. Grimes } 580df8bae1dSRodney W. Grimes 581df8bae1dSRodney W. Grimes /* 582df8bae1dSRodney W. Grimes * Lesser-used path for M_PREPEND: 583df8bae1dSRodney W. Grimes * allocate new mbuf to prepend to chain, 584df8bae1dSRodney W. Grimes * copy junk along. 585df8bae1dSRodney W. Grimes */ 586df8bae1dSRodney W. Grimes struct mbuf * 587122a814aSBosko Milekic m_prepend(struct mbuf *m, int len, int how) 588df8bae1dSRodney W. Grimes { 589df8bae1dSRodney W. Grimes struct mbuf *mn; 590df8bae1dSRodney W. Grimes 591df8bae1dSRodney W. Grimes MGET(mn, how, m->m_type); 592122a814aSBosko Milekic if (mn == NULL) { 593df8bae1dSRodney W. Grimes m_freem(m); 594122a814aSBosko Milekic return (NULL); 595df8bae1dSRodney W. Grimes } 596df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { 597df8bae1dSRodney W. Grimes M_COPY_PKTHDR(mn, m); 598df8bae1dSRodney W. Grimes m->m_flags &= ~M_PKTHDR; 599df8bae1dSRodney W. Grimes } 600df8bae1dSRodney W. Grimes mn->m_next = m; 601df8bae1dSRodney W. Grimes m = mn; 602df8bae1dSRodney W. Grimes if (len < MHLEN) 603df8bae1dSRodney W. Grimes MH_ALIGN(m, len); 604df8bae1dSRodney W. Grimes m->m_len = len; 605df8bae1dSRodney W. Grimes return (m); 606df8bae1dSRodney W. Grimes } 607df8bae1dSRodney W. Grimes 608df8bae1dSRodney W. Grimes /* 609df8bae1dSRodney W. Grimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 610df8bae1dSRodney W. Grimes * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 6112a0c503eSBosko Milekic * The wait parameter is a choice of M_TRYWAIT/M_DONTWAIT from caller. 6121c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 6131c38f2eaSArchie Cobbs * only their reference counts are incremented. 614df8bae1dSRodney W. Grimes */ 615df8bae1dSRodney W. Grimes struct mbuf * 616122a814aSBosko Milekic m_copym(struct mbuf *m, int off0, int len, int wait) 617df8bae1dSRodney W. Grimes { 618122a814aSBosko Milekic struct mbuf *n, **np; 619122a814aSBosko Milekic int off = off0; 620df8bae1dSRodney W. Grimes struct mbuf *top; 621df8bae1dSRodney W. Grimes int copyhdr = 0; 622df8bae1dSRodney W. Grimes 623e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copym, negative off %d", off)); 624e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copym, negative len %d", len)); 625df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 626df8bae1dSRodney W. Grimes copyhdr = 1; 627df8bae1dSRodney W. Grimes while (off > 0) { 628e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain")); 629df8bae1dSRodney W. Grimes if (off < m->m_len) 630df8bae1dSRodney W. Grimes break; 631df8bae1dSRodney W. Grimes off -= m->m_len; 632df8bae1dSRodney W. Grimes m = m->m_next; 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes np = ⊤ 635df8bae1dSRodney W. Grimes top = 0; 636df8bae1dSRodney W. Grimes while (len > 0) { 637122a814aSBosko Milekic if (m == NULL) { 638e0a653ddSAlfred Perlstein KASSERT(len == M_COPYALL, 639e0a653ddSAlfred Perlstein ("m_copym, length > size of mbuf chain")); 640df8bae1dSRodney W. Grimes break; 641df8bae1dSRodney W. Grimes } 642df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 643df8bae1dSRodney W. Grimes *np = n; 644122a814aSBosko Milekic if (n == NULL) 645df8bae1dSRodney W. Grimes goto nospace; 646df8bae1dSRodney W. Grimes if (copyhdr) { 647df8bae1dSRodney W. Grimes M_COPY_PKTHDR(n, m); 648df8bae1dSRodney W. Grimes if (len == M_COPYALL) 649df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 650df8bae1dSRodney W. Grimes else 651df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 652df8bae1dSRodney W. Grimes copyhdr = 0; 653df8bae1dSRodney W. Grimes } 654df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 655df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 656df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 657df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 658df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 659a5c4836dSDavid Malone MEXT_ADD_REF(m); 660df8bae1dSRodney W. Grimes } else 661df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 662df8bae1dSRodney W. Grimes (unsigned)n->m_len); 663df8bae1dSRodney W. Grimes if (len != M_COPYALL) 664df8bae1dSRodney W. Grimes len -= n->m_len; 665df8bae1dSRodney W. Grimes off = 0; 666df8bae1dSRodney W. Grimes m = m->m_next; 667df8bae1dSRodney W. Grimes np = &n->m_next; 668df8bae1dSRodney W. Grimes } 6695ea487f3SAlfred Perlstein if (top == NULL) { 6705ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 6715ea487f3SAlfred Perlstein mbstat.m_mcfail++; 6725ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 6735ea487f3SAlfred Perlstein } 674df8bae1dSRodney W. Grimes return (top); 675df8bae1dSRodney W. Grimes nospace: 676df8bae1dSRodney W. Grimes m_freem(top); 6775ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 6785ea487f3SAlfred Perlstein mbstat.m_mcfail++; 6795ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 680122a814aSBosko Milekic return (NULL); 681df8bae1dSRodney W. Grimes } 682df8bae1dSRodney W. Grimes 683df8bae1dSRodney W. Grimes /* 6846a06dea0SGarrett Wollman * Copy an entire packet, including header (which must be present). 6856a06dea0SGarrett Wollman * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. 6861c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 6871c38f2eaSArchie Cobbs * only their reference counts are incremented. 6885fe86675SLuigi Rizzo * Preserve alignment of the first mbuf so if the creator has left 6895fe86675SLuigi Rizzo * some room at the beginning (e.g. for inserting protocol headers) 6905fe86675SLuigi Rizzo * the copies still have the room available. 6916a06dea0SGarrett Wollman */ 6926a06dea0SGarrett Wollman struct mbuf * 693122a814aSBosko Milekic m_copypacket(struct mbuf *m, int how) 6946a06dea0SGarrett Wollman { 6956a06dea0SGarrett Wollman struct mbuf *top, *n, *o; 6966a06dea0SGarrett Wollman 6976a06dea0SGarrett Wollman MGET(n, how, m->m_type); 6986a06dea0SGarrett Wollman top = n; 699122a814aSBosko Milekic if (n == NULL) 7006a06dea0SGarrett Wollman goto nospace; 7016a06dea0SGarrett Wollman 7026a06dea0SGarrett Wollman M_COPY_PKTHDR(n, m); 7036a06dea0SGarrett Wollman n->m_len = m->m_len; 7046a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 7056a06dea0SGarrett Wollman n->m_data = m->m_data; 7066a06dea0SGarrett Wollman n->m_ext = m->m_ext; 7076a06dea0SGarrett Wollman n->m_flags |= M_EXT; 708a5c4836dSDavid Malone MEXT_ADD_REF(m); 7096a06dea0SGarrett Wollman } else { 7105fe86675SLuigi Rizzo n->m_data = n->m_pktdat + (m->m_data - m->m_pktdat ); 7116a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 7126a06dea0SGarrett Wollman } 7136a06dea0SGarrett Wollman 7146a06dea0SGarrett Wollman m = m->m_next; 7156a06dea0SGarrett Wollman while (m) { 7166a06dea0SGarrett Wollman MGET(o, how, m->m_type); 717122a814aSBosko Milekic if (o == NULL) 7186a06dea0SGarrett Wollman goto nospace; 7196a06dea0SGarrett Wollman 7206a06dea0SGarrett Wollman n->m_next = o; 7216a06dea0SGarrett Wollman n = n->m_next; 7226a06dea0SGarrett Wollman 7236a06dea0SGarrett Wollman n->m_len = m->m_len; 7246a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 7256a06dea0SGarrett Wollman n->m_data = m->m_data; 7266a06dea0SGarrett Wollman n->m_ext = m->m_ext; 7276a06dea0SGarrett Wollman n->m_flags |= M_EXT; 728a5c4836dSDavid Malone MEXT_ADD_REF(m); 7296a06dea0SGarrett Wollman } else { 7306a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 7316a06dea0SGarrett Wollman } 7326a06dea0SGarrett Wollman 7336a06dea0SGarrett Wollman m = m->m_next; 7346a06dea0SGarrett Wollman } 7356a06dea0SGarrett Wollman return top; 7366a06dea0SGarrett Wollman nospace: 7376a06dea0SGarrett Wollman m_freem(top); 7385ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 7395ea487f3SAlfred Perlstein mbstat.m_mcfail++; 7405ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 741122a814aSBosko Milekic return (NULL); 7426a06dea0SGarrett Wollman } 7436a06dea0SGarrett Wollman 7446a06dea0SGarrett Wollman /* 745df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 746df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 747df8bae1dSRodney W. Grimes */ 74826f9a767SRodney W. Grimes void 749122a814aSBosko Milekic m_copydata(struct mbuf *m, int off, int len, caddr_t cp) 750df8bae1dSRodney W. Grimes { 751122a814aSBosko Milekic unsigned count; 752df8bae1dSRodney W. Grimes 753e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copydata, negative off %d", off)); 754e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copydata, negative len %d", len)); 755df8bae1dSRodney W. Grimes while (off > 0) { 756e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); 757df8bae1dSRodney W. Grimes if (off < m->m_len) 758df8bae1dSRodney W. Grimes break; 759df8bae1dSRodney W. Grimes off -= m->m_len; 760df8bae1dSRodney W. Grimes m = m->m_next; 761df8bae1dSRodney W. Grimes } 762df8bae1dSRodney W. Grimes while (len > 0) { 763e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain")); 764df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 765df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 766df8bae1dSRodney W. Grimes len -= count; 767df8bae1dSRodney W. Grimes cp += count; 768df8bae1dSRodney W. Grimes off = 0; 769df8bae1dSRodney W. Grimes m = m->m_next; 770df8bae1dSRodney W. Grimes } 771df8bae1dSRodney W. Grimes } 772df8bae1dSRodney W. Grimes 773df8bae1dSRodney W. Grimes /* 7741c38f2eaSArchie Cobbs * Copy a packet header mbuf chain into a completely new chain, including 7751c38f2eaSArchie Cobbs * copying any mbuf clusters. Use this instead of m_copypacket() when 7761c38f2eaSArchie Cobbs * you need a writable copy of an mbuf chain. 7771c38f2eaSArchie Cobbs */ 7781c38f2eaSArchie Cobbs struct mbuf * 779122a814aSBosko Milekic m_dup(struct mbuf *m, int how) 7801c38f2eaSArchie Cobbs { 7811c38f2eaSArchie Cobbs struct mbuf **p, *top = NULL; 7821c38f2eaSArchie Cobbs int remain, moff, nsize; 7831c38f2eaSArchie Cobbs 7841c38f2eaSArchie Cobbs /* Sanity check */ 7851c38f2eaSArchie Cobbs if (m == NULL) 786122a814aSBosko Milekic return (NULL); 7871c38f2eaSArchie Cobbs KASSERT((m->m_flags & M_PKTHDR) != 0, ("%s: !PKTHDR", __FUNCTION__)); 7881c38f2eaSArchie Cobbs 7891c38f2eaSArchie Cobbs /* While there's more data, get a new mbuf, tack it on, and fill it */ 7901c38f2eaSArchie Cobbs remain = m->m_pkthdr.len; 7911c38f2eaSArchie Cobbs moff = 0; 7921c38f2eaSArchie Cobbs p = ⊤ 7931c38f2eaSArchie Cobbs while (remain > 0 || top == NULL) { /* allow m->m_pkthdr.len == 0 */ 7941c38f2eaSArchie Cobbs struct mbuf *n; 7951c38f2eaSArchie Cobbs 7961c38f2eaSArchie Cobbs /* Get the next new mbuf */ 7971c38f2eaSArchie Cobbs MGET(n, how, m->m_type); 7981c38f2eaSArchie Cobbs if (n == NULL) 7991c38f2eaSArchie Cobbs goto nospace; 8001c38f2eaSArchie Cobbs if (top == NULL) { /* first one, must be PKTHDR */ 8011c38f2eaSArchie Cobbs M_COPY_PKTHDR(n, m); 8021c38f2eaSArchie Cobbs nsize = MHLEN; 8031c38f2eaSArchie Cobbs } else /* not the first one */ 8041c38f2eaSArchie Cobbs nsize = MLEN; 8051c38f2eaSArchie Cobbs if (remain >= MINCLSIZE) { 8061c38f2eaSArchie Cobbs MCLGET(n, how); 8071c38f2eaSArchie Cobbs if ((n->m_flags & M_EXT) == 0) { 8081c38f2eaSArchie Cobbs (void)m_free(n); 8091c38f2eaSArchie Cobbs goto nospace; 8101c38f2eaSArchie Cobbs } 8111c38f2eaSArchie Cobbs nsize = MCLBYTES; 8121c38f2eaSArchie Cobbs } 8131c38f2eaSArchie Cobbs n->m_len = 0; 8141c38f2eaSArchie Cobbs 8151c38f2eaSArchie Cobbs /* Link it into the new chain */ 8161c38f2eaSArchie Cobbs *p = n; 8171c38f2eaSArchie Cobbs p = &n->m_next; 8181c38f2eaSArchie Cobbs 8191c38f2eaSArchie Cobbs /* Copy data from original mbuf(s) into new mbuf */ 8201c38f2eaSArchie Cobbs while (n->m_len < nsize && m != NULL) { 8211c38f2eaSArchie Cobbs int chunk = min(nsize - n->m_len, m->m_len - moff); 8221c38f2eaSArchie Cobbs 8231c38f2eaSArchie Cobbs bcopy(m->m_data + moff, n->m_data + n->m_len, chunk); 8241c38f2eaSArchie Cobbs moff += chunk; 8251c38f2eaSArchie Cobbs n->m_len += chunk; 8261c38f2eaSArchie Cobbs remain -= chunk; 8271c38f2eaSArchie Cobbs if (moff == m->m_len) { 8281c38f2eaSArchie Cobbs m = m->m_next; 8291c38f2eaSArchie Cobbs moff = 0; 8301c38f2eaSArchie Cobbs } 8311c38f2eaSArchie Cobbs } 8321c38f2eaSArchie Cobbs 8331c38f2eaSArchie Cobbs /* Check correct total mbuf length */ 8341c38f2eaSArchie Cobbs KASSERT((remain > 0 && m != NULL) || (remain == 0 && m == NULL), 8351c38f2eaSArchie Cobbs ("%s: bogus m_pkthdr.len", __FUNCTION__)); 8361c38f2eaSArchie Cobbs } 8371c38f2eaSArchie Cobbs return (top); 8381c38f2eaSArchie Cobbs 8391c38f2eaSArchie Cobbs nospace: 8401c38f2eaSArchie Cobbs m_freem(top); 8415ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 8425ea487f3SAlfred Perlstein mbstat.m_mcfail++; 8435ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 844122a814aSBosko Milekic return (NULL); 8451c38f2eaSArchie Cobbs } 8461c38f2eaSArchie Cobbs 8471c38f2eaSArchie Cobbs /* 848df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 849df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 850df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 851df8bae1dSRodney W. Grimes */ 85226f9a767SRodney W. Grimes void 853122a814aSBosko Milekic m_cat(struct mbuf *m, struct mbuf *n) 854df8bae1dSRodney W. Grimes { 855df8bae1dSRodney W. Grimes while (m->m_next) 856df8bae1dSRodney W. Grimes m = m->m_next; 857df8bae1dSRodney W. Grimes while (n) { 858df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT || 859df8bae1dSRodney W. Grimes m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 860df8bae1dSRodney W. Grimes /* just join the two chains */ 861df8bae1dSRodney W. Grimes m->m_next = n; 862df8bae1dSRodney W. Grimes return; 863df8bae1dSRodney W. Grimes } 864df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 865df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 866df8bae1dSRodney W. Grimes (u_int)n->m_len); 867df8bae1dSRodney W. Grimes m->m_len += n->m_len; 868df8bae1dSRodney W. Grimes n = m_free(n); 869df8bae1dSRodney W. Grimes } 870df8bae1dSRodney W. Grimes } 871df8bae1dSRodney W. Grimes 87226f9a767SRodney W. Grimes void 873122a814aSBosko Milekic m_adj(struct mbuf *mp, int req_len) 874df8bae1dSRodney W. Grimes { 875122a814aSBosko Milekic int len = req_len; 876122a814aSBosko Milekic struct mbuf *m; 877122a814aSBosko Milekic int count; 878df8bae1dSRodney W. Grimes 879df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 880df8bae1dSRodney W. Grimes return; 881df8bae1dSRodney W. Grimes if (len >= 0) { 882df8bae1dSRodney W. Grimes /* 883df8bae1dSRodney W. Grimes * Trim from head. 884df8bae1dSRodney W. Grimes */ 885df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 886df8bae1dSRodney W. Grimes if (m->m_len <= len) { 887df8bae1dSRodney W. Grimes len -= m->m_len; 888df8bae1dSRodney W. Grimes m->m_len = 0; 889df8bae1dSRodney W. Grimes m = m->m_next; 890df8bae1dSRodney W. Grimes } else { 891df8bae1dSRodney W. Grimes m->m_len -= len; 892df8bae1dSRodney W. Grimes m->m_data += len; 893df8bae1dSRodney W. Grimes len = 0; 894df8bae1dSRodney W. Grimes } 895df8bae1dSRodney W. Grimes } 896df8bae1dSRodney W. Grimes m = mp; 897df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 898df8bae1dSRodney W. Grimes m->m_pkthdr.len -= (req_len - len); 899df8bae1dSRodney W. Grimes } else { 900df8bae1dSRodney W. Grimes /* 901df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 902df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 903df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 904df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 905df8bae1dSRodney W. Grimes * after the remaining size. 906df8bae1dSRodney W. Grimes */ 907df8bae1dSRodney W. Grimes len = -len; 908df8bae1dSRodney W. Grimes count = 0; 909df8bae1dSRodney W. Grimes for (;;) { 910df8bae1dSRodney W. Grimes count += m->m_len; 911df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 912df8bae1dSRodney W. Grimes break; 913df8bae1dSRodney W. Grimes m = m->m_next; 914df8bae1dSRodney W. Grimes } 915df8bae1dSRodney W. Grimes if (m->m_len >= len) { 916df8bae1dSRodney W. Grimes m->m_len -= len; 917df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 918df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 919df8bae1dSRodney W. Grimes return; 920df8bae1dSRodney W. Grimes } 921df8bae1dSRodney W. Grimes count -= len; 922df8bae1dSRodney W. Grimes if (count < 0) 923df8bae1dSRodney W. Grimes count = 0; 924df8bae1dSRodney W. Grimes /* 925df8bae1dSRodney W. Grimes * Correct length for chain is "count". 926df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 927df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 928df8bae1dSRodney W. Grimes */ 929df8bae1dSRodney W. Grimes m = mp; 930df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 931df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 932df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 933df8bae1dSRodney W. Grimes if (m->m_len >= count) { 934df8bae1dSRodney W. Grimes m->m_len = count; 935df8bae1dSRodney W. Grimes break; 936df8bae1dSRodney W. Grimes } 937df8bae1dSRodney W. Grimes count -= m->m_len; 938df8bae1dSRodney W. Grimes } 939797f2d22SPoul-Henning Kamp while (m->m_next) 940797f2d22SPoul-Henning Kamp (m = m->m_next) ->m_len = 0; 941df8bae1dSRodney W. Grimes } 942df8bae1dSRodney W. Grimes } 943df8bae1dSRodney W. Grimes 944df8bae1dSRodney W. Grimes /* 945df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 946df8bae1dSRodney W. Grimes * and in the data area of an mbuf (so that mtod and dtom 947df8bae1dSRodney W. Grimes * will work for a structure of size len). Returns the resulting 948df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 949df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 950df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 951df8bae1dSRodney W. Grimes */ 952df8bae1dSRodney W. Grimes struct mbuf * 953122a814aSBosko Milekic m_pullup(struct mbuf *n, int len) 954df8bae1dSRodney W. Grimes { 955122a814aSBosko Milekic struct mbuf *m; 956122a814aSBosko Milekic int count; 957df8bae1dSRodney W. Grimes int space; 958df8bae1dSRodney W. Grimes 959df8bae1dSRodney W. Grimes /* 960df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 961df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 962df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 963df8bae1dSRodney W. Grimes */ 964df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 965df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 966df8bae1dSRodney W. Grimes if (n->m_len >= len) 967df8bae1dSRodney W. Grimes return (n); 968df8bae1dSRodney W. Grimes m = n; 969df8bae1dSRodney W. Grimes n = n->m_next; 970df8bae1dSRodney W. Grimes len -= m->m_len; 971df8bae1dSRodney W. Grimes } else { 972df8bae1dSRodney W. Grimes if (len > MHLEN) 973df8bae1dSRodney W. Grimes goto bad; 974df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, n->m_type); 975122a814aSBosko Milekic if (m == NULL) 976df8bae1dSRodney W. Grimes goto bad; 977df8bae1dSRodney W. Grimes m->m_len = 0; 978df8bae1dSRodney W. Grimes if (n->m_flags & M_PKTHDR) { 979df8bae1dSRodney W. Grimes M_COPY_PKTHDR(m, n); 980df8bae1dSRodney W. Grimes n->m_flags &= ~M_PKTHDR; 981df8bae1dSRodney W. Grimes } 982df8bae1dSRodney W. Grimes } 983df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 984df8bae1dSRodney W. Grimes do { 985df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 986df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 987df8bae1dSRodney W. Grimes (unsigned)count); 988df8bae1dSRodney W. Grimes len -= count; 989df8bae1dSRodney W. Grimes m->m_len += count; 990df8bae1dSRodney W. Grimes n->m_len -= count; 991df8bae1dSRodney W. Grimes space -= count; 992df8bae1dSRodney W. Grimes if (n->m_len) 993df8bae1dSRodney W. Grimes n->m_data += count; 994df8bae1dSRodney W. Grimes else 995df8bae1dSRodney W. Grimes n = m_free(n); 996df8bae1dSRodney W. Grimes } while (len > 0 && n); 997df8bae1dSRodney W. Grimes if (len > 0) { 998df8bae1dSRodney W. Grimes (void) m_free(m); 999df8bae1dSRodney W. Grimes goto bad; 1000df8bae1dSRodney W. Grimes } 1001df8bae1dSRodney W. Grimes m->m_next = n; 1002df8bae1dSRodney W. Grimes return (m); 1003df8bae1dSRodney W. Grimes bad: 1004df8bae1dSRodney W. Grimes m_freem(n); 10055ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 10065ea487f3SAlfred Perlstein mbstat.m_mcfail++; 10075ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 1008122a814aSBosko Milekic return (NULL); 1009df8bae1dSRodney W. Grimes } 1010df8bae1dSRodney W. Grimes 1011df8bae1dSRodney W. Grimes /* 1012df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 1013df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 1014df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 1015df8bae1dSRodney W. Grimes */ 1016df8bae1dSRodney W. Grimes struct mbuf * 1017122a814aSBosko Milekic m_split(struct mbuf *m0, int len0, int wait) 1018df8bae1dSRodney W. Grimes { 1019122a814aSBosko Milekic struct mbuf *m, *n; 1020df8bae1dSRodney W. Grimes unsigned len = len0, remain; 1021df8bae1dSRodney W. Grimes 1022df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 1023df8bae1dSRodney W. Grimes len -= m->m_len; 1024122a814aSBosko Milekic if (m == NULL) 1025122a814aSBosko Milekic return (NULL); 1026df8bae1dSRodney W. Grimes remain = m->m_len - len; 1027df8bae1dSRodney W. Grimes if (m0->m_flags & M_PKTHDR) { 1028df8bae1dSRodney W. Grimes MGETHDR(n, wait, m0->m_type); 1029122a814aSBosko Milekic if (n == NULL) 1030122a814aSBosko Milekic return (NULL); 1031df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 1032df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 1033df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 1034df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 1035df8bae1dSRodney W. Grimes goto extpacket; 1036df8bae1dSRodney W. Grimes if (remain > MHLEN) { 1037df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 1038df8bae1dSRodney W. Grimes MH_ALIGN(n, 0); 1039df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 1040122a814aSBosko Milekic if (n->m_next == NULL) { 1041df8bae1dSRodney W. Grimes (void) m_free(n); 1042122a814aSBosko Milekic return (NULL); 1043df8bae1dSRodney W. Grimes } else 1044df8bae1dSRodney W. Grimes return (n); 1045df8bae1dSRodney W. Grimes } else 1046df8bae1dSRodney W. Grimes MH_ALIGN(n, remain); 1047df8bae1dSRodney W. Grimes } else if (remain == 0) { 1048df8bae1dSRodney W. Grimes n = m->m_next; 1049122a814aSBosko Milekic m->m_next = NULL; 1050df8bae1dSRodney W. Grimes return (n); 1051df8bae1dSRodney W. Grimes } else { 1052df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 1053122a814aSBosko Milekic if (n == NULL) 1054122a814aSBosko Milekic return (NULL); 1055df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 1056df8bae1dSRodney W. Grimes } 1057df8bae1dSRodney W. Grimes extpacket: 1058df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 1059df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 1060df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 1061a5c4836dSDavid Malone MEXT_ADD_REF(m); 1062df8bae1dSRodney W. Grimes m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ 1063df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 1064df8bae1dSRodney W. Grimes } else { 1065df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 1066df8bae1dSRodney W. Grimes } 1067df8bae1dSRodney W. Grimes n->m_len = remain; 1068df8bae1dSRodney W. Grimes m->m_len = len; 1069df8bae1dSRodney W. Grimes n->m_next = m->m_next; 1070122a814aSBosko Milekic m->m_next = NULL; 1071df8bae1dSRodney W. Grimes return (n); 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes /* 1074df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 1075df8bae1dSRodney W. Grimes */ 1076df8bae1dSRodney W. Grimes struct mbuf * 1077122a814aSBosko Milekic m_devget(char *buf, int totlen, int off0, struct ifnet *ifp, 1078122a814aSBosko Milekic void (*copy)(char *from, caddr_t to, u_int len)) 1079df8bae1dSRodney W. Grimes { 1080122a814aSBosko Milekic struct mbuf *m; 1081df8bae1dSRodney W. Grimes struct mbuf *top = 0, **mp = ⊤ 1082122a814aSBosko Milekic int off = off0, len; 1083122a814aSBosko Milekic char *cp; 1084df8bae1dSRodney W. Grimes char *epkt; 1085df8bae1dSRodney W. Grimes 1086df8bae1dSRodney W. Grimes cp = buf; 1087df8bae1dSRodney W. Grimes epkt = cp + totlen; 1088df8bae1dSRodney W. Grimes if (off) { 1089df8bae1dSRodney W. Grimes cp += off + 2 * sizeof(u_short); 1090df8bae1dSRodney W. Grimes totlen -= 2 * sizeof(u_short); 1091df8bae1dSRodney W. Grimes } 1092df8bae1dSRodney W. Grimes MGETHDR(m, M_DONTWAIT, MT_DATA); 1093122a814aSBosko Milekic if (m == NULL) 1094122a814aSBosko Milekic return (NULL); 1095df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 1096df8bae1dSRodney W. Grimes m->m_pkthdr.len = totlen; 1097df8bae1dSRodney W. Grimes m->m_len = MHLEN; 1098df8bae1dSRodney W. Grimes 1099df8bae1dSRodney W. Grimes while (totlen > 0) { 1100df8bae1dSRodney W. Grimes if (top) { 1101df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_DATA); 1102122a814aSBosko Milekic if (m == NULL) { 1103df8bae1dSRodney W. Grimes m_freem(top); 1104122a814aSBosko Milekic return (NULL); 1105df8bae1dSRodney W. Grimes } 1106df8bae1dSRodney W. Grimes m->m_len = MLEN; 1107df8bae1dSRodney W. Grimes } 1108df8bae1dSRodney W. Grimes len = min(totlen, epkt - cp); 1109df8bae1dSRodney W. Grimes if (len >= MINCLSIZE) { 1110df8bae1dSRodney W. Grimes MCLGET(m, M_DONTWAIT); 1111df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 1112df8bae1dSRodney W. Grimes m->m_len = len = min(len, MCLBYTES); 1113df8bae1dSRodney W. Grimes else 1114df8bae1dSRodney W. Grimes len = m->m_len; 1115df8bae1dSRodney W. Grimes } else { 1116df8bae1dSRodney W. Grimes /* 1117df8bae1dSRodney W. Grimes * Place initial small packet/header at end of mbuf. 1118df8bae1dSRodney W. Grimes */ 1119df8bae1dSRodney W. Grimes if (len < m->m_len) { 1120122a814aSBosko Milekic if (top == NULL && len + 1121122a814aSBosko Milekic max_linkhdr <= m->m_len) 1122df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 1123df8bae1dSRodney W. Grimes m->m_len = len; 1124df8bae1dSRodney W. Grimes } else 1125df8bae1dSRodney W. Grimes len = m->m_len; 1126df8bae1dSRodney W. Grimes } 1127df8bae1dSRodney W. Grimes if (copy) 1128df8bae1dSRodney W. Grimes copy(cp, mtod(m, caddr_t), (unsigned)len); 1129df8bae1dSRodney W. Grimes else 1130df8bae1dSRodney W. Grimes bcopy(cp, mtod(m, caddr_t), (unsigned)len); 1131df8bae1dSRodney W. Grimes cp += len; 1132df8bae1dSRodney W. Grimes *mp = m; 1133df8bae1dSRodney W. Grimes mp = &m->m_next; 1134df8bae1dSRodney W. Grimes totlen -= len; 1135df8bae1dSRodney W. Grimes if (cp == epkt) 1136df8bae1dSRodney W. Grimes cp = buf; 1137df8bae1dSRodney W. Grimes } 1138df8bae1dSRodney W. Grimes return (top); 1139df8bae1dSRodney W. Grimes } 1140c5789ba3SPoul-Henning Kamp 1141c5789ba3SPoul-Henning Kamp /* 1142c5789ba3SPoul-Henning Kamp * Copy data from a buffer back into the indicated mbuf chain, 1143c5789ba3SPoul-Henning Kamp * starting "off" bytes from the beginning, extending the mbuf 1144c5789ba3SPoul-Henning Kamp * chain if necessary. 1145c5789ba3SPoul-Henning Kamp */ 1146c5789ba3SPoul-Henning Kamp void 1147122a814aSBosko Milekic m_copyback(struct mbuf *m0, int off, int len, caddr_t cp) 1148c5789ba3SPoul-Henning Kamp { 1149122a814aSBosko Milekic int mlen; 1150122a814aSBosko Milekic struct mbuf *m = m0, *n; 1151c5789ba3SPoul-Henning Kamp int totlen = 0; 1152c5789ba3SPoul-Henning Kamp 1153122a814aSBosko Milekic if (m0 == NULL) 1154c5789ba3SPoul-Henning Kamp return; 1155c5789ba3SPoul-Henning Kamp while (off > (mlen = m->m_len)) { 1156c5789ba3SPoul-Henning Kamp off -= mlen; 1157c5789ba3SPoul-Henning Kamp totlen += mlen; 1158122a814aSBosko Milekic if (m->m_next == NULL) { 1159c5789ba3SPoul-Henning Kamp n = m_getclr(M_DONTWAIT, m->m_type); 1160122a814aSBosko Milekic if (n == NULL) 1161c5789ba3SPoul-Henning Kamp goto out; 1162c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len + off); 1163c5789ba3SPoul-Henning Kamp m->m_next = n; 1164c5789ba3SPoul-Henning Kamp } 1165c5789ba3SPoul-Henning Kamp m = m->m_next; 1166c5789ba3SPoul-Henning Kamp } 1167c5789ba3SPoul-Henning Kamp while (len > 0) { 1168c5789ba3SPoul-Henning Kamp mlen = min (m->m_len - off, len); 1169c5789ba3SPoul-Henning Kamp bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 1170c5789ba3SPoul-Henning Kamp cp += mlen; 1171c5789ba3SPoul-Henning Kamp len -= mlen; 1172c5789ba3SPoul-Henning Kamp mlen += off; 1173c5789ba3SPoul-Henning Kamp off = 0; 1174c5789ba3SPoul-Henning Kamp totlen += mlen; 1175c5789ba3SPoul-Henning Kamp if (len == 0) 1176c5789ba3SPoul-Henning Kamp break; 1177122a814aSBosko Milekic if (m->m_next == NULL) { 1178c5789ba3SPoul-Henning Kamp n = m_get(M_DONTWAIT, m->m_type); 1179122a814aSBosko Milekic if (n == NULL) 1180c5789ba3SPoul-Henning Kamp break; 1181c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len); 1182c5789ba3SPoul-Henning Kamp m->m_next = n; 1183c5789ba3SPoul-Henning Kamp } 1184c5789ba3SPoul-Henning Kamp m = m->m_next; 1185c5789ba3SPoul-Henning Kamp } 1186c5789ba3SPoul-Henning Kamp out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 1187c5789ba3SPoul-Henning Kamp m->m_pkthdr.len = totlen; 1188c5789ba3SPoul-Henning Kamp } 1189ce4a64f7SPoul-Henning Kamp 1190ce4a64f7SPoul-Henning Kamp void 1191ce4a64f7SPoul-Henning Kamp m_print(const struct mbuf *m) 1192ce4a64f7SPoul-Henning Kamp { 1193ce4a64f7SPoul-Henning Kamp int len; 11946357e7b5SEivind Eklund const struct mbuf *m2; 1195ce4a64f7SPoul-Henning Kamp 1196ce4a64f7SPoul-Henning Kamp len = m->m_pkthdr.len; 1197ce4a64f7SPoul-Henning Kamp m2 = m; 1198ce4a64f7SPoul-Henning Kamp while (len) { 1199ce4a64f7SPoul-Henning Kamp printf("%p %*D\n", m2, m2->m_len, (u_char *)m2->m_data, "-"); 1200ce4a64f7SPoul-Henning Kamp len -= m2->m_len; 1201ce4a64f7SPoul-Henning Kamp m2 = m2->m_next; 1202ce4a64f7SPoul-Henning Kamp } 1203ce4a64f7SPoul-Henning Kamp return; 1204ce4a64f7SPoul-Henning Kamp } 1205