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