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