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> 4064cfdf46SBruce Evans #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 42df8bae1dSRodney W. Grimes #include <sys/kernel.h> 43639acc13SGarrett Wollman #include <sys/sysctl.h> 44df8bae1dSRodney W. Grimes #include <sys/domain.h> 45df8bae1dSRodney W. Grimes #include <sys/protosw.h> 46df8bae1dSRodney W. Grimes 47df8bae1dSRodney W. Grimes #include <vm/vm.h> 4828f8db14SBruce Evans #include <vm/vm_kern.h> 49efeaf95aSDavid Greenman #include <vm/vm_extern.h> 50df8bae1dSRodney W. Grimes 514590fd3aSDavid Greenman static void mbinit __P((void *)); 522b14f991SJulian Elischer SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) 532b14f991SJulian Elischer 54df8bae1dSRodney W. Grimes struct mbuf *mbutl; 55df8bae1dSRodney W. Grimes char *mclrefcnt; 5628f8db14SBruce Evans struct mbstat mbstat; 576a06dea0SGarrett Wollman struct mbuf *mmbfree; 5828f8db14SBruce Evans union mcluster *mclfree; 5928f8db14SBruce Evans int max_linkhdr; 6028f8db14SBruce Evans int max_protohdr; 6128f8db14SBruce Evans int max_hdr; 6228f8db14SBruce Evans int max_datalen; 63134c934cSMike Smith int nmbclusters; 64134c934cSMike Smith int nmbufs; 65df8bae1dSRodney W. Grimes 66ce02431fSDoug Rabson SYSCTL_DECL(_kern_ipc); 67639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_LINKHDR, max_linkhdr, CTLFLAG_RW, 68639acc13SGarrett Wollman &max_linkhdr, 0, ""); 69639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_PROTOHDR, max_protohdr, CTLFLAG_RW, 70639acc13SGarrett Wollman &max_protohdr, 0, ""); 71639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RW, &max_hdr, 0, ""); 72639acc13SGarrett Wollman SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RW, 73639acc13SGarrett Wollman &max_datalen, 0, ""); 74639acc13SGarrett Wollman SYSCTL_STRUCT(_kern_ipc, KIPC_MBSTAT, mbstat, CTLFLAG_RW, &mbstat, mbstat, ""); 75134c934cSMike Smith SYSCTL_INT(_kern_ipc, KIPC_NMBCLUSTERS, nmbclusters, CTLFLAG_RD, 76134c934cSMike Smith &nmbclusters, 0, "Maximum number of mbuf clusters avaliable"); 77134c934cSMike Smith #ifndef NMBCLUSTERS 78134c934cSMike Smith #define NMBCLUSTERS (512 + MAXUSERS * 16) 79134c934cSMike Smith #endif 80134c934cSMike Smith TUNABLE_INT_DECL("kern.ipc.nmbclusters", NMBCLUSTERS, nmbclusters); 81134c934cSMike Smith TUNABLE_INT_DECL("kern.ipc.nmbufs", NMBCLUSTERS * 4, nmbufs); /* XXX fixup? */ 82639acc13SGarrett Wollman 8387b6de2bSPoul-Henning Kamp static void m_reclaim __P((void)); 8487b6de2bSPoul-Henning Kamp 850482730eSPoul-Henning Kamp /* "number of clusters of pages" */ 860482730eSPoul-Henning Kamp #define NCL_INIT 1 870482730eSPoul-Henning Kamp 887642f474SPoul-Henning Kamp #define NMB_INIT 16 897642f474SPoul-Henning Kamp 902b14f991SJulian Elischer /* ARGSUSED*/ 912b14f991SJulian Elischer static void 92d841aaa7SBruce Evans mbinit(dummy) 93d841aaa7SBruce Evans void *dummy; 94df8bae1dSRodney W. Grimes { 95df8bae1dSRodney W. Grimes int s; 96df8bae1dSRodney W. Grimes 976a06dea0SGarrett Wollman mmbfree = NULL; mclfree = NULL; 98639acc13SGarrett Wollman mbstat.m_msize = MSIZE; 99639acc13SGarrett Wollman mbstat.m_mclbytes = MCLBYTES; 100639acc13SGarrett Wollman mbstat.m_minclsize = MINCLSIZE; 101639acc13SGarrett Wollman mbstat.m_mlen = MLEN; 102639acc13SGarrett Wollman mbstat.m_mhlen = MHLEN; 103639acc13SGarrett Wollman 104df8bae1dSRodney W. Grimes s = splimp(); 1056a06dea0SGarrett Wollman if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0) 1066a06dea0SGarrett Wollman goto bad; 10730f700e9SGarrett Wollman #if MCLBYTES <= PAGE_SIZE 108df8bae1dSRodney W. Grimes if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 109df8bae1dSRodney W. Grimes goto bad; 11030f700e9SGarrett Wollman #else 11130f700e9SGarrett Wollman /* It's OK to call contigmalloc in this context. */ 11264cfdf46SBruce Evans if (m_clalloc(16, M_WAIT) == 0) 11330f700e9SGarrett Wollman goto bad; 11430f700e9SGarrett Wollman #endif 115df8bae1dSRodney W. Grimes splx(s); 116df8bae1dSRodney W. Grimes return; 117df8bae1dSRodney W. Grimes bad: 118df8bae1dSRodney W. Grimes panic("mbinit"); 119df8bae1dSRodney W. Grimes } 120df8bae1dSRodney W. Grimes 121df8bae1dSRodney W. Grimes /* 1226a06dea0SGarrett Wollman * Allocate at least nmb mbufs and place on mbuf free list. 1236a06dea0SGarrett Wollman * Must be called at splimp. 1246a06dea0SGarrett Wollman */ 1256a06dea0SGarrett Wollman /* ARGSUSED */ 1266a06dea0SGarrett Wollman int 12764cfdf46SBruce Evans m_mballoc(nmb, how) 1286a06dea0SGarrett Wollman register int nmb; 12964cfdf46SBruce Evans int how; 1306a06dea0SGarrett Wollman { 1316a06dea0SGarrett Wollman register caddr_t p; 1326a06dea0SGarrett Wollman register int i; 1336a06dea0SGarrett Wollman int nbytes; 1346a06dea0SGarrett Wollman 1356a06dea0SGarrett Wollman /* Once we run out of map space, it will be impossible to get 1366a06dea0SGarrett Wollman * any more (nothing is ever freed back to the map) (XXX which 1376a06dea0SGarrett Wollman * is dumb). (however you are not dead as m_reclaim might 1386a06dea0SGarrett Wollman * still be able to free a substantial amount of space). 1396a06dea0SGarrett Wollman */ 1406a06dea0SGarrett Wollman if (mb_map_full) 1416a06dea0SGarrett Wollman return (0); 1426a06dea0SGarrett Wollman 1436a06dea0SGarrett Wollman nbytes = round_page(nmb * MSIZE); 144d8392c6cSGarrett Wollman p = (caddr_t)kmem_malloc(mb_map, nbytes, M_NOWAIT); 14564cfdf46SBruce Evans if (p == 0 && how == M_WAIT) { 146d8392c6cSGarrett Wollman mbstat.m_wait++; 147d8392c6cSGarrett Wollman p = (caddr_t)kmem_malloc(mb_map, nbytes, M_WAITOK); 148d8392c6cSGarrett Wollman } 149d8392c6cSGarrett Wollman 1506a06dea0SGarrett Wollman /* 15164cfdf46SBruce Evans * Either the map is now full, or `how' is M_NOWAIT and there 1526a06dea0SGarrett Wollman * are no pages left. 1536a06dea0SGarrett Wollman */ 1546a06dea0SGarrett Wollman if (p == NULL) 1556a06dea0SGarrett Wollman return (0); 1566a06dea0SGarrett Wollman 1576a06dea0SGarrett Wollman nmb = nbytes / MSIZE; 1586a06dea0SGarrett Wollman for (i = 0; i < nmb; i++) { 1596a06dea0SGarrett Wollman ((struct mbuf *)p)->m_next = mmbfree; 1606a06dea0SGarrett Wollman mmbfree = (struct mbuf *)p; 1616a06dea0SGarrett Wollman p += MSIZE; 1626a06dea0SGarrett Wollman } 1636a06dea0SGarrett Wollman mbstat.m_mbufs += nmb; 1646a06dea0SGarrett Wollman return (1); 1656a06dea0SGarrett Wollman } 1666a06dea0SGarrett Wollman 16730f700e9SGarrett Wollman #if MCLBYTES > PAGE_SIZE 168d8392c6cSGarrett Wollman static int i_want_my_mcl; 16930f700e9SGarrett Wollman 170d8392c6cSGarrett Wollman static void 17130f700e9SGarrett Wollman kproc_mclalloc(void) 17230f700e9SGarrett Wollman { 17330f700e9SGarrett Wollman int status; 17430f700e9SGarrett Wollman 17530f700e9SGarrett Wollman while (1) { 17630f700e9SGarrett Wollman tsleep(&i_want_my_mcl, PVM, "mclalloc", 0); 17730f700e9SGarrett Wollman 17830f700e9SGarrett Wollman for (; i_want_my_mcl; i_want_my_mcl--) { 17964cfdf46SBruce Evans if (m_clalloc(1, M_WAIT) == 0) 18030f700e9SGarrett Wollman printf("m_clalloc failed even in process context!\n"); 18130f700e9SGarrett Wollman } 18230f700e9SGarrett Wollman } 18330f700e9SGarrett Wollman } 18430f700e9SGarrett Wollman 18530f700e9SGarrett Wollman static struct proc *mclallocproc; 18630f700e9SGarrett Wollman static struct kproc_desc mclalloc_kp = { 18730f700e9SGarrett Wollman "mclalloc", 18830f700e9SGarrett Wollman kproc_mclalloc, 18930f700e9SGarrett Wollman &mclallocproc 19030f700e9SGarrett Wollman }; 1919c8b8baaSPeter Wemm SYSINIT(mclallocproc, SI_SUB_KTHREAD_UPDATE, SI_ORDER_ANY, kproc_start, 19230f700e9SGarrett Wollman &mclalloc_kp); 19330f700e9SGarrett Wollman #endif 19430f700e9SGarrett Wollman 1956a06dea0SGarrett Wollman /* 196df8bae1dSRodney W. Grimes * Allocate some number of mbuf clusters 197df8bae1dSRodney W. Grimes * and place on cluster free list. 198df8bae1dSRodney W. Grimes * Must be called at splimp. 199df8bae1dSRodney W. Grimes */ 200df8bae1dSRodney W. Grimes /* ARGSUSED */ 20126f9a767SRodney W. Grimes int 20264cfdf46SBruce Evans m_clalloc(ncl, how) 203df8bae1dSRodney W. Grimes register int ncl; 20464cfdf46SBruce Evans int how; 205df8bae1dSRodney W. Grimes { 206df8bae1dSRodney W. Grimes register caddr_t p; 207df8bae1dSRodney W. Grimes register int i; 208df8bae1dSRodney W. Grimes int npg; 209df8bae1dSRodney W. Grimes 2105eb7d0cdSDavid Greenman /* 2115eb7d0cdSDavid Greenman * Once we run out of map space, it will be impossible 2125eb7d0cdSDavid Greenman * to get any more (nothing is ever freed back to the 2135eb7d0cdSDavid Greenman * map). 2145eb7d0cdSDavid Greenman */ 215d8392c6cSGarrett Wollman if (mb_map_full) { 216d8392c6cSGarrett Wollman mbstat.m_drops++; 2175eb7d0cdSDavid Greenman return (0); 218d8392c6cSGarrett Wollman } 2195eb7d0cdSDavid Greenman 22030f700e9SGarrett Wollman #if MCLBYTES > PAGE_SIZE 22164cfdf46SBruce Evans if (how != M_WAIT) { 22230f700e9SGarrett Wollman i_want_my_mcl += ncl; 22330f700e9SGarrett Wollman wakeup(&i_want_my_mcl); 224d8392c6cSGarrett Wollman mbstat.m_wait++; 22530f700e9SGarrett Wollman p = 0; 22630f700e9SGarrett Wollman } else { 22730f700e9SGarrett Wollman p = contigmalloc1(MCLBYTES * ncl, M_DEVBUF, M_WAITOK, 0ul, 22830f700e9SGarrett Wollman ~0ul, PAGE_SIZE, 0, mb_map); 22930f700e9SGarrett Wollman } 23030f700e9SGarrett Wollman #else 231e911eafcSPoul-Henning Kamp npg = ncl; 232649c409dSDavid Greenman p = (caddr_t)kmem_malloc(mb_map, ctob(npg), 23364cfdf46SBruce Evans how != M_WAIT ? M_NOWAIT : M_WAITOK); 23430f700e9SGarrett Wollman ncl = ncl * PAGE_SIZE / MCLBYTES; 23530f700e9SGarrett Wollman #endif 2365eb7d0cdSDavid Greenman /* 23764cfdf46SBruce Evans * Either the map is now full, or `how' is M_NOWAIT and there 2385eb7d0cdSDavid Greenman * are no pages left. 2395eb7d0cdSDavid Greenman */ 240d8392c6cSGarrett Wollman if (p == NULL) { 241d8392c6cSGarrett Wollman mbstat.m_drops++; 242df8bae1dSRodney W. Grimes return (0); 243d8392c6cSGarrett Wollman } 2445eb7d0cdSDavid Greenman 245df8bae1dSRodney W. Grimes for (i = 0; i < ncl; i++) { 246df8bae1dSRodney W. Grimes ((union mcluster *)p)->mcl_next = mclfree; 247df8bae1dSRodney W. Grimes mclfree = (union mcluster *)p; 248df8bae1dSRodney W. Grimes p += MCLBYTES; 249df8bae1dSRodney W. Grimes mbstat.m_clfree++; 250df8bae1dSRodney W. Grimes } 251df8bae1dSRodney W. Grimes mbstat.m_clusters += ncl; 252df8bae1dSRodney W. Grimes return (1); 253df8bae1dSRodney W. Grimes } 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes /* 256eca2dddaSDag-Erling Smørgrav * When MGET fails, ask protocols to free space when short of memory, 257df8bae1dSRodney W. Grimes * then re-attempt to allocate an mbuf. 258df8bae1dSRodney W. Grimes */ 259df8bae1dSRodney W. Grimes struct mbuf * 260df8bae1dSRodney W. Grimes m_retry(i, t) 261df8bae1dSRodney W. Grimes int i, t; 262df8bae1dSRodney W. Grimes { 263df8bae1dSRodney W. Grimes register struct mbuf *m; 264df8bae1dSRodney W. Grimes 26501ddfa33SDavid Greenman /* 26601ddfa33SDavid Greenman * Must only do the reclaim if not in an interrupt context. 26701ddfa33SDavid Greenman */ 26801ddfa33SDavid Greenman if (i == M_WAIT) 269df8bae1dSRodney W. Grimes m_reclaim(); 270df8bae1dSRodney W. Grimes #define m_retry(i, t) (struct mbuf *)0 271df8bae1dSRodney W. Grimes MGET(m, i, t); 272df8bae1dSRodney W. Grimes #undef m_retry 2739523f5c1SDavid Greenman if (m != NULL) { 2749b4b42d1SDavid Greenman mbstat.m_wait++; 2759523f5c1SDavid Greenman } else { 2769523f5c1SDavid Greenman if (i == M_DONTWAIT) 2779b4b42d1SDavid Greenman mbstat.m_drops++; 2789523f5c1SDavid Greenman else 2799523f5c1SDavid Greenman panic("Out of mbuf clusters"); 2809523f5c1SDavid Greenman } 281df8bae1dSRodney W. Grimes return (m); 282df8bae1dSRodney W. Grimes } 283df8bae1dSRodney W. Grimes 284df8bae1dSRodney W. Grimes /* 285df8bae1dSRodney W. Grimes * As above; retry an MGETHDR. 286df8bae1dSRodney W. Grimes */ 287df8bae1dSRodney W. Grimes struct mbuf * 288df8bae1dSRodney W. Grimes m_retryhdr(i, t) 289df8bae1dSRodney W. Grimes int i, t; 290df8bae1dSRodney W. Grimes { 291df8bae1dSRodney W. Grimes register struct mbuf *m; 292df8bae1dSRodney W. Grimes 29301ddfa33SDavid Greenman /* 29401ddfa33SDavid Greenman * Must only do the reclaim if not in an interrupt context. 29501ddfa33SDavid Greenman */ 29601ddfa33SDavid Greenman if (i == M_WAIT) 297df8bae1dSRodney W. Grimes m_reclaim(); 298df8bae1dSRodney W. Grimes #define m_retryhdr(i, t) (struct mbuf *)0 299df8bae1dSRodney W. Grimes MGETHDR(m, i, t); 300df8bae1dSRodney W. Grimes #undef m_retryhdr 3019523f5c1SDavid Greenman if (m != NULL) { 3029b4b42d1SDavid Greenman mbstat.m_wait++; 3039523f5c1SDavid Greenman } else { 3049523f5c1SDavid Greenman if (i == M_DONTWAIT) 3059b4b42d1SDavid Greenman mbstat.m_drops++; 3069523f5c1SDavid Greenman else 3079523f5c1SDavid Greenman panic("Out of mbuf clusters"); 3089523f5c1SDavid Greenman } 309df8bae1dSRodney W. Grimes return (m); 310df8bae1dSRodney W. Grimes } 311df8bae1dSRodney W. Grimes 31287b6de2bSPoul-Henning Kamp static void 313df8bae1dSRodney W. Grimes m_reclaim() 314df8bae1dSRodney W. Grimes { 315df8bae1dSRodney W. Grimes register struct domain *dp; 316df8bae1dSRodney W. Grimes register struct protosw *pr; 317df8bae1dSRodney W. Grimes int s = splimp(); 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes for (dp = domains; dp; dp = dp->dom_next) 320df8bae1dSRodney W. Grimes for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 321df8bae1dSRodney W. Grimes if (pr->pr_drain) 322df8bae1dSRodney W. Grimes (*pr->pr_drain)(); 323df8bae1dSRodney W. Grimes splx(s); 324df8bae1dSRodney W. Grimes mbstat.m_drain++; 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes /* 328df8bae1dSRodney W. Grimes * Space allocation routines. 329df8bae1dSRodney W. Grimes * These are also available as macros 330df8bae1dSRodney W. Grimes * for critical paths. 331df8bae1dSRodney W. Grimes */ 332df8bae1dSRodney W. Grimes struct mbuf * 33364cfdf46SBruce Evans m_get(how, type) 33464cfdf46SBruce Evans int how, type; 335df8bae1dSRodney W. Grimes { 336df8bae1dSRodney W. Grimes register struct mbuf *m; 337df8bae1dSRodney W. Grimes 33864cfdf46SBruce Evans MGET(m, how, type); 339df8bae1dSRodney W. Grimes return (m); 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes 342df8bae1dSRodney W. Grimes struct mbuf * 34364cfdf46SBruce Evans m_gethdr(how, type) 34464cfdf46SBruce Evans int how, type; 345df8bae1dSRodney W. Grimes { 346df8bae1dSRodney W. Grimes register struct mbuf *m; 347df8bae1dSRodney W. Grimes 34864cfdf46SBruce Evans MGETHDR(m, how, type); 349df8bae1dSRodney W. Grimes return (m); 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes struct mbuf * 35364cfdf46SBruce Evans m_getclr(how, type) 35464cfdf46SBruce Evans int how, type; 355df8bae1dSRodney W. Grimes { 356df8bae1dSRodney W. Grimes register struct mbuf *m; 357df8bae1dSRodney W. Grimes 35864cfdf46SBruce Evans MGET(m, how, type); 359df8bae1dSRodney W. Grimes if (m == 0) 360df8bae1dSRodney W. Grimes return (0); 361df8bae1dSRodney W. Grimes bzero(mtod(m, caddr_t), MLEN); 362df8bae1dSRodney W. Grimes return (m); 363df8bae1dSRodney W. Grimes } 364df8bae1dSRodney W. Grimes 365df8bae1dSRodney W. Grimes struct mbuf * 366df8bae1dSRodney W. Grimes m_free(m) 367df8bae1dSRodney W. Grimes struct mbuf *m; 368df8bae1dSRodney W. Grimes { 369df8bae1dSRodney W. Grimes register struct mbuf *n; 370df8bae1dSRodney W. Grimes 371df8bae1dSRodney W. Grimes MFREE(m, n); 372df8bae1dSRodney W. Grimes return (n); 373df8bae1dSRodney W. Grimes } 374df8bae1dSRodney W. Grimes 375df8bae1dSRodney W. Grimes void 376df8bae1dSRodney W. Grimes m_freem(m) 377df8bae1dSRodney W. Grimes register struct mbuf *m; 378df8bae1dSRodney W. Grimes { 379df8bae1dSRodney W. Grimes register struct mbuf *n; 380df8bae1dSRodney W. Grimes 381df8bae1dSRodney W. Grimes if (m == NULL) 382df8bae1dSRodney W. Grimes return; 383df8bae1dSRodney W. Grimes do { 384df8bae1dSRodney W. Grimes MFREE(m, n); 385797f2d22SPoul-Henning Kamp m = n; 386797f2d22SPoul-Henning Kamp } while (m); 387df8bae1dSRodney W. Grimes } 388df8bae1dSRodney W. Grimes 389df8bae1dSRodney W. Grimes /* 390df8bae1dSRodney W. Grimes * Mbuffer utility routines. 391df8bae1dSRodney W. Grimes */ 392df8bae1dSRodney W. Grimes 393df8bae1dSRodney W. Grimes /* 394df8bae1dSRodney W. Grimes * Lesser-used path for M_PREPEND: 395df8bae1dSRodney W. Grimes * allocate new mbuf to prepend to chain, 396df8bae1dSRodney W. Grimes * copy junk along. 397df8bae1dSRodney W. Grimes */ 398df8bae1dSRodney W. Grimes struct mbuf * 399df8bae1dSRodney W. Grimes m_prepend(m, len, how) 400df8bae1dSRodney W. Grimes register struct mbuf *m; 401df8bae1dSRodney W. Grimes int len, how; 402df8bae1dSRodney W. Grimes { 403df8bae1dSRodney W. Grimes struct mbuf *mn; 404df8bae1dSRodney W. Grimes 405df8bae1dSRodney W. Grimes MGET(mn, how, m->m_type); 406df8bae1dSRodney W. Grimes if (mn == (struct mbuf *)NULL) { 407df8bae1dSRodney W. Grimes m_freem(m); 408df8bae1dSRodney W. Grimes return ((struct mbuf *)NULL); 409df8bae1dSRodney W. Grimes } 410df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { 411df8bae1dSRodney W. Grimes M_COPY_PKTHDR(mn, m); 412df8bae1dSRodney W. Grimes m->m_flags &= ~M_PKTHDR; 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes mn->m_next = m; 415df8bae1dSRodney W. Grimes m = mn; 416df8bae1dSRodney W. Grimes if (len < MHLEN) 417df8bae1dSRodney W. Grimes MH_ALIGN(m, len); 418df8bae1dSRodney W. Grimes m->m_len = len; 419df8bae1dSRodney W. Grimes return (m); 420df8bae1dSRodney W. Grimes } 421df8bae1dSRodney W. Grimes 422df8bae1dSRodney W. Grimes /* 423df8bae1dSRodney W. Grimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 424df8bae1dSRodney W. Grimes * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 425df8bae1dSRodney W. Grimes * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. 426df8bae1dSRodney W. Grimes */ 427639acc13SGarrett Wollman #define MCFail (mbstat.m_mcfail) 428df8bae1dSRodney W. Grimes 429df8bae1dSRodney W. Grimes struct mbuf * 430df8bae1dSRodney W. Grimes m_copym(m, off0, len, wait) 431df8bae1dSRodney W. Grimes register struct mbuf *m; 432df8bae1dSRodney W. Grimes int off0, wait; 433df8bae1dSRodney W. Grimes register int len; 434df8bae1dSRodney W. Grimes { 435df8bae1dSRodney W. Grimes register struct mbuf *n, **np; 436df8bae1dSRodney W. Grimes register int off = off0; 437df8bae1dSRodney W. Grimes struct mbuf *top; 438df8bae1dSRodney W. Grimes int copyhdr = 0; 439df8bae1dSRodney W. Grimes 440e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copym, negative off %d", off)); 441e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copym, negative len %d", len)); 442df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 443df8bae1dSRodney W. Grimes copyhdr = 1; 444df8bae1dSRodney W. Grimes while (off > 0) { 445e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain")); 446df8bae1dSRodney W. Grimes if (off < m->m_len) 447df8bae1dSRodney W. Grimes break; 448df8bae1dSRodney W. Grimes off -= m->m_len; 449df8bae1dSRodney W. Grimes m = m->m_next; 450df8bae1dSRodney W. Grimes } 451df8bae1dSRodney W. Grimes np = ⊤ 452df8bae1dSRodney W. Grimes top = 0; 453df8bae1dSRodney W. Grimes while (len > 0) { 454df8bae1dSRodney W. Grimes if (m == 0) { 455e0a653ddSAlfred Perlstein KASSERT(len == M_COPYALL, 456e0a653ddSAlfred Perlstein ("m_copym, length > size of mbuf chain")); 457df8bae1dSRodney W. Grimes break; 458df8bae1dSRodney W. Grimes } 459df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 460df8bae1dSRodney W. Grimes *np = n; 461df8bae1dSRodney W. Grimes if (n == 0) 462df8bae1dSRodney W. Grimes goto nospace; 463df8bae1dSRodney W. Grimes if (copyhdr) { 464df8bae1dSRodney W. Grimes M_COPY_PKTHDR(n, m); 465df8bae1dSRodney W. Grimes if (len == M_COPYALL) 466df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 467df8bae1dSRodney W. Grimes else 468df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 469df8bae1dSRodney W. Grimes copyhdr = 0; 470df8bae1dSRodney W. Grimes } 471df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 472df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 473df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 4740885c1d2SJulian Elischer if(!m->m_ext.ext_ref) 475df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 4760885c1d2SJulian Elischer else 4770885c1d2SJulian Elischer (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 4780885c1d2SJulian Elischer m->m_ext.ext_size); 479df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 480df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 481df8bae1dSRodney W. Grimes } else 482df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 483df8bae1dSRodney W. Grimes (unsigned)n->m_len); 484df8bae1dSRodney W. Grimes if (len != M_COPYALL) 485df8bae1dSRodney W. Grimes len -= n->m_len; 486df8bae1dSRodney W. Grimes off = 0; 487df8bae1dSRodney W. Grimes m = m->m_next; 488df8bae1dSRodney W. Grimes np = &n->m_next; 489df8bae1dSRodney W. Grimes } 490df8bae1dSRodney W. Grimes if (top == 0) 491df8bae1dSRodney W. Grimes MCFail++; 492df8bae1dSRodney W. Grimes return (top); 493df8bae1dSRodney W. Grimes nospace: 494df8bae1dSRodney W. Grimes m_freem(top); 495df8bae1dSRodney W. Grimes MCFail++; 496df8bae1dSRodney W. Grimes return (0); 497df8bae1dSRodney W. Grimes } 498df8bae1dSRodney W. Grimes 499df8bae1dSRodney W. Grimes /* 5006a06dea0SGarrett Wollman * Copy an entire packet, including header (which must be present). 5016a06dea0SGarrett Wollman * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. 5026a06dea0SGarrett Wollman */ 5036a06dea0SGarrett Wollman struct mbuf * 5046a06dea0SGarrett Wollman m_copypacket(m, how) 5056a06dea0SGarrett Wollman struct mbuf *m; 5066a06dea0SGarrett Wollman int how; 5076a06dea0SGarrett Wollman { 5086a06dea0SGarrett Wollman struct mbuf *top, *n, *o; 5096a06dea0SGarrett Wollman 5106a06dea0SGarrett Wollman MGET(n, how, m->m_type); 5116a06dea0SGarrett Wollman top = n; 5126a06dea0SGarrett Wollman if (!n) 5136a06dea0SGarrett Wollman goto nospace; 5146a06dea0SGarrett Wollman 5156a06dea0SGarrett Wollman M_COPY_PKTHDR(n, m); 5166a06dea0SGarrett Wollman n->m_len = m->m_len; 5176a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 5186a06dea0SGarrett Wollman n->m_data = m->m_data; 5193e5e083cSPoul-Henning Kamp if(!m->m_ext.ext_ref) 5206a06dea0SGarrett Wollman mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 5213e5e083cSPoul-Henning Kamp else 5223e5e083cSPoul-Henning Kamp (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 5233e5e083cSPoul-Henning Kamp m->m_ext.ext_size); 5246a06dea0SGarrett Wollman n->m_ext = m->m_ext; 5256a06dea0SGarrett Wollman n->m_flags |= M_EXT; 5266a06dea0SGarrett Wollman } else { 5276a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5286a06dea0SGarrett Wollman } 5296a06dea0SGarrett Wollman 5306a06dea0SGarrett Wollman m = m->m_next; 5316a06dea0SGarrett Wollman while (m) { 5326a06dea0SGarrett Wollman MGET(o, how, m->m_type); 5336a06dea0SGarrett Wollman if (!o) 5346a06dea0SGarrett Wollman goto nospace; 5356a06dea0SGarrett Wollman 5366a06dea0SGarrett Wollman n->m_next = o; 5376a06dea0SGarrett Wollman n = n->m_next; 5386a06dea0SGarrett Wollman 5396a06dea0SGarrett Wollman n->m_len = m->m_len; 5406a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 5416a06dea0SGarrett Wollman n->m_data = m->m_data; 5423e5e083cSPoul-Henning Kamp if(!m->m_ext.ext_ref) 5436a06dea0SGarrett Wollman mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 5443e5e083cSPoul-Henning Kamp else 5453e5e083cSPoul-Henning Kamp (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 5463e5e083cSPoul-Henning Kamp m->m_ext.ext_size); 5476a06dea0SGarrett Wollman n->m_ext = m->m_ext; 5486a06dea0SGarrett Wollman n->m_flags |= M_EXT; 5496a06dea0SGarrett Wollman } else { 5506a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5516a06dea0SGarrett Wollman } 5526a06dea0SGarrett Wollman 5536a06dea0SGarrett Wollman m = m->m_next; 5546a06dea0SGarrett Wollman } 5556a06dea0SGarrett Wollman return top; 5566a06dea0SGarrett Wollman nospace: 5576a06dea0SGarrett Wollman m_freem(top); 5586a06dea0SGarrett Wollman MCFail++; 5596a06dea0SGarrett Wollman return 0; 5606a06dea0SGarrett Wollman } 5616a06dea0SGarrett Wollman 5626a06dea0SGarrett Wollman /* 563df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 564df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 565df8bae1dSRodney W. Grimes */ 56626f9a767SRodney W. Grimes void 567df8bae1dSRodney W. Grimes m_copydata(m, off, len, cp) 568df8bae1dSRodney W. Grimes register struct mbuf *m; 569df8bae1dSRodney W. Grimes register int off; 570df8bae1dSRodney W. Grimes register int len; 571df8bae1dSRodney W. Grimes caddr_t cp; 572df8bae1dSRodney W. Grimes { 573df8bae1dSRodney W. Grimes register unsigned count; 574df8bae1dSRodney W. Grimes 575e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copydata, negative off %d", off)); 576e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copydata, negative len %d", len)); 577df8bae1dSRodney W. Grimes while (off > 0) { 578e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); 579df8bae1dSRodney W. Grimes if (off < m->m_len) 580df8bae1dSRodney W. Grimes break; 581df8bae1dSRodney W. Grimes off -= m->m_len; 582df8bae1dSRodney W. Grimes m = m->m_next; 583df8bae1dSRodney W. Grimes } 584df8bae1dSRodney W. Grimes while (len > 0) { 585e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain")); 586df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 587df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 588df8bae1dSRodney W. Grimes len -= count; 589df8bae1dSRodney W. Grimes cp += count; 590df8bae1dSRodney W. Grimes off = 0; 591df8bae1dSRodney W. Grimes m = m->m_next; 592df8bae1dSRodney W. Grimes } 593df8bae1dSRodney W. Grimes } 594df8bae1dSRodney W. Grimes 595df8bae1dSRodney W. Grimes /* 596df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 597df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 598df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 599df8bae1dSRodney W. Grimes */ 60026f9a767SRodney W. Grimes void 601df8bae1dSRodney W. Grimes m_cat(m, n) 602df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 603df8bae1dSRodney W. Grimes { 604df8bae1dSRodney W. Grimes while (m->m_next) 605df8bae1dSRodney W. Grimes m = m->m_next; 606df8bae1dSRodney W. Grimes while (n) { 607df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT || 608df8bae1dSRodney W. Grimes m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 609df8bae1dSRodney W. Grimes /* just join the two chains */ 610df8bae1dSRodney W. Grimes m->m_next = n; 611df8bae1dSRodney W. Grimes return; 612df8bae1dSRodney W. Grimes } 613df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 614df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 615df8bae1dSRodney W. Grimes (u_int)n->m_len); 616df8bae1dSRodney W. Grimes m->m_len += n->m_len; 617df8bae1dSRodney W. Grimes n = m_free(n); 618df8bae1dSRodney W. Grimes } 619df8bae1dSRodney W. Grimes } 620df8bae1dSRodney W. Grimes 62126f9a767SRodney W. Grimes void 622df8bae1dSRodney W. Grimes m_adj(mp, req_len) 623df8bae1dSRodney W. Grimes struct mbuf *mp; 624df8bae1dSRodney W. Grimes int req_len; 625df8bae1dSRodney W. Grimes { 626df8bae1dSRodney W. Grimes register int len = req_len; 627df8bae1dSRodney W. Grimes register struct mbuf *m; 628d68fa50cSBruce Evans register int count; 629df8bae1dSRodney W. Grimes 630df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 631df8bae1dSRodney W. Grimes return; 632df8bae1dSRodney W. Grimes if (len >= 0) { 633df8bae1dSRodney W. Grimes /* 634df8bae1dSRodney W. Grimes * Trim from head. 635df8bae1dSRodney W. Grimes */ 636df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 637df8bae1dSRodney W. Grimes if (m->m_len <= len) { 638df8bae1dSRodney W. Grimes len -= m->m_len; 639df8bae1dSRodney W. Grimes m->m_len = 0; 640df8bae1dSRodney W. Grimes m = m->m_next; 641df8bae1dSRodney W. Grimes } else { 642df8bae1dSRodney W. Grimes m->m_len -= len; 643df8bae1dSRodney W. Grimes m->m_data += len; 644df8bae1dSRodney W. Grimes len = 0; 645df8bae1dSRodney W. Grimes } 646df8bae1dSRodney W. Grimes } 647df8bae1dSRodney W. Grimes m = mp; 648df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 649df8bae1dSRodney W. Grimes m->m_pkthdr.len -= (req_len - len); 650df8bae1dSRodney W. Grimes } else { 651df8bae1dSRodney W. Grimes /* 652df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 653df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 654df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 655df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 656df8bae1dSRodney W. Grimes * after the remaining size. 657df8bae1dSRodney W. Grimes */ 658df8bae1dSRodney W. Grimes len = -len; 659df8bae1dSRodney W. Grimes count = 0; 660df8bae1dSRodney W. Grimes for (;;) { 661df8bae1dSRodney W. Grimes count += m->m_len; 662df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 663df8bae1dSRodney W. Grimes break; 664df8bae1dSRodney W. Grimes m = m->m_next; 665df8bae1dSRodney W. Grimes } 666df8bae1dSRodney W. Grimes if (m->m_len >= len) { 667df8bae1dSRodney W. Grimes m->m_len -= len; 668df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 669df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 670df8bae1dSRodney W. Grimes return; 671df8bae1dSRodney W. Grimes } 672df8bae1dSRodney W. Grimes count -= len; 673df8bae1dSRodney W. Grimes if (count < 0) 674df8bae1dSRodney W. Grimes count = 0; 675df8bae1dSRodney W. Grimes /* 676df8bae1dSRodney W. Grimes * Correct length for chain is "count". 677df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 678df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 679df8bae1dSRodney W. Grimes */ 680df8bae1dSRodney W. Grimes m = mp; 681df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 682df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 683df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 684df8bae1dSRodney W. Grimes if (m->m_len >= count) { 685df8bae1dSRodney W. Grimes m->m_len = count; 686df8bae1dSRodney W. Grimes break; 687df8bae1dSRodney W. Grimes } 688df8bae1dSRodney W. Grimes count -= m->m_len; 689df8bae1dSRodney W. Grimes } 690797f2d22SPoul-Henning Kamp while (m->m_next) 691797f2d22SPoul-Henning Kamp (m = m->m_next) ->m_len = 0; 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes } 694df8bae1dSRodney W. Grimes 695df8bae1dSRodney W. Grimes /* 696df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 697df8bae1dSRodney W. Grimes * and in the data area of an mbuf (so that mtod and dtom 698df8bae1dSRodney W. Grimes * will work for a structure of size len). Returns the resulting 699df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 700df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 701df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 702df8bae1dSRodney W. Grimes */ 703639acc13SGarrett Wollman #define MPFail (mbstat.m_mpfail) 704df8bae1dSRodney W. Grimes 705df8bae1dSRodney W. Grimes struct mbuf * 706df8bae1dSRodney W. Grimes m_pullup(n, len) 707df8bae1dSRodney W. Grimes register struct mbuf *n; 708df8bae1dSRodney W. Grimes int len; 709df8bae1dSRodney W. Grimes { 710df8bae1dSRodney W. Grimes register struct mbuf *m; 711df8bae1dSRodney W. Grimes register int count; 712df8bae1dSRodney W. Grimes int space; 713df8bae1dSRodney W. Grimes 714df8bae1dSRodney W. Grimes /* 715df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 716df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 717df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 718df8bae1dSRodney W. Grimes */ 719df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 720df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 721df8bae1dSRodney W. Grimes if (n->m_len >= len) 722df8bae1dSRodney W. Grimes return (n); 723df8bae1dSRodney W. Grimes m = n; 724df8bae1dSRodney W. Grimes n = n->m_next; 725df8bae1dSRodney W. Grimes len -= m->m_len; 726df8bae1dSRodney W. Grimes } else { 727df8bae1dSRodney W. Grimes if (len > MHLEN) 728df8bae1dSRodney W. Grimes goto bad; 729df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, n->m_type); 730df8bae1dSRodney W. Grimes if (m == 0) 731df8bae1dSRodney W. Grimes goto bad; 732df8bae1dSRodney W. Grimes m->m_len = 0; 733df8bae1dSRodney W. Grimes if (n->m_flags & M_PKTHDR) { 734df8bae1dSRodney W. Grimes M_COPY_PKTHDR(m, n); 735df8bae1dSRodney W. Grimes n->m_flags &= ~M_PKTHDR; 736df8bae1dSRodney W. Grimes } 737df8bae1dSRodney W. Grimes } 738df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 739df8bae1dSRodney W. Grimes do { 740df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 741df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 742df8bae1dSRodney W. Grimes (unsigned)count); 743df8bae1dSRodney W. Grimes len -= count; 744df8bae1dSRodney W. Grimes m->m_len += count; 745df8bae1dSRodney W. Grimes n->m_len -= count; 746df8bae1dSRodney W. Grimes space -= count; 747df8bae1dSRodney W. Grimes if (n->m_len) 748df8bae1dSRodney W. Grimes n->m_data += count; 749df8bae1dSRodney W. Grimes else 750df8bae1dSRodney W. Grimes n = m_free(n); 751df8bae1dSRodney W. Grimes } while (len > 0 && n); 752df8bae1dSRodney W. Grimes if (len > 0) { 753df8bae1dSRodney W. Grimes (void) m_free(m); 754df8bae1dSRodney W. Grimes goto bad; 755df8bae1dSRodney W. Grimes } 756df8bae1dSRodney W. Grimes m->m_next = n; 757df8bae1dSRodney W. Grimes return (m); 758df8bae1dSRodney W. Grimes bad: 759df8bae1dSRodney W. Grimes m_freem(n); 760df8bae1dSRodney W. Grimes MPFail++; 761df8bae1dSRodney W. Grimes return (0); 762df8bae1dSRodney W. Grimes } 763df8bae1dSRodney W. Grimes 764df8bae1dSRodney W. Grimes /* 765df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 766df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 767df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 768df8bae1dSRodney W. Grimes */ 769df8bae1dSRodney W. Grimes struct mbuf * 770df8bae1dSRodney W. Grimes m_split(m0, len0, wait) 771df8bae1dSRodney W. Grimes register struct mbuf *m0; 772df8bae1dSRodney W. Grimes int len0, wait; 773df8bae1dSRodney W. Grimes { 774df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 775df8bae1dSRodney W. Grimes unsigned len = len0, remain; 776df8bae1dSRodney W. Grimes 777df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 778df8bae1dSRodney W. Grimes len -= m->m_len; 779df8bae1dSRodney W. Grimes if (m == 0) 780df8bae1dSRodney W. Grimes return (0); 781df8bae1dSRodney W. Grimes remain = m->m_len - len; 782df8bae1dSRodney W. Grimes if (m0->m_flags & M_PKTHDR) { 783df8bae1dSRodney W. Grimes MGETHDR(n, wait, m0->m_type); 784df8bae1dSRodney W. Grimes if (n == 0) 785df8bae1dSRodney W. Grimes return (0); 786df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 787df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 788df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 789df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 790df8bae1dSRodney W. Grimes goto extpacket; 791df8bae1dSRodney W. Grimes if (remain > MHLEN) { 792df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 793df8bae1dSRodney W. Grimes MH_ALIGN(n, 0); 794df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 795df8bae1dSRodney W. Grimes if (n->m_next == 0) { 796df8bae1dSRodney W. Grimes (void) m_free(n); 797df8bae1dSRodney W. Grimes return (0); 798df8bae1dSRodney W. Grimes } else 799df8bae1dSRodney W. Grimes return (n); 800df8bae1dSRodney W. Grimes } else 801df8bae1dSRodney W. Grimes MH_ALIGN(n, remain); 802df8bae1dSRodney W. Grimes } else if (remain == 0) { 803df8bae1dSRodney W. Grimes n = m->m_next; 804df8bae1dSRodney W. Grimes m->m_next = 0; 805df8bae1dSRodney W. Grimes return (n); 806df8bae1dSRodney W. Grimes } else { 807df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 808df8bae1dSRodney W. Grimes if (n == 0) 809df8bae1dSRodney W. Grimes return (0); 810df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 811df8bae1dSRodney W. Grimes } 812df8bae1dSRodney W. Grimes extpacket: 813df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 814df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 815df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 8160885c1d2SJulian Elischer if(!m->m_ext.ext_ref) 817df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 8180885c1d2SJulian Elischer else 8190885c1d2SJulian Elischer (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 8200885c1d2SJulian Elischer m->m_ext.ext_size); 821df8bae1dSRodney W. Grimes m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ 822df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 823df8bae1dSRodney W. Grimes } else { 824df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 825df8bae1dSRodney W. Grimes } 826df8bae1dSRodney W. Grimes n->m_len = remain; 827df8bae1dSRodney W. Grimes m->m_len = len; 828df8bae1dSRodney W. Grimes n->m_next = m->m_next; 829df8bae1dSRodney W. Grimes m->m_next = 0; 830df8bae1dSRodney W. Grimes return (n); 831df8bae1dSRodney W. Grimes } 832df8bae1dSRodney W. Grimes /* 833df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 834df8bae1dSRodney W. Grimes */ 835df8bae1dSRodney W. Grimes struct mbuf * 836df8bae1dSRodney W. Grimes m_devget(buf, totlen, off0, ifp, copy) 837df8bae1dSRodney W. Grimes char *buf; 838df8bae1dSRodney W. Grimes int totlen, off0; 839df8bae1dSRodney W. Grimes struct ifnet *ifp; 84098d93822SBruce Evans void (*copy) __P((char *from, caddr_t to, u_int len)); 841df8bae1dSRodney W. Grimes { 842df8bae1dSRodney W. Grimes register struct mbuf *m; 843df8bae1dSRodney W. Grimes struct mbuf *top = 0, **mp = ⊤ 844df8bae1dSRodney W. Grimes register int off = off0, len; 845df8bae1dSRodney W. Grimes register char *cp; 846df8bae1dSRodney W. Grimes char *epkt; 847df8bae1dSRodney W. Grimes 848df8bae1dSRodney W. Grimes cp = buf; 849df8bae1dSRodney W. Grimes epkt = cp + totlen; 850df8bae1dSRodney W. Grimes if (off) { 851df8bae1dSRodney W. Grimes cp += off + 2 * sizeof(u_short); 852df8bae1dSRodney W. Grimes totlen -= 2 * sizeof(u_short); 853df8bae1dSRodney W. Grimes } 854df8bae1dSRodney W. Grimes MGETHDR(m, M_DONTWAIT, MT_DATA); 855df8bae1dSRodney W. Grimes if (m == 0) 856df8bae1dSRodney W. Grimes return (0); 857df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 858df8bae1dSRodney W. Grimes m->m_pkthdr.len = totlen; 859df8bae1dSRodney W. Grimes m->m_len = MHLEN; 860df8bae1dSRodney W. Grimes 861df8bae1dSRodney W. Grimes while (totlen > 0) { 862df8bae1dSRodney W. Grimes if (top) { 863df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_DATA); 864df8bae1dSRodney W. Grimes if (m == 0) { 865df8bae1dSRodney W. Grimes m_freem(top); 866df8bae1dSRodney W. Grimes return (0); 867df8bae1dSRodney W. Grimes } 868df8bae1dSRodney W. Grimes m->m_len = MLEN; 869df8bae1dSRodney W. Grimes } 870df8bae1dSRodney W. Grimes len = min(totlen, epkt - cp); 871df8bae1dSRodney W. Grimes if (len >= MINCLSIZE) { 872df8bae1dSRodney W. Grimes MCLGET(m, M_DONTWAIT); 873df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 874df8bae1dSRodney W. Grimes m->m_len = len = min(len, MCLBYTES); 875df8bae1dSRodney W. Grimes else 876df8bae1dSRodney W. Grimes len = m->m_len; 877df8bae1dSRodney W. Grimes } else { 878df8bae1dSRodney W. Grimes /* 879df8bae1dSRodney W. Grimes * Place initial small packet/header at end of mbuf. 880df8bae1dSRodney W. Grimes */ 881df8bae1dSRodney W. Grimes if (len < m->m_len) { 882df8bae1dSRodney W. Grimes if (top == 0 && len + max_linkhdr <= m->m_len) 883df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 884df8bae1dSRodney W. Grimes m->m_len = len; 885df8bae1dSRodney W. Grimes } else 886df8bae1dSRodney W. Grimes len = m->m_len; 887df8bae1dSRodney W. Grimes } 888df8bae1dSRodney W. Grimes if (copy) 889df8bae1dSRodney W. Grimes copy(cp, mtod(m, caddr_t), (unsigned)len); 890df8bae1dSRodney W. Grimes else 891df8bae1dSRodney W. Grimes bcopy(cp, mtod(m, caddr_t), (unsigned)len); 892df8bae1dSRodney W. Grimes cp += len; 893df8bae1dSRodney W. Grimes *mp = m; 894df8bae1dSRodney W. Grimes mp = &m->m_next; 895df8bae1dSRodney W. Grimes totlen -= len; 896df8bae1dSRodney W. Grimes if (cp == epkt) 897df8bae1dSRodney W. Grimes cp = buf; 898df8bae1dSRodney W. Grimes } 899df8bae1dSRodney W. Grimes return (top); 900df8bae1dSRodney W. Grimes } 901c5789ba3SPoul-Henning Kamp 902c5789ba3SPoul-Henning Kamp /* 903c5789ba3SPoul-Henning Kamp * Copy data from a buffer back into the indicated mbuf chain, 904c5789ba3SPoul-Henning Kamp * starting "off" bytes from the beginning, extending the mbuf 905c5789ba3SPoul-Henning Kamp * chain if necessary. 906c5789ba3SPoul-Henning Kamp */ 907c5789ba3SPoul-Henning Kamp void 908c5789ba3SPoul-Henning Kamp m_copyback(m0, off, len, cp) 909c5789ba3SPoul-Henning Kamp struct mbuf *m0; 910c5789ba3SPoul-Henning Kamp register int off; 911c5789ba3SPoul-Henning Kamp register int len; 912c5789ba3SPoul-Henning Kamp caddr_t cp; 913c5789ba3SPoul-Henning Kamp { 914c5789ba3SPoul-Henning Kamp register int mlen; 915c5789ba3SPoul-Henning Kamp register struct mbuf *m = m0, *n; 916c5789ba3SPoul-Henning Kamp int totlen = 0; 917c5789ba3SPoul-Henning Kamp 918c5789ba3SPoul-Henning Kamp if (m0 == 0) 919c5789ba3SPoul-Henning Kamp return; 920c5789ba3SPoul-Henning Kamp while (off > (mlen = m->m_len)) { 921c5789ba3SPoul-Henning Kamp off -= mlen; 922c5789ba3SPoul-Henning Kamp totlen += mlen; 923c5789ba3SPoul-Henning Kamp if (m->m_next == 0) { 924c5789ba3SPoul-Henning Kamp n = m_getclr(M_DONTWAIT, m->m_type); 925c5789ba3SPoul-Henning Kamp if (n == 0) 926c5789ba3SPoul-Henning Kamp goto out; 927c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len + off); 928c5789ba3SPoul-Henning Kamp m->m_next = n; 929c5789ba3SPoul-Henning Kamp } 930c5789ba3SPoul-Henning Kamp m = m->m_next; 931c5789ba3SPoul-Henning Kamp } 932c5789ba3SPoul-Henning Kamp while (len > 0) { 933c5789ba3SPoul-Henning Kamp mlen = min (m->m_len - off, len); 934c5789ba3SPoul-Henning Kamp bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 935c5789ba3SPoul-Henning Kamp cp += mlen; 936c5789ba3SPoul-Henning Kamp len -= mlen; 937c5789ba3SPoul-Henning Kamp mlen += off; 938c5789ba3SPoul-Henning Kamp off = 0; 939c5789ba3SPoul-Henning Kamp totlen += mlen; 940c5789ba3SPoul-Henning Kamp if (len == 0) 941c5789ba3SPoul-Henning Kamp break; 942c5789ba3SPoul-Henning Kamp if (m->m_next == 0) { 943c5789ba3SPoul-Henning Kamp n = m_get(M_DONTWAIT, m->m_type); 944c5789ba3SPoul-Henning Kamp if (n == 0) 945c5789ba3SPoul-Henning Kamp break; 946c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len); 947c5789ba3SPoul-Henning Kamp m->m_next = n; 948c5789ba3SPoul-Henning Kamp } 949c5789ba3SPoul-Henning Kamp m = m->m_next; 950c5789ba3SPoul-Henning Kamp } 951c5789ba3SPoul-Henning Kamp out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 952c5789ba3SPoul-Henning Kamp m->m_pkthdr.len = totlen; 953c5789ba3SPoul-Henning Kamp } 954ce4a64f7SPoul-Henning Kamp 955ce4a64f7SPoul-Henning Kamp void 956ce4a64f7SPoul-Henning Kamp m_print(const struct mbuf *m) 957ce4a64f7SPoul-Henning Kamp { 958ce4a64f7SPoul-Henning Kamp int len; 959ce4a64f7SPoul-Henning Kamp struct mbuf *m2; 960ce4a64f7SPoul-Henning Kamp 961ce4a64f7SPoul-Henning Kamp len = m->m_pkthdr.len; 962ce4a64f7SPoul-Henning Kamp m2 = m; 963ce4a64f7SPoul-Henning Kamp while (len) { 964ce4a64f7SPoul-Henning Kamp printf("%p %*D\n", m2, m2->m_len, (u_char *)m2->m_data, "-"); 965ce4a64f7SPoul-Henning Kamp len -= m2->m_len; 966ce4a64f7SPoul-Henning Kamp m2 = m2->m_next; 967ce4a64f7SPoul-Henning Kamp } 968ce4a64f7SPoul-Henning Kamp return; 969ce4a64f7SPoul-Henning Kamp } 970