]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
xnu-201.19.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 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
23
24 /*
25 * Copyright (C) 1999 WIDE Project.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of the project nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 */
52
53 /*
54 * Copyright (c) 1982, 1986, 1988, 1991, 1993
55 * The Regents of the University of California. All rights reserved.
56 *
57 * Redistribution and use in source and binary forms, with or without
58 * modification, are permitted provided that the following conditions
59 * are met:
60 * 1. Redistributions of source code must retain the above copyright
61 * notice, this list of conditions and the following disclaimer.
62 * 2. Redistributions in binary form must reproduce the above copyright
63 * notice, this list of conditions and the following disclaimer in the
64 * documentation and/or other materials provided with the distribution.
65 * 3. All advertising materials mentioning features or use of this software
66 * must display the following acknowledgement:
67 * This product includes software developed by the University of
68 * California, Berkeley and its contributors.
69 * 4. Neither the name of the University nor the names of its contributors
70 * may be used to endorse or promote products derived from this software
71 * without specific prior written permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
74 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
77 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
78 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
79 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
83 * SUCH DAMAGE.
84 *
85 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
86 */
87
88 #define PULLDOWN_STAT
89 /*#define PULLDOWN_DEBUG*/
90
91 #ifdef PULLDOWN_STAT
92 #if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
93 #include "opt_inet.h"
94 #endif
95 #endif
96
97 #include <sys/param.h>
98 #include <sys/systm.h>
99 #include <sys/proc.h>
100 #include <sys/malloc.h>
101 #include <sys/mbuf.h>
102 #if defined(PULLDOWN_STAT) && defined(INET6)
103 #include <netinet/in.h>
104 #include <netinet/ip6.h>
105 #include <netinet6/ip6_var.h>
106 #endif
107
108 /*
109 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
110 * packet chain before "off" is kept untouched.
111 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
112 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
113 *
114 * on error return (NULL return value), original "m" will be freed.
115 *
116 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
117 */
118 struct mbuf *
119 m_pulldown(m, off, len, offp)
120 struct mbuf *m;
121 int off, len;
122 int *offp;
123 {
124 struct mbuf *n, *o;
125 int hlen, tlen, olen;
126 int sharedcluster;
127 #if defined(PULLDOWN_STAT) && defined(INET6)
128 static struct mbuf *prev = NULL;
129 int prevlen = 0, prevmlen = 0;
130 #endif
131
132 /* check invalid arguments. */
133 if (m == NULL)
134 panic("m == NULL in m_pulldown()");
135 if (len > MCLBYTES) {
136 m_freem(m);
137 return NULL; /* impossible */
138 }
139
140 #if defined(PULLDOWN_STAT) && defined(INET6)
141 ip6stat.ip6s_pulldown++;
142 #endif
143
144 #if defined(PULLDOWN_STAT) && defined(INET6)
145 /* statistics for m_pullup */
146 ip6stat.ip6s_pullup++;
147 if (off + len > MHLEN)
148 ip6stat.ip6s_pullup_fail++;
149 else {
150 int dlen, mlen;
151
152 dlen = (prev == m) ? prevlen : m->m_len;
153 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
154
155 if (dlen >= off + len)
156 ip6stat.ip6s_pullup--; /* call will not be made! */
157 else if ((m->m_flags & M_EXT) != 0) {
158 ip6stat.ip6s_pullup_alloc++;
159 ip6stat.ip6s_pullup_copy++;
160 } else {
161 if (mlen >= off + len)
162 ip6stat.ip6s_pullup_copy++;
163 else {
164 ip6stat.ip6s_pullup_alloc++;
165 ip6stat.ip6s_pullup_copy++;
166 }
167 }
168
169 prevlen = off + len;
170 prevmlen = MHLEN;
171 }
172
173 /* statistics for m_pullup2 */
174 ip6stat.ip6s_pullup2++;
175 if (off + len > MCLBYTES)
176 ip6stat.ip6s_pullup2_fail++;
177 else {
178 int dlen, mlen;
179
180 dlen = (prev == m) ? prevlen : m->m_len;
181 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
182 prevlen = off + len;
183 prevmlen = mlen;
184
185 if (dlen >= off + len)
186 ip6stat.ip6s_pullup2--; /* call will not be made! */
187 else if ((m->m_flags & M_EXT) != 0) {
188 ip6stat.ip6s_pullup2_alloc++;
189 ip6stat.ip6s_pullup2_copy++;
190 prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
191 } else {
192 if (mlen >= off + len)
193 ip6stat.ip6s_pullup2_copy++;
194 else {
195 ip6stat.ip6s_pullup2_alloc++;
196 ip6stat.ip6s_pullup2_copy++;
197 prevmlen = (off + len > MHLEN) ? MCLBYTES
198 : MHLEN;
199 }
200 }
201 }
202
203 prev = m;
204 #endif
205
206 #ifdef PULLDOWN_DEBUG
207 {
208 struct mbuf *t;
209 printf("before:");
210 for (t = m; t; t = t->m_next)
211 printf(" %d", t->m_len);
212 printf("\n");
213 }
214 #endif
215 n = m;
216 while (n != NULL && off > 0) {
217 if (n->m_len > off)
218 break;
219 off -= n->m_len;
220 n = n->m_next;
221 }
222 /* be sure to point non-empty mbuf */
223 while (n != NULL && n->m_len == 0)
224 n = n->m_next;
225 if (!n) {
226 m_freem(m);
227 return NULL; /* mbuf chain too short */
228 }
229
230 /*
231 * the target data is on <n, off>.
232 * if we got enough data on the mbuf "n", we're done.
233 */
234 if ((off == 0 || offp) && len <= n->m_len - off)
235 goto ok;
236
237 #if defined(PULLDOWN_STAT) && defined(INET6)
238 ip6stat.ip6s_pulldown_copy++;
239 #endif
240
241 /*
242 * when len < n->m_len - off and off != 0, it is a special case.
243 * len bytes from <n, off> sits in single mbuf, but the caller does
244 * not like the starting position (off).
245 * chop the current mbuf into two pieces, set off to 0.
246 */
247 if (len < n->m_len - off) {
248 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
249 if (o == NULL) {
250 m_freem(m);
251 return NULL; /* ENOBUFS */
252 }
253 n->m_len = off;
254 o->m_next = n->m_next;
255 n->m_next = o;
256 n = n->m_next;
257 off = 0;
258 goto ok;
259 }
260
261 /*
262 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
263 * and construct contiguous mbuf with m_len == len.
264 * note that hlen + tlen == len, and tlen > 0.
265 */
266 hlen = n->m_len - off;
267 tlen = len - hlen;
268
269 /*
270 * ensure that we have enough trailing data on mbuf chain.
271 * if not, we can do nothing about the chain.
272 */
273 olen = 0;
274 for (o = n->m_next; o != NULL; o = o->m_next)
275 olen += o->m_len;
276 if (hlen + olen < len) {
277 m_freem(m);
278 return NULL; /* mbuf chain too short */
279 }
280
281 /*
282 * easy cases first.
283 * we need to use m_copydata() to get data from <n->m_next, 0>.
284 */
285 if ((n->m_flags & M_EXT) == 0)
286 sharedcluster = 0;
287 else {
288 #ifdef __bsdi__
289 if (n->m_ext.ext_func)
290 #else
291 if (n->m_ext.ext_free)
292 #endif
293 sharedcluster = 1;
294 #ifdef __NetBSD__
295 else if (MCLISREFERENCED(n))
296 #else
297 else if (mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1)
298 #endif
299 sharedcluster = 1;
300 else
301 sharedcluster = 0;
302 }
303 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
304 && !sharedcluster) {
305 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
306 n->m_len += tlen;
307 m_adj(n->m_next, tlen);
308 goto ok;
309 }
310 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
311 && !sharedcluster) {
312 n->m_next->m_data -= hlen;
313 n->m_next->m_len += hlen;
314 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
315 n->m_len -= hlen;
316 n = n->m_next;
317 off = 0;
318 goto ok;
319 }
320
321 /*
322 * now, we need to do the hard way. don't m_copy as there's no room
323 * on both end.
324 */
325 #if defined(PULLDOWN_STAT) && defined(INET6)
326 ip6stat.ip6s_pulldown_alloc++;
327 #endif
328 MGET(o, M_DONTWAIT, m->m_type);
329 if (o == NULL) {
330 m_freem(m);
331 return NULL; /* ENOBUFS */
332 }
333 if (len > MHLEN) { /* use MHLEN just for safety */
334 MCLGET(o, M_DONTWAIT);
335 if ((o->m_flags & M_EXT) == 0) {
336 m_freem(m);
337 m_free(o);
338 return NULL; /* ENOBUFS */
339 }
340 }
341 /* get hlen from <n, off> into <o, 0> */
342 o->m_len = hlen;
343 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
344 n->m_len -= hlen;
345 /* get tlen from <n->m_next, 0> into <o, hlen> */
346 m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
347 o->m_len += tlen;
348 m_adj(n->m_next, tlen);
349 o->m_next = n->m_next;
350 n->m_next = o;
351 n = o;
352 off = 0;
353
354 ok:
355 #ifdef PULLDOWN_DEBUG
356 {
357 struct mbuf *t;
358 printf("after:");
359 for (t = m; t; t = t->m_next)
360 printf("%c%d", t == n ? '*' : ' ', t->m_len);
361 printf(" (off=%d)\n", off);
362 }
363 #endif
364 if (offp)
365 *offp = off;
366 return n;
367 }
368
369 /*
370 * pkthdr.aux chain manipulation.
371 * we don't allow clusters at this moment.
372 */
373 struct mbuf *
374 m_aux_add(m, af, type)
375 struct mbuf *m;
376 int af, type;
377 {
378 struct mbuf *n;
379 struct mauxtag *t;
380
381 if ((m->m_flags & M_PKTHDR) == 0)
382 return NULL;
383
384 n = m_aux_find(m, af, type);
385 if (n)
386 return n;
387
388 MGET(n, M_WAIT, m->m_type);
389 if (n == NULL)
390 return NULL;
391
392 t = mtod(n, struct mauxtag *);
393 t->af = af;
394 t->type = type;
395 n->m_data += sizeof(struct mauxtag);
396 n->m_len = 0;
397 n->m_next = m->m_pkthdr.aux;
398 m->m_pkthdr.aux = n;
399 return n;
400 }
401
402 struct mbuf *
403 m_aux_find(m, af, type)
404 struct mbuf *m;
405 int af, type;
406 {
407 struct mbuf *n;
408 struct mauxtag *t;
409
410 if ((m->m_flags & M_PKTHDR) == 0)
411 return NULL;
412
413 for (n = m->m_pkthdr.aux; n; n = n->m_next) {
414 t = (struct mauxtag *)n->m_dat;
415 if (t->af == af && t->type == type)
416 return n;
417 }
418 return NULL;
419 }
420
421 void
422 m_aux_delete(m, victim)
423 struct mbuf *m;
424 struct mbuf *victim;
425 {
426 struct mbuf *n, *prev, *next;
427 struct mauxtag *t;
428
429 if ((m->m_flags & M_PKTHDR) == 0)
430 return;
431
432 prev = NULL;
433 n = m->m_pkthdr.aux;
434 while (n) {
435 t = (struct mauxtag *)n->m_dat;
436 next = n->m_next;
437 if (n == victim) {
438 if (prev)
439 prev->m_next = n->m_next;
440 else
441 m->m_pkthdr.aux = n->m_next;
442 n->m_next = NULL;
443 m_free(n);
444 } else
445 prev = n;
446 n = next;
447 }
448 }