|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1988, 1991, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/systm.h> ! 63: #include <sys/malloc.h> ! 64: #include <sys/mbuf.h> ! 65: #include <sys/kernel.h> ! 66: #include <sys/syslog.h> ! 67: #include <sys/protosw.h> ! 68: #include <sys/domain.h> ! 69: #include <net/netisr.h> ! 70: ! 71: struct mbuf *mfree; /* mbuf free list */ ! 72: struct mbuf *mfreelater; /* mbuf deallocation list */ ! 73: extern vm_map_t mb_map; /* special map */ ! 74: int m_want; /* sleepers on mbufs */ ! 75: extern int nmbclusters; /* max number of mapped clusters */ ! 76: short *mclrefcnt; /* mapped cluster reference counts */ ! 77: union mcluster *mclfree; /* mapped cluster free list */ ! 78: int max_linkhdr; /* largest link-level header */ ! 79: int max_protohdr; /* largest protocol header */ ! 80: int max_hdr; /* largest link+protocol header */ ! 81: int max_datalen; /* MHLEN - max_hdr */ ! 82: struct mbstat mbstat; /* statistics */ ! 83: union mcluster *mbutl; /* first mapped cluster address */ ! 84: union mcluster embutl; /* virtual address of mclusters */ ! 85: ! 86: static int nclpp; /* # clusters per physical page */ ! 87: static char mbfail[] = "mbuf not mapped"; ! 88: ! 89: static int m_howmany(); ! 90: ! 91: /* The number of cluster mbufs that are allocated, to start. */ ! 92: #define MINCL max(16, 2) ! 93: ! 94: void ! 95: mbinit() ! 96: { ! 97: int s,m; ! 98: ! 99: if (nclpp) ! 100: return; ! 101: s = splimp(); ! 102: nclpp = round_page(MCLBYTES) / MCLBYTES; /* see mbufgc() */ ! 103: if (nclpp < 1) nclpp = 1; ! 104: MBUF_LOCKINIT(); ! 105: // NETISR_LOCKINIT(); ! 106: if (nmbclusters == 0) ! 107: nmbclusters = NMBCLUSTERS; ! 108: MALLOC(mclrefcnt, short *, nmbclusters * sizeof (short), ! 109: M_TEMP, M_WAITOK); ! 110: if (mclrefcnt == 0) ! 111: panic("mbinit"); ! 112: for (m = 0; m < nmbclusters; m++) ! 113: mclrefcnt[m] = -1; ! 114: MBUF_LOCK(); ! 115: if (m_clalloc(max(4096/CLBYTES, 1) * 10, M_DONTWAIT) == 0) ! 116: goto bad; ! 117: MBUF_UNLOCK(); ! 118: splx(s); ! 119: return; ! 120: bad: ! 121: panic("mbinit"); ! 122: } ! 123: ! 124: /* ! 125: * Allocate some number of mbuf clusters ! 126: * and place on cluster free list. ! 127: * Must be called at splimp. ! 128: */ ! 129: /* ARGSUSED */ ! 130: m_clalloc(ncl, nowait) ! 131: register int ncl; ! 132: int nowait; ! 133: { ! 134: register union mcluster *mcl; ! 135: register int i; ! 136: vm_size_t size; ! 137: static char doing_alloc; ! 138: ! 139: if (doing_alloc || (i = m_howmany()) <= 0) ! 140: goto out; ! 141: doing_alloc = 1; ! 142: MBUF_UNLOCK(); ! 143: ! 144: if (ncl < i) ncl = i; ! 145: size = round_page(ncl * MCLBYTES); ! 146: mcl = (union mcluster *)kmem_mb_alloc(mb_map, size); ! 147: if (mcl == 0 && ncl > 1) { ! 148: size = round_page(MCLBYTES); /* Try for 1 if failed */ ! 149: mcl = (union mcluster *)kmem_mb_alloc(mb_map, size); ! 150: } ! 151: MBUF_LOCK(); ! 152: doing_alloc = 0; ! 153: if (mcl) { ! 154: ncl = size / MCLBYTES; ! 155: for (i = 0; i < ncl; i++) { ! 156: if (++mclrefcnt[mtocl(mcl)] != 0) ! 157: panic("m_clalloc already there"); ! 158: mcl->mcl_next = mclfree; ! 159: mclfree = mcl++; ! 160: } ! 161: mbstat.m_clfree += ncl; ! 162: mbstat.m_clusters += ncl; ! 163: return (ncl); ! 164: } /* else ... */ ! 165: out: ! 166: if (mclfree) ! 167: return 1; ! 168: mbstat.m_drops++; ! 169: return 0; ! 170: } ! 171: ! 172: /* ! 173: * Add more free mbufs by cutting up a cluster. ! 174: */ ! 175: m_expand(canwait) ! 176: int canwait; ! 177: { ! 178: register caddr_t mcl; ! 179: ! 180: if (mbstat.m_clfree < (mbstat.m_clusters >> 4)) ! 181: /* 1/16th of the total number of cluster mbufs allocated is ! 182: reserved for large packets. The number reserved must ! 183: always be < 1/2, or future allocation will be prevented. ! 184: */ ! 185: return 0; ! 186: ! 187: MCLALLOC(mcl, canwait); ! 188: if (mcl) { ! 189: register struct mbuf *m = (struct mbuf *)mcl; ! 190: register int i = NMBPCL; ! 191: int s = splimp(); ! 192: MBUF_LOCK(); ! 193: mbstat.m_mtypes[MT_FREE] += i; ! 194: mbstat.m_mbufs += i; ! 195: while (i--) { ! 196: m->m_type = MT_FREE; ! 197: m->m_next = mfree; ! 198: mfree = m++; ! 199: } ! 200: i = m_want; ! 201: m_want = 0; ! 202: MBUF_UNLOCK(); ! 203: splx(s); ! 204: if (i) wakeup((caddr_t)&mfree); ! 205: return 1; ! 206: } ! 207: return 0; ! 208: } ! 209: ! 210: /* ! 211: * When MGET failes, ask protocols to free space when short of memory, ! 212: * then re-attempt to allocate an mbuf. ! 213: */ ! 214: struct mbuf * ! 215: m_retry(canwait, type) ! 216: int canwait, type; ! 217: { ! 218: #define m_retry(h, t) 0 ! 219: register struct mbuf *m; ! 220: int wait, s; ! 221: ! 222: for (;;) { ! 223: (void) m_expand(canwait); ! 224: MGET(m, XXX, type); ! 225: if (m || canwait == M_DONTWAIT) ! 226: break; ! 227: s = splimp(); ! 228: MBUF_LOCK(); ! 229: wait = m_want++; ! 230: if (wait == 0) ! 231: mbstat.m_drain++; ! 232: else { ! 233: assert_wait((caddr_t)&mfree, FALSE); ! 234: mbstat.m_wait++; ! 235: } ! 236: MBUF_UNLOCK(); ! 237: if (wait == 0) { ! 238: splx(s); ! 239: m_reclaim(); ! 240: } else { ! 241: /* Sleep with a small timeout as insurance */ ! 242: (void) tsleep((caddr_t)0, PZERO-1, "m_retry", hz); ! 243: splx(s); ! 244: } ! 245: } ! 246: return (m); ! 247: #undef m_retry ! 248: } ! 249: ! 250: /* ! 251: * As above; retry an MGETHDR. ! 252: */ ! 253: struct mbuf * ! 254: m_retryhdr(canwait, type) ! 255: int canwait, type; ! 256: { ! 257: register struct mbuf *m; ! 258: ! 259: if (m = m_retry(canwait, type)) { ! 260: m->m_flags |= M_PKTHDR; ! 261: m->m_data = m->m_pktdat; ! 262: } ! 263: return (m); ! 264: } ! 265: ! 266: m_reclaim() ! 267: { ! 268: register struct domain *dp; ! 269: register struct protosw *pr; ! 270: int s = splimp(); ! 271: ! 272: for (dp = domains; dp; dp = dp->dom_next) ! 273: for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) ! 274: if (pr->pr_drain) ! 275: (*pr->pr_drain)(); ! 276: splx(s); ! 277: mbstat.m_drain++; ! 278: } ! 279: ! 280: /* ! 281: * Space allocation routines. ! 282: * These are also available as macros ! 283: * for critical paths. ! 284: */ ! 285: struct mbuf * ! 286: m_get(nowait, type) ! 287: int nowait, type; ! 288: { ! 289: register struct mbuf *m; ! 290: ! 291: MGET(m, nowait, type); ! 292: return (m); ! 293: } ! 294: ! 295: struct mbuf * ! 296: m_gethdr(nowait, type) ! 297: int nowait, type; ! 298: { ! 299: register struct mbuf *m; ! 300: ! 301: MGETHDR(m, nowait, type); ! 302: return (m); ! 303: } ! 304: ! 305: struct mbuf * ! 306: m_getclr(nowait, type) ! 307: int nowait, type; ! 308: { ! 309: register struct mbuf *m; ! 310: ! 311: MGET(m, nowait, type); ! 312: if (m == 0) ! 313: return (0); ! 314: bzero(mtod(m, caddr_t), MLEN); ! 315: return (m); ! 316: } ! 317: ! 318: struct mbuf * ! 319: m_free(m) ! 320: struct mbuf *m; ! 321: { ! 322: struct mbuf *n = m->m_next; ! 323: int i, s; ! 324: ! 325: if (m->m_type == MT_FREE) ! 326: panic("freeing free mbuf"); ! 327: s = splimp(); ! 328: MBUF_LOCK(); ! 329: if (m->m_flags & M_EXT) { ! 330: if (MCLHASREFERENCE(m)) { ! 331: remque((queue_t)&m->m_ext.ext_refs); ! 332: } else if (m->m_ext.ext_free == NULL) { ! 333: union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf; ! 334: if (MCLUNREF(mcl)) { ! 335: mcl->mcl_next = mclfree; ! 336: mclfree = mcl; ! 337: ++mbstat.m_clfree; ! 338: } else /* sanity check - not referenced this way */ ! 339: panic("m_free m_ext cluster not free"); ! 340: } else { ! 341: (*(m->m_ext.ext_free))(m->m_ext.ext_buf, ! 342: m->m_ext.ext_size, m->m_ext.ext_arg); ! 343: } ! 344: } ! 345: mbstat.m_mtypes[m->m_type]--; ! 346: (void) MCLUNREF(m); ! 347: m->m_type = MT_FREE; ! 348: mbstat.m_mtypes[m->m_type]++; ! 349: m->m_flags = 0; ! 350: m->m_next = mfree; ! 351: m->m_len = 0; ! 352: mfree = m; ! 353: i = m_want; ! 354: m_want = 0; ! 355: MBUF_UNLOCK(); ! 356: splx(s); ! 357: if (i) wakeup((caddr_t)&mfree); ! 358: return (n); ! 359: } ! 360: ! 361: void ! 362: m_freem(m) ! 363: register struct mbuf *m; ! 364: { ! 365: while (m) ! 366: m = m_free(m); ! 367: } ! 368: ! 369: /* ! 370: * Mbuffer utility routines. ! 371: */ ! 372: /* ! 373: * Compute the amount of space available ! 374: * before the current start of data in an mbuf. ! 375: */ ! 376: m_leadingspace(m) ! 377: register struct mbuf *m; ! 378: { ! 379: if (m->m_flags & M_EXT) { ! 380: if (MCLHASREFERENCE(m)) ! 381: return(0); ! 382: return (m->m_data - m->m_ext.ext_buf); ! 383: } ! 384: if (m->m_flags & M_PKTHDR) ! 385: return (m->m_data - m->m_pktdat); ! 386: return (m->m_data - m->m_dat); ! 387: } ! 388: ! 389: /* ! 390: * Compute the amount of space available ! 391: * after the end of data in an mbuf. ! 392: */ ! 393: m_trailingspace(m) ! 394: register struct mbuf *m; ! 395: { ! 396: if (m->m_flags & M_EXT) { ! 397: if (MCLHASREFERENCE(m)) ! 398: return(0); ! 399: return (m->m_ext.ext_buf + m->m_ext.ext_size - ! 400: (m->m_data + m->m_len)); ! 401: } ! 402: return (&m->m_dat[MLEN] - (m->m_data + m->m_len)); ! 403: } ! 404: ! 405: /* ! 406: * Lesser-used path for M_PREPEND: ! 407: * allocate new mbuf to prepend to chain, ! 408: * copy junk along. ! 409: */ ! 410: struct mbuf * ! 411: m_prepend(m, len, how) ! 412: register struct mbuf *m; ! 413: int len, how; ! 414: { ! 415: struct mbuf *mn; ! 416: ! 417: MGET(mn, how, m->m_type); ! 418: if (mn == (struct mbuf *)NULL) { ! 419: m_freem(m); ! 420: return ((struct mbuf *)NULL); ! 421: } ! 422: if (m->m_flags & M_PKTHDR) { ! 423: M_COPY_PKTHDR(mn, m); ! 424: m->m_flags &= ~M_PKTHDR; ! 425: } ! 426: mn->m_next = m; ! 427: m = mn; ! 428: if (len < MHLEN) ! 429: MH_ALIGN(m, len); ! 430: m->m_len = len; ! 431: return (m); ! 432: } ! 433: ! 434: /* ! 435: * Make a copy of an mbuf chain starting "off0" bytes from the beginning, ! 436: * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. ! 437: * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. ! 438: */ ! 439: int MCFail; ! 440: ! 441: struct mbuf * ! 442: m_copym(m, off0, len, wait) ! 443: register struct mbuf *m; ! 444: int off0, wait; ! 445: register int len; ! 446: { ! 447: register struct mbuf *n, **np; ! 448: register int off = off0; ! 449: struct mbuf *top; ! 450: int copyhdr = 0; ! 451: ! 452: if (off < 0 || len < 0) ! 453: panic("m_copym"); ! 454: if (off == 0 && m->m_flags & M_PKTHDR) ! 455: copyhdr = 1; ! 456: while (off > 0) { ! 457: if (m == 0) ! 458: panic("m_copym"); ! 459: if (off < m->m_len) ! 460: break; ! 461: off -= m->m_len; ! 462: m = m->m_next; ! 463: } ! 464: np = ⊤ ! 465: top = 0; ! 466: while (len > 0) { ! 467: if (m == 0) { ! 468: if (len != M_COPYALL) ! 469: panic("m_copym"); ! 470: break; ! 471: } ! 472: MGET(n, wait, m->m_type); ! 473: *np = n; ! 474: if (n == 0) ! 475: goto nospace; ! 476: if (copyhdr) { ! 477: M_COPY_PKTHDR(n, m); ! 478: if (len == M_COPYALL) ! 479: n->m_pkthdr.len -= off0; ! 480: else ! 481: n->m_pkthdr.len = len; ! 482: copyhdr = 0; ! 483: } ! 484: if (len == M_COPYALL) { ! 485: if (min(len, (m->m_len - off)) == len) { ! 486: printf("m->m_len %d - off %d = %d, %d\n", ! 487: m->m_len, off, m->m_len - off, ! 488: min(len, (m->m_len - off))); ! 489: } ! 490: } ! 491: n->m_len = min(len, (m->m_len - off)); ! 492: if (n->m_len == M_COPYALL) { ! 493: printf("n->m_len == M_COPYALL, fixing\n"); ! 494: n->m_len = MHLEN; ! 495: } ! 496: if (m->m_flags & M_EXT) { ! 497: int s = splimp(); ! 498: MBUF_LOCK(); ! 499: n->m_ext = m->m_ext; ! 500: insque((queue_t)&n->m_ext.ext_refs, (queue_t)&m->m_ext.ext_refs); ! 501: MBUF_UNLOCK(); ! 502: splx(s); ! 503: n->m_data = m->m_data + off; ! 504: n->m_flags |= M_EXT; ! 505: } else ! 506: bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), ! 507: (unsigned)n->m_len); ! 508: if (len != M_COPYALL) ! 509: len -= n->m_len; ! 510: off = 0; ! 511: m = m->m_next; ! 512: np = &n->m_next; ! 513: } ! 514: if (top == 0) ! 515: MCFail++; ! 516: return (top); ! 517: nospace: ! 518: m_freem(top); ! 519: MCFail++; ! 520: return (0); ! 521: } ! 522: ! 523: /* ! 524: * Copy data from an mbuf chain starting "off" bytes from the beginning, ! 525: * continuing for "len" bytes, into the indicated buffer. ! 526: */ ! 527: m_copydata(m, off, len, cp) ! 528: register struct mbuf *m; ! 529: register int off; ! 530: register int len; ! 531: caddr_t cp; ! 532: { ! 533: register unsigned count; ! 534: ! 535: if (off < 0 || len < 0) ! 536: panic("m_copydata"); ! 537: while (off > 0) { ! 538: if (m == 0) ! 539: panic("m_copydata"); ! 540: if (off < m->m_len) ! 541: break; ! 542: off -= m->m_len; ! 543: m = m->m_next; ! 544: } ! 545: while (len > 0) { ! 546: if (m == 0) ! 547: panic("m_copydata"); ! 548: count = min(m->m_len - off, len); ! 549: bcopy(mtod(m, caddr_t) + off, cp, count); ! 550: len -= count; ! 551: cp += count; ! 552: off = 0; ! 553: m = m->m_next; ! 554: } ! 555: } ! 556: ! 557: /* ! 558: * Concatenate mbuf chain n to m. ! 559: * Both chains must be of the same type (e.g. MT_DATA). ! 560: * Any m_pkthdr is not updated. ! 561: */ ! 562: m_cat(m, n) ! 563: register struct mbuf *m, *n; ! 564: { ! 565: while (m->m_next) ! 566: m = m->m_next; ! 567: while (n) { ! 568: if (m->m_flags & M_EXT || ! 569: m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { ! 570: /* just join the two chains */ ! 571: m->m_next = n; ! 572: return; ! 573: } ! 574: /* splat the data from one into the other */ ! 575: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, ! 576: (u_int)n->m_len); ! 577: m->m_len += n->m_len; ! 578: n = m_free(n); ! 579: } ! 580: } ! 581: ! 582: void ! 583: m_adj(mp, req_len) ! 584: struct mbuf *mp; ! 585: int req_len; ! 586: { ! 587: register int len = req_len; ! 588: register struct mbuf *m; ! 589: register count; ! 590: ! 591: if ((m = mp) == NULL) ! 592: return; ! 593: if (len >= 0) { ! 594: /* ! 595: * Trim from head. ! 596: */ ! 597: while (m != NULL && len > 0) { ! 598: if (m->m_len <= len) { ! 599: len -= m->m_len; ! 600: m->m_len = 0; ! 601: m = m->m_next; ! 602: } else { ! 603: m->m_len -= len; ! 604: m->m_data += len; ! 605: len = 0; ! 606: } ! 607: } ! 608: m = mp; ! 609: if (m->m_flags & M_PKTHDR) ! 610: m->m_pkthdr.len -= (req_len - len); ! 611: } else { ! 612: /* ! 613: * Trim from tail. Scan the mbuf chain, ! 614: * calculating its length and finding the last mbuf. ! 615: * If the adjustment only affects this mbuf, then just ! 616: * adjust and return. Otherwise, rescan and truncate ! 617: * after the remaining size. ! 618: */ ! 619: len = -len; ! 620: count = 0; ! 621: for (;;) { ! 622: count += m->m_len; ! 623: if (m->m_next == (struct mbuf *)0) ! 624: break; ! 625: m = m->m_next; ! 626: } ! 627: if (m->m_len >= len) { ! 628: m->m_len -= len; ! 629: m = mp; ! 630: if (m->m_flags & M_PKTHDR) ! 631: m->m_pkthdr.len -= len; ! 632: return; ! 633: } ! 634: count -= len; ! 635: if (count < 0) ! 636: count = 0; ! 637: /* ! 638: * Correct length for chain is "count". ! 639: * Find the mbuf with last data, adjust its length, ! 640: * and toss data from remaining mbufs on chain. ! 641: */ ! 642: m = mp; ! 643: if (m->m_flags & M_PKTHDR) ! 644: m->m_pkthdr.len = count; ! 645: for (; m; m = m->m_next) { ! 646: if (m->m_len >= count) { ! 647: m->m_len = count; ! 648: break; ! 649: } ! 650: count -= m->m_len; ! 651: } ! 652: while (m = m->m_next) ! 653: m->m_len = 0; ! 654: } ! 655: } ! 656: ! 657: /* ! 658: * Rearange an mbuf chain so that len bytes are contiguous ! 659: * and in the data area of an mbuf (so that mtod and dtom ! 660: * will work for a structure of size len). Returns the resulting ! 661: * mbuf chain on success, frees it and returns null on failure. ! 662: * If there is room, it will add up to max_protohdr-len extra bytes to the ! 663: * contiguous region in an attempt to avoid being called next time. ! 664: */ ! 665: int MPFail; ! 666: ! 667: struct mbuf * ! 668: m_pullup(n, len) ! 669: register struct mbuf *n; ! 670: int len; ! 671: { ! 672: register struct mbuf *m; ! 673: register int count; ! 674: int space; ! 675: ! 676: /* ! 677: * If first mbuf has no cluster, and has room for len bytes ! 678: * without shifting current data, pullup into it, ! 679: * otherwise allocate a new mbuf to prepend to the chain. ! 680: */ ! 681: if ((n->m_flags & M_EXT) == 0 && ! 682: n->m_data + len < &n->m_dat[MLEN] && n->m_next) { ! 683: if (n->m_len >= len) ! 684: return (n); ! 685: m = n; ! 686: n = n->m_next; ! 687: len -= m->m_len; ! 688: } else { ! 689: if (len > MHLEN) ! 690: goto bad; ! 691: MGET(m, M_DONTWAIT, n->m_type); ! 692: if (m == 0) ! 693: goto bad; ! 694: m->m_len = 0; ! 695: if (n->m_flags & M_PKTHDR) { ! 696: M_COPY_PKTHDR(m, n); ! 697: n->m_flags &= ~M_PKTHDR; ! 698: } ! 699: } ! 700: space = &m->m_dat[MLEN] - (m->m_data + m->m_len); ! 701: do { ! 702: count = min(min(max(len, max_protohdr), space), n->m_len); ! 703: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, ! 704: (unsigned)count); ! 705: len -= count; ! 706: m->m_len += count; ! 707: n->m_len -= count; ! 708: space -= count; ! 709: if (n->m_len) ! 710: n->m_data += count; ! 711: else ! 712: n = m_free(n); ! 713: } while (len > 0 && n); ! 714: if (len > 0) { ! 715: (void) m_free(m); ! 716: goto bad; ! 717: } ! 718: m->m_next = n; ! 719: return (m); ! 720: bad: ! 721: m_freem(n); ! 722: MPFail++; ! 723: return (0); ! 724: } ! 725: ! 726: /* ! 727: * Partition an mbuf chain in two pieces, returning the tail -- ! 728: * all but the first len0 bytes. In case of failure, it returns NULL and ! 729: * attempts to restore the chain to its original state. ! 730: */ ! 731: struct mbuf * ! 732: m_split(m0, len0, wait) ! 733: register struct mbuf *m0; ! 734: int len0, wait; ! 735: { ! 736: register struct mbuf *m, *n; ! 737: unsigned len = len0, remain; ! 738: ! 739: for (m = m0; m && len > m->m_len; m = m->m_next) ! 740: len -= m->m_len; ! 741: if (m == 0) ! 742: return (0); ! 743: remain = m->m_len - len; ! 744: if (m0->m_flags & M_PKTHDR) { ! 745: MGETHDR(n, wait, m0->m_type); ! 746: if (n == 0) ! 747: return (0); ! 748: n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; ! 749: n->m_pkthdr.len = m0->m_pkthdr.len - len0; ! 750: m0->m_pkthdr.len = len0; ! 751: if (m->m_flags & M_EXT) ! 752: goto extpacket; ! 753: if (remain > MHLEN) { ! 754: /* m can't be the lead packet */ ! 755: MH_ALIGN(n, 0); ! 756: n->m_next = m_split(m, len, wait); ! 757: if (n->m_next == 0) { ! 758: (void) m_free(n); ! 759: return (0); ! 760: } else ! 761: return (n); ! 762: } else ! 763: MH_ALIGN(n, remain); ! 764: } else if (remain == 0) { ! 765: n = m->m_next; ! 766: m->m_next = 0; ! 767: return (n); ! 768: } else { ! 769: MGET(n, wait, m->m_type); ! 770: if (n == 0) ! 771: return (0); ! 772: M_ALIGN(n, remain); ! 773: } ! 774: extpacket: ! 775: if (m->m_flags & M_EXT) { ! 776: n->m_flags |= M_EXT; ! 777: n->m_ext = m->m_ext; ! 778: mclrefcnt[mtocl(m->m_ext.ext_buf)]++; ! 779: m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ ! 780: n->m_data = m->m_data + len; ! 781: } else { ! 782: bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); ! 783: } ! 784: n->m_len = remain; ! 785: m->m_len = len; ! 786: n->m_next = m->m_next; ! 787: m->m_next = 0; ! 788: return (n); ! 789: } ! 790: /* ! 791: * Routine to copy from device local memory into mbufs. ! 792: */ ! 793: struct mbuf * ! 794: m_devget(buf, totlen, off0, ifp, copy) ! 795: char *buf; ! 796: int totlen, off0; ! 797: struct ifnet *ifp; ! 798: void (*copy)(); ! 799: { ! 800: register struct mbuf *m; ! 801: struct mbuf *top = 0, **mp = ⊤ ! 802: register int off = off0, len; ! 803: register char *cp; ! 804: char *epkt; ! 805: ! 806: cp = buf; ! 807: epkt = cp + totlen; ! 808: if (off) { ! 809: /* ! 810: * If 'off' is non-zero, packet is trailer-encapsulated, ! 811: * so we have to skip the type and length fields. ! 812: */ ! 813: cp += off + 2 * sizeof(u_int16_t); ! 814: totlen -= 2 * sizeof(u_int16_t); ! 815: } ! 816: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 817: if (m == 0) ! 818: return (0); ! 819: m->m_pkthdr.rcvif = ifp; ! 820: m->m_pkthdr.len = totlen; ! 821: m->m_len = MHLEN; ! 822: ! 823: while (totlen > 0) { ! 824: if (top) { ! 825: MGET(m, M_DONTWAIT, MT_DATA); ! 826: if (m == 0) { ! 827: m_freem(top); ! 828: return (0); ! 829: } ! 830: m->m_len = MLEN; ! 831: } ! 832: len = min(totlen, epkt - cp); ! 833: if (len >= MINCLSIZE) { ! 834: MCLGET(m, M_DONTWAIT); ! 835: if (m->m_flags & M_EXT) ! 836: m->m_len = len = min(len, MCLBYTES); ! 837: else { ! 838: /* give up when it's out of cluster mbufs */ ! 839: if (top) ! 840: m_freem(top); ! 841: m_freem(m); ! 842: return (0); ! 843: } ! 844: } else { ! 845: /* ! 846: * Place initial small packet/header at end of mbuf. ! 847: */ ! 848: if (len < m->m_len) { ! 849: if (top == 0 && len + max_linkhdr <= m->m_len) ! 850: m->m_data += max_linkhdr; ! 851: m->m_len = len; ! 852: } else ! 853: len = m->m_len; ! 854: } ! 855: if (copy) ! 856: copy(cp, mtod(m, caddr_t), (unsigned)len); ! 857: else ! 858: bcopy(cp, mtod(m, caddr_t), (unsigned)len); ! 859: cp += len; ! 860: *mp = m; ! 861: mp = &m->m_next; ! 862: totlen -= len; ! 863: if (cp == epkt) ! 864: cp = buf; ! 865: } ! 866: return (top); ! 867: } ! 868: ! 869: /* ! 870: * Cluster freelist allocation check. Mbuf lock/splimp must be held. ! 871: * Ensure hysteresis between hi/lo. ! 872: */ ! 873: static int ! 874: m_howmany() ! 875: { ! 876: register int i; ! 877: ! 878: /* Under minimum */ ! 879: if (mbstat.m_clusters < MINCL) ! 880: return (MINCL - mbstat.m_clusters); ! 881: /* Too few (free < 1/2 total) and not over maximum */ ! 882: if (mbstat.m_clusters < nmbclusters && ! 883: (i = ((mbstat.m_clusters >> 1) - mbstat.m_clfree)) > 0) ! 884: return i; ! 885: return 0; ! 886: } ! 887:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.