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.28 2006/05/28 11:07:04 liamjfoy 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(struct mbuf *, int, int, enum direction); 134 #endif 135 #ifdef INET6 136 static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction); 137 #endif 138 static int encap_add(struct encaptab *); 139 static int encap_remove(struct encaptab *); 140 static int encap_afcheck(int, const struct sockaddr *, const struct sockaddr *); 141 #ifdef USE_RADIX 142 static struct radix_node_head *encap_rnh(int); 143 static int mask_matchlen(const struct sockaddr *); 144 #endif 145 #ifndef USE_RADIX 146 static int mask_match(const struct encaptab *, const struct sockaddr *, 147 const struct sockaddr *); 148 #endif 149 static void encap_fillarg(struct mbuf *, const struct encaptab *); 150 151 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); 152 153 #ifdef USE_RADIX 154 extern int max_keylen; /* radix.c */ 155 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */ 156 #endif 157 158 void 159 encap_setkeylen(void) 160 { 161 #ifdef USE_RADIX 162 if (sizeof(struct pack4) > max_keylen) 163 max_keylen = sizeof(struct pack4); 164 #ifdef INET6 165 if (sizeof(struct pack6) > max_keylen) 166 max_keylen = sizeof(struct pack6); 167 #endif 168 #endif 169 } 170 171 void 172 encap_init(void) 173 { 174 static int initialized = 0; 175 176 if (initialized) 177 return; 178 initialized++; 179 #if 0 180 /* 181 * we cannot use LIST_INIT() here, since drivers may want to call 182 * encap_attach(), on driver attach. encap_init() will be called 183 * on AF_INET{,6} initialization, which happens after driver 184 * initialization - using LIST_INIT() here can nuke encap_attach() 185 * from drivers. 186 */ 187 LIST_INIT(&encaptab); 188 #endif 189 190 #ifdef USE_RADIX 191 /* 192 * initialize radix lookup table. 193 * max_keylen initialization happen in the rn_init(). 194 */ 195 rn_init(); 196 rn_inithead((void *)&encap_head[0], sizeof(struct sockaddr_pack) << 3); 197 #ifdef INET6 198 rn_inithead((void *)&encap_head[1], sizeof(struct sockaddr_pack) << 3); 199 #endif 200 #endif 201 } 202 203 #ifdef INET 204 static struct encaptab * 205 encap4_lookup(struct mbuf *m, int off, int proto, 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 encap4_input(struct mbuf *m, ...) 298 { 299 int off, proto; 300 va_list ap; 301 const struct protosw *psw; 302 struct encaptab *match; 303 304 va_start(ap, m); 305 off = va_arg(ap, int); 306 proto = va_arg(ap, int); 307 va_end(ap); 308 309 match = encap4_lookup(m, off, proto, INBOUND); 310 311 if (match) { 312 /* found a match, "match" has the best one */ 313 psw = match->psw; 314 if (psw && psw->pr_input) { 315 encap_fillarg(m, match); 316 (*psw->pr_input)(m, off, proto); 317 } else 318 m_freem(m); 319 return; 320 } 321 322 /* last resort: inject to raw socket */ 323 rip_input(m, off, proto); 324 } 325 #endif 326 327 #ifdef INET6 328 static struct encaptab * 329 encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir) 330 { 331 struct ip6_hdr *ip6; 332 struct pack6 pack; 333 int prio, matchprio; 334 struct encaptab *ep, *match; 335 #ifdef USE_RADIX 336 struct radix_node_head *rnh = encap_rnh(AF_INET6); 337 struct radix_node *rn; 338 #endif 339 340 #ifdef DIAGNOSTIC 341 if (m->m_len < sizeof(*ip6)) 342 panic("encap6_lookup"); 343 #endif 344 ip6 = mtod(m, struct ip6_hdr *); 345 346 bzero(&pack, sizeof(pack)); 347 pack.p.sp_len = sizeof(pack); 348 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6; 349 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6); 350 if (dir == INBOUND) { 351 pack.mine.sin6_addr = ip6->ip6_dst; 352 pack.yours.sin6_addr = ip6->ip6_src; 353 } else { 354 pack.mine.sin6_addr = ip6->ip6_src; 355 pack.yours.sin6_addr = ip6->ip6_dst; 356 } 357 358 match = NULL; 359 matchprio = 0; 360 361 #ifdef USE_RADIX 362 rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh); 363 if (rn && (rn->rn_flags & RNF_ROOT) == 0) { 364 match = (struct encaptab *)rn; 365 matchprio = mask_matchlen(match->srcmask) + 366 mask_matchlen(match->dstmask); 367 } 368 #endif 369 370 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 371 if (ep->af != AF_INET6) 372 continue; 373 if (ep->proto >= 0 && ep->proto != proto) 374 continue; 375 if (ep->func) 376 prio = (*ep->func)(m, off, proto, ep->arg); 377 else { 378 #ifdef USE_RADIX 379 continue; 380 #else 381 prio = mask_match(ep, (struct sockaddr *)&pack.mine, 382 (struct sockaddr *)&pack.yours); 383 #endif 384 } 385 386 /* see encap4_lookup() for issues here */ 387 if (prio <= 0) 388 continue; 389 if (prio > matchprio) { 390 matchprio = prio; 391 match = ep; 392 } 393 } 394 395 return match; 396 #undef s 397 #undef d 398 } 399 400 int 401 encap6_input(struct mbuf **mp, int *offp, int proto) 402 { 403 struct mbuf *m = *mp; 404 const struct ip6protosw *psw; 405 struct encaptab *match; 406 407 match = encap6_lookup(m, *offp, proto, INBOUND); 408 409 if (match) { 410 /* found a match */ 411 psw = (const struct ip6protosw *)match->psw; 412 if (psw && psw->pr_input) { 413 encap_fillarg(m, match); 414 return (*psw->pr_input)(mp, offp, proto); 415 } else { 416 m_freem(m); 417 return IPPROTO_DONE; 418 } 419 } 420 421 /* last resort: inject to raw socket */ 422 return rip6_input(mp, offp, proto); 423 } 424 #endif 425 426 static int 427 encap_add(struct encaptab *ep) 428 { 429 #ifdef USE_RADIX 430 struct radix_node_head *rnh = encap_rnh(ep->af); 431 #endif 432 int error = 0; 433 434 LIST_INSERT_HEAD(&encaptab, ep, chain); 435 #ifdef USE_RADIX 436 if (!ep->func && rnh) { 437 if (!rnh->rnh_addaddr((caddr_t)ep->addrpack, 438 (caddr_t)ep->maskpack, rnh, ep->nodes)) { 439 error = EEXIST; 440 goto fail; 441 } 442 } 443 #endif 444 return error; 445 446 fail: 447 LIST_REMOVE(ep, chain); 448 return error; 449 } 450 451 static int 452 encap_remove(struct encaptab *ep) 453 { 454 #ifdef USE_RADIX 455 struct radix_node_head *rnh = encap_rnh(ep->af); 456 #endif 457 int error = 0; 458 459 LIST_REMOVE(ep, chain); 460 #ifdef USE_RADIX 461 if (!ep->func && rnh) { 462 if (!rnh->rnh_deladdr((caddr_t)ep->addrpack, 463 (caddr_t)ep->maskpack, rnh)) 464 error = ESRCH; 465 } 466 #endif 467 return error; 468 } 469 470 static int 471 encap_afcheck(int af, const struct sockaddr *sp, const struct sockaddr *dp) 472 { 473 if (sp && dp) { 474 if (sp->sa_len != dp->sa_len) 475 return EINVAL; 476 if (af != sp->sa_family || af != dp->sa_family) 477 return EINVAL; 478 } else if (!sp && !dp) 479 ; 480 else 481 return EINVAL; 482 483 switch (af) { 484 case AF_INET: 485 if (sp && sp->sa_len != sizeof(struct sockaddr_in)) 486 return EINVAL; 487 if (dp && dp->sa_len != sizeof(struct sockaddr_in)) 488 return EINVAL; 489 break; 490 #ifdef INET6 491 case AF_INET6: 492 if (sp && sp->sa_len != sizeof(struct sockaddr_in6)) 493 return EINVAL; 494 if (dp && dp->sa_len != sizeof(struct sockaddr_in6)) 495 return EINVAL; 496 break; 497 #endif 498 default: 499 return EAFNOSUPPORT; 500 } 501 502 return 0; 503 } 504 505 /* 506 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side. 507 * length of mask (sm and dm) is assumed to be same as sp/dp. 508 * Return value will be necessary as input (cookie) for encap_detach(). 509 */ 510 const struct encaptab * 511 encap_attach(int af, int proto, 512 const struct sockaddr *sp, const struct sockaddr *sm, 513 const struct sockaddr *dp, const struct sockaddr *dm, 514 const struct protosw *psw, void *arg) 515 { 516 struct encaptab *ep; 517 int error; 518 int s; 519 size_t l; 520 struct pack4 *pack4; 521 #ifdef INET6 522 struct pack6 *pack6; 523 #endif 524 525 s = splsoftnet(); 526 /* sanity check on args */ 527 error = encap_afcheck(af, sp, dp); 528 if (error) 529 goto fail; 530 531 /* check if anyone have already attached with exactly same config */ 532 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 533 if (ep->af != af) 534 continue; 535 if (ep->proto != proto) 536 continue; 537 if (ep->func) 538 continue; 539 #ifdef DIAGNOSTIC 540 if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask) 541 panic("null pointers in encaptab"); 542 #endif 543 if (ep->src->sa_len != sp->sa_len || 544 bcmp(ep->src, sp, sp->sa_len) != 0 || 545 bcmp(ep->srcmask, sm, sp->sa_len) != 0) 546 continue; 547 if (ep->dst->sa_len != dp->sa_len || 548 bcmp(ep->dst, dp, dp->sa_len) != 0 || 549 bcmp(ep->dstmask, dm, dp->sa_len) != 0) 550 continue; 551 552 error = EEXIST; 553 goto fail; 554 } 555 556 switch (af) { 557 case AF_INET: 558 l = sizeof(*pack4); 559 break; 560 #ifdef INET6 561 case AF_INET6: 562 l = sizeof(*pack6); 563 break; 564 #endif 565 default: 566 goto fail; 567 } 568 569 /* M_NETADDR ok? */ 570 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT|M_ZERO); 571 if (ep == NULL) { 572 error = ENOBUFS; 573 goto fail; 574 } 575 ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT|M_ZERO); 576 if (ep->addrpack == NULL) { 577 error = ENOBUFS; 578 goto gc; 579 } 580 ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT|M_ZERO); 581 if (ep->maskpack == NULL) { 582 error = ENOBUFS; 583 goto gc; 584 } 585 586 ep->af = af; 587 ep->proto = proto; 588 ep->addrpack->sa_len = l & 0xff; 589 ep->maskpack->sa_len = l & 0xff; 590 switch (af) { 591 case AF_INET: 592 pack4 = (struct pack4 *)ep->addrpack; 593 ep->src = (struct sockaddr *)&pack4->mine; 594 ep->dst = (struct sockaddr *)&pack4->yours; 595 pack4 = (struct pack4 *)ep->maskpack; 596 ep->srcmask = (struct sockaddr *)&pack4->mine; 597 ep->dstmask = (struct sockaddr *)&pack4->yours; 598 break; 599 #ifdef INET6 600 case AF_INET6: 601 pack6 = (struct pack6 *)ep->addrpack; 602 ep->src = (struct sockaddr *)&pack6->mine; 603 ep->dst = (struct sockaddr *)&pack6->yours; 604 pack6 = (struct pack6 *)ep->maskpack; 605 ep->srcmask = (struct sockaddr *)&pack6->mine; 606 ep->dstmask = (struct sockaddr *)&pack6->yours; 607 break; 608 #endif 609 } 610 611 bcopy(sp, ep->src, sp->sa_len); 612 bcopy(sm, ep->srcmask, sp->sa_len); 613 bcopy(dp, ep->dst, dp->sa_len); 614 bcopy(dm, ep->dstmask, dp->sa_len); 615 ep->psw = psw; 616 ep->arg = arg; 617 618 error = encap_add(ep); 619 if (error) 620 goto gc; 621 622 error = 0; 623 splx(s); 624 return ep; 625 626 gc: 627 if (ep->addrpack) 628 free(ep->addrpack, M_NETADDR); 629 if (ep->maskpack) 630 free(ep->maskpack, M_NETADDR); 631 if (ep) 632 free(ep, M_NETADDR); 633 fail: 634 splx(s); 635 return NULL; 636 } 637 638 const struct encaptab * 639 encap_attach_func(int af, int proto, 640 int (*func)(struct mbuf *, int, int, void *), 641 const struct protosw *psw, void *arg) 642 { 643 struct encaptab *ep; 644 int error; 645 int s; 646 647 s = splsoftnet(); 648 /* sanity check on args */ 649 if (!func) { 650 error = EINVAL; 651 goto fail; 652 } 653 654 error = encap_afcheck(af, NULL, NULL); 655 if (error) 656 goto fail; 657 658 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ 659 if (ep == NULL) { 660 error = ENOBUFS; 661 goto fail; 662 } 663 bzero(ep, sizeof(*ep)); 664 665 ep->af = af; 666 ep->proto = proto; 667 ep->func = func; 668 ep->psw = psw; 669 ep->arg = arg; 670 671 error = encap_add(ep); 672 if (error) 673 goto fail; 674 675 error = 0; 676 splx(s); 677 return ep; 678 679 fail: 680 splx(s); 681 return NULL; 682 } 683 684 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */ 685 686 #ifdef INET6 687 void 688 encap6_ctlinput(int cmd, struct sockaddr *sa, void *d0) 689 { 690 void *d = d0; 691 struct ip6_hdr *ip6; 692 struct mbuf *m; 693 int off; 694 struct ip6ctlparam *ip6cp = NULL; 695 int nxt; 696 struct encaptab *ep; 697 const struct ip6protosw *psw; 698 699 if (sa->sa_family != AF_INET6 || 700 sa->sa_len != sizeof(struct sockaddr_in6)) 701 return; 702 703 if ((unsigned)cmd >= PRC_NCMDS) 704 return; 705 if (cmd == PRC_HOSTDEAD) 706 d = NULL; 707 else if (cmd == PRC_MSGSIZE) 708 ; /* special code is present, see below */ 709 else if (inet6ctlerrmap[cmd] == 0) 710 return; 711 712 /* if the parameter is from icmp6, decode it. */ 713 if (d != NULL) { 714 ip6cp = (struct ip6ctlparam *)d; 715 m = ip6cp->ip6c_m; 716 ip6 = ip6cp->ip6c_ip6; 717 off = ip6cp->ip6c_off; 718 nxt = ip6cp->ip6c_nxt; 719 720 if (ip6 && cmd == PRC_MSGSIZE) { 721 int valid = 0; 722 struct encaptab *match; 723 724 /* 725 * Check to see if we have a valid encap configuration. 726 */ 727 match = encap6_lookup(m, off, nxt, OUTBOUND); 728 if (match) 729 valid++; 730 731 /* 732 * Depending on the value of "valid" and routing table 733 * size (mtudisc_{hi,lo}wat), we will: 734 * - recalcurate the new MTU and create the 735 * corresponding routing entry, or 736 * - ignore the MTU change notification. 737 */ 738 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 739 } 740 } else { 741 m = NULL; 742 ip6 = NULL; 743 nxt = -1; 744 } 745 746 /* inform all listeners */ 747 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { 748 if (ep->af != AF_INET6) 749 continue; 750 if (ep->proto >= 0 && ep->proto != nxt) 751 continue; 752 753 /* should optimize by looking at address pairs */ 754 755 /* XXX need to pass ep->arg or ep itself to listeners */ 756 psw = (const struct ip6protosw *)ep->psw; 757 if (psw && psw->pr_ctlinput) 758 (*psw->pr_ctlinput)(cmd, sa, d); 759 } 760 761 rip6_ctlinput(cmd, sa, d0); 762 } 763 #endif 764 765 int 766 encap_detach(const struct encaptab *cookie) 767 { 768 const struct encaptab *ep = cookie; 769 struct encaptab *p; 770 int error; 771 772 for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) { 773 if (p == ep) { 774 error = encap_remove(p); 775 if (error) 776 return error; 777 if (!ep->func) { 778 free(p->addrpack, M_NETADDR); 779 free(p->maskpack, M_NETADDR); 780 } 781 free(p, M_NETADDR); /*XXX*/ 782 return 0; 783 } 784 } 785 786 return ENOENT; 787 } 788 789 #ifdef USE_RADIX 790 static struct radix_node_head * 791 encap_rnh(int af) 792 { 793 794 switch (af) { 795 case AF_INET: 796 return encap_head[0]; 797 #ifdef INET6 798 case AF_INET6: 799 return encap_head[1]; 800 #endif 801 default: 802 return NULL; 803 } 804 } 805 806 static int 807 mask_matchlen(const struct sockaddr *sa) 808 { 809 const char *p, *ep; 810 int l; 811 812 p = (const char *)sa; 813 ep = p + sa->sa_len; 814 p += 2; /* sa_len + sa_family */ 815 816 l = 0; 817 while (p < ep) { 818 l += (*p ? 8 : 0); /* estimate */ 819 p++; 820 } 821 return l; 822 } 823 #endif 824 825 #ifndef USE_RADIX 826 static int 827 mask_match(const struct encaptab *ep, 828 const struct sockaddr *sp, 829 const struct sockaddr *dp) 830 { 831 struct sockaddr_storage s; 832 struct sockaddr_storage d; 833 int i; 834 const u_int8_t *p, *q; 835 u_int8_t *r; 836 int matchlen; 837 838 #ifdef DIAGNOSTIC 839 if (ep->func) 840 panic("wrong encaptab passed to mask_match"); 841 #endif 842 if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) 843 return 0; 844 if (sp->sa_family != ep->af || dp->sa_family != ep->af) 845 return 0; 846 if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len) 847 return 0; 848 849 matchlen = 0; 850 851 p = (const u_int8_t *)sp; 852 q = (const u_int8_t *)ep->srcmask; 853 r = (u_int8_t *)&s; 854 for (i = 0 ; i < sp->sa_len; i++) { 855 r[i] = p[i] & q[i]; 856 /* XXX estimate */ 857 matchlen += (q[i] ? 8 : 0); 858 } 859 860 p = (const u_int8_t *)dp; 861 q = (const u_int8_t *)ep->dstmask; 862 r = (u_int8_t *)&d; 863 for (i = 0 ; i < dp->sa_len; i++) { 864 r[i] = p[i] & q[i]; 865 /* XXX rough estimate */ 866 matchlen += (q[i] ? 8 : 0); 867 } 868 869 /* need to overwrite len/family portion as we don't compare them */ 870 s.ss_len = sp->sa_len; 871 s.ss_family = sp->sa_family; 872 d.ss_len = dp->sa_len; 873 d.ss_family = dp->sa_family; 874 875 if (bcmp(&s, ep->src, ep->src->sa_len) == 0 && 876 bcmp(&d, ep->dst, ep->dst->sa_len) == 0) { 877 return matchlen; 878 } else 879 return 0; 880 } 881 #endif 882 883 static void 884 encap_fillarg(struct mbuf *m, const struct encaptab *ep) 885 { 886 struct m_tag *mtag; 887 888 mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT); 889 if (mtag) { 890 *(void **)(mtag + 1) = ep->arg; 891 m_tag_prepend(m, mtag); 892 } 893 } 894 895 void * 896 encap_getarg(struct mbuf *m) 897 { 898 void *p; 899 struct m_tag *mtag; 900 901 p = NULL; 902 mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL); 903 if (mtag != NULL) { 904 p = *(void **)(mtag + 1); 905 m_tag_delete(m, mtag); 906 } 907 return p; 908 } 909