]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
8f31d88f51ada14ab1d88202b10f4c7f3f1461f8
[apple/xnu.git] / bsd / kern / uipc_mbuf2.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
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
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
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.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
31
32 /*
33 * Copyright (C) 1999 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 */
60
61 /*
62 * Copyright (c) 1982, 1986, 1988, 1991, 1993
63 * The Regents of the University of California. All rights reserved.
64 *
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions
67 * are met:
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.
80 *
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
91 * SUCH DAMAGE.
92 *
93 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
94 */
95
96
97 /*#define PULLDOWN_DEBUG*/
98
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>
108 #endif
109
110 /*
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.
115 *
116 * on error return (NULL return value), original "m" will be freed.
117 *
118 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
119 */
120 struct mbuf *
121 m_pulldown(m, off, len, offp)
122 struct mbuf *m;
123 int off, len;
124 int *offp;
125 {
126 struct mbuf *n, *o;
127 int hlen, tlen, olen;
128 int sharedcluster;
129 #if defined(PULLDOWN_STAT) && defined(INET6)
130 static struct mbuf *prev = NULL;
131 int prevlen = 0, prevmlen = 0;
132 #endif
133
134 /* check invalid arguments. */
135 if (m == NULL)
136 panic("m == NULL in m_pulldown()");
137 if (len > MCLBYTES) {
138 m_freem(m);
139 return NULL; /* impossible */
140 }
141
142 #if defined(PULLDOWN_STAT) && defined(INET6)
143 ip6stat.ip6s_pulldown++;
144 #endif
145
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++;
151 else {
152 int dlen, mlen;
153
154 dlen = (prev == m) ? prevlen : m->m_len;
155 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
156
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++;
162 } else {
163 if (mlen >= off + len)
164 ip6stat.ip6s_pullup_copy++;
165 else {
166 ip6stat.ip6s_pullup_alloc++;
167 ip6stat.ip6s_pullup_copy++;
168 }
169 }
170
171 prevlen = off + len;
172 prevmlen = MHLEN;
173 }
174
175 /* statistics for m_pullup2 */
176 ip6stat.ip6s_pullup2++;
177 if (off + len > MCLBYTES)
178 ip6stat.ip6s_pullup2_fail++;
179 else {
180 int dlen, mlen;
181
182 dlen = (prev == m) ? prevlen : m->m_len;
183 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
184 prevlen = off + len;
185 prevmlen = mlen;
186
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;
193 } else {
194 if (mlen >= off + len)
195 ip6stat.ip6s_pullup2_copy++;
196 else {
197 ip6stat.ip6s_pullup2_alloc++;
198 ip6stat.ip6s_pullup2_copy++;
199 prevmlen = (off + len > MHLEN) ? MCLBYTES
200 : MHLEN;
201 }
202 }
203 }
204
205 prev = m;
206 #endif
207
208 #ifdef PULLDOWN_DEBUG
209 {
210 struct mbuf *t;
211 printf("before:");
212 for (t = m; t; t = t->m_next)
213 printf(" %d", t->m_len);
214 printf("\n");
215 }
216 #endif
217 n = m;
218 while (n != NULL && off > 0) {
219 if (n->m_len > off)
220 break;
221 off -= n->m_len;
222 n = n->m_next;
223 }
224 /* be sure to point non-empty mbuf */
225 while (n != NULL && n->m_len == 0)
226 n = n->m_next;
227 if (!n) {
228 m_freem(m);
229 return NULL; /* mbuf chain too short */
230 }
231
232 /*
233 * the target data is on <n, off>.
234 * if we got enough data on the mbuf "n", we're done.
235 */
236 if ((off == 0 || offp) && len <= n->m_len - off)
237 goto ok;
238
239 #if defined(PULLDOWN_STAT) && defined(INET6)
240 ip6stat.ip6s_pulldown_copy++;
241 #endif
242
243 /*
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.
248 */
249 if (len < n->m_len - off) {
250 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
251 if (o == NULL) {
252 m_freem(m);
253 return NULL; /* ENOBUFS */
254 }
255 n->m_len = off;
256 o->m_next = n->m_next;
257 n->m_next = o;
258 n = n->m_next;
259 off = 0;
260 goto ok;
261 }
262
263 /*
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.
267 */
268 hlen = n->m_len - off;
269 tlen = len - hlen;
270
271 /*
272 * ensure that we have enough trailing data on mbuf chain.
273 * if not, we can do nothing about the chain.
274 */
275 olen = 0;
276 for (o = n->m_next; o != NULL; o = o->m_next)
277 olen += o->m_len;
278 if (hlen + olen < len) {
279 m_freem(m);
280 return NULL; /* mbuf chain too short */
281 }
282
283 /*
284 * easy cases first.
285 * we need to use m_copydata() to get data from <n->m_next, 0>.
286 */
287 if ((n->m_flags & M_EXT) == 0)
288 sharedcluster = 0;
289 else {
290 if (n->m_ext.ext_free)
291 sharedcluster = 1;
292 else if (m_mclhasreference(n))
293 sharedcluster = 1;
294 else
295 sharedcluster = 0;
296 }
297 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
298 && !sharedcluster) {
299 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
300 n->m_len += tlen;
301 m_adj(n->m_next, tlen);
302 goto ok;
303 }
304 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
305 && !sharedcluster) {
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);
309 n->m_len -= hlen;
310 n = n->m_next;
311 off = 0;
312 goto ok;
313 }
314
315 /*
316 * now, we need to do the hard way. don't m_copy as there's no room
317 * on both end.
318 */
319 #if defined(PULLDOWN_STAT) && defined(INET6)
320 ip6stat.ip6s_pulldown_alloc++;
321 #endif
322 MGET(o, M_DONTWAIT, m->m_type);
323 if (o == NULL) {
324 m_freem(m);
325 return NULL; /* ENOBUFS */
326 }
327 if (len > MHLEN) { /* use MHLEN just for safety */
328 MCLGET(o, M_DONTWAIT);
329 if ((o->m_flags & M_EXT) == 0) {
330 m_freem(m);
331 m_free(o);
332 return NULL; /* ENOBUFS */
333 }
334 }
335 /* get hlen from <n, off> into <o, 0> */
336 o->m_len = hlen;
337 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
338 n->m_len -= 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);
341 o->m_len += tlen;
342 m_adj(n->m_next, tlen);
343 o->m_next = n->m_next;
344 n->m_next = o;
345 n = o;
346 off = 0;
347
348 ok:
349 #ifdef PULLDOWN_DEBUG
350 {
351 struct mbuf *t;
352 printf("after:");
353 for (t = m; t; t = t->m_next)
354 printf("%c%d", t == n ? '*' : ' ', t->m_len);
355 printf(" (off=%d)\n", off);
356 }
357 #endif
358 if (offp)
359 *offp = off;
360 return n;
361 }
362
363 /*
364 * pkthdr.aux chain manipulation.
365 * we don't allow clusters at this moment.
366 */
367 struct mbuf *
368 m_aux_add(m, af, type)
369 struct mbuf *m;
370 int af, type;
371 {
372 struct mbuf *n;
373 struct mauxtag *t;
374
375 if ((m->m_flags & M_PKTHDR) == 0)
376 return NULL;
377
378 n = m_aux_find(m, af, type);
379 if (n)
380 return n;
381
382 MGET(n, M_DONTWAIT, m->m_type);
383 if (n == NULL)
384 return NULL;
385
386 t = mtod(n, struct mauxtag *);
387 t->af = af;
388 t->type = type;
389 n->m_data += sizeof(struct mauxtag);
390 n->m_len = 0;
391 n->m_next = m->m_pkthdr.aux;
392 m->m_pkthdr.aux = n;
393 return n;
394 }
395
396 struct mbuf *
397 m_aux_find(m, af, type)
398 struct mbuf *m;
399 int af, type;
400 {
401 struct mbuf *n;
402 struct mauxtag *t;
403
404 if ((m->m_flags & M_PKTHDR) == 0)
405 return NULL;
406
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)
410 return n;
411 }
412 return NULL;
413 }
414
415 void
416 m_aux_delete(m, victim)
417 struct mbuf *m;
418 struct mbuf *victim;
419 {
420 struct mbuf *n, *prev, *next;
421 struct mauxtag *t;
422
423 if ((m->m_flags & M_PKTHDR) == 0)
424 return;
425
426 prev = NULL;
427 n = m->m_pkthdr.aux;
428 while (n) {
429 t = (struct mauxtag *)n->m_dat;
430 next = n->m_next;
431 if (n == victim) {
432 if (prev)
433 prev->m_next = n->m_next;
434 else
435 m->m_pkthdr.aux = n->m_next;
436 n->m_next = NULL;
437 m_free(n);
438 } else
439 prev = n;
440 n = next;
441 }
442 }
443
444 /* Get a packet tag structure along with specified data following. */
445 struct m_tag *
446 m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
447 {
448 struct m_tag *t;
449
450 if (len < 0)
451 return NULL;
452 #ifndef __APPLE__
453 t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
454 #else
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);
458 if (m == NULL)
459 return NULL;
460 t = (struct m_tag *) m->m_dat;
461 } else if (len + sizeof(struct m_tag) <= MCLBYTES) {
462 MCLALLOC((caddr_t)t, wait);
463 } else
464 t = NULL;
465 #endif
466 if (t == NULL)
467 return NULL;
468 t->m_tag_type = type;
469 t->m_tag_len = len;
470 t->m_tag_id = id;
471 return t;
472 }
473
474
475 /* Free a packet tag. */
476 void
477 m_tag_free(struct m_tag *t)
478 {
479 #ifndef __APPLE__
480 free(t, M_PACKET_TAGS);
481 #else
482 /* FREE(t, M_TEMP); */
483 if (t == NULL)
484 return;
485 if (t->m_tag_len <= MLEN) {
486 struct mbuf * m = m_dtom(t);
487 m_free(m);
488 } else {
489 MCLFREE((caddr_t)t);
490 }
491 #endif
492 }
493
494 /* Prepend a packet tag. */
495 void
496 m_tag_prepend(struct mbuf *m, struct m_tag *t)
497 {
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);
500 }
501
502 /* Unlink a packet tag. */
503 void
504 m_tag_unlink(struct mbuf *m, struct m_tag *t)
505 {
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);
508 }
509
510 /* Unlink and free a packet tag. */
511 void
512 m_tag_delete(struct mbuf *m, struct m_tag *t)
513 {
514 KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
515 m_tag_unlink(m, t);
516 m_tag_free(t);
517 }
518
519 /* Unlink and free a packet tag chain, starting from given tag. */
520 void
521 m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
522 {
523 struct m_tag *p, *q;
524
525 KASSERT(m, ("m_tag_delete_chain: null mbuf"));
526 if (t != NULL)
527 p = t;
528 else
529 p = SLIST_FIRST(&m->m_pkthdr.tags);
530 if (p == NULL)
531 return;
532 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
533 m_tag_delete(m, q);
534 m_tag_delete(m, p);
535 }
536
537 /* Find a tag, starting from a given position. */
538 struct m_tag *
539 m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
540 {
541 struct m_tag *p;
542
543 KASSERT(m, ("m_tag_find: null mbuf"));
544 if (t == NULL)
545 p = SLIST_FIRST(&m->m_pkthdr.tags);
546 else
547 p = SLIST_NEXT(t, m_tag_link);
548 while (p != NULL) {
549 if (p->m_tag_id == id && p->m_tag_type == type)
550 return p;
551 p = SLIST_NEXT(p, m_tag_link);
552 }
553 return NULL;
554 }
555
556 /* Copy a single tag. */
557 struct m_tag *
558 m_tag_copy(struct m_tag *t, int how)
559 {
560 struct m_tag *p;
561
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);
564 if (p == NULL)
565 return (NULL);
566 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
567 return p;
568 }
569
570 /*
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
574 * destination mbuf.
575 */
576 int
577 m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
578 {
579 struct m_tag *p, *t, *tprev = NULL;
580
581 KASSERT(to && from,
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);
586 if (t == NULL) {
587 m_tag_delete_chain(to, NULL);
588 return 0;
589 }
590 if (tprev == NULL)
591 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
592 else {
593 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
594 tprev = t;
595 }
596 }
597 return 1;
598 }
599
600 /* Initialize tags on an mbuf. */
601 void
602 m_tag_init(struct mbuf *m)
603 {
604 SLIST_INIT(&m->m_pkthdr.tags);
605 }
606
607 /* Get first tag in chain. */
608 struct m_tag *
609 m_tag_first(struct mbuf *m)
610 {
611 return SLIST_FIRST(&m->m_pkthdr.tags);
612 }
613
614 /* Get next tag in chain. */
615 struct m_tag *
616 m_tag_next(__unused struct mbuf *m, struct m_tag *t)
617 {
618 return SLIST_NEXT(t, m_tag_link);
619 }