123417Smckusick /* 233460Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 333185Sbostic * All rights reserved. 423417Smckusick * 533185Sbostic * Redistribution and use in source and binary forms are permitted 634860Sbostic * provided that the above copyright notice and this paragraph are 734860Sbostic * duplicated in all such forms and that any documentation, 834860Sbostic * advertising materials, and other materials related to such 934860Sbostic * distribution and use acknowledge that the software was developed 1034860Sbostic * by the University of California, Berkeley. The name of the 1134860Sbostic * University may not be used to endorse or promote products derived 1234860Sbostic * from this software without specific prior written permission. 1334860Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434860Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534860Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633185Sbostic * 17*41998Smckusick * @(#)uipc_mbuf.c 7.14 (Berkeley) 05/15/90 1823417Smckusick */ 194585Swnj 2017102Sbloom #include "param.h" 2117102Sbloom #include "user.h" 2217102Sbloom #include "proc.h" 2317102Sbloom #include "cmap.h" 2438962Skarels #include "malloc.h" 2517102Sbloom #include "map.h" 2638962Skarels #define MBTYPES 2717102Sbloom #include "mbuf.h" 2817102Sbloom #include "vm.h" 2917102Sbloom #include "kernel.h" 3030442Skarels #include "syslog.h" 3130442Skarels #include "domain.h" 3230442Skarels #include "protosw.h" 3338962Skarels #include "machine/pte.h" 344585Swnj 355228Swnj mbinit() 365228Swnj { 3721107Skarels int s; 385228Swnj 3938962Skarels #if MCLBYTES < 4096 40*41998Smckusick #define NCL_INIT (4096/CLBYTES) 4132659Skarels #else 4232659Skarels #define NCL_INIT 1 4332659Skarels #endif 4421107Skarels s = splimp(); 4538962Skarels if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 465228Swnj goto bad; 4721107Skarels splx(s); 485228Swnj return; 495228Swnj bad: 505228Swnj panic("mbinit"); 515228Swnj } 525228Swnj 5321107Skarels /* 5438962Skarels * Allocate some number of mbuf clusters 5538962Skarels * and place on cluster free list. 5621107Skarels * Must be called at splimp. 5721107Skarels */ 5830442Skarels /* ARGSUSED */ 5938962Skarels m_clalloc(ncl, canwait) 605228Swnj register int ncl; 615228Swnj { 625228Swnj int npg, mbx; 6338962Skarels register caddr_t p; 645228Swnj register int i; 6530442Skarels static int logged; 665228Swnj 675228Swnj npg = ncl * CLSIZE; 688792Sroot mbx = rmalloc(mbmap, (long)npg); 6921107Skarels if (mbx == 0) { 7030442Skarels if (logged == 0) { 7130442Skarels logged++; 7230442Skarels log(LOG_ERR, "mbuf map full\n"); 7330442Skarels } 745228Swnj return (0); 7521107Skarels } 7638962Skarels p = cltom(mbx * NBPG / MCLBYTES); 779765Ssam if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 789765Ssam rmfree(mbmap, (long)npg, (long)mbx); 795228Swnj return (0); 809765Ssam } 8138962Skarels vmaccess(&Mbmap[mbx], p, npg); 8238962Skarels ncl = ncl * CLBYTES / MCLBYTES; 8338962Skarels for (i = 0; i < ncl; i++) { 8438962Skarels ((union mcluster *)p)->mcl_next = mclfree; 8538962Skarels mclfree = (union mcluster *)p; 8638962Skarels p += MCLBYTES; 8738962Skarels mbstat.m_clfree++; 8838962Skarels } 8938962Skarels mbstat.m_clusters += ncl; 9038962Skarels return (1); 9138962Skarels } 925228Swnj 9338962Skarels /* 9438962Skarels * When MGET failes, ask protocols to free space when short of memory, 9538962Skarels * then re-attempt to allocate an mbuf. 9638962Skarels */ 9738962Skarels struct mbuf * 9838962Skarels m_retry(i, t) 9938962Skarels int i, t; 10038962Skarels { 10138962Skarels register struct mbuf *m; 1025228Swnj 10338962Skarels m_reclaim(); 10438962Skarels #define m_retry(i, t) (struct mbuf *)0 10538962Skarels MGET(m, i, t); 10638962Skarels #undef m_retry 10738962Skarels return (m); 1085228Swnj } 1095228Swnj 11021107Skarels /* 11138962Skarels * As above; retry an MGETHDR. 11221107Skarels */ 11338962Skarels struct mbuf * 11438962Skarels m_retryhdr(i, t) 11538962Skarels int i, t; 1165228Swnj { 11738962Skarels register struct mbuf *m; 11838962Skarels 11938962Skarels m_reclaim(); 12038962Skarels #define m_retryhdr(i, t) (struct mbuf *)0 12138962Skarels MGETHDR(m, i, t); 12238962Skarels #undef m_retryhdr 12338962Skarels return (m); 12438962Skarels } 12538962Skarels 12638962Skarels m_reclaim() 12738962Skarels { 12830442Skarels register struct domain *dp; 12930442Skarels register struct protosw *pr; 13038962Skarels int s = splimp(); 1315228Swnj 13238962Skarels for (dp = domains; dp; dp = dp->dom_next) 13338962Skarels for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 13438962Skarels if (pr->pr_drain) 13538962Skarels (*pr->pr_drain)(); 13638962Skarels splx(s); 13738962Skarels mbstat.m_drain++; 1385228Swnj } 1395228Swnj 1405228Swnj /* 1415228Swnj * Space allocation routines. 1425228Swnj * These are also available as macros 1435228Swnj * for critical paths. 1445228Swnj */ 1454585Swnj struct mbuf * 1469634Ssam m_get(canwait, type) 1479634Ssam int canwait, type; 1484585Swnj { 1494585Swnj register struct mbuf *m; 1504585Swnj 1519634Ssam MGET(m, canwait, type); 1524585Swnj return (m); 1534585Swnj } 1544585Swnj 1554585Swnj struct mbuf * 15638962Skarels m_gethdr(canwait, type) 15738962Skarels int canwait, type; 15838962Skarels { 15938962Skarels register struct mbuf *m; 16038962Skarels 16138962Skarels MGETHDR(m, canwait, type); 16238962Skarels return (m); 16338962Skarels } 16438962Skarels 16538962Skarels struct mbuf * 1669634Ssam m_getclr(canwait, type) 1679634Ssam int canwait, type; 1684890Swnj { 1694890Swnj register struct mbuf *m; 1704890Swnj 17121107Skarels MGET(m, canwait, type); 1724890Swnj if (m == 0) 1734890Swnj return (0); 1744890Swnj bzero(mtod(m, caddr_t), MLEN); 1754890Swnj return (m); 1764890Swnj } 1774890Swnj 1784890Swnj struct mbuf * 1794585Swnj m_free(m) 1804585Swnj struct mbuf *m; 1814585Swnj { 1824585Swnj register struct mbuf *n; 1834585Swnj 1844585Swnj MFREE(m, n); 1854585Swnj return (n); 1864585Swnj } 1874585Swnj 1884669Swnj m_freem(m) 1894585Swnj register struct mbuf *m; 1904585Swnj { 1914585Swnj register struct mbuf *n; 1924585Swnj 1934585Swnj if (m == NULL) 1944916Swnj return; 1954585Swnj do { 1964585Swnj MFREE(m, n); 1974585Swnj } while (m = n); 1984585Swnj } 1994585Swnj 2005228Swnj /* 2015228Swnj * Mbuffer utility routines. 2025228Swnj */ 20321107Skarels 20421107Skarels /* 20538962Skarels * Lesser-used path for M_PREPEND: 20638962Skarels * allocate new mbuf to prepend to chain, 20738962Skarels * copy junk along. 20838962Skarels */ 20938962Skarels struct mbuf * 21038962Skarels m_prepend(m, len, how) 21138962Skarels register struct mbuf *m; 21238962Skarels int len, how; 21338962Skarels { 21438962Skarels struct mbuf *mn; 21538962Skarels 21638962Skarels MGET(mn, how, m->m_type); 21738962Skarels if (mn == (struct mbuf *)NULL) { 21838962Skarels m_freem(m); 21938962Skarels return ((struct mbuf *)NULL); 22038962Skarels } 22138962Skarels if (m->m_flags & M_PKTHDR) { 22238962Skarels M_COPY_PKTHDR(mn, m); 22338962Skarels m->m_flags &= ~M_PKTHDR; 22438962Skarels } 22538962Skarels mn->m_next = m; 22638962Skarels m = mn; 22738962Skarels if (len < MHLEN) 22838962Skarels MH_ALIGN(m, len); 22938962Skarels m->m_len = len; 23038962Skarels return (m); 23138962Skarels } 23238962Skarels 23333606Skarels /* 23438962Skarels * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 23521107Skarels * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 23638962Skarels * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. 23721107Skarels */ 2384927Swnj struct mbuf * 23938962Skarels m_copym(m, off0, len, wait) 2404927Swnj register struct mbuf *m; 24138962Skarels int off0, wait; 2424927Swnj register int len; 2434927Swnj { 2444927Swnj register struct mbuf *n, **np; 24538962Skarels register int off = off0; 24638962Skarels struct mbuf *top; 24738962Skarels int copyhdr = 0; 2484927Swnj 2494927Swnj if (off < 0 || len < 0) 25038962Skarels panic("m_copym"); 25138962Skarels if (off == 0 && m->m_flags & M_PKTHDR) 25238962Skarels copyhdr = 1; 2534927Swnj while (off > 0) { 2544927Swnj if (m == 0) 25538962Skarels panic("m_copym"); 2564927Swnj if (off < m->m_len) 2574927Swnj break; 2584927Swnj off -= m->m_len; 2594927Swnj m = m->m_next; 2604927Swnj } 2614927Swnj np = ⊤ 2624927Swnj top = 0; 2634927Swnj while (len > 0) { 2645609Swnj if (m == 0) { 2655609Swnj if (len != M_COPYALL) 26638962Skarels panic("m_copym"); 2675609Swnj break; 2685609Swnj } 26938962Skarels MGET(n, wait, m->m_type); 2704927Swnj *np = n; 2714927Swnj if (n == 0) 2724927Swnj goto nospace; 27338962Skarels if (copyhdr) { 27438962Skarels M_COPY_PKTHDR(n, m); 27538962Skarels if (len == M_COPYALL) 27638962Skarels n->m_pkthdr.len -= off0; 27738962Skarels else 27838962Skarels n->m_pkthdr.len = len; 27938962Skarels copyhdr = 0; 28038962Skarels } 2814927Swnj n->m_len = MIN(len, m->m_len - off); 28238962Skarels if (m->m_flags & M_EXT) { 28338962Skarels n->m_data = m->m_data + off; 28438962Skarels mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 28538962Skarels n->m_ext = m->m_ext; 28638962Skarels n->m_flags |= M_EXT; 2878318Sroot } else 2884927Swnj bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 2894927Swnj (unsigned)n->m_len); 2905609Swnj if (len != M_COPYALL) 2915609Swnj len -= n->m_len; 2924927Swnj off = 0; 2934927Swnj m = m->m_next; 2944927Swnj np = &n->m_next; 2954927Swnj } 2964927Swnj return (top); 2974927Swnj nospace: 2984927Swnj m_freem(top); 2994927Swnj return (0); 3004927Swnj } 3014927Swnj 30233606Skarels /* 30333606Skarels * Copy data from an mbuf chain starting "off" bytes from the beginning, 30433606Skarels * continuing for "len" bytes, into the indicated buffer. 30533606Skarels */ 30633606Skarels m_copydata(m, off, len, cp) 30733606Skarels register struct mbuf *m; 30833988Skarels register int off; 30933606Skarels register int len; 31033988Skarels caddr_t cp; 31133606Skarels { 31233606Skarels register unsigned count; 31333606Skarels 31433606Skarels if (off < 0 || len < 0) 31533606Skarels panic("m_copydata"); 31633606Skarels while (off > 0) { 31733606Skarels if (m == 0) 31833606Skarels panic("m_copydata"); 31933606Skarels if (off < m->m_len) 32033606Skarels break; 32133606Skarels off -= m->m_len; 32233606Skarels m = m->m_next; 32333606Skarels } 32433606Skarels while (len > 0) { 32533606Skarels if (m == 0) 32633606Skarels panic("m_copydata"); 32733988Skarels count = MIN(m->m_len - off, len); 32833606Skarels bcopy(mtod(m, caddr_t) + off, cp, count); 32933606Skarels len -= count; 33033988Skarels cp += count; 33133606Skarels off = 0; 33233606Skarels m = m->m_next; 33333606Skarels } 33433606Skarels } 33533606Skarels 33638962Skarels /* 33738962Skarels * Concatenate mbuf chain n to m. 33838962Skarels * Both chains must be of the same type (e.g. MT_DATA). 33938962Skarels * Any m_pkthdr is not updated. 34038962Skarels */ 3414669Swnj m_cat(m, n) 3424669Swnj register struct mbuf *m, *n; 3434669Swnj { 3444669Swnj while (m->m_next) 3454669Swnj m = m->m_next; 3466091Sroot while (n) { 34738962Skarels if (m->m_flags & M_EXT || 34838962Skarels m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 3496091Sroot /* just join the two chains */ 3504669Swnj m->m_next = n; 3516091Sroot return; 3524669Swnj } 3536091Sroot /* splat the data from one into the other */ 3546091Sroot bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 3556091Sroot (u_int)n->m_len); 3566091Sroot m->m_len += n->m_len; 3576091Sroot n = m_free(n); 3586091Sroot } 3594669Swnj } 3604669Swnj 36138962Skarels m_adj(mp, req_len) 3624585Swnj struct mbuf *mp; 3634585Swnj { 36438962Skarels register int len = req_len; 36524764Skarels register struct mbuf *m; 36624764Skarels register count; 3674585Swnj 3684585Swnj if ((m = mp) == NULL) 3694585Swnj return; 3704822Swnj if (len >= 0) { 37138962Skarels /* 37238962Skarels * Trim from head. 37338962Skarels */ 3744585Swnj while (m != NULL && len > 0) { 3754822Swnj if (m->m_len <= len) { 3764585Swnj len -= m->m_len; 3774585Swnj m->m_len = 0; 3784585Swnj m = m->m_next; 3794822Swnj } else { 3804585Swnj m->m_len -= len; 38138962Skarels m->m_data += len; 38238962Skarels len = 0; 3834585Swnj } 3844585Swnj } 38538962Skarels m = mp; 38638962Skarels if (mp->m_flags & M_PKTHDR) 38738962Skarels m->m_pkthdr.len -= (req_len - len); 3884822Swnj } else { 38924764Skarels /* 39024764Skarels * Trim from tail. Scan the mbuf chain, 39124764Skarels * calculating its length and finding the last mbuf. 39224764Skarels * If the adjustment only affects this mbuf, then just 39324764Skarels * adjust and return. Otherwise, rescan and truncate 39424764Skarels * after the remaining size. 39524764Skarels */ 3964585Swnj len = -len; 39724764Skarels count = 0; 39824764Skarels for (;;) { 39924764Skarels count += m->m_len; 40024764Skarels if (m->m_next == (struct mbuf *)0) 4014585Swnj break; 40224764Skarels m = m->m_next; 40324764Skarels } 40424764Skarels if (m->m_len >= len) { 40524764Skarels m->m_len -= len; 40639227Ssklower if ((mp = m)->m_flags & M_PKTHDR) 40739227Ssklower m->m_pkthdr.len -= len; 40824764Skarels return; 40924764Skarels } 41024764Skarels count -= len; 41138962Skarels if (count < 0) 41238962Skarels count = 0; 41324764Skarels /* 41424764Skarels * Correct length for chain is "count". 41524764Skarels * Find the mbuf with last data, adjust its length, 41624764Skarels * and toss data from remaining mbufs on chain. 41724764Skarels */ 41838962Skarels m = mp; 41938962Skarels if (m->m_flags & M_PKTHDR) 42038962Skarels m->m_pkthdr.len = count; 42138962Skarels for (; m; m = m->m_next) { 42224764Skarels if (m->m_len >= count) { 42324764Skarels m->m_len = count; 42424764Skarels break; 4254585Swnj } 42624764Skarels count -= m->m_len; 4274585Swnj } 42824764Skarels while (m = m->m_next) 42924764Skarels m->m_len = 0; 4304585Swnj } 4314585Swnj } 4325228Swnj 43323816Skarels /* 43423816Skarels * Rearange an mbuf chain so that len bytes are contiguous 43523816Skarels * and in the data area of an mbuf (so that mtod and dtom 43624764Skarels * will work for a structure of size len). Returns the resulting 43724764Skarels * mbuf chain on success, frees it and returns null on failure. 43838962Skarels * If there is room, it will add up to max_protohdr-len extra bytes to the 43924764Skarels * contiguous region in an attempt to avoid being called next time. 44023816Skarels */ 4415310Sroot struct mbuf * 44224764Skarels m_pullup(n, len) 44324764Skarels register struct mbuf *n; 4445228Swnj int len; 4455228Swnj { 44624764Skarels register struct mbuf *m; 44724764Skarels register int count; 44824764Skarels int space; 4495228Swnj 45038962Skarels /* 45138962Skarels * If first mbuf has no cluster, and has room for len bytes 45238962Skarels * without shifting current data, pullup into it, 45338962Skarels * otherwise allocate a new mbuf to prepend to the chain. 45438962Skarels */ 45538962Skarels if ((n->m_flags & M_EXT) == 0 && 45638962Skarels n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 45738962Skarels if (n->m_len >= len) 45838962Skarels return (n); 45924764Skarels m = n; 46024764Skarels n = n->m_next; 46124764Skarels len -= m->m_len; 46224764Skarels } else { 46338962Skarels if (len > MHLEN) 46424764Skarels goto bad; 46524764Skarels MGET(m, M_DONTWAIT, n->m_type); 46624764Skarels if (m == 0) 46724764Skarels goto bad; 46824764Skarels m->m_len = 0; 46938962Skarels if (n->m_flags & M_PKTHDR) 47038962Skarels M_COPY_PKTHDR(m, n); 47124764Skarels } 47238962Skarels space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 4735310Sroot do { 47438962Skarels count = min(min(max(len, max_protohdr), space), n->m_len); 47538962Skarels bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 4766164Ssam (unsigned)count); 4776164Ssam len -= count; 4786164Ssam m->m_len += count; 4796164Ssam n->m_len -= count; 48038962Skarels space -= count; 4815310Sroot if (n->m_len) 48238962Skarels n->m_data += count; 48323816Skarels else 48423816Skarels n = m_free(n); 48524764Skarels } while (len > 0 && n); 48624764Skarels if (len > 0) { 4875310Sroot (void) m_free(m); 4885310Sroot goto bad; 4895310Sroot } 4905310Sroot m->m_next = n; 4915310Sroot return (m); 4925310Sroot bad: 4935732Sroot m_freem(n); 4945228Swnj return (0); 4955228Swnj } 496