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