]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / kern / uipc_mbuf2.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
26
27 /*
28 * Copyright (C) 1999 WIDE Project.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
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.
42 *
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
53 * SUCH DAMAGE.
54 */
55
56 /*
57 * Copyright (c) 1982, 1986, 1988, 1991, 1993
58 * The Regents of the University of California. All rights reserved.
59 *
60 * Redistribution and use in source and binary forms, with or without
61 * modification, are permitted provided that the following conditions
62 * are met:
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.
75 *
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
86 * SUCH DAMAGE.
87 *
88 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
89 */
90
91
92 /*#define PULLDOWN_DEBUG*/
93
94 #include <sys/param.h>
95 #include <sys/systm.h>
96 #include <sys/proc.h>
97 #include <sys/malloc.h>
98 #include <sys/mbuf.h>
99 #if defined(PULLDOWN_STAT) && defined(INET6)
100 #include <netinet/in.h>
101 #include <netinet/ip6.h>
102 #include <netinet6/ip6_var.h>
103 #endif
104
105 /*
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.
110 *
111 * on error return (NULL return value), original "m" will be freed.
112 *
113 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
114 */
115 struct mbuf *
116 m_pulldown(m, off, len, offp)
117 struct mbuf *m;
118 int off, len;
119 int *offp;
120 {
121 struct mbuf *n, *o;
122 int hlen, tlen, olen;
123 int sharedcluster;
124 #if defined(PULLDOWN_STAT) && defined(INET6)
125 static struct mbuf *prev = NULL;
126 int prevlen = 0, prevmlen = 0;
127 #endif
128
129 /* check invalid arguments. */
130 if (m == NULL)
131 panic("m == NULL in m_pulldown()");
132 if (len > MCLBYTES) {
133 m_freem(m);
134 return NULL; /* impossible */
135 }
136
137 #if defined(PULLDOWN_STAT) && defined(INET6)
138 ip6stat.ip6s_pulldown++;
139 #endif
140
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++;
146 else {
147 int dlen, mlen;
148
149 dlen = (prev == m) ? prevlen : m->m_len;
150 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
151
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++;
157 } else {
158 if (mlen >= off + len)
159 ip6stat.ip6s_pullup_copy++;
160 else {
161 ip6stat.ip6s_pullup_alloc++;
162 ip6stat.ip6s_pullup_copy++;
163 }
164 }
165
166 prevlen = off + len;
167 prevmlen = MHLEN;
168 }
169
170 /* statistics for m_pullup2 */
171 ip6stat.ip6s_pullup2++;
172 if (off + len > MCLBYTES)
173 ip6stat.ip6s_pullup2_fail++;
174 else {
175 int dlen, mlen;
176
177 dlen = (prev == m) ? prevlen : m->m_len;
178 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
179 prevlen = off + len;
180 prevmlen = mlen;
181
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;
188 } else {
189 if (mlen >= off + len)
190 ip6stat.ip6s_pullup2_copy++;
191 else {
192 ip6stat.ip6s_pullup2_alloc++;
193 ip6stat.ip6s_pullup2_copy++;
194 prevmlen = (off + len > MHLEN) ? MCLBYTES
195 : MHLEN;
196 }
197 }
198 }
199
200 prev = m;
201 #endif
202
203 #ifdef PULLDOWN_DEBUG
204 {
205 struct mbuf *t;
206 printf("before:");
207 for (t = m; t; t = t->m_next)
208 printf(" %d", t->m_len);
209 printf("\n");
210 }
211 #endif
212 n = m;
213 while (n != NULL && off > 0) {
214 if (n->m_len > off)
215 break;
216 off -= n->m_len;
217 n = n->m_next;
218 }
219 /* be sure to point non-empty mbuf */
220 while (n != NULL && n->m_len == 0)
221 n = n->m_next;
222 if (!n) {
223 m_freem(m);
224 return NULL; /* mbuf chain too short */
225 }
226
227 /*
228 * the target data is on <n, off>.
229 * if we got enough data on the mbuf "n", we're done.
230 */
231 if ((off == 0 || offp) && len <= n->m_len - off)
232 goto ok;
233
234 #if defined(PULLDOWN_STAT) && defined(INET6)
235 ip6stat.ip6s_pulldown_copy++;
236 #endif
237
238 /*
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.
243 */
244 if (len < n->m_len - off) {
245 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
246 if (o == NULL) {
247 m_freem(m);
248 return NULL; /* ENOBUFS */
249 }
250 n->m_len = off;
251 o->m_next = n->m_next;
252 n->m_next = o;
253 n = n->m_next;
254 off = 0;
255 goto ok;
256 }
257
258 /*
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.
262 */
263 hlen = n->m_len - off;
264 tlen = len - hlen;
265
266 /*
267 * ensure that we have enough trailing data on mbuf chain.
268 * if not, we can do nothing about the chain.
269 */
270 olen = 0;
271 for (o = n->m_next; o != NULL; o = o->m_next)
272 olen += o->m_len;
273 if (hlen + olen < len) {
274 m_freem(m);
275 return NULL; /* mbuf chain too short */
276 }
277
278 /*
279 * easy cases first.
280 * we need to use m_copydata() to get data from <n->m_next, 0>.
281 */
282 if ((n->m_flags & M_EXT) == 0)
283 sharedcluster = 0;
284 else {
285 #ifdef __bsdi__
286 if (n->m_ext.ext_func)
287 #else
288 if (n->m_ext.ext_free)
289 #endif
290 sharedcluster = 1;
291 #ifdef __NetBSD__
292 else if (MCLISREFERENCED(n))
293 #else
294 else if (mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1)
295 #endif
296 sharedcluster = 1;
297 else
298 sharedcluster = 0;
299 }
300 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
301 && !sharedcluster) {
302 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
303 n->m_len += tlen;
304 m_adj(n->m_next, tlen);
305 goto ok;
306 }
307 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
308 && !sharedcluster) {
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);
312 n->m_len -= hlen;
313 n = n->m_next;
314 off = 0;
315 goto ok;
316 }
317
318 /*
319 * now, we need to do the hard way. don't m_copy as there's no room
320 * on both end.
321 */
322 #if defined(PULLDOWN_STAT) && defined(INET6)
323 ip6stat.ip6s_pulldown_alloc++;
324 #endif
325 MGET(o, M_DONTWAIT, m->m_type);
326 if (o == NULL) {
327 m_freem(m);
328 return NULL; /* ENOBUFS */
329 }
330 if (len > MHLEN) { /* use MHLEN just for safety */
331 MCLGET(o, M_DONTWAIT);
332 if ((o->m_flags & M_EXT) == 0) {
333 m_freem(m);
334 m_free(o);
335 return NULL; /* ENOBUFS */
336 }
337 }
338 /* get hlen from <n, off> into <o, 0> */
339 o->m_len = hlen;
340 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
341 n->m_len -= 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);
344 o->m_len += tlen;
345 m_adj(n->m_next, tlen);
346 o->m_next = n->m_next;
347 n->m_next = o;
348 n = o;
349 off = 0;
350
351 ok:
352 #ifdef PULLDOWN_DEBUG
353 {
354 struct mbuf *t;
355 printf("after:");
356 for (t = m; t; t = t->m_next)
357 printf("%c%d", t == n ? '*' : ' ', t->m_len);
358 printf(" (off=%d)\n", off);
359 }
360 #endif
361 if (offp)
362 *offp = off;
363 return n;
364 }
365
366 /*
367 * pkthdr.aux chain manipulation.
368 * we don't allow clusters at this moment.
369 */
370 struct mbuf *
371 m_aux_add(m, af, type)
372 struct mbuf *m;
373 int af, type;
374 {
375 struct mbuf *n;
376 struct mauxtag *t;
377
378 if ((m->m_flags & M_PKTHDR) == 0)
379 return NULL;
380
381 n = m_aux_find(m, af, type);
382 if (n)
383 return n;
384
385 MGET(n, M_DONTWAIT, m->m_type);
386 if (n == NULL)
387 return NULL;
388
389 t = mtod(n, struct mauxtag *);
390 t->af = af;
391 t->type = type;
392 n->m_data += sizeof(struct mauxtag);
393 n->m_len = 0;
394 n->m_next = m->m_pkthdr.aux;
395 m->m_pkthdr.aux = n;
396 return n;
397 }
398
399 struct mbuf *
400 m_aux_find(m, af, type)
401 struct mbuf *m;
402 int af, type;
403 {
404 struct mbuf *n;
405 struct mauxtag *t;
406
407 if ((m->m_flags & M_PKTHDR) == 0)
408 return NULL;
409
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)
413 return n;
414 }
415 return NULL;
416 }
417
418 void
419 m_aux_delete(m, victim)
420 struct mbuf *m;
421 struct mbuf *victim;
422 {
423 struct mbuf *n, *prev, *next;
424 struct mauxtag *t;
425
426 if ((m->m_flags & M_PKTHDR) == 0)
427 return;
428
429 prev = NULL;
430 n = m->m_pkthdr.aux;
431 while (n) {
432 t = (struct mauxtag *)n->m_dat;
433 next = n->m_next;
434 if (n == victim) {
435 if (prev)
436 prev->m_next = n->m_next;
437 else
438 m->m_pkthdr.aux = n->m_next;
439 n->m_next = NULL;
440 m_free(n);
441 } else
442 prev = n;
443 n = next;
444 }
445 }