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 /*      $OpenBSD: uipc_mbuf2.c,v 1.45 2020/12/12 11:48:54 jan 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/malloc.h>
   68 #include <sys/pool.h>
   69 #include <sys/mbuf.h>
   70 
   71 extern struct pool mtagpool;
   72 
   73 /* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
   74 static struct mbuf *m_dup1(struct mbuf *, int, int, int);
   75 
   76 /*
   77  * ensure that [off, off + len] is contiguous on the mbuf chain "m".
   78  * packet chain before "off" is kept untouched.
   79  * if offp == NULL, the target will start at <retval, 0> on resulting chain.
   80  * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
   81  *
   82  * on error return (NULL return value), original "m" will be freed.
   83  *
   84  * XXX m_trailingspace/m_leadingspace on shared cluster (sharedcluster)
   85  */
   86 struct mbuf *
   87 m_pulldown(struct mbuf *m, int off, int len, int *offp)
   88 {
   89         struct mbuf *n, *o;
   90         int hlen, tlen, olen;
   91         int sharedcluster;
   92 
   93         /* check invalid arguments. */
   94         if (m == NULL)
   95                 panic("m == NULL in m_pulldown()");
   96 
   97         if ((n = m_getptr(m, off, &off)) == NULL) {
   98                 m_freem(m);
   99                 return (NULL);  /* mbuf chain too short */
  100         }
  101 
  102         sharedcluster = M_READONLY(n);
  103 
  104         /*
  105          * the target data is on <n, off>.
  106          * if we got enough data on the mbuf "n", we're done.
  107          */
  108         if ((off == 0 || offp) && len <= n->m_len - off && !sharedcluster)
  109                 goto ok;
  110 
  111         /*
  112          * when len <= n->m_len - off and off != 0, it is a special case.
  113          * len bytes from <n, off> sits in single mbuf, but the caller does
  114          * not like the starting position (off).
  115          * chop the current mbuf into two pieces, set off to 0.
  116          */
  117         if (len <= n->m_len - off) {
  118                 struct mbuf *mlast;
  119 
  120                 o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
  121                 if (o == NULL) {
  122                         m_freem(m);
  123                         return (NULL);  /* ENOBUFS */
  124                 }
  125                 for (mlast = o; mlast->m_next != NULL; mlast = mlast->m_next)
  126                         ;
  127                 n->m_len = off;
  128                 mlast->m_next = n->m_next;
  129                 n->m_next = o;
  130                 n = o;
  131                 off = 0;
  132                 goto ok;
  133         }
  134 
  135         /*
  136          * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
  137          * and construct contiguous mbuf with m_len == len.
  138          * note that hlen + tlen == len, and tlen > 0.
  139          */
  140         hlen = n->m_len - off;
  141         tlen = len - hlen;
  142 
  143         /*
  144          * ensure that we have enough trailing data on mbuf chain.
  145          * if not, we can do nothing about the chain.
  146          */
  147         olen = 0;
  148         for (o = n->m_next; o != NULL; o = o->m_next)
  149                 olen += o->m_len;
  150         if (hlen + olen < len) {
  151                 m_freem(m);
  152                 return (NULL);  /* mbuf chain too short */
  153         }
  154 
  155         /*
  156          * easy cases first.
  157          * we need to use m_copydata() to get data from <n->m_next, 0>.
  158          */
  159         if ((off == 0 || offp) && m_trailingspace(n) >= tlen &&
  160             !sharedcluster) {
  161                 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
  162                 n->m_len += tlen;
  163                 m_adj(n->m_next, tlen);
  164                 goto ok;
  165         }
  166         if ((off == 0 || offp) && m_leadingspace(n->m_next) >= hlen &&
  167             !sharedcluster && n->m_next->m_len >= tlen) {
  168                 n->m_next->m_data -= hlen;
  169                 n->m_next->m_len += hlen;
  170                 memmove(mtod(n->m_next, caddr_t), mtod(n, caddr_t) + off, hlen);
  171                 n->m_len -= hlen;
  172                 n = n->m_next;
  173                 off = 0;
  174                 goto ok;
  175         }
  176 
  177         /*
  178          * now, we need to do the hard way.  don't m_copym as there's no room
  179          * on both ends.
  180          */
  181         if (len > MAXMCLBYTES) {
  182                 m_freem(m);
  183                 return (NULL);
  184         }
  185         MGET(o, M_DONTWAIT, m->m_type);
  186         if (o && len > MLEN) {
  187                 MCLGETL(o, M_DONTWAIT, len);
  188                 if ((o->m_flags & M_EXT) == 0) {
  189                         m_free(o);
  190                         o = NULL;
  191                 }
  192         }
  193         if (!o) {
  194                 m_freem(m);
  195                 return (NULL);  /* ENOBUFS */
  196         }
  197         /* get hlen from <n, off> into <o, 0> */
  198         o->m_len = hlen;
  199         memmove(mtod(o, caddr_t), mtod(n, caddr_t) + off, hlen);
  200         n->m_len -= hlen;
  201         /* get tlen from <n->m_next, 0> into <o, hlen> */
  202         m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
  203         o->m_len += tlen;
  204         m_adj(n->m_next, tlen);
  205         o->m_next = n->m_next;
  206         n->m_next = o;
  207         n = o;
  208         off = 0;
  209 
  210 ok:
  211         if (offp)
  212                 *offp = off;
  213         return (n);
  214 }
  215 
  216 static struct mbuf *
  217 m_dup1(struct mbuf *m, int off, int len, int wait)
  218 {
  219         struct mbuf *n;
  220         int l;
  221 
  222         if (len > MAXMCLBYTES)
  223                 return (NULL);
  224         if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
  225                 MGETHDR(n, wait, m->m_type);
  226                 if (n == NULL)
  227                         return (NULL);
  228                 if (m_dup_pkthdr(n, m, wait)) {
  229                         m_free(n);
  230                         return (NULL);
  231                 }
  232                 l = MHLEN;
  233         } else {
  234                 MGET(n, wait, m->m_type);
  235                 l = MLEN;
  236         }
  237         if (n && len > l) {
  238                 MCLGETL(n, wait, len);
  239                 if ((n->m_flags & M_EXT) == 0) {
  240                         m_free(n);
  241                         n = NULL;
  242                 }
  243         }
  244         if (!n)
  245                 return (NULL);
  246 
  247         m_copydata(m, off, len, mtod(n, caddr_t));
  248         n->m_len = len;
  249 
  250         return (n);
  251 }
  252 
  253 /* Get a packet tag structure along with specified data following. */
  254 struct m_tag *
  255 m_tag_get(int type, int len, int wait)
  256 {
  257         struct m_tag *t;
  258 
  259         if (len < 0)
  260                 return (NULL);
  261         if (len > PACKET_TAG_MAXSIZE)
  262                 panic("requested tag size for pool %#x is too big", type);
  263         t = pool_get(&mtagpool, wait == M_WAITOK ? PR_WAITOK : PR_NOWAIT);
  264         if (t == NULL)
  265                 return (NULL);
  266         t->m_tag_id = type;
  267         t->m_tag_len = len;
  268         return (t);
  269 }
  270 
  271 /* Prepend a packet tag. */
  272 void
  273 m_tag_prepend(struct mbuf *m, struct m_tag *t)
  274 {
  275         SLIST_INSERT_HEAD(&m->m_pkthdr.ph_tags, t, m_tag_link);
  276         m->m_pkthdr.ph_tagsset |= t->m_tag_id;
  277 }
  278 
  279 /* Unlink and free a packet tag. */
  280 void
  281 m_tag_delete(struct mbuf *m, struct m_tag *t)
  282 {
  283         u_int32_t        ph_tagsset = 0;
  284         struct m_tag    *p;
  285 
  286         SLIST_REMOVE(&m->m_pkthdr.ph_tags, t, m_tag, m_tag_link);
  287         pool_put(&mtagpool, t);
  288 
  289         SLIST_FOREACH(p, &m->m_pkthdr.ph_tags, m_tag_link)
  290                 ph_tagsset |= p->m_tag_id;
  291         m->m_pkthdr.ph_tagsset = ph_tagsset;
  292 
  293 }
  294 
  295 /* Unlink and free a packet tag chain. */
  296 void
  297 m_tag_delete_chain(struct mbuf *m)
  298 {
  299         struct m_tag *p;
  300 
  301         while ((p = SLIST_FIRST(&m->m_pkthdr.ph_tags)) != NULL) {
  302                 SLIST_REMOVE_HEAD(&m->m_pkthdr.ph_tags, m_tag_link);
  303                 pool_put(&mtagpool, p);
  304         }
  305         m->m_pkthdr.ph_tagsset = 0;
  306 }
  307 
  308 /* Find a tag, starting from a given position. */
  309 struct m_tag *
  310 m_tag_find(struct mbuf *m, int type, struct m_tag *t)
  311 {
  312         struct m_tag *p;
  313 
  314         if (!(m->m_pkthdr.ph_tagsset & type))
  315                 return (NULL);
  316 
  317         if (t == NULL)
  318                 p = SLIST_FIRST(&m->m_pkthdr.ph_tags);
  319         else
  320                 p = SLIST_NEXT(t, m_tag_link);
  321         while (p != NULL) {
  322                 if (p->m_tag_id == type)
  323                         return (p);
  324                 p = SLIST_NEXT(p, m_tag_link);
  325         }
  326         return (NULL);
  327 }
  328 
  329 /* Copy a single tag. */
  330 struct m_tag *
  331 m_tag_copy(struct m_tag *t, int wait)
  332 {
  333         struct m_tag *p;
  334 
  335         p = m_tag_get(t->m_tag_id, t->m_tag_len, wait);
  336         if (p == NULL)
  337                 return (NULL);
  338         memcpy(p + 1, t + 1, t->m_tag_len); /* Copy the data */
  339         return (p);
  340 }
  341 
  342 /*
  343  * Copy two tag chains. The destination mbuf (to) loses any attached
  344  * tags even if the operation fails. This should not be a problem, as
  345  * m_tag_copy_chain() is typically called with a newly-allocated
  346  * destination mbuf.
  347  */
  348 int
  349 m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int wait)
  350 {
  351         struct m_tag *p, *t, *tprev = NULL;
  352 
  353         m_tag_delete_chain(to);
  354         SLIST_FOREACH(p, &from->m_pkthdr.ph_tags, m_tag_link) {
  355                 t = m_tag_copy(p, wait);
  356                 if (t == NULL) {
  357                         m_tag_delete_chain(to);
  358                         return (ENOBUFS);
  359                 }
  360                 if (tprev == NULL)
  361                         SLIST_INSERT_HEAD(&to->m_pkthdr.ph_tags, t, m_tag_link);
  362                 else
  363                         SLIST_INSERT_AFTER(tprev, t, m_tag_link);
  364                 tprev = t;
  365                 to->m_pkthdr.ph_tagsset |= t->m_tag_id;
  366         }
  367         return (0);
  368 }
  369 
  370 /* Initialize tags on an mbuf. */
  371 void
  372 m_tag_init(struct mbuf *m)
  373 {
  374         SLIST_INIT(&m->m_pkthdr.ph_tags);
  375 }
  376 
  377 /* Get first tag in chain. */
  378 struct m_tag *
  379 m_tag_first(struct mbuf *m)
  380 {
  381         return (SLIST_FIRST(&m->m_pkthdr.ph_tags));
  382 }
  383 
  384 /* Get next tag in chain. */
  385 struct m_tag *
  386 m_tag_next(struct mbuf *m, struct m_tag *t)
  387 {
  388         return (SLIST_NEXT(t, m_tag_link));
  389 }

Cache object: 69701354968782cb3f4dd813e80a8b78


[ 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.