1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*	$NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $	*/
29
30/*
31 * Copyright (C) 1999 WIDE Project.
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 *    notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 *    notice, this list of conditions and the following disclaimer in the
41 *    documentation and/or other materials provided with the distribution.
42 * 3. Neither the name of the project nor the names of its contributors
43 *    may be used to endorse or promote products derived from this software
44 *    without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58
59/*
60 * Copyright (c) 1982, 1986, 1988, 1991, 1993
61 *	The Regents of the University of California.  All rights reserved.
62 *
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
65 * are met:
66 * 1. Redistributions of source code must retain the above copyright
67 *    notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 *    notice, this list of conditions and the following disclaimer in the
70 *    documentation and/or other materials provided with the distribution.
71 * 3. All advertising materials mentioning features or use of this software
72 *    must display the following acknowledgement:
73 *	This product includes software developed by the University of
74 *	California, Berkeley and its contributors.
75 * 4. Neither the name of the University nor the names of its contributors
76 *    may be used to endorse or promote products derived from this software
77 *    without specific prior written permission.
78 *
79 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 * SUCH DAMAGE.
90 *
91 *	@(#)uipc_mbuf.c	8.4 (Berkeley) 2/14/95
92 */
93/*
94 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
95 * support for mandatory and extensible security protections.  This notice
96 * is included in support of clause 2.2 (b) of the Apple Public License,
97 * Version 2.0.
98 */
99
100
101/*#define PULLDOWN_DEBUG*/
102
103#include <sys/param.h>
104#include <sys/systm.h>
105#include <sys/proc_internal.h>
106#include <sys/malloc.h>
107#include <sys/mbuf.h>
108#if defined(PULLDOWN_STAT) && defined(INET6)
109#include <netinet/in.h>
110#include <netinet/ip6.h>
111#include <netinet6/ip6_var.h>
112#endif
113
114#if CONFIG_MACF_NET
115#include <security/mac_framework.h>
116#endif
117
118/*
119 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
120 * packet chain before "off" is kept untouched.
121 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
122 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
123 *
124 * on error return (NULL return value), original "m" will be freed.
125 *
126 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
127 */
128struct mbuf *
129m_pulldown(struct mbuf *m, int off, int len, int *offp)
130{
131	struct mbuf *n, *o;
132	int hlen, tlen, olen;
133	int sharedcluster;
134#if defined(PULLDOWN_STAT) && defined(INET6)
135	static struct mbuf *prev = NULL;
136	int prevlen = 0, prevmlen = 0;
137#endif
138
139	/* check invalid arguments. */
140	if (m == NULL)
141		panic("m == NULL in m_pulldown()");
142	if (len > MCLBYTES) {
143		m_freem(m);
144		return NULL;	/* impossible */
145	}
146
147#if defined(PULLDOWN_STAT) && defined(INET6)
148	ip6stat.ip6s_pulldown++;
149#endif
150
151#if defined(PULLDOWN_STAT) && defined(INET6)
152	/* statistics for m_pullup */
153	ip6stat.ip6s_pullup++;
154	if (off + len > MHLEN)
155		ip6stat.ip6s_pullup_fail++;
156	else {
157		int dlen, mlen;
158
159		dlen = (prev == m) ? prevlen : m->m_len;
160		mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
161
162		if (dlen >= off + len)
163			ip6stat.ip6s_pullup--; /* call will not be made! */
164		else if ((m->m_flags & M_EXT) != 0) {
165			ip6stat.ip6s_pullup_alloc++;
166			ip6stat.ip6s_pullup_copy++;
167		} else {
168			if (mlen >= off + len)
169				ip6stat.ip6s_pullup_copy++;
170			else {
171				ip6stat.ip6s_pullup_alloc++;
172				ip6stat.ip6s_pullup_copy++;
173			}
174		}
175
176		prevlen = off + len;
177		prevmlen = MHLEN;
178	}
179
180	/* statistics for m_pullup2 */
181	ip6stat.ip6s_pullup2++;
182	if (off + len > MCLBYTES)
183		ip6stat.ip6s_pullup2_fail++;
184	else {
185		int dlen, mlen;
186
187		dlen = (prev == m) ? prevlen : m->m_len;
188		mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
189		prevlen = off + len;
190		prevmlen = mlen;
191
192		if (dlen >= off + len)
193			ip6stat.ip6s_pullup2--; /* call will not be made! */
194		else if ((m->m_flags & M_EXT) != 0) {
195			ip6stat.ip6s_pullup2_alloc++;
196			ip6stat.ip6s_pullup2_copy++;
197			prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
198		} else {
199			if (mlen >= off + len)
200				ip6stat.ip6s_pullup2_copy++;
201			else {
202				ip6stat.ip6s_pullup2_alloc++;
203				ip6stat.ip6s_pullup2_copy++;
204				prevmlen = (off + len > MHLEN) ? MCLBYTES
205							       : MHLEN;
206			}
207		}
208	}
209
210	prev = m;
211#endif
212
213#ifdef PULLDOWN_DEBUG
214    {
215	struct mbuf *t;
216	printf("before:");
217	for (t = m; t; t = t->m_next)
218		printf(" %d", t->m_len);
219	printf("\n");
220    }
221#endif
222	n = m;
223	while (n != NULL && off > 0) {
224		if (n->m_len > off)
225			break;
226		off -= n->m_len;
227		n = n->m_next;
228	}
229	/* be sure to point non-empty mbuf */
230	while (n != NULL && n->m_len == 0)
231		n = n->m_next;
232	if (!n) {
233		m_freem(m);
234		return NULL;	/* mbuf chain too short */
235	}
236
237	/*
238	 * the target data is on <n, off>.
239	 * if we got enough data on the mbuf "n", we're done.
240	 */
241	if ((off == 0 || offp) && len <= n->m_len - off)
242		goto ok;
243
244#if defined(PULLDOWN_STAT) && defined(INET6)
245	ip6stat.ip6s_pulldown_copy++;
246#endif
247
248	/*
249	 * when len < n->m_len - off and off != 0, it is a special case.
250	 * len bytes from <n, off> sits in single mbuf, but the caller does
251	 * not like the starting position (off).
252	 * chop the current mbuf into two pieces, set off to 0.
253	 */
254	if (len < n->m_len - off) {
255		o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
256		if (o == NULL) {
257			m_freem(m);
258			return NULL;	/* ENOBUFS */
259		}
260		n->m_len = off;
261		o->m_next = n->m_next;
262		n->m_next = o;
263		n = n->m_next;
264		off = 0;
265		goto ok;
266	}
267
268	/*
269	 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
270	 * and construct contiguous mbuf with m_len == len.
271	 * note that hlen + tlen == len, and tlen > 0.
272	 */
273	hlen = n->m_len - off;
274	tlen = len - hlen;
275
276	/*
277	 * ensure that we have enough trailing data on mbuf chain.
278	 * if not, we can do nothing about the chain.
279	 */
280	olen = 0;
281	for (o = n->m_next; o != NULL; o = o->m_next)
282		olen += o->m_len;
283	if (hlen + olen < len) {
284		m_freem(m);
285		return NULL;	/* mbuf chain too short */
286	}
287
288	/*
289	 * easy cases first.
290	 * we need to use m_copydata() to get data from <n->m_next, 0>.
291	 */
292	if ((n->m_flags & M_EXT) == 0)
293		sharedcluster = 0;
294	else {
295		if (n->m_ext.ext_free)
296			sharedcluster = 1;
297		else if (m_mclhasreference(n))
298			sharedcluster = 1;
299		else
300			sharedcluster = 0;
301	}
302	if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
303	 && !sharedcluster) {
304		m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
305		n->m_len += tlen;
306		m_adj(n->m_next, tlen);
307		goto ok;
308	}
309	if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
310	 && !sharedcluster) {
311		n->m_next->m_data -= hlen;
312		n->m_next->m_len += hlen;
313		bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
314		n->m_len -= hlen;
315		n = n->m_next;
316		off = 0;
317		goto ok;
318	}
319
320	/*
321	 * now, we need to do the hard way.  don't m_copy as there's no room
322	 * on both end.
323	 */
324#if defined(PULLDOWN_STAT) && defined(INET6)
325	ip6stat.ip6s_pulldown_alloc++;
326#endif
327	MGET(o, M_DONTWAIT, m->m_type);
328	if (o == NULL) {
329		m_freem(m);
330		return NULL;	/* ENOBUFS */
331	}
332	if (len > MHLEN) {	/* use MHLEN just for safety */
333		MCLGET(o, M_DONTWAIT);
334		if ((o->m_flags & M_EXT) == 0) {
335			m_freem(m);
336			m_free(o);
337			return NULL;	/* ENOBUFS */
338		}
339	}
340	/* get hlen from <n, off> into <o, 0> */
341	o->m_len = hlen;
342	bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
343	n->m_len -= hlen;
344	/* get tlen from <n->m_next, 0> into <o, hlen> */
345	m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
346	o->m_len += tlen;
347	m_adj(n->m_next, tlen);
348	o->m_next = n->m_next;
349	n->m_next = o;
350	n = o;
351	off = 0;
352
353ok:
354#ifdef PULLDOWN_DEBUG
355    {
356	struct mbuf *t;
357	printf("after:");
358	for (t = m; t; t = t->m_next)
359		printf("%c%d", t == n ? '*' : ' ', t->m_len);
360	printf(" (off=%d)\n", off);
361    }
362#endif
363	if (offp)
364		*offp = off;
365	return n;
366}
367
368/* Get a packet tag structure along with specified data following. */
369struct m_tag *
370m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
371{
372	struct m_tag *t;
373
374	if (len < 0)
375		return NULL;
376#ifndef __APPLE__
377	t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
378#else
379	/*MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_TEMP, M_WAITOK);*/
380        if (len + sizeof(struct m_tag) <= MLEN) {
381		struct mbuf *m = m_get(wait, MT_TAG);
382		if (m == NULL)
383			return NULL;
384		t = mtod(m, struct m_tag *);
385        } else if (len + sizeof(struct m_tag) <= MCLBYTES) {
386        	t = (struct m_tag *) m_mclalloc(wait);
387        } else
388                t = NULL;
389#endif
390	if (t == NULL)
391		return NULL;
392	t->m_tag_type = type;
393	t->m_tag_len = len;
394	t->m_tag_id = id;
395	return t;
396}
397
398
399/* Free a packet tag. */
400void
401m_tag_free(struct m_tag *t)
402{
403#if CONFIG_MACF_NET
404	if (t != NULL &&
405	    t->m_tag_id   == KERNEL_MODULE_TAG_ID &&
406	    t->m_tag_type == KERNEL_TAG_TYPE_MACLABEL)
407		mac_mbuf_tag_destroy(t);
408#endif
409#ifndef __APPLE__
410	free(t, M_PACKET_TAGS);
411#else
412	/* FREE(t, M_TEMP); */
413	if (t == NULL)
414		return;
415	if (t->m_tag_len + sizeof(struct m_tag) <= MLEN) {
416		struct mbuf * m = m_dtom(t);
417		m_free(m);
418	} else {
419		MCLFREE((caddr_t)t);
420	}
421#endif
422}
423
424/* Prepend a packet tag. */
425void
426m_tag_prepend(struct mbuf *m, struct m_tag *t)
427{
428	KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
429	SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
430}
431
432/* Unlink a packet tag. */
433void
434m_tag_unlink(struct mbuf *m, struct m_tag *t)
435{
436	KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
437	SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
438}
439
440/* Unlink and free a packet tag. */
441void
442m_tag_delete(struct mbuf *m, struct m_tag *t)
443{
444	KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
445	m_tag_unlink(m, t);
446	m_tag_free(t);
447}
448
449/* Unlink and free a packet tag chain, starting from given tag. */
450void
451m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
452{
453	struct m_tag *p, *q;
454
455	KASSERT(m, ("m_tag_delete_chain: null mbuf"));
456	if (t != NULL)
457		p = t;
458	else
459		p = SLIST_FIRST(&m->m_pkthdr.tags);
460	if (p == NULL)
461		return;
462	while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
463		m_tag_delete(m, q);
464	m_tag_delete(m, p);
465}
466
467/* Find a tag, starting from a given position. */
468struct m_tag *
469m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
470{
471	struct m_tag *p;
472
473	KASSERT(m, ("m_tag_find: null mbuf"));
474	if (t == NULL)
475		p = SLIST_FIRST(&m->m_pkthdr.tags);
476	else
477		p = SLIST_NEXT(t, m_tag_link);
478	while (p != NULL) {
479		if (p->m_tag_id == id && p->m_tag_type == type)
480			return p;
481		p = SLIST_NEXT(p, m_tag_link);
482	}
483	return NULL;
484}
485
486/* Copy a single tag. */
487struct m_tag *
488m_tag_copy(struct m_tag *t, int how)
489{
490	struct m_tag *p;
491
492	KASSERT(t, ("m_tag_copy: null tag"));
493	p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how);
494	if (p == NULL)
495		return (NULL);
496#if CONFIG_MACF_NET
497	/*
498	 * XXXMAC: we should probably pass off the initialization, and
499	 * copying here?  can we hid that KERNEL_TAG_TYPE_MACLABEL is
500	 * special from the mbuf code?
501	 */
502	if (t != NULL &&
503	    t->m_tag_id   == KERNEL_MODULE_TAG_ID &&
504	    t->m_tag_type == KERNEL_TAG_TYPE_MACLABEL) {
505		if (mac_mbuf_tag_init(p, how) != 0) {
506			m_tag_free(p);
507			return (NULL);
508		}
509		mac_mbuf_tag_copy(t, p);
510	} else
511#endif
512	bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
513	return p;
514}
515
516/*
517 * Copy two tag chains. The destination mbuf (to) loses any attached
518 * tags even if the operation fails. This should not be a problem, as
519 * m_tag_copy_chain() is typically called with a newly-allocated
520 * destination mbuf.
521 */
522int
523m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
524{
525	struct m_tag *p, *t, *tprev = NULL;
526
527	KASSERT(to && from,
528		("m_tag_copy: null argument, to %p from %p", to, from));
529	m_tag_delete_chain(to, NULL);
530	SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
531		t = m_tag_copy(p, how);
532		if (t == NULL) {
533			m_tag_delete_chain(to, NULL);
534			return 0;
535		}
536		if (tprev == NULL)
537			SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
538		else {
539			SLIST_INSERT_AFTER(tprev, t, m_tag_link);
540			tprev = t;
541		}
542	}
543	return 1;
544}
545
546/* Initialize tags on an mbuf. */
547void
548m_tag_init(struct mbuf *m)
549{
550	SLIST_INIT(&m->m_pkthdr.tags);
551}
552
553/* Get first tag in chain. */
554struct m_tag *
555m_tag_first(struct mbuf *m)
556{
557	return SLIST_FIRST(&m->m_pkthdr.tags);
558}
559
560/* Get next tag in chain. */
561struct m_tag *
562m_tag_next(__unused struct mbuf *m, struct m_tag *t)
563{
564	return SLIST_NEXT(t, m_tag_link);
565}
566