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 34639acc13SGarrett Wollman * $Id: uipc_mbuf.c,v 1.28 1997/02/18 20:43:05 wollman Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39df8bae1dSRodney W. Grimes #include <sys/proc.h> 40df8bae1dSRodney W. Grimes #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #define MBTYPES 42df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 43df8bae1dSRodney W. Grimes #include <sys/kernel.h> 44639acc13SGarrett Wollman #include <sys/sysctl.h> 45df8bae1dSRodney W. Grimes #include <sys/syslog.h> 46df8bae1dSRodney W. Grimes #include <sys/domain.h> 47df8bae1dSRodney W. Grimes #include <sys/protosw.h> 48df8bae1dSRodney W. Grimes 49df8bae1dSRodney W. Grimes #include <vm/vm.h> 50efeaf95aSDavid Greenman #include <vm/vm_param.h> 5128f8db14SBruce Evans #include <vm/vm_kern.h> 52efeaf95aSDavid Greenman #include <vm/vm_extern.h> 53df8bae1dSRodney W. Grimes 544590fd3aSDavid Greenman static void mbinit __P((void *)); 552b14f991SJulian Elischer SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) 562b14f991SJulian Elischer 57df8bae1dSRodney W. Grimes struct mbuf *mbutl; 58df8bae1dSRodney W. Grimes char *mclrefcnt; 5928f8db14SBruce Evans struct mbstat mbstat; 606a06dea0SGarrett Wollman struct mbuf *mmbfree; 6128f8db14SBruce Evans union mcluster *mclfree; 6228f8db14SBruce Evans int max_linkhdr; 6328f8db14SBruce Evans int max_protohdr; 6428f8db14SBruce Evans int max_hdr; 6528f8db14SBruce Evans int max_datalen; 66df8bae1dSRodney W. Grimes 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, ""); 75639acc13SGarrett Wollman 7687b6de2bSPoul-Henning Kamp static void m_reclaim __P((void)); 7787b6de2bSPoul-Henning Kamp 780482730eSPoul-Henning Kamp /* "number of clusters of pages" */ 790482730eSPoul-Henning Kamp #define NCL_INIT 1 800482730eSPoul-Henning Kamp 817642f474SPoul-Henning Kamp #define NMB_INIT 16 827642f474SPoul-Henning Kamp 832b14f991SJulian Elischer /* ARGSUSED*/ 842b14f991SJulian Elischer static void 85d841aaa7SBruce Evans mbinit(dummy) 86d841aaa7SBruce Evans void *dummy; 87df8bae1dSRodney W. Grimes { 88df8bae1dSRodney W. Grimes int s; 89df8bae1dSRodney W. Grimes 906a06dea0SGarrett Wollman mmbfree = NULL; mclfree = NULL; 91639acc13SGarrett Wollman mbstat.m_msize = MSIZE; 92639acc13SGarrett Wollman mbstat.m_mclbytes = MCLBYTES; 93639acc13SGarrett Wollman mbstat.m_minclsize = MINCLSIZE; 94639acc13SGarrett Wollman mbstat.m_mlen = MLEN; 95639acc13SGarrett Wollman mbstat.m_mhlen = MHLEN; 96639acc13SGarrett Wollman 97df8bae1dSRodney W. Grimes s = splimp(); 986a06dea0SGarrett Wollman if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0) 996a06dea0SGarrett Wollman goto bad; 10030f700e9SGarrett Wollman #if MCLBYTES <= PAGE_SIZE 101df8bae1dSRodney W. Grimes if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 102df8bae1dSRodney W. Grimes goto bad; 10330f700e9SGarrett Wollman #else 10430f700e9SGarrett Wollman /* It's OK to call contigmalloc in this context. */ 10530f700e9SGarrett Wollman if (m_clalloc(16, 0) == 0) 10630f700e9SGarrett Wollman goto bad; 10730f700e9SGarrett Wollman #endif 108df8bae1dSRodney W. Grimes splx(s); 109df8bae1dSRodney W. Grimes return; 110df8bae1dSRodney W. Grimes bad: 111df8bae1dSRodney W. Grimes panic("mbinit"); 112df8bae1dSRodney W. Grimes } 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes /* 1156a06dea0SGarrett Wollman * Allocate at least nmb mbufs and place on mbuf free list. 1166a06dea0SGarrett Wollman * Must be called at splimp. 1176a06dea0SGarrett Wollman */ 1186a06dea0SGarrett Wollman /* ARGSUSED */ 1196a06dea0SGarrett Wollman int 1206a06dea0SGarrett Wollman m_mballoc(nmb, nowait) 1216a06dea0SGarrett Wollman register int nmb; 1226a06dea0SGarrett Wollman int nowait; 1236a06dea0SGarrett Wollman { 1246a06dea0SGarrett Wollman register caddr_t p; 1256a06dea0SGarrett Wollman register int i; 1266a06dea0SGarrett Wollman int nbytes; 1276a06dea0SGarrett Wollman 1286a06dea0SGarrett Wollman /* Once we run out of map space, it will be impossible to get 1296a06dea0SGarrett Wollman * any more (nothing is ever freed back to the map) (XXX which 1306a06dea0SGarrett Wollman * is dumb). (however you are not dead as m_reclaim might 1316a06dea0SGarrett Wollman * still be able to free a substantial amount of space). 1326a06dea0SGarrett Wollman */ 1336a06dea0SGarrett Wollman if (mb_map_full) 1346a06dea0SGarrett Wollman return (0); 1356a06dea0SGarrett Wollman 1366a06dea0SGarrett Wollman nbytes = round_page(nmb * MSIZE); 137d8392c6cSGarrett Wollman p = (caddr_t)kmem_malloc(mb_map, nbytes, M_NOWAIT); 138d8392c6cSGarrett Wollman if (p == 0 && !nowait) { 139d8392c6cSGarrett Wollman mbstat.m_wait++; 140d8392c6cSGarrett Wollman p = (caddr_t)kmem_malloc(mb_map, nbytes, M_WAITOK); 141d8392c6cSGarrett Wollman } 142d8392c6cSGarrett Wollman 1436a06dea0SGarrett Wollman /* 1446a06dea0SGarrett Wollman * Either the map is now full, or this is nowait and there 1456a06dea0SGarrett Wollman * are no pages left. 1466a06dea0SGarrett Wollman */ 1476a06dea0SGarrett Wollman if (p == NULL) 1486a06dea0SGarrett Wollman return (0); 1496a06dea0SGarrett Wollman 1506a06dea0SGarrett Wollman nmb = nbytes / MSIZE; 1516a06dea0SGarrett Wollman for (i = 0; i < nmb; i++) { 1526a06dea0SGarrett Wollman ((struct mbuf *)p)->m_next = mmbfree; 1536a06dea0SGarrett Wollman mmbfree = (struct mbuf *)p; 1546a06dea0SGarrett Wollman p += MSIZE; 1556a06dea0SGarrett Wollman } 1566a06dea0SGarrett Wollman mbstat.m_mbufs += nmb; 1576a06dea0SGarrett Wollman return (1); 1586a06dea0SGarrett Wollman } 1596a06dea0SGarrett Wollman 16030f700e9SGarrett Wollman #if MCLBYTES > PAGE_SIZE 161d8392c6cSGarrett Wollman static int i_want_my_mcl; 16230f700e9SGarrett Wollman 163d8392c6cSGarrett Wollman static void 16430f700e9SGarrett Wollman kproc_mclalloc(void) 16530f700e9SGarrett Wollman { 16630f700e9SGarrett Wollman int status; 16730f700e9SGarrett Wollman 16830f700e9SGarrett Wollman while (1) { 16930f700e9SGarrett Wollman tsleep(&i_want_my_mcl, PVM, "mclalloc", 0); 17030f700e9SGarrett Wollman 17130f700e9SGarrett Wollman for (; i_want_my_mcl; i_want_my_mcl--) { 17230f700e9SGarrett Wollman if (m_clalloc(1, 0) == 0) 17330f700e9SGarrett Wollman printf("m_clalloc failed even in process context!\n"); 17430f700e9SGarrett Wollman } 17530f700e9SGarrett Wollman } 17630f700e9SGarrett Wollman } 17730f700e9SGarrett Wollman 17830f700e9SGarrett Wollman static struct proc *mclallocproc; 17930f700e9SGarrett Wollman static struct kproc_desc mclalloc_kp = { 18030f700e9SGarrett Wollman "mclalloc", 18130f700e9SGarrett Wollman kproc_mclalloc, 18230f700e9SGarrett Wollman &mclallocproc 18330f700e9SGarrett Wollman }; 18430f700e9SGarrett Wollman SYSINIT_KT(mclallocproc, SI_SUB_KTHREAD_UPDATE, SI_ORDER_ANY, kproc_start, 18530f700e9SGarrett Wollman &mclalloc_kp); 18630f700e9SGarrett Wollman #endif 18730f700e9SGarrett Wollman 1886a06dea0SGarrett Wollman /* 189df8bae1dSRodney W. Grimes * Allocate some number of mbuf clusters 190df8bae1dSRodney W. Grimes * and place on cluster free list. 191df8bae1dSRodney W. Grimes * Must be called at splimp. 192df8bae1dSRodney W. Grimes */ 193df8bae1dSRodney W. Grimes /* ARGSUSED */ 19426f9a767SRodney W. Grimes int 195df8bae1dSRodney W. Grimes m_clalloc(ncl, nowait) 196df8bae1dSRodney W. Grimes register int ncl; 197df8bae1dSRodney W. Grimes int nowait; 198df8bae1dSRodney W. Grimes { 199df8bae1dSRodney W. Grimes register caddr_t p; 200df8bae1dSRodney W. Grimes register int i; 201df8bae1dSRodney W. Grimes int npg; 202df8bae1dSRodney W. Grimes 2035eb7d0cdSDavid Greenman /* 2045eb7d0cdSDavid Greenman * Once we run out of map space, it will be impossible 2055eb7d0cdSDavid Greenman * to get any more (nothing is ever freed back to the 2065eb7d0cdSDavid Greenman * map). 2075eb7d0cdSDavid Greenman */ 208d8392c6cSGarrett Wollman if (mb_map_full) { 209d8392c6cSGarrett Wollman mbstat.m_drops++; 2105eb7d0cdSDavid Greenman return (0); 211d8392c6cSGarrett Wollman } 2125eb7d0cdSDavid Greenman 21330f700e9SGarrett Wollman #if MCLBYTES > PAGE_SIZE 21430f700e9SGarrett Wollman if (nowait) { 21530f700e9SGarrett Wollman i_want_my_mcl += ncl; 21630f700e9SGarrett Wollman wakeup(&i_want_my_mcl); 217d8392c6cSGarrett Wollman mbstat.m_wait++; 21830f700e9SGarrett Wollman p = 0; 21930f700e9SGarrett Wollman } else { 22030f700e9SGarrett Wollman p = contigmalloc1(MCLBYTES * ncl, M_DEVBUF, M_WAITOK, 0ul, 22130f700e9SGarrett Wollman ~0ul, PAGE_SIZE, 0, mb_map); 22230f700e9SGarrett Wollman } 22330f700e9SGarrett Wollman #else 224e911eafcSPoul-Henning Kamp npg = ncl; 225649c409dSDavid Greenman p = (caddr_t)kmem_malloc(mb_map, ctob(npg), 2260bc786d0SBruce Evans nowait ? M_NOWAIT : M_WAITOK); 22730f700e9SGarrett Wollman ncl = ncl * PAGE_SIZE / MCLBYTES; 22830f700e9SGarrett Wollman #endif 2295eb7d0cdSDavid Greenman /* 2305eb7d0cdSDavid Greenman * Either the map is now full, or this is nowait and there 2315eb7d0cdSDavid Greenman * are no pages left. 2325eb7d0cdSDavid Greenman */ 233d8392c6cSGarrett Wollman if (p == NULL) { 234d8392c6cSGarrett Wollman mbstat.m_drops++; 235df8bae1dSRodney W. Grimes return (0); 236d8392c6cSGarrett Wollman } 2375eb7d0cdSDavid Greenman 238df8bae1dSRodney W. Grimes for (i = 0; i < ncl; i++) { 239df8bae1dSRodney W. Grimes ((union mcluster *)p)->mcl_next = mclfree; 240df8bae1dSRodney W. Grimes mclfree = (union mcluster *)p; 241df8bae1dSRodney W. Grimes p += MCLBYTES; 242df8bae1dSRodney W. Grimes mbstat.m_clfree++; 243df8bae1dSRodney W. Grimes } 244df8bae1dSRodney W. Grimes mbstat.m_clusters += ncl; 245df8bae1dSRodney W. Grimes return (1); 246df8bae1dSRodney W. Grimes } 247df8bae1dSRodney W. Grimes 248df8bae1dSRodney W. Grimes /* 249df8bae1dSRodney W. Grimes * When MGET failes, ask protocols to free space when short of memory, 250df8bae1dSRodney W. Grimes * then re-attempt to allocate an mbuf. 251df8bae1dSRodney W. Grimes */ 252df8bae1dSRodney W. Grimes struct mbuf * 253df8bae1dSRodney W. Grimes m_retry(i, t) 254df8bae1dSRodney W. Grimes int i, t; 255df8bae1dSRodney W. Grimes { 256df8bae1dSRodney W. Grimes register struct mbuf *m; 257df8bae1dSRodney W. Grimes 258df8bae1dSRodney W. Grimes m_reclaim(); 259df8bae1dSRodney W. Grimes #define m_retry(i, t) (struct mbuf *)0 260df8bae1dSRodney W. Grimes MGET(m, i, t); 261df8bae1dSRodney W. Grimes #undef m_retry 2629b4b42d1SDavid Greenman if (m != NULL) 2639b4b42d1SDavid Greenman mbstat.m_wait++; 2649b4b42d1SDavid Greenman else 2659b4b42d1SDavid Greenman mbstat.m_drops++; 266df8bae1dSRodney W. Grimes return (m); 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 269df8bae1dSRodney W. Grimes /* 270df8bae1dSRodney W. Grimes * As above; retry an MGETHDR. 271df8bae1dSRodney W. Grimes */ 272df8bae1dSRodney W. Grimes struct mbuf * 273df8bae1dSRodney W. Grimes m_retryhdr(i, t) 274df8bae1dSRodney W. Grimes int i, t; 275df8bae1dSRodney W. Grimes { 276df8bae1dSRodney W. Grimes register struct mbuf *m; 277df8bae1dSRodney W. Grimes 278df8bae1dSRodney W. Grimes m_reclaim(); 279df8bae1dSRodney W. Grimes #define m_retryhdr(i, t) (struct mbuf *)0 280df8bae1dSRodney W. Grimes MGETHDR(m, i, t); 281df8bae1dSRodney W. Grimes #undef m_retryhdr 2829b4b42d1SDavid Greenman if (m != NULL) 2839b4b42d1SDavid Greenman mbstat.m_wait++; 2849b4b42d1SDavid Greenman else 2859b4b42d1SDavid Greenman mbstat.m_drops++; 286df8bae1dSRodney W. Grimes return (m); 287df8bae1dSRodney W. Grimes } 288df8bae1dSRodney W. Grimes 28987b6de2bSPoul-Henning Kamp static void 290df8bae1dSRodney W. Grimes m_reclaim() 291df8bae1dSRodney W. Grimes { 292df8bae1dSRodney W. Grimes register struct domain *dp; 293df8bae1dSRodney W. Grimes register struct protosw *pr; 294df8bae1dSRodney W. Grimes int s = splimp(); 295df8bae1dSRodney W. Grimes 296df8bae1dSRodney W. Grimes for (dp = domains; dp; dp = dp->dom_next) 297df8bae1dSRodney W. Grimes for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 298df8bae1dSRodney W. Grimes if (pr->pr_drain) 299df8bae1dSRodney W. Grimes (*pr->pr_drain)(); 300df8bae1dSRodney W. Grimes splx(s); 301df8bae1dSRodney W. Grimes mbstat.m_drain++; 302df8bae1dSRodney W. Grimes } 303df8bae1dSRodney W. Grimes 304df8bae1dSRodney W. Grimes /* 305df8bae1dSRodney W. Grimes * Space allocation routines. 306df8bae1dSRodney W. Grimes * These are also available as macros 307df8bae1dSRodney W. Grimes * for critical paths. 308df8bae1dSRodney W. Grimes */ 309df8bae1dSRodney W. Grimes struct mbuf * 310df8bae1dSRodney W. Grimes m_get(nowait, type) 311df8bae1dSRodney W. Grimes int nowait, type; 312df8bae1dSRodney W. Grimes { 313df8bae1dSRodney W. Grimes register struct mbuf *m; 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes MGET(m, nowait, type); 316df8bae1dSRodney W. Grimes return (m); 317df8bae1dSRodney W. Grimes } 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes struct mbuf * 320df8bae1dSRodney W. Grimes m_gethdr(nowait, type) 321df8bae1dSRodney W. Grimes int nowait, type; 322df8bae1dSRodney W. Grimes { 323df8bae1dSRodney W. Grimes register struct mbuf *m; 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes MGETHDR(m, nowait, type); 326df8bae1dSRodney W. Grimes return (m); 327df8bae1dSRodney W. Grimes } 328df8bae1dSRodney W. Grimes 329df8bae1dSRodney W. Grimes struct mbuf * 330df8bae1dSRodney W. Grimes m_getclr(nowait, type) 331df8bae1dSRodney W. Grimes int nowait, type; 332df8bae1dSRodney W. Grimes { 333df8bae1dSRodney W. Grimes register struct mbuf *m; 334df8bae1dSRodney W. Grimes 335df8bae1dSRodney W. Grimes MGET(m, nowait, type); 336df8bae1dSRodney W. Grimes if (m == 0) 337df8bae1dSRodney W. Grimes return (0); 338df8bae1dSRodney W. Grimes bzero(mtod(m, caddr_t), MLEN); 339df8bae1dSRodney W. Grimes return (m); 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes 342df8bae1dSRodney W. Grimes struct mbuf * 343df8bae1dSRodney W. Grimes m_free(m) 344df8bae1dSRodney W. Grimes struct mbuf *m; 345df8bae1dSRodney W. Grimes { 346df8bae1dSRodney W. Grimes register struct mbuf *n; 347df8bae1dSRodney W. Grimes 348df8bae1dSRodney W. Grimes MFREE(m, n); 349df8bae1dSRodney W. Grimes return (n); 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes void 353df8bae1dSRodney W. Grimes m_freem(m) 354df8bae1dSRodney W. Grimes register struct mbuf *m; 355df8bae1dSRodney W. Grimes { 356df8bae1dSRodney W. Grimes register struct mbuf *n; 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes if (m == NULL) 359df8bae1dSRodney W. Grimes return; 360df8bae1dSRodney W. Grimes do { 361df8bae1dSRodney W. Grimes MFREE(m, n); 362797f2d22SPoul-Henning Kamp m = n; 363797f2d22SPoul-Henning Kamp } while (m); 364df8bae1dSRodney W. Grimes } 365df8bae1dSRodney W. Grimes 366df8bae1dSRodney W. Grimes /* 367df8bae1dSRodney W. Grimes * Mbuffer utility routines. 368df8bae1dSRodney W. Grimes */ 369df8bae1dSRodney W. Grimes 370df8bae1dSRodney W. Grimes /* 371df8bae1dSRodney W. Grimes * Lesser-used path for M_PREPEND: 372df8bae1dSRodney W. Grimes * allocate new mbuf to prepend to chain, 373df8bae1dSRodney W. Grimes * copy junk along. 374df8bae1dSRodney W. Grimes */ 375df8bae1dSRodney W. Grimes struct mbuf * 376df8bae1dSRodney W. Grimes m_prepend(m, len, how) 377df8bae1dSRodney W. Grimes register struct mbuf *m; 378df8bae1dSRodney W. Grimes int len, how; 379df8bae1dSRodney W. Grimes { 380df8bae1dSRodney W. Grimes struct mbuf *mn; 381df8bae1dSRodney W. Grimes 382df8bae1dSRodney W. Grimes MGET(mn, how, m->m_type); 383df8bae1dSRodney W. Grimes if (mn == (struct mbuf *)NULL) { 384df8bae1dSRodney W. Grimes m_freem(m); 385df8bae1dSRodney W. Grimes return ((struct mbuf *)NULL); 386df8bae1dSRodney W. Grimes } 387df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { 388df8bae1dSRodney W. Grimes M_COPY_PKTHDR(mn, m); 389df8bae1dSRodney W. Grimes m->m_flags &= ~M_PKTHDR; 390df8bae1dSRodney W. Grimes } 391df8bae1dSRodney W. Grimes mn->m_next = m; 392df8bae1dSRodney W. Grimes m = mn; 393df8bae1dSRodney W. Grimes if (len < MHLEN) 394df8bae1dSRodney W. Grimes MH_ALIGN(m, len); 395df8bae1dSRodney W. Grimes m->m_len = len; 396df8bae1dSRodney W. Grimes return (m); 397df8bae1dSRodney W. Grimes } 398df8bae1dSRodney W. Grimes 399df8bae1dSRodney W. Grimes /* 400df8bae1dSRodney W. Grimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 401df8bae1dSRodney W. Grimes * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 402df8bae1dSRodney W. Grimes * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. 403df8bae1dSRodney W. Grimes */ 404639acc13SGarrett Wollman #define MCFail (mbstat.m_mcfail) 405df8bae1dSRodney W. Grimes 406df8bae1dSRodney W. Grimes struct mbuf * 407df8bae1dSRodney W. Grimes m_copym(m, off0, len, wait) 408df8bae1dSRodney W. Grimes register struct mbuf *m; 409df8bae1dSRodney W. Grimes int off0, wait; 410df8bae1dSRodney W. Grimes register int len; 411df8bae1dSRodney W. Grimes { 412df8bae1dSRodney W. Grimes register struct mbuf *n, **np; 413df8bae1dSRodney W. Grimes register int off = off0; 414df8bae1dSRodney W. Grimes struct mbuf *top; 415df8bae1dSRodney W. Grimes int copyhdr = 0; 416df8bae1dSRodney W. Grimes 417df8bae1dSRodney W. Grimes if (off < 0 || len < 0) 418df8bae1dSRodney W. Grimes panic("m_copym"); 419df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 420df8bae1dSRodney W. Grimes copyhdr = 1; 421df8bae1dSRodney W. Grimes while (off > 0) { 422df8bae1dSRodney W. Grimes if (m == 0) 423df8bae1dSRodney W. Grimes panic("m_copym"); 424df8bae1dSRodney W. Grimes if (off < m->m_len) 425df8bae1dSRodney W. Grimes break; 426df8bae1dSRodney W. Grimes off -= m->m_len; 427df8bae1dSRodney W. Grimes m = m->m_next; 428df8bae1dSRodney W. Grimes } 429df8bae1dSRodney W. Grimes np = ⊤ 430df8bae1dSRodney W. Grimes top = 0; 431df8bae1dSRodney W. Grimes while (len > 0) { 432df8bae1dSRodney W. Grimes if (m == 0) { 433df8bae1dSRodney W. Grimes if (len != M_COPYALL) 434df8bae1dSRodney W. Grimes panic("m_copym"); 435df8bae1dSRodney W. Grimes break; 436df8bae1dSRodney W. Grimes } 437df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 438df8bae1dSRodney W. Grimes *np = n; 439df8bae1dSRodney W. Grimes if (n == 0) 440df8bae1dSRodney W. Grimes goto nospace; 441df8bae1dSRodney W. Grimes if (copyhdr) { 442df8bae1dSRodney W. Grimes M_COPY_PKTHDR(n, m); 443df8bae1dSRodney W. Grimes if (len == M_COPYALL) 444df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 445df8bae1dSRodney W. Grimes else 446df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 447df8bae1dSRodney W. Grimes copyhdr = 0; 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 450df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 451df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 4520885c1d2SJulian Elischer if(!m->m_ext.ext_ref) 453df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 4540885c1d2SJulian Elischer else 4550885c1d2SJulian Elischer (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 4560885c1d2SJulian Elischer m->m_ext.ext_size); 457df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 458df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 459df8bae1dSRodney W. Grimes } else 460df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 461df8bae1dSRodney W. Grimes (unsigned)n->m_len); 462df8bae1dSRodney W. Grimes if (len != M_COPYALL) 463df8bae1dSRodney W. Grimes len -= n->m_len; 464df8bae1dSRodney W. Grimes off = 0; 465df8bae1dSRodney W. Grimes m = m->m_next; 466df8bae1dSRodney W. Grimes np = &n->m_next; 467df8bae1dSRodney W. Grimes } 468df8bae1dSRodney W. Grimes if (top == 0) 469df8bae1dSRodney W. Grimes MCFail++; 470df8bae1dSRodney W. Grimes return (top); 471df8bae1dSRodney W. Grimes nospace: 472df8bae1dSRodney W. Grimes m_freem(top); 473df8bae1dSRodney W. Grimes MCFail++; 474df8bae1dSRodney W. Grimes return (0); 475df8bae1dSRodney W. Grimes } 476df8bae1dSRodney W. Grimes 477df8bae1dSRodney W. Grimes /* 4786a06dea0SGarrett Wollman * Copy an entire packet, including header (which must be present). 4796a06dea0SGarrett Wollman * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. 4806a06dea0SGarrett Wollman */ 4816a06dea0SGarrett Wollman struct mbuf * 4826a06dea0SGarrett Wollman m_copypacket(m, how) 4836a06dea0SGarrett Wollman struct mbuf *m; 4846a06dea0SGarrett Wollman int how; 4856a06dea0SGarrett Wollman { 4866a06dea0SGarrett Wollman struct mbuf *top, *n, *o; 4876a06dea0SGarrett Wollman 4886a06dea0SGarrett Wollman MGET(n, how, m->m_type); 4896a06dea0SGarrett Wollman top = n; 4906a06dea0SGarrett Wollman if (!n) 4916a06dea0SGarrett Wollman goto nospace; 4926a06dea0SGarrett Wollman 4936a06dea0SGarrett Wollman M_COPY_PKTHDR(n, m); 4946a06dea0SGarrett Wollman n->m_len = m->m_len; 4956a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 4966a06dea0SGarrett Wollman n->m_data = m->m_data; 4976a06dea0SGarrett Wollman mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 4986a06dea0SGarrett Wollman n->m_ext = m->m_ext; 4996a06dea0SGarrett Wollman n->m_flags |= M_EXT; 5006a06dea0SGarrett Wollman } else { 5016a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5026a06dea0SGarrett Wollman } 5036a06dea0SGarrett Wollman 5046a06dea0SGarrett Wollman m = m->m_next; 5056a06dea0SGarrett Wollman while (m) { 5066a06dea0SGarrett Wollman MGET(o, how, m->m_type); 5076a06dea0SGarrett Wollman if (!o) 5086a06dea0SGarrett Wollman goto nospace; 5096a06dea0SGarrett Wollman 5106a06dea0SGarrett Wollman n->m_next = o; 5116a06dea0SGarrett Wollman n = n->m_next; 5126a06dea0SGarrett Wollman 5136a06dea0SGarrett Wollman n->m_len = m->m_len; 5146a06dea0SGarrett Wollman if (m->m_flags & M_EXT) { 5156a06dea0SGarrett Wollman n->m_data = m->m_data; 5166a06dea0SGarrett Wollman mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 5176a06dea0SGarrett Wollman n->m_ext = m->m_ext; 5186a06dea0SGarrett Wollman n->m_flags |= M_EXT; 5196a06dea0SGarrett Wollman } else { 5206a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5216a06dea0SGarrett Wollman } 5226a06dea0SGarrett Wollman 5236a06dea0SGarrett Wollman m = m->m_next; 5246a06dea0SGarrett Wollman } 5256a06dea0SGarrett Wollman return top; 5266a06dea0SGarrett Wollman nospace: 5276a06dea0SGarrett Wollman m_freem(top); 5286a06dea0SGarrett Wollman MCFail++; 5296a06dea0SGarrett Wollman return 0; 5306a06dea0SGarrett Wollman } 5316a06dea0SGarrett Wollman 5326a06dea0SGarrett Wollman /* 533df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 534df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 535df8bae1dSRodney W. Grimes */ 53626f9a767SRodney W. Grimes void 537df8bae1dSRodney W. Grimes m_copydata(m, off, len, cp) 538df8bae1dSRodney W. Grimes register struct mbuf *m; 539df8bae1dSRodney W. Grimes register int off; 540df8bae1dSRodney W. Grimes register int len; 541df8bae1dSRodney W. Grimes caddr_t cp; 542df8bae1dSRodney W. Grimes { 543df8bae1dSRodney W. Grimes register unsigned count; 544df8bae1dSRodney W. Grimes 545df8bae1dSRodney W. Grimes if (off < 0 || len < 0) 546df8bae1dSRodney W. Grimes panic("m_copydata"); 547df8bae1dSRodney W. Grimes while (off > 0) { 548df8bae1dSRodney W. Grimes if (m == 0) 549df8bae1dSRodney W. Grimes panic("m_copydata"); 550df8bae1dSRodney W. Grimes if (off < m->m_len) 551df8bae1dSRodney W. Grimes break; 552df8bae1dSRodney W. Grimes off -= m->m_len; 553df8bae1dSRodney W. Grimes m = m->m_next; 554df8bae1dSRodney W. Grimes } 555df8bae1dSRodney W. Grimes while (len > 0) { 556df8bae1dSRodney W. Grimes if (m == 0) 557df8bae1dSRodney W. Grimes panic("m_copydata"); 558df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 559df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 560df8bae1dSRodney W. Grimes len -= count; 561df8bae1dSRodney W. Grimes cp += count; 562df8bae1dSRodney W. Grimes off = 0; 563df8bae1dSRodney W. Grimes m = m->m_next; 564df8bae1dSRodney W. Grimes } 565df8bae1dSRodney W. Grimes } 566df8bae1dSRodney W. Grimes 567df8bae1dSRodney W. Grimes /* 568df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 569df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 570df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 571df8bae1dSRodney W. Grimes */ 57226f9a767SRodney W. Grimes void 573df8bae1dSRodney W. Grimes m_cat(m, n) 574df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 575df8bae1dSRodney W. Grimes { 576df8bae1dSRodney W. Grimes while (m->m_next) 577df8bae1dSRodney W. Grimes m = m->m_next; 578df8bae1dSRodney W. Grimes while (n) { 579df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT || 580df8bae1dSRodney W. Grimes m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 581df8bae1dSRodney W. Grimes /* just join the two chains */ 582df8bae1dSRodney W. Grimes m->m_next = n; 583df8bae1dSRodney W. Grimes return; 584df8bae1dSRodney W. Grimes } 585df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 586df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 587df8bae1dSRodney W. Grimes (u_int)n->m_len); 588df8bae1dSRodney W. Grimes m->m_len += n->m_len; 589df8bae1dSRodney W. Grimes n = m_free(n); 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes 59326f9a767SRodney W. Grimes void 594df8bae1dSRodney W. Grimes m_adj(mp, req_len) 595df8bae1dSRodney W. Grimes struct mbuf *mp; 596df8bae1dSRodney W. Grimes int req_len; 597df8bae1dSRodney W. Grimes { 598df8bae1dSRodney W. Grimes register int len = req_len; 599df8bae1dSRodney W. Grimes register struct mbuf *m; 600df8bae1dSRodney W. Grimes register count; 601df8bae1dSRodney W. Grimes 602df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 603df8bae1dSRodney W. Grimes return; 604df8bae1dSRodney W. Grimes if (len >= 0) { 605df8bae1dSRodney W. Grimes /* 606df8bae1dSRodney W. Grimes * Trim from head. 607df8bae1dSRodney W. Grimes */ 608df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 609df8bae1dSRodney W. Grimes if (m->m_len <= len) { 610df8bae1dSRodney W. Grimes len -= m->m_len; 611df8bae1dSRodney W. Grimes m->m_len = 0; 612df8bae1dSRodney W. Grimes m = m->m_next; 613df8bae1dSRodney W. Grimes } else { 614df8bae1dSRodney W. Grimes m->m_len -= len; 615df8bae1dSRodney W. Grimes m->m_data += len; 616df8bae1dSRodney W. Grimes len = 0; 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes } 619df8bae1dSRodney W. Grimes m = mp; 620df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 621df8bae1dSRodney W. Grimes m->m_pkthdr.len -= (req_len - len); 622df8bae1dSRodney W. Grimes } else { 623df8bae1dSRodney W. Grimes /* 624df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 625df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 626df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 627df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 628df8bae1dSRodney W. Grimes * after the remaining size. 629df8bae1dSRodney W. Grimes */ 630df8bae1dSRodney W. Grimes len = -len; 631df8bae1dSRodney W. Grimes count = 0; 632df8bae1dSRodney W. Grimes for (;;) { 633df8bae1dSRodney W. Grimes count += m->m_len; 634df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 635df8bae1dSRodney W. Grimes break; 636df8bae1dSRodney W. Grimes m = m->m_next; 637df8bae1dSRodney W. Grimes } 638df8bae1dSRodney W. Grimes if (m->m_len >= len) { 639df8bae1dSRodney W. Grimes m->m_len -= len; 640df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 641df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 642df8bae1dSRodney W. Grimes return; 643df8bae1dSRodney W. Grimes } 644df8bae1dSRodney W. Grimes count -= len; 645df8bae1dSRodney W. Grimes if (count < 0) 646df8bae1dSRodney W. Grimes count = 0; 647df8bae1dSRodney W. Grimes /* 648df8bae1dSRodney W. Grimes * Correct length for chain is "count". 649df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 650df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 651df8bae1dSRodney W. Grimes */ 652df8bae1dSRodney W. Grimes m = mp; 653df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 654df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 655df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 656df8bae1dSRodney W. Grimes if (m->m_len >= count) { 657df8bae1dSRodney W. Grimes m->m_len = count; 658df8bae1dSRodney W. Grimes break; 659df8bae1dSRodney W. Grimes } 660df8bae1dSRodney W. Grimes count -= m->m_len; 661df8bae1dSRodney W. Grimes } 662797f2d22SPoul-Henning Kamp while (m->m_next) 663797f2d22SPoul-Henning Kamp (m = m->m_next) ->m_len = 0; 664df8bae1dSRodney W. Grimes } 665df8bae1dSRodney W. Grimes } 666df8bae1dSRodney W. Grimes 667df8bae1dSRodney W. Grimes /* 668df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 669df8bae1dSRodney W. Grimes * and in the data area of an mbuf (so that mtod and dtom 670df8bae1dSRodney W. Grimes * will work for a structure of size len). Returns the resulting 671df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 672df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 673df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 674df8bae1dSRodney W. Grimes */ 675639acc13SGarrett Wollman #define MPFail (mbstat.m_mpfail) 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes struct mbuf * 678df8bae1dSRodney W. Grimes m_pullup(n, len) 679df8bae1dSRodney W. Grimes register struct mbuf *n; 680df8bae1dSRodney W. Grimes int len; 681df8bae1dSRodney W. Grimes { 682df8bae1dSRodney W. Grimes register struct mbuf *m; 683df8bae1dSRodney W. Grimes register int count; 684df8bae1dSRodney W. Grimes int space; 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes /* 687df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 688df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 689df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 690df8bae1dSRodney W. Grimes */ 691df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 692df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 693df8bae1dSRodney W. Grimes if (n->m_len >= len) 694df8bae1dSRodney W. Grimes return (n); 695df8bae1dSRodney W. Grimes m = n; 696df8bae1dSRodney W. Grimes n = n->m_next; 697df8bae1dSRodney W. Grimes len -= m->m_len; 698df8bae1dSRodney W. Grimes } else { 699df8bae1dSRodney W. Grimes if (len > MHLEN) 700df8bae1dSRodney W. Grimes goto bad; 701df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, n->m_type); 702df8bae1dSRodney W. Grimes if (m == 0) 703df8bae1dSRodney W. Grimes goto bad; 704df8bae1dSRodney W. Grimes m->m_len = 0; 705df8bae1dSRodney W. Grimes if (n->m_flags & M_PKTHDR) { 706df8bae1dSRodney W. Grimes M_COPY_PKTHDR(m, n); 707df8bae1dSRodney W. Grimes n->m_flags &= ~M_PKTHDR; 708df8bae1dSRodney W. Grimes } 709df8bae1dSRodney W. Grimes } 710df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 711df8bae1dSRodney W. Grimes do { 712df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 713df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 714df8bae1dSRodney W. Grimes (unsigned)count); 715df8bae1dSRodney W. Grimes len -= count; 716df8bae1dSRodney W. Grimes m->m_len += count; 717df8bae1dSRodney W. Grimes n->m_len -= count; 718df8bae1dSRodney W. Grimes space -= count; 719df8bae1dSRodney W. Grimes if (n->m_len) 720df8bae1dSRodney W. Grimes n->m_data += count; 721df8bae1dSRodney W. Grimes else 722df8bae1dSRodney W. Grimes n = m_free(n); 723df8bae1dSRodney W. Grimes } while (len > 0 && n); 724df8bae1dSRodney W. Grimes if (len > 0) { 725df8bae1dSRodney W. Grimes (void) m_free(m); 726df8bae1dSRodney W. Grimes goto bad; 727df8bae1dSRodney W. Grimes } 728df8bae1dSRodney W. Grimes m->m_next = n; 729df8bae1dSRodney W. Grimes return (m); 730df8bae1dSRodney W. Grimes bad: 731df8bae1dSRodney W. Grimes m_freem(n); 732df8bae1dSRodney W. Grimes MPFail++; 733df8bae1dSRodney W. Grimes return (0); 734df8bae1dSRodney W. Grimes } 735df8bae1dSRodney W. Grimes 736df8bae1dSRodney W. Grimes /* 737df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 738df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 739df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 740df8bae1dSRodney W. Grimes */ 741df8bae1dSRodney W. Grimes struct mbuf * 742df8bae1dSRodney W. Grimes m_split(m0, len0, wait) 743df8bae1dSRodney W. Grimes register struct mbuf *m0; 744df8bae1dSRodney W. Grimes int len0, wait; 745df8bae1dSRodney W. Grimes { 746df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 747df8bae1dSRodney W. Grimes unsigned len = len0, remain; 748df8bae1dSRodney W. Grimes 749df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 750df8bae1dSRodney W. Grimes len -= m->m_len; 751df8bae1dSRodney W. Grimes if (m == 0) 752df8bae1dSRodney W. Grimes return (0); 753df8bae1dSRodney W. Grimes remain = m->m_len - len; 754df8bae1dSRodney W. Grimes if (m0->m_flags & M_PKTHDR) { 755df8bae1dSRodney W. Grimes MGETHDR(n, wait, m0->m_type); 756df8bae1dSRodney W. Grimes if (n == 0) 757df8bae1dSRodney W. Grimes return (0); 758df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 759df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 760df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 761df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 762df8bae1dSRodney W. Grimes goto extpacket; 763df8bae1dSRodney W. Grimes if (remain > MHLEN) { 764df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 765df8bae1dSRodney W. Grimes MH_ALIGN(n, 0); 766df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 767df8bae1dSRodney W. Grimes if (n->m_next == 0) { 768df8bae1dSRodney W. Grimes (void) m_free(n); 769df8bae1dSRodney W. Grimes return (0); 770df8bae1dSRodney W. Grimes } else 771df8bae1dSRodney W. Grimes return (n); 772df8bae1dSRodney W. Grimes } else 773df8bae1dSRodney W. Grimes MH_ALIGN(n, remain); 774df8bae1dSRodney W. Grimes } else if (remain == 0) { 775df8bae1dSRodney W. Grimes n = m->m_next; 776df8bae1dSRodney W. Grimes m->m_next = 0; 777df8bae1dSRodney W. Grimes return (n); 778df8bae1dSRodney W. Grimes } else { 779df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 780df8bae1dSRodney W. Grimes if (n == 0) 781df8bae1dSRodney W. Grimes return (0); 782df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 783df8bae1dSRodney W. Grimes } 784df8bae1dSRodney W. Grimes extpacket: 785df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 786df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 787df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 7880885c1d2SJulian Elischer if(!m->m_ext.ext_ref) 789df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 7900885c1d2SJulian Elischer else 7910885c1d2SJulian Elischer (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, 7920885c1d2SJulian Elischer m->m_ext.ext_size); 793df8bae1dSRodney W. Grimes m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ 794df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 795df8bae1dSRodney W. Grimes } else { 796df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 797df8bae1dSRodney W. Grimes } 798df8bae1dSRodney W. Grimes n->m_len = remain; 799df8bae1dSRodney W. Grimes m->m_len = len; 800df8bae1dSRodney W. Grimes n->m_next = m->m_next; 801df8bae1dSRodney W. Grimes m->m_next = 0; 802df8bae1dSRodney W. Grimes return (n); 803df8bae1dSRodney W. Grimes } 804df8bae1dSRodney W. Grimes /* 805df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 806df8bae1dSRodney W. Grimes */ 807df8bae1dSRodney W. Grimes struct mbuf * 808df8bae1dSRodney W. Grimes m_devget(buf, totlen, off0, ifp, copy) 809df8bae1dSRodney W. Grimes char *buf; 810df8bae1dSRodney W. Grimes int totlen, off0; 811df8bae1dSRodney W. Grimes struct ifnet *ifp; 81298d93822SBruce Evans void (*copy) __P((char *from, caddr_t to, u_int len)); 813df8bae1dSRodney W. Grimes { 814df8bae1dSRodney W. Grimes register struct mbuf *m; 815df8bae1dSRodney W. Grimes struct mbuf *top = 0, **mp = ⊤ 816df8bae1dSRodney W. Grimes register int off = off0, len; 817df8bae1dSRodney W. Grimes register char *cp; 818df8bae1dSRodney W. Grimes char *epkt; 819df8bae1dSRodney W. Grimes 820df8bae1dSRodney W. Grimes cp = buf; 821df8bae1dSRodney W. Grimes epkt = cp + totlen; 822df8bae1dSRodney W. Grimes if (off) { 823df8bae1dSRodney W. Grimes cp += off + 2 * sizeof(u_short); 824df8bae1dSRodney W. Grimes totlen -= 2 * sizeof(u_short); 825df8bae1dSRodney W. Grimes } 826df8bae1dSRodney W. Grimes MGETHDR(m, M_DONTWAIT, MT_DATA); 827df8bae1dSRodney W. Grimes if (m == 0) 828df8bae1dSRodney W. Grimes return (0); 829df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 830df8bae1dSRodney W. Grimes m->m_pkthdr.len = totlen; 831df8bae1dSRodney W. Grimes m->m_len = MHLEN; 832df8bae1dSRodney W. Grimes 833df8bae1dSRodney W. Grimes while (totlen > 0) { 834df8bae1dSRodney W. Grimes if (top) { 835df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_DATA); 836df8bae1dSRodney W. Grimes if (m == 0) { 837df8bae1dSRodney W. Grimes m_freem(top); 838df8bae1dSRodney W. Grimes return (0); 839df8bae1dSRodney W. Grimes } 840df8bae1dSRodney W. Grimes m->m_len = MLEN; 841df8bae1dSRodney W. Grimes } 842df8bae1dSRodney W. Grimes len = min(totlen, epkt - cp); 843df8bae1dSRodney W. Grimes if (len >= MINCLSIZE) { 844df8bae1dSRodney W. Grimes MCLGET(m, M_DONTWAIT); 845df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 846df8bae1dSRodney W. Grimes m->m_len = len = min(len, MCLBYTES); 847df8bae1dSRodney W. Grimes else 848df8bae1dSRodney W. Grimes len = m->m_len; 849df8bae1dSRodney W. Grimes } else { 850df8bae1dSRodney W. Grimes /* 851df8bae1dSRodney W. Grimes * Place initial small packet/header at end of mbuf. 852df8bae1dSRodney W. Grimes */ 853df8bae1dSRodney W. Grimes if (len < m->m_len) { 854df8bae1dSRodney W. Grimes if (top == 0 && len + max_linkhdr <= m->m_len) 855df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 856df8bae1dSRodney W. Grimes m->m_len = len; 857df8bae1dSRodney W. Grimes } else 858df8bae1dSRodney W. Grimes len = m->m_len; 859df8bae1dSRodney W. Grimes } 860df8bae1dSRodney W. Grimes if (copy) 861df8bae1dSRodney W. Grimes copy(cp, mtod(m, caddr_t), (unsigned)len); 862df8bae1dSRodney W. Grimes else 863df8bae1dSRodney W. Grimes bcopy(cp, mtod(m, caddr_t), (unsigned)len); 864df8bae1dSRodney W. Grimes cp += len; 865df8bae1dSRodney W. Grimes *mp = m; 866df8bae1dSRodney W. Grimes mp = &m->m_next; 867df8bae1dSRodney W. Grimes totlen -= len; 868df8bae1dSRodney W. Grimes if (cp == epkt) 869df8bae1dSRodney W. Grimes cp = buf; 870df8bae1dSRodney W. Grimes } 871df8bae1dSRodney W. Grimes return (top); 872df8bae1dSRodney W. Grimes } 873c5789ba3SPoul-Henning Kamp 874c5789ba3SPoul-Henning Kamp /* 875c5789ba3SPoul-Henning Kamp * Copy data from a buffer back into the indicated mbuf chain, 876c5789ba3SPoul-Henning Kamp * starting "off" bytes from the beginning, extending the mbuf 877c5789ba3SPoul-Henning Kamp * chain if necessary. 878c5789ba3SPoul-Henning Kamp */ 879c5789ba3SPoul-Henning Kamp void 880c5789ba3SPoul-Henning Kamp m_copyback(m0, off, len, cp) 881c5789ba3SPoul-Henning Kamp struct mbuf *m0; 882c5789ba3SPoul-Henning Kamp register int off; 883c5789ba3SPoul-Henning Kamp register int len; 884c5789ba3SPoul-Henning Kamp caddr_t cp; 885c5789ba3SPoul-Henning Kamp { 886c5789ba3SPoul-Henning Kamp register int mlen; 887c5789ba3SPoul-Henning Kamp register struct mbuf *m = m0, *n; 888c5789ba3SPoul-Henning Kamp int totlen = 0; 889c5789ba3SPoul-Henning Kamp 890c5789ba3SPoul-Henning Kamp if (m0 == 0) 891c5789ba3SPoul-Henning Kamp return; 892c5789ba3SPoul-Henning Kamp while (off > (mlen = m->m_len)) { 893c5789ba3SPoul-Henning Kamp off -= mlen; 894c5789ba3SPoul-Henning Kamp totlen += mlen; 895c5789ba3SPoul-Henning Kamp if (m->m_next == 0) { 896c5789ba3SPoul-Henning Kamp n = m_getclr(M_DONTWAIT, m->m_type); 897c5789ba3SPoul-Henning Kamp if (n == 0) 898c5789ba3SPoul-Henning Kamp goto out; 899c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len + off); 900c5789ba3SPoul-Henning Kamp m->m_next = n; 901c5789ba3SPoul-Henning Kamp } 902c5789ba3SPoul-Henning Kamp m = m->m_next; 903c5789ba3SPoul-Henning Kamp } 904c5789ba3SPoul-Henning Kamp while (len > 0) { 905c5789ba3SPoul-Henning Kamp mlen = min (m->m_len - off, len); 906c5789ba3SPoul-Henning Kamp bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 907c5789ba3SPoul-Henning Kamp cp += mlen; 908c5789ba3SPoul-Henning Kamp len -= mlen; 909c5789ba3SPoul-Henning Kamp mlen += off; 910c5789ba3SPoul-Henning Kamp off = 0; 911c5789ba3SPoul-Henning Kamp totlen += mlen; 912c5789ba3SPoul-Henning Kamp if (len == 0) 913c5789ba3SPoul-Henning Kamp break; 914c5789ba3SPoul-Henning Kamp if (m->m_next == 0) { 915c5789ba3SPoul-Henning Kamp n = m_get(M_DONTWAIT, m->m_type); 916c5789ba3SPoul-Henning Kamp if (n == 0) 917c5789ba3SPoul-Henning Kamp break; 918c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len); 919c5789ba3SPoul-Henning Kamp m->m_next = n; 920c5789ba3SPoul-Henning Kamp } 921c5789ba3SPoul-Henning Kamp m = m->m_next; 922c5789ba3SPoul-Henning Kamp } 923c5789ba3SPoul-Henning Kamp out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 924c5789ba3SPoul-Henning Kamp m->m_pkthdr.len = totlen; 925c5789ba3SPoul-Henning Kamp } 926