1/*
2 * Copyright (c) 2000-2011 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#include <sys/mcache.h>
109#if INET6
110#include <netinet/in.h>
111#include <netinet/ip6.h>
112#include <netinet6/ip6_var.h>
113#endif /* INET6 */
114
115#if CONFIG_MACF_NET
116#include <security/mac_framework.h>
117#endif
118
119/*
120 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
121 * packet chain before "off" is kept untouched.
122 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
123 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
124 *
125 * on error return (NULL return value), original "m" will be freed.
126 *
127 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
128 */
129struct mbuf *
130m_pulldown(struct mbuf *m, int off, int len, int *offp)
131{
132	struct mbuf *n, *o;
133	int hlen, tlen, olen;
134	int sharedcluster;
135#if defined(PULLDOWN_STAT) && INET6
136	static struct mbuf *prev = NULL;
137	int prevlen = 0, prevmlen = 0;
138#endif
139
140	/* check invalid arguments. */
141	if (m == NULL)
142		panic("m == NULL in m_pulldown()");
143	if (len > MCLBYTES) {
144		m_freem(m);
145		return NULL;	/* impossible */
146	}
147
148#if defined(PULLDOWN_STAT) && INET6
149	ip6stat.ip6s_pulldown++;
150#endif
151
152#if defined(PULLDOWN_STAT) && INET6
153	/* statistics for m_pullup */
154	ip6stat.ip6s_pullup++;
155	if (off + len > MHLEN)
156		ip6stat.ip6s_pullup_fail++;
157	else {
158		int dlen, mlen;
159
160		dlen = (prev == m) ? prevlen : m->m_len;
161		mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
162
163		if (dlen >= off + len)
164			ip6stat.ip6s_pullup--; /* call will not be made! */
165		else if ((m->m_flags & M_EXT) != 0) {
166			ip6stat.ip6s_pullup_alloc++;
167			ip6stat.ip6s_pullup_copy++;
168		} else {
169			if (mlen >= off + len)
170				ip6stat.ip6s_pullup_copy++;
171			else {
172				ip6stat.ip6s_pullup_alloc++;
173				ip6stat.ip6s_pullup_copy++;
174			}
175		}
176
177		prevlen = off + len;
178		prevmlen = MHLEN;
179	}
180
181	/* statistics for m_pullup2 */
182	ip6stat.ip6s_pullup2++;
183	if (off + len > MCLBYTES)
184		ip6stat.ip6s_pullup2_fail++;
185	else {
186		int dlen, mlen;
187
188		dlen = (prev == m) ? prevlen : m->m_len;
189		mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
190		prevlen = off + len;
191		prevmlen = mlen;
192
193		if (dlen >= off + len)
194			ip6stat.ip6s_pullup2--; /* call will not be made! */
195		else if ((m->m_flags & M_EXT) != 0) {
196			ip6stat.ip6s_pullup2_alloc++;
197			ip6stat.ip6s_pullup2_copy++;
198			prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
199		} else {
200			if (mlen >= off + len)
201				ip6stat.ip6s_pullup2_copy++;
202			else {
203				ip6stat.ip6s_pullup2_alloc++;
204				ip6stat.ip6s_pullup2_copy++;
205				prevmlen = (off + len > MHLEN) ? MCLBYTES
206							       : MHLEN;
207			}
208		}
209	}
210
211	prev = m;
212#endif
213
214#ifdef PULLDOWN_DEBUG
215    {
216	struct mbuf *t;
217	printf("before:");
218	for (t = m; t; t = t->m_next)
219		printf(" %d", t->m_len);
220	printf("\n");
221    }
222#endif
223	n = m;
224	while (n != NULL && off > 0) {
225		if (n->m_len > off)
226			break;
227		off -= n->m_len;
228		n = n->m_next;
229	}
230	/* be sure to point non-empty mbuf */
231	while (n != NULL && n->m_len == 0)
232		n = n->m_next;
233	if (!n) {
234		m_freem(m);
235		return NULL;	/* mbuf chain too short */
236	}
237
238	/*
239	 * the target data is on <n, off>.
240	 * if we got enough data on the mbuf "n", we're done.
241	 */
242	if ((off == 0 || offp) && len <= n->m_len - off)
243		goto ok;
244
245#if defined(PULLDOWN_STAT) && INET6
246	ip6stat.ip6s_pulldown_copy++;
247#endif
248
249	/*
250	 * when len < n->m_len - off and off != 0, it is a special case.
251	 * len bytes from <n, off> sits in single mbuf, but the caller does
252	 * not like the starting position (off).
253	 * chop the current mbuf into two pieces, set off to 0.
254	 */
255	if (len < n->m_len - off) {
256		o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
257		if (o == NULL) {
258			m_freem(m);
259			return NULL;	/* ENOBUFS */
260		}
261		n->m_len = off;
262		o->m_next = n->m_next;
263		n->m_next = o;
264		n = n->m_next;
265		off = 0;
266		goto ok;
267	}
268
269	/*
270	 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
271	 * and construct contiguous mbuf with m_len == len.
272	 * note that hlen + tlen == len, and tlen > 0.
273	 */
274	hlen = n->m_len - off;
275	tlen = len - hlen;
276
277	/*
278	 * ensure that we have enough trailing data on mbuf chain.
279	 * if not, we can do nothing about the chain.
280	 */
281	olen = 0;
282	for (o = n->m_next; o != NULL; o = o->m_next)
283		olen += o->m_len;
284	if (hlen + olen < len) {
285		m_freem(m);
286		return NULL;	/* mbuf chain too short */
287	}
288
289	/*
290	 * easy cases first.
291	 * we need to use m_copydata() to get data from <n->m_next, 0>.
292	 */
293	if ((n->m_flags & M_EXT) == 0)
294		sharedcluster = 0;
295	else {
296		if (n->m_ext.ext_free)
297			sharedcluster = 1;
298		else if (m_mclhasreference(n))
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) && 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
354ok:
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 * Create and return an m_tag, either by re-using space in a previous tag
371 * or by allocating a new mbuf/cluster
372 */
373struct m_tag *
374m_tag_create(u_int32_t id, u_int16_t type, int len, int wait, struct mbuf *buf)
375{
376	struct m_tag *t = NULL;
377	struct m_tag *p;
378
379	if (len < 0)
380		return (NULL);
381
382	if (len + sizeof (struct m_tag) + sizeof (struct m_taghdr) > MLEN)
383		return (m_tag_alloc(id, type, len, wait));
384
385	/*
386	 * We've exhausted all external cases. Now, go through the m_tag
387	 * chain and see if we can fit it in any of them.
388	 * If not (t == NULL), call m_tag_alloc to store it in a new mbuf.
389	 */
390	p = SLIST_FIRST(&buf->m_pkthdr.tags);
391	while(p != NULL) {
392		/* 2KCL m_tag */
393		if (M_TAG_ALIGN(p->m_tag_len) +
394		    sizeof (struct m_taghdr) > MLEN) {
395			p = SLIST_NEXT(p, m_tag_link);
396			continue;
397		}
398
399		VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN);
400
401		struct mbuf *m = m_dtom(p);
402		struct m_taghdr *hdr = (struct m_taghdr *)(void *)m->m_data;
403
404		VERIFY(IS_P2ALIGNED(hdr + 1, sizeof (u_int64_t)));
405		VERIFY(m->m_flags & M_TAGHDR && !(m->m_flags & M_EXT));
406
407		/* The mbuf can store this m_tag */
408		if (M_TAG_ALIGN(len) <= MLEN - m->m_len) {
409			t = (struct m_tag *)(void *)(m->m_data + m->m_len);
410			VERIFY(IS_P2ALIGNED(t, sizeof (u_int64_t)));
411			hdr->refcnt++;
412			m->m_len += M_TAG_ALIGN(len);
413			VERIFY(m->m_len <= MLEN);
414			break;
415		}
416
417		p = SLIST_NEXT(p, m_tag_link);
418	}
419
420	if (t == NULL)
421		return (m_tag_alloc(id, type, len, wait));
422
423	t->m_tag_cookie = M_TAG_VALID_PATTERN;
424	t->m_tag_type = type;
425	t->m_tag_len = len;
426	t->m_tag_id = id;
427	if (len > 0)
428		bzero(t + 1, len);
429	return (t);
430}
431
432/* Get a packet tag structure along with specified data following. */
433struct m_tag *
434m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
435{
436	struct m_tag *t;
437
438	if (len < 0)
439		return (NULL);
440
441        if (M_TAG_ALIGN(len) + sizeof (struct m_taghdr) <= MLEN) {
442		struct mbuf *m = m_get(wait, MT_TAG);
443		struct m_taghdr *hdr;
444
445		if (m == NULL)
446			return (NULL);
447
448		m->m_flags |= M_TAGHDR;
449
450		hdr = (struct m_taghdr *)(void *)m->m_data;
451		VERIFY(IS_P2ALIGNED(hdr + 1, sizeof (u_int64_t)));
452		hdr->refcnt = 1;
453		m->m_len += sizeof (struct m_taghdr);
454		t = (struct m_tag *)(void *)(m->m_data + m->m_len);
455		VERIFY(IS_P2ALIGNED(t, sizeof (u_int64_t)));
456		m->m_len += M_TAG_ALIGN(len);
457		VERIFY(m->m_len <= MLEN);
458        } else if (len + sizeof (struct m_tag) <= MCLBYTES) {
459		t = (struct m_tag *)(void *)m_mclalloc(wait);
460        } else {
461                t = NULL;
462	}
463
464	if (t == NULL)
465		return (NULL);
466
467	VERIFY(IS_P2ALIGNED(t, sizeof (u_int64_t)));
468	t->m_tag_cookie = M_TAG_VALID_PATTERN;
469	t->m_tag_type = type;
470	t->m_tag_len = len;
471	t->m_tag_id = id;
472	if (len > 0)
473		bzero(t + 1, len);
474	return (t);
475}
476
477
478/* Free a packet tag. */
479void
480m_tag_free(struct m_tag *t)
481{
482#if CONFIG_MACF_NET
483	if (t != NULL &&
484	    t->m_tag_id   == KERNEL_MODULE_TAG_ID &&
485	    t->m_tag_type == KERNEL_TAG_TYPE_MACLABEL)
486		mac_mbuf_tag_destroy(t);
487#endif
488#if INET6
489	if (t != NULL &&
490	    t->m_tag_id   == KERNEL_MODULE_TAG_ID &&
491	    t->m_tag_type == KERNEL_TAG_TYPE_INET6 &&
492	    t->m_tag_len  == sizeof (struct ip6aux))
493		ip6_destroyaux((struct ip6aux *)(t + 1));
494#endif /* INET6 */
495	if (t == NULL)
496		return;
497
498	VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN);
499
500	if (M_TAG_ALIGN(t->m_tag_len) + sizeof (struct m_taghdr) <= MLEN) {
501		struct mbuf * m = m_dtom(t);
502		VERIFY(m->m_flags & M_TAGHDR);
503		struct m_taghdr *hdr = (struct m_taghdr *)(void *)m->m_data;
504
505		VERIFY(IS_P2ALIGNED(hdr + 1, sizeof (u_int64_t)));
506
507		/* No other tags in this mbuf */
508		if(--hdr->refcnt == 0) {
509			m_free(m);
510			return;
511		}
512
513		/* Pattern-fill the header */
514		u_int64_t *fill_ptr = (u_int64_t *)t;
515		u_int64_t *end_ptr = (u_int64_t *)(t + 1);
516		while (fill_ptr < end_ptr) {
517			*fill_ptr = M_TAG_FREE_PATTERN;
518			fill_ptr++;
519		}
520	} else {
521		m_mclfree((caddr_t)t);
522	}
523}
524
525/* Prepend a packet tag. */
526void
527m_tag_prepend(struct mbuf *m, struct m_tag *t)
528{
529	VERIFY(m != NULL && t != NULL);
530
531	SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
532}
533
534/* Unlink a packet tag. */
535void
536m_tag_unlink(struct mbuf *m, struct m_tag *t)
537{
538	VERIFY(m != NULL && t != NULL);
539	VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN);
540
541	SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
542}
543
544/* Unlink and free a packet tag. */
545void
546m_tag_delete(struct mbuf *m, struct m_tag *t)
547{
548	VERIFY(m != NULL && t != NULL);
549
550	m_tag_unlink(m, t);
551	m_tag_free(t);
552}
553
554/* Unlink and free a packet tag chain, starting from given tag. */
555void
556m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
557{
558	struct m_tag *p, *q;
559
560	VERIFY(m != NULL);
561
562	if (t != NULL) {
563		p = t;
564	} else {
565		p = SLIST_FIRST(&m->m_pkthdr.tags);
566	}
567	if (p == NULL)
568		return;
569
570	VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN);
571	while ((q = SLIST_NEXT(p, m_tag_link)) != NULL) {
572		VERIFY(q->m_tag_cookie == M_TAG_VALID_PATTERN);
573		m_tag_delete(m, q);
574	}
575	m_tag_delete(m, p);
576}
577
578/* Find a tag, starting from a given position. */
579struct m_tag *
580m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
581{
582	struct m_tag *p;
583
584	VERIFY(m != NULL);
585
586	if (t == NULL) {
587		p = SLIST_FIRST(&m->m_pkthdr.tags);
588	} else {
589		VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN);
590		p = SLIST_NEXT(t, m_tag_link);
591	}
592	while (p != NULL) {
593		VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN);
594		if (p->m_tag_id == id && p->m_tag_type == type)
595			return (p);
596		p = SLIST_NEXT(p, m_tag_link);
597	}
598	return (NULL);
599}
600
601/* Copy a single tag. */
602struct m_tag *
603m_tag_copy(struct m_tag *t, int how)
604{
605	struct m_tag *p;
606
607	VERIFY(t != NULL);
608
609	p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how);
610	if (p == NULL)
611		return (NULL);
612#if CONFIG_MACF_NET
613	/*
614	 * XXXMAC: we should probably pass off the initialization, and
615	 * copying here?  can we hid that KERNEL_TAG_TYPE_MACLABEL is
616	 * special from the mbuf code?
617	 */
618	if (t != NULL &&
619	    t->m_tag_id   == KERNEL_MODULE_TAG_ID &&
620	    t->m_tag_type == KERNEL_TAG_TYPE_MACLABEL) {
621		if (mac_mbuf_tag_init(p, how) != 0) {
622			m_tag_free(p);
623			return (NULL);
624		}
625		mac_mbuf_tag_copy(t, p);
626	} else
627#endif
628#if INET6
629	if (t != NULL &&
630	    t->m_tag_id   == KERNEL_MODULE_TAG_ID &&
631	    t->m_tag_type == KERNEL_TAG_TYPE_INET6 &&
632	    t->m_tag_len  == sizeof (struct ip6aux)) {
633		ip6_copyaux((struct ip6aux *)(t + 1), (struct ip6aux *)(p + 1));
634	} else
635#endif /* INET6 */
636	bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
637	return (p);
638}
639
640/*
641 * Copy two tag chains. The destination mbuf (to) loses any attached
642 * tags even if the operation fails. This should not be a problem, as
643 * m_tag_copy_chain() is typically called with a newly-allocated
644 * destination mbuf.
645 */
646int
647m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
648{
649	struct m_tag *p, *t, *tprev = NULL;
650
651	VERIFY(to != NULL && from != NULL);
652
653	m_tag_delete_chain(to, NULL);
654	SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
655		VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN);
656		t = m_tag_copy(p, how);
657		if (t == NULL) {
658			m_tag_delete_chain(to, NULL);
659			return (0);
660		}
661		if (tprev == NULL) {
662			SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
663		} else {
664			SLIST_INSERT_AFTER(tprev, t, m_tag_link);
665			tprev = t;
666		}
667	}
668	return (1);
669}
670
671/* Initialize tags on an mbuf. */
672void
673m_tag_init(struct mbuf *m)
674{
675	VERIFY(m != NULL);
676
677	SLIST_INIT(&m->m_pkthdr.tags);
678	bzero(&m->m_pkthdr.pf_mtag, sizeof (m->m_pkthdr.pf_mtag));
679	bzero(&m->m_pkthdr.tcp_mtag, sizeof (m->m_pkthdr.tcp_mtag));
680}
681
682/* Get first tag in chain. */
683struct m_tag *
684m_tag_first(struct mbuf *m)
685{
686	VERIFY(m != NULL);
687
688	return (SLIST_FIRST(&m->m_pkthdr.tags));
689}
690
691/* Get next tag in chain. */
692struct m_tag *
693m_tag_next(struct mbuf *m, struct m_tag *t)
694{
695#pragma unused(m)
696	VERIFY(t != NULL);
697	VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN);
698
699	return (SLIST_NEXT(t, m_tag_link));
700}
701
702int
703m_set_traffic_class(struct mbuf *m, mbuf_traffic_class_t tc)
704{
705	u_int32_t val = MBUF_TC2SCVAL(tc);	/* just the val portion */
706
707	return (m_set_service_class(m, m_service_class_from_val(val)));
708}
709
710mbuf_traffic_class_t
711m_get_traffic_class(struct mbuf *m)
712{
713	return (MBUF_SC2TC(m_get_service_class(m)));
714}
715
716void
717m_service_class_init(struct mbuf *m)
718{
719	if (m->m_flags & M_PKTHDR)
720		(void) m_set_service_class(m, MBUF_SC_BE);
721}
722
723int
724m_set_service_class(struct mbuf *m, mbuf_svc_class_t sc)
725{
726	int error = 0;
727
728	VERIFY(m->m_flags & M_PKTHDR);
729
730	if (MBUF_VALID_SC(sc))
731		m->m_pkthdr.svc = sc;
732	else
733		error = EINVAL;
734
735	return (error);
736}
737
738mbuf_svc_class_t
739m_get_service_class(struct mbuf *m)
740{
741	mbuf_svc_class_t sc;
742
743	VERIFY(m->m_flags & M_PKTHDR);
744
745	if (MBUF_VALID_SC(m->m_pkthdr.svc))
746		sc = m->m_pkthdr.svc;
747	else
748		sc = MBUF_SC_BE;
749
750	return (sc);
751}
752
753mbuf_svc_class_t
754m_service_class_from_idx(u_int32_t i)
755{
756	mbuf_svc_class_t sc = MBUF_SC_BE;
757
758	switch (i) {
759	case SCIDX_BK_SYS:
760		return (MBUF_SC_BK_SYS);
761
762	case SCIDX_BK:
763		return (MBUF_SC_BK);
764
765	case SCIDX_BE:
766		return (MBUF_SC_BE);
767
768	case SCIDX_RD:
769		return (MBUF_SC_RD);
770
771	case SCIDX_OAM:
772		return (MBUF_SC_OAM);
773
774	case SCIDX_AV:
775		return (MBUF_SC_AV);
776
777	case SCIDX_RV:
778		return (MBUF_SC_RV);
779
780	case SCIDX_VI:
781		return (MBUF_SC_VI);
782
783	case SCIDX_VO:
784		return (MBUF_SC_VO);
785
786	case SCIDX_CTL:
787		return (MBUF_SC_CTL);
788
789	default:
790		break;
791	}
792
793	VERIFY(0);
794	/* NOTREACHED */
795	return (sc);
796}
797
798mbuf_svc_class_t
799m_service_class_from_val(u_int32_t v)
800{
801	mbuf_svc_class_t sc = MBUF_SC_BE;
802
803	switch (v) {
804	case SCVAL_BK_SYS:
805		return (MBUF_SC_BK_SYS);
806
807	case SCVAL_BK:
808		return (MBUF_SC_BK);
809
810	case SCVAL_BE:
811		return (MBUF_SC_BE);
812
813	case SCVAL_RD:
814		return (MBUF_SC_RD);
815
816	case SCVAL_OAM:
817		return (MBUF_SC_OAM);
818
819	case SCVAL_AV:
820		return (MBUF_SC_AV);
821
822	case SCVAL_RV:
823		return (MBUF_SC_RV);
824
825	case SCVAL_VI:
826		return (MBUF_SC_VI);
827
828	case SCVAL_VO:
829		return (MBUF_SC_VO);
830
831	case SCVAL_CTL:
832		return (MBUF_SC_CTL);
833
834	default:
835		break;
836	}
837
838	VERIFY(0);
839	/* NOTREACHED */
840	return (sc);
841}
842