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.8 2002/03/04 13:24:12 sommerfeld 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 #ifdef MROUTING 111 #include <netinet/ip_mroute.h> 112 #endif 113 114 #include <net/net_osdep.h> 115 116 /* to lookup a pair of address using radix tree */ 117 struct sockaddr_pack { 118 u_int8_t sp_len; 119 u_int8_t sp_family; /* not really used */ 120 /* followed by variable-length data */ 121 } __attribute__((__packed__)); 122 123 struct pack4 { 124 struct sockaddr_pack p; 125 struct sockaddr_in mine; 126 struct sockaddr_in yours; 127 } __attribute__((__packed__)); 128 struct pack6 { 129 struct sockaddr_pack p; 130 struct sockaddr_in6 mine; 131 struct sockaddr_in6 yours; 132 } __attribute__((__packed__)); 133 134 enum direction { INBOUND, OUTBOUND }; 135 136 #ifdef INET 137 static struct encaptab *encap4_lookup __P((struct mbuf *, int, int, 138 enum direction)); 139 #endif 140 #ifdef INET6 141 static struct encaptab *encap6_lookup __P((struct mbuf *, int, int, 142 enum direction)); 143 #endif 144 static int encap_add __P((struct encaptab *)); 145 static int encap_remove __P((struct encaptab *)); 146 static int encap_afcheck __P((int, const struct sockaddr *, const struct sockaddr *)); 147 #ifdef USE_RADIX 148 static struct radix_node_head *encap_rnh __P((int)); 149 static int mask_matchlen __P((const struct sockaddr *)); 150 #endif 151 #ifndef USE_RADIX 152 static int mask_match __P((const struct encaptab *, const struct sockaddr *, 153 const struct sockaddr *)); 154 #endif 155 static void encap_fillarg __P((struct mbuf *, const struct encaptab *)); 156 157 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); 158 159 #ifdef USE_RADIX 160 extern int max_keylen; /* radix.c */ 161 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */ 162 #endif 163 164 void 165 encap_init() 166 { 167 static int initialized = 0; 168 169 if (initialized) 170 return; 171 initialized++; 172 #if 0 173 /* 174 * we cannot use LIST_INIT() here, since drivers may want to call 175 * encap_attach(), on driver attach. encap_init() will be called 176 * on AF_INET{,6} initialization, which happens after driver 177 * initialization - using LIST_INIT() here can nuke encap_attach() 178 * from drivers. 179 */ 180 LIST_INIT(&encaptab); 181 #endif 182 183 #ifdef USE_RADIX 184 /* 185 * initialize radix lookup table. 186 * max_keylen initialization should happen before the call to rn_init(). 187 */ 188 rn_inithead((void **)&encap_head[0], sizeof(struct sockaddr_pack) << 3); 189 if (sizeof(struct pack4) > max_keylen) 190 max_keylen = sizeof(struct pack4); 191 #ifdef INET6 192 rn_inithead((void **)&encap_head[1], sizeof(struct sockaddr_pack) << 3); 193 if (sizeof(struct pack6) > max_keylen) 194 max_keylen = sizeof(struct pack6); 195 #endif 196 #endif 197 } 198 199 #ifdef INET 200 static struct encaptab * 201 encap4_lookup(m, off, proto, dir) 202 struct mbuf *m; 203 int off; 204 int proto; 205 enum direction dir; 206 { 207 struct ip *ip; 208 struct pack4 pack; 209 struct encaptab *ep, *match; 210 int prio, matchprio; 211 #ifdef USE_RADIX 212 struct radix_node_head *rnh = encap_rnh(AF_INET); 213 struct radix_node *rn; 214 #endif 215 216 #ifdef DIAGNOSTIC 217 if (m->m_len < sizeof(*ip)) 218 panic("encap4_lookup"); 219 #endif 220 ip = mtod(m, struct ip *); 221 222 bzero(&pack, sizeof(pack)); 223 pack.p.sp_len = sizeof(pack); 224 pack.mine.sin_family = pack.yours.sin_family = AF_INET; 225 pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in); 226 if (dir == INBOUND) { 227 pack.mine.sin_addr = ip->ip_dst; 228 pack.yours.sin_addr = ip->ip_src; 229 } else { 230 pack.mine.sin_addr = ip->ip_src; 231 pack.yours.sin_addr = ip->ip_dst; 232 } 233 234 match = NULL; 235 matchprio = 0; 236 237 #ifdef USE_RADIX 238 rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh); 239 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 240 match = (struct encaptab *)rn; 241 matchprio = mask_matchlen(match->srcmask) + 242 mask_matchlen(match->dstmask); 243 } 244 #endif 245 246 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 247 if (ep->af != AF_INET) 248 continue; 249 if (ep->proto >= 0 && ep->proto != proto) 250 continue; 251 if (ep->func) 252 prio = (*ep->func)(m, off, proto, ep->arg); 253 else { 254 #ifdef USE_RADIX 255 continue; 256 #else 257 prio = mask_match(ep, (struct sockaddr *)&pack.mine, 258 (struct sockaddr *)&pack.yours); 259 #endif 260 } 261 262 /* 263 * We prioritize the matches by using bit length of the 264 * matches. mask_match() and user-supplied matching function 265 * should return the bit length of the matches (for example, 266 * if both src/dst are matched for IPv4, 64 should be returned). 267 * 0 or negative return value means "it did not match". 268 * 269 * The question is, since we have two "mask" portion, we 270 * cannot really define total order between entries. 271 * For example, which of these should be preferred? 272 * mask_match() returns 48 (32 + 16) for both of them. 273 * src=3ffe::/16, dst=3ffe:501::/32 274 * src=3ffe:501::/32, dst=3ffe::/16 275 * 276 * We need to loop through all the possible candidates 277 * to get the best match - the search takes O(n) for 278 * n attachments (i.e. interfaces). 279 * 280 * For radix-based lookup, I guess source takes precedence. 281 * See rn_{refines,lexobetter} for the correct answer. 282 */ 283 if (prio <= 0) 284 continue; 285 if (prio > matchprio) { 286 matchprio = prio; 287 match = ep; 288 } 289 } 290 291 return match; 292 #undef s 293 #undef d 294 } 295 296 void 297 #if __STDC__ 298 encap4_input(struct mbuf *m, ...) 299 #else 300 encap4_input(m, va_alist) 301 struct mbuf *m; 302 va_dcl 303 #endif 304 { 305 int off, proto; 306 va_list ap; 307 const struct protosw *psw; 308 struct encaptab *match; 309 310 va_start(ap, m); 311 off = va_arg(ap, int); 312 proto = va_arg(ap, int); 313 va_end(ap); 314 315 match = encap4_lookup(m, off, proto, INBOUND); 316 317 if (match) { 318 /* found a match, "match" has the best one */ 319 psw = match->psw; 320 if (psw && psw->pr_input) { 321 encap_fillarg(m, match); 322 (*psw->pr_input)(m, off, proto); 323 } else 324 m_freem(m); 325 return; 326 } 327 328 /* last resort: inject to raw socket */ 329 rip_input(m, off, proto); 330 } 331 #endif 332 333 #ifdef INET6 334 static struct encaptab * 335 encap6_lookup(m, off, proto, dir) 336 struct mbuf *m; 337 int off; 338 int proto; 339 enum direction dir; 340 { 341 struct ip6_hdr *ip6; 342 struct pack6 pack; 343 int prio, matchprio; 344 struct encaptab *ep, *match; 345 #ifdef USE_RADIX 346 struct radix_node_head *rnh = encap_rnh(AF_INET6); 347 struct radix_node *rn; 348 #endif 349 350 #ifdef DIAGNOSTIC 351 if (m->m_len < sizeof(*ip6)) 352 panic("encap6_lookup"); 353 #endif 354 ip6 = mtod(m, struct ip6_hdr *); 355 356 bzero(&pack, sizeof(pack)); 357 pack.p.sp_len = sizeof(pack); 358 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6; 359 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6); 360 if (dir == INBOUND) { 361 pack.mine.sin6_addr = ip6->ip6_dst; 362 pack.yours.sin6_addr = ip6->ip6_src; 363 } else { 364 pack.mine.sin6_addr = ip6->ip6_src; 365 pack.yours.sin6_addr = ip6->ip6_dst; 366 } 367 368 match = NULL; 369 matchprio = 0; 370 371 #ifdef USE_RADIX 372 rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh); 373 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 374 match = (struct encaptab *)rn; 375 matchprio = mask_matchlen(match->srcmask) + 376 mask_matchlen(match->dstmask); 377 } 378 #endif 379 380 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 381 if (ep->af != AF_INET6) 382 continue; 383 if (ep->proto >= 0 && ep->proto != proto) 384 continue; 385 if (ep->func) 386 prio = (*ep->func)(m, off, proto, ep->arg); 387 else { 388 #ifdef USE_RADIX 389 continue; 390 #else 391 prio = mask_match(ep, (struct sockaddr *)&pack.mine, 392 (struct sockaddr *)&pack.yours); 393 #endif 394 } 395 396 /* see encap4_lookup() for issues here */ 397 if (prio <= 0) 398 continue; 399 if (prio > matchprio) { 400 matchprio = prio; 401 match = ep; 402 } 403 } 404 405 return match; 406 #undef s 407 #undef d 408 } 409 410 int 411 encap6_input(mp, offp, proto) 412 struct mbuf **mp; 413 int *offp; 414 int proto; 415 { 416 struct mbuf *m = *mp; 417 const struct ip6protosw *psw; 418 struct encaptab *match; 419 420 match = encap6_lookup(m, *offp, proto, INBOUND); 421 422 if (match) { 423 /* found a match */ 424 psw = (const struct ip6protosw *)match->psw; 425 if (psw && psw->pr_input) { 426 encap_fillarg(m, match); 427 return (*psw->pr_input)(mp, offp, proto); 428 } else { 429 m_freem(m); 430 return IPPROTO_DONE; 431 } 432 } 433 434 /* last resort: inject to raw socket */ 435 return rip6_input(mp, offp, proto); 436 } 437 #endif 438 439 static int 440 encap_add(ep) 441 struct encaptab *ep; 442 { 443 #ifdef USE_RADIX 444 struct radix_node_head *rnh = encap_rnh(ep->af); 445 #endif 446 int error = 0; 447 448 LIST_INSERT_HEAD(&encaptab, ep, chain); 449 #ifdef USE_RADIX 450 if (!ep->func && rnh) { 451 if (!rnh->rnh_addaddr((caddr_t)ep->addrpack, 452 (caddr_t)ep->maskpack, rnh, ep->nodes)) { 453 error = EEXIST; 454 goto fail; 455 } 456 } 457 #endif 458 return error; 459 460 fail: 461 LIST_REMOVE(ep, chain); 462 return error; 463 } 464 465 static int 466 encap_remove(ep) 467 struct encaptab *ep; 468 { 469 #ifdef USE_RADIX 470 struct radix_node_head *rnh = encap_rnh(ep->af); 471 #endif 472 int error = 0; 473 474 LIST_REMOVE(ep, chain); 475 #ifdef USE_RADIX 476 if (!ep->func && rnh) { 477 if (!rnh->rnh_deladdr((caddr_t)ep->addrpack, 478 (caddr_t)ep->maskpack, rnh)) 479 error = ESRCH; 480 } 481 #endif 482 return error; 483 } 484 485 static int 486 encap_afcheck(af, sp, dp) 487 int af; 488 const struct sockaddr *sp; 489 const struct sockaddr *dp; 490 { 491 if (sp && dp) { 492 if (sp->sa_len != dp->sa_len) 493 return EINVAL; 494 if (af != sp->sa_family || af != dp->sa_family) 495 return EINVAL; 496 } else if (!sp && !dp) 497 ; 498 else 499 return EINVAL; 500 501 switch (af) { 502 case AF_INET: 503 if (sp && sp->sa_len != sizeof(struct sockaddr_in)) 504 return EINVAL; 505 if (dp && dp->sa_len != sizeof(struct sockaddr_in)) 506 return EINVAL; 507 break; 508 #ifdef INET6 509 case AF_INET6: 510 if (sp && sp->sa_len != sizeof(struct sockaddr_in6)) 511 return EINVAL; 512 if (dp && dp->sa_len != sizeof(struct sockaddr_in6)) 513 return EINVAL; 514 break; 515 #endif 516 default: 517 return EAFNOSUPPORT; 518 } 519 520 return 0; 521 } 522 523 /* 524 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side. 525 * length of mask (sm and dm) is assumed to be same as sp/dp. 526 * Return value will be necessary as input (cookie) for encap_detach(). 527 */ 528 const struct encaptab * 529 encap_attach(af, proto, sp, sm, dp, dm, psw, arg) 530 int af; 531 int proto; 532 const struct sockaddr *sp, *sm; 533 const struct sockaddr *dp, *dm; 534 const struct protosw *psw; 535 void *arg; 536 { 537 struct encaptab *ep; 538 int error; 539 int s; 540 size_t l; 541 struct pack4 *pack4; 542 #ifdef INET6 543 struct pack6 *pack6; 544 #endif 545 546 s = splsoftnet(); 547 /* sanity check on args */ 548 error = encap_afcheck(af, sp, dp); 549 if (error) 550 goto fail; 551 552 /* check if anyone have already attached with exactly same config */ 553 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 554 if (ep->af != af) 555 continue; 556 if (ep->proto != proto) 557 continue; 558 if (ep->func) 559 continue; 560 #ifdef DIAGNOSTIC 561 if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask) 562 panic("null pointers in encaptab"); 563 #endif 564 if (ep->src->sa_len != sp->sa_len || 565 bcmp(ep->src, sp, sp->sa_len) != 0 || 566 bcmp(ep->srcmask, sm, sp->sa_len) != 0) 567 continue; 568 if (ep->dst->sa_len != dp->sa_len || 569 bcmp(ep->dst, dp, dp->sa_len) != 0 || 570 bcmp(ep->dstmask, dm, dp->sa_len) != 0) 571 continue; 572 573 error = EEXIST; 574 goto fail; 575 } 576 577 switch (af) { 578 case AF_INET: 579 l = sizeof(*pack4); 580 break; 581 #ifdef INET6 582 case AF_INET6: 583 l = sizeof(*pack6); 584 break; 585 #endif 586 default: 587 goto fail; 588 } 589 590 #ifdef DIAGNOSTIC 591 /* if l exceeds the value sa_len can possibly express, it's wrong. */ 592 if (l > (1 << (8 * sizeof(ep->addrpack->sa_len)))) { 593 error = EINVAL; 594 goto fail; 595 } 596 #endif 597 598 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /* M_NETADDR ok? */ 599 if (ep == NULL) { 600 error = ENOBUFS; 601 goto fail; 602 } 603 bzero(ep, sizeof(*ep)); 604 ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT); 605 if (ep->addrpack == NULL) { 606 error = ENOBUFS; 607 goto gc; 608 } 609 ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT); 610 if (ep->maskpack == NULL) { 611 error = ENOBUFS; 612 goto gc; 613 } 614 615 ep->af = af; 616 ep->proto = proto; 617 ep->addrpack->sa_len = l & 0xff; 618 ep->maskpack->sa_len = l & 0xff; 619 switch (af) { 620 case AF_INET: 621 pack4 = (struct pack4 *)ep->addrpack; 622 ep->src = (struct sockaddr *)&pack4->mine; 623 ep->dst = (struct sockaddr *)&pack4->yours; 624 pack4 = (struct pack4 *)ep->maskpack; 625 ep->srcmask = (struct sockaddr *)&pack4->mine; 626 ep->dstmask = (struct sockaddr *)&pack4->yours; 627 break; 628 #ifdef INET6 629 case AF_INET6: 630 pack6 = (struct pack6 *)ep->addrpack; 631 ep->src = (struct sockaddr *)&pack6->mine; 632 ep->dst = (struct sockaddr *)&pack6->yours; 633 pack6 = (struct pack6 *)ep->maskpack; 634 ep->srcmask = (struct sockaddr *)&pack6->mine; 635 ep->dstmask = (struct sockaddr *)&pack6->yours; 636 break; 637 #endif 638 } 639 640 bcopy(sp, ep->src, sp->sa_len); 641 bcopy(sm, ep->srcmask, sp->sa_len); 642 bcopy(dp, ep->dst, dp->sa_len); 643 bcopy(dm, ep->dstmask, dp->sa_len); 644 ep->psw = psw; 645 ep->arg = arg; 646 647 error = encap_add(ep); 648 if (error) 649 goto gc; 650 651 error = 0; 652 splx(s); 653 return ep; 654 655 gc: 656 if (ep->addrpack) 657 free(ep->addrpack, M_NETADDR); 658 if (ep->maskpack) 659 free(ep->maskpack, M_NETADDR); 660 if (ep) 661 free(ep, M_NETADDR); 662 fail: 663 splx(s); 664 return NULL; 665 } 666 667 const struct encaptab * 668 encap_attach_func(af, proto, func, psw, arg) 669 int af; 670 int proto; 671 int (*func) __P((const struct mbuf *, int, int, void *)); 672 const struct protosw *psw; 673 void *arg; 674 { 675 struct encaptab *ep; 676 int error; 677 int s; 678 679 s = splsoftnet(); 680 /* sanity check on args */ 681 if (!func) { 682 error = EINVAL; 683 goto fail; 684 } 685 686 error = encap_afcheck(af, NULL, NULL); 687 if (error) 688 goto fail; 689 690 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ 691 if (ep == NULL) { 692 error = ENOBUFS; 693 goto fail; 694 } 695 bzero(ep, sizeof(*ep)); 696 697 ep->af = af; 698 ep->proto = proto; 699 ep->func = func; 700 ep->psw = psw; 701 ep->arg = arg; 702 703 error = encap_add(ep); 704 if (error) 705 goto fail; 706 707 error = 0; 708 splx(s); 709 return ep; 710 711 fail: 712 splx(s); 713 return NULL; 714 } 715 716 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */ 717 718 #ifdef INET6 719 void 720 encap6_ctlinput(cmd, sa, d0) 721 int cmd; 722 struct sockaddr *sa; 723 void *d0; 724 { 725 void *d = d0; 726 struct ip6_hdr *ip6; 727 struct mbuf *m; 728 int off; 729 struct ip6ctlparam *ip6cp = NULL; 730 const struct sockaddr_in6 *sa6_src = NULL; 731 void *cmdarg; 732 int nxt; 733 struct encaptab *ep; 734 const struct ip6protosw *psw; 735 736 if (sa->sa_family != AF_INET6 || 737 sa->sa_len != sizeof(struct sockaddr_in6)) 738 return; 739 740 if ((unsigned)cmd >= PRC_NCMDS) 741 return; 742 if (cmd == PRC_HOSTDEAD) 743 d = NULL; 744 else if (cmd == PRC_MSGSIZE) 745 ; /* special code is present, see below */ 746 else if (inet6ctlerrmap[cmd] == 0) 747 return; 748 749 /* if the parameter is from icmp6, decode it. */ 750 if (d != NULL) { 751 ip6cp = (struct ip6ctlparam *)d; 752 m = ip6cp->ip6c_m; 753 ip6 = ip6cp->ip6c_ip6; 754 off = ip6cp->ip6c_off; 755 cmdarg = ip6cp->ip6c_cmdarg; 756 sa6_src = ip6cp->ip6c_src; 757 nxt = ip6cp->ip6c_nxt; 758 } else { 759 m = NULL; 760 ip6 = NULL; 761 cmdarg = NULL; 762 sa6_src = &sa6_any; 763 nxt = -1; 764 } 765 766 if (ip6 && cmd == PRC_MSGSIZE) { 767 int valid = 0; 768 struct encaptab *match; 769 770 /* 771 * Check to see if we have a valid encap configuration. 772 */ 773 match = encap6_lookup(m, off, nxt, OUTBOUND); 774 775 if (match) 776 valid++; 777 778 /* 779 * Depending on the value of "valid" and routing table 780 * size (mtudisc_{hi,lo}wat), we will: 781 * - recalcurate the new MTU and create the 782 * corresponding routing entry, or 783 * - ignore the MTU change notification. 784 */ 785 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 786 } 787 788 /* inform all listeners */ 789 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 790 if (ep->af != AF_INET6) 791 continue; 792 if (ep->proto >= 0 && ep->proto != nxt) 793 continue; 794 795 /* should optimize by looking at address pairs */ 796 797 /* XXX need to pass ep->arg or ep itself to listeners */ 798 psw = (const struct ip6protosw *)ep->psw; 799 if (psw && psw->pr_ctlinput) 800 (*psw->pr_ctlinput)(cmd, sa, d); 801 } 802 803 rip6_ctlinput(cmd, sa, d0); 804 } 805 #endif 806 807 int 808 encap_detach(cookie) 809 const struct encaptab *cookie; 810 { 811 const struct encaptab *ep = cookie; 812 struct encaptab *p; 813 int error; 814 815 for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) { 816 if (p == ep) { 817 error = encap_remove(p); 818 if (error) 819 return error; 820 if (!ep->func) { 821 free(p->addrpack, M_NETADDR); 822 free(p->maskpack, M_NETADDR); 823 } 824 free(p, M_NETADDR); /*XXX*/ 825 return 0; 826 } 827 } 828 829 return ENOENT; 830 } 831 832 #ifdef USE_RADIX 833 static struct radix_node_head * 834 encap_rnh(af) 835 int af; 836 { 837 838 switch (af) { 839 case AF_INET: 840 return encap_head[0]; 841 #ifdef INET6 842 case AF_INET6: 843 return encap_head[1]; 844 #endif 845 default: 846 return NULL; 847 } 848 } 849 850 static int 851 mask_matchlen(sa) 852 const struct sockaddr *sa; 853 { 854 const char *p, *ep; 855 int l; 856 857 p = (const char *)sa; 858 ep = p + sa->sa_len; 859 p += 2; /* sa_len + sa_family */ 860 861 l = 0; 862 while (p < ep) { 863 l += (*p ? 8 : 0); /* estimate */ 864 p++; 865 } 866 return l; 867 } 868 #endif 869 870 #ifndef USE_RADIX 871 static int 872 mask_match(ep, sp, dp) 873 const struct encaptab *ep; 874 const struct sockaddr *sp; 875 const struct sockaddr *dp; 876 { 877 struct sockaddr_storage s; 878 struct sockaddr_storage d; 879 int i; 880 const u_int8_t *p, *q; 881 u_int8_t *r; 882 int matchlen; 883 884 #ifdef DIAGNOSTIC 885 if (ep->func) 886 panic("wrong encaptab passed to mask_match"); 887 #endif 888 if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) 889 return 0; 890 if (sp->sa_family != ep->af || dp->sa_family != ep->af) 891 return 0; 892 if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len) 893 return 0; 894 895 matchlen = 0; 896 897 p = (const u_int8_t *)sp; 898 q = (const u_int8_t *)ep->srcmask; 899 r = (u_int8_t *)&s; 900 for (i = 0 ; i < sp->sa_len; i++) { 901 r[i] = p[i] & q[i]; 902 /* XXX estimate */ 903 matchlen += (q[i] ? 8 : 0); 904 } 905 906 p = (const u_int8_t *)dp; 907 q = (const u_int8_t *)ep->dstmask; 908 r = (u_int8_t *)&d; 909 for (i = 0 ; i < dp->sa_len; i++) { 910 r[i] = p[i] & q[i]; 911 /* XXX rough estimate */ 912 matchlen += (q[i] ? 8 : 0); 913 } 914 915 /* need to overwrite len/family portion as we don't compare them */ 916 s.ss_len = sp->sa_len; 917 s.ss_family = sp->sa_family; 918 d.ss_len = dp->sa_len; 919 d.ss_family = dp->sa_family; 920 921 if (bcmp(&s, ep->src, ep->src->sa_len) == 0 && 922 bcmp(&d, ep->dst, ep->dst->sa_len) == 0) { 923 return matchlen; 924 } else 925 return 0; 926 } 927 #endif 928 929 static void 930 encap_fillarg(m, ep) 931 struct mbuf *m; 932 const struct encaptab *ep; 933 { 934 struct mbuf *n; 935 936 n = m_aux_add(m, AF_INET, IPPROTO_IPV4); 937 if (n) { 938 *mtod(n, void **) = ep->arg; 939 n->m_len = sizeof(void *); 940 } 941 } 942 943 void * 944 encap_getarg(m) 945 struct mbuf *m; 946 { 947 void *p; 948 struct mbuf *n; 949 950 p = NULL; 951 n = m_aux_find(m, AF_INET, IPPROTO_IPV4); 952 if (n) { 953 if (n->m_len == sizeof(void *)) 954 p = *mtod(n, void **); 955 m_aux_delete(m, n); 956 } 957 return p; 958 } 959