]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
28 * Copyright (C) 1999 WIDE Project.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. Neither the name of the project nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * Copyright (c) 1982, 1986, 1988, 1991, 1993
58 * The Regents of the University of California. All rights reserved.
60 * Redistribution and use in source and binary forms, with or without
61 * modification, are permitted provided that the following conditions
63 * 1. Redistributions of source code must retain the above copyright
64 * notice, this list of conditions and the following disclaimer.
65 * 2. Redistributions in binary form must reproduce the above copyright
66 * notice, this list of conditions and the following disclaimer in the
67 * documentation and/or other materials provided with the distribution.
68 * 3. All advertising materials mentioning features or use of this software
69 * must display the following acknowledgement:
70 * This product includes software developed by the University of
71 * California, Berkeley and its contributors.
72 * 4. Neither the name of the University nor the names of its contributors
73 * may be used to endorse or promote products derived from this software
74 * without specific prior written permission.
76 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
80 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
92 /*#define PULLDOWN_DEBUG*/
94 #include <sys/param.h>
95 #include <sys/systm.h>
97 #include <sys/malloc.h>
99 #if defined(PULLDOWN_STAT) && defined(INET6)
100 #include <netinet/in.h>
101 #include <netinet/ip6.h>
102 #include <netinet6/ip6_var.h>
106 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
107 * packet chain before "off" is kept untouched.
108 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
109 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
111 * on error return (NULL return value), original "m" will be freed.
113 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
116 m_pulldown(m
, off
, len
, offp
)
122 int hlen
, tlen
, olen
;
124 #if defined(PULLDOWN_STAT) && defined(INET6)
125 static struct mbuf
*prev
= NULL
;
126 int prevlen
= 0, prevmlen
= 0;
129 /* check invalid arguments. */
131 panic("m == NULL in m_pulldown()");
132 if (len
> MCLBYTES
) {
134 return NULL
; /* impossible */
137 #if defined(PULLDOWN_STAT) && defined(INET6)
138 ip6stat
.ip6s_pulldown
++;
141 #if defined(PULLDOWN_STAT) && defined(INET6)
142 /* statistics for m_pullup */
143 ip6stat
.ip6s_pullup
++;
144 if (off
+ len
> MHLEN
)
145 ip6stat
.ip6s_pullup_fail
++;
149 dlen
= (prev
== m
) ? prevlen
: m
->m_len
;
150 mlen
= (prev
== m
) ? prevmlen
: m
->m_len
+ M_TRAILINGSPACE(m
);
152 if (dlen
>= off
+ len
)
153 ip6stat
.ip6s_pullup
--; /* call will not be made! */
154 else if ((m
->m_flags
& M_EXT
) != 0) {
155 ip6stat
.ip6s_pullup_alloc
++;
156 ip6stat
.ip6s_pullup_copy
++;
158 if (mlen
>= off
+ len
)
159 ip6stat
.ip6s_pullup_copy
++;
161 ip6stat
.ip6s_pullup_alloc
++;
162 ip6stat
.ip6s_pullup_copy
++;
170 /* statistics for m_pullup2 */
171 ip6stat
.ip6s_pullup2
++;
172 if (off
+ len
> MCLBYTES
)
173 ip6stat
.ip6s_pullup2_fail
++;
177 dlen
= (prev
== m
) ? prevlen
: m
->m_len
;
178 mlen
= (prev
== m
) ? prevmlen
: m
->m_len
+ M_TRAILINGSPACE(m
);
182 if (dlen
>= off
+ len
)
183 ip6stat
.ip6s_pullup2
--; /* call will not be made! */
184 else if ((m
->m_flags
& M_EXT
) != 0) {
185 ip6stat
.ip6s_pullup2_alloc
++;
186 ip6stat
.ip6s_pullup2_copy
++;
187 prevmlen
= (off
+ len
> MHLEN
) ? MCLBYTES
: MHLEN
;
189 if (mlen
>= off
+ len
)
190 ip6stat
.ip6s_pullup2_copy
++;
192 ip6stat
.ip6s_pullup2_alloc
++;
193 ip6stat
.ip6s_pullup2_copy
++;
194 prevmlen
= (off
+ len
> MHLEN
) ? MCLBYTES
203 #ifdef PULLDOWN_DEBUG
207 for (t
= m
; t
; t
= t
->m_next
)
208 printf(" %d", t
->m_len
);
213 while (n
!= NULL
&& off
> 0) {
219 /* be sure to point non-empty mbuf */
220 while (n
!= NULL
&& n
->m_len
== 0)
224 return NULL
; /* mbuf chain too short */
228 * the target data is on <n, off>.
229 * if we got enough data on the mbuf "n", we're done.
231 if ((off
== 0 || offp
) && len
<= n
->m_len
- off
)
234 #if defined(PULLDOWN_STAT) && defined(INET6)
235 ip6stat
.ip6s_pulldown_copy
++;
239 * when len < n->m_len - off and off != 0, it is a special case.
240 * len bytes from <n, off> sits in single mbuf, but the caller does
241 * not like the starting position (off).
242 * chop the current mbuf into two pieces, set off to 0.
244 if (len
< n
->m_len
- off
) {
245 o
= m_copym(n
, off
, n
->m_len
- off
, M_DONTWAIT
);
248 return NULL
; /* ENOBUFS */
251 o
->m_next
= n
->m_next
;
259 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
260 * and construct contiguous mbuf with m_len == len.
261 * note that hlen + tlen == len, and tlen > 0.
263 hlen
= n
->m_len
- off
;
267 * ensure that we have enough trailing data on mbuf chain.
268 * if not, we can do nothing about the chain.
271 for (o
= n
->m_next
; o
!= NULL
; o
= o
->m_next
)
273 if (hlen
+ olen
< len
) {
275 return NULL
; /* mbuf chain too short */
280 * we need to use m_copydata() to get data from <n->m_next, 0>.
282 if ((n
->m_flags
& M_EXT
) == 0)
286 if (n
->m_ext
.ext_func
)
288 if (n
->m_ext
.ext_free
)
292 else if (MCLISREFERENCED(n
))
294 else if (mclrefcnt
[mtocl(n
->m_ext
.ext_buf
)] > 1)
300 if ((off
== 0 || offp
) && M_TRAILINGSPACE(n
) >= tlen
302 m_copydata(n
->m_next
, 0, tlen
, mtod(n
, caddr_t
) + n
->m_len
);
304 m_adj(n
->m_next
, tlen
);
307 if ((off
== 0 || offp
) && M_LEADINGSPACE(n
->m_next
) >= hlen
309 n
->m_next
->m_data
-= hlen
;
310 n
->m_next
->m_len
+= hlen
;
311 bcopy(mtod(n
, caddr_t
) + off
, mtod(n
->m_next
, caddr_t
), hlen
);
319 * now, we need to do the hard way. don't m_copy as there's no room
322 #if defined(PULLDOWN_STAT) && defined(INET6)
323 ip6stat
.ip6s_pulldown_alloc
++;
325 MGET(o
, M_DONTWAIT
, m
->m_type
);
328 return NULL
; /* ENOBUFS */
330 if (len
> MHLEN
) { /* use MHLEN just for safety */
331 MCLGET(o
, M_DONTWAIT
);
332 if ((o
->m_flags
& M_EXT
) == 0) {
335 return NULL
; /* ENOBUFS */
338 /* get hlen from <n, off> into <o, 0> */
340 bcopy(mtod(n
, caddr_t
) + off
, mtod(o
, caddr_t
), hlen
);
342 /* get tlen from <n->m_next, 0> into <o, hlen> */
343 m_copydata(n
->m_next
, 0, tlen
, mtod(o
, caddr_t
) + o
->m_len
);
345 m_adj(n
->m_next
, tlen
);
346 o
->m_next
= n
->m_next
;
352 #ifdef PULLDOWN_DEBUG
356 for (t
= m
; t
; t
= t
->m_next
)
357 printf("%c%d", t
== n
? '*' : ' ', t
->m_len
);
358 printf(" (off=%d)\n", off
);
367 * pkthdr.aux chain manipulation.
368 * we don't allow clusters at this moment.
371 m_aux_add(m
, af
, type
)
378 if ((m
->m_flags
& M_PKTHDR
) == 0)
381 n
= m_aux_find(m
, af
, type
);
385 MGET(n
, M_DONTWAIT
, m
->m_type
);
389 t
= mtod(n
, struct mauxtag
*);
392 n
->m_data
+= sizeof(struct mauxtag
);
394 n
->m_next
= m
->m_pkthdr
.aux
;
400 m_aux_find(m
, af
, type
)
407 if ((m
->m_flags
& M_PKTHDR
) == 0)
410 for (n
= m
->m_pkthdr
.aux
; n
; n
= n
->m_next
) {
411 t
= (struct mauxtag
*)n
->m_dat
;
412 if (t
->af
== af
&& t
->type
== type
)
419 m_aux_delete(m
, victim
)
423 struct mbuf
*n
, *prev
, *next
;
426 if ((m
->m_flags
& M_PKTHDR
) == 0)
432 t
= (struct mauxtag
*)n
->m_dat
;
436 prev
->m_next
= n
->m_next
;
438 m
->m_pkthdr
.aux
= n
->m_next
;