1 /* $NetBSD: ip_encap.c,v 1.51 2016/01/26 05:58:05 knakahara 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.51 2016/01/26 05:58:05 knakahara 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 #include <net/route.h> 88 89 #include <netinet/in.h> 90 #include <netinet/in_systm.h> 91 #include <netinet/ip.h> 92 #include <netinet/ip_var.h> 93 #include <netinet/ip_encap.h> 94 #ifdef MROUTING 95 #include <netinet/ip_mroute.h> 96 #endif /* MROUTING */ 97 98 #ifdef INET6 99 #include <netinet/ip6.h> 100 #include <netinet6/ip6_var.h> 101 #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */ 102 #include <netinet6/in6_var.h> 103 #include <netinet6/in6_pcb.h> 104 #include <netinet/icmp6.h> 105 #endif 106 107 #include <net/net_osdep.h> 108 109 enum direction { INBOUND, OUTBOUND }; 110 111 #ifdef INET 112 static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction); 113 #endif 114 #ifdef INET6 115 static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction); 116 #endif 117 static int encap_add(struct encaptab *); 118 static int encap_remove(struct encaptab *); 119 static int encap_afcheck(int, const struct sockaddr *, const struct sockaddr *); 120 static struct radix_node_head *encap_rnh(int); 121 static int mask_matchlen(const struct sockaddr *); 122 static void encap_fillarg(struct mbuf *, const struct encaptab *); 123 124 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); 125 126 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */ 127 128 void 129 encap_init(void) 130 { 131 static int initialized = 0; 132 133 if (initialized) 134 return; 135 initialized++; 136 #if 0 137 /* 138 * we cannot use LIST_INIT() here, since drivers may want to call 139 * encap_attach(), on driver attach. encap_init() will be called 140 * on AF_INET{,6} initialization, which happens after driver 141 * initialization - using LIST_INIT() here can nuke encap_attach() 142 * from drivers. 143 */ 144 LIST_INIT(&encaptab); 145 #endif 146 147 /* 148 * initialize radix lookup table when the radix subsystem is inited. 149 */ 150 rn_delayedinit((void *)&encap_head[0], 151 sizeof(struct sockaddr_pack) << 3); 152 #ifdef INET6 153 rn_delayedinit((void *)&encap_head[1], 154 sizeof(struct sockaddr_pack) << 3); 155 #endif 156 } 157 158 #ifdef INET 159 static struct encaptab * 160 encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir) 161 { 162 struct ip *ip; 163 struct ip_pack4 pack; 164 struct encaptab *ep, *match; 165 int prio, matchprio; 166 struct radix_node_head *rnh = encap_rnh(AF_INET); 167 struct radix_node *rn; 168 169 KASSERT(m->m_len >= sizeof(*ip)); 170 171 ip = mtod(m, struct ip *); 172 173 memset(&pack, 0, sizeof(pack)); 174 pack.p.sp_len = sizeof(pack); 175 pack.mine.sin_family = pack.yours.sin_family = AF_INET; 176 pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in); 177 if (dir == INBOUND) { 178 pack.mine.sin_addr = ip->ip_dst; 179 pack.yours.sin_addr = ip->ip_src; 180 } else { 181 pack.mine.sin_addr = ip->ip_src; 182 pack.yours.sin_addr = ip->ip_dst; 183 } 184 185 match = NULL; 186 matchprio = 0; 187 188 rn = rnh->rnh_matchaddr((void *)&pack, rnh); 189 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 190 match = (struct encaptab *)rn; 191 matchprio = mask_matchlen(match->srcmask) + 192 mask_matchlen(match->dstmask); 193 } 194 195 LIST_FOREACH(ep, &encaptab, chain) { 196 if (ep->af != AF_INET) 197 continue; 198 if (ep->proto >= 0 && ep->proto != proto) 199 continue; 200 if (ep->func) 201 prio = (*ep->func)(m, off, proto, ep->arg); 202 else 203 continue; 204 205 /* 206 * We prioritize the matches by using bit length of the 207 * matches. mask_match() and user-supplied matching function 208 * should return the bit length of the matches (for example, 209 * if both src/dst are matched for IPv4, 64 should be returned). 210 * 0 or negative return value means "it did not match". 211 * 212 * The question is, since we have two "mask" portion, we 213 * cannot really define total order between entries. 214 * For example, which of these should be preferred? 215 * mask_match() returns 48 (32 + 16) for both of them. 216 * src=3ffe::/16, dst=3ffe:501::/32 217 * src=3ffe:501::/32, dst=3ffe::/16 218 * 219 * We need to loop through all the possible candidates 220 * to get the best match - the search takes O(n) for 221 * n attachments (i.e. interfaces). 222 * 223 * For radix-based lookup, I guess source takes precedence. 224 * See rn_{refines,lexobetter} for the correct answer. 225 */ 226 if (prio <= 0) 227 continue; 228 if (prio > matchprio) { 229 matchprio = prio; 230 match = ep; 231 } 232 } 233 234 return match; 235 } 236 237 void 238 encap4_input(struct mbuf *m, ...) 239 { 240 int off, proto; 241 va_list ap; 242 const struct encapsw *esw; 243 struct encaptab *match; 244 245 va_start(ap, m); 246 off = va_arg(ap, int); 247 proto = va_arg(ap, int); 248 va_end(ap); 249 250 match = encap4_lookup(m, off, proto, INBOUND); 251 252 if (match) { 253 /* found a match, "match" has the best one */ 254 esw = match->esw; 255 if (esw && esw->encapsw4.pr_input) { 256 encap_fillarg(m, match); 257 (*esw->encapsw4.pr_input)(m, off, proto); 258 } else 259 m_freem(m); 260 return; 261 } 262 263 /* last resort: inject to raw socket */ 264 rip_input(m, off, proto); 265 } 266 #endif 267 268 #ifdef INET6 269 static struct encaptab * 270 encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir) 271 { 272 struct ip6_hdr *ip6; 273 struct ip_pack6 pack; 274 int prio, matchprio; 275 struct encaptab *ep, *match; 276 struct radix_node_head *rnh = encap_rnh(AF_INET6); 277 struct radix_node *rn; 278 279 KASSERT(m->m_len >= sizeof(*ip6)); 280 281 ip6 = mtod(m, struct ip6_hdr *); 282 283 memset(&pack, 0, sizeof(pack)); 284 pack.p.sp_len = sizeof(pack); 285 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6; 286 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6); 287 if (dir == INBOUND) { 288 pack.mine.sin6_addr = ip6->ip6_dst; 289 pack.yours.sin6_addr = ip6->ip6_src; 290 } else { 291 pack.mine.sin6_addr = ip6->ip6_src; 292 pack.yours.sin6_addr = ip6->ip6_dst; 293 } 294 295 match = NULL; 296 matchprio = 0; 297 298 rn = rnh->rnh_matchaddr((void *)&pack, rnh); 299 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 300 match = (struct encaptab *)rn; 301 matchprio = mask_matchlen(match->srcmask) + 302 mask_matchlen(match->dstmask); 303 } 304 305 LIST_FOREACH(ep, &encaptab, chain) { 306 if (ep->af != AF_INET6) 307 continue; 308 if (ep->proto >= 0 && ep->proto != proto) 309 continue; 310 if (ep->func) 311 prio = (*ep->func)(m, off, proto, ep->arg); 312 else 313 continue; 314 315 /* see encap4_lookup() for issues here */ 316 if (prio <= 0) 317 continue; 318 if (prio > matchprio) { 319 matchprio = prio; 320 match = ep; 321 } 322 } 323 324 return match; 325 } 326 327 int 328 encap6_input(struct mbuf **mp, int *offp, int proto) 329 { 330 struct mbuf *m = *mp; 331 const struct encapsw *esw; 332 struct encaptab *match; 333 334 match = encap6_lookup(m, *offp, proto, INBOUND); 335 336 if (match) { 337 /* found a match */ 338 esw = match->esw; 339 if (esw && esw->encapsw6.pr_input) { 340 encap_fillarg(m, match); 341 return (*esw->encapsw6.pr_input)(mp, offp, proto); 342 } else { 343 m_freem(m); 344 return IPPROTO_DONE; 345 } 346 } 347 348 /* last resort: inject to raw socket */ 349 return rip6_input(mp, offp, proto); 350 } 351 #endif 352 353 static int 354 encap_add(struct encaptab *ep) 355 { 356 struct radix_node_head *rnh = encap_rnh(ep->af); 357 int error = 0; 358 359 LIST_INSERT_HEAD(&encaptab, ep, chain); 360 if (!ep->func && rnh) { 361 if (!rnh->rnh_addaddr((void *)ep->addrpack, 362 (void *)ep->maskpack, rnh, ep->nodes)) { 363 error = EEXIST; 364 goto fail; 365 } 366 } 367 return error; 368 369 fail: 370 LIST_REMOVE(ep, chain); 371 return error; 372 } 373 374 static int 375 encap_remove(struct encaptab *ep) 376 { 377 struct radix_node_head *rnh = encap_rnh(ep->af); 378 int error = 0; 379 380 LIST_REMOVE(ep, chain); 381 if (!ep->func && rnh) { 382 if (!rnh->rnh_deladdr((void *)ep->addrpack, 383 (void *)ep->maskpack, rnh)) 384 error = ESRCH; 385 } 386 return error; 387 } 388 389 static int 390 encap_afcheck(int af, const struct sockaddr *sp, const struct sockaddr *dp) 391 { 392 if (sp && dp) { 393 if (sp->sa_len != dp->sa_len) 394 return EINVAL; 395 if (af != sp->sa_family || af != dp->sa_family) 396 return EINVAL; 397 } else if (!sp && !dp) 398 ; 399 else 400 return EINVAL; 401 402 switch (af) { 403 case AF_INET: 404 if (sp && sp->sa_len != sizeof(struct sockaddr_in)) 405 return EINVAL; 406 if (dp && dp->sa_len != sizeof(struct sockaddr_in)) 407 return EINVAL; 408 break; 409 #ifdef INET6 410 case AF_INET6: 411 if (sp && sp->sa_len != sizeof(struct sockaddr_in6)) 412 return EINVAL; 413 if (dp && dp->sa_len != sizeof(struct sockaddr_in6)) 414 return EINVAL; 415 break; 416 #endif 417 default: 418 return EAFNOSUPPORT; 419 } 420 421 return 0; 422 } 423 424 /* 425 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side. 426 * length of mask (sm and dm) is assumed to be same as sp/dp. 427 * Return value will be necessary as input (cookie) for encap_detach(). 428 */ 429 const struct encaptab * 430 encap_attach(int af, int proto, 431 const struct sockaddr *sp, const struct sockaddr *sm, 432 const struct sockaddr *dp, const struct sockaddr *dm, 433 const struct encapsw *esw, void *arg) 434 { 435 struct encaptab *ep; 436 int error; 437 int s; 438 size_t l; 439 struct ip_pack4 *pack4; 440 #ifdef INET6 441 struct ip_pack6 *pack6; 442 #endif 443 444 s = splsoftnet(); 445 /* sanity check on args */ 446 error = encap_afcheck(af, sp, dp); 447 if (error) 448 goto fail; 449 450 /* check if anyone have already attached with exactly same config */ 451 LIST_FOREACH(ep, &encaptab, chain) { 452 if (ep->af != af) 453 continue; 454 if (ep->proto != proto) 455 continue; 456 if (ep->func) 457 continue; 458 459 KASSERT(ep->src != NULL); 460 KASSERT(ep->dst != NULL); 461 KASSERT(ep->srcmask != NULL); 462 KASSERT(ep->dstmask != NULL); 463 464 if (ep->src->sa_len != sp->sa_len || 465 memcmp(ep->src, sp, sp->sa_len) != 0 || 466 memcmp(ep->srcmask, sm, sp->sa_len) != 0) 467 continue; 468 if (ep->dst->sa_len != dp->sa_len || 469 memcmp(ep->dst, dp, dp->sa_len) != 0 || 470 memcmp(ep->dstmask, dm, dp->sa_len) != 0) 471 continue; 472 473 error = EEXIST; 474 goto fail; 475 } 476 477 switch (af) { 478 case AF_INET: 479 l = sizeof(*pack4); 480 break; 481 #ifdef INET6 482 case AF_INET6: 483 l = sizeof(*pack6); 484 break; 485 #endif 486 default: 487 goto fail; 488 } 489 490 /* M_NETADDR ok? */ 491 ep = kmem_zalloc(sizeof(*ep), KM_NOSLEEP); 492 if (ep == NULL) { 493 error = ENOBUFS; 494 goto fail; 495 } 496 ep->addrpack = kmem_zalloc(l, KM_NOSLEEP); 497 if (ep->addrpack == NULL) { 498 error = ENOBUFS; 499 goto gc; 500 } 501 ep->maskpack = kmem_zalloc(l, KM_NOSLEEP); 502 if (ep->maskpack == NULL) { 503 error = ENOBUFS; 504 goto gc; 505 } 506 507 ep->af = af; 508 ep->proto = proto; 509 ep->addrpack->sa_len = l & 0xff; 510 ep->maskpack->sa_len = l & 0xff; 511 switch (af) { 512 case AF_INET: 513 pack4 = (struct ip_pack4 *)ep->addrpack; 514 ep->src = (struct sockaddr *)&pack4->mine; 515 ep->dst = (struct sockaddr *)&pack4->yours; 516 pack4 = (struct ip_pack4 *)ep->maskpack; 517 ep->srcmask = (struct sockaddr *)&pack4->mine; 518 ep->dstmask = (struct sockaddr *)&pack4->yours; 519 break; 520 #ifdef INET6 521 case AF_INET6: 522 pack6 = (struct ip_pack6 *)ep->addrpack; 523 ep->src = (struct sockaddr *)&pack6->mine; 524 ep->dst = (struct sockaddr *)&pack6->yours; 525 pack6 = (struct ip_pack6 *)ep->maskpack; 526 ep->srcmask = (struct sockaddr *)&pack6->mine; 527 ep->dstmask = (struct sockaddr *)&pack6->yours; 528 break; 529 #endif 530 } 531 532 memcpy(ep->src, sp, sp->sa_len); 533 memcpy(ep->srcmask, sm, sp->sa_len); 534 memcpy(ep->dst, dp, dp->sa_len); 535 memcpy(ep->dstmask, dm, dp->sa_len); 536 ep->esw = esw; 537 ep->arg = arg; 538 539 error = encap_add(ep); 540 if (error) 541 goto gc; 542 543 error = 0; 544 splx(s); 545 return ep; 546 547 gc: 548 if (ep->addrpack) 549 kmem_free(ep->addrpack, l); 550 if (ep->maskpack) 551 kmem_free(ep->maskpack, l); 552 if (ep) 553 kmem_free(ep, sizeof(*ep)); 554 fail: 555 splx(s); 556 return NULL; 557 } 558 559 const struct encaptab * 560 encap_attach_func(int af, int proto, 561 int (*func)(struct mbuf *, int, int, void *), 562 const struct encapsw *esw, void *arg) 563 { 564 struct encaptab *ep; 565 int error; 566 int s; 567 568 s = splsoftnet(); 569 /* sanity check on args */ 570 if (!func) { 571 error = EINVAL; 572 goto fail; 573 } 574 575 error = encap_afcheck(af, NULL, NULL); 576 if (error) 577 goto fail; 578 579 ep = kmem_alloc(sizeof(*ep), KM_NOSLEEP); /*XXX*/ 580 if (ep == NULL) { 581 error = ENOBUFS; 582 goto fail; 583 } 584 memset(ep, 0, sizeof(*ep)); 585 586 ep->af = af; 587 ep->proto = proto; 588 ep->func = func; 589 ep->esw = esw; 590 ep->arg = arg; 591 592 error = encap_add(ep); 593 if (error) 594 goto fail; 595 596 error = 0; 597 splx(s); 598 return ep; 599 600 fail: 601 splx(s); 602 return NULL; 603 } 604 605 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */ 606 607 #ifdef INET6 608 void * 609 encap6_ctlinput(int cmd, const struct sockaddr *sa, void *d0) 610 { 611 void *d = d0; 612 struct ip6_hdr *ip6; 613 struct mbuf *m; 614 int off; 615 struct ip6ctlparam *ip6cp = NULL; 616 int nxt; 617 struct encaptab *ep; 618 const struct encapsw *esw; 619 620 if (sa->sa_family != AF_INET6 || 621 sa->sa_len != sizeof(struct sockaddr_in6)) 622 return NULL; 623 624 if ((unsigned)cmd >= PRC_NCMDS) 625 return NULL; 626 if (cmd == PRC_HOSTDEAD) 627 d = NULL; 628 else if (cmd == PRC_MSGSIZE) 629 ; /* special code is present, see below */ 630 else if (inet6ctlerrmap[cmd] == 0) 631 return NULL; 632 633 /* if the parameter is from icmp6, decode it. */ 634 if (d != NULL) { 635 ip6cp = (struct ip6ctlparam *)d; 636 m = ip6cp->ip6c_m; 637 ip6 = ip6cp->ip6c_ip6; 638 off = ip6cp->ip6c_off; 639 nxt = ip6cp->ip6c_nxt; 640 641 if (ip6 && cmd == PRC_MSGSIZE) { 642 int valid = 0; 643 struct encaptab *match; 644 645 /* 646 * Check to see if we have a valid encap configuration. 647 */ 648 match = encap6_lookup(m, off, nxt, OUTBOUND); 649 if (match) 650 valid++; 651 652 /* 653 * Depending on the value of "valid" and routing table 654 * size (mtudisc_{hi,lo}wat), we will: 655 * - recalcurate the new MTU and create the 656 * corresponding routing entry, or 657 * - ignore the MTU change notification. 658 */ 659 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 660 } 661 } else { 662 m = NULL; 663 ip6 = NULL; 664 nxt = -1; 665 } 666 667 /* inform all listeners */ 668 LIST_FOREACH(ep, &encaptab, chain) { 669 if (ep->af != AF_INET6) 670 continue; 671 if (ep->proto >= 0 && ep->proto != nxt) 672 continue; 673 674 /* should optimize by looking at address pairs */ 675 676 /* XXX need to pass ep->arg or ep itself to listeners */ 677 esw = ep->esw; 678 if (esw && esw->encapsw6.pr_ctlinput) { 679 (*esw->encapsw6.pr_ctlinput)(cmd, sa, d); 680 } 681 } 682 683 rip6_ctlinput(cmd, sa, d0); 684 return NULL; 685 } 686 #endif 687 688 int 689 encap_detach(const struct encaptab *cookie) 690 { 691 const struct encaptab *ep = cookie; 692 struct encaptab *p, *np; 693 int error; 694 695 LIST_FOREACH_SAFE(p, &encaptab, chain, np) { 696 if (p == ep) { 697 error = encap_remove(p); 698 if (error) 699 return error; 700 if (!ep->func) { 701 kmem_free(p->addrpack, ep->addrpack->sa_len); 702 kmem_free(p->maskpack, ep->maskpack->sa_len); 703 } 704 kmem_free(p, sizeof(*p)); /*XXX*/ 705 return 0; 706 } 707 } 708 709 return ENOENT; 710 } 711 712 static struct radix_node_head * 713 encap_rnh(int af) 714 { 715 716 switch (af) { 717 case AF_INET: 718 return encap_head[0]; 719 #ifdef INET6 720 case AF_INET6: 721 return encap_head[1]; 722 #endif 723 default: 724 return NULL; 725 } 726 } 727 728 static int 729 mask_matchlen(const struct sockaddr *sa) 730 { 731 const char *p, *ep; 732 int l; 733 734 p = (const char *)sa; 735 ep = p + sa->sa_len; 736 p += 2; /* sa_len + sa_family */ 737 738 l = 0; 739 while (p < ep) { 740 l += (*p ? 8 : 0); /* estimate */ 741 p++; 742 } 743 return l; 744 } 745 746 static void 747 encap_fillarg(struct mbuf *m, const struct encaptab *ep) 748 { 749 struct m_tag *mtag; 750 751 mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT); 752 if (mtag) { 753 *(void **)(mtag + 1) = ep->arg; 754 m_tag_prepend(m, mtag); 755 } 756 } 757 758 void * 759 encap_getarg(struct mbuf *m) 760 { 761 void *p; 762 struct m_tag *mtag; 763 764 p = NULL; 765 mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL); 766 if (mtag != NULL) { 767 p = *(void **)(mtag + 1); 768 m_tag_delete(m, mtag); 769 } 770 return p; 771 } 772