qemu/slirp/src/mbuf.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause */
   2/*
   3 * Copyright (c) 1995 Danny Gasparovski
   4 */
   5
   6/*
   7 * mbuf's in SLiRP are much simpler than the real mbufs in
   8 * FreeBSD.  They are fixed size, determined by the MTU,
   9 * so that one whole packet can fit.  Mbuf's cannot be
  10 * chained together.  If there's more data than the mbuf
  11 * could hold, an external g_malloced buffer is pointed to
  12 * by m_ext (and the data pointers) and M_EXT is set in
  13 * the flags
  14 */
  15
  16#include "slirp.h"
  17
  18#define MBUF_THRESH 30
  19
  20/*
  21 * Find a nice value for msize
  22 */
  23#define SLIRP_MSIZE\
  24    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
  25
  26void
  27m_init(Slirp *slirp)
  28{
  29    slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist;
  30    slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist;
  31}
  32
  33void m_cleanup(Slirp *slirp)
  34{
  35    struct mbuf *m, *next;
  36
  37    m = (struct mbuf *) slirp->m_usedlist.qh_link;
  38    while ((struct quehead *) m != &slirp->m_usedlist) {
  39        next = m->m_next;
  40        if (m->m_flags & M_EXT) {
  41            g_free(m->m_ext);
  42        }
  43        g_free(m);
  44        m = next;
  45    }
  46    m = (struct mbuf *) slirp->m_freelist.qh_link;
  47    while ((struct quehead *) m != &slirp->m_freelist) {
  48        next = m->m_next;
  49        g_free(m);
  50        m = next;
  51    }
  52}
  53
  54/*
  55 * Get an mbuf from the free list, if there are none
  56 * allocate one
  57 *
  58 * Because fragmentation can occur if we alloc new mbufs and
  59 * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
  60 * which tells m_free to actually g_free() it
  61 */
  62struct mbuf *
  63m_get(Slirp *slirp)
  64{
  65        register struct mbuf *m;
  66        int flags = 0;
  67
  68        DEBUG_CALL("m_get");
  69
  70        if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
  71                m = g_malloc(SLIRP_MSIZE);
  72                slirp->mbuf_alloced++;
  73                if (slirp->mbuf_alloced > MBUF_THRESH)
  74                        flags = M_DOFREE;
  75                m->slirp = slirp;
  76        } else {
  77                m = (struct mbuf *) slirp->m_freelist.qh_link;
  78                remque(m);
  79        }
  80
  81        /* Insert it in the used list */
  82        insque(m,&slirp->m_usedlist);
  83        m->m_flags = (flags | M_USEDLIST);
  84
  85        /* Initialise it */
  86        m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
  87        m->m_data = m->m_dat;
  88        m->m_len = 0;
  89        m->m_nextpkt = NULL;
  90        m->m_prevpkt = NULL;
  91        m->resolution_requested = false;
  92        m->expiration_date = (uint64_t)-1;
  93        DEBUG_ARG("m = %p", m);
  94        return m;
  95}
  96
  97void
  98m_free(struct mbuf *m)
  99{
 100
 101  DEBUG_CALL("m_free");
 102  DEBUG_ARG("m = %p", m);
 103
 104  if(m) {
 105        /* Remove from m_usedlist */
 106        if (m->m_flags & M_USEDLIST)
 107           remque(m);
 108
 109        /* If it's M_EXT, free() it */
 110        if (m->m_flags & M_EXT) {
 111                g_free(m->m_ext);
 112        }
 113        /*
 114         * Either free() it or put it on the free list
 115         */
 116        if (m->m_flags & M_DOFREE) {
 117                m->slirp->mbuf_alloced--;
 118                g_free(m);
 119        } else if ((m->m_flags & M_FREELIST) == 0) {
 120                insque(m,&m->slirp->m_freelist);
 121                m->m_flags = M_FREELIST; /* Clobber other flags */
 122        }
 123  } /* if(m) */
 124}
 125
 126/*
 127 * Copy data from one mbuf to the end of
 128 * the other.. if result is too big for one mbuf, allocate
 129 * an M_EXT data segment
 130 */
 131void
 132m_cat(struct mbuf *m, struct mbuf *n)
 133{
 134        /*
 135         * If there's no room, realloc
 136         */
 137        if (M_FREEROOM(m) < n->m_len)
 138                m_inc(m, m->m_len + n->m_len);
 139
 140        memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
 141        m->m_len += n->m_len;
 142
 143        m_free(n);
 144}
 145
 146
 147/* make m 'size' bytes large from m_data */
 148void
 149m_inc(struct mbuf *m, int size)
 150{
 151    int gapsize;
 152
 153    /* some compilers throw up on gotos.  This one we can fake. */
 154    if (M_ROOM(m) > size) {
 155        return;
 156    }
 157
 158    if (m->m_flags & M_EXT) {
 159        gapsize = m->m_data - m->m_ext;
 160        m->m_ext = g_realloc(m->m_ext, size + gapsize);
 161    } else {
 162        gapsize = m->m_data - m->m_dat;
 163        m->m_ext = g_malloc(size + gapsize);
 164        memcpy(m->m_ext, m->m_dat, m->m_size);
 165        m->m_flags |= M_EXT;
 166    }
 167
 168    m->m_data = m->m_ext + gapsize;
 169    m->m_size = size + gapsize;
 170}
 171
 172
 173
 174void
 175m_adj(struct mbuf *m, int len)
 176{
 177        if (m == NULL)
 178                return;
 179        if (len >= 0) {
 180                /* Trim from head */
 181                m->m_data += len;
 182                m->m_len -= len;
 183        } else {
 184                /* Trim from tail */
 185                len = -len;
 186                m->m_len -= len;
 187        }
 188}
 189
 190
 191/*
 192 * Copy len bytes from m, starting off bytes into n
 193 */
 194int
 195m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
 196{
 197        if (len > M_FREEROOM(n))
 198                return -1;
 199
 200        memcpy((n->m_data + n->m_len), (m->m_data + off), len);
 201        n->m_len += len;
 202        return 0;
 203}
 204
 205
 206/*
 207 * Given a pointer into an mbuf, return the mbuf
 208 * XXX This is a kludge, I should eliminate the need for it
 209 * Fortunately, it's not used often
 210 */
 211struct mbuf *
 212dtom(Slirp *slirp, void *dat)
 213{
 214        struct mbuf *m;
 215
 216        DEBUG_CALL("dtom");
 217        DEBUG_ARG("dat = %p", dat);
 218
 219        /* bug corrected for M_EXT buffers */
 220        for (m = (struct mbuf *) slirp->m_usedlist.qh_link;
 221             (struct quehead *) m != &slirp->m_usedlist;
 222             m = m->m_next) {
 223          if (m->m_flags & M_EXT) {
 224            if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
 225              return m;
 226          } else {
 227            if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
 228              return m;
 229          }
 230        }
 231
 232        DEBUG_ERROR("dtom failed");
 233
 234        return (struct mbuf *)0;
 235}
 236