nbd: Permit simple error to NBD_CMD_BLOCK_STATUS
[qemu/ericb.git] / slirp / src / mbuf.c
blob800406ca9eaad4067f4b686cd29ece3e8bfa46a1
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * Copyright (c) 1995 Danny Gasparovski
4 */
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
16 #include "slirp.h"
18 #define MBUF_THRESH 30
21 * Find a nice value for msize
23 #define SLIRP_MSIZE\
24 (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
26 void
27 m_init(Slirp *slirp)
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;
33 void m_cleanup(Slirp *slirp)
35 struct mbuf *m, *next;
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);
43 g_free(m);
44 m = next;
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;
55 * Get an mbuf from the free list, if there are none
56 * allocate one
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
62 struct mbuf *
63 m_get(Slirp *slirp)
65 register struct mbuf *m;
66 int flags = 0;
68 DEBUG_CALL("m_get");
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);
81 /* Insert it in the used list */
82 insque(m,&slirp->m_usedlist);
83 m->m_flags = (flags | M_USEDLIST);
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;
97 void
98 m_free(struct mbuf *m)
101 DEBUG_CALL("m_free");
102 DEBUG_ARG("m = %p", m);
104 if(m) {
105 /* Remove from m_usedlist */
106 if (m->m_flags & M_USEDLIST)
107 remque(m);
109 /* If it's M_EXT, free() it */
110 if (m->m_flags & M_EXT) {
111 g_free(m->m_ext);
114 * Either free() it or put it on the free list
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 */
123 } /* if(m) */
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
131 void
132 m_cat(struct mbuf *m, struct mbuf *n)
135 * If there's no room, realloc
137 if (M_FREEROOM(m) < n->m_len)
138 m_inc(m, m->m_len + n->m_len);
140 memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
141 m->m_len += n->m_len;
143 m_free(n);
147 /* make m 'size' bytes large from m_data */
148 void
149 m_inc(struct mbuf *m, int size)
151 int gapsize;
153 /* some compilers throw up on gotos. This one we can fake. */
154 if (M_ROOM(m) > size) {
155 return;
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;
168 m->m_data = m->m_ext + gapsize;
169 m->m_size = size + gapsize;
174 void
175 m_adj(struct mbuf *m, int len)
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;
192 * Copy len bytes from m, starting off bytes into n
195 m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
197 if (len > M_FREEROOM(n))
198 return -1;
200 memcpy((n->m_data + n->m_len), (m->m_data + off), len);
201 n->m_len += len;
202 return 0;
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
211 struct mbuf *
212 dtom(Slirp *slirp, void *dat)
214 struct mbuf *m;
216 DEBUG_CALL("dtom");
217 DEBUG_ARG("dat = %p", dat);
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;
232 DEBUG_ERROR("dtom failed");
234 return (struct mbuf *)0;