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. 4261c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 4271c38f2eaSArchie Cobbs * only their reference counts are incremented. 428df8bae1dSRodney W. Grimes */ 429639acc13SGarrett Wollman #define MCFail (mbstat.m_mcfail) 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes struct mbuf * 432df8bae1dSRodney W. Grimes m_copym(m, off0, len, wait) 433df8bae1dSRodney W. Grimes register struct mbuf *m; 434df8bae1dSRodney W. Grimes int off0, wait; 435df8bae1dSRodney W. Grimes register int len; 436df8bae1dSRodney W. Grimes { 437df8bae1dSRodney W. Grimes register struct mbuf *n, **np; 438df8bae1dSRodney W. Grimes register int off = off0; 439df8bae1dSRodney W. Grimes struct mbuf *top; 440df8bae1dSRodney W. Grimes int copyhdr = 0; 441df8bae1dSRodney W. Grimes 442e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copym, negative off %d", off)); 443e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copym, negative len %d", len)); 444df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 445df8bae1dSRodney W. Grimes copyhdr = 1; 446df8bae1dSRodney W. Grimes while (off > 0) { 447e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain")); 448df8bae1dSRodney W. Grimes if (off < m->m_len) 449df8bae1dSRodney W. Grimes break; 450df8bae1dSRodney W. Grimes off -= m->m_len; 451df8bae1dSRodney W. Grimes m = m->m_next; 452df8bae1dSRodney W. Grimes } 453df8bae1dSRodney W. Grimes np = ⊤ 454df8bae1dSRodney W. Grimes top = 0; 455df8bae1dSRodney W. Grimes while (len > 0) { 456df8bae1dSRodney W. Grimes if (m == 0) { 457e0a653ddSAlfred Perlstein KASSERT(len == M_COPYALL, 458e0a653ddSAlfred Perlstein ("m_copym, length > size of mbuf chain")); 459df8bae1dSRodney W. Grimes break; 460df8bae1dSRodney W. Grimes } 461df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 462df8bae1dSRodney W. Grimes *np = n; 463df8bae1dSRodney W. Grimes if (n == 0) 464df8bae1dSRodney W. Grimes goto nospace; 465df8bae1dSRodney W. Grimes if (copyhdr) { 466df8bae1dSRodney W. Grimes M_COPY_PKTHDR(n, m); 467df8bae1dSRodney W. Grimes if (len == M_COPYALL) 468df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 469df8bae1dSRodney W. Grimes else 470df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 471df8bae1dSRodney W. Grimes copyhdr = 0; 472df8bae1dSRodney W. Grimes } 473df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 474df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 475df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 4760885c1d2SJulian Elischer if(!m->m_ext.ext_ref) 477df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 4780885c1d2SJulian Elischer else 4790885c1d2SJulian Elischer (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 4800885c1d2SJulian Elischer m->m_ext.ext_size); 481df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 482df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 483df8bae1dSRodney W. Grimes } else 484df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 485df8bae1dSRodney W. Grimes (unsigned)n->m_len); 486df8bae1dSRodney W. Grimes if (len != M_COPYALL) 487df8bae1dSRodney W. Grimes len -= n->m_len; 488df8bae1dSRodney W. Grimes off = 0; 489df8bae1dSRodney W. Grimes m = m->m_next; 490df8bae1dSRodney W. Grimes np = &n->m_next; 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes if (top == 0) 493df8bae1dSRodney W. Grimes MCFail++; 494df8bae1dSRodney W. Grimes return (top); 495df8bae1dSRodney W. Grimes nospace: 496df8bae1dSRodney W. Grimes m_freem(top); 497df8bae1dSRodney W. Grimes MCFail++; 498df8bae1dSRodney W. Grimes return (0); 499df8bae1dSRodney W. Grimes } 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes /* 5026a06dea0SGarrett Wollman * Copy an entire packet, including header (which must be present). 5036a06dea0SGarrett Wollman * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. 5041c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 5051c38f2eaSArchie Cobbs * only their reference counts are incremented. 5066a06dea0SGarrett Wollman */ 5076a06dea0SGarrett Wollman struct mbuf * 5086a06dea0SGarrett Wollman m_copypacket(m, how) 5096a06dea0SGarrett Wollman struct mbuf *m; 5106a06dea0SGarrett Wollman int how; 5116a06dea0SGarrett Wollman { 5126a06dea0SGarrett Wollman struct mbuf *top, *n, *o; 5136a06dea0SGarrett Wollman 5146a06dea0SGarrett Wollman MGET(n, how, m->m_type); 5156a06dea0SGarrett Wollman top = n; 5166a06dea0SGarrett Wollman if (!n) 5176a06dea0SGarrett Wollman goto nospace; 5186a06dea0SGarrett Wollman 5196a06dea0SGarrett Wollman M_COPY_PKTHDR(n, m); 5206a06dea0SGarrett Wollman n->m_len = m->m_len; 5216a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 5226a06dea0SGarrett Wollman n->m_data = m->m_data; 5233e5e083cSPoul-Henning Kamp if(!m->m_ext.ext_ref) 5246a06dea0SGarrett Wollman mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 5253e5e083cSPoul-Henning Kamp else 5263e5e083cSPoul-Henning Kamp (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 5273e5e083cSPoul-Henning Kamp m->m_ext.ext_size); 5286a06dea0SGarrett Wollman n->m_ext = m->m_ext; 5296a06dea0SGarrett Wollman n->m_flags |= M_EXT; 5306a06dea0SGarrett Wollman } else { 5316a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5326a06dea0SGarrett Wollman } 5336a06dea0SGarrett Wollman 5346a06dea0SGarrett Wollman m = m->m_next; 5356a06dea0SGarrett Wollman while (m) { 5366a06dea0SGarrett Wollman MGET(o, how, m->m_type); 5376a06dea0SGarrett Wollman if (!o) 5386a06dea0SGarrett Wollman goto nospace; 5396a06dea0SGarrett Wollman 5406a06dea0SGarrett Wollman n->m_next = o; 5416a06dea0SGarrett Wollman n = n->m_next; 5426a06dea0SGarrett Wollman 5436a06dea0SGarrett Wollman n->m_len = m->m_len; 5446a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 5456a06dea0SGarrett Wollman n->m_data = m->m_data; 5463e5e083cSPoul-Henning Kamp if(!m->m_ext.ext_ref) 5476a06dea0SGarrett Wollman mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 5483e5e083cSPoul-Henning Kamp else 5493e5e083cSPoul-Henning Kamp (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 5503e5e083cSPoul-Henning Kamp m->m_ext.ext_size); 5516a06dea0SGarrett Wollman n->m_ext = m->m_ext; 5526a06dea0SGarrett Wollman n->m_flags |= M_EXT; 5536a06dea0SGarrett Wollman } else { 5546a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5556a06dea0SGarrett Wollman } 5566a06dea0SGarrett Wollman 5576a06dea0SGarrett Wollman m = m->m_next; 5586a06dea0SGarrett Wollman } 5596a06dea0SGarrett Wollman return top; 5606a06dea0SGarrett Wollman nospace: 5616a06dea0SGarrett Wollman m_freem(top); 5626a06dea0SGarrett Wollman MCFail++; 5636a06dea0SGarrett Wollman return 0; 5646a06dea0SGarrett Wollman } 5656a06dea0SGarrett Wollman 5666a06dea0SGarrett Wollman /* 567df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 568df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 569df8bae1dSRodney W. Grimes */ 57026f9a767SRodney W. Grimes void 571df8bae1dSRodney W. Grimes m_copydata(m, off, len, cp) 572df8bae1dSRodney W. Grimes register struct mbuf *m; 573df8bae1dSRodney W. Grimes register int off; 574df8bae1dSRodney W. Grimes register int len; 575df8bae1dSRodney W. Grimes caddr_t cp; 576df8bae1dSRodney W. Grimes { 577df8bae1dSRodney W. Grimes register unsigned count; 578df8bae1dSRodney W. Grimes 579e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copydata, negative off %d", off)); 580e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copydata, negative len %d", len)); 581df8bae1dSRodney W. Grimes while (off > 0) { 582e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); 583df8bae1dSRodney W. Grimes if (off < m->m_len) 584df8bae1dSRodney W. Grimes break; 585df8bae1dSRodney W. Grimes off -= m->m_len; 586df8bae1dSRodney W. Grimes m = m->m_next; 587df8bae1dSRodney W. Grimes } 588df8bae1dSRodney W. Grimes while (len > 0) { 589e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain")); 590df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 591df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 592df8bae1dSRodney W. Grimes len -= count; 593df8bae1dSRodney W. Grimes cp += count; 594df8bae1dSRodney W. Grimes off = 0; 595df8bae1dSRodney W. Grimes m = m->m_next; 596df8bae1dSRodney W. Grimes } 597df8bae1dSRodney W. Grimes } 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes /* 6001c38f2eaSArchie Cobbs * Copy a packet header mbuf chain into a completely new chain, including 6011c38f2eaSArchie Cobbs * copying any mbuf clusters. Use this instead of m_copypacket() when 6021c38f2eaSArchie Cobbs * you need a writable copy of an mbuf chain. 6031c38f2eaSArchie Cobbs */ 6041c38f2eaSArchie Cobbs struct mbuf * 6051c38f2eaSArchie Cobbs m_dup(m, how) 6061c38f2eaSArchie Cobbs struct mbuf *m; 6071c38f2eaSArchie Cobbs int how; 6081c38f2eaSArchie Cobbs { 6091c38f2eaSArchie Cobbs struct mbuf **p, *top = NULL; 6101c38f2eaSArchie Cobbs int remain, moff, nsize; 6111c38f2eaSArchie Cobbs 6121c38f2eaSArchie Cobbs /* Sanity check */ 6131c38f2eaSArchie Cobbs if (m == NULL) 6141c38f2eaSArchie Cobbs return (0); 6151c38f2eaSArchie Cobbs KASSERT((m->m_flags & M_PKTHDR) != 0, ("%s: !PKTHDR", __FUNCTION__)); 6161c38f2eaSArchie Cobbs 6171c38f2eaSArchie Cobbs /* While there's more data, get a new mbuf, tack it on, and fill it */ 6181c38f2eaSArchie Cobbs remain = m->m_pkthdr.len; 6191c38f2eaSArchie Cobbs moff = 0; 6201c38f2eaSArchie Cobbs p = ⊤ 6211c38f2eaSArchie Cobbs while (remain > 0 || top == NULL) { /* allow m->m_pkthdr.len == 0 */ 6221c38f2eaSArchie Cobbs struct mbuf *n; 6231c38f2eaSArchie Cobbs 6241c38f2eaSArchie Cobbs /* Get the next new mbuf */ 6251c38f2eaSArchie Cobbs MGET(n, how, m->m_type); 6261c38f2eaSArchie Cobbs if (n == NULL) 6271c38f2eaSArchie Cobbs goto nospace; 6281c38f2eaSArchie Cobbs if (top == NULL) { /* first one, must be PKTHDR */ 6291c38f2eaSArchie Cobbs M_COPY_PKTHDR(n, m); 6301c38f2eaSArchie Cobbs nsize = MHLEN; 6311c38f2eaSArchie Cobbs } else /* not the first one */ 6321c38f2eaSArchie Cobbs nsize = MLEN; 6331c38f2eaSArchie Cobbs if (remain >= MINCLSIZE) { 6341c38f2eaSArchie Cobbs MCLGET(n, how); 6351c38f2eaSArchie Cobbs if ((n->m_flags & M_EXT) == 0) { 6361c38f2eaSArchie Cobbs (void)m_free(n); 6371c38f2eaSArchie Cobbs goto nospace; 6381c38f2eaSArchie Cobbs } 6391c38f2eaSArchie Cobbs nsize = MCLBYTES; 6401c38f2eaSArchie Cobbs } 6411c38f2eaSArchie Cobbs n->m_len = 0; 6421c38f2eaSArchie Cobbs 6431c38f2eaSArchie Cobbs /* Link it into the new chain */ 6441c38f2eaSArchie Cobbs *p = n; 6451c38f2eaSArchie Cobbs p = &n->m_next; 6461c38f2eaSArchie Cobbs 6471c38f2eaSArchie Cobbs /* Copy data from original mbuf(s) into new mbuf */ 6481c38f2eaSArchie Cobbs while (n->m_len < nsize && m != NULL) { 6491c38f2eaSArchie Cobbs int chunk = min(nsize - n->m_len, m->m_len - moff); 6501c38f2eaSArchie Cobbs 6511c38f2eaSArchie Cobbs bcopy(m->m_data + moff, n->m_data + n->m_len, chunk); 6521c38f2eaSArchie Cobbs moff += chunk; 6531c38f2eaSArchie Cobbs n->m_len += chunk; 6541c38f2eaSArchie Cobbs remain -= chunk; 6551c38f2eaSArchie Cobbs if (moff == m->m_len) { 6561c38f2eaSArchie Cobbs m = m->m_next; 6571c38f2eaSArchie Cobbs moff = 0; 6581c38f2eaSArchie Cobbs } 6591c38f2eaSArchie Cobbs } 6601c38f2eaSArchie Cobbs 6611c38f2eaSArchie Cobbs /* Check correct total mbuf length */ 6621c38f2eaSArchie Cobbs KASSERT((remain > 0 && m != NULL) || (remain == 0 && m == NULL), 6631c38f2eaSArchie Cobbs ("%s: bogus m_pkthdr.len", __FUNCTION__)); 6641c38f2eaSArchie Cobbs } 6651c38f2eaSArchie Cobbs return (top); 6661c38f2eaSArchie Cobbs 6671c38f2eaSArchie Cobbs nospace: 6681c38f2eaSArchie Cobbs m_freem(top); 6691c38f2eaSArchie Cobbs MCFail++; 6701c38f2eaSArchie Cobbs return (0); 6711c38f2eaSArchie Cobbs } 6721c38f2eaSArchie Cobbs 6731c38f2eaSArchie Cobbs /* 674df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 675df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 676df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 677df8bae1dSRodney W. Grimes */ 67826f9a767SRodney W. Grimes void 679df8bae1dSRodney W. Grimes m_cat(m, n) 680df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 681df8bae1dSRodney W. Grimes { 682df8bae1dSRodney W. Grimes while (m->m_next) 683df8bae1dSRodney W. Grimes m = m->m_next; 684df8bae1dSRodney W. Grimes while (n) { 685df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT || 686df8bae1dSRodney W. Grimes m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 687df8bae1dSRodney W. Grimes /* just join the two chains */ 688df8bae1dSRodney W. Grimes m->m_next = n; 689df8bae1dSRodney W. Grimes return; 690df8bae1dSRodney W. Grimes } 691df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 692df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 693df8bae1dSRodney W. Grimes (u_int)n->m_len); 694df8bae1dSRodney W. Grimes m->m_len += n->m_len; 695df8bae1dSRodney W. Grimes n = m_free(n); 696df8bae1dSRodney W. Grimes } 697df8bae1dSRodney W. Grimes } 698df8bae1dSRodney W. Grimes 69926f9a767SRodney W. Grimes void 700df8bae1dSRodney W. Grimes m_adj(mp, req_len) 701df8bae1dSRodney W. Grimes struct mbuf *mp; 702df8bae1dSRodney W. Grimes int req_len; 703df8bae1dSRodney W. Grimes { 704df8bae1dSRodney W. Grimes register int len = req_len; 705df8bae1dSRodney W. Grimes register struct mbuf *m; 706d68fa50cSBruce Evans register int count; 707df8bae1dSRodney W. Grimes 708df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 709df8bae1dSRodney W. Grimes return; 710df8bae1dSRodney W. Grimes if (len >= 0) { 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * Trim from head. 713df8bae1dSRodney W. Grimes */ 714df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 715df8bae1dSRodney W. Grimes if (m->m_len <= len) { 716df8bae1dSRodney W. Grimes len -= m->m_len; 717df8bae1dSRodney W. Grimes m->m_len = 0; 718df8bae1dSRodney W. Grimes m = m->m_next; 719df8bae1dSRodney W. Grimes } else { 720df8bae1dSRodney W. Grimes m->m_len -= len; 721df8bae1dSRodney W. Grimes m->m_data += len; 722df8bae1dSRodney W. Grimes len = 0; 723df8bae1dSRodney W. Grimes } 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes m = mp; 726df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 727df8bae1dSRodney W. Grimes m->m_pkthdr.len -= (req_len - len); 728df8bae1dSRodney W. Grimes } else { 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 731df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 732df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 733df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 734df8bae1dSRodney W. Grimes * after the remaining size. 735df8bae1dSRodney W. Grimes */ 736df8bae1dSRodney W. Grimes len = -len; 737df8bae1dSRodney W. Grimes count = 0; 738df8bae1dSRodney W. Grimes for (;;) { 739df8bae1dSRodney W. Grimes count += m->m_len; 740df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 741df8bae1dSRodney W. Grimes break; 742df8bae1dSRodney W. Grimes m = m->m_next; 743df8bae1dSRodney W. Grimes } 744df8bae1dSRodney W. Grimes if (m->m_len >= len) { 745df8bae1dSRodney W. Grimes m->m_len -= len; 746df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 747df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 748df8bae1dSRodney W. Grimes return; 749df8bae1dSRodney W. Grimes } 750df8bae1dSRodney W. Grimes count -= len; 751df8bae1dSRodney W. Grimes if (count < 0) 752df8bae1dSRodney W. Grimes count = 0; 753df8bae1dSRodney W. Grimes /* 754df8bae1dSRodney W. Grimes * Correct length for chain is "count". 755df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 756df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 757df8bae1dSRodney W. Grimes */ 758df8bae1dSRodney W. Grimes m = mp; 759df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 760df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 761df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 762df8bae1dSRodney W. Grimes if (m->m_len >= count) { 763df8bae1dSRodney W. Grimes m->m_len = count; 764df8bae1dSRodney W. Grimes break; 765df8bae1dSRodney W. Grimes } 766df8bae1dSRodney W. Grimes count -= m->m_len; 767df8bae1dSRodney W. Grimes } 768797f2d22SPoul-Henning Kamp while (m->m_next) 769797f2d22SPoul-Henning Kamp (m = m->m_next) ->m_len = 0; 770df8bae1dSRodney W. Grimes } 771df8bae1dSRodney W. Grimes } 772df8bae1dSRodney W. Grimes 773df8bae1dSRodney W. Grimes /* 774df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 775df8bae1dSRodney W. Grimes * and in the data area of an mbuf (so that mtod and dtom 776df8bae1dSRodney W. Grimes * will work for a structure of size len). Returns the resulting 777df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 778df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 779df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 780df8bae1dSRodney W. Grimes */ 781639acc13SGarrett Wollman #define MPFail (mbstat.m_mpfail) 782df8bae1dSRodney W. Grimes 783df8bae1dSRodney W. Grimes struct mbuf * 784df8bae1dSRodney W. Grimes m_pullup(n, len) 785df8bae1dSRodney W. Grimes register struct mbuf *n; 786df8bae1dSRodney W. Grimes int len; 787df8bae1dSRodney W. Grimes { 788df8bae1dSRodney W. Grimes register struct mbuf *m; 789df8bae1dSRodney W. Grimes register int count; 790df8bae1dSRodney W. Grimes int space; 791df8bae1dSRodney W. Grimes 792df8bae1dSRodney W. Grimes /* 793df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 794df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 795df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 796df8bae1dSRodney W. Grimes */ 797df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 798df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 799df8bae1dSRodney W. Grimes if (n->m_len >= len) 800df8bae1dSRodney W. Grimes return (n); 801df8bae1dSRodney W. Grimes m = n; 802df8bae1dSRodney W. Grimes n = n->m_next; 803df8bae1dSRodney W. Grimes len -= m->m_len; 804df8bae1dSRodney W. Grimes } else { 805df8bae1dSRodney W. Grimes if (len > MHLEN) 806df8bae1dSRodney W. Grimes goto bad; 807df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, n->m_type); 808df8bae1dSRodney W. Grimes if (m == 0) 809df8bae1dSRodney W. Grimes goto bad; 810df8bae1dSRodney W. Grimes m->m_len = 0; 811df8bae1dSRodney W. Grimes if (n->m_flags & M_PKTHDR) { 812df8bae1dSRodney W. Grimes M_COPY_PKTHDR(m, n); 813df8bae1dSRodney W. Grimes n->m_flags &= ~M_PKTHDR; 814df8bae1dSRodney W. Grimes } 815df8bae1dSRodney W. Grimes } 816df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 817df8bae1dSRodney W. Grimes do { 818df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 819df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 820df8bae1dSRodney W. Grimes (unsigned)count); 821df8bae1dSRodney W. Grimes len -= count; 822df8bae1dSRodney W. Grimes m->m_len += count; 823df8bae1dSRodney W. Grimes n->m_len -= count; 824df8bae1dSRodney W. Grimes space -= count; 825df8bae1dSRodney W. Grimes if (n->m_len) 826df8bae1dSRodney W. Grimes n->m_data += count; 827df8bae1dSRodney W. Grimes else 828df8bae1dSRodney W. Grimes n = m_free(n); 829df8bae1dSRodney W. Grimes } while (len > 0 && n); 830df8bae1dSRodney W. Grimes if (len > 0) { 831df8bae1dSRodney W. Grimes (void) m_free(m); 832df8bae1dSRodney W. Grimes goto bad; 833df8bae1dSRodney W. Grimes } 834df8bae1dSRodney W. Grimes m->m_next = n; 835df8bae1dSRodney W. Grimes return (m); 836df8bae1dSRodney W. Grimes bad: 837df8bae1dSRodney W. Grimes m_freem(n); 838df8bae1dSRodney W. Grimes MPFail++; 839df8bae1dSRodney W. Grimes return (0); 840df8bae1dSRodney W. Grimes } 841df8bae1dSRodney W. Grimes 842df8bae1dSRodney W. Grimes /* 843df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 844df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 845df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 846df8bae1dSRodney W. Grimes */ 847df8bae1dSRodney W. Grimes struct mbuf * 848df8bae1dSRodney W. Grimes m_split(m0, len0, wait) 849df8bae1dSRodney W. Grimes register struct mbuf *m0; 850df8bae1dSRodney W. Grimes int len0, wait; 851df8bae1dSRodney W. Grimes { 852df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 853df8bae1dSRodney W. Grimes unsigned len = len0, remain; 854df8bae1dSRodney W. Grimes 855df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 856df8bae1dSRodney W. Grimes len -= m->m_len; 857df8bae1dSRodney W. Grimes if (m == 0) 858df8bae1dSRodney W. Grimes return (0); 859df8bae1dSRodney W. Grimes remain = m->m_len - len; 860df8bae1dSRodney W. Grimes if (m0->m_flags & M_PKTHDR) { 861df8bae1dSRodney W. Grimes MGETHDR(n, wait, m0->m_type); 862df8bae1dSRodney W. Grimes if (n == 0) 863df8bae1dSRodney W. Grimes return (0); 864df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 865df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 866df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 867df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 868df8bae1dSRodney W. Grimes goto extpacket; 869df8bae1dSRodney W. Grimes if (remain > MHLEN) { 870df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 871df8bae1dSRodney W. Grimes MH_ALIGN(n, 0); 872df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 873df8bae1dSRodney W. Grimes if (n->m_next == 0) { 874df8bae1dSRodney W. Grimes (void) m_free(n); 875df8bae1dSRodney W. Grimes return (0); 876df8bae1dSRodney W. Grimes } else 877df8bae1dSRodney W. Grimes return (n); 878df8bae1dSRodney W. Grimes } else 879df8bae1dSRodney W. Grimes MH_ALIGN(n, remain); 880df8bae1dSRodney W. Grimes } else if (remain == 0) { 881df8bae1dSRodney W. Grimes n = m->m_next; 882df8bae1dSRodney W. Grimes m->m_next = 0; 883df8bae1dSRodney W. Grimes return (n); 884df8bae1dSRodney W. Grimes } else { 885df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 886df8bae1dSRodney W. Grimes if (n == 0) 887df8bae1dSRodney W. Grimes return (0); 888df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 889df8bae1dSRodney W. Grimes } 890df8bae1dSRodney W. Grimes extpacket: 891df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 892df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 893df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 8940885c1d2SJulian Elischer if(!m->m_ext.ext_ref) 895df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 8960885c1d2SJulian Elischer else 8970885c1d2SJulian Elischer (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 8980885c1d2SJulian Elischer m->m_ext.ext_size); 899df8bae1dSRodney W. Grimes m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ 900df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 901df8bae1dSRodney W. Grimes } else { 902df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 903df8bae1dSRodney W. Grimes } 904df8bae1dSRodney W. Grimes n->m_len = remain; 905df8bae1dSRodney W. Grimes m->m_len = len; 906df8bae1dSRodney W. Grimes n->m_next = m->m_next; 907df8bae1dSRodney W. Grimes m->m_next = 0; 908df8bae1dSRodney W. Grimes return (n); 909df8bae1dSRodney W. Grimes } 910df8bae1dSRodney W. Grimes /* 911df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 912df8bae1dSRodney W. Grimes */ 913df8bae1dSRodney W. Grimes struct mbuf * 914df8bae1dSRodney W. Grimes m_devget(buf, totlen, off0, ifp, copy) 915df8bae1dSRodney W. Grimes char *buf; 916df8bae1dSRodney W. Grimes int totlen, off0; 917df8bae1dSRodney W. Grimes struct ifnet *ifp; 91898d93822SBruce Evans void (*copy) __P((char *from, caddr_t to, u_int len)); 919df8bae1dSRodney W. Grimes { 920df8bae1dSRodney W. Grimes register struct mbuf *m; 921df8bae1dSRodney W. Grimes struct mbuf *top = 0, **mp = ⊤ 922df8bae1dSRodney W. Grimes register int off = off0, len; 923df8bae1dSRodney W. Grimes register char *cp; 924df8bae1dSRodney W. Grimes char *epkt; 925df8bae1dSRodney W. Grimes 926df8bae1dSRodney W. Grimes cp = buf; 927df8bae1dSRodney W. Grimes epkt = cp + totlen; 928df8bae1dSRodney W. Grimes if (off) { 929df8bae1dSRodney W. Grimes cp += off + 2 * sizeof(u_short); 930df8bae1dSRodney W. Grimes totlen -= 2 * sizeof(u_short); 931df8bae1dSRodney W. Grimes } 932df8bae1dSRodney W. Grimes MGETHDR(m, M_DONTWAIT, MT_DATA); 933df8bae1dSRodney W. Grimes if (m == 0) 934df8bae1dSRodney W. Grimes return (0); 935df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 936df8bae1dSRodney W. Grimes m->m_pkthdr.len = totlen; 937df8bae1dSRodney W. Grimes m->m_len = MHLEN; 938df8bae1dSRodney W. Grimes 939df8bae1dSRodney W. Grimes while (totlen > 0) { 940df8bae1dSRodney W. Grimes if (top) { 941df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_DATA); 942df8bae1dSRodney W. Grimes if (m == 0) { 943df8bae1dSRodney W. Grimes m_freem(top); 944df8bae1dSRodney W. Grimes return (0); 945df8bae1dSRodney W. Grimes } 946df8bae1dSRodney W. Grimes m->m_len = MLEN; 947df8bae1dSRodney W. Grimes } 948df8bae1dSRodney W. Grimes len = min(totlen, epkt - cp); 949df8bae1dSRodney W. Grimes if (len >= MINCLSIZE) { 950df8bae1dSRodney W. Grimes MCLGET(m, M_DONTWAIT); 951df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 952df8bae1dSRodney W. Grimes m->m_len = len = min(len, MCLBYTES); 953df8bae1dSRodney W. Grimes else 954df8bae1dSRodney W. Grimes len = m->m_len; 955df8bae1dSRodney W. Grimes } else { 956df8bae1dSRodney W. Grimes /* 957df8bae1dSRodney W. Grimes * Place initial small packet/header at end of mbuf. 958df8bae1dSRodney W. Grimes */ 959df8bae1dSRodney W. Grimes if (len < m->m_len) { 960df8bae1dSRodney W. Grimes if (top == 0 && len + max_linkhdr <= m->m_len) 961df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 962df8bae1dSRodney W. Grimes m->m_len = len; 963df8bae1dSRodney W. Grimes } else 964df8bae1dSRodney W. Grimes len = m->m_len; 965df8bae1dSRodney W. Grimes } 966df8bae1dSRodney W. Grimes if (copy) 967df8bae1dSRodney W. Grimes copy(cp, mtod(m, caddr_t), (unsigned)len); 968df8bae1dSRodney W. Grimes else 969df8bae1dSRodney W. Grimes bcopy(cp, mtod(m, caddr_t), (unsigned)len); 970df8bae1dSRodney W. Grimes cp += len; 971df8bae1dSRodney W. Grimes *mp = m; 972df8bae1dSRodney W. Grimes mp = &m->m_next; 973df8bae1dSRodney W. Grimes totlen -= len; 974df8bae1dSRodney W. Grimes if (cp == epkt) 975df8bae1dSRodney W. Grimes cp = buf; 976df8bae1dSRodney W. Grimes } 977df8bae1dSRodney W. Grimes return (top); 978df8bae1dSRodney W. Grimes } 979c5789ba3SPoul-Henning Kamp 980c5789ba3SPoul-Henning Kamp /* 981c5789ba3SPoul-Henning Kamp * Copy data from a buffer back into the indicated mbuf chain, 982c5789ba3SPoul-Henning Kamp * starting "off" bytes from the beginning, extending the mbuf 983c5789ba3SPoul-Henning Kamp * chain if necessary. 984c5789ba3SPoul-Henning Kamp */ 985c5789ba3SPoul-Henning Kamp void 986c5789ba3SPoul-Henning Kamp m_copyback(m0, off, len, cp) 987c5789ba3SPoul-Henning Kamp struct mbuf *m0; 988c5789ba3SPoul-Henning Kamp register int off; 989c5789ba3SPoul-Henning Kamp register int len; 990c5789ba3SPoul-Henning Kamp caddr_t cp; 991c5789ba3SPoul-Henning Kamp { 992c5789ba3SPoul-Henning Kamp register int mlen; 993c5789ba3SPoul-Henning Kamp register struct mbuf *m = m0, *n; 994c5789ba3SPoul-Henning Kamp int totlen = 0; 995c5789ba3SPoul-Henning Kamp 996c5789ba3SPoul-Henning Kamp if (m0 == 0) 997c5789ba3SPoul-Henning Kamp return; 998c5789ba3SPoul-Henning Kamp while (off > (mlen = m->m_len)) { 999c5789ba3SPoul-Henning Kamp off -= mlen; 1000c5789ba3SPoul-Henning Kamp totlen += mlen; 1001c5789ba3SPoul-Henning Kamp if (m->m_next == 0) { 1002c5789ba3SPoul-Henning Kamp n = m_getclr(M_DONTWAIT, m->m_type); 1003c5789ba3SPoul-Henning Kamp if (n == 0) 1004c5789ba3SPoul-Henning Kamp goto out; 1005c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len + off); 1006c5789ba3SPoul-Henning Kamp m->m_next = n; 1007c5789ba3SPoul-Henning Kamp } 1008c5789ba3SPoul-Henning Kamp m = m->m_next; 1009c5789ba3SPoul-Henning Kamp } 1010c5789ba3SPoul-Henning Kamp while (len > 0) { 1011c5789ba3SPoul-Henning Kamp mlen = min (m->m_len - off, len); 1012c5789ba3SPoul-Henning Kamp bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 1013c5789ba3SPoul-Henning Kamp cp += mlen; 1014c5789ba3SPoul-Henning Kamp len -= mlen; 1015c5789ba3SPoul-Henning Kamp mlen += off; 1016c5789ba3SPoul-Henning Kamp off = 0; 1017c5789ba3SPoul-Henning Kamp totlen += mlen; 1018c5789ba3SPoul-Henning Kamp if (len == 0) 1019c5789ba3SPoul-Henning Kamp break; 1020c5789ba3SPoul-Henning Kamp if (m->m_next == 0) { 1021c5789ba3SPoul-Henning Kamp n = m_get(M_DONTWAIT, m->m_type); 1022c5789ba3SPoul-Henning Kamp if (n == 0) 1023c5789ba3SPoul-Henning Kamp break; 1024c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len); 1025c5789ba3SPoul-Henning Kamp m->m_next = n; 1026c5789ba3SPoul-Henning Kamp } 1027c5789ba3SPoul-Henning Kamp m = m->m_next; 1028c5789ba3SPoul-Henning Kamp } 1029c5789ba3SPoul-Henning Kamp out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 1030c5789ba3SPoul-Henning Kamp m->m_pkthdr.len = totlen; 1031c5789ba3SPoul-Henning Kamp } 1032ce4a64f7SPoul-Henning Kamp 1033ce4a64f7SPoul-Henning Kamp void 1034ce4a64f7SPoul-Henning Kamp m_print(const struct mbuf *m) 1035ce4a64f7SPoul-Henning Kamp { 1036ce4a64f7SPoul-Henning Kamp int len; 1037eed9fd42SPeter Wemm const struct mbuf *m2; 1038ce4a64f7SPoul-Henning Kamp 1039ce4a64f7SPoul-Henning Kamp len = m->m_pkthdr.len; 1040ce4a64f7SPoul-Henning Kamp m2 = m; 1041ce4a64f7SPoul-Henning Kamp while (len) { 1042ce4a64f7SPoul-Henning Kamp printf("%p %*D\n", m2, m2->m_len, (u_char *)m2->m_data, "-"); 1043ce4a64f7SPoul-Henning Kamp len -= m2->m_len; 1044ce4a64f7SPoul-Henning Kamp m2 = m2->m_next; 1045ce4a64f7SPoul-Henning Kamp } 1046ce4a64f7SPoul-Henning Kamp return; 1047ce4a64f7SPoul-Henning Kamp } 1048