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