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