1 //==========================================================================
3 // src/sys/kern/uipc_mbuf2.c
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
8 // -------------------------------------------
10 // Portions of this software may have been derived from OpenBSD,
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
17 // -------------------------------------------
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
22 /* $KAME: uipc_mbuf2.c,v 1.31 2001/11/28 11:08:53 itojun Exp $ */
23 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
26 * Copyright (C) 1999 WIDE Project.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. Neither the name of the project nor the names of its contributors
38 * may be used to endorse or promote products derived from this software
39 * without specific prior written permission.
41 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * Copyright (c) 1982, 1986, 1988, 1991, 1993
56 * The Regents of the University of California. All rights reserved.
58 * Redistribution and use in source and binary forms, with or without
59 * modification, are permitted provided that the following conditions
61 * 1. Redistributions of source code must retain the above copyright
62 * notice, this list of conditions and the following disclaimer.
63 * 2. Redistributions in binary form must reproduce the above copyright
64 * notice, this list of conditions and the following disclaimer in the
65 * documentation and/or other materials provided with the distribution.
66 * 3. All advertising materials mentioning features or use of this software
67 * must display the following acknowledgement:
68 * This product includes software developed by the University of
69 * California, Berkeley and its contributors.
70 * 4. Neither the name of the University nor the names of its contributors
71 * may be used to endorse or promote products derived from this software
72 * without specific prior written permission.
74 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
75 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
78 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
79 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
80 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
83 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
86 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
89 #include <sys/param.h>
90 #include <sys/malloc.h>
94 #define M_SHAREDCLUSTER(m) \
95 (((m)->m_flags & M_EXT) != 0 && \
96 ((m)->m_ext.ext_func || mclrefcnt[mtocl((m)->m_ext.ext_buf)] > 1))
97 #elif defined(__NetBSD__) || defined(__OpenBSD__)
98 #define M_SHAREDCLUSTER(m) \
99 (((m)->m_flags & M_EXT) != 0 && \
100 ((m)->m_ext.ext_free || MCLISREFERENCED((m))))
102 #define M_SHAREDCLUSTER(m) \
103 (((m)->m_flags & M_EXT) != 0 && \
104 ((m)->m_ext.ext_free || mclrefcnt[mtocl((m)->m_ext.ext_buf)] > 1))
108 /* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
109 static struct mbuf *m_dup1 __P((struct mbuf *, int, int, int));
113 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
114 * packet chain before "off" is kept untouched.
115 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
116 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
118 * on error return (NULL return value), original "m" will be freed.
120 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
123 m_pulldown(m, off, len, offp)
129 int hlen, tlen, olen;
132 static struct mbuf *prev = NULL;
133 int prevlen = 0, prevmlen = 0;
136 /* check invalid arguments. */
138 panic("m == NULL in m_pulldown()");
139 if (len > MCLBYTES) {
141 return NULL; /* impossible */
145 mbstat.m_pulldowns++;
149 /* statistics for m_pullup */
151 if (off + len > MHLEN)
152 mbstat.m_pullup_fail++;
156 dlen = (prev == m) ? prevlen : m->m_len;
157 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
159 if (dlen >= off + len)
160 mbstat.m_pullups--; /* call will not be made! */
161 else if ((m->m_flags & M_EXT) != 0) {
162 mbstat.m_pullup_alloc++;
163 mbstat.m_pullup_copy++;
165 if (mlen >= off + len)
166 mbstat.m_pullup_copy++;
168 mbstat.m_pullup_alloc++;
169 mbstat.m_pullup_copy++;
177 /* statistics for m_pullup2 */
179 if (off + len > MCLBYTES)
180 mbstat.m_pullup2_fail++;
184 dlen = (prev == m) ? prevlen : m->m_len;
185 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
189 if (dlen >= off + len)
190 mbstat.m_pullup2--; /* call will not be made! */
191 else if ((m->m_flags & M_EXT) != 0) {
192 mbstat.m_pullup2_alloc++;
193 mbstat.m_pullup2_copy++;
194 prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
196 if (mlen >= off + len)
197 mbstat.m_pullup2_copy++;
199 mbstat.m_pullup2_alloc++;
200 mbstat.m_pullup2_copy++;
201 prevmlen = (off + len > MHLEN) ? MCLBYTES
210 #ifdef PULLDOWN_DEBUG
214 for (t = m; t; t = t->m_next)
215 printf(" %d", t->m_len);
220 while (n != NULL && off > 0) {
226 /* be sure to point non-empty mbuf */
227 while (n != NULL && n->m_len == 0)
231 return NULL; /* mbuf chain too short */
234 sharedcluster = M_SHAREDCLUSTER(n);
237 * the target data is on <n, off>.
238 * if we got enough data on the mbuf "n", we're done.
240 if ((off == 0 || offp) && len <= n->m_len - off && !sharedcluster)
244 mbstat.m_pulldown_copy++;
248 * when len <= n->m_len - off and off != 0, it is a special case.
249 * len bytes from <n, off> sits in single mbuf, but the caller does
250 * not like the starting position (off).
251 * chop the current mbuf into two pieces, set off to 0.
253 if (len <= n->m_len - off) {
255 o = m_dup(n, off, n->m_len - off, M_DONTWAIT);
257 o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
261 return NULL; /* ENOBUFS */
264 o->m_next = n->m_next;
272 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
273 * and construct contiguous mbuf with m_len == len.
274 * note that hlen + tlen == len, and tlen > 0.
276 hlen = n->m_len - off;
280 * ensure that we have enough trailing data on mbuf chain.
281 * if not, we can do nothing about the chain.
284 for (o = n->m_next; o != NULL; o = o->m_next)
286 if (hlen + olen < len) {
288 return NULL; /* mbuf chain too short */
293 * we need to use m_copydata() to get data from <n->m_next, 0>.
295 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen &&
297 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
299 m_adj(n->m_next, tlen);
302 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen &&
304 n->m_next->m_data -= hlen;
305 n->m_next->m_len += hlen;
306 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
314 * now, we need to do the hard way. don't m_copy as there's no room
318 mbstat.m_pulldown_alloc++;
320 MGET(o, M_DONTWAIT, m->m_type);
321 if (o && len > MLEN) {
322 MCLGET(o, M_DONTWAIT);
323 if ((o->m_flags & M_EXT) == 0) {
330 return NULL; /* ENOBUFS */
332 /* get hlen from <n, off> into <o, 0> */
334 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
336 /* get tlen from <n->m_next, 0> into <o, hlen> */
337 m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
339 m_adj(n->m_next, tlen);
340 o->m_next = n->m_next;
346 #ifdef PULLDOWN_DEBUG
350 for (t = m; t; t = t->m_next)
351 printf("%c%d", t == n ? '*' : ' ', t->m_len);
352 printf(" (off=%d)\n", off);
362 m_dup1(m, off, len, wait)
374 if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
376 MGETHDR(n, wait, m->m_type);
380 MGET(n, wait, m->m_type);
385 if ((n->m_flags & M_EXT) == 0) {
400 m_copydata(m, off, len, mtod(n, caddr_t));
408 * pkthdr.aux chain manipulation.
409 * we don't allow clusters at this moment.
412 m_aux_add2(m, af, type, p)
420 if ((m->m_flags & M_PKTHDR) == 0)
423 n = m_aux_find(m, af, type);
427 MGET(n, M_DONTWAIT, m->m_type);
431 t = mtod(n, struct mauxtag *);
432 bzero(t, sizeof(*t));
436 n->m_data += sizeof(struct mauxtag);
438 n->m_next = m->m_pkthdr.aux;
444 m_aux_find2(m, af, type, p)
452 if ((m->m_flags & M_PKTHDR) == 0)
455 for (n = m->m_pkthdr.aux; n; n = n->m_next) {
456 t = (struct mauxtag *)n->m_dat;
457 if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) {
458 printf("m_aux_find: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data);
461 if (t->af == af && t->type == type && t->p == p)
468 m_aux_find(m, af, type)
473 return m_aux_find2(m, af, type, NULL);
477 m_aux_add(m, af, type)
482 return m_aux_add2(m, af, type, NULL);
486 m_aux_delete(m, victim)
490 struct mbuf *n, *prev, *next;
493 if ((m->m_flags & M_PKTHDR) == 0)
499 t = (struct mauxtag *)n->m_dat;
501 if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) {
502 printf("m_aux_delete: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data);
509 prev->m_next = n->m_next;
511 m->m_pkthdr.aux = n->m_next;
521 /* Get a packet tag structure along with specified data following. */
523 m_tag_get(type, len, wait)
532 MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_PACKET_TAGS,
541 /* Free a packet tag. */
546 FREE(t, M_PACKET_TAGS);
549 /* Prepend a packet tag. */
555 SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
558 /* Unlink a packet tag. */
564 SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
567 /* Unlink and free a packet tag. */
577 /* Unlink and free a packet tag chain, starting from given tag. */
579 m_tag_delete_chain(m, t)
588 p = SLIST_FIRST(&m->m_pkthdr.tags);
591 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
596 /* Find a tag, starting from a given position. */
598 m_tag_find(m, type, t)
606 p = SLIST_FIRST(&m->m_pkthdr.tags);
608 p = SLIST_NEXT(t, m_tag_link);
610 if (p->m_tag_id == type)
612 p = SLIST_NEXT(p, m_tag_link);
617 /* Copy a single tag. */
624 p = m_tag_get(t->m_tag_id, t->m_tag_len, M_NOWAIT);
627 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
632 * Copy two tag chains. The destination mbuf (to) loses any attached
633 * tags even if the operation fails. This should not be a problem, as
634 * m_tag_copy_chain() is typically called with a newly-allocated
638 m_tag_copy_chain(to, from)
642 struct m_tag *p, *t, *tprev = NULL;
644 m_tag_delete_chain(to, NULL);
645 SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
648 m_tag_delete_chain(to, NULL);
652 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
654 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
661 /* Initialize tags on an mbuf. */
666 SLIST_INIT(&m->m_pkthdr.tags);
669 /* Get first tag in chain. */
674 return (SLIST_FIRST(&m->m_pkthdr.tags));
677 /* Get next tag in chain. */
683 return (SLIST_NEXT(t, m_tag_link));