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 : }
|