Annotation of XNU/bsd/kern/uipc_mbuf.c, revision 1.1

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 = &top;
        !           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 = &top;
        !           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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.