LCOV - code coverage report
Current view: top level - kern - uipc_mbuf2.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 155 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: uipc_mbuf2.c,v 1.42 2015/11/13 10:12:39 mpi 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           0 : 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           0 :         if (m == NULL)
      95           0 :                 panic("m == NULL in m_pulldown()");
      96             : 
      97           0 :         if ((n = m_getptr(m, off, &off)) == NULL) {
      98           0 :                 m_freem(m);
      99           0 :                 return (NULL);  /* mbuf chain too short */
     100             :         }
     101             : 
     102           0 :         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           0 :         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           0 :         if (len <= n->m_len - off) {
     118             :                 struct mbuf *mlast;
     119             : 
     120           0 :                 o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
     121           0 :                 if (o == NULL) {
     122           0 :                         m_freem(m);
     123           0 :                         return (NULL);  /* ENOBUFS */
     124             :                 }
     125           0 :                 for (mlast = o; mlast->m_next != NULL; mlast = mlast->m_next)
     126             :                         ;
     127           0 :                 n->m_len = off;
     128           0 :                 mlast->m_next = n->m_next;
     129           0 :                 n->m_next = o;
     130             :                 n = o;
     131           0 :                 off = 0;
     132           0 :                 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           0 :         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           0 :         for (o = n->m_next; o != NULL; o = o->m_next)
     149           0 :                 olen += o->m_len;
     150           0 :         if (hlen + olen < len) {
     151           0 :                 m_freem(m);
     152           0 :                 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           0 :         if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen &&
     160             :             !sharedcluster) {
     161           0 :                 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
     162           0 :                 n->m_len += tlen;
     163           0 :                 m_adj(n->m_next, tlen);
     164           0 :                 goto ok;
     165             :         }
     166           0 :         if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen &&
     167           0 :             !sharedcluster && n->m_next->m_len >= tlen) {
     168           0 :                 n->m_next->m_data -= hlen;
     169           0 :                 n->m_next->m_len += hlen;
     170           0 :                 memmove(mtod(n->m_next, caddr_t), mtod(n, caddr_t) + off, hlen);
     171           0 :                 n->m_len -= hlen;
     172           0 :                 n = n->m_next;
     173           0 :                 off = 0;
     174           0 :                 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           0 :         if (len > MAXMCLBYTES) {
     182           0 :                 m_freem(m);
     183           0 :                 return (NULL);
     184             :         }
     185           0 :         MGET(o, M_DONTWAIT, m->m_type);
     186           0 :         if (o && len > MLEN) {
     187           0 :                 MCLGETI(o, M_DONTWAIT, NULL, len);
     188           0 :                 if ((o->m_flags & M_EXT) == 0) {
     189           0 :                         m_free(o);
     190             :                         o = NULL;
     191           0 :                 }
     192             :         }
     193           0 :         if (!o) {
     194           0 :                 m_freem(m);
     195           0 :                 return (NULL);  /* ENOBUFS */
     196             :         }
     197             :         /* get hlen from <n, off> into <o, 0> */
     198           0 :         o->m_len = hlen;
     199           0 :         memmove(mtod(o, caddr_t), mtod(n, caddr_t) + off, hlen);
     200           0 :         n->m_len -= hlen;
     201             :         /* get tlen from <n->m_next, 0> into <o, hlen> */
     202           0 :         m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
     203           0 :         o->m_len += tlen;
     204           0 :         m_adj(n->m_next, tlen);
     205           0 :         o->m_next = n->m_next;
     206           0 :         n->m_next = o;
     207             :         n = o;
     208           0 :         off = 0;
     209             : 
     210             : ok:
     211           0 :         if (offp)
     212           0 :                 *offp = off;
     213           0 :         return (n);
     214           0 : }
     215             : 
     216             : static struct mbuf *
     217           0 : m_dup1(struct mbuf *m, int off, int len, int wait)
     218             : {
     219             :         struct mbuf *n;
     220             :         int l;
     221             : 
     222           0 :         if (len > MAXMCLBYTES)
     223           0 :                 return (NULL);
     224           0 :         if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
     225           0 :                 MGETHDR(n, wait, m->m_type);
     226           0 :                 if (n == NULL)
     227           0 :                         return (NULL);
     228           0 :                 if (m_dup_pkthdr(n, m, wait)) {
     229           0 :                         m_free(n);
     230           0 :                         return (NULL);
     231             :                 }
     232             :                 l = MHLEN;
     233           0 :         } else {
     234           0 :                 MGET(n, wait, m->m_type);
     235             :                 l = MLEN;
     236             :         }
     237           0 :         if (n && len > l) {
     238           0 :                 MCLGETI(n, wait, NULL, len);
     239           0 :                 if ((n->m_flags & M_EXT) == 0) {
     240           0 :                         m_free(n);
     241             :                         n = NULL;
     242           0 :                 }
     243             :         }
     244           0 :         if (!n)
     245           0 :                 return (NULL);
     246             : 
     247           0 :         m_copydata(m, off, len, mtod(n, caddr_t));
     248           0 :         n->m_len = len;
     249             : 
     250           0 :         return (n);
     251           0 : }
     252             : 
     253             : /* Get a packet tag structure along with specified data following. */
     254             : struct m_tag *
     255           0 : m_tag_get(int type, int len, int wait)
     256             : {
     257             :         struct m_tag *t;
     258             : 
     259           0 :         if (len < 0)
     260           0 :                 return (NULL);
     261           0 :         if (len > PACKET_TAG_MAXSIZE)
     262           0 :                 panic("requested tag size for pool %#x is too big", type);
     263           0 :         t = pool_get(&mtagpool, wait == M_WAITOK ? PR_WAITOK : PR_NOWAIT);
     264           0 :         if (t == NULL)
     265           0 :                 return (NULL);
     266           0 :         t->m_tag_id = type;
     267           0 :         t->m_tag_len = len;
     268           0 :         return (t);
     269           0 : }
     270             : 
     271             : /* Prepend a packet tag. */
     272             : void
     273           0 : m_tag_prepend(struct mbuf *m, struct m_tag *t)
     274             : {
     275           0 :         SLIST_INSERT_HEAD(&m->m_pkthdr.ph_tags, t, m_tag_link);
     276           0 :         m->m_pkthdr.ph_tagsset |= t->m_tag_id;
     277           0 : }
     278             : 
     279             : /* Unlink and free a packet tag. */
     280             : void
     281           0 : 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           0 :         SLIST_REMOVE(&m->m_pkthdr.ph_tags, t, m_tag, m_tag_link);
     287           0 :         pool_put(&mtagpool, t);
     288             : 
     289           0 :         SLIST_FOREACH(p, &m->m_pkthdr.ph_tags, m_tag_link)
     290           0 :                 ph_tagsset |= p->m_tag_id;
     291           0 :         m->m_pkthdr.ph_tagsset = ph_tagsset;
     292             : 
     293           0 : }
     294             : 
     295             : /* Unlink and free a packet tag chain. */
     296             : void
     297           0 : m_tag_delete_chain(struct mbuf *m)
     298             : {
     299             :         struct m_tag *p;
     300             : 
     301           0 :         while ((p = SLIST_FIRST(&m->m_pkthdr.ph_tags)) != NULL) {
     302           0 :                 SLIST_REMOVE_HEAD(&m->m_pkthdr.ph_tags, m_tag_link);
     303           0 :                 pool_put(&mtagpool, p);
     304             :         }
     305           0 :         m->m_pkthdr.ph_tagsset = 0;
     306           0 : }
     307             : 
     308             : /* Find a tag, starting from a given position. */
     309             : struct m_tag *
     310           0 : m_tag_find(struct mbuf *m, int type, struct m_tag *t)
     311             : {
     312             :         struct m_tag *p;
     313             : 
     314           0 :         if (!(m->m_pkthdr.ph_tagsset & type))
     315           0 :                 return (NULL);
     316             : 
     317           0 :         if (t == NULL)
     318           0 :                 p = SLIST_FIRST(&m->m_pkthdr.ph_tags);
     319             :         else
     320           0 :                 p = SLIST_NEXT(t, m_tag_link);
     321           0 :         while (p != NULL) {
     322           0 :                 if (p->m_tag_id == type)
     323           0 :                         return (p);
     324           0 :                 p = SLIST_NEXT(p, m_tag_link);
     325             :         }
     326           0 :         return (NULL);
     327           0 : }
     328             : 
     329             : /* Copy a single tag. */
     330             : struct m_tag *
     331           0 : m_tag_copy(struct m_tag *t, int wait)
     332             : {
     333             :         struct m_tag *p;
     334             : 
     335           0 :         p = m_tag_get(t->m_tag_id, t->m_tag_len, wait);
     336           0 :         if (p == NULL)
     337           0 :                 return (NULL);
     338           0 :         memcpy(p + 1, t + 1, t->m_tag_len); /* Copy the data */
     339           0 :         return (p);
     340           0 : }
     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           0 : m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int wait)
     350             : {
     351             :         struct m_tag *p, *t, *tprev = NULL;
     352             : 
     353           0 :         m_tag_delete_chain(to);
     354           0 :         SLIST_FOREACH(p, &from->m_pkthdr.ph_tags, m_tag_link) {
     355           0 :                 t = m_tag_copy(p, wait);
     356           0 :                 if (t == NULL) {
     357           0 :                         m_tag_delete_chain(to);
     358           0 :                         return (ENOBUFS);
     359             :                 }
     360           0 :                 if (tprev == NULL)
     361           0 :                         SLIST_INSERT_HEAD(&to->m_pkthdr.ph_tags, t, m_tag_link);
     362             :                 else
     363           0 :                         SLIST_INSERT_AFTER(tprev, t, m_tag_link);
     364             :                 tprev = t;
     365           0 :                 to->m_pkthdr.ph_tagsset |= t->m_tag_id;
     366             :         }
     367           0 :         return (0);
     368           0 : }
     369             : 
     370             : /* Initialize tags on an mbuf. */
     371             : void
     372           0 : m_tag_init(struct mbuf *m)
     373             : {
     374           0 :         SLIST_INIT(&m->m_pkthdr.ph_tags);
     375           0 : }
     376             : 
     377             : /* Get first tag in chain. */
     378             : struct m_tag *
     379           0 : m_tag_first(struct mbuf *m)
     380             : {
     381           0 :         return (SLIST_FIRST(&m->m_pkthdr.ph_tags));
     382             : }
     383             : 
     384             : /* Get next tag in chain. */
     385             : struct m_tag *
     386           0 : m_tag_next(struct mbuf *m, struct m_tag *t)
     387             : {
     388           0 :         return (SLIST_NEXT(t, m_tag_link));
     389             : }

Generated by: LCOV version 1.13