]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/uipc_mbuf2.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / kern / uipc_mbuf2.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1c79356b 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1c79356b
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
24
25/*
26 * Copyright (C) 1999 WIDE Project.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
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.
40 *
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
51 * SUCH DAMAGE.
52 */
53
54/*
55 * Copyright (c) 1982, 1986, 1988, 1991, 1993
56 * The Regents of the University of California. All rights reserved.
57 *
58 * Redistribution and use in source and binary forms, with or without
59 * modification, are permitted provided that the following conditions
60 * are met:
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.
73 *
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
84 * SUCH DAMAGE.
85 *
86 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
87 */
88
1c79356b 89
9bccf70c 90/*#define PULLDOWN_DEBUG*/
1c79356b
A
91
92#include <sys/param.h>
93#include <sys/systm.h>
91447636 94#include <sys/proc_internal.h>
1c79356b
A
95#include <sys/malloc.h>
96#include <sys/mbuf.h>
97#if defined(PULLDOWN_STAT) && defined(INET6)
98#include <netinet/in.h>
99#include <netinet/ip6.h>
100#include <netinet6/ip6_var.h>
101#endif
102
103/*
104 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
105 * packet chain before "off" is kept untouched.
106 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
107 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
108 *
109 * on error return (NULL return value), original "m" will be freed.
110 *
111 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
112 */
113struct mbuf *
114m_pulldown(m, off, len, offp)
115 struct mbuf *m;
116 int off, len;
117 int *offp;
118{
119 struct mbuf *n, *o;
120 int hlen, tlen, olen;
121 int sharedcluster;
122#if defined(PULLDOWN_STAT) && defined(INET6)
123 static struct mbuf *prev = NULL;
124 int prevlen = 0, prevmlen = 0;
125#endif
126
127 /* check invalid arguments. */
128 if (m == NULL)
129 panic("m == NULL in m_pulldown()");
130 if (len > MCLBYTES) {
131 m_freem(m);
132 return NULL; /* impossible */
133 }
134
135#if defined(PULLDOWN_STAT) && defined(INET6)
136 ip6stat.ip6s_pulldown++;
137#endif
138
139#if defined(PULLDOWN_STAT) && defined(INET6)
140 /* statistics for m_pullup */
141 ip6stat.ip6s_pullup++;
142 if (off + len > MHLEN)
143 ip6stat.ip6s_pullup_fail++;
144 else {
145 int dlen, mlen;
146
147 dlen = (prev == m) ? prevlen : m->m_len;
148 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
149
150 if (dlen >= off + len)
151 ip6stat.ip6s_pullup--; /* call will not be made! */
152 else if ((m->m_flags & M_EXT) != 0) {
153 ip6stat.ip6s_pullup_alloc++;
154 ip6stat.ip6s_pullup_copy++;
155 } else {
156 if (mlen >= off + len)
157 ip6stat.ip6s_pullup_copy++;
158 else {
159 ip6stat.ip6s_pullup_alloc++;
160 ip6stat.ip6s_pullup_copy++;
161 }
162 }
163
164 prevlen = off + len;
165 prevmlen = MHLEN;
166 }
167
168 /* statistics for m_pullup2 */
169 ip6stat.ip6s_pullup2++;
170 if (off + len > MCLBYTES)
171 ip6stat.ip6s_pullup2_fail++;
172 else {
173 int dlen, mlen;
174
175 dlen = (prev == m) ? prevlen : m->m_len;
176 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
177 prevlen = off + len;
178 prevmlen = mlen;
179
180 if (dlen >= off + len)
181 ip6stat.ip6s_pullup2--; /* call will not be made! */
182 else if ((m->m_flags & M_EXT) != 0) {
183 ip6stat.ip6s_pullup2_alloc++;
184 ip6stat.ip6s_pullup2_copy++;
185 prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
186 } else {
187 if (mlen >= off + len)
188 ip6stat.ip6s_pullup2_copy++;
189 else {
190 ip6stat.ip6s_pullup2_alloc++;
191 ip6stat.ip6s_pullup2_copy++;
192 prevmlen = (off + len > MHLEN) ? MCLBYTES
193 : MHLEN;
194 }
195 }
196 }
197
198 prev = m;
199#endif
200
201#ifdef PULLDOWN_DEBUG
202 {
203 struct mbuf *t;
204 printf("before:");
205 for (t = m; t; t = t->m_next)
206 printf(" %d", t->m_len);
207 printf("\n");
208 }
209#endif
210 n = m;
211 while (n != NULL && off > 0) {
212 if (n->m_len > off)
213 break;
214 off -= n->m_len;
215 n = n->m_next;
216 }
217 /* be sure to point non-empty mbuf */
218 while (n != NULL && n->m_len == 0)
219 n = n->m_next;
220 if (!n) {
221 m_freem(m);
222 return NULL; /* mbuf chain too short */
223 }
224
225 /*
226 * the target data is on <n, off>.
227 * if we got enough data on the mbuf "n", we're done.
228 */
229 if ((off == 0 || offp) && len <= n->m_len - off)
230 goto ok;
231
232#if defined(PULLDOWN_STAT) && defined(INET6)
233 ip6stat.ip6s_pulldown_copy++;
234#endif
235
236 /*
237 * when len < n->m_len - off and off != 0, it is a special case.
238 * len bytes from <n, off> sits in single mbuf, but the caller does
239 * not like the starting position (off).
240 * chop the current mbuf into two pieces, set off to 0.
241 */
242 if (len < n->m_len - off) {
243 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
244 if (o == NULL) {
245 m_freem(m);
246 return NULL; /* ENOBUFS */
247 }
248 n->m_len = off;
249 o->m_next = n->m_next;
250 n->m_next = o;
251 n = n->m_next;
252 off = 0;
253 goto ok;
254 }
255
256 /*
257 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
258 * and construct contiguous mbuf with m_len == len.
259 * note that hlen + tlen == len, and tlen > 0.
260 */
261 hlen = n->m_len - off;
262 tlen = len - hlen;
263
264 /*
265 * ensure that we have enough trailing data on mbuf chain.
266 * if not, we can do nothing about the chain.
267 */
268 olen = 0;
269 for (o = n->m_next; o != NULL; o = o->m_next)
270 olen += o->m_len;
271 if (hlen + olen < len) {
272 m_freem(m);
273 return NULL; /* mbuf chain too short */
274 }
275
276 /*
277 * easy cases first.
278 * we need to use m_copydata() to get data from <n->m_next, 0>.
279 */
280 if ((n->m_flags & M_EXT) == 0)
281 sharedcluster = 0;
282 else {
1c79356b 283 if (n->m_ext.ext_free)
1c79356b 284 sharedcluster = 1;
91447636 285 else if (m_mclhasreference(n))
1c79356b
A
286 sharedcluster = 1;
287 else
288 sharedcluster = 0;
289 }
290 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
291 && !sharedcluster) {
292 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
293 n->m_len += tlen;
294 m_adj(n->m_next, tlen);
295 goto ok;
296 }
297 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
298 && !sharedcluster) {
299 n->m_next->m_data -= hlen;
300 n->m_next->m_len += hlen;
301 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
302 n->m_len -= hlen;
303 n = n->m_next;
304 off = 0;
305 goto ok;
306 }
307
308 /*
309 * now, we need to do the hard way. don't m_copy as there's no room
310 * on both end.
311 */
312#if defined(PULLDOWN_STAT) && defined(INET6)
313 ip6stat.ip6s_pulldown_alloc++;
314#endif
315 MGET(o, M_DONTWAIT, m->m_type);
316 if (o == NULL) {
317 m_freem(m);
318 return NULL; /* ENOBUFS */
319 }
320 if (len > MHLEN) { /* use MHLEN just for safety */
321 MCLGET(o, M_DONTWAIT);
322 if ((o->m_flags & M_EXT) == 0) {
323 m_freem(m);
324 m_free(o);
325 return NULL; /* ENOBUFS */
326 }
327 }
328 /* get hlen from <n, off> into <o, 0> */
329 o->m_len = hlen;
330 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
331 n->m_len -= hlen;
332 /* get tlen from <n->m_next, 0> into <o, hlen> */
333 m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
334 o->m_len += tlen;
335 m_adj(n->m_next, tlen);
336 o->m_next = n->m_next;
337 n->m_next = o;
338 n = o;
339 off = 0;
340
341ok:
342#ifdef PULLDOWN_DEBUG
343 {
344 struct mbuf *t;
345 printf("after:");
346 for (t = m; t; t = t->m_next)
347 printf("%c%d", t == n ? '*' : ' ', t->m_len);
348 printf(" (off=%d)\n", off);
349 }
350#endif
351 if (offp)
352 *offp = off;
353 return n;
354}
355
356/*
357 * pkthdr.aux chain manipulation.
358 * we don't allow clusters at this moment.
359 */
360struct mbuf *
361m_aux_add(m, af, type)
362 struct mbuf *m;
363 int af, type;
364{
365 struct mbuf *n;
366 struct mauxtag *t;
367
368 if ((m->m_flags & M_PKTHDR) == 0)
369 return NULL;
370
371 n = m_aux_find(m, af, type);
372 if (n)
373 return n;
374
55e303ae 375 MGET(n, M_DONTWAIT, m->m_type);
1c79356b
A
376 if (n == NULL)
377 return NULL;
378
379 t = mtod(n, struct mauxtag *);
380 t->af = af;
381 t->type = type;
382 n->m_data += sizeof(struct mauxtag);
383 n->m_len = 0;
384 n->m_next = m->m_pkthdr.aux;
385 m->m_pkthdr.aux = n;
386 return n;
387}
388
389struct mbuf *
390m_aux_find(m, af, type)
391 struct mbuf *m;
392 int af, type;
393{
394 struct mbuf *n;
395 struct mauxtag *t;
396
397 if ((m->m_flags & M_PKTHDR) == 0)
398 return NULL;
399
400 for (n = m->m_pkthdr.aux; n; n = n->m_next) {
401 t = (struct mauxtag *)n->m_dat;
402 if (t->af == af && t->type == type)
403 return n;
404 }
405 return NULL;
406}
407
408void
409m_aux_delete(m, victim)
410 struct mbuf *m;
411 struct mbuf *victim;
412{
413 struct mbuf *n, *prev, *next;
414 struct mauxtag *t;
415
416 if ((m->m_flags & M_PKTHDR) == 0)
417 return;
418
419 prev = NULL;
420 n = m->m_pkthdr.aux;
421 while (n) {
422 t = (struct mauxtag *)n->m_dat;
423 next = n->m_next;
424 if (n == victim) {
425 if (prev)
426 prev->m_next = n->m_next;
427 else
428 m->m_pkthdr.aux = n->m_next;
429 n->m_next = NULL;
430 m_free(n);
431 } else
432 prev = n;
433 n = next;
434 }
435}
91447636
A
436
437/* Get a packet tag structure along with specified data following. */
438struct m_tag *
439m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
440{
441 struct m_tag *t;
442
443 if (len < 0)
444 return NULL;
445#ifndef __APPLE__
446 t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
447#else
448 /*MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_TEMP, M_WAITOK);*/
449 if (len + sizeof(struct m_tag) <= MLEN) {
450 struct mbuf *m = m_get(wait, MT_TAG);
451 if (m == NULL)
452 return NULL;
453 t = (struct m_tag *) m->m_dat;
454 } else if (len + sizeof(struct m_tag) <= MCLBYTES) {
455 MCLALLOC((caddr_t)t, wait);
456 } else
457 t = NULL;
458#endif
459 if (t == NULL)
460 return NULL;
461 t->m_tag_type = type;
462 t->m_tag_len = len;
463 t->m_tag_id = id;
464 return t;
465}
466
467
468/* Free a packet tag. */
469void
470m_tag_free(struct m_tag *t)
471{
472#ifndef __APPLE__
473 free(t, M_PACKET_TAGS);
474#else
475 /* FREE(t, M_TEMP); */
476 if (t == NULL)
477 return;
478 if (t->m_tag_len <= MLEN) {
479 struct mbuf * m = m_dtom(t);
480 m_free(m);
481 } else {
482 MCLFREE((caddr_t)t);
483 }
484#endif
485}
486
487/* Prepend a packet tag. */
488void
489m_tag_prepend(struct mbuf *m, struct m_tag *t)
490{
491 KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
492 SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
493}
494
495/* Unlink a packet tag. */
496void
497m_tag_unlink(struct mbuf *m, struct m_tag *t)
498{
499 KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
500 SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
501}
502
503/* Unlink and free a packet tag. */
504void
505m_tag_delete(struct mbuf *m, struct m_tag *t)
506{
507 KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
508 m_tag_unlink(m, t);
509 m_tag_free(t);
510}
511
512/* Unlink and free a packet tag chain, starting from given tag. */
513void
514m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
515{
516 struct m_tag *p, *q;
517
518 KASSERT(m, ("m_tag_delete_chain: null mbuf"));
519 if (t != NULL)
520 p = t;
521 else
522 p = SLIST_FIRST(&m->m_pkthdr.tags);
523 if (p == NULL)
524 return;
525 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
526 m_tag_delete(m, q);
527 m_tag_delete(m, p);
528}
529
530/* Find a tag, starting from a given position. */
531struct m_tag *
532m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
533{
534 struct m_tag *p;
535
536 KASSERT(m, ("m_tag_find: null mbuf"));
537 if (t == NULL)
538 p = SLIST_FIRST(&m->m_pkthdr.tags);
539 else
540 p = SLIST_NEXT(t, m_tag_link);
541 while (p != NULL) {
542 if (p->m_tag_id == id && p->m_tag_type == type)
543 return p;
544 p = SLIST_NEXT(p, m_tag_link);
545 }
546 return NULL;
547}
548
549/* Copy a single tag. */
550struct m_tag *
551m_tag_copy(struct m_tag *t, int how)
552{
553 struct m_tag *p;
554
555 KASSERT(t, ("m_tag_copy: null tag"));
3a60a9f5 556 p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how);
91447636
A
557 if (p == NULL)
558 return (NULL);
559 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
560 return p;
561}
562
563/*
564 * Copy two tag chains. The destination mbuf (to) loses any attached
565 * tags even if the operation fails. This should not be a problem, as
566 * m_tag_copy_chain() is typically called with a newly-allocated
567 * destination mbuf.
568 */
569int
570m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
571{
572 struct m_tag *p, *t, *tprev = NULL;
573
574 KASSERT(to && from,
575 ("m_tag_copy: null argument, to %p from %p", to, from));
576 m_tag_delete_chain(to, NULL);
577 SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
578 t = m_tag_copy(p, how);
579 if (t == NULL) {
580 m_tag_delete_chain(to, NULL);
581 return 0;
582 }
583 if (tprev == NULL)
584 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
585 else {
586 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
587 tprev = t;
588 }
589 }
590 return 1;
591}
592
593/* Initialize tags on an mbuf. */
594void
595m_tag_init(struct mbuf *m)
596{
597 SLIST_INIT(&m->m_pkthdr.tags);
598}
599
600/* Get first tag in chain. */
601struct m_tag *
602m_tag_first(struct mbuf *m)
603{
604 return SLIST_FIRST(&m->m_pkthdr.tags);
605}
606
607/* Get next tag in chain. */
608struct m_tag *
609m_tag_next(__unused struct mbuf *m, struct m_tag *t)
610{
611 return SLIST_NEXT(t, m_tag_link);
612}