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 34df8bae1dSRodney W. Grimes */ 35df8bae1dSRodney W. Grimes 36df8bae1dSRodney W. Grimes #include <sys/param.h> 37df8bae1dSRodney W. Grimes #include <sys/systm.h> 38df8bae1dSRodney W. Grimes #include <sys/proc.h> 39df8bae1dSRodney W. Grimes #include <sys/malloc.h> 40df8bae1dSRodney W. Grimes #include <sys/map.h> 41df8bae1dSRodney W. Grimes #define MBTYPES 42df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 43df8bae1dSRodney W. Grimes #include <sys/kernel.h> 44df8bae1dSRodney W. Grimes #include <sys/syslog.h> 45df8bae1dSRodney W. Grimes #include <sys/domain.h> 46df8bae1dSRodney W. Grimes #include <sys/protosw.h> 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <vm/vm.h> 49df8bae1dSRodney W. Grimes 50df8bae1dSRodney W. Grimes extern vm_map_t mb_map; 51df8bae1dSRodney W. Grimes struct mbuf *mbutl; 52df8bae1dSRodney W. Grimes char *mclrefcnt; 53df8bae1dSRodney W. Grimes 54df8bae1dSRodney W. Grimes mbinit() 55df8bae1dSRodney W. Grimes { 56df8bae1dSRodney W. Grimes int s; 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #if CLBYTES < 4096 59df8bae1dSRodney W. Grimes #define NCL_INIT (4096/CLBYTES) 60df8bae1dSRodney W. Grimes #else 61df8bae1dSRodney W. Grimes #define NCL_INIT 1 62df8bae1dSRodney W. Grimes #endif 63df8bae1dSRodney W. Grimes s = splimp(); 64df8bae1dSRodney W. Grimes if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 65df8bae1dSRodney W. Grimes goto bad; 66df8bae1dSRodney W. Grimes splx(s); 67df8bae1dSRodney W. Grimes return; 68df8bae1dSRodney W. Grimes bad: 69df8bae1dSRodney W. Grimes panic("mbinit"); 70df8bae1dSRodney W. Grimes } 71df8bae1dSRodney W. Grimes 72df8bae1dSRodney W. Grimes /* 73df8bae1dSRodney W. Grimes * Allocate some number of mbuf clusters 74df8bae1dSRodney W. Grimes * and place on cluster free list. 75df8bae1dSRodney W. Grimes * Must be called at splimp. 76df8bae1dSRodney W. Grimes */ 77df8bae1dSRodney W. Grimes /* ARGSUSED */ 78df8bae1dSRodney W. Grimes m_clalloc(ncl, nowait) 79df8bae1dSRodney W. Grimes register int ncl; 80df8bae1dSRodney W. Grimes int nowait; 81df8bae1dSRodney W. Grimes { 82df8bae1dSRodney W. Grimes static int logged; 83df8bae1dSRodney W. Grimes register caddr_t p; 84df8bae1dSRodney W. Grimes register int i; 85df8bae1dSRodney W. Grimes int npg; 86df8bae1dSRodney W. Grimes 87df8bae1dSRodney W. Grimes npg = ncl * CLSIZE; 88df8bae1dSRodney W. Grimes p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !nowait); 89df8bae1dSRodney W. Grimes if (p == NULL) { 90df8bae1dSRodney W. Grimes if (logged == 0) { 91df8bae1dSRodney W. Grimes logged++; 92df8bae1dSRodney W. Grimes log(LOG_ERR, "mb_map full\n"); 93df8bae1dSRodney W. Grimes } 94df8bae1dSRodney W. Grimes return (0); 95df8bae1dSRodney W. Grimes } 96df8bae1dSRodney W. Grimes ncl = ncl * CLBYTES / MCLBYTES; 97df8bae1dSRodney W. Grimes for (i = 0; i < ncl; i++) { 98df8bae1dSRodney W. Grimes ((union mcluster *)p)->mcl_next = mclfree; 99df8bae1dSRodney W. Grimes mclfree = (union mcluster *)p; 100df8bae1dSRodney W. Grimes p += MCLBYTES; 101df8bae1dSRodney W. Grimes mbstat.m_clfree++; 102df8bae1dSRodney W. Grimes } 103df8bae1dSRodney W. Grimes mbstat.m_clusters += ncl; 104df8bae1dSRodney W. Grimes return (1); 105df8bae1dSRodney W. Grimes } 106df8bae1dSRodney W. Grimes 107df8bae1dSRodney W. Grimes /* 108df8bae1dSRodney W. Grimes * When MGET failes, ask protocols to free space when short of memory, 109df8bae1dSRodney W. Grimes * then re-attempt to allocate an mbuf. 110df8bae1dSRodney W. Grimes */ 111df8bae1dSRodney W. Grimes struct mbuf * 112df8bae1dSRodney W. Grimes m_retry(i, t) 113df8bae1dSRodney W. Grimes int i, t; 114df8bae1dSRodney W. Grimes { 115df8bae1dSRodney W. Grimes register struct mbuf *m; 116df8bae1dSRodney W. Grimes 117df8bae1dSRodney W. Grimes m_reclaim(); 118df8bae1dSRodney W. Grimes #define m_retry(i, t) (struct mbuf *)0 119df8bae1dSRodney W. Grimes MGET(m, i, t); 120df8bae1dSRodney W. Grimes #undef m_retry 121df8bae1dSRodney W. Grimes return (m); 122df8bae1dSRodney W. Grimes } 123df8bae1dSRodney W. Grimes 124df8bae1dSRodney W. Grimes /* 125df8bae1dSRodney W. Grimes * As above; retry an MGETHDR. 126df8bae1dSRodney W. Grimes */ 127df8bae1dSRodney W. Grimes struct mbuf * 128df8bae1dSRodney W. Grimes m_retryhdr(i, t) 129df8bae1dSRodney W. Grimes int i, t; 130df8bae1dSRodney W. Grimes { 131df8bae1dSRodney W. Grimes register struct mbuf *m; 132df8bae1dSRodney W. Grimes 133df8bae1dSRodney W. Grimes m_reclaim(); 134df8bae1dSRodney W. Grimes #define m_retryhdr(i, t) (struct mbuf *)0 135df8bae1dSRodney W. Grimes MGETHDR(m, i, t); 136df8bae1dSRodney W. Grimes #undef m_retryhdr 137df8bae1dSRodney W. Grimes return (m); 138df8bae1dSRodney W. Grimes } 139df8bae1dSRodney W. Grimes 140df8bae1dSRodney W. Grimes m_reclaim() 141df8bae1dSRodney W. Grimes { 142df8bae1dSRodney W. Grimes register struct domain *dp; 143df8bae1dSRodney W. Grimes register struct protosw *pr; 144df8bae1dSRodney W. Grimes int s = splimp(); 145df8bae1dSRodney W. Grimes 146df8bae1dSRodney W. Grimes for (dp = domains; dp; dp = dp->dom_next) 147df8bae1dSRodney W. Grimes for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 148df8bae1dSRodney W. Grimes if (pr->pr_drain) 149df8bae1dSRodney W. Grimes (*pr->pr_drain)(); 150df8bae1dSRodney W. Grimes splx(s); 151df8bae1dSRodney W. Grimes mbstat.m_drain++; 152df8bae1dSRodney W. Grimes } 153df8bae1dSRodney W. Grimes 154df8bae1dSRodney W. Grimes /* 155df8bae1dSRodney W. Grimes * Space allocation routines. 156df8bae1dSRodney W. Grimes * These are also available as macros 157df8bae1dSRodney W. Grimes * for critical paths. 158df8bae1dSRodney W. Grimes */ 159df8bae1dSRodney W. Grimes struct mbuf * 160df8bae1dSRodney W. Grimes m_get(nowait, type) 161df8bae1dSRodney W. Grimes int nowait, type; 162df8bae1dSRodney W. Grimes { 163df8bae1dSRodney W. Grimes register struct mbuf *m; 164df8bae1dSRodney W. Grimes 165df8bae1dSRodney W. Grimes MGET(m, nowait, type); 166df8bae1dSRodney W. Grimes return (m); 167df8bae1dSRodney W. Grimes } 168df8bae1dSRodney W. Grimes 169df8bae1dSRodney W. Grimes struct mbuf * 170df8bae1dSRodney W. Grimes m_gethdr(nowait, type) 171df8bae1dSRodney W. Grimes int nowait, type; 172df8bae1dSRodney W. Grimes { 173df8bae1dSRodney W. Grimes register struct mbuf *m; 174df8bae1dSRodney W. Grimes 175df8bae1dSRodney W. Grimes MGETHDR(m, nowait, type); 176df8bae1dSRodney W. Grimes return (m); 177df8bae1dSRodney W. Grimes } 178df8bae1dSRodney W. Grimes 179df8bae1dSRodney W. Grimes struct mbuf * 180df8bae1dSRodney W. Grimes m_getclr(nowait, type) 181df8bae1dSRodney W. Grimes int nowait, type; 182df8bae1dSRodney W. Grimes { 183df8bae1dSRodney W. Grimes register struct mbuf *m; 184df8bae1dSRodney W. Grimes 185df8bae1dSRodney W. Grimes MGET(m, nowait, type); 186df8bae1dSRodney W. Grimes if (m == 0) 187df8bae1dSRodney W. Grimes return (0); 188df8bae1dSRodney W. Grimes bzero(mtod(m, caddr_t), MLEN); 189df8bae1dSRodney W. Grimes return (m); 190df8bae1dSRodney W. Grimes } 191df8bae1dSRodney W. Grimes 192df8bae1dSRodney W. Grimes struct mbuf * 193df8bae1dSRodney W. Grimes m_free(m) 194df8bae1dSRodney W. Grimes struct mbuf *m; 195df8bae1dSRodney W. Grimes { 196df8bae1dSRodney W. Grimes register struct mbuf *n; 197df8bae1dSRodney W. Grimes 198df8bae1dSRodney W. Grimes MFREE(m, n); 199df8bae1dSRodney W. Grimes return (n); 200df8bae1dSRodney W. Grimes } 201df8bae1dSRodney W. Grimes 202df8bae1dSRodney W. Grimes void 203df8bae1dSRodney W. Grimes m_freem(m) 204df8bae1dSRodney W. Grimes register struct mbuf *m; 205df8bae1dSRodney W. Grimes { 206df8bae1dSRodney W. Grimes register struct mbuf *n; 207df8bae1dSRodney W. Grimes 208df8bae1dSRodney W. Grimes if (m == NULL) 209df8bae1dSRodney W. Grimes return; 210df8bae1dSRodney W. Grimes do { 211df8bae1dSRodney W. Grimes MFREE(m, n); 212df8bae1dSRodney W. Grimes } while (m = n); 213df8bae1dSRodney W. Grimes } 214df8bae1dSRodney W. Grimes 215df8bae1dSRodney W. Grimes /* 216df8bae1dSRodney W. Grimes * Mbuffer utility routines. 217df8bae1dSRodney W. Grimes */ 218df8bae1dSRodney W. Grimes 219df8bae1dSRodney W. Grimes /* 220df8bae1dSRodney W. Grimes * Lesser-used path for M_PREPEND: 221df8bae1dSRodney W. Grimes * allocate new mbuf to prepend to chain, 222df8bae1dSRodney W. Grimes * copy junk along. 223df8bae1dSRodney W. Grimes */ 224df8bae1dSRodney W. Grimes struct mbuf * 225df8bae1dSRodney W. Grimes m_prepend(m, len, how) 226df8bae1dSRodney W. Grimes register struct mbuf *m; 227df8bae1dSRodney W. Grimes int len, how; 228df8bae1dSRodney W. Grimes { 229df8bae1dSRodney W. Grimes struct mbuf *mn; 230df8bae1dSRodney W. Grimes 231df8bae1dSRodney W. Grimes MGET(mn, how, m->m_type); 232df8bae1dSRodney W. Grimes if (mn == (struct mbuf *)NULL) { 233df8bae1dSRodney W. Grimes m_freem(m); 234df8bae1dSRodney W. Grimes return ((struct mbuf *)NULL); 235df8bae1dSRodney W. Grimes } 236df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { 237df8bae1dSRodney W. Grimes M_COPY_PKTHDR(mn, m); 238df8bae1dSRodney W. Grimes m->m_flags &= ~M_PKTHDR; 239df8bae1dSRodney W. Grimes } 240df8bae1dSRodney W. Grimes mn->m_next = m; 241df8bae1dSRodney W. Grimes m = mn; 242df8bae1dSRodney W. Grimes if (len < MHLEN) 243df8bae1dSRodney W. Grimes MH_ALIGN(m, len); 244df8bae1dSRodney W. Grimes m->m_len = len; 245df8bae1dSRodney W. Grimes return (m); 246df8bae1dSRodney W. Grimes } 247df8bae1dSRodney W. Grimes 248df8bae1dSRodney W. Grimes /* 249df8bae1dSRodney W. Grimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 250df8bae1dSRodney W. Grimes * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 251df8bae1dSRodney W. Grimes * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. 252df8bae1dSRodney W. Grimes */ 253df8bae1dSRodney W. Grimes int MCFail; 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes struct mbuf * 256df8bae1dSRodney W. Grimes m_copym(m, off0, len, wait) 257df8bae1dSRodney W. Grimes register struct mbuf *m; 258df8bae1dSRodney W. Grimes int off0, wait; 259df8bae1dSRodney W. Grimes register int len; 260df8bae1dSRodney W. Grimes { 261df8bae1dSRodney W. Grimes register struct mbuf *n, **np; 262df8bae1dSRodney W. Grimes register int off = off0; 263df8bae1dSRodney W. Grimes struct mbuf *top; 264df8bae1dSRodney W. Grimes int copyhdr = 0; 265df8bae1dSRodney W. Grimes 266df8bae1dSRodney W. Grimes if (off < 0 || len < 0) 267df8bae1dSRodney W. Grimes panic("m_copym"); 268df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 269df8bae1dSRodney W. Grimes copyhdr = 1; 270df8bae1dSRodney W. Grimes while (off > 0) { 271df8bae1dSRodney W. Grimes if (m == 0) 272df8bae1dSRodney W. Grimes panic("m_copym"); 273df8bae1dSRodney W. Grimes if (off < m->m_len) 274df8bae1dSRodney W. Grimes break; 275df8bae1dSRodney W. Grimes off -= m->m_len; 276df8bae1dSRodney W. Grimes m = m->m_next; 277df8bae1dSRodney W. Grimes } 278df8bae1dSRodney W. Grimes np = ⊤ 279df8bae1dSRodney W. Grimes top = 0; 280df8bae1dSRodney W. Grimes while (len > 0) { 281df8bae1dSRodney W. Grimes if (m == 0) { 282df8bae1dSRodney W. Grimes if (len != M_COPYALL) 283df8bae1dSRodney W. Grimes panic("m_copym"); 284df8bae1dSRodney W. Grimes break; 285df8bae1dSRodney W. Grimes } 286df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 287df8bae1dSRodney W. Grimes *np = n; 288df8bae1dSRodney W. Grimes if (n == 0) 289df8bae1dSRodney W. Grimes goto nospace; 290df8bae1dSRodney W. Grimes if (copyhdr) { 291df8bae1dSRodney W. Grimes M_COPY_PKTHDR(n, m); 292df8bae1dSRodney W. Grimes if (len == M_COPYALL) 293df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 294df8bae1dSRodney W. Grimes else 295df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 296df8bae1dSRodney W. Grimes copyhdr = 0; 297df8bae1dSRodney W. Grimes } 298df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 299df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 300df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 301df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 302df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 303df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 304df8bae1dSRodney W. Grimes } else 305df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 306df8bae1dSRodney W. Grimes (unsigned)n->m_len); 307df8bae1dSRodney W. Grimes if (len != M_COPYALL) 308df8bae1dSRodney W. Grimes len -= n->m_len; 309df8bae1dSRodney W. Grimes off = 0; 310df8bae1dSRodney W. Grimes m = m->m_next; 311df8bae1dSRodney W. Grimes np = &n->m_next; 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes if (top == 0) 314df8bae1dSRodney W. Grimes MCFail++; 315df8bae1dSRodney W. Grimes return (top); 316df8bae1dSRodney W. Grimes nospace: 317df8bae1dSRodney W. Grimes m_freem(top); 318df8bae1dSRodney W. Grimes MCFail++; 319df8bae1dSRodney W. Grimes return (0); 320df8bae1dSRodney W. Grimes } 321df8bae1dSRodney W. Grimes 322df8bae1dSRodney W. Grimes /* 323df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 324df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 325df8bae1dSRodney W. Grimes */ 326df8bae1dSRodney W. Grimes m_copydata(m, off, len, cp) 327df8bae1dSRodney W. Grimes register struct mbuf *m; 328df8bae1dSRodney W. Grimes register int off; 329df8bae1dSRodney W. Grimes register int len; 330df8bae1dSRodney W. Grimes caddr_t cp; 331df8bae1dSRodney W. Grimes { 332df8bae1dSRodney W. Grimes register unsigned count; 333df8bae1dSRodney W. Grimes 334df8bae1dSRodney W. Grimes if (off < 0 || len < 0) 335df8bae1dSRodney W. Grimes panic("m_copydata"); 336df8bae1dSRodney W. Grimes while (off > 0) { 337df8bae1dSRodney W. Grimes if (m == 0) 338df8bae1dSRodney W. Grimes panic("m_copydata"); 339df8bae1dSRodney W. Grimes if (off < m->m_len) 340df8bae1dSRodney W. Grimes break; 341df8bae1dSRodney W. Grimes off -= m->m_len; 342df8bae1dSRodney W. Grimes m = m->m_next; 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes while (len > 0) { 345df8bae1dSRodney W. Grimes if (m == 0) 346df8bae1dSRodney W. Grimes panic("m_copydata"); 347df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 348df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 349df8bae1dSRodney W. Grimes len -= count; 350df8bae1dSRodney W. Grimes cp += count; 351df8bae1dSRodney W. Grimes off = 0; 352df8bae1dSRodney W. Grimes m = m->m_next; 353df8bae1dSRodney W. Grimes } 354df8bae1dSRodney W. Grimes } 355df8bae1dSRodney W. Grimes 356df8bae1dSRodney W. Grimes /* 357df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 358df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 359df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 360df8bae1dSRodney W. Grimes */ 361df8bae1dSRodney W. Grimes m_cat(m, n) 362df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 363df8bae1dSRodney W. Grimes { 364df8bae1dSRodney W. Grimes while (m->m_next) 365df8bae1dSRodney W. Grimes m = m->m_next; 366df8bae1dSRodney W. Grimes while (n) { 367df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT || 368df8bae1dSRodney W. Grimes m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 369df8bae1dSRodney W. Grimes /* just join the two chains */ 370df8bae1dSRodney W. Grimes m->m_next = n; 371df8bae1dSRodney W. Grimes return; 372df8bae1dSRodney W. Grimes } 373df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 374df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 375df8bae1dSRodney W. Grimes (u_int)n->m_len); 376df8bae1dSRodney W. Grimes m->m_len += n->m_len; 377df8bae1dSRodney W. Grimes n = m_free(n); 378df8bae1dSRodney W. Grimes } 379df8bae1dSRodney W. Grimes } 380df8bae1dSRodney W. Grimes 381df8bae1dSRodney W. Grimes m_adj(mp, req_len) 382df8bae1dSRodney W. Grimes struct mbuf *mp; 383df8bae1dSRodney W. Grimes int req_len; 384df8bae1dSRodney W. Grimes { 385df8bae1dSRodney W. Grimes register int len = req_len; 386df8bae1dSRodney W. Grimes register struct mbuf *m; 387df8bae1dSRodney W. Grimes register count; 388df8bae1dSRodney W. Grimes 389df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 390df8bae1dSRodney W. Grimes return; 391df8bae1dSRodney W. Grimes if (len >= 0) { 392df8bae1dSRodney W. Grimes /* 393df8bae1dSRodney W. Grimes * Trim from head. 394df8bae1dSRodney W. Grimes */ 395df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 396df8bae1dSRodney W. Grimes if (m->m_len <= len) { 397df8bae1dSRodney W. Grimes len -= m->m_len; 398df8bae1dSRodney W. Grimes m->m_len = 0; 399df8bae1dSRodney W. Grimes m = m->m_next; 400df8bae1dSRodney W. Grimes } else { 401df8bae1dSRodney W. Grimes m->m_len -= len; 402df8bae1dSRodney W. Grimes m->m_data += len; 403df8bae1dSRodney W. Grimes len = 0; 404df8bae1dSRodney W. Grimes } 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes m = mp; 407df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 408df8bae1dSRodney W. Grimes m->m_pkthdr.len -= (req_len - len); 409df8bae1dSRodney W. Grimes } else { 410df8bae1dSRodney W. Grimes /* 411df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 412df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 413df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 414df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 415df8bae1dSRodney W. Grimes * after the remaining size. 416df8bae1dSRodney W. Grimes */ 417df8bae1dSRodney W. Grimes len = -len; 418df8bae1dSRodney W. Grimes count = 0; 419df8bae1dSRodney W. Grimes for (;;) { 420df8bae1dSRodney W. Grimes count += m->m_len; 421df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 422df8bae1dSRodney W. Grimes break; 423df8bae1dSRodney W. Grimes m = m->m_next; 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes if (m->m_len >= len) { 426df8bae1dSRodney W. Grimes m->m_len -= len; 427df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 428df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 429df8bae1dSRodney W. Grimes return; 430df8bae1dSRodney W. Grimes } 431df8bae1dSRodney W. Grimes count -= len; 432df8bae1dSRodney W. Grimes if (count < 0) 433df8bae1dSRodney W. Grimes count = 0; 434df8bae1dSRodney W. Grimes /* 435df8bae1dSRodney W. Grimes * Correct length for chain is "count". 436df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 437df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 438df8bae1dSRodney W. Grimes */ 439df8bae1dSRodney W. Grimes m = mp; 440df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 441df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 442df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 443df8bae1dSRodney W. Grimes if (m->m_len >= count) { 444df8bae1dSRodney W. Grimes m->m_len = count; 445df8bae1dSRodney W. Grimes break; 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes count -= m->m_len; 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes while (m = m->m_next) 450df8bae1dSRodney W. Grimes m->m_len = 0; 451df8bae1dSRodney W. Grimes } 452df8bae1dSRodney W. Grimes } 453df8bae1dSRodney W. Grimes 454df8bae1dSRodney W. Grimes /* 455df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 456df8bae1dSRodney W. Grimes * and in the data area of an mbuf (so that mtod and dtom 457df8bae1dSRodney W. Grimes * will work for a structure of size len). Returns the resulting 458df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 459df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 460df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 461df8bae1dSRodney W. Grimes */ 462df8bae1dSRodney W. Grimes int MPFail; 463df8bae1dSRodney W. Grimes 464df8bae1dSRodney W. Grimes struct mbuf * 465df8bae1dSRodney W. Grimes m_pullup(n, len) 466df8bae1dSRodney W. Grimes register struct mbuf *n; 467df8bae1dSRodney W. Grimes int len; 468df8bae1dSRodney W. Grimes { 469df8bae1dSRodney W. Grimes register struct mbuf *m; 470df8bae1dSRodney W. Grimes register int count; 471df8bae1dSRodney W. Grimes int space; 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes /* 474df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 475df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 476df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 477df8bae1dSRodney W. Grimes */ 478df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 479df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 480df8bae1dSRodney W. Grimes if (n->m_len >= len) 481df8bae1dSRodney W. Grimes return (n); 482df8bae1dSRodney W. Grimes m = n; 483df8bae1dSRodney W. Grimes n = n->m_next; 484df8bae1dSRodney W. Grimes len -= m->m_len; 485df8bae1dSRodney W. Grimes } else { 486df8bae1dSRodney W. Grimes if (len > MHLEN) 487df8bae1dSRodney W. Grimes goto bad; 488df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, n->m_type); 489df8bae1dSRodney W. Grimes if (m == 0) 490df8bae1dSRodney W. Grimes goto bad; 491df8bae1dSRodney W. Grimes m->m_len = 0; 492df8bae1dSRodney W. Grimes if (n->m_flags & M_PKTHDR) { 493df8bae1dSRodney W. Grimes M_COPY_PKTHDR(m, n); 494df8bae1dSRodney W. Grimes n->m_flags &= ~M_PKTHDR; 495df8bae1dSRodney W. Grimes } 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 498df8bae1dSRodney W. Grimes do { 499df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 500df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 501df8bae1dSRodney W. Grimes (unsigned)count); 502df8bae1dSRodney W. Grimes len -= count; 503df8bae1dSRodney W. Grimes m->m_len += count; 504df8bae1dSRodney W. Grimes n->m_len -= count; 505df8bae1dSRodney W. Grimes space -= count; 506df8bae1dSRodney W. Grimes if (n->m_len) 507df8bae1dSRodney W. Grimes n->m_data += count; 508df8bae1dSRodney W. Grimes else 509df8bae1dSRodney W. Grimes n = m_free(n); 510df8bae1dSRodney W. Grimes } while (len > 0 && n); 511df8bae1dSRodney W. Grimes if (len > 0) { 512df8bae1dSRodney W. Grimes (void) m_free(m); 513df8bae1dSRodney W. Grimes goto bad; 514df8bae1dSRodney W. Grimes } 515df8bae1dSRodney W. Grimes m->m_next = n; 516df8bae1dSRodney W. Grimes return (m); 517df8bae1dSRodney W. Grimes bad: 518df8bae1dSRodney W. Grimes m_freem(n); 519df8bae1dSRodney W. Grimes MPFail++; 520df8bae1dSRodney W. Grimes return (0); 521df8bae1dSRodney W. Grimes } 522df8bae1dSRodney W. Grimes 523df8bae1dSRodney W. Grimes /* 524df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 525df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 526df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 527df8bae1dSRodney W. Grimes */ 528df8bae1dSRodney W. Grimes struct mbuf * 529df8bae1dSRodney W. Grimes m_split(m0, len0, wait) 530df8bae1dSRodney W. Grimes register struct mbuf *m0; 531df8bae1dSRodney W. Grimes int len0, wait; 532df8bae1dSRodney W. Grimes { 533df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 534df8bae1dSRodney W. Grimes unsigned len = len0, remain; 535df8bae1dSRodney W. Grimes 536df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 537df8bae1dSRodney W. Grimes len -= m->m_len; 538df8bae1dSRodney W. Grimes if (m == 0) 539df8bae1dSRodney W. Grimes return (0); 540df8bae1dSRodney W. Grimes remain = m->m_len - len; 541df8bae1dSRodney W. Grimes if (m0->m_flags & M_PKTHDR) { 542df8bae1dSRodney W. Grimes MGETHDR(n, wait, m0->m_type); 543df8bae1dSRodney W. Grimes if (n == 0) 544df8bae1dSRodney W. Grimes return (0); 545df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 546df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 547df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 548df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 549df8bae1dSRodney W. Grimes goto extpacket; 550df8bae1dSRodney W. Grimes if (remain > MHLEN) { 551df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 552df8bae1dSRodney W. Grimes MH_ALIGN(n, 0); 553df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 554df8bae1dSRodney W. Grimes if (n->m_next == 0) { 555df8bae1dSRodney W. Grimes (void) m_free(n); 556df8bae1dSRodney W. Grimes return (0); 557df8bae1dSRodney W. Grimes } else 558df8bae1dSRodney W. Grimes return (n); 559df8bae1dSRodney W. Grimes } else 560df8bae1dSRodney W. Grimes MH_ALIGN(n, remain); 561df8bae1dSRodney W. Grimes } else if (remain == 0) { 562df8bae1dSRodney W. Grimes n = m->m_next; 563df8bae1dSRodney W. Grimes m->m_next = 0; 564df8bae1dSRodney W. Grimes return (n); 565df8bae1dSRodney W. Grimes } else { 566df8bae1dSRodney W. Grimes MGET(n, wait, m->m_type); 567df8bae1dSRodney W. Grimes if (n == 0) 568df8bae1dSRodney W. Grimes return (0); 569df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 570df8bae1dSRodney W. Grimes } 571df8bae1dSRodney W. Grimes extpacket: 572df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { 573df8bae1dSRodney W. Grimes n->m_flags |= M_EXT; 574df8bae1dSRodney W. Grimes n->m_ext = m->m_ext; 575df8bae1dSRodney W. Grimes mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 576df8bae1dSRodney W. Grimes m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ 577df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 578df8bae1dSRodney W. Grimes } else { 579df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes n->m_len = remain; 582df8bae1dSRodney W. Grimes m->m_len = len; 583df8bae1dSRodney W. Grimes n->m_next = m->m_next; 584df8bae1dSRodney W. Grimes m->m_next = 0; 585df8bae1dSRodney W. Grimes return (n); 586df8bae1dSRodney W. Grimes } 587df8bae1dSRodney W. Grimes /* 588df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 589df8bae1dSRodney W. Grimes */ 590df8bae1dSRodney W. Grimes struct mbuf * 591df8bae1dSRodney W. Grimes m_devget(buf, totlen, off0, ifp, copy) 592df8bae1dSRodney W. Grimes char *buf; 593df8bae1dSRodney W. Grimes int totlen, off0; 594df8bae1dSRodney W. Grimes struct ifnet *ifp; 595df8bae1dSRodney W. Grimes void (*copy)(); 596df8bae1dSRodney W. Grimes { 597df8bae1dSRodney W. Grimes register struct mbuf *m; 598df8bae1dSRodney W. Grimes struct mbuf *top = 0, **mp = ⊤ 599df8bae1dSRodney W. Grimes register int off = off0, len; 600df8bae1dSRodney W. Grimes register char *cp; 601df8bae1dSRodney W. Grimes char *epkt; 602df8bae1dSRodney W. Grimes 603df8bae1dSRodney W. Grimes cp = buf; 604df8bae1dSRodney W. Grimes epkt = cp + totlen; 605df8bae1dSRodney W. Grimes if (off) { 606df8bae1dSRodney W. Grimes cp += off + 2 * sizeof(u_short); 607df8bae1dSRodney W. Grimes totlen -= 2 * sizeof(u_short); 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes MGETHDR(m, M_DONTWAIT, MT_DATA); 610df8bae1dSRodney W. Grimes if (m == 0) 611df8bae1dSRodney W. Grimes return (0); 612df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = ifp; 613df8bae1dSRodney W. Grimes m->m_pkthdr.len = totlen; 614df8bae1dSRodney W. Grimes m->m_len = MHLEN; 615df8bae1dSRodney W. Grimes 616df8bae1dSRodney W. Grimes while (totlen > 0) { 617df8bae1dSRodney W. Grimes if (top) { 618df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_DATA); 619df8bae1dSRodney W. Grimes if (m == 0) { 620df8bae1dSRodney W. Grimes m_freem(top); 621df8bae1dSRodney W. Grimes return (0); 622df8bae1dSRodney W. Grimes } 623df8bae1dSRodney W. Grimes m->m_len = MLEN; 624df8bae1dSRodney W. Grimes } 625df8bae1dSRodney W. Grimes len = min(totlen, epkt - cp); 626df8bae1dSRodney W. Grimes if (len >= MINCLSIZE) { 627df8bae1dSRodney W. Grimes MCLGET(m, M_DONTWAIT); 628df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 629df8bae1dSRodney W. Grimes m->m_len = len = min(len, MCLBYTES); 630df8bae1dSRodney W. Grimes else 631df8bae1dSRodney W. Grimes len = m->m_len; 632df8bae1dSRodney W. Grimes } else { 633df8bae1dSRodney W. Grimes /* 634df8bae1dSRodney W. Grimes * Place initial small packet/header at end of mbuf. 635df8bae1dSRodney W. Grimes */ 636df8bae1dSRodney W. Grimes if (len < m->m_len) { 637df8bae1dSRodney W. Grimes if (top == 0 && len + max_linkhdr <= m->m_len) 638df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 639df8bae1dSRodney W. Grimes m->m_len = len; 640df8bae1dSRodney W. Grimes } else 641df8bae1dSRodney W. Grimes len = m->m_len; 642df8bae1dSRodney W. Grimes } 643df8bae1dSRodney W. Grimes if (copy) 644df8bae1dSRodney W. Grimes copy(cp, mtod(m, caddr_t), (unsigned)len); 645df8bae1dSRodney W. Grimes else 646df8bae1dSRodney W. Grimes bcopy(cp, mtod(m, caddr_t), (unsigned)len); 647df8bae1dSRodney W. Grimes cp += len; 648df8bae1dSRodney W. Grimes *mp = m; 649df8bae1dSRodney W. Grimes mp = &m->m_next; 650df8bae1dSRodney W. Grimes totlen -= len; 651df8bae1dSRodney W. Grimes if (cp == epkt) 652df8bae1dSRodney W. Grimes cp = buf; 653df8bae1dSRodney W. Grimes } 654df8bae1dSRodney W. Grimes return (top); 655df8bae1dSRodney W. Grimes } 656