FreeBSD/Linux Kernel Cross Reference
sys/kern/uipc_mbuf2.c
1 /* $FreeBSD: releng/5.1/sys/kern/uipc_mbuf2.c 113487 2003-04-14 20:39:06Z rwatson $ */
2 /* $KAME: uipc_mbuf2.c,v 1.31 2001/11/28 11:08:53 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. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
67 */
68
69 /*#define PULLDOWN_DEBUG*/
70
71 #include "opt_mac.h"
72
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/kernel.h>
76 #include <sys/lock.h>
77 #include <sys/mac.h>
78 #include <sys/malloc.h>
79 #include <sys/mbuf.h>
80 #include <sys/mutex.h>
81
82 MALLOC_DEFINE(M_PACKET_TAGS, "tag", "packet-attached information");
83
84 /* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
85 static struct mbuf *m_dup1(struct mbuf *, int, int, int);
86
87 /*
88 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
89 * packet chain before "off" is kept untouched.
90 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
91 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
92 *
93 * on error return (NULL return value), original "m" will be freed.
94 *
95 * XXX: M_TRAILINGSPACE/M_LEADINGSPACE only permitted on writable ext_buf.
96 */
97 struct mbuf *
98 m_pulldown(struct mbuf *m, int off, int len, int *offp)
99 {
100 struct mbuf *n, *o;
101 int hlen, tlen, olen;
102 int writable;
103
104 /* check invalid arguments. */
105 if (m == NULL)
106 panic("m == NULL in m_pulldown()");
107 if (len > MCLBYTES) {
108 m_freem(m);
109 return NULL; /* impossible */
110 }
111
112 #ifdef PULLDOWN_DEBUG
113 {
114 struct mbuf *t;
115 printf("before:");
116 for (t = m; t; t = t->m_next)
117 printf(" %d", t->m_len);
118 printf("\n");
119 }
120 #endif
121 n = m;
122 while (n != NULL && off > 0) {
123 if (n->m_len > off)
124 break;
125 off -= n->m_len;
126 n = n->m_next;
127 }
128 /* be sure to point non-empty mbuf */
129 while (n != NULL && n->m_len == 0)
130 n = n->m_next;
131 if (!n) {
132 m_freem(m);
133 return NULL; /* mbuf chain too short */
134 }
135
136 /*
137 * XXX: This code is flawed because it considers a "writable" mbuf
138 * data region to require all of the following:
139 * (i) mbuf _has_ to have M_EXT set; if it is just a regular
140 * mbuf, it is still not considered "writable."
141 * (ii) since mbuf has M_EXT, the ext_type _has_ to be
142 * EXT_CLUSTER. Anything else makes it non-writable.
143 * (iii) M_WRITABLE() must evaluate true.
144 * Ideally, the requirement should only be (iii).
145 *
146 * If we're writable, we're sure we're writable, because the ref. count
147 * cannot increase from 1, as that would require posession of mbuf
148 * n by someone else (which is impossible). However, if we're _not_
149 * writable, we may eventually become writable )if the ref. count drops
150 * to 1), but we'll fail to notice it unless we re-evaluate
151 * M_WRITABLE(). For now, we only evaluate once at the beginning and
152 * live with this.
153 */
154 /*
155 * XXX: This is dumb. If we're just a regular mbuf with no M_EXT,
156 * then we're not "writable," according to this code.
157 */
158 writable = 0;
159 if ((n->m_flags & M_EXT) == 0 ||
160 (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n)))
161 writable = 1;
162
163 /*
164 * the target data is on <n, off>.
165 * if we got enough data on the mbuf "n", we're done.
166 */
167 if ((off == 0 || offp) && len <= n->m_len - off && writable)
168 goto ok;
169
170 /*
171 * when len <= n->m_len - off and off != 0, it is a special case.
172 * len bytes from <n, off> sits in single mbuf, but the caller does
173 * not like the starting position (off).
174 * chop the current mbuf into two pieces, set off to 0.
175 */
176 if (len <= n->m_len - off) {
177 o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
178 if (o == NULL) {
179 m_freem(m);
180 return NULL; /* ENOBUFS */
181 }
182 n->m_len = off;
183 o->m_next = n->m_next;
184 n->m_next = o;
185 n = n->m_next;
186 off = 0;
187 goto ok;
188 }
189
190 /*
191 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
192 * and construct contiguous mbuf with m_len == len.
193 * note that hlen + tlen == len, and tlen > 0.
194 */
195 hlen = n->m_len - off;
196 tlen = len - hlen;
197
198 /*
199 * ensure that we have enough trailing data on mbuf chain.
200 * if not, we can do nothing about the chain.
201 */
202 olen = 0;
203 for (o = n->m_next; o != NULL; o = o->m_next)
204 olen += o->m_len;
205 if (hlen + olen < len) {
206 m_freem(m);
207 return NULL; /* mbuf chain too short */
208 }
209
210 /*
211 * easy cases first.
212 * we need to use m_copydata() to get data from <n->m_next, 0>.
213 */
214 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
215 && writable) {
216 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
217 n->m_len += tlen;
218 m_adj(n->m_next, tlen);
219 goto ok;
220 }
221 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
222 && writable) {
223 n->m_next->m_data -= hlen;
224 n->m_next->m_len += hlen;
225 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
226 n->m_len -= hlen;
227 n = n->m_next;
228 off = 0;
229 goto ok;
230 }
231
232 /*
233 * now, we need to do the hard way. don't m_copy as there's no room
234 * on both end.
235 */
236 MGET(o, M_DONTWAIT, m->m_type);
237 if (o && len > MLEN) {
238 MCLGET(o, M_DONTWAIT);
239 if ((o->m_flags & M_EXT) == 0) {
240 m_free(o);
241 o = NULL;
242 }
243 }
244 if (!o) {
245 m_freem(m);
246 return NULL; /* ENOBUFS */
247 }
248 /* get hlen from <n, off> into <o, 0> */
249 o->m_len = hlen;
250 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
251 n->m_len -= hlen;
252 /* get tlen from <n->m_next, 0> into <o, hlen> */
253 m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
254 o->m_len += tlen;
255 m_adj(n->m_next, tlen);
256 o->m_next = n->m_next;
257 n->m_next = o;
258 n = o;
259 off = 0;
260
261 ok:
262 #ifdef PULLDOWN_DEBUG
263 {
264 struct mbuf *t;
265 printf("after:");
266 for (t = m; t; t = t->m_next)
267 printf("%c%d", t == n ? '*' : ' ', t->m_len);
268 printf(" (off=%d)\n", off);
269 }
270 #endif
271 if (offp)
272 *offp = off;
273 return n;
274 }
275
276 static struct mbuf *
277 m_dup1(struct mbuf *m, int off, int len, int wait)
278 {
279 struct mbuf *n;
280 int l;
281 int copyhdr;
282
283 if (len > MCLBYTES)
284 return NULL;
285 if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
286 copyhdr = 1;
287 MGETHDR(n, wait, m->m_type);
288 l = MHLEN;
289 } else {
290 copyhdr = 0;
291 MGET(n, wait, m->m_type);
292 l = MLEN;
293 }
294 if (n && len > l) {
295 MCLGET(n, wait);
296 if ((n->m_flags & M_EXT) == 0) {
297 m_free(n);
298 n = NULL;
299 }
300 }
301 if (!n)
302 return NULL;
303
304 if (copyhdr && !m_dup_pkthdr(n, m, wait)) {
305 m_free(n);
306 return NULL;
307 }
308 m_copydata(m, off, len, mtod(n, caddr_t));
309 return n;
310 }
311
312 /* Get a packet tag structure along with specified data following. */
313 struct m_tag *
314 m_tag_alloc(u_int32_t cookie, int type, int len, int wait)
315 {
316 struct m_tag *t;
317
318 if (len < 0)
319 return NULL;
320 t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
321 if (t == NULL)
322 return NULL;
323 t->m_tag_id = type;
324 t->m_tag_len = len;
325 t->m_tag_cookie = cookie;
326 return t;
327 }
328
329 /* Free a packet tag. */
330 void
331 m_tag_free(struct m_tag *t)
332 {
333 #ifdef MAC
334 if (t->m_tag_id == PACKET_TAG_MACLABEL)
335 mac_destroy_mbuf_tag(t);
336 #endif
337 free(t, M_PACKET_TAGS);
338 }
339
340 /* Prepend a packet tag. */
341 void
342 m_tag_prepend(struct mbuf *m, struct m_tag *t)
343 {
344 KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
345 SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
346 }
347
348 /* Unlink a packet tag. */
349 void
350 m_tag_unlink(struct mbuf *m, struct m_tag *t)
351 {
352 KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
353 SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
354 }
355
356 /* Unlink and free a packet tag. */
357 void
358 m_tag_delete(struct mbuf *m, struct m_tag *t)
359 {
360 KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
361 m_tag_unlink(m, t);
362 m_tag_free(t);
363 }
364
365 /* Unlink and free a packet tag chain, starting from given tag. */
366 void
367 m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
368 {
369 struct m_tag *p, *q;
370
371 KASSERT(m, ("m_tag_delete_chain: null mbuf"));
372 if (t != NULL)
373 p = t;
374 else
375 p = SLIST_FIRST(&m->m_pkthdr.tags);
376 if (p == NULL)
377 return;
378 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
379 m_tag_delete(m, q);
380 m_tag_delete(m, p);
381 }
382
383 /* Find a tag, starting from a given position. */
384 struct m_tag *
385 m_tag_locate(struct mbuf *m, u_int32_t cookie, int type, struct m_tag *t)
386 {
387 struct m_tag *p;
388
389 KASSERT(m, ("m_tag_locate: null mbuf"));
390 if (t == NULL)
391 p = SLIST_FIRST(&m->m_pkthdr.tags);
392 else
393 p = SLIST_NEXT(t, m_tag_link);
394 while (p != NULL) {
395 if (p->m_tag_cookie == cookie && p->m_tag_id == type)
396 return p;
397 p = SLIST_NEXT(p, m_tag_link);
398 }
399 return NULL;
400 }
401
402 /* Copy a single tag. */
403 struct m_tag *
404 m_tag_copy(struct m_tag *t, int how)
405 {
406 struct m_tag *p;
407
408 KASSERT(t, ("m_tag_copy: null tag"));
409 p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how);
410 if (p == NULL)
411 return (NULL);
412 #ifdef MAC
413 /*
414 * XXXMAC: we should probably pass off the initialization, and
415 * copying here? can we hide that PACKET_TAG_MACLABEL is
416 * special from the mbuf code?
417 */
418 if (t->m_tag_id == PACKET_TAG_MACLABEL) {
419 if (mac_init_mbuf_tag(p, how) != 0) {
420 m_tag_free(p);
421 return (NULL);
422 }
423 mac_copy_mbuf_tag(t, p);
424 } else
425 #endif
426 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
427 return p;
428 }
429
430 /*
431 * Copy two tag chains. The destination mbuf (to) loses any attached
432 * tags even if the operation fails. This should not be a problem, as
433 * m_tag_copy_chain() is typically called with a newly-allocated
434 * destination mbuf.
435 */
436 int
437 m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
438 {
439 struct m_tag *p, *t, *tprev = NULL;
440
441 KASSERT(to && from,
442 ("m_tag_copy_chain: null argument, to %p from %p", to, from));
443 m_tag_delete_chain(to, NULL);
444 SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
445 t = m_tag_copy(p, how);
446 if (t == NULL) {
447 m_tag_delete_chain(to, NULL);
448 return 0;
449 }
450 if (tprev == NULL)
451 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
452 else
453 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
454 tprev = t;
455 }
456 return 1;
457 }
458
459 /* Initialize tags on an mbuf. */
460 void
461 m_tag_init(struct mbuf *m)
462 {
463 SLIST_INIT(&m->m_pkthdr.tags);
464 }
465
466 /* Get first tag in chain. */
467 struct m_tag *
468 m_tag_first(struct mbuf *m)
469 {
470 return SLIST_FIRST(&m->m_pkthdr.tags);
471 }
472
473 /* Get next tag in chain. */
474 struct m_tag *
475 m_tag_next(struct mbuf *m, struct m_tag *t)
476 {
477 return SLIST_NEXT(t, m_tag_link);
478 }
Cache object: 18612d8a07263309ef19357334829456
|