1 /* $NetBSD: ip_encap.c,v 1.53 2016/04/26 08:44:44 ozaki-r Exp $ */ 2 /* $KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 /* 33 * My grandfather said that there's a devil inside tunnelling technology... 34 * 35 * We have surprisingly many protocols that want packets with IP protocol 36 * #4 or #41. Here's a list of protocols that want protocol #41: 37 * RFC1933 configured tunnel 38 * RFC1933 automatic tunnel 39 * RFC2401 IPsec tunnel 40 * RFC2473 IPv6 generic packet tunnelling 41 * RFC2529 6over4 tunnel 42 * RFC3056 6to4 tunnel 43 * isatap tunnel 44 * mobile-ip6 (uses RFC2473) 45 * Here's a list of protocol that want protocol #4: 46 * RFC1853 IPv4-in-IPv4 tunnelling 47 * RFC2003 IPv4 encapsulation within IPv4 48 * RFC2344 reverse tunnelling for mobile-ip4 49 * RFC2401 IPsec tunnel 50 * Well, what can I say. They impose different en/decapsulation mechanism 51 * from each other, so they need separate protocol handler. The only one 52 * we can easily determine by protocol # is IPsec, which always has 53 * AH/ESP/IPComp header right after outer IP header. 54 * 55 * So, clearly good old protosw does not work for protocol #4 and #41. 56 * The code will let you match protocol via src/dst address pair. 57 */ 58 /* XXX is M_NETADDR correct? */ 59 60 /* 61 * The code will use radix table for tunnel lookup, for 62 * tunnels registered with encap_attach() with a addr/mask pair. 63 * Faster on machines with thousands of tunnel registerations (= interfaces). 64 * 65 * The code assumes that radix table code can handle non-continuous netmask, 66 * as it will pass radix table memory region with (src + dst) sockaddr pair. 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.53 2016/04/26 08:44:44 ozaki-r Exp $"); 71 72 #ifdef _KERNEL_OPT 73 #include "opt_mrouting.h" 74 #include "opt_inet.h" 75 #endif 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/socket.h> 80 #include <sys/sockio.h> 81 #include <sys/mbuf.h> 82 #include <sys/errno.h> 83 #include <sys/queue.h> 84 #include <sys/kmem.h> 85 86 #include <net/if.h> 87 88 #include <netinet/in.h> 89 #include <netinet/in_systm.h> 90 #include <netinet/ip.h> 91 #include <netinet/ip_var.h> 92 #include <netinet/ip_encap.h> 93 #ifdef MROUTING 94 #include <netinet/ip_mroute.h> 95 #endif /* MROUTING */ 96 97 #ifdef INET6 98 #include <netinet/ip6.h> 99 #include <netinet6/ip6_var.h> 100 #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */ 101 #include <netinet6/in6_var.h> 102 #include <netinet6/in6_pcb.h> 103 #include <netinet/icmp6.h> 104 #endif 105 106 #include <net/net_osdep.h> 107 108 enum direction { INBOUND, OUTBOUND }; 109 110 #ifdef INET 111 static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction); 112 #endif 113 #ifdef INET6 114 static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction); 115 #endif 116 static int encap_add(struct encaptab *); 117 static int encap_remove(struct encaptab *); 118 static int encap_afcheck(int, const struct sockaddr *, const struct sockaddr *); 119 static struct radix_node_head *encap_rnh(int); 120 static int mask_matchlen(const struct sockaddr *); 121 static void encap_fillarg(struct mbuf *, const struct encaptab *); 122 123 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); 124 125 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */ 126 127 void 128 encap_init(void) 129 { 130 static int initialized = 0; 131 132 if (initialized) 133 return; 134 initialized++; 135 #if 0 136 /* 137 * we cannot use LIST_INIT() here, since drivers may want to call 138 * encap_attach(), on driver attach. encap_init() will be called 139 * on AF_INET{,6} initialization, which happens after driver 140 * initialization - using LIST_INIT() here can nuke encap_attach() 141 * from drivers. 142 */ 143 LIST_INIT(&encaptab); 144 #endif 145 146 /* 147 * initialize radix lookup table when the radix subsystem is inited. 148 */ 149 rn_delayedinit((void *)&encap_head[0], 150 sizeof(struct sockaddr_pack) << 3); 151 #ifdef INET6 152 rn_delayedinit((void *)&encap_head[1], 153 sizeof(struct sockaddr_pack) << 3); 154 #endif 155 } 156 157 #ifdef INET 158 static struct encaptab * 159 encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir) 160 { 161 struct ip *ip; 162 struct ip_pack4 pack; 163 struct encaptab *ep, *match; 164 int prio, matchprio; 165 struct radix_node_head *rnh = encap_rnh(AF_INET); 166 struct radix_node *rn; 167 168 KASSERT(m->m_len >= sizeof(*ip)); 169 170 ip = mtod(m, struct ip *); 171 172 memset(&pack, 0, sizeof(pack)); 173 pack.p.sp_len = sizeof(pack); 174 pack.mine.sin_family = pack.yours.sin_family = AF_INET; 175 pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in); 176 if (dir == INBOUND) { 177 pack.mine.sin_addr = ip->ip_dst; 178 pack.yours.sin_addr = ip->ip_src; 179 } else { 180 pack.mine.sin_addr = ip->ip_src; 181 pack.yours.sin_addr = ip->ip_dst; 182 } 183 184 match = NULL; 185 matchprio = 0; 186 187 rn = rnh->rnh_matchaddr((void *)&pack, rnh); 188 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 189 match = (struct encaptab *)rn; 190 matchprio = mask_matchlen(match->srcmask) + 191 mask_matchlen(match->dstmask); 192 } 193 194 LIST_FOREACH(ep, &encaptab, chain) { 195 if (ep->af != AF_INET) 196 continue; 197 if (ep->proto >= 0 && ep->proto != proto) 198 continue; 199 if (ep->func) 200 prio = (*ep->func)(m, off, proto, ep->arg); 201 else 202 continue; 203 204 /* 205 * We prioritize the matches by using bit length of the 206 * matches. mask_match() and user-supplied matching function 207 * should return the bit length of the matches (for example, 208 * if both src/dst are matched for IPv4, 64 should be returned). 209 * 0 or negative return value means "it did not match". 210 * 211 * The question is, since we have two "mask" portion, we 212 * cannot really define total order between entries. 213 * For example, which of these should be preferred? 214 * mask_match() returns 48 (32 + 16) for both of them. 215 * src=3ffe::/16, dst=3ffe:501::/32 216 * src=3ffe:501::/32, dst=3ffe::/16 217 * 218 * We need to loop through all the possible candidates 219 * to get the best match - the search takes O(n) for 220 * n attachments (i.e. interfaces). 221 * 222 * For radix-based lookup, I guess source takes precedence. 223 * See rn_{refines,lexobetter} for the correct answer. 224 */ 225 if (prio <= 0) 226 continue; 227 if (prio > matchprio) { 228 matchprio = prio; 229 match = ep; 230 } 231 } 232 233 return match; 234 } 235 236 void 237 encap4_input(struct mbuf *m, ...) 238 { 239 int off, proto; 240 va_list ap; 241 const struct encapsw *esw; 242 struct encaptab *match; 243 244 va_start(ap, m); 245 off = va_arg(ap, int); 246 proto = va_arg(ap, int); 247 va_end(ap); 248 249 match = encap4_lookup(m, off, proto, INBOUND); 250 251 if (match) { 252 /* found a match, "match" has the best one */ 253 esw = match->esw; 254 if (esw && esw->encapsw4.pr_input) { 255 encap_fillarg(m, match); 256 (*esw->encapsw4.pr_input)(m, off, proto); 257 } else 258 m_freem(m); 259 return; 260 } 261 262 /* last resort: inject to raw socket */ 263 rip_input(m, off, proto); 264 } 265 #endif 266 267 #ifdef INET6 268 static struct encaptab * 269 encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir) 270 { 271 struct ip6_hdr *ip6; 272 struct ip_pack6 pack; 273 int prio, matchprio; 274 struct encaptab *ep, *match; 275 struct radix_node_head *rnh = encap_rnh(AF_INET6); 276 struct radix_node *rn; 277 278 KASSERT(m->m_len >= sizeof(*ip6)); 279 280 ip6 = mtod(m, struct ip6_hdr *); 281 282 memset(&pack, 0, sizeof(pack)); 283 pack.p.sp_len = sizeof(pack); 284 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6; 285 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6); 286 if (dir == INBOUND) { 287 pack.mine.sin6_addr = ip6->ip6_dst; 288 pack.yours.sin6_addr = ip6->ip6_src; 289 } else { 290 pack.mine.sin6_addr = ip6->ip6_src; 291 pack.yours.sin6_addr = ip6->ip6_dst; 292 } 293 294 match = NULL; 295 matchprio = 0; 296 297 rn = rnh->rnh_matchaddr((void *)&pack, rnh); 298 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 299 match = (struct encaptab *)rn; 300 matchprio = mask_matchlen(match->srcmask) + 301 mask_matchlen(match->dstmask); 302 } 303 304 LIST_FOREACH(ep, &encaptab, chain) { 305 if (ep->af != AF_INET6) 306 continue; 307 if (ep->proto >= 0 && ep->proto != proto) 308 continue; 309 if (ep->func) 310 prio = (*ep->func)(m, off, proto, ep->arg); 311 else 312 continue; 313 314 /* see encap4_lookup() for issues here */ 315 if (prio <= 0) 316 continue; 317 if (prio > matchprio) { 318 matchprio = prio; 319 match = ep; 320 } 321 } 322 323 return match; 324 } 325 326 int 327 encap6_input(struct mbuf **mp, int *offp, int proto) 328 { 329 struct mbuf *m = *mp; 330 const struct encapsw *esw; 331 struct encaptab *match; 332 333 match = encap6_lookup(m, *offp, proto, INBOUND); 334 335 if (match) { 336 /* found a match */ 337 esw = match->esw; 338 if (esw && esw->encapsw6.pr_input) { 339 encap_fillarg(m, match); 340 return (*esw->encapsw6.pr_input)(mp, offp, proto); 341 } else { 342 m_freem(m); 343 return IPPROTO_DONE; 344 } 345 } 346 347 /* last resort: inject to raw socket */ 348 return rip6_input(mp, offp, proto); 349 } 350 #endif 351 352 static int 353 encap_add(struct encaptab *ep) 354 { 355 struct radix_node_head *rnh = encap_rnh(ep->af); 356 int error = 0; 357 358 LIST_INSERT_HEAD(&encaptab, ep, chain); 359 if (!ep->func && rnh) { 360 if (!rnh->rnh_addaddr((void *)ep->addrpack, 361 (void *)ep->maskpack, rnh, ep->nodes)) { 362 error = EEXIST; 363 goto fail; 364 } 365 } 366 return error; 367 368 fail: 369 LIST_REMOVE(ep, chain); 370 return error; 371 } 372 373 static int 374 encap_remove(struct encaptab *ep) 375 { 376 struct radix_node_head *rnh = encap_rnh(ep->af); 377 int error = 0; 378 379 LIST_REMOVE(ep, chain); 380 if (!ep->func && rnh) { 381 if (!rnh->rnh_deladdr((void *)ep->addrpack, 382 (void *)ep->maskpack, rnh)) 383 error = ESRCH; 384 } 385 return error; 386 } 387 388 static int 389 encap_afcheck(int af, const struct sockaddr *sp, const struct sockaddr *dp) 390 { 391 if (sp && dp) { 392 if (sp->sa_len != dp->sa_len) 393 return EINVAL; 394 if (af != sp->sa_family || af != dp->sa_family) 395 return EINVAL; 396 } else if (!sp && !dp) 397 ; 398 else 399 return EINVAL; 400 401 switch (af) { 402 case AF_INET: 403 if (sp && sp->sa_len != sizeof(struct sockaddr_in)) 404 return EINVAL; 405 if (dp && dp->sa_len != sizeof(struct sockaddr_in)) 406 return EINVAL; 407 break; 408 #ifdef INET6 409 case AF_INET6: 410 if (sp && sp->sa_len != sizeof(struct sockaddr_in6)) 411 return EINVAL; 412 if (dp && dp->sa_len != sizeof(struct sockaddr_in6)) 413 return EINVAL; 414 break; 415 #endif 416 default: 417 return EAFNOSUPPORT; 418 } 419 420 return 0; 421 } 422 423 /* 424 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side. 425 * length of mask (sm and dm) is assumed to be same as sp/dp. 426 * Return value will be necessary as input (cookie) for encap_detach(). 427 */ 428 const struct encaptab * 429 encap_attach(int af, int proto, 430 const struct sockaddr *sp, const struct sockaddr *sm, 431 const struct sockaddr *dp, const struct sockaddr *dm, 432 const struct encapsw *esw, void *arg) 433 { 434 struct encaptab *ep; 435 int error; 436 int s; 437 size_t l; 438 struct ip_pack4 *pack4; 439 #ifdef INET6 440 struct ip_pack6 *pack6; 441 #endif 442 443 s = splsoftnet(); 444 /* sanity check on args */ 445 error = encap_afcheck(af, sp, dp); 446 if (error) 447 goto fail; 448 449 /* check if anyone have already attached with exactly same config */ 450 LIST_FOREACH(ep, &encaptab, chain) { 451 if (ep->af != af) 452 continue; 453 if (ep->proto != proto) 454 continue; 455 if (ep->func) 456 continue; 457 458 KASSERT(ep->src != NULL); 459 KASSERT(ep->dst != NULL); 460 KASSERT(ep->srcmask != NULL); 461 KASSERT(ep->dstmask != NULL); 462 463 if (ep->src->sa_len != sp->sa_len || 464 memcmp(ep->src, sp, sp->sa_len) != 0 || 465 memcmp(ep->srcmask, sm, sp->sa_len) != 0) 466 continue; 467 if (ep->dst->sa_len != dp->sa_len || 468 memcmp(ep->dst, dp, dp->sa_len) != 0 || 469 memcmp(ep->dstmask, dm, dp->sa_len) != 0) 470 continue; 471 472 error = EEXIST; 473 goto fail; 474 } 475 476 switch (af) { 477 case AF_INET: 478 l = sizeof(*pack4); 479 break; 480 #ifdef INET6 481 case AF_INET6: 482 l = sizeof(*pack6); 483 break; 484 #endif 485 default: 486 goto fail; 487 } 488 489 /* M_NETADDR ok? */ 490 ep = kmem_zalloc(sizeof(*ep), KM_NOSLEEP); 491 if (ep == NULL) { 492 error = ENOBUFS; 493 goto fail; 494 } 495 ep->addrpack = kmem_zalloc(l, KM_NOSLEEP); 496 if (ep->addrpack == NULL) { 497 error = ENOBUFS; 498 goto gc; 499 } 500 ep->maskpack = kmem_zalloc(l, KM_NOSLEEP); 501 if (ep->maskpack == NULL) { 502 error = ENOBUFS; 503 goto gc; 504 } 505 506 ep->af = af; 507 ep->proto = proto; 508 ep->addrpack->sa_len = l & 0xff; 509 ep->maskpack->sa_len = l & 0xff; 510 switch (af) { 511 case AF_INET: 512 pack4 = (struct ip_pack4 *)ep->addrpack; 513 ep->src = (struct sockaddr *)&pack4->mine; 514 ep->dst = (struct sockaddr *)&pack4->yours; 515 pack4 = (struct ip_pack4 *)ep->maskpack; 516 ep->srcmask = (struct sockaddr *)&pack4->mine; 517 ep->dstmask = (struct sockaddr *)&pack4->yours; 518 break; 519 #ifdef INET6 520 case AF_INET6: 521 pack6 = (struct ip_pack6 *)ep->addrpack; 522 ep->src = (struct sockaddr *)&pack6->mine; 523 ep->dst = (struct sockaddr *)&pack6->yours; 524 pack6 = (struct ip_pack6 *)ep->maskpack; 525 ep->srcmask = (struct sockaddr *)&pack6->mine; 526 ep->dstmask = (struct sockaddr *)&pack6->yours; 527 break; 528 #endif 529 } 530 531 memcpy(ep->src, sp, sp->sa_len); 532 memcpy(ep->srcmask, sm, sp->sa_len); 533 memcpy(ep->dst, dp, dp->sa_len); 534 memcpy(ep->dstmask, dm, dp->sa_len); 535 ep->esw = esw; 536 ep->arg = arg; 537 538 error = encap_add(ep); 539 if (error) 540 goto gc; 541 542 error = 0; 543 splx(s); 544 return ep; 545 546 gc: 547 if (ep->addrpack) 548 kmem_free(ep->addrpack, l); 549 if (ep->maskpack) 550 kmem_free(ep->maskpack, l); 551 if (ep) 552 kmem_free(ep, sizeof(*ep)); 553 fail: 554 splx(s); 555 return NULL; 556 } 557 558 const struct encaptab * 559 encap_attach_func(int af, int proto, 560 int (*func)(struct mbuf *, int, int, void *), 561 const struct encapsw *esw, void *arg) 562 { 563 struct encaptab *ep; 564 int error; 565 int s; 566 567 s = splsoftnet(); 568 /* sanity check on args */ 569 if (!func) { 570 error = EINVAL; 571 goto fail; 572 } 573 574 error = encap_afcheck(af, NULL, NULL); 575 if (error) 576 goto fail; 577 578 ep = kmem_alloc(sizeof(*ep), KM_NOSLEEP); /*XXX*/ 579 if (ep == NULL) { 580 error = ENOBUFS; 581 goto fail; 582 } 583 memset(ep, 0, sizeof(*ep)); 584 585 ep->af = af; 586 ep->proto = proto; 587 ep->func = func; 588 ep->esw = esw; 589 ep->arg = arg; 590 591 error = encap_add(ep); 592 if (error) 593 goto fail; 594 595 error = 0; 596 splx(s); 597 return ep; 598 599 fail: 600 splx(s); 601 return NULL; 602 } 603 604 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */ 605 606 #ifdef INET6 607 void * 608 encap6_ctlinput(int cmd, const struct sockaddr *sa, void *d0) 609 { 610 void *d = d0; 611 struct ip6_hdr *ip6; 612 struct mbuf *m; 613 int off; 614 struct ip6ctlparam *ip6cp = NULL; 615 int nxt; 616 struct encaptab *ep; 617 const struct encapsw *esw; 618 619 if (sa->sa_family != AF_INET6 || 620 sa->sa_len != sizeof(struct sockaddr_in6)) 621 return NULL; 622 623 if ((unsigned)cmd >= PRC_NCMDS) 624 return NULL; 625 if (cmd == PRC_HOSTDEAD) 626 d = NULL; 627 else if (cmd == PRC_MSGSIZE) 628 ; /* special code is present, see below */ 629 else if (inet6ctlerrmap[cmd] == 0) 630 return NULL; 631 632 /* if the parameter is from icmp6, decode it. */ 633 if (d != NULL) { 634 ip6cp = (struct ip6ctlparam *)d; 635 m = ip6cp->ip6c_m; 636 ip6 = ip6cp->ip6c_ip6; 637 off = ip6cp->ip6c_off; 638 nxt = ip6cp->ip6c_nxt; 639 640 if (ip6 && cmd == PRC_MSGSIZE) { 641 int valid = 0; 642 struct encaptab *match; 643 644 /* 645 * Check to see if we have a valid encap configuration. 646 */ 647 match = encap6_lookup(m, off, nxt, OUTBOUND); 648 if (match) 649 valid++; 650 651 /* 652 * Depending on the value of "valid" and routing table 653 * size (mtudisc_{hi,lo}wat), we will: 654 * - recalcurate the new MTU and create the 655 * corresponding routing entry, or 656 * - ignore the MTU change notification. 657 */ 658 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 659 } 660 } else { 661 m = NULL; 662 ip6 = NULL; 663 nxt = -1; 664 } 665 666 /* inform all listeners */ 667 LIST_FOREACH(ep, &encaptab, chain) { 668 if (ep->af != AF_INET6) 669 continue; 670 if (ep->proto >= 0 && ep->proto != nxt) 671 continue; 672 673 /* should optimize by looking at address pairs */ 674 675 /* XXX need to pass ep->arg or ep itself to listeners */ 676 esw = ep->esw; 677 if (esw && esw->encapsw6.pr_ctlinput) { 678 (*esw->encapsw6.pr_ctlinput)(cmd, sa, d, ep->arg); 679 } 680 } 681 682 rip6_ctlinput(cmd, sa, d0); 683 return NULL; 684 } 685 #endif 686 687 int 688 encap_detach(const struct encaptab *cookie) 689 { 690 const struct encaptab *ep = cookie; 691 struct encaptab *p, *np; 692 int error; 693 694 LIST_FOREACH_SAFE(p, &encaptab, chain, np) { 695 if (p == ep) { 696 error = encap_remove(p); 697 if (error) 698 return error; 699 if (!ep->func) { 700 kmem_free(p->addrpack, ep->addrpack->sa_len); 701 kmem_free(p->maskpack, ep->maskpack->sa_len); 702 } 703 kmem_free(p, sizeof(*p)); /*XXX*/ 704 return 0; 705 } 706 } 707 708 return ENOENT; 709 } 710 711 static struct radix_node_head * 712 encap_rnh(int af) 713 { 714 715 switch (af) { 716 case AF_INET: 717 return encap_head[0]; 718 #ifdef INET6 719 case AF_INET6: 720 return encap_head[1]; 721 #endif 722 default: 723 return NULL; 724 } 725 } 726 727 static int 728 mask_matchlen(const struct sockaddr *sa) 729 { 730 const char *p, *ep; 731 int l; 732 733 p = (const char *)sa; 734 ep = p + sa->sa_len; 735 p += 2; /* sa_len + sa_family */ 736 737 l = 0; 738 while (p < ep) { 739 l += (*p ? 8 : 0); /* estimate */ 740 p++; 741 } 742 return l; 743 } 744 745 static void 746 encap_fillarg(struct mbuf *m, const struct encaptab *ep) 747 { 748 struct m_tag *mtag; 749 750 mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT); 751 if (mtag) { 752 *(void **)(mtag + 1) = ep->arg; 753 m_tag_prepend(m, mtag); 754 } 755 } 756 757 void * 758 encap_getarg(struct mbuf *m) 759 { 760 void *p; 761 struct m_tag *mtag; 762 763 p = NULL; 764 mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL); 765 if (mtag != NULL) { 766 p = *(void **)(mtag + 1); 767 m_tag_delete(m, mtag); 768 } 769 return p; 770 } 771