[BACK]Return to uipc_mbuf.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/uipc_mbuf.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: uipc_mbuf.c,v 1.85 2007/07/20 09:59:19 claudio Exp $  */
        !             2: /*     $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $   */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1982, 1986, 1988, 1991, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the University nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  *
        !            32:  *     @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
        !            33:  */
        !            34:
        !            35: /*
        !            36:  *     @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
        !            37:  *
        !            38:  * NRL grants permission for redistribution and use in source and binary
        !            39:  * forms, with or without modification, of the software and documentation
        !            40:  * created at NRL provided that the following conditions are met:
        !            41:  *
        !            42:  * 1. Redistributions of source code must retain the above copyright
        !            43:  *    notice, this list of conditions and the following disclaimer.
        !            44:  * 2. Redistributions in binary form must reproduce the above copyright
        !            45:  *    notice, this list of conditions and the following disclaimer in the
        !            46:  *    documentation and/or other materials provided with the distribution.
        !            47:  * 3. All advertising materials mentioning features or use of this software
        !            48:  *    must display the following acknowledgements:
        !            49:  *     This product includes software developed by the University of
        !            50:  *     California, Berkeley and its contributors.
        !            51:  *     This product includes software developed at the Information
        !            52:  *     Technology Division, US Naval Research Laboratory.
        !            53:  * 4. Neither the name of the NRL nor the names of its contributors
        !            54:  *    may be used to endorse or promote products derived from this software
        !            55:  *    without specific prior written permission.
        !            56:  *
        !            57:  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
        !            58:  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            59:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
        !            60:  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
        !            61:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        !            62:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            63:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        !            64:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        !            65:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
        !            66:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
        !            67:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            68:  *
        !            69:  * The views and conclusions contained in the software and documentation
        !            70:  * are those of the authors and should not be interpreted as representing
        !            71:  * official policies, either expressed or implied, of the US Naval
        !            72:  * Research Laboratory (NRL).
        !            73:  */
        !            74:
        !            75: #include <sys/param.h>
        !            76: #include <sys/systm.h>
        !            77: #include <sys/proc.h>
        !            78: #include <sys/malloc.h>
        !            79: #define MBTYPES
        !            80: #include <sys/mbuf.h>
        !            81: #include <sys/kernel.h>
        !            82: #include <sys/syslog.h>
        !            83: #include <sys/domain.h>
        !            84: #include <sys/protosw.h>
        !            85: #include <sys/pool.h>
        !            86:
        !            87: #include <machine/cpu.h>
        !            88:
        !            89: #include <uvm/uvm_extern.h>
        !            90:
        !            91: struct mbstat mbstat;          /* mbuf stats */
        !            92: struct pool mbpool;            /* mbuf pool */
        !            93: struct pool mclpool;           /* mbuf cluster pool */
        !            94:
        !            95: int max_linkhdr;               /* largest link-level header */
        !            96: int max_protohdr;              /* largest protocol header */
        !            97: int max_hdr;                   /* largest link+protocol header */
        !            98: int max_datalen;               /* MHLEN - max_hdr */
        !            99:
        !           100: struct mbuf *m_copym0(struct mbuf *, int, int, int, int);
        !           101: void   nmbclust_update(void);
        !           102:
        !           103:
        !           104: const char *mclpool_warnmsg =
        !           105:     "WARNING: mclpool limit reached; increase kern.maxclusters";
        !           106:
        !           107: /*
        !           108:  * Initialize the mbuf allocator.
        !           109:  */
        !           110: void
        !           111: mbinit(void)
        !           112: {
        !           113:        pool_init(&mbpool, MSIZE, 0, 0, 0, "mbpl", NULL);
        !           114:        pool_init(&mclpool, MCLBYTES, 0, 0, 0, "mclpl", NULL);
        !           115:
        !           116:        nmbclust_update();
        !           117:
        !           118:        /*
        !           119:         * Set a low water mark for both mbufs and clusters.  This should
        !           120:         * help ensure that they can be allocated in a memory starvation
        !           121:         * situation.  This is important for e.g. diskless systems which
        !           122:         * must allocate mbufs in order for the pagedaemon to clean pages.
        !           123:         */
        !           124:        pool_setlowat(&mbpool, mblowat);
        !           125:        pool_setlowat(&mclpool, mcllowat);
        !           126: }
        !           127:
        !           128: void
        !           129: nmbclust_update(void)
        !           130: {
        !           131:        /*
        !           132:         * Set the hard limit on the mclpool to the number of
        !           133:         * mbuf clusters the kernel is to support.  Log the limit
        !           134:         * reached message max once a minute.
        !           135:         */
        !           136:        (void)pool_sethardlimit(&mclpool, nmbclust, mclpool_warnmsg, 60);
        !           137:        pool_sethiwat(&mbpool, nmbclust);
        !           138: }
        !           139:
        !           140: void
        !           141: m_reclaim(void *arg, int flags)
        !           142: {
        !           143:        struct domain *dp;
        !           144:        struct protosw *pr;
        !           145:        int s = splvm();
        !           146:
        !           147:        for (dp = domains; dp; dp = dp->dom_next)
        !           148:                for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
        !           149:                        if (pr->pr_drain)
        !           150:                                (*pr->pr_drain)();
        !           151:        splx(s);
        !           152:        mbstat.m_drain++;
        !           153: }
        !           154:
        !           155: /*
        !           156:  * Space allocation routines.
        !           157:  */
        !           158: struct mbuf *
        !           159: m_get(int nowait, int type)
        !           160: {
        !           161:        struct mbuf *m;
        !           162:        int s;
        !           163:
        !           164:        s = splvm();
        !           165:        m = pool_get(&mbpool, nowait == M_WAIT ? PR_WAITOK|PR_LIMITFAIL : 0);
        !           166:        if (m) {
        !           167:                m->m_type = type;
        !           168:                mbstat.m_mtypes[type]++;
        !           169:                m->m_next = (struct mbuf *)NULL;
        !           170:                m->m_nextpkt = (struct mbuf *)NULL;
        !           171:                m->m_data = m->m_dat;
        !           172:                m->m_flags = 0;
        !           173:        }
        !           174:        splx(s);
        !           175:        return (m);
        !           176: }
        !           177:
        !           178: struct mbuf *
        !           179: m_gethdr(int nowait, int type)
        !           180: {
        !           181:        struct mbuf *m;
        !           182:        int s;
        !           183:
        !           184:        s = splvm();
        !           185:        m = pool_get(&mbpool, nowait == M_WAIT ? PR_WAITOK|PR_LIMITFAIL : 0);
        !           186:        if (m) {
        !           187:                m->m_type = type;
        !           188:                mbstat.m_mtypes[type]++;
        !           189:                m->m_next = (struct mbuf *)NULL;
        !           190:                m->m_nextpkt = (struct mbuf *)NULL;
        !           191:                m->m_data = m->m_pktdat;
        !           192:                m->m_flags = M_PKTHDR;
        !           193:                m->m_pkthdr.rcvif = NULL;
        !           194:                SLIST_INIT(&m->m_pkthdr.tags);
        !           195:                m->m_pkthdr.csum_flags = 0;
        !           196:                m->m_pkthdr.pf.hdr = NULL;
        !           197:                m->m_pkthdr.pf.rtableid = 0;
        !           198:                m->m_pkthdr.pf.qid = 0;
        !           199:                m->m_pkthdr.pf.tag = 0;
        !           200:                m->m_pkthdr.pf.flags = 0;
        !           201:                m->m_pkthdr.pf.routed = 0;
        !           202:        }
        !           203:        splx(s);
        !           204:        return (m);
        !           205: }
        !           206:
        !           207: struct mbuf *
        !           208: m_getclr(int nowait, int type)
        !           209: {
        !           210:        struct mbuf *m;
        !           211:
        !           212:        MGET(m, nowait, type);
        !           213:        if (m == NULL)
        !           214:                return (NULL);
        !           215:        memset(mtod(m, caddr_t), 0, MLEN);
        !           216:        return (m);
        !           217: }
        !           218:
        !           219: void
        !           220: m_clget(struct mbuf *m, int how)
        !           221: {
        !           222:        int s;
        !           223:
        !           224:        s = splvm();
        !           225:        m->m_ext.ext_buf =
        !           226:            pool_get(&mclpool, how == M_WAIT ? (PR_WAITOK|PR_LIMITFAIL) : 0);
        !           227:        splx(s);
        !           228:        if (m->m_ext.ext_buf != NULL) {
        !           229:                m->m_data = m->m_ext.ext_buf;
        !           230:                m->m_flags |= M_EXT|M_CLUSTER;
        !           231:                m->m_ext.ext_size = MCLBYTES;
        !           232:                m->m_ext.ext_free = NULL;
        !           233:                m->m_ext.ext_arg = NULL;
        !           234:                MCLINITREFERENCE(m);
        !           235:        }
        !           236: }
        !           237:
        !           238: struct mbuf *
        !           239: m_free(struct mbuf *m)
        !           240: {
        !           241:        struct mbuf *n;
        !           242:        int s;
        !           243:
        !           244:        s = splvm();
        !           245:        mbstat.m_mtypes[m->m_type]--;
        !           246:        if (m->m_flags & M_PKTHDR)
        !           247:                m_tag_delete_chain(m);
        !           248:        if (m->m_flags & M_EXT) {
        !           249:                if (MCLISREFERENCED(m))
        !           250:                        _MCLDEREFERENCE(m);
        !           251:                else if (m->m_flags & M_CLUSTER)
        !           252:                        pool_put(&mclpool, m->m_ext.ext_buf);
        !           253:                else if (m->m_ext.ext_free)
        !           254:                        (*(m->m_ext.ext_free))(m->m_ext.ext_buf,
        !           255:                            m->m_ext.ext_size, m->m_ext.ext_arg);
        !           256:                else
        !           257:                        free(m->m_ext.ext_buf,m->m_ext.ext_type);
        !           258:                m->m_flags &= ~(M_CLUSTER|M_EXT);
        !           259:                m->m_ext.ext_size = 0;
        !           260:        }
        !           261:        n = m->m_next;
        !           262:        pool_put(&mbpool, m);
        !           263:        splx(s);
        !           264:
        !           265:        return (n);
        !           266: }
        !           267:
        !           268: void
        !           269: m_freem(struct mbuf *m)
        !           270: {
        !           271:        struct mbuf *n;
        !           272:
        !           273:        if (m == NULL)
        !           274:                return;
        !           275:        do {
        !           276:                MFREE(m, n);
        !           277:        } while ((m = n) != NULL);
        !           278: }
        !           279:
        !           280: /*
        !           281:  * Mbuffer utility routines.
        !           282:  */
        !           283:
        !           284: /*
        !           285:  * Lesser-used path for M_PREPEND:
        !           286:  * allocate new mbuf to prepend to chain,
        !           287:  * copy junk along.
        !           288:  */
        !           289: struct mbuf *
        !           290: m_prepend(struct mbuf *m, int len, int how)
        !           291: {
        !           292:        struct mbuf *mn;
        !           293:
        !           294:        if (len > MHLEN)
        !           295:                panic("mbuf prepend length too big");
        !           296:
        !           297:        MGET(mn, how, m->m_type);
        !           298:        if (mn == NULL) {
        !           299:                m_freem(m);
        !           300:                return (NULL);
        !           301:        }
        !           302:        if (m->m_flags & M_PKTHDR)
        !           303:                M_MOVE_PKTHDR(mn, m);
        !           304:        mn->m_next = m;
        !           305:        m = mn;
        !           306:        MH_ALIGN(m, len);
        !           307:        m->m_len = len;
        !           308:        return (m);
        !           309: }
        !           310:
        !           311: /*
        !           312:  * Make a copy of an mbuf chain starting "off" bytes from the beginning,
        !           313:  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
        !           314:  * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
        !           315:  */
        !           316: int MCFail;
        !           317:
        !           318: struct mbuf *
        !           319: m_copym(struct mbuf *m, int off, int len, int wait)
        !           320: {
        !           321:        return m_copym0(m, off, len, wait, 0);  /* shallow copy on M_EXT */
        !           322: }
        !           323:
        !           324: /*
        !           325:  * m_copym2() is like m_copym(), except it COPIES cluster mbufs, instead
        !           326:  * of merely bumping the reference count.
        !           327:  */
        !           328: struct mbuf *
        !           329: m_copym2(struct mbuf *m, int off, int len, int wait)
        !           330: {
        !           331:        return m_copym0(m, off, len, wait, 1);  /* deep copy */
        !           332: }
        !           333:
        !           334: struct mbuf *
        !           335: m_copym0(struct mbuf *m, int off, int len, int wait, int deep)
        !           336: {
        !           337:        struct mbuf *n, **np;
        !           338:        struct mbuf *top;
        !           339:        int copyhdr = 0;
        !           340:
        !           341:        if (off < 0 || len < 0)
        !           342:                panic("m_copym0: off %d, len %d", off, len);
        !           343:        if (off == 0 && m->m_flags & M_PKTHDR)
        !           344:                copyhdr = 1;
        !           345:        while (off > 0) {
        !           346:                if (m == NULL)
        !           347:                        panic("m_copym0: null mbuf");
        !           348:                if (off < m->m_len)
        !           349:                        break;
        !           350:                off -= m->m_len;
        !           351:                m = m->m_next;
        !           352:        }
        !           353:        np = &top;
        !           354:        top = NULL;
        !           355:        while (len > 0) {
        !           356:                if (m == NULL) {
        !           357:                        if (len != M_COPYALL)
        !           358:                                panic("m_copym0: m == NULL and not COPYALL");
        !           359:                        break;
        !           360:                }
        !           361:                MGET(n, wait, m->m_type);
        !           362:                *np = n;
        !           363:                if (n == NULL)
        !           364:                        goto nospace;
        !           365:                if (copyhdr) {
        !           366:                        M_DUP_PKTHDR(n, m);
        !           367:                        if (len != M_COPYALL)
        !           368:                                n->m_pkthdr.len = len;
        !           369:                        copyhdr = 0;
        !           370:                }
        !           371:                n->m_len = min(len, m->m_len - off);
        !           372:                if (m->m_flags & M_EXT) {
        !           373:                        if (!deep) {
        !           374:                                n->m_data = m->m_data + off;
        !           375:                                n->m_ext = m->m_ext;
        !           376:                                MCLADDREFERENCE(m, n);
        !           377:                        } else {
        !           378:                                /*
        !           379:                                 * we are unsure about the way m was allocated.
        !           380:                                 * copy into multiple MCLBYTES cluster mbufs.
        !           381:                                 */
        !           382:                                MCLGET(n, wait);
        !           383:                                n->m_len = 0;
        !           384:                                n->m_len = M_TRAILINGSPACE(n);
        !           385:                                n->m_len = min(n->m_len, len);
        !           386:                                n->m_len = min(n->m_len, m->m_len - off);
        !           387:                                memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off,
        !           388:                                    (unsigned)n->m_len);
        !           389:                        }
        !           390:                } else
        !           391:                        memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off,
        !           392:                            (unsigned)n->m_len);
        !           393:                if (len != M_COPYALL)
        !           394:                        len -= n->m_len;
        !           395:                off += n->m_len;
        !           396: #ifdef DIAGNOSTIC
        !           397:                if (off > m->m_len)
        !           398:                        panic("m_copym0 overrun");
        !           399: #endif
        !           400:                if (off == m->m_len) {
        !           401:                        m = m->m_next;
        !           402:                        off = 0;
        !           403:                }
        !           404:                np = &n->m_next;
        !           405:        }
        !           406:        if (top == NULL)
        !           407:                MCFail++;
        !           408:        return (top);
        !           409: nospace:
        !           410:        m_freem(top);
        !           411:        MCFail++;
        !           412:        return (NULL);
        !           413: }
        !           414:
        !           415: /*
        !           416:  * Copy data from an mbuf chain starting "off" bytes from the beginning,
        !           417:  * continuing for "len" bytes, into the indicated buffer.
        !           418:  */
        !           419: void
        !           420: m_copydata(struct mbuf *m, int off, int len, caddr_t cp)
        !           421: {
        !           422:        unsigned count;
        !           423:
        !           424:        if (off < 0)
        !           425:                panic("m_copydata: off %d < 0", off);
        !           426:        if (len < 0)
        !           427:                panic("m_copydata: len %d < 0", len);
        !           428:        while (off > 0) {
        !           429:                if (m == NULL)
        !           430:                        panic("m_copydata: null mbuf in skip");
        !           431:                if (off < m->m_len)
        !           432:                        break;
        !           433:                off -= m->m_len;
        !           434:                m = m->m_next;
        !           435:        }
        !           436:        while (len > 0) {
        !           437:                if (m == NULL)
        !           438:                        panic("m_copydata: null mbuf");
        !           439:                count = min(m->m_len - off, len);
        !           440:                bcopy(mtod(m, caddr_t) + off, cp, count);
        !           441:                len -= count;
        !           442:                cp += count;
        !           443:                off = 0;
        !           444:                m = m->m_next;
        !           445:        }
        !           446: }
        !           447:
        !           448: /*
        !           449:  * Copy data from a buffer back into the indicated mbuf chain,
        !           450:  * starting "off" bytes from the beginning, extending the mbuf
        !           451:  * chain if necessary. The mbuf needs to be properly initialized
        !           452:  * including the setting of m_len.
        !           453:  */
        !           454: void
        !           455: m_copyback(struct mbuf *m0, int off, int len, const void *_cp)
        !           456: {
        !           457:        int mlen;
        !           458:        struct mbuf *m = m0, *n;
        !           459:        int totlen = 0;
        !           460:        caddr_t cp = (caddr_t)_cp;
        !           461:
        !           462:        if (m0 == NULL)
        !           463:                return;
        !           464:        while (off > (mlen = m->m_len)) {
        !           465:                off -= mlen;
        !           466:                totlen += mlen;
        !           467:                if (m->m_next == NULL) {
        !           468:                        n = m_getclr(M_DONTWAIT, m->m_type);
        !           469:                        if (n == NULL)
        !           470:                                goto out;
        !           471:                        n->m_len = min(MLEN, len + off);
        !           472:                        m->m_next = n;
        !           473:                }
        !           474:                m = m->m_next;
        !           475:        }
        !           476:        while (len > 0) {
        !           477:                mlen = min (m->m_len - off, len);
        !           478:                bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
        !           479:                cp += mlen;
        !           480:                len -= mlen;
        !           481:                mlen += off;
        !           482:                off = 0;
        !           483:                totlen += mlen;
        !           484:                if (len == 0)
        !           485:                        break;
        !           486:                if (m->m_next == NULL) {
        !           487:                        n = m_get(M_DONTWAIT, m->m_type);
        !           488:                        if (n == NULL)
        !           489:                                break;
        !           490:                        n->m_len = min(MLEN, len);
        !           491:                        m->m_next = n;
        !           492:                }
        !           493:                m = m->m_next;
        !           494:        }
        !           495: out:   if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
        !           496:                m->m_pkthdr.len = totlen;
        !           497: }
        !           498:
        !           499: /*
        !           500:  * Concatenate mbuf chain n to m.
        !           501:  * n might be copied into m (when n->m_len is small), therefore data portion of
        !           502:  * n could be copied into an mbuf of different mbuf type.
        !           503:  * Therefore both chains should be of the same type (e.g. MT_DATA).
        !           504:  * Any m_pkthdr is not updated.
        !           505:  */
        !           506: void
        !           507: m_cat(struct mbuf *m, struct mbuf *n)
        !           508: {
        !           509:        while (m->m_next)
        !           510:                m = m->m_next;
        !           511:        while (n) {
        !           512:                if (M_READONLY(m) || n->m_len > M_TRAILINGSPACE(m)) {
        !           513:                        /* just join the two chains */
        !           514:                        m->m_next = n;
        !           515:                        return;
        !           516:                }
        !           517:                /* splat the data from one into the other */
        !           518:                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
        !           519:                    (u_int)n->m_len);
        !           520:                m->m_len += n->m_len;
        !           521:                n = m_free(n);
        !           522:        }
        !           523: }
        !           524:
        !           525: void
        !           526: m_adj(struct mbuf *mp, int req_len)
        !           527: {
        !           528:        int len = req_len;
        !           529:        struct mbuf *m;
        !           530:        int count;
        !           531:
        !           532:        if ((m = mp) == NULL)
        !           533:                return;
        !           534:        if (len >= 0) {
        !           535:                /*
        !           536:                 * Trim from head.
        !           537:                 */
        !           538:                while (m != NULL && len > 0) {
        !           539:                        if (m->m_len <= len) {
        !           540:                                len -= m->m_len;
        !           541:                                m->m_len = 0;
        !           542:                                m = m->m_next;
        !           543:                        } else {
        !           544:                                m->m_len -= len;
        !           545:                                m->m_data += len;
        !           546:                                len = 0;
        !           547:                        }
        !           548:                }
        !           549:                m = mp;
        !           550:                if (mp->m_flags & M_PKTHDR)
        !           551:                        m->m_pkthdr.len -= (req_len - len);
        !           552:        } else {
        !           553:                /*
        !           554:                 * Trim from tail.  Scan the mbuf chain,
        !           555:                 * calculating its length and finding the last mbuf.
        !           556:                 * If the adjustment only affects this mbuf, then just
        !           557:                 * adjust and return.  Otherwise, rescan and truncate
        !           558:                 * after the remaining size.
        !           559:                 */
        !           560:                len = -len;
        !           561:                count = 0;
        !           562:                for (;;) {
        !           563:                        count += m->m_len;
        !           564:                        if (m->m_next == NULL)
        !           565:                                break;
        !           566:                        m = m->m_next;
        !           567:                }
        !           568:                if (m->m_len >= len) {
        !           569:                        m->m_len -= len;
        !           570:                        if (mp->m_flags & M_PKTHDR)
        !           571:                                mp->m_pkthdr.len -= len;
        !           572:                        return;
        !           573:                }
        !           574:                count -= len;
        !           575:                if (count < 0)
        !           576:                        count = 0;
        !           577:                /*
        !           578:                 * Correct length for chain is "count".
        !           579:                 * Find the mbuf with last data, adjust its length,
        !           580:                 * and toss data from remaining mbufs on chain.
        !           581:                 */
        !           582:                m = mp;
        !           583:                if (m->m_flags & M_PKTHDR)
        !           584:                        m->m_pkthdr.len = count;
        !           585:                for (; m; m = m->m_next) {
        !           586:                        if (m->m_len >= count) {
        !           587:                                m->m_len = count;
        !           588:                                break;
        !           589:                        }
        !           590:                        count -= m->m_len;
        !           591:                }
        !           592:                while ((m = m->m_next) != NULL)
        !           593:                        m->m_len = 0;
        !           594:        }
        !           595: }
        !           596:
        !           597: /*
        !           598:  * Rearange an mbuf chain so that len bytes are contiguous
        !           599:  * and in the data area of an mbuf (so that mtod and dtom
        !           600:  * will work for a structure of size len).  Returns the resulting
        !           601:  * mbuf chain on success, frees it and returns null on failure.
        !           602:  * If there is room, it will add up to max_protohdr-len extra bytes to the
        !           603:  * contiguous region in an attempt to avoid being called next time.
        !           604:  */
        !           605: int MPFail;
        !           606:
        !           607: struct mbuf *
        !           608: m_pullup(struct mbuf *n, int len)
        !           609: {
        !           610:        struct mbuf *m;
        !           611:        int count;
        !           612:        int space;
        !           613:
        !           614:        /*
        !           615:         * If first mbuf has no cluster, and has room for len bytes
        !           616:         * without shifting current data, pullup into it,
        !           617:         * otherwise allocate a new mbuf to prepend to the chain.
        !           618:         */
        !           619:        if ((n->m_flags & M_EXT) == 0 &&
        !           620:            n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
        !           621:                if (n->m_len >= len)
        !           622:                        return (n);
        !           623:                m = n;
        !           624:                n = n->m_next;
        !           625:                len -= m->m_len;
        !           626:        } else {
        !           627:                if (len > MHLEN)
        !           628:                        goto bad;
        !           629:                MGET(m, M_DONTWAIT, n->m_type);
        !           630:                if (m == NULL)
        !           631:                        goto bad;
        !           632:                m->m_len = 0;
        !           633:                if (n->m_flags & M_PKTHDR)
        !           634:                        M_MOVE_PKTHDR(m, n);
        !           635:        }
        !           636:        space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
        !           637:        do {
        !           638:                count = min(min(max(len, max_protohdr), space), n->m_len);
        !           639:                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
        !           640:                    (unsigned)count);
        !           641:                len -= count;
        !           642:                m->m_len += count;
        !           643:                n->m_len -= count;
        !           644:                space -= count;
        !           645:                if (n->m_len)
        !           646:                        n->m_data += count;
        !           647:                else
        !           648:                        n = m_free(n);
        !           649:        } while (len > 0 && n);
        !           650:        if (len > 0) {
        !           651:                (void)m_free(m);
        !           652:                goto bad;
        !           653:        }
        !           654:        m->m_next = n;
        !           655:        return (m);
        !           656: bad:
        !           657:        m_freem(n);
        !           658:        MPFail++;
        !           659:        return (NULL);
        !           660: }
        !           661:
        !           662: /*
        !           663:  * m_pullup2() works like m_pullup, save that len can be <= MCLBYTES.
        !           664:  * m_pullup2() only works on values of len such that MHLEN < len <= MCLBYTES,
        !           665:  * it calls m_pullup() for values <= MHLEN.  It also only coagulates the
        !           666:  * reqested number of bytes.  (For those of us who expect unwieldly option
        !           667:  * headers.
        !           668:  *
        !           669:  * KEBE SAYS:  Remember that dtom() calls with data in clusters does not work!
        !           670:  */
        !           671: struct mbuf *
        !           672: m_pullup2(struct mbuf *n, int len)
        !           673: {
        !           674:        struct mbuf *m;
        !           675:        int count;
        !           676:
        !           677:        if (len <= MHLEN)
        !           678:                return m_pullup(n, len);
        !           679:        if ((n->m_flags & M_EXT) != 0 &&
        !           680:            n->m_data + len < &n->m_data[MCLBYTES] && n->m_next) {
        !           681:                if (n->m_len >= len)
        !           682:                        return (n);
        !           683:                m = n;
        !           684:                n = n->m_next;
        !           685:                len -= m->m_len;
        !           686:        } else {
        !           687:                if (len > MCLBYTES)
        !           688:                        goto bad;
        !           689:                MGET(m, M_DONTWAIT, n->m_type);
        !           690:                if (m == NULL)
        !           691:                        goto bad;
        !           692:                MCLGET(m, M_DONTWAIT);
        !           693:                if ((m->m_flags & M_EXT) == 0)
        !           694:                        goto bad;
        !           695:                m->m_len = 0;
        !           696:                if (n->m_flags & M_PKTHDR) {
        !           697:                        /* Too many adverse side effects. */
        !           698:                        /* M_MOVE_PKTHDR(m, n); */
        !           699:                        m->m_flags = (n->m_flags & M_COPYFLAGS) |
        !           700:                            M_EXT | M_CLUSTER;
        !           701:                        M_MOVE_HDR(m, n);
        !           702:                        /* n->m_data is cool. */
        !           703:                }
        !           704:        }
        !           705:
        !           706:        do {
        !           707:                count = min(len, n->m_len);
        !           708:                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
        !           709:                    (unsigned)count);
        !           710:                len -= count;
        !           711:                m->m_len += count;
        !           712:                n->m_len -= count;
        !           713:                if (n->m_len)
        !           714:                        n->m_data += count;
        !           715:                else
        !           716:                        n = m_free(n);
        !           717:        } while (len > 0 && n);
        !           718:        if (len > 0) {
        !           719:                (void)m_free(m);
        !           720:                goto bad;
        !           721:        }
        !           722:        m->m_next = n;
        !           723:
        !           724:        return (m);
        !           725: bad:
        !           726:        m_freem(n);
        !           727:        MPFail++;
        !           728:        return (NULL);
        !           729: }
        !           730:
        !           731: /*
        !           732:  * Return a pointer to mbuf/offset of location in mbuf chain.
        !           733:  */
        !           734: struct mbuf *
        !           735: m_getptr(struct mbuf *m, int loc, int *off)
        !           736: {
        !           737:        while (loc >= 0) {
        !           738:                /* Normal end of search */
        !           739:                if (m->m_len > loc) {
        !           740:                        *off = loc;
        !           741:                        return (m);
        !           742:                }
        !           743:                else {
        !           744:                        loc -= m->m_len;
        !           745:
        !           746:                        if (m->m_next == NULL) {
        !           747:                                if (loc == 0) {
        !           748:                                        /* Point at the end of valid data */
        !           749:                                        *off = m->m_len;
        !           750:                                        return (m);
        !           751:                                }
        !           752:                                else
        !           753:                                        return (NULL);
        !           754:                        } else
        !           755:                                m = m->m_next;
        !           756:                }
        !           757:        }
        !           758:
        !           759:        return (NULL);
        !           760: }
        !           761:
        !           762: /*
        !           763:  * Inject a new mbuf chain of length siz in mbuf chain m0 at
        !           764:  * position len0. Returns a pointer to the first injected mbuf, or
        !           765:  * NULL on failure (m0 is left undisturbed). Note that if there is
        !           766:  * enough space for an object of size siz in the appropriate position,
        !           767:  * no memory will be allocated. Also, there will be no data movement in
        !           768:  * the first len0 bytes (pointers to that will remain valid).
        !           769:  *
        !           770:  * XXX It is assumed that siz is less than the size of an mbuf at the moment.
        !           771:  */
        !           772: struct mbuf *
        !           773: m_inject(struct mbuf *m0, int len0, int siz, int wait)
        !           774: {
        !           775:        struct mbuf *m, *n, *n2 = NULL, *n3;
        !           776:        unsigned len = len0, remain;
        !           777:
        !           778:        if ((siz >= MHLEN) || (len0 <= 0))
        !           779:                return (NULL);
        !           780:        for (m = m0; m && len > m->m_len; m = m->m_next)
        !           781:                len -= m->m_len;
        !           782:        if (m == NULL)
        !           783:                return (NULL);
        !           784:        remain = m->m_len - len;
        !           785:        if (remain == 0) {
        !           786:                if ((m->m_next) && (M_LEADINGSPACE(m->m_next) >= siz)) {
        !           787:                        m->m_next->m_len += siz;
        !           788:                        if (m0->m_flags & M_PKTHDR)
        !           789:                                m0->m_pkthdr.len += siz;
        !           790:                        m->m_next->m_data -= siz;
        !           791:                        return m->m_next;
        !           792:                }
        !           793:        } else {
        !           794:                n2 = m_copym2(m, len, remain, wait);
        !           795:                if (n2 == NULL)
        !           796:                        return (NULL);
        !           797:        }
        !           798:
        !           799:        MGET(n, wait, MT_DATA);
        !           800:        if (n == NULL) {
        !           801:                if (n2)
        !           802:                        m_freem(n2);
        !           803:                return (NULL);
        !           804:        }
        !           805:
        !           806:        n->m_len = siz;
        !           807:        if (m0->m_flags & M_PKTHDR)
        !           808:                m0->m_pkthdr.len += siz;
        !           809:        m->m_len -= remain; /* Trim */
        !           810:        if (n2) {
        !           811:                for (n3 = n; n3->m_next != NULL; n3 = n3->m_next)
        !           812:                        ;
        !           813:                n3->m_next = n2;
        !           814:        } else
        !           815:                n3 = n;
        !           816:        for (; n3->m_next != NULL; n3 = n3->m_next)
        !           817:                ;
        !           818:        n3->m_next = m->m_next;
        !           819:        m->m_next = n;
        !           820:        return n;
        !           821: }
        !           822:
        !           823: /*
        !           824:  * Partition an mbuf chain in two pieces, returning the tail --
        !           825:  * all but the first len0 bytes.  In case of failure, it returns NULL and
        !           826:  * attempts to restore the chain to its original state.
        !           827:  */
        !           828: struct mbuf *
        !           829: m_split(struct mbuf *m0, int len0, int wait)
        !           830: {
        !           831:        struct mbuf *m, *n;
        !           832:        unsigned len = len0, remain, olen;
        !           833:
        !           834:        for (m = m0; m && len > m->m_len; m = m->m_next)
        !           835:                len -= m->m_len;
        !           836:        if (m == NULL)
        !           837:                return (NULL);
        !           838:        remain = m->m_len - len;
        !           839:        if (m0->m_flags & M_PKTHDR) {
        !           840:                MGETHDR(n, wait, m0->m_type);
        !           841:                if (n == NULL)
        !           842:                        return (NULL);
        !           843:                M_DUP_PKTHDR(n, m0);
        !           844:                n->m_pkthdr.len -= len0;
        !           845:                olen = m0->m_pkthdr.len;
        !           846:                m0->m_pkthdr.len = len0;
        !           847:                if (m->m_flags & M_EXT)
        !           848:                        goto extpacket;
        !           849:                if (remain > MHLEN) {
        !           850:                        /* m can't be the lead packet */
        !           851:                        MH_ALIGN(n, 0);
        !           852:                        n->m_next = m_split(m, len, wait);
        !           853:                        if (n->m_next == NULL) {
        !           854:                                (void) m_free(n);
        !           855:                                m0->m_pkthdr.len = olen;
        !           856:                                return (NULL);
        !           857:                        } else
        !           858:                                return (n);
        !           859:                } else
        !           860:                        MH_ALIGN(n, remain);
        !           861:        } else if (remain == 0) {
        !           862:                n = m->m_next;
        !           863:                m->m_next = NULL;
        !           864:                return (n);
        !           865:        } else {
        !           866:                MGET(n, wait, m->m_type);
        !           867:                if (n == NULL)
        !           868:                        return (NULL);
        !           869:                M_ALIGN(n, remain);
        !           870:        }
        !           871: extpacket:
        !           872:        if (m->m_flags & M_EXT) {
        !           873:                n->m_ext = m->m_ext;
        !           874:                MCLADDREFERENCE(m, n);
        !           875:                n->m_data = m->m_data + len;
        !           876:        } else {
        !           877:                bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
        !           878:        }
        !           879:        n->m_len = remain;
        !           880:        m->m_len = len;
        !           881:        n->m_next = m->m_next;
        !           882:        m->m_next = NULL;
        !           883:        return (n);
        !           884: }
        !           885:
        !           886: /*
        !           887:  * Routine to copy from device local memory into mbufs.
        !           888:  */
        !           889: struct mbuf *
        !           890: m_devget(char *buf, int totlen, int off, struct ifnet *ifp,
        !           891:     void (*copy)(const void *, void *, size_t))
        !           892: {
        !           893:        struct mbuf *m;
        !           894:        struct mbuf *top = NULL, **mp = &top;
        !           895:        int len;
        !           896:        char *cp;
        !           897:        char *epkt;
        !           898:
        !           899:        cp = buf;
        !           900:        epkt = cp + totlen;
        !           901:        if (off) {
        !           902:                /*
        !           903:                 * If 'off' is non-zero, packet is trailer-encapsulated,
        !           904:                 * so we have to skip the type and length fields.
        !           905:                 */
        !           906:                cp += off + 2 * sizeof(u_int16_t);
        !           907:                totlen -= 2 * sizeof(u_int16_t);
        !           908:        }
        !           909:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           910:        if (m == NULL)
        !           911:                return (NULL);
        !           912:        m->m_pkthdr.rcvif = ifp;
        !           913:        m->m_pkthdr.len = totlen;
        !           914:        m->m_len = MHLEN;
        !           915:
        !           916:        while (totlen > 0) {
        !           917:                if (top != NULL) {
        !           918:                        MGET(m, M_DONTWAIT, MT_DATA);
        !           919:                        if (m == NULL) {
        !           920:                                m_freem(top);
        !           921:                                return (NULL);
        !           922:                        }
        !           923:                        m->m_len = MLEN;
        !           924:                }
        !           925:                len = min(totlen, epkt - cp);
        !           926:                if (len >= MINCLSIZE) {
        !           927:                        MCLGET(m, M_DONTWAIT);
        !           928:                        if (m->m_flags & M_EXT)
        !           929:                                m->m_len = len = min(len, MCLBYTES);
        !           930:                        else
        !           931:                                len = m->m_len;
        !           932:                } else {
        !           933:                        /*
        !           934:                         * Place initial small packet/header at end of mbuf.
        !           935:                         */
        !           936:                        if (len < m->m_len) {
        !           937:                                if (top == NULL &&
        !           938:                                    len + max_linkhdr <= m->m_len)
        !           939:                                        m->m_data += max_linkhdr;
        !           940:                                m->m_len = len;
        !           941:                        } else
        !           942:                                len = m->m_len;
        !           943:                }
        !           944:                if (copy)
        !           945:                        copy(cp, mtod(m, caddr_t), (size_t)len);
        !           946:                else
        !           947:                        bcopy(cp, mtod(m, caddr_t), (size_t)len);
        !           948:                cp += len;
        !           949:                *mp = m;
        !           950:                mp = &m->m_next;
        !           951:                totlen -= len;
        !           952:                if (cp == epkt)
        !           953:                        cp = buf;
        !           954:        }
        !           955:        return (top);
        !           956: }
        !           957:
        !           958: void
        !           959: m_zero(struct mbuf *m)
        !           960: {
        !           961:        while (m) {
        !           962: #ifdef DIAGNOSTIC
        !           963:                if (M_READONLY(m))
        !           964:                        panic("m_zero: M_READONLY");
        !           965: #endif /* DIAGNOSTIC */
        !           966:                if (m->m_flags & M_EXT)
        !           967:                        memset(m->m_ext.ext_buf, 0, m->m_ext.ext_size);
        !           968:                else {
        !           969:                        if (m->m_flags & M_PKTHDR)
        !           970:                                memset(m->m_pktdat, 0, MHLEN);
        !           971:                        else
        !           972:                                memset(m->m_dat, 0, MLEN);
        !           973:                }
        !           974:                m = m->m_next;
        !           975:        }
        !           976: }
        !           977:
        !           978: /*
        !           979:  * Apply function f to the data in an mbuf chain starting "off" bytes from the
        !           980:  * beginning, continuing for "len" bytes.
        !           981:  */
        !           982: int
        !           983: m_apply(struct mbuf *m, int off, int len,
        !           984:     int (*f)(caddr_t, caddr_t, unsigned int), caddr_t fstate)
        !           985: {
        !           986:        int rval;
        !           987:        unsigned int count;
        !           988:
        !           989:        if (len < 0)
        !           990:                panic("m_apply: len %d < 0", len);
        !           991:        if (off < 0)
        !           992:                panic("m_apply: off %d < 0", off);
        !           993:        while (off > 0) {
        !           994:                if (m == NULL)
        !           995:                        panic("m_apply: null mbuf in skip");
        !           996:                if (off < m->m_len)
        !           997:                        break;
        !           998:                off -= m->m_len;
        !           999:                m = m->m_next;
        !          1000:        }
        !          1001:        while (len > 0) {
        !          1002:                if (m == NULL)
        !          1003:                        panic("m_apply: null mbuf");
        !          1004:                count = min(m->m_len - off, len);
        !          1005:
        !          1006:                rval = f(fstate, mtod(m, caddr_t) + off, count);
        !          1007:                if (rval)
        !          1008:                        return (rval);
        !          1009:
        !          1010:                len -= count;
        !          1011:                off = 0;
        !          1012:                m = m->m_next;
        !          1013:        }
        !          1014:
        !          1015:        return (0);
        !          1016: }

CVSweb