The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/uipc_mbuf2.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: releng/5.1/sys/kern/uipc_mbuf2.c 113487 2003-04-14 20:39:06Z rwatson $        */
    2 /*      $KAME: uipc_mbuf2.c,v 1.31 2001/11/28 11:08:53 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. All advertising materials mentioning features or use of this software
   47  *    must display the following acknowledgement:
   48  *      This product includes software developed by the University of
   49  *      California, Berkeley and its contributors.
   50  * 4. Neither the name of the University nor the names of its contributors
   51  *    may be used to endorse or promote products derived from this software
   52  *    without specific prior written permission.
   53  *
   54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   64  * SUCH DAMAGE.
   65  *
   66  *      @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
   67  */
   68 
   69 /*#define PULLDOWN_DEBUG*/
   70 
   71 #include "opt_mac.h"
   72 
   73 #include <sys/param.h>
   74 #include <sys/systm.h>
   75 #include <sys/kernel.h>
   76 #include <sys/lock.h>
   77 #include <sys/mac.h>
   78 #include <sys/malloc.h>
   79 #include <sys/mbuf.h>
   80 #include <sys/mutex.h>
   81 
   82 MALLOC_DEFINE(M_PACKET_TAGS, "tag", "packet-attached information");
   83 
   84 /* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
   85 static struct mbuf *m_dup1(struct mbuf *, int, int, int);
   86 
   87 /*
   88  * ensure that [off, off + len) is contiguous on the mbuf chain "m".
   89  * packet chain before "off" is kept untouched.
   90  * if offp == NULL, the target will start at <retval, 0> on resulting chain.
   91  * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
   92  *
   93  * on error return (NULL return value), original "m" will be freed.
   94  *
   95  * XXX: M_TRAILINGSPACE/M_LEADINGSPACE only permitted on writable ext_buf.
   96  */
   97 struct mbuf *
   98 m_pulldown(struct mbuf *m, int off, int len, int *offp)
   99 {
  100         struct mbuf *n, *o;
  101         int hlen, tlen, olen;
  102         int writable;
  103 
  104         /* check invalid arguments. */
  105         if (m == NULL)
  106                 panic("m == NULL in m_pulldown()");
  107         if (len > MCLBYTES) {
  108                 m_freem(m);
  109                 return NULL;    /* impossible */
  110         }
  111 
  112 #ifdef PULLDOWN_DEBUG
  113     {
  114         struct mbuf *t;
  115         printf("before:");
  116         for (t = m; t; t = t->m_next)
  117                 printf(" %d", t->m_len);
  118         printf("\n");
  119     }
  120 #endif
  121         n = m;
  122         while (n != NULL && off > 0) {
  123                 if (n->m_len > off)
  124                         break;
  125                 off -= n->m_len;
  126                 n = n->m_next;
  127         }
  128         /* be sure to point non-empty mbuf */
  129         while (n != NULL && n->m_len == 0)
  130                 n = n->m_next;
  131         if (!n) {
  132                 m_freem(m);
  133                 return NULL;    /* mbuf chain too short */
  134         }
  135 
  136         /*
  137          * XXX: This code is flawed because it considers a "writable" mbuf
  138          *      data region to require all of the following:
  139          *        (i) mbuf _has_ to have M_EXT set; if it is just a regular
  140          *            mbuf, it is still not considered "writable."
  141          *        (ii) since mbuf has M_EXT, the ext_type _has_ to be
  142          *             EXT_CLUSTER. Anything else makes it non-writable.
  143          *        (iii) M_WRITABLE() must evaluate true.
  144          *      Ideally, the requirement should only be (iii).
  145          *
  146          * If we're writable, we're sure we're writable, because the ref. count
  147          * cannot increase from 1, as that would require posession of mbuf
  148          * n by someone else (which is impossible). However, if we're _not_
  149          * writable, we may eventually become writable )if the ref. count drops
  150          * to 1), but we'll fail to notice it unless we re-evaluate
  151          * M_WRITABLE(). For now, we only evaluate once at the beginning and
  152          * live with this.
  153          */
  154         /*
  155          * XXX: This is dumb. If we're just a regular mbuf with no M_EXT,
  156          *      then we're not "writable," according to this code.
  157          */
  158         writable = 0;
  159         if ((n->m_flags & M_EXT) == 0 ||
  160             (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n)))
  161                 writable = 1;
  162 
  163         /*
  164          * the target data is on <n, off>.
  165          * if we got enough data on the mbuf "n", we're done.
  166          */
  167         if ((off == 0 || offp) && len <= n->m_len - off && writable)
  168                 goto ok;
  169 
  170         /*
  171          * when len <= n->m_len - off and off != 0, it is a special case.
  172          * len bytes from <n, off> sits in single mbuf, but the caller does
  173          * not like the starting position (off).
  174          * chop the current mbuf into two pieces, set off to 0.
  175          */
  176         if (len <= n->m_len - off) {
  177                 o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
  178                 if (o == NULL) {
  179                         m_freem(m);
  180                         return NULL;    /* ENOBUFS */
  181                 }
  182                 n->m_len = off;
  183                 o->m_next = n->m_next;
  184                 n->m_next = o;
  185                 n = n->m_next;
  186                 off = 0;
  187                 goto ok;
  188         }
  189 
  190         /*
  191          * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
  192          * and construct contiguous mbuf with m_len == len.
  193          * note that hlen + tlen == len, and tlen > 0.
  194          */
  195         hlen = n->m_len - off;
  196         tlen = len - hlen;
  197 
  198         /*
  199          * ensure that we have enough trailing data on mbuf chain.
  200          * if not, we can do nothing about the chain.
  201          */
  202         olen = 0;
  203         for (o = n->m_next; o != NULL; o = o->m_next)
  204                 olen += o->m_len;
  205         if (hlen + olen < len) {
  206                 m_freem(m);
  207                 return NULL;    /* mbuf chain too short */
  208         }
  209 
  210         /*
  211          * easy cases first.
  212          * we need to use m_copydata() to get data from <n->m_next, 0>.
  213          */
  214         if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
  215          && writable) {
  216                 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
  217                 n->m_len += tlen;
  218                 m_adj(n->m_next, tlen);
  219                 goto ok;
  220         }
  221         if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
  222          && writable) {
  223                 n->m_next->m_data -= hlen;
  224                 n->m_next->m_len += hlen;
  225                 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
  226                 n->m_len -= hlen;
  227                 n = n->m_next;
  228                 off = 0;
  229                 goto ok;
  230         }
  231 
  232         /*
  233          * now, we need to do the hard way.  don't m_copy as there's no room
  234          * on both end.
  235          */
  236         MGET(o, M_DONTWAIT, m->m_type);
  237         if (o && len > MLEN) {
  238                 MCLGET(o, M_DONTWAIT);
  239                 if ((o->m_flags & M_EXT) == 0) {
  240                         m_free(o);
  241                         o = NULL;
  242                 }
  243         }
  244         if (!o) {
  245                 m_freem(m);
  246                 return NULL;    /* ENOBUFS */
  247         }
  248         /* get hlen from <n, off> into <o, 0> */
  249         o->m_len = hlen;
  250         bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
  251         n->m_len -= hlen;
  252         /* get tlen from <n->m_next, 0> into <o, hlen> */
  253         m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
  254         o->m_len += tlen;
  255         m_adj(n->m_next, tlen);
  256         o->m_next = n->m_next;
  257         n->m_next = o;
  258         n = o;
  259         off = 0;
  260 
  261 ok:
  262 #ifdef PULLDOWN_DEBUG
  263     {
  264         struct mbuf *t;
  265         printf("after:");
  266         for (t = m; t; t = t->m_next)
  267                 printf("%c%d", t == n ? '*' : ' ', t->m_len);
  268         printf(" (off=%d)\n", off);
  269     }
  270 #endif
  271         if (offp)
  272                 *offp = off;
  273         return n;
  274 }
  275 
  276 static struct mbuf *
  277 m_dup1(struct mbuf *m, int off, int len, int wait)
  278 {
  279         struct mbuf *n;
  280         int l;
  281         int copyhdr;
  282 
  283         if (len > MCLBYTES)
  284                 return NULL;
  285         if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
  286                 copyhdr = 1;
  287                 MGETHDR(n, wait, m->m_type);
  288                 l = MHLEN;
  289         } else {
  290                 copyhdr = 0;
  291                 MGET(n, wait, m->m_type);
  292                 l = MLEN;
  293         }
  294         if (n && len > l) {
  295                 MCLGET(n, wait);
  296                 if ((n->m_flags & M_EXT) == 0) {
  297                         m_free(n);
  298                         n = NULL;
  299                 }
  300         }
  301         if (!n)
  302                 return NULL;
  303 
  304         if (copyhdr && !m_dup_pkthdr(n, m, wait)) {
  305                 m_free(n);
  306                 return NULL;
  307         }
  308         m_copydata(m, off, len, mtod(n, caddr_t));
  309         return n;
  310 }
  311 
  312 /* Get a packet tag structure along with specified data following. */
  313 struct m_tag *
  314 m_tag_alloc(u_int32_t cookie, int type, int len, int wait)
  315 {
  316         struct m_tag *t;
  317 
  318         if (len < 0)
  319                 return NULL;
  320         t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
  321         if (t == NULL)
  322                 return NULL;
  323         t->m_tag_id = type;
  324         t->m_tag_len = len;
  325         t->m_tag_cookie = cookie;
  326         return t;
  327 }
  328 
  329 /* Free a packet tag. */
  330 void
  331 m_tag_free(struct m_tag *t)
  332 {
  333 #ifdef MAC
  334         if (t->m_tag_id == PACKET_TAG_MACLABEL)
  335                 mac_destroy_mbuf_tag(t);
  336 #endif
  337         free(t, M_PACKET_TAGS);
  338 }
  339 
  340 /* Prepend a packet tag. */
  341 void
  342 m_tag_prepend(struct mbuf *m, struct m_tag *t)
  343 {
  344         KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
  345         SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
  346 }
  347 
  348 /* Unlink a packet tag. */
  349 void
  350 m_tag_unlink(struct mbuf *m, struct m_tag *t)
  351 {
  352         KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
  353         SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
  354 }
  355 
  356 /* Unlink and free a packet tag. */
  357 void
  358 m_tag_delete(struct mbuf *m, struct m_tag *t)
  359 {
  360         KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
  361         m_tag_unlink(m, t);
  362         m_tag_free(t);
  363 }
  364 
  365 /* Unlink and free a packet tag chain, starting from given tag. */
  366 void
  367 m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
  368 {
  369         struct m_tag *p, *q;
  370 
  371         KASSERT(m, ("m_tag_delete_chain: null mbuf"));
  372         if (t != NULL)
  373                 p = t;
  374         else
  375                 p = SLIST_FIRST(&m->m_pkthdr.tags);
  376         if (p == NULL)
  377                 return;
  378         while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
  379                 m_tag_delete(m, q);
  380         m_tag_delete(m, p);
  381 }
  382 
  383 /* Find a tag, starting from a given position. */
  384 struct m_tag *
  385 m_tag_locate(struct mbuf *m, u_int32_t cookie, int type, struct m_tag *t)
  386 {
  387         struct m_tag *p;
  388 
  389         KASSERT(m, ("m_tag_locate: null mbuf"));
  390         if (t == NULL)
  391                 p = SLIST_FIRST(&m->m_pkthdr.tags);
  392         else
  393                 p = SLIST_NEXT(t, m_tag_link);
  394         while (p != NULL) {
  395                 if (p->m_tag_cookie == cookie && p->m_tag_id == type)
  396                         return p;
  397                 p = SLIST_NEXT(p, m_tag_link);
  398         }
  399         return NULL;
  400 }
  401 
  402 /* Copy a single tag. */
  403 struct m_tag *
  404 m_tag_copy(struct m_tag *t, int how)
  405 {
  406         struct m_tag *p;
  407 
  408         KASSERT(t, ("m_tag_copy: null tag"));
  409         p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how);
  410         if (p == NULL)
  411                 return (NULL);
  412 #ifdef MAC
  413         /*
  414          * XXXMAC: we should probably pass off the initialization, and
  415          * copying here?  can we hide that PACKET_TAG_MACLABEL is
  416          * special from the mbuf code?
  417          */
  418         if (t->m_tag_id == PACKET_TAG_MACLABEL) {
  419                 if (mac_init_mbuf_tag(p, how) != 0) {
  420                         m_tag_free(p);
  421                         return (NULL);
  422                 }
  423                 mac_copy_mbuf_tag(t, p);
  424         } else
  425 #endif
  426                 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
  427         return p;
  428 }
  429 
  430 /*
  431  * Copy two tag chains. The destination mbuf (to) loses any attached
  432  * tags even if the operation fails. This should not be a problem, as
  433  * m_tag_copy_chain() is typically called with a newly-allocated
  434  * destination mbuf.
  435  */
  436 int
  437 m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
  438 {
  439         struct m_tag *p, *t, *tprev = NULL;
  440 
  441         KASSERT(to && from,
  442                 ("m_tag_copy_chain: null argument, to %p from %p", to, from));
  443         m_tag_delete_chain(to, NULL);
  444         SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
  445                 t = m_tag_copy(p, how);
  446                 if (t == NULL) {
  447                         m_tag_delete_chain(to, NULL);
  448                         return 0;
  449                 }
  450                 if (tprev == NULL)
  451                         SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
  452                 else
  453                         SLIST_INSERT_AFTER(tprev, t, m_tag_link);
  454                 tprev = t;
  455         }
  456         return 1;
  457 }
  458 
  459 /* Initialize tags on an mbuf. */
  460 void
  461 m_tag_init(struct mbuf *m)
  462 {
  463         SLIST_INIT(&m->m_pkthdr.tags);
  464 }
  465 
  466 /* Get first tag in chain. */
  467 struct m_tag *
  468 m_tag_first(struct mbuf *m)
  469 {
  470         return SLIST_FIRST(&m->m_pkthdr.tags);
  471 }
  472 
  473 /* Get next tag in chain. */
  474 struct m_tag *
  475 m_tag_next(struct mbuf *m, struct m_tag *t)
  476 {
  477         return SLIST_NEXT(t, m_tag_link);
  478 }

Cache object: 18612d8a07263309ef19357334829456


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.