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