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

Annotation of sys/kern/uipc_mbuf2.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: uipc_mbuf2.c,v 1.28 2007/03/17 09:26:35 art Exp $     */
                      2: /*     $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun Exp $     */
                      3: /*     $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $   */
                      4:
                      5: /*
                      6:  * Copyright (C) 1999 WIDE Project.
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. Neither the name of the project nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33:
                     34: /*
                     35:  * Copyright (c) 1982, 1986, 1988, 1991, 1993
                     36:  *     The Regents of the University of California.  All rights reserved.
                     37:  *
                     38:  * Redistribution and use in source and binary forms, with or without
                     39:  * modification, are permitted provided that the following conditions
                     40:  * are met:
                     41:  * 1. Redistributions of source code must retain the above copyright
                     42:  *    notice, this list of conditions and the following disclaimer.
                     43:  * 2. Redistributions in binary form must reproduce the above copyright
                     44:  *    notice, this list of conditions and the following disclaimer in the
                     45:  *    documentation and/or other materials provided with the distribution.
                     46:  * 3. Neither the name of the University nor the names of its contributors
                     47:  *    may be used to endorse or promote products derived from this software
                     48:  *    without specific prior written permission.
                     49:  *
                     50:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     51:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     52:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     53:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     54:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     55:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     56:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     57:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     58:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     59:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     60:  * SUCH DAMAGE.
                     61:  *
                     62:  *     @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
                     63:  */
                     64:
                     65: #include <sys/param.h>
                     66: #include <sys/systm.h>
                     67: #include <sys/proc.h>
                     68: #include <sys/malloc.h>
                     69: #include <sys/mbuf.h>
                     70:
                     71: /* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
                     72: static struct mbuf *m_dup1(struct mbuf *, int, int, int);
                     73:
                     74: /*
                     75:  * ensure that [off, off + len] is contiguous on the mbuf chain "m".
                     76:  * packet chain before "off" is kept untouched.
                     77:  * if offp == NULL, the target will start at <retval, 0> on resulting chain.
                     78:  * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
                     79:  *
                     80:  * on error return (NULL return value), original "m" will be freed.
                     81:  *
                     82:  * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
                     83:  */
                     84: struct mbuf *
                     85: m_pulldown(struct mbuf *m, int off, int len, int *offp)
                     86: {
                     87:        struct mbuf *n, *o;
                     88:        int hlen, tlen, olen;
                     89:        int sharedcluster;
                     90:
                     91:        /* check invalid arguments. */
                     92:        if (m == NULL)
                     93:                panic("m == NULL in m_pulldown()");
                     94:        if (len > MCLBYTES) {
                     95:                m_freem(m);
                     96:                return (NULL);  /* impossible */
                     97:        }
                     98:
                     99:        n = m;
                    100:        while (n != NULL && off > 0) {
                    101:                if (n->m_len > off)
                    102:                        break;
                    103:                off -= n->m_len;
                    104:                n = n->m_next;
                    105:        }
                    106:        /* be sure to point non-empty mbuf */
                    107:        while (n != NULL && n->m_len == 0)
                    108:                n = n->m_next;
                    109:        if (!n) {
                    110:                m_freem(m);
                    111:                return (NULL);  /* mbuf chain too short */
                    112:        }
                    113:
                    114:        sharedcluster = M_READONLY(n);
                    115:
                    116:        /*
                    117:         * the target data is on <n, off>.
                    118:         * if we got enough data on the mbuf "n", we're done.
                    119:         */
                    120:        if ((off == 0 || offp) && len <= n->m_len - off && !sharedcluster)
                    121:                goto ok;
                    122:
                    123:        /*
                    124:         * when len <= n->m_len - off and off != 0, it is a special case.
                    125:         * len bytes from <n, off> sits in single mbuf, but the caller does
                    126:         * not like the starting position (off).
                    127:         * chop the current mbuf into two pieces, set off to 0.
                    128:         */
                    129:        if (len <= n->m_len - off) {
                    130:                struct mbuf *mlast;
                    131:
                    132:                o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
                    133:                if (o == NULL) {
                    134:                        m_freem(m);
                    135:                        return (NULL);  /* ENOBUFS */
                    136:                }
                    137:                for (mlast = o; mlast->m_next != NULL; mlast = mlast->m_next)
                    138:                        ;
                    139:                n->m_len = off;
                    140:                mlast->m_next = n->m_next;
                    141:                n->m_next = o;
                    142:                n = o;
                    143:                off = 0;
                    144:                goto ok;
                    145:        }
                    146:
                    147:        /*
                    148:         * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
                    149:         * and construct contiguous mbuf with m_len == len.
                    150:         * note that hlen + tlen == len, and tlen > 0.
                    151:         */
                    152:        hlen = n->m_len - off;
                    153:        tlen = len - hlen;
                    154:
                    155:        /*
                    156:         * ensure that we have enough trailing data on mbuf chain.
                    157:         * if not, we can do nothing about the chain.
                    158:         */
                    159:        olen = 0;
                    160:        for (o = n->m_next; o != NULL; o = o->m_next)
                    161:                olen += o->m_len;
                    162:        if (hlen + olen < len) {
                    163:                m_freem(m);
                    164:                return (NULL);  /* mbuf chain too short */
                    165:        }
                    166:
                    167:        /*
                    168:         * easy cases first.
                    169:         * we need to use m_copydata() to get data from <n->m_next, 0>.
                    170:         */
                    171:        if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen &&
                    172:            !sharedcluster) {
                    173:                m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
                    174:                n->m_len += tlen;
                    175:                m_adj(n->m_next, tlen);
                    176:                goto ok;
                    177:        }
                    178:        if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen &&
                    179:            !sharedcluster && n->m_next->m_len >= tlen) {
                    180:                n->m_next->m_data -= hlen;
                    181:                n->m_next->m_len += hlen;
                    182:                bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
                    183:                n->m_len -= hlen;
                    184:                n = n->m_next;
                    185:                off = 0;
                    186:                goto ok;
                    187:        }
                    188:
                    189:        /*
                    190:         * now, we need to do the hard way.  don't m_copy as there's no room
                    191:         * on both ends.
                    192:         */
                    193:        MGET(o, M_DONTWAIT, m->m_type);
                    194:        if (o && len > MLEN) {
                    195:                MCLGET(o, M_DONTWAIT);
                    196:                if ((o->m_flags & M_EXT) == 0) {
                    197:                        m_free(o);
                    198:                        o = NULL;
                    199:                }
                    200:        }
                    201:        if (!o) {
                    202:                m_freem(m);
                    203:                return (NULL);  /* ENOBUFS */
                    204:        }
                    205:        /* get hlen from <n, off> into <o, 0> */
                    206:        o->m_len = hlen;
                    207:        bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
                    208:        n->m_len -= hlen;
                    209:        /* get tlen from <n->m_next, 0> into <o, hlen> */
                    210:        m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
                    211:        o->m_len += tlen;
                    212:        m_adj(n->m_next, tlen);
                    213:        o->m_next = n->m_next;
                    214:        n->m_next = o;
                    215:        n = o;
                    216:        off = 0;
                    217:
                    218: ok:
                    219:        if (offp)
                    220:                *offp = off;
                    221:        return (n);
                    222: }
                    223:
                    224: static struct mbuf *
                    225: m_dup1(struct mbuf *m, int off, int len, int wait)
                    226: {
                    227:        struct mbuf *n;
                    228:        int l;
                    229:
                    230:        if (len > MCLBYTES)
                    231:                return (NULL);
                    232:        if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
                    233:                MGETHDR(n, wait, m->m_type);
                    234:                if (n == NULL)
                    235:                        return (NULL);
                    236:                M_DUP_PKTHDR(n, m);
                    237:                l = MHLEN;
                    238:        } else {
                    239:                MGET(n, wait, m->m_type);
                    240:                l = MLEN;
                    241:        }
                    242:        if (n && len > l) {
                    243:                MCLGET(n, wait);
                    244:                if ((n->m_flags & M_EXT) == 0) {
                    245:                        m_free(n);
                    246:                        n = NULL;
                    247:                }
                    248:        }
                    249:        if (!n)
                    250:                return (NULL);
                    251:
                    252:        m_copydata(m, off, len, mtod(n, caddr_t));
                    253:        n->m_len = len;
                    254:
                    255:        return (n);
                    256: }
                    257:
                    258: /* Get a packet tag structure along with specified data following. */
                    259: struct m_tag *
                    260: m_tag_get(int type, int len, int wait)
                    261: {
                    262:        struct m_tag *t;
                    263:
                    264:        if (len < 0)
                    265:                return (NULL);
                    266:        t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
                    267:        if (t == NULL)
                    268:                return (NULL);
                    269:        t->m_tag_id = type;
                    270:        t->m_tag_len = len;
                    271:        return (t);
                    272: }
                    273:
                    274: /* Prepend a packet tag. */
                    275: void
                    276: m_tag_prepend(struct mbuf *m, struct m_tag *t)
                    277: {
                    278:        SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
                    279: }
                    280:
                    281: /* Unlink and free a packet tag. */
                    282: void
                    283: m_tag_delete(struct mbuf *m, struct m_tag *t)
                    284: {
                    285:        SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
                    286:        free(t, M_PACKET_TAGS);
                    287: }
                    288:
                    289: /* Unlink and free a packet tag chain. */
                    290: void
                    291: m_tag_delete_chain(struct mbuf *m)
                    292: {
                    293:        struct m_tag *p;
                    294:
                    295:        while ((p = SLIST_FIRST(&m->m_pkthdr.tags)) != NULL) {
                    296:                SLIST_REMOVE_HEAD(&m->m_pkthdr.tags, m_tag_link);
                    297:                free(p, M_PACKET_TAGS);
                    298:        }
                    299: }
                    300:
                    301: /* Find a tag, starting from a given position. */
                    302: struct m_tag *
                    303: m_tag_find(struct mbuf *m, int type, struct m_tag *t)
                    304: {
                    305:        struct m_tag *p;
                    306:
                    307:        if (t == NULL)
                    308:                p = SLIST_FIRST(&m->m_pkthdr.tags);
                    309:        else
                    310:                p = SLIST_NEXT(t, m_tag_link);
                    311:        while (p != NULL) {
                    312:                if (p->m_tag_id == type)
                    313:                        return (p);
                    314:                p = SLIST_NEXT(p, m_tag_link);
                    315:        }
                    316:        return (NULL);
                    317: }
                    318:
                    319: /* Copy a single tag. */
                    320: struct m_tag *
                    321: m_tag_copy(struct m_tag *t)
                    322: {
                    323:        struct m_tag *p;
                    324:
                    325:        p = m_tag_get(t->m_tag_id, t->m_tag_len, M_NOWAIT);
                    326:        if (p == NULL)
                    327:                return (NULL);
                    328:        bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
                    329:        return (p);
                    330: }
                    331:
                    332: /*
                    333:  * Copy two tag chains. The destination mbuf (to) loses any attached
                    334:  * tags even if the operation fails. This should not be a problem, as
                    335:  * m_tag_copy_chain() is typically called with a newly-allocated
                    336:  * destination mbuf.
                    337:  */
                    338: int
                    339: m_tag_copy_chain(struct mbuf *to, struct mbuf *from)
                    340: {
                    341:        struct m_tag *p, *t, *tprev = NULL;
                    342:
                    343:        m_tag_delete_chain(to);
                    344:        SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
                    345:                t = m_tag_copy(p);
                    346:                if (t == NULL) {
                    347:                        m_tag_delete_chain(to);
                    348:                        return (0);
                    349:                }
                    350:                if (tprev == NULL)
                    351:                        SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
                    352:                else
                    353:                        SLIST_INSERT_AFTER(tprev, t, m_tag_link);
                    354:                tprev = t;
                    355:        }
                    356:        return (1);
                    357: }
                    358:
                    359: /* Initialize tags on an mbuf. */
                    360: void
                    361: m_tag_init(struct mbuf *m)
                    362: {
                    363:        SLIST_INIT(&m->m_pkthdr.tags);
                    364: }
                    365:
                    366: /* Get first tag in chain. */
                    367: struct m_tag *
                    368: m_tag_first(struct mbuf *m)
                    369: {
                    370:        return (SLIST_FIRST(&m->m_pkthdr.tags));
                    371: }
                    372:
                    373: /* Get next tag in chain. */
                    374: struct m_tag *
                    375: m_tag_next(struct mbuf *m, struct m_tag *t)
                    376: {
                    377:        return (SLIST_NEXT(t, m_tag_link));
                    378: }

CVSweb