]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
8f31d88f51ada14ab1d88202b10f4c7f3f1461f8
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
33 * Copyright (C) 1999 WIDE Project.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * Copyright (c) 1982, 1986, 1988, 1991, 1993
63 * The Regents of the University of California. All rights reserved.
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions
68 * 1. Redistributions of source code must retain the above copyright
69 * notice, this list of conditions and the following disclaimer.
70 * 2. Redistributions in binary form must reproduce the above copyright
71 * notice, this list of conditions and the following disclaimer in the
72 * documentation and/or other materials provided with the distribution.
73 * 3. All advertising materials mentioning features or use of this software
74 * must display the following acknowledgement:
75 * This product includes software developed by the University of
76 * California, Berkeley and its contributors.
77 * 4. Neither the name of the University nor the names of its contributors
78 * may be used to endorse or promote products derived from this software
79 * without specific prior written permission.
81 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
82 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
85 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
93 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
97 /*#define PULLDOWN_DEBUG*/
99 #include <sys/param.h>
100 #include <sys/systm.h>
101 #include <sys/proc_internal.h>
102 #include <sys/malloc.h>
103 #include <sys/mbuf.h>
104 #if defined(PULLDOWN_STAT) && defined(INET6)
105 #include <netinet/in.h>
106 #include <netinet/ip6.h>
107 #include <netinet6/ip6_var.h>
111 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
112 * packet chain before "off" is kept untouched.
113 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
114 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
116 * on error return (NULL return value), original "m" will be freed.
118 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
121 m_pulldown(m
, off
, len
, offp
)
127 int hlen
, tlen
, olen
;
129 #if defined(PULLDOWN_STAT) && defined(INET6)
130 static struct mbuf
*prev
= NULL
;
131 int prevlen
= 0, prevmlen
= 0;
134 /* check invalid arguments. */
136 panic("m == NULL in m_pulldown()");
137 if (len
> MCLBYTES
) {
139 return NULL
; /* impossible */
142 #if defined(PULLDOWN_STAT) && defined(INET6)
143 ip6stat
.ip6s_pulldown
++;
146 #if defined(PULLDOWN_STAT) && defined(INET6)
147 /* statistics for m_pullup */
148 ip6stat
.ip6s_pullup
++;
149 if (off
+ len
> MHLEN
)
150 ip6stat
.ip6s_pullup_fail
++;
154 dlen
= (prev
== m
) ? prevlen
: m
->m_len
;
155 mlen
= (prev
== m
) ? prevmlen
: m
->m_len
+ M_TRAILINGSPACE(m
);
157 if (dlen
>= off
+ len
)
158 ip6stat
.ip6s_pullup
--; /* call will not be made! */
159 else if ((m
->m_flags
& M_EXT
) != 0) {
160 ip6stat
.ip6s_pullup_alloc
++;
161 ip6stat
.ip6s_pullup_copy
++;
163 if (mlen
>= off
+ len
)
164 ip6stat
.ip6s_pullup_copy
++;
166 ip6stat
.ip6s_pullup_alloc
++;
167 ip6stat
.ip6s_pullup_copy
++;
175 /* statistics for m_pullup2 */
176 ip6stat
.ip6s_pullup2
++;
177 if (off
+ len
> MCLBYTES
)
178 ip6stat
.ip6s_pullup2_fail
++;
182 dlen
= (prev
== m
) ? prevlen
: m
->m_len
;
183 mlen
= (prev
== m
) ? prevmlen
: m
->m_len
+ M_TRAILINGSPACE(m
);
187 if (dlen
>= off
+ len
)
188 ip6stat
.ip6s_pullup2
--; /* call will not be made! */
189 else if ((m
->m_flags
& M_EXT
) != 0) {
190 ip6stat
.ip6s_pullup2_alloc
++;
191 ip6stat
.ip6s_pullup2_copy
++;
192 prevmlen
= (off
+ len
> MHLEN
) ? MCLBYTES
: MHLEN
;
194 if (mlen
>= off
+ len
)
195 ip6stat
.ip6s_pullup2_copy
++;
197 ip6stat
.ip6s_pullup2_alloc
++;
198 ip6stat
.ip6s_pullup2_copy
++;
199 prevmlen
= (off
+ len
> MHLEN
) ? MCLBYTES
208 #ifdef PULLDOWN_DEBUG
212 for (t
= m
; t
; t
= t
->m_next
)
213 printf(" %d", t
->m_len
);
218 while (n
!= NULL
&& off
> 0) {
224 /* be sure to point non-empty mbuf */
225 while (n
!= NULL
&& n
->m_len
== 0)
229 return NULL
; /* mbuf chain too short */
233 * the target data is on <n, off>.
234 * if we got enough data on the mbuf "n", we're done.
236 if ((off
== 0 || offp
) && len
<= n
->m_len
- off
)
239 #if defined(PULLDOWN_STAT) && defined(INET6)
240 ip6stat
.ip6s_pulldown_copy
++;
244 * when len < n->m_len - off and off != 0, it is a special case.
245 * len bytes from <n, off> sits in single mbuf, but the caller does
246 * not like the starting position (off).
247 * chop the current mbuf into two pieces, set off to 0.
249 if (len
< n
->m_len
- off
) {
250 o
= m_copym(n
, off
, n
->m_len
- off
, M_DONTWAIT
);
253 return NULL
; /* ENOBUFS */
256 o
->m_next
= n
->m_next
;
264 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
265 * and construct contiguous mbuf with m_len == len.
266 * note that hlen + tlen == len, and tlen > 0.
268 hlen
= n
->m_len
- off
;
272 * ensure that we have enough trailing data on mbuf chain.
273 * if not, we can do nothing about the chain.
276 for (o
= n
->m_next
; o
!= NULL
; o
= o
->m_next
)
278 if (hlen
+ olen
< len
) {
280 return NULL
; /* mbuf chain too short */
285 * we need to use m_copydata() to get data from <n->m_next, 0>.
287 if ((n
->m_flags
& M_EXT
) == 0)
290 if (n
->m_ext
.ext_free
)
292 else if (m_mclhasreference(n
))
297 if ((off
== 0 || offp
) && M_TRAILINGSPACE(n
) >= tlen
299 m_copydata(n
->m_next
, 0, tlen
, mtod(n
, caddr_t
) + n
->m_len
);
301 m_adj(n
->m_next
, tlen
);
304 if ((off
== 0 || offp
) && M_LEADINGSPACE(n
->m_next
) >= hlen
306 n
->m_next
->m_data
-= hlen
;
307 n
->m_next
->m_len
+= hlen
;
308 bcopy(mtod(n
, caddr_t
) + off
, mtod(n
->m_next
, caddr_t
), hlen
);
316 * now, we need to do the hard way. don't m_copy as there's no room
319 #if defined(PULLDOWN_STAT) && defined(INET6)
320 ip6stat
.ip6s_pulldown_alloc
++;
322 MGET(o
, M_DONTWAIT
, m
->m_type
);
325 return NULL
; /* ENOBUFS */
327 if (len
> MHLEN
) { /* use MHLEN just for safety */
328 MCLGET(o
, M_DONTWAIT
);
329 if ((o
->m_flags
& M_EXT
) == 0) {
332 return NULL
; /* ENOBUFS */
335 /* get hlen from <n, off> into <o, 0> */
337 bcopy(mtod(n
, caddr_t
) + off
, mtod(o
, caddr_t
), hlen
);
339 /* get tlen from <n->m_next, 0> into <o, hlen> */
340 m_copydata(n
->m_next
, 0, tlen
, mtod(o
, caddr_t
) + o
->m_len
);
342 m_adj(n
->m_next
, tlen
);
343 o
->m_next
= n
->m_next
;
349 #ifdef PULLDOWN_DEBUG
353 for (t
= m
; t
; t
= t
->m_next
)
354 printf("%c%d", t
== n
? '*' : ' ', t
->m_len
);
355 printf(" (off=%d)\n", off
);
364 * pkthdr.aux chain manipulation.
365 * we don't allow clusters at this moment.
368 m_aux_add(m
, af
, type
)
375 if ((m
->m_flags
& M_PKTHDR
) == 0)
378 n
= m_aux_find(m
, af
, type
);
382 MGET(n
, M_DONTWAIT
, m
->m_type
);
386 t
= mtod(n
, struct mauxtag
*);
389 n
->m_data
+= sizeof(struct mauxtag
);
391 n
->m_next
= m
->m_pkthdr
.aux
;
397 m_aux_find(m
, af
, type
)
404 if ((m
->m_flags
& M_PKTHDR
) == 0)
407 for (n
= m
->m_pkthdr
.aux
; n
; n
= n
->m_next
) {
408 t
= (struct mauxtag
*)n
->m_dat
;
409 if (t
->af
== af
&& t
->type
== type
)
416 m_aux_delete(m
, victim
)
420 struct mbuf
*n
, *prev
, *next
;
423 if ((m
->m_flags
& M_PKTHDR
) == 0)
429 t
= (struct mauxtag
*)n
->m_dat
;
433 prev
->m_next
= n
->m_next
;
435 m
->m_pkthdr
.aux
= n
->m_next
;
444 /* Get a packet tag structure along with specified data following. */
446 m_tag_alloc(u_int32_t id
, u_int16_t type
, int len
, int wait
)
453 t
= malloc(len
+ sizeof(struct m_tag
), M_PACKET_TAGS
, wait
);
455 /*MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_TEMP, M_WAITOK);*/
456 if (len
+ sizeof(struct m_tag
) <= MLEN
) {
457 struct mbuf
*m
= m_get(wait
, MT_TAG
);
460 t
= (struct m_tag
*) m
->m_dat
;
461 } else if (len
+ sizeof(struct m_tag
) <= MCLBYTES
) {
462 MCLALLOC((caddr_t
)t
, wait
);
468 t
->m_tag_type
= type
;
475 /* Free a packet tag. */
477 m_tag_free(struct m_tag
*t
)
480 free(t
, M_PACKET_TAGS
);
482 /* FREE(t, M_TEMP); */
485 if (t
->m_tag_len
<= MLEN
) {
486 struct mbuf
* m
= m_dtom(t
);
494 /* Prepend a packet tag. */
496 m_tag_prepend(struct mbuf
*m
, struct m_tag
*t
)
498 KASSERT(m
&& t
, ("m_tag_prepend: null argument, m %p t %p", m
, t
));
499 SLIST_INSERT_HEAD(&m
->m_pkthdr
.tags
, t
, m_tag_link
);
502 /* Unlink a packet tag. */
504 m_tag_unlink(struct mbuf
*m
, struct m_tag
*t
)
506 KASSERT(m
&& t
, ("m_tag_unlink: null argument, m %p t %p", m
, t
));
507 SLIST_REMOVE(&m
->m_pkthdr
.tags
, t
, m_tag
, m_tag_link
);
510 /* Unlink and free a packet tag. */
512 m_tag_delete(struct mbuf
*m
, struct m_tag
*t
)
514 KASSERT(m
&& t
, ("m_tag_delete: null argument, m %p t %p", m
, t
));
519 /* Unlink and free a packet tag chain, starting from given tag. */
521 m_tag_delete_chain(struct mbuf
*m
, struct m_tag
*t
)
525 KASSERT(m
, ("m_tag_delete_chain: null mbuf"));
529 p
= SLIST_FIRST(&m
->m_pkthdr
.tags
);
532 while ((q
= SLIST_NEXT(p
, m_tag_link
)) != NULL
)
537 /* Find a tag, starting from a given position. */
539 m_tag_locate(struct mbuf
*m
, u_int32_t id
, u_int16_t type
, struct m_tag
*t
)
543 KASSERT(m
, ("m_tag_find: null mbuf"));
545 p
= SLIST_FIRST(&m
->m_pkthdr
.tags
);
547 p
= SLIST_NEXT(t
, m_tag_link
);
549 if (p
->m_tag_id
== id
&& p
->m_tag_type
== type
)
551 p
= SLIST_NEXT(p
, m_tag_link
);
556 /* Copy a single tag. */
558 m_tag_copy(struct m_tag
*t
, int how
)
562 KASSERT(t
, ("m_tag_copy: null tag"));
563 p
= m_tag_alloc(t
->m_tag_id
, t
->m_tag_type
, t
->m_tag_len
, how
);
566 bcopy(t
+ 1, p
+ 1, t
->m_tag_len
); /* Copy the data */
571 * Copy two tag chains. The destination mbuf (to) loses any attached
572 * tags even if the operation fails. This should not be a problem, as
573 * m_tag_copy_chain() is typically called with a newly-allocated
577 m_tag_copy_chain(struct mbuf
*to
, struct mbuf
*from
, int how
)
579 struct m_tag
*p
, *t
, *tprev
= NULL
;
582 ("m_tag_copy: null argument, to %p from %p", to
, from
));
583 m_tag_delete_chain(to
, NULL
);
584 SLIST_FOREACH(p
, &from
->m_pkthdr
.tags
, m_tag_link
) {
585 t
= m_tag_copy(p
, how
);
587 m_tag_delete_chain(to
, NULL
);
591 SLIST_INSERT_HEAD(&to
->m_pkthdr
.tags
, t
, m_tag_link
);
593 SLIST_INSERT_AFTER(tprev
, t
, m_tag_link
);
600 /* Initialize tags on an mbuf. */
602 m_tag_init(struct mbuf
*m
)
604 SLIST_INIT(&m
->m_pkthdr
.tags
);
607 /* Get first tag in chain. */
609 m_tag_first(struct mbuf
*m
)
611 return SLIST_FIRST(&m
->m_pkthdr
.tags
);
614 /* Get next tag in chain. */
616 m_tag_next(__unused
struct mbuf
*m
, struct m_tag
*t
)
618 return SLIST_NEXT(t
, m_tag_link
);