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 37240ef842SDavid E. O'Brien #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 5481930014SPeter Wemm #ifndef NMBCLUSTERS 5581930014SPeter Wemm #define NMBCLUSTERS (512 + MAXUSERS * 16) 5681930014SPeter Wemm #endif 5781930014SPeter Wemm 58122a814aSBosko Milekic static void mbinit(void *); 592b14f991SJulian Elischer SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) 602b14f991SJulian Elischer 61df8bae1dSRodney W. Grimes struct mbuf *mbutl; 6228f8db14SBruce Evans struct mbstat mbstat; 63af0e6bcdSAlfred Perlstein u_long mbtypes[MT_NTYPES]; 6428f8db14SBruce Evans int max_linkhdr; 6528f8db14SBruce Evans int max_protohdr; 6628f8db14SBruce Evans int max_hdr; 6728f8db14SBruce Evans int max_datalen; 6881930014SPeter Wemm int nmbclusters = NMBCLUSTERS; 6981930014SPeter Wemm int nmbufs = NMBCLUSTERS * 4; 70181d2a15SBosko Milekic int nmbcnt; 717d032714SBosko Milekic u_long m_mballoc_wid = 0; 727d032714SBosko Milekic u_long m_clalloc_wid = 0; 73df8bae1dSRodney W. Grimes 747d032714SBosko Milekic /* 757d032714SBosko Milekic * freelist header structures... 767d032714SBosko Milekic * mbffree_lst, mclfree_lst, mcntfree_lst 777d032714SBosko Milekic */ 787d032714SBosko Milekic struct mbffree_lst mmbfree; 797d032714SBosko Milekic struct mclfree_lst mclfree; 807d032714SBosko Milekic struct mcntfree_lst mcntfree; 815ea487f3SAlfred Perlstein struct mtx mbuf_mtx; 827d032714SBosko Milekic 837d032714SBosko Milekic /* 847d032714SBosko Milekic * sysctl(8) exported objects 857d032714SBosko Milekic */ 86ce02431fSDoug Rabson SYSCTL_DECL(_kern_ipc); 87639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_LINKHDR, max_linkhdr, CTLFLAG_RW, 88639acc13SGarrett Wollman &max_linkhdr, 0, ""); 89639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_PROTOHDR, max_protohdr, CTLFLAG_RW, 90639acc13SGarrett Wollman &max_protohdr, 0, ""); 91639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RW, &max_hdr, 0, ""); 92639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RW, 93639acc13SGarrett Wollman &max_datalen, 0, ""); 94f48b807fSBrian Feldman SYSCTL_INT(_kern_ipc, OID_AUTO, mbuf_wait, CTLFLAG_RW, 95f48b807fSBrian Feldman &mbuf_wait, 0, ""); 969ad48853SAlfred Perlstein SYSCTL_STRUCT(_kern_ipc, KIPC_MBSTAT, mbstat, CTLFLAG_RD, &mbstat, mbstat, ""); 97af0e6bcdSAlfred Perlstein SYSCTL_OPAQUE(_kern_ipc, OID_AUTO, mbtypes, CTLFLAG_RD, mbtypes, 98af0e6bcdSAlfred Perlstein sizeof(mbtypes), "LU", ""); 99134c934cSMike Smith SYSCTL_INT(_kern_ipc, KIPC_NMBCLUSTERS, nmbclusters, CTLFLAG_RD, 100736e4b67SMike Smith &nmbclusters, 0, "Maximum number of mbuf clusters available"); 101736e4b67SMike Smith SYSCTL_INT(_kern_ipc, OID_AUTO, nmbufs, CTLFLAG_RD, &nmbufs, 0, 102736e4b67SMike Smith "Maximum number of mbufs available"); 103181d2a15SBosko Milekic SYSCTL_INT(_kern_ipc, OID_AUTO, nmbcnt, CTLFLAG_RD, &nmbcnt, 0, 104181d2a15SBosko Milekic "Maximum number of ext_buf counters available"); 1054b8ae40aSBosko Milekic 10609786698SPeter Wemm TUNABLE_INT("kern.ipc.nmbclusters", &nmbclusters); 10709786698SPeter Wemm TUNABLE_INT("kern.ipc.nmbufs", &nmbufs); 10809786698SPeter Wemm TUNABLE_INT("kern.ipc.nmbcnt", &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 117db957588SPeter Wemm static void 118db957588SPeter Wemm tunable_mbinit(void *dummy) 119db957588SPeter Wemm { 120db957588SPeter Wemm 121db957588SPeter Wemm /* 122db957588SPeter Wemm * Sanity checks and pre-initialization for non-constants. 123db957588SPeter Wemm * This has to be done before VM initialization. 124db957588SPeter Wemm */ 125db957588SPeter Wemm if (nmbufs < nmbclusters * 2) 126db957588SPeter Wemm nmbufs = nmbclusters * 2; 127db957588SPeter Wemm if (nmbcnt == 0) 128db957588SPeter Wemm nmbcnt = EXT_COUNTERS; 129db957588SPeter Wemm } 130db957588SPeter Wemm SYSINIT(tunable_mbinit, SI_SUB_TUNABLES, SI_ORDER_ANY, tunable_mbinit, NULL); 131db957588SPeter Wemm 1327d032714SBosko Milekic /* 1337d032714SBosko Milekic * Full mbuf subsystem initialization done here. 1347d032714SBosko Milekic * 1357d032714SBosko Milekic * XXX: If ever we have system specific map setups to do, then move them to 1367d032714SBosko Milekic * machdep.c - for now, there is no reason for this stuff to go there. 1377d032714SBosko Milekic */ 1382b14f991SJulian Elischer static void 139122a814aSBosko Milekic mbinit(void *dummy) 140df8bae1dSRodney W. Grimes { 141d04d50d1SBosko Milekic vm_offset_t maxaddr; 142d04d50d1SBosko Milekic vm_size_t mb_map_size; 143df8bae1dSRodney W. Grimes 1447d032714SBosko Milekic /* 1457d032714SBosko Milekic * Setup the mb_map, allocate requested VM space. 1467d032714SBosko Milekic */ 147d04d50d1SBosko Milekic mb_map_size = (vm_size_t)(nmbufs * MSIZE + nmbclusters * MCLBYTES + 148d04d50d1SBosko Milekic nmbcnt * sizeof(union mext_refcnt)); 149d04d50d1SBosko Milekic mb_map_size = rounddown(mb_map_size, PAGE_SIZE); 1507d032714SBosko Milekic mb_map = kmem_suballoc(kmem_map, (vm_offset_t *)&mbutl, &maxaddr, 1517d032714SBosko Milekic mb_map_size); 152122a814aSBosko Milekic /* XXX XXX XXX: mb_map->system_map = 1; */ 153a5c4836dSDavid Malone 1547d032714SBosko Milekic /* 1557d032714SBosko Milekic * Initialize the free list headers, and setup locks for lists. 1567d032714SBosko Milekic */ 1577d032714SBosko Milekic mmbfree.m_head = NULL; 1587d032714SBosko Milekic mclfree.m_head = NULL; 1597d032714SBosko Milekic mcntfree.m_head = NULL; 1605ea487f3SAlfred Perlstein mtx_init(&mbuf_mtx, "mbuf free list lock", MTX_DEF); 1614b8ae40aSBosko Milekic cv_init(&mmbfree.m_starved, "mbuf free list starved cv"); 1624b8ae40aSBosko Milekic cv_init(&mclfree.m_starved, "mbuf cluster free list starved cv"); 1637d032714SBosko Milekic 1647d032714SBosko Milekic /* 1657d032714SBosko Milekic * Initialize mbuf subsystem (sysctl exported) statistics structure. 1667d032714SBosko Milekic */ 167639acc13SGarrett Wollman mbstat.m_msize = MSIZE; 168639acc13SGarrett Wollman mbstat.m_mclbytes = MCLBYTES; 169639acc13SGarrett Wollman mbstat.m_minclsize = MINCLSIZE; 170639acc13SGarrett Wollman mbstat.m_mlen = MLEN; 171639acc13SGarrett Wollman mbstat.m_mhlen = MHLEN; 172639acc13SGarrett Wollman 1737d032714SBosko Milekic /* 1747d032714SBosko Milekic * Perform some initial allocations. 1757d032714SBosko Milekic */ 1765ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 1777d032714SBosko Milekic if (m_alloc_ref(REF_INIT, M_DONTWAIT) == 0) 178a5c4836dSDavid Malone goto bad; 1796a06dea0SGarrett Wollman if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0) 1806a06dea0SGarrett Wollman goto bad; 181df8bae1dSRodney W. Grimes if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 182df8bae1dSRodney W. Grimes goto bad; 1835ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 1847d032714SBosko Milekic 185df8bae1dSRodney W. Grimes return; 186df8bae1dSRodney W. Grimes bad: 187a5c4836dSDavid Malone panic("mbinit: failed to initialize mbuf subsystem!"); 188a5c4836dSDavid Malone } 189a5c4836dSDavid Malone 190a5c4836dSDavid Malone /* 191a5c4836dSDavid Malone * Allocate at least nmb reference count structs and place them 192a5c4836dSDavid Malone * on the ref cnt free list. 1937d032714SBosko Milekic * 1947d032714SBosko Milekic * Must be called with the mcntfree lock held. 195a5c4836dSDavid Malone */ 196a5c4836dSDavid Malone int 197122a814aSBosko Milekic m_alloc_ref(u_int nmb, int how) 198a5c4836dSDavid Malone { 199a5c4836dSDavid Malone caddr_t p; 200a5c4836dSDavid Malone u_int nbytes; 201a5c4836dSDavid Malone int i; 202a5c4836dSDavid Malone 203a5c4836dSDavid Malone /* 204a5c4836dSDavid Malone * We don't cap the amount of memory that can be used 205a5c4836dSDavid Malone * by the reference counters, like we do for mbufs and 2067d032714SBosko Milekic * mbuf clusters. In fact, we're absolutely sure that we 2077d032714SBosko Milekic * won't ever be going over our allocated space. We keep enough 2087d032714SBosko Milekic * space in mb_map to accomodate maximum values of allocatable 2097d032714SBosko Milekic * external buffers including, but not limited to, clusters. 2107d032714SBosko Milekic * (That's also why we won't have to have wait routines for 2117d032714SBosko Milekic * counters). 2127d032714SBosko Milekic * 2137d032714SBosko Milekic * If we're in here, we're absolutely certain to be returning 2147d032714SBosko Milekic * succesfully, as long as there is physical memory to accomodate 2157d032714SBosko Milekic * us. And if there isn't, but we're willing to wait, then 2167d032714SBosko Milekic * kmem_malloc() will do the only waiting needed. 217a5c4836dSDavid Malone */ 218a5c4836dSDavid Malone 219a5c4836dSDavid Malone nbytes = round_page(nmb * sizeof(union mext_refcnt)); 2205ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2215ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 2222a0c503eSBosko Milekic if ((p = (caddr_t)kmem_malloc(mb_map, nbytes, how == M_TRYWAIT ? 2232a0c503eSBosko Milekic M_WAITOK : M_NOWAIT)) == NULL) { 2245ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2255ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 226a5c4836dSDavid Malone return (0); 2277d032714SBosko Milekic } 228a5c4836dSDavid Malone nmb = nbytes / sizeof(union mext_refcnt); 229a5c4836dSDavid Malone 2307d032714SBosko Milekic /* 2317d032714SBosko Milekic * We don't let go of the mutex in order to avoid a race. 2327d032714SBosko Milekic * It is up to the caller to let go of the mutex. 2337d032714SBosko Milekic */ 2345ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2355ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 236a5c4836dSDavid Malone for (i = 0; i < nmb; i++) { 2377d032714SBosko Milekic ((union mext_refcnt *)p)->next_ref = mcntfree.m_head; 2387d032714SBosko Milekic mcntfree.m_head = (union mext_refcnt *)p; 239a5c4836dSDavid Malone p += sizeof(union mext_refcnt); 240a5c4836dSDavid Malone mbstat.m_refree++; 241a5c4836dSDavid Malone } 242a5c4836dSDavid Malone mbstat.m_refcnt += nmb; 243a5c4836dSDavid Malone 244a5c4836dSDavid Malone return (1); 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes 247df8bae1dSRodney W. Grimes /* 2486a06dea0SGarrett Wollman * Allocate at least nmb mbufs and place on mbuf free list. 2497d032714SBosko Milekic * 2507d032714SBosko Milekic * Must be called with the mmbfree lock held. 2516a06dea0SGarrett Wollman */ 2526a06dea0SGarrett Wollman int 253122a814aSBosko Milekic m_mballoc(int nmb, int how) 2546a06dea0SGarrett Wollman { 255122a814aSBosko Milekic caddr_t p; 256122a814aSBosko Milekic int i; 2576a06dea0SGarrett Wollman int nbytes; 2586a06dea0SGarrett Wollman 2599612101eSBosko Milekic nbytes = round_page(nmb * MSIZE); 2609612101eSBosko Milekic nmb = nbytes / MSIZE; 2619612101eSBosko Milekic 262f48b807fSBrian Feldman /* 2637d032714SBosko Milekic * If we've hit the mbuf limit, stop allocating from mb_map. 2647d032714SBosko Milekic * Also, once we run out of map space, it will be impossible to 2657d032714SBosko Milekic * get any more (nothing is ever freed back to the map). 266736e4b67SMike Smith */ 2672ba1a895SBosko Milekic if (mb_map_full || ((nmb + mbstat.m_mbufs) > nmbufs)) 2686a06dea0SGarrett Wollman return (0); 269d8392c6cSGarrett Wollman 2705ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 2715ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 2725ea487f3SAlfred Perlstein p = (caddr_t)kmem_malloc(mb_map, nbytes, how == M_TRYWAIT ? 2735ea487f3SAlfred Perlstein M_WAITOK : M_NOWAIT); 2745ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) { 2755ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 2765ea487f3SAlfred Perlstein if (p == NULL) 2775ea487f3SAlfred Perlstein mbstat.m_wait++; 2787d032714SBosko Milekic } 2797d032714SBosko Milekic 2806a06dea0SGarrett Wollman /* 2817d032714SBosko Milekic * Either the map is now full, or `how' is M_DONTWAIT and there 2826a06dea0SGarrett Wollman * are no pages left. 2836a06dea0SGarrett Wollman */ 2846a06dea0SGarrett Wollman if (p == NULL) 2856a06dea0SGarrett Wollman return (0); 2866a06dea0SGarrett Wollman 2877d032714SBosko Milekic /* 2887d032714SBosko Milekic * We don't let go of the mutex in order to avoid a race. 2897d032714SBosko Milekic * It is up to the caller to let go of the mutex when done 2907d032714SBosko Milekic * with grabbing the mbuf from the free list. 2917d032714SBosko Milekic */ 2926a06dea0SGarrett Wollman for (i = 0; i < nmb; i++) { 2937d032714SBosko Milekic ((struct mbuf *)p)->m_next = mmbfree.m_head; 2947d032714SBosko Milekic mmbfree.m_head = (struct mbuf *)p; 2956a06dea0SGarrett Wollman p += MSIZE; 2966a06dea0SGarrett Wollman } 2976a06dea0SGarrett Wollman mbstat.m_mbufs += nmb; 298af0e6bcdSAlfred Perlstein mbtypes[MT_FREE] += nmb; 2996a06dea0SGarrett Wollman return (1); 3006a06dea0SGarrett Wollman } 3016a06dea0SGarrett Wollman 302f48b807fSBrian Feldman /* 303f48b807fSBrian Feldman * Once the mb_map has been exhausted and if the call to the allocation macros 3042a0c503eSBosko Milekic * (or, in some cases, functions) is with M_TRYWAIT, then it is necessary to 3052a0c503eSBosko Milekic * rely solely on reclaimed mbufs. 3067d032714SBosko Milekic * 3077d032714SBosko Milekic * Here we request for the protocols to free up some resources and, if we 3087d032714SBosko Milekic * still cannot get anything, then we wait for an mbuf to be freed for a 3094b8ae40aSBosko Milekic * designated (mbuf_wait) time, at most. 3107d032714SBosko Milekic * 311d113d385SBosko Milekic * Must be called with the mmbfree mutex held. 312f48b807fSBrian Feldman */ 313f48b807fSBrian Feldman struct mbuf * 3147d032714SBosko Milekic m_mballoc_wait(void) 315f48b807fSBrian Feldman { 3167d032714SBosko Milekic struct mbuf *p = NULL; 317f48b807fSBrian Feldman 318f48b807fSBrian Feldman /* 3197d032714SBosko Milekic * See if we can drain some resources out of the protocols. 320d113d385SBosko Milekic * We drop the mmbfree mutex to avoid recursing into it in some of 321d113d385SBosko Milekic * the drain routines. Clearly, we're faced with a race here because 322d113d385SBosko Milekic * once something is freed during the drain, it may be grabbed right 323d113d385SBosko Milekic * from under us by some other thread. But we accept this possibility 324d113d385SBosko Milekic * in order to avoid a potentially large lock recursion and, more 325d113d385SBosko Milekic * importantly, to avoid a potential lock order reversal which may 326d113d385SBosko Milekic * result in deadlock (See comment above m_reclaim()). 327f48b807fSBrian Feldman */ 3285ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 3297d032714SBosko Milekic m_reclaim(); 330d113d385SBosko Milekic 3315ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 3327d032714SBosko Milekic _MGET(p, M_DONTWAIT); 3337d032714SBosko Milekic 3347d032714SBosko Milekic if (p == NULL) { 3354b8ae40aSBosko Milekic int retval; 3364b8ae40aSBosko Milekic 3377d032714SBosko Milekic m_mballoc_wid++; 3384b8ae40aSBosko Milekic retval = cv_timedwait(&mmbfree.m_starved, &mbuf_mtx, 33956acb799SBosko Milekic mbuf_wait); 3407d032714SBosko Milekic m_mballoc_wid--; 3417d032714SBosko Milekic 3427d032714SBosko Milekic /* 3434b8ae40aSBosko Milekic * If we got signaled (i.e. didn't time out), allocate. 3447d032714SBosko Milekic */ 3454b8ae40aSBosko Milekic if (retval == 0) 3467d032714SBosko Milekic _MGET(p, M_DONTWAIT); 347f48b807fSBrian Feldman } 348f48b807fSBrian Feldman 3497d032714SBosko Milekic if (p != NULL) { 3505ea487f3SAlfred Perlstein mbstat.m_wait++; 3517d032714SBosko Milekic if (mmbfree.m_head != NULL) 3524b8ae40aSBosko Milekic MBWAKEUP(m_mballoc_wid, &mmbfree.m_starved); 3532ba1a895SBosko Milekic } 3547d032714SBosko Milekic 355f48b807fSBrian Feldman return (p); 356f48b807fSBrian Feldman } 357f48b807fSBrian Feldman 3586a06dea0SGarrett Wollman /* 359df8bae1dSRodney W. Grimes * Allocate some number of mbuf clusters 360df8bae1dSRodney W. Grimes * and place on cluster free list. 3617d032714SBosko Milekic * 3627d032714SBosko Milekic * Must be called with the mclfree lock held. 363df8bae1dSRodney W. Grimes */ 36426f9a767SRodney W. Grimes int 365122a814aSBosko Milekic m_clalloc(int ncl, int how) 366df8bae1dSRodney W. Grimes { 367122a814aSBosko Milekic caddr_t p; 368122a814aSBosko Milekic int i; 3699612101eSBosko Milekic int npg_sz; 3709612101eSBosko Milekic 3719612101eSBosko Milekic npg_sz = round_page(ncl * MCLBYTES); 3729612101eSBosko Milekic ncl = npg_sz / MCLBYTES; 373df8bae1dSRodney W. Grimes 3745eb7d0cdSDavid Greenman /* 3757d032714SBosko Milekic * If the map is now full (nothing will ever be freed to it). 376736e4b67SMike Smith * If we've hit the mcluster number limit, stop allocating from 3777d032714SBosko Milekic * mb_map. 378736e4b67SMike Smith */ 3792ba1a895SBosko Milekic if (mb_map_full || ((ncl + mbstat.m_clusters) > nmbclusters)) 380736e4b67SMike Smith return (0); 381736e4b67SMike Smith 3825ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 3835ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 3849612101eSBosko Milekic p = (caddr_t)kmem_malloc(mb_map, npg_sz, 3852a0c503eSBosko Milekic how == M_TRYWAIT ? M_WAITOK : M_NOWAIT); 3865ea487f3SAlfred Perlstein if (1 /* XXX: how == M_TRYWAIT */) 3875ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 3887d032714SBosko Milekic 3895eb7d0cdSDavid Greenman /* 3907d032714SBosko Milekic * Either the map is now full, or `how' is M_DONTWAIT and there 3915eb7d0cdSDavid Greenman * are no pages left. 3925eb7d0cdSDavid Greenman */ 3932ba1a895SBosko Milekic if (p == NULL) 394df8bae1dSRodney W. Grimes return (0); 3955eb7d0cdSDavid Greenman 396df8bae1dSRodney W. Grimes for (i = 0; i < ncl; i++) { 3977d032714SBosko Milekic ((union mcluster *)p)->mcl_next = mclfree.m_head; 3987d032714SBosko Milekic mclfree.m_head = (union mcluster *)p; 399df8bae1dSRodney W. Grimes p += MCLBYTES; 400df8bae1dSRodney W. Grimes mbstat.m_clfree++; 401df8bae1dSRodney W. Grimes } 402df8bae1dSRodney W. Grimes mbstat.m_clusters += ncl; 403df8bae1dSRodney W. Grimes return (1); 404df8bae1dSRodney W. Grimes } 405df8bae1dSRodney W. Grimes 406df8bae1dSRodney W. Grimes /* 407f48b807fSBrian Feldman * Once the mb_map submap has been exhausted and the allocation is called with 4082a0c503eSBosko Milekic * M_TRYWAIT, we rely on the mclfree list. If nothing is free, we will 4094b8ae40aSBosko Milekic * block on a cv for a designated amount of time (mbuf_wait) or until we're 4104b8ae40aSBosko Milekic * signaled due to sudden mcluster availability. 4117d032714SBosko Milekic * 4127d032714SBosko Milekic * Must be called with the mclfree lock held. 413f48b807fSBrian Feldman */ 414f48b807fSBrian Feldman caddr_t 415f48b807fSBrian Feldman m_clalloc_wait(void) 416f48b807fSBrian Feldman { 4177d032714SBosko Milekic caddr_t p = NULL; 4184b8ae40aSBosko Milekic int retval; 419f48b807fSBrian Feldman 420f48b807fSBrian Feldman m_clalloc_wid++; 4214b8ae40aSBosko Milekic retval = cv_timedwait(&mclfree.m_starved, &mbuf_mtx, mbuf_wait); 422f48b807fSBrian Feldman m_clalloc_wid--; 423f48b807fSBrian Feldman 424f48b807fSBrian Feldman /* 4257d032714SBosko Milekic * Now that we (think) that we've got something, try again. 426f48b807fSBrian Feldman */ 4274b8ae40aSBosko Milekic if (retval == 0) 428a5c4836dSDavid Malone _MCLALLOC(p, M_DONTWAIT); 429f48b807fSBrian Feldman 4307d032714SBosko Milekic if (p != NULL) { 4315ea487f3SAlfred Perlstein mbstat.m_wait++; 4327d032714SBosko Milekic if (mclfree.m_head != NULL) 4334b8ae40aSBosko Milekic MBWAKEUP(m_clalloc_wid, &mclfree.m_starved); 4342ba1a895SBosko Milekic } 435f48b807fSBrian Feldman 436f48b807fSBrian Feldman return (p); 437f48b807fSBrian Feldman } 438f48b807fSBrian Feldman 439f48b807fSBrian Feldman /* 4407d032714SBosko Milekic * m_reclaim: drain protocols in hopes to free up some resources... 4417d032714SBosko Milekic * 442d113d385SBosko Milekic * XXX: No locks should be held going in here. The drain routines have 443d113d385SBosko Milekic * to presently acquire some locks which raises the possibility of lock 444d113d385SBosko Milekic * order violation if we're holding any mutex if that mutex is acquired in 445d113d385SBosko Milekic * reverse order relative to one of the locks in the drain routines. 446df8bae1dSRodney W. Grimes */ 44787b6de2bSPoul-Henning Kamp static void 448122a814aSBosko Milekic m_reclaim(void) 449df8bae1dSRodney W. Grimes { 450122a814aSBosko Milekic struct domain *dp; 451122a814aSBosko Milekic struct protosw *pr; 452df8bae1dSRodney W. Grimes 45335c05ac6SBosko Milekic #ifdef WITNESS 4544b8ae40aSBosko Milekic KASSERT(witness_list(curproc) == 0, 45535c05ac6SBosko Milekic ("m_reclaim called with locks held")); 45635c05ac6SBosko Milekic #endif 45735c05ac6SBosko Milekic 458df8bae1dSRodney W. Grimes for (dp = domains; dp; dp = dp->dom_next) 459df8bae1dSRodney W. Grimes for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 460df8bae1dSRodney W. Grimes if (pr->pr_drain) 461df8bae1dSRodney W. Grimes (*pr->pr_drain)(); 462df8bae1dSRodney W. Grimes mbstat.m_drain++; 463df8bae1dSRodney W. Grimes } 464df8bae1dSRodney W. Grimes 465df8bae1dSRodney W. Grimes /* 466df8bae1dSRodney W. Grimes * Space allocation routines. 467fffd12bdSBosko Milekic * Some of these are also available as macros 468df8bae1dSRodney W. Grimes * for critical paths. 469df8bae1dSRodney W. Grimes */ 470df8bae1dSRodney W. Grimes struct mbuf * 471122a814aSBosko Milekic m_get(int how, int type) 472df8bae1dSRodney W. Grimes { 473122a814aSBosko Milekic struct mbuf *m; 474df8bae1dSRodney W. Grimes 47564cfdf46SBruce Evans MGET(m, how, type); 476df8bae1dSRodney W. Grimes return (m); 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes 479df8bae1dSRodney W. Grimes struct mbuf * 480122a814aSBosko Milekic m_gethdr(int how, int type) 481df8bae1dSRodney W. Grimes { 482122a814aSBosko Milekic struct mbuf *m; 483df8bae1dSRodney W. Grimes 48464cfdf46SBruce Evans MGETHDR(m, how, type); 485df8bae1dSRodney W. Grimes return (m); 486df8bae1dSRodney W. Grimes } 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes struct mbuf * 489122a814aSBosko Milekic m_getclr(int how, int type) 490df8bae1dSRodney W. Grimes { 491122a814aSBosko Milekic struct mbuf *m; 492df8bae1dSRodney W. Grimes 49364cfdf46SBruce Evans MGET(m, how, type); 4945ea487f3SAlfred Perlstein if (m != NULL) 495df8bae1dSRodney W. Grimes bzero(mtod(m, caddr_t), MLEN); 496df8bae1dSRodney W. Grimes return (m); 497df8bae1dSRodney W. Grimes } 498df8bae1dSRodney W. Grimes 499df8bae1dSRodney W. Grimes struct mbuf * 500122a814aSBosko Milekic m_free(struct mbuf *m) 501df8bae1dSRodney W. Grimes { 502122a814aSBosko Milekic struct mbuf *n; 503df8bae1dSRodney W. Grimes 504df8bae1dSRodney W. Grimes MFREE(m, n); 505df8bae1dSRodney W. Grimes return (n); 506df8bae1dSRodney W. Grimes } 507df8bae1dSRodney W. Grimes 508fffd12bdSBosko Milekic /* 509fffd12bdSBosko Milekic * struct mbuf * 510fffd12bdSBosko Milekic * m_getm(m, len, how, type) 511fffd12bdSBosko Milekic * 512fffd12bdSBosko Milekic * This will allocate len-worth of mbufs and/or mbuf clusters (whatever fits 513fffd12bdSBosko Milekic * best) and return a pointer to the top of the allocated chain. If m is 514fffd12bdSBosko Milekic * non-null, then we assume that it is a single mbuf or an mbuf chain to 515fffd12bdSBosko Milekic * which we want len bytes worth of mbufs and/or clusters attached, and so 516fffd12bdSBosko Milekic * if we succeed in allocating it, we will just return a pointer to m. 517fffd12bdSBosko Milekic * 518fffd12bdSBosko Milekic * If we happen to fail at any point during the allocation, we will free 519fffd12bdSBosko Milekic * up everything we have already allocated and return NULL. 520fffd12bdSBosko Milekic * 521fffd12bdSBosko Milekic */ 522fffd12bdSBosko Milekic struct mbuf * 523fffd12bdSBosko Milekic m_getm(struct mbuf *m, int len, int how, int type) 524fffd12bdSBosko Milekic { 525fffd12bdSBosko Milekic struct mbuf *top, *tail, *mp, *mtail = NULL; 526fffd12bdSBosko Milekic 527fffd12bdSBosko Milekic KASSERT(len >= 0, ("len is < 0 in m_getm")); 528fffd12bdSBosko Milekic 52903137ec8SBoris Popov MGET(mp, how, type); 530fffd12bdSBosko Milekic if (mp == NULL) 531fffd12bdSBosko Milekic return (NULL); 532fffd12bdSBosko Milekic else if (len > MINCLSIZE) { 533fffd12bdSBosko Milekic MCLGET(mp, how); 534fffd12bdSBosko Milekic if ((mp->m_flags & M_EXT) == 0) { 535fffd12bdSBosko Milekic m_free(mp); 536fffd12bdSBosko Milekic return (NULL); 537fffd12bdSBosko Milekic } 538fffd12bdSBosko Milekic } 539fffd12bdSBosko Milekic mp->m_len = 0; 540fffd12bdSBosko Milekic len -= M_TRAILINGSPACE(mp); 541fffd12bdSBosko Milekic 542fffd12bdSBosko Milekic if (m != NULL) 543fffd12bdSBosko Milekic for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next); 544fffd12bdSBosko Milekic else 545fffd12bdSBosko Milekic m = mp; 546fffd12bdSBosko Milekic 547fffd12bdSBosko Milekic top = tail = mp; 548fffd12bdSBosko Milekic while (len > 0) { 54903137ec8SBoris Popov MGET(mp, how, type); 550fffd12bdSBosko Milekic if (mp == NULL) 551fffd12bdSBosko Milekic goto failed; 552fffd12bdSBosko Milekic 553fffd12bdSBosko Milekic tail->m_next = mp; 554fffd12bdSBosko Milekic tail = mp; 555fffd12bdSBosko Milekic if (len > MINCLSIZE) { 556fffd12bdSBosko Milekic MCLGET(mp, how); 557fffd12bdSBosko Milekic if ((mp->m_flags & M_EXT) == 0) 558fffd12bdSBosko Milekic goto failed; 559fffd12bdSBosko Milekic } 560fffd12bdSBosko Milekic 561fffd12bdSBosko Milekic mp->m_len = 0; 562fffd12bdSBosko Milekic len -= M_TRAILINGSPACE(mp); 563fffd12bdSBosko Milekic } 564fffd12bdSBosko Milekic 565fffd12bdSBosko Milekic if (mtail != NULL) 566fffd12bdSBosko Milekic mtail->m_next = top; 567fffd12bdSBosko Milekic return (m); 568fffd12bdSBosko Milekic 569fffd12bdSBosko Milekic failed: 570fffd12bdSBosko Milekic m_freem(top); 571fffd12bdSBosko Milekic return (NULL); 572fffd12bdSBosko Milekic } 573fffd12bdSBosko Milekic 574df8bae1dSRodney W. Grimes void 575122a814aSBosko Milekic m_freem(struct mbuf *m) 576df8bae1dSRodney W. Grimes { 577122a814aSBosko Milekic struct mbuf *n; 578df8bae1dSRodney W. Grimes 579df8bae1dSRodney W. Grimes if (m == NULL) 580df8bae1dSRodney W. Grimes return; 581df8bae1dSRodney W. Grimes do { 582df8bae1dSRodney W. Grimes MFREE(m, n); 583797f2d22SPoul-Henning Kamp m = n; 584797f2d22SPoul-Henning Kamp } while (m); 585df8bae1dSRodney W. Grimes } 586df8bae1dSRodney W. Grimes 587df8bae1dSRodney W. Grimes /* 588df8bae1dSRodney W. Grimes * Lesser-used path for M_PREPEND: 589df8bae1dSRodney W. Grimes * allocate new mbuf to prepend to chain, 590df8bae1dSRodney W. Grimes * copy junk along. 591df8bae1dSRodney W. Grimes */ 592df8bae1dSRodney W. Grimes struct mbuf * 593122a814aSBosko Milekic m_prepend(struct mbuf *m, int len, int how) 594df8bae1dSRodney W. Grimes { 595df8bae1dSRodney W. Grimes struct mbuf *mn; 596df8bae1dSRodney W. Grimes 597df8bae1dSRodney W. Grimes MGET(mn, how, m->m_type); 598122a814aSBosko Milekic if (mn == NULL) { 599df8bae1dSRodney W. Grimes m_freem(m); 600122a814aSBosko Milekic return (NULL); 601df8bae1dSRodney W. Grimes } 602df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { 603df8bae1dSRodney W. Grimes M_COPY_PKTHDR(mn, m); 604df8bae1dSRodney W. Grimes m->m_flags &= ~M_PKTHDR; 605df8bae1dSRodney W. Grimes } 606df8bae1dSRodney W. Grimes mn->m_next = m; 607df8bae1dSRodney W. Grimes m = mn; 608df8bae1dSRodney W. Grimes if (len < MHLEN) 609df8bae1dSRodney W. Grimes MH_ALIGN(m, len); 610df8bae1dSRodney W. Grimes m->m_len = len; 611df8bae1dSRodney W. Grimes return (m); 612df8bae1dSRodney W. Grimes } 613df8bae1dSRodney W. Grimes 614df8bae1dSRodney W. Grimes /* 615df8bae1dSRodney W. Grimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 616df8bae1dSRodney W. Grimes * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 6172a0c503eSBosko Milekic * The wait parameter is a choice of M_TRYWAIT/M_DONTWAIT from caller. 6181c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 6191c38f2eaSArchie Cobbs * only their reference counts are incremented. 620df8bae1dSRodney W. Grimes */ 621df8bae1dSRodney W. Grimes struct mbuf * 622122a814aSBosko Milekic m_copym(struct mbuf *m, int off0, int len, int wait) 623df8bae1dSRodney W. Grimes { 624122a814aSBosko Milekic struct mbuf *n, **np; 625122a814aSBosko Milekic int off = off0; 626df8bae1dSRodney W. Grimes struct mbuf *top; 627df8bae1dSRodney W. Grimes int copyhdr = 0; 628df8bae1dSRodney W. Grimes 629e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copym, negative off %d", off)); 630e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copym, negative len %d", len)); 631df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 632df8bae1dSRodney W. Grimes copyhdr = 1; 633df8bae1dSRodney W. Grimes while (off > 0) { 634e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain")); 635df8bae1dSRodney W. Grimes if (off < m->m_len) 636df8bae1dSRodney W. Grimes break; 637df8bae1dSRodney W. Grimes off -= m->m_len; 638df8bae1dSRodney W. Grimes m = m->m_next; 639df8bae1dSRodney W. Grimes } 640df8bae1dSRodney W. Grimes np = ⊤ 641df8bae1dSRodney W. Grimes top = 0; 642df8bae1dSRodney W. Grimes while (len > 0) { 643122a814aSBosko Milekic if (m == NULL) { 644e0a653ddSAlfred Perlstein KASSERT(len == M_COPYALL, 645e0a653ddSAlfred Perlstein ("m_copym, length > size of mbuf chain")); 646df8bae1dSRodney W. Grimes break; 647df8bae1dSRodney W. Grimes } 648df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 649df8bae1dSRodney W. Grimes *np = n; 650122a814aSBosko Milekic if (n == NULL) 651df8bae1dSRodney W. Grimes goto nospace; 652df8bae1dSRodney W. Grimes if (copyhdr) { 653df8bae1dSRodney W. Grimes M_COPY_PKTHDR(n, m); 654df8bae1dSRodney W. Grimes if (len == M_COPYALL) 655df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 656df8bae1dSRodney W. Grimes else 657df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 658df8bae1dSRodney W. Grimes copyhdr = 0; 659df8bae1dSRodney W. Grimes } 660df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 661df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 662df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 663df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 664df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 665a5c4836dSDavid Malone MEXT_ADD_REF(m); 666df8bae1dSRodney W. Grimes } else 667df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 668df8bae1dSRodney W. Grimes (unsigned)n->m_len); 669df8bae1dSRodney W. Grimes if (len != M_COPYALL) 670df8bae1dSRodney W. Grimes len -= n->m_len; 671df8bae1dSRodney W. Grimes off = 0; 672df8bae1dSRodney W. Grimes m = m->m_next; 673df8bae1dSRodney W. Grimes np = &n->m_next; 674df8bae1dSRodney W. Grimes } 6755ea487f3SAlfred Perlstein if (top == NULL) { 6765ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 6775ea487f3SAlfred Perlstein mbstat.m_mcfail++; 6785ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 6795ea487f3SAlfred Perlstein } 680df8bae1dSRodney W. Grimes return (top); 681df8bae1dSRodney W. Grimes nospace: 682df8bae1dSRodney W. Grimes m_freem(top); 6835ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 6845ea487f3SAlfred Perlstein mbstat.m_mcfail++; 6855ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 686122a814aSBosko Milekic return (NULL); 687df8bae1dSRodney W. Grimes } 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes /* 6906a06dea0SGarrett Wollman * Copy an entire packet, including header (which must be present). 6916a06dea0SGarrett Wollman * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. 6921c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 6931c38f2eaSArchie Cobbs * only their reference counts are incremented. 6945fe86675SLuigi Rizzo * Preserve alignment of the first mbuf so if the creator has left 6955fe86675SLuigi Rizzo * some room at the beginning (e.g. for inserting protocol headers) 6965fe86675SLuigi Rizzo * the copies still have the room available. 6976a06dea0SGarrett Wollman */ 6986a06dea0SGarrett Wollman struct mbuf * 699122a814aSBosko Milekic m_copypacket(struct mbuf *m, int how) 7006a06dea0SGarrett Wollman { 7016a06dea0SGarrett Wollman struct mbuf *top, *n, *o; 7026a06dea0SGarrett Wollman 7036a06dea0SGarrett Wollman MGET(n, how, m->m_type); 7046a06dea0SGarrett Wollman top = n; 705122a814aSBosko Milekic if (n == NULL) 7066a06dea0SGarrett Wollman goto nospace; 7076a06dea0SGarrett Wollman 7086a06dea0SGarrett Wollman M_COPY_PKTHDR(n, m); 7096a06dea0SGarrett Wollman n->m_len = m->m_len; 7106a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 7116a06dea0SGarrett Wollman n->m_data = m->m_data; 7126a06dea0SGarrett Wollman n->m_ext = m->m_ext; 7136a06dea0SGarrett Wollman n->m_flags |= M_EXT; 714a5c4836dSDavid Malone MEXT_ADD_REF(m); 7156a06dea0SGarrett Wollman } else { 7165fe86675SLuigi Rizzo n->m_data = n->m_pktdat + (m->m_data - m->m_pktdat ); 7176a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 7186a06dea0SGarrett Wollman } 7196a06dea0SGarrett Wollman 7206a06dea0SGarrett Wollman m = m->m_next; 7216a06dea0SGarrett Wollman while (m) { 7226a06dea0SGarrett Wollman MGET(o, how, m->m_type); 723122a814aSBosko Milekic if (o == NULL) 7246a06dea0SGarrett Wollman goto nospace; 7256a06dea0SGarrett Wollman 7266a06dea0SGarrett Wollman n->m_next = o; 7276a06dea0SGarrett Wollman n = n->m_next; 7286a06dea0SGarrett Wollman 7296a06dea0SGarrett Wollman n->m_len = m->m_len; 7306a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 7316a06dea0SGarrett Wollman n->m_data = m->m_data; 7326a06dea0SGarrett Wollman n->m_ext = m->m_ext; 7336a06dea0SGarrett Wollman n->m_flags |= M_EXT; 734a5c4836dSDavid Malone MEXT_ADD_REF(m); 7356a06dea0SGarrett Wollman } else { 7366a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 7376a06dea0SGarrett Wollman } 7386a06dea0SGarrett Wollman 7396a06dea0SGarrett Wollman m = m->m_next; 7406a06dea0SGarrett Wollman } 7416a06dea0SGarrett Wollman return top; 7426a06dea0SGarrett Wollman nospace: 7436a06dea0SGarrett Wollman m_freem(top); 7445ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 7455ea487f3SAlfred Perlstein mbstat.m_mcfail++; 7465ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 747122a814aSBosko Milekic return (NULL); 7486a06dea0SGarrett Wollman } 7496a06dea0SGarrett Wollman 7506a06dea0SGarrett Wollman /* 751df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 752df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 753df8bae1dSRodney W. Grimes */ 75426f9a767SRodney W. Grimes void 755122a814aSBosko Milekic m_copydata(struct mbuf *m, int off, int len, caddr_t cp) 756df8bae1dSRodney W. Grimes { 757122a814aSBosko Milekic unsigned count; 758df8bae1dSRodney W. Grimes 759e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copydata, negative off %d", off)); 760e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copydata, negative len %d", len)); 761df8bae1dSRodney W. Grimes while (off > 0) { 762e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); 763df8bae1dSRodney W. Grimes if (off < m->m_len) 764df8bae1dSRodney W. Grimes break; 765df8bae1dSRodney W. Grimes off -= m->m_len; 766df8bae1dSRodney W. Grimes m = m->m_next; 767df8bae1dSRodney W. Grimes } 768df8bae1dSRodney W. Grimes while (len > 0) { 769e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain")); 770df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 771df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 772df8bae1dSRodney W. Grimes len -= count; 773df8bae1dSRodney W. Grimes cp += count; 774df8bae1dSRodney W. Grimes off = 0; 775df8bae1dSRodney W. Grimes m = m->m_next; 776df8bae1dSRodney W. Grimes } 777df8bae1dSRodney W. Grimes } 778df8bae1dSRodney W. Grimes 779df8bae1dSRodney W. Grimes /* 7801c38f2eaSArchie Cobbs * Copy a packet header mbuf chain into a completely new chain, including 7811c38f2eaSArchie Cobbs * copying any mbuf clusters. Use this instead of m_copypacket() when 7821c38f2eaSArchie Cobbs * you need a writable copy of an mbuf chain. 7831c38f2eaSArchie Cobbs */ 7841c38f2eaSArchie Cobbs struct mbuf * 785122a814aSBosko Milekic m_dup(struct mbuf *m, int how) 7861c38f2eaSArchie Cobbs { 7871c38f2eaSArchie Cobbs struct mbuf **p, *top = NULL; 7881c38f2eaSArchie Cobbs int remain, moff, nsize; 7891c38f2eaSArchie Cobbs 7901c38f2eaSArchie Cobbs /* Sanity check */ 7911c38f2eaSArchie Cobbs if (m == NULL) 792122a814aSBosko Milekic return (NULL); 7931c38f2eaSArchie Cobbs KASSERT((m->m_flags & M_PKTHDR) != 0, ("%s: !PKTHDR", __FUNCTION__)); 7941c38f2eaSArchie Cobbs 7951c38f2eaSArchie Cobbs /* While there's more data, get a new mbuf, tack it on, and fill it */ 7961c38f2eaSArchie Cobbs remain = m->m_pkthdr.len; 7971c38f2eaSArchie Cobbs moff = 0; 7981c38f2eaSArchie Cobbs p = ⊤ 7991c38f2eaSArchie Cobbs while (remain > 0 || top == NULL) { /* allow m->m_pkthdr.len == 0 */ 8001c38f2eaSArchie Cobbs struct mbuf *n; 8011c38f2eaSArchie Cobbs 8021c38f2eaSArchie Cobbs /* Get the next new mbuf */ 8031c38f2eaSArchie Cobbs MGET(n, how, m->m_type); 8041c38f2eaSArchie Cobbs if (n == NULL) 8051c38f2eaSArchie Cobbs goto nospace; 8061c38f2eaSArchie Cobbs if (top == NULL) { /* first one, must be PKTHDR */ 8071c38f2eaSArchie Cobbs M_COPY_PKTHDR(n, m); 8081c38f2eaSArchie Cobbs nsize = MHLEN; 8091c38f2eaSArchie Cobbs } else /* not the first one */ 8101c38f2eaSArchie Cobbs nsize = MLEN; 8111c38f2eaSArchie Cobbs if (remain >= MINCLSIZE) { 8121c38f2eaSArchie Cobbs MCLGET(n, how); 8131c38f2eaSArchie Cobbs if ((n->m_flags & M_EXT) == 0) { 8141c38f2eaSArchie Cobbs (void)m_free(n); 8151c38f2eaSArchie Cobbs goto nospace; 8161c38f2eaSArchie Cobbs } 8171c38f2eaSArchie Cobbs nsize = MCLBYTES; 8181c38f2eaSArchie Cobbs } 8191c38f2eaSArchie Cobbs n->m_len = 0; 8201c38f2eaSArchie Cobbs 8211c38f2eaSArchie Cobbs /* Link it into the new chain */ 8221c38f2eaSArchie Cobbs *p = n; 8231c38f2eaSArchie Cobbs p = &n->m_next; 8241c38f2eaSArchie Cobbs 8251c38f2eaSArchie Cobbs /* Copy data from original mbuf(s) into new mbuf */ 8261c38f2eaSArchie Cobbs while (n->m_len < nsize && m != NULL) { 8271c38f2eaSArchie Cobbs int chunk = min(nsize - n->m_len, m->m_len - moff); 8281c38f2eaSArchie Cobbs 8291c38f2eaSArchie Cobbs bcopy(m->m_data + moff, n->m_data + n->m_len, chunk); 8301c38f2eaSArchie Cobbs moff += chunk; 8311c38f2eaSArchie Cobbs n->m_len += chunk; 8321c38f2eaSArchie Cobbs remain -= chunk; 8331c38f2eaSArchie Cobbs if (moff == m->m_len) { 8341c38f2eaSArchie Cobbs m = m->m_next; 8351c38f2eaSArchie Cobbs moff = 0; 8361c38f2eaSArchie Cobbs } 8371c38f2eaSArchie Cobbs } 8381c38f2eaSArchie Cobbs 8391c38f2eaSArchie Cobbs /* Check correct total mbuf length */ 8401c38f2eaSArchie Cobbs KASSERT((remain > 0 && m != NULL) || (remain == 0 && m == NULL), 8411c38f2eaSArchie Cobbs ("%s: bogus m_pkthdr.len", __FUNCTION__)); 8421c38f2eaSArchie Cobbs } 8431c38f2eaSArchie Cobbs return (top); 8441c38f2eaSArchie Cobbs 8451c38f2eaSArchie Cobbs nospace: 8461c38f2eaSArchie Cobbs m_freem(top); 8475ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 8485ea487f3SAlfred Perlstein mbstat.m_mcfail++; 8495ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 850122a814aSBosko Milekic return (NULL); 8511c38f2eaSArchie Cobbs } 8521c38f2eaSArchie Cobbs 8531c38f2eaSArchie Cobbs /* 854df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 855df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 856df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 857df8bae1dSRodney W. Grimes */ 85826f9a767SRodney W. Grimes void 859122a814aSBosko Milekic m_cat(struct mbuf *m, struct mbuf *n) 860df8bae1dSRodney W. Grimes { 861df8bae1dSRodney W. Grimes while (m->m_next) 862df8bae1dSRodney W. Grimes m = m->m_next; 863df8bae1dSRodney W. Grimes while (n) { 864df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT || 865df8bae1dSRodney W. Grimes m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 866df8bae1dSRodney W. Grimes /* just join the two chains */ 867df8bae1dSRodney W. Grimes m->m_next = n; 868df8bae1dSRodney W. Grimes return; 869df8bae1dSRodney W. Grimes } 870df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 871df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 872df8bae1dSRodney W. Grimes (u_int)n->m_len); 873df8bae1dSRodney W. Grimes m->m_len += n->m_len; 874df8bae1dSRodney W. Grimes n = m_free(n); 875df8bae1dSRodney W. Grimes } 876df8bae1dSRodney W. Grimes } 877df8bae1dSRodney W. Grimes 87826f9a767SRodney W. Grimes void 879122a814aSBosko Milekic m_adj(struct mbuf *mp, int req_len) 880df8bae1dSRodney W. Grimes { 881122a814aSBosko Milekic int len = req_len; 882122a814aSBosko Milekic struct mbuf *m; 883122a814aSBosko Milekic int count; 884df8bae1dSRodney W. Grimes 885df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 886df8bae1dSRodney W. Grimes return; 887df8bae1dSRodney W. Grimes if (len >= 0) { 888df8bae1dSRodney W. Grimes /* 889df8bae1dSRodney W. Grimes * Trim from head. 890df8bae1dSRodney W. Grimes */ 891df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 892df8bae1dSRodney W. Grimes if (m->m_len <= len) { 893df8bae1dSRodney W. Grimes len -= m->m_len; 894df8bae1dSRodney W. Grimes m->m_len = 0; 895df8bae1dSRodney W. Grimes m = m->m_next; 896df8bae1dSRodney W. Grimes } else { 897df8bae1dSRodney W. Grimes m->m_len -= len; 898df8bae1dSRodney W. Grimes m->m_data += len; 899df8bae1dSRodney W. Grimes len = 0; 900df8bae1dSRodney W. Grimes } 901df8bae1dSRodney W. Grimes } 902df8bae1dSRodney W. Grimes m = mp; 903df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 904df8bae1dSRodney W. Grimes m->m_pkthdr.len -= (req_len - len); 905df8bae1dSRodney W. Grimes } else { 906df8bae1dSRodney W. Grimes /* 907df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 908df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 909df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 910df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 911df8bae1dSRodney W. Grimes * after the remaining size. 912df8bae1dSRodney W. Grimes */ 913df8bae1dSRodney W. Grimes len = -len; 914df8bae1dSRodney W. Grimes count = 0; 915df8bae1dSRodney W. Grimes for (;;) { 916df8bae1dSRodney W. Grimes count += m->m_len; 917df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 918df8bae1dSRodney W. Grimes break; 919df8bae1dSRodney W. Grimes m = m->m_next; 920df8bae1dSRodney W. Grimes } 921df8bae1dSRodney W. Grimes if (m->m_len >= len) { 922df8bae1dSRodney W. Grimes m->m_len -= len; 923df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 924df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 925df8bae1dSRodney W. Grimes return; 926df8bae1dSRodney W. Grimes } 927df8bae1dSRodney W. Grimes count -= len; 928df8bae1dSRodney W. Grimes if (count < 0) 929df8bae1dSRodney W. Grimes count = 0; 930df8bae1dSRodney W. Grimes /* 931df8bae1dSRodney W. Grimes * Correct length for chain is "count". 932df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 933df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 934df8bae1dSRodney W. Grimes */ 935df8bae1dSRodney W. Grimes m = mp; 936df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 937df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 938df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 939df8bae1dSRodney W. Grimes if (m->m_len >= count) { 940df8bae1dSRodney W. Grimes m->m_len = count; 941df8bae1dSRodney W. Grimes break; 942df8bae1dSRodney W. Grimes } 943df8bae1dSRodney W. Grimes count -= m->m_len; 944df8bae1dSRodney W. Grimes } 945797f2d22SPoul-Henning Kamp while (m->m_next) 946797f2d22SPoul-Henning Kamp (m = m->m_next) ->m_len = 0; 947df8bae1dSRodney W. Grimes } 948df8bae1dSRodney W. Grimes } 949df8bae1dSRodney W. Grimes 950df8bae1dSRodney W. Grimes /* 951df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 952df8bae1dSRodney W. Grimes * and in the data area of an mbuf (so that mtod and dtom 953df8bae1dSRodney W. Grimes * will work for a structure of size len). Returns the resulting 954df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 955df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 956df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 957df8bae1dSRodney W. Grimes */ 958df8bae1dSRodney W. Grimes struct mbuf * 959122a814aSBosko Milekic m_pullup(struct mbuf *n, int len) 960df8bae1dSRodney W. Grimes { 961122a814aSBosko Milekic struct mbuf *m; 962122a814aSBosko Milekic int count; 963df8bae1dSRodney W. Grimes int space; 964df8bae1dSRodney W. Grimes 965df8bae1dSRodney W. Grimes /* 966df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 967df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 968df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 969df8bae1dSRodney W. Grimes */ 970df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 971df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 972df8bae1dSRodney W. Grimes if (n->m_len >= len) 973df8bae1dSRodney W. Grimes return (n); 974df8bae1dSRodney W. Grimes m = n; 975df8bae1dSRodney W. Grimes n = n->m_next; 976df8bae1dSRodney W. Grimes len -= m->m_len; 977df8bae1dSRodney W. Grimes } else { 978df8bae1dSRodney W. Grimes if (len > MHLEN) 979df8bae1dSRodney W. Grimes goto bad; 980df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, n->m_type); 981122a814aSBosko Milekic if (m == NULL) 982df8bae1dSRodney W. Grimes goto bad; 983df8bae1dSRodney W. Grimes m->m_len = 0; 984df8bae1dSRodney W. Grimes if (n->m_flags & M_PKTHDR) { 985df8bae1dSRodney W. Grimes M_COPY_PKTHDR(m, n); 986df8bae1dSRodney W. Grimes n->m_flags &= ~M_PKTHDR; 987df8bae1dSRodney W. Grimes } 988df8bae1dSRodney W. Grimes } 989df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 990df8bae1dSRodney W. Grimes do { 991df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 992df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 993df8bae1dSRodney W. Grimes (unsigned)count); 994df8bae1dSRodney W. Grimes len -= count; 995df8bae1dSRodney W. Grimes m->m_len += count; 996df8bae1dSRodney W. Grimes n->m_len -= count; 997df8bae1dSRodney W. Grimes space -= count; 998df8bae1dSRodney W. Grimes if (n->m_len) 999df8bae1dSRodney W. Grimes n->m_data += count; 1000df8bae1dSRodney W. Grimes else 1001df8bae1dSRodney W. Grimes n = m_free(n); 1002df8bae1dSRodney W. Grimes } while (len > 0 && n); 1003df8bae1dSRodney W. Grimes if (len > 0) { 1004df8bae1dSRodney W. Grimes (void) m_free(m); 1005df8bae1dSRodney W. Grimes goto bad; 1006df8bae1dSRodney W. Grimes } 1007df8bae1dSRodney W. Grimes m->m_next = n; 1008df8bae1dSRodney W. Grimes return (m); 1009df8bae1dSRodney W. Grimes bad: 1010df8bae1dSRodney W. Grimes m_freem(n); 10115ea487f3SAlfred Perlstein mtx_lock(&mbuf_mtx); 1012629db604SBosko Milekic mbstat.m_mpfail++; 10135ea487f3SAlfred Perlstein mtx_unlock(&mbuf_mtx); 1014122a814aSBosko Milekic return (NULL); 1015df8bae1dSRodney W. Grimes } 1016df8bae1dSRodney W. Grimes 1017df8bae1dSRodney W. Grimes /* 1018df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 1019df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 1020df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 1021df8bae1dSRodney W. Grimes */ 1022df8bae1dSRodney W. Grimes struct mbuf * 1023122a814aSBosko Milekic m_split(struct mbuf *m0, int len0, int wait) 1024df8bae1dSRodney W. Grimes { 1025122a814aSBosko Milekic struct mbuf *m, *n; 1026df8bae1dSRodney W. Grimes unsigned len = len0, remain; 1027df8bae1dSRodney W. Grimes 1028df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 1029df8bae1dSRodney W. Grimes len -= m->m_len; 1030122a814aSBosko Milekic if (m == NULL) 1031122a814aSBosko Milekic return (NULL); 1032df8bae1dSRodney W. Grimes remain = m->m_len - len; 1033df8bae1dSRodney W. Grimes if (m0->m_flags & M_PKTHDR) { 1034df8bae1dSRodney W. Grimes MGETHDR(n, wait, m0->m_type); 1035122a814aSBosko Milekic if (n == NULL) 1036122a814aSBosko Milekic return (NULL); 1037df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 1038df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 1039df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 1040df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 1041df8bae1dSRodney W. Grimes goto extpacket; 1042df8bae1dSRodney W. Grimes if (remain > MHLEN) { 1043df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 1044df8bae1dSRodney W. Grimes MH_ALIGN(n, 0); 1045df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 1046122a814aSBosko Milekic if (n->m_next == NULL) { 1047df8bae1dSRodney W. Grimes (void) m_free(n); 1048122a814aSBosko Milekic return (NULL); 1049df8bae1dSRodney W. Grimes } else 1050df8bae1dSRodney W. Grimes return (n); 1051df8bae1dSRodney W. Grimes } else 1052df8bae1dSRodney W. Grimes MH_ALIGN(n, remain); 1053df8bae1dSRodney W. Grimes } else if (remain == 0) { 1054df8bae1dSRodney W. Grimes n = m->m_next; 1055122a814aSBosko Milekic m->m_next = NULL; 1056df8bae1dSRodney W. Grimes return (n); 1057df8bae1dSRodney W. Grimes } else { 1058df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 1059122a814aSBosko Milekic if (n == NULL) 1060122a814aSBosko Milekic return (NULL); 1061df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 1062df8bae1dSRodney W. Grimes } 1063df8bae1dSRodney W. Grimes extpacket: 1064df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 1065df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 1066df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 1067a5c4836dSDavid Malone MEXT_ADD_REF(m); 1068df8bae1dSRodney W. Grimes m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ 1069df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 1070df8bae1dSRodney W. Grimes } else { 1071df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes n->m_len = remain; 1074df8bae1dSRodney W. Grimes m->m_len = len; 1075df8bae1dSRodney W. Grimes n->m_next = m->m_next; 1076122a814aSBosko Milekic m->m_next = NULL; 1077df8bae1dSRodney W. Grimes return (n); 1078df8bae1dSRodney W. Grimes } 1079df8bae1dSRodney W. Grimes /* 1080df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 1081f5eece3fSBosko Milekic * Note that `off' argument is offset into first mbuf of target chain from 1082f5eece3fSBosko Milekic * which to begin copying the data to. 1083df8bae1dSRodney W. Grimes */ 1084df8bae1dSRodney W. Grimes struct mbuf * 1085f5eece3fSBosko Milekic m_devget(char *buf, int totlen, int off, struct ifnet *ifp, 1086122a814aSBosko Milekic void (*copy)(char *from, caddr_t to, u_int len)) 1087df8bae1dSRodney W. Grimes { 1088122a814aSBosko Milekic struct mbuf *m; 1089df8bae1dSRodney W. Grimes struct mbuf *top = 0, **mp = ⊤ 1090f5eece3fSBosko Milekic int len; 1091df8bae1dSRodney W. Grimes 1092f5eece3fSBosko Milekic if (off < 0 || off > MHLEN) 1093f5eece3fSBosko Milekic return (NULL); 1094f5eece3fSBosko Milekic 1095df8bae1dSRodney W. Grimes MGETHDR(m, M_DONTWAIT, MT_DATA); 1096122a814aSBosko Milekic if (m == NULL) 1097122a814aSBosko Milekic return (NULL); 1098df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 1099df8bae1dSRodney W. Grimes m->m_pkthdr.len = totlen; 1100f5eece3fSBosko Milekic len = MHLEN; 1101df8bae1dSRodney W. Grimes 1102df8bae1dSRodney W. Grimes while (totlen > 0) { 1103df8bae1dSRodney W. Grimes if (top) { 1104df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_DATA); 1105122a814aSBosko Milekic if (m == NULL) { 1106df8bae1dSRodney W. Grimes m_freem(top); 1107122a814aSBosko Milekic return (NULL); 1108df8bae1dSRodney W. Grimes } 1109f5eece3fSBosko Milekic len = MLEN; 1110df8bae1dSRodney W. Grimes } 1111f5eece3fSBosko Milekic if (totlen + off >= MINCLSIZE) { 1112df8bae1dSRodney W. Grimes MCLGET(m, M_DONTWAIT); 1113df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 1114f5eece3fSBosko Milekic len = MCLBYTES; 1115df8bae1dSRodney W. Grimes } else { 1116df8bae1dSRodney W. Grimes /* 1117df8bae1dSRodney W. Grimes * Place initial small packet/header at end of mbuf. 1118df8bae1dSRodney W. Grimes */ 1119f5eece3fSBosko Milekic if (top == NULL && totlen + off + max_linkhdr <= len) { 1120df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 1121f5eece3fSBosko Milekic len -= max_linkhdr; 1122df8bae1dSRodney W. Grimes } 1123f5eece3fSBosko Milekic } 1124f5eece3fSBosko Milekic if (off) { 1125f5eece3fSBosko Milekic m->m_data += off; 1126f5eece3fSBosko Milekic len -= off; 1127f5eece3fSBosko Milekic off = 0; 1128f5eece3fSBosko Milekic } 1129f5eece3fSBosko Milekic m->m_len = len = min(totlen, len); 1130df8bae1dSRodney W. Grimes if (copy) 1131f5eece3fSBosko Milekic copy(buf, mtod(m, caddr_t), (unsigned)len); 1132df8bae1dSRodney W. Grimes else 1133f5eece3fSBosko Milekic bcopy(buf, mtod(m, caddr_t), (unsigned)len); 1134f5eece3fSBosko Milekic buf += len; 1135df8bae1dSRodney W. Grimes *mp = m; 1136df8bae1dSRodney W. Grimes mp = &m->m_next; 1137df8bae1dSRodney W. Grimes totlen -= len; 1138df8bae1dSRodney W. Grimes } 1139df8bae1dSRodney W. Grimes return (top); 1140df8bae1dSRodney W. Grimes } 1141c5789ba3SPoul-Henning Kamp 1142c5789ba3SPoul-Henning Kamp /* 1143c5789ba3SPoul-Henning Kamp * Copy data from a buffer back into the indicated mbuf chain, 1144c5789ba3SPoul-Henning Kamp * starting "off" bytes from the beginning, extending the mbuf 1145c5789ba3SPoul-Henning Kamp * chain if necessary. 1146c5789ba3SPoul-Henning Kamp */ 1147c5789ba3SPoul-Henning Kamp void 1148122a814aSBosko Milekic m_copyback(struct mbuf *m0, int off, int len, caddr_t cp) 1149c5789ba3SPoul-Henning Kamp { 1150122a814aSBosko Milekic int mlen; 1151122a814aSBosko Milekic struct mbuf *m = m0, *n; 1152c5789ba3SPoul-Henning Kamp int totlen = 0; 1153c5789ba3SPoul-Henning Kamp 1154122a814aSBosko Milekic if (m0 == NULL) 1155c5789ba3SPoul-Henning Kamp return; 1156c5789ba3SPoul-Henning Kamp while (off > (mlen = m->m_len)) { 1157c5789ba3SPoul-Henning Kamp off -= mlen; 1158c5789ba3SPoul-Henning Kamp totlen += mlen; 1159122a814aSBosko Milekic if (m->m_next == NULL) { 1160c5789ba3SPoul-Henning Kamp n = m_getclr(M_DONTWAIT, m->m_type); 1161122a814aSBosko Milekic if (n == NULL) 1162c5789ba3SPoul-Henning Kamp goto out; 1163c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len + off); 1164c5789ba3SPoul-Henning Kamp m->m_next = n; 1165c5789ba3SPoul-Henning Kamp } 1166c5789ba3SPoul-Henning Kamp m = m->m_next; 1167c5789ba3SPoul-Henning Kamp } 1168c5789ba3SPoul-Henning Kamp while (len > 0) { 1169c5789ba3SPoul-Henning Kamp mlen = min (m->m_len - off, len); 1170c5789ba3SPoul-Henning Kamp bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 1171c5789ba3SPoul-Henning Kamp cp += mlen; 1172c5789ba3SPoul-Henning Kamp len -= mlen; 1173c5789ba3SPoul-Henning Kamp mlen += off; 1174c5789ba3SPoul-Henning Kamp off = 0; 1175c5789ba3SPoul-Henning Kamp totlen += mlen; 1176c5789ba3SPoul-Henning Kamp if (len == 0) 1177c5789ba3SPoul-Henning Kamp break; 1178122a814aSBosko Milekic if (m->m_next == NULL) { 1179c5789ba3SPoul-Henning Kamp n = m_get(M_DONTWAIT, m->m_type); 1180122a814aSBosko Milekic if (n == NULL) 1181c5789ba3SPoul-Henning Kamp break; 1182c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len); 1183c5789ba3SPoul-Henning Kamp m->m_next = n; 1184c5789ba3SPoul-Henning Kamp } 1185c5789ba3SPoul-Henning Kamp m = m->m_next; 1186c5789ba3SPoul-Henning Kamp } 1187c5789ba3SPoul-Henning Kamp out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 1188c5789ba3SPoul-Henning Kamp m->m_pkthdr.len = totlen; 1189c5789ba3SPoul-Henning Kamp } 1190ce4a64f7SPoul-Henning Kamp 1191ce4a64f7SPoul-Henning Kamp void 1192ce4a64f7SPoul-Henning Kamp m_print(const struct mbuf *m) 1193ce4a64f7SPoul-Henning Kamp { 1194ce4a64f7SPoul-Henning Kamp int len; 11956357e7b5SEivind Eklund const struct mbuf *m2; 1196ce4a64f7SPoul-Henning Kamp 1197ce4a64f7SPoul-Henning Kamp len = m->m_pkthdr.len; 1198ce4a64f7SPoul-Henning Kamp m2 = m; 1199ce4a64f7SPoul-Henning Kamp while (len) { 1200ce4a64f7SPoul-Henning Kamp printf("%p %*D\n", m2, m2->m_len, (u_char *)m2->m_data, "-"); 1201ce4a64f7SPoul-Henning Kamp len -= m2->m_len; 1202ce4a64f7SPoul-Henning Kamp m2 = m2->m_next; 1203ce4a64f7SPoul-Henning Kamp } 1204ce4a64f7SPoul-Henning Kamp return; 1205ce4a64f7SPoul-Henning Kamp } 1206