]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
xnu-344.23.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
89 /*#define PULLDOWN_DEBUG*/
90
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/proc.h>
94 #include <sys/malloc.h>
95 #include <sys/mbuf.h>
96 #if defined(PULLDOWN_STAT) && defined(INET6)
97 #include <netinet/in.h>
98 #include <netinet/ip6.h>
99 #include <netinet6/ip6_var.h>
100 #endif
101
102 /*
103 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
104 * packet chain before "off" is kept untouched.
105 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
106 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
107 *
108 * on error return (NULL return value), original "m" will be freed.
109 *
110 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
111 */
112 struct mbuf *
113 m_pulldown(m, off, len, offp)
114 struct mbuf *m;
115 int off, len;
116 int *offp;
117 {
118 struct mbuf *n, *o;
119 int hlen, tlen, olen;
120 int sharedcluster;
121 #if defined(PULLDOWN_STAT) && defined(INET6)
122 static struct mbuf *prev = NULL;
123 int prevlen = 0, prevmlen = 0;
124 #endif
125
126 /* check invalid arguments. */
127 if (m == NULL)
128 panic("m == NULL in m_pulldown()");
129 if (len > MCLBYTES) {
130 m_freem(m);
131 return NULL; /* impossible */
132 }
133
134 #if defined(PULLDOWN_STAT) && defined(INET6)
135 ip6stat.ip6s_pulldown++;
136 #endif
137
138 #if defined(PULLDOWN_STAT) && defined(INET6)
139 /* statistics for m_pullup */
140 ip6stat.ip6s_pullup++;
141 if (off + len > MHLEN)
142 ip6stat.ip6s_pullup_fail++;
143 else {
144 int dlen, mlen;
145
146 dlen = (prev == m) ? prevlen : m->m_len;
147 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
148
149 if (dlen >= off + len)
150 ip6stat.ip6s_pullup--; /* call will not be made! */
151 else if ((m->m_flags & M_EXT) != 0) {
152 ip6stat.ip6s_pullup_alloc++;
153 ip6stat.ip6s_pullup_copy++;
154 } else {
155 if (mlen >= off + len)
156 ip6stat.ip6s_pullup_copy++;
157 else {
158 ip6stat.ip6s_pullup_alloc++;
159 ip6stat.ip6s_pullup_copy++;
160 }
161 }
162
163 prevlen = off + len;
164 prevmlen = MHLEN;
165 }
166
167 /* statistics for m_pullup2 */
168 ip6stat.ip6s_pullup2++;
169 if (off + len > MCLBYTES)
170 ip6stat.ip6s_pullup2_fail++;
171 else {
172 int dlen, mlen;
173
174 dlen = (prev == m) ? prevlen : m->m_len;
175 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
176 prevlen = off + len;
177 prevmlen = mlen;
178
179 if (dlen >= off + len)
180 ip6stat.ip6s_pullup2--; /* call will not be made! */
181 else if ((m->m_flags & M_EXT) != 0) {
182 ip6stat.ip6s_pullup2_alloc++;
183 ip6stat.ip6s_pullup2_copy++;
184 prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
185 } else {
186 if (mlen >= off + len)
187 ip6stat.ip6s_pullup2_copy++;
188 else {
189 ip6stat.ip6s_pullup2_alloc++;
190 ip6stat.ip6s_pullup2_copy++;
191 prevmlen = (off + len > MHLEN) ? MCLBYTES
192 : MHLEN;
193 }
194 }
195 }
196
197 prev = m;
198 #endif
199
200 #ifdef PULLDOWN_DEBUG
201 {
202 struct mbuf *t;
203 printf("before:");
204 for (t = m; t; t = t->m_next)
205 printf(" %d", t->m_len);
206 printf("\n");
207 }
208 #endif
209 n = m;
210 while (n != NULL && off > 0) {
211 if (n->m_len > off)
212 break;
213 off -= n->m_len;
214 n = n->m_next;
215 }
216 /* be sure to point non-empty mbuf */
217 while (n != NULL && n->m_len == 0)
218 n = n->m_next;
219 if (!n) {
220 m_freem(m);
221 return NULL; /* mbuf chain too short */
222 }
223
224 /*
225 * the target data is on <n, off>.
226 * if we got enough data on the mbuf "n", we're done.
227 */
228 if ((off == 0 || offp) && len <= n->m_len - off)
229 goto ok;
230
231 #if defined(PULLDOWN_STAT) && defined(INET6)
232 ip6stat.ip6s_pulldown_copy++;
233 #endif
234
235 /*
236 * when len < n->m_len - off and off != 0, it is a special case.
237 * len bytes from <n, off> sits in single mbuf, but the caller does
238 * not like the starting position (off).
239 * chop the current mbuf into two pieces, set off to 0.
240 */
241 if (len < n->m_len - off) {
242 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
243 if (o == NULL) {
244 m_freem(m);
245 return NULL; /* ENOBUFS */
246 }
247 n->m_len = off;
248 o->m_next = n->m_next;
249 n->m_next = o;
250 n = n->m_next;
251 off = 0;
252 goto ok;
253 }
254
255 /*
256 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
257 * and construct contiguous mbuf with m_len == len.
258 * note that hlen + tlen == len, and tlen > 0.
259 */
260 hlen = n->m_len - off;
261 tlen = len - hlen;
262
263 /*
264 * ensure that we have enough trailing data on mbuf chain.
265 * if not, we can do nothing about the chain.
266 */
267 olen = 0;
268 for (o = n->m_next; o != NULL; o = o->m_next)
269 olen += o->m_len;
270 if (hlen + olen < len) {
271 m_freem(m);
272 return NULL; /* mbuf chain too short */
273 }
274
275 /*
276 * easy cases first.
277 * we need to use m_copydata() to get data from <n->m_next, 0>.
278 */
279 if ((n->m_flags & M_EXT) == 0)
280 sharedcluster = 0;
281 else {
282 #ifdef __bsdi__
283 if (n->m_ext.ext_func)
284 #else
285 if (n->m_ext.ext_free)
286 #endif
287 sharedcluster = 1;
288 #ifdef __NetBSD__
289 else if (MCLISREFERENCED(n))
290 #else
291 else if (mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1)
292 #endif
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_WAIT, 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 }