icmp6.c revision 1.6
1/* $NetBSD: icmp6.c,v 1.6 1999/07/09 22:57:26 thorpej 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/* 33 * Copyright (c) 1982, 1986, 1988, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 65 */ 66 67#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) 68#include "opt_inet.h" 69#include "opt_ipsec.h" 70#endif 71 72#include <sys/param.h> 73#include <sys/systm.h> 74#include <sys/malloc.h> 75#include <sys/mbuf.h> 76#include <sys/protosw.h> 77#include <sys/socket.h> 78#include <sys/socketvar.h> 79#include <sys/time.h> 80#include <sys/kernel.h> 81#include <sys/syslog.h> 82 83#include <net/if.h> 84#include <net/route.h> 85#include <net/if_dl.h> 86#include <net/if_types.h> 87 88#include <netinet/in.h> 89#include <netinet/in_var.h> 90#include <netinet6/in6_systm.h> 91#include <netinet6/ip6.h> 92#include <netinet6/ip6_var.h> 93#include <netinet6/icmp6.h> 94#include <netinet6/mld6_var.h> 95#if !defined(__FreeBSD__) || __FreeBSD__ < 3 96#include <netinet6/in6_pcb.h> 97#else 98#include <netinet/in_pcb.h> 99#endif 100#include <netinet6/nd6.h> 101#include <netinet6/in6_ifattach.h> 102 103#ifdef IPSEC 104#include <netkey/key.h> 105#include <netkey/key_debug.h> 106#endif 107 108#include "faith.h" 109 110extern struct protosw inet6sw[]; 111extern u_char ip6_protox[]; 112 113struct icmp6stat icmp6stat; 114 115#if !defined(__FreeBSD__) || __FreeBSD__ < 3 116extern struct in6pcb rawin6pcb; 117#else 118extern struct inpcbhead ripcb; 119#endif 120extern u_int icmp6errratelim; 121static int icmp6_rip6_input __P((struct mbuf **, int)); 122static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); 123static struct mbuf * ni6_input __P((struct mbuf *, int)); 124static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, 125 struct ifnet **)); 126static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, 127 struct ifnet *, int)); 128 129#ifdef COMPAT_RFC1885 130static struct route_in6 icmp6_reflect_rt; 131#endif 132static struct timeval icmp6_nextsend = {0, 0}; 133 134void 135icmp6_init() 136{ 137 mld6_init(); 138} 139 140/* 141 * Generate an error packet of type error in response to bad IP6 packet. 142 */ 143void 144icmp6_error(m, type, code, param) 145 struct mbuf *m; 146 int type, code, param; 147{ 148 struct ip6_hdr *oip6, *nip6; 149 struct icmp6_hdr *icmp6; 150 u_int prep; 151 int off; 152 u_char nxt; 153 154 icmp6stat.icp6s_error++; 155 156 if (m->m_flags & M_DECRYPTED) 157 goto freeit; 158 159 oip6 = mtod(m, struct ip6_hdr *); 160 161 /* 162 * Multicast destination check. For unrecognized option errors, 163 * this check has already done in ip6_unknown_opt(), so we can 164 * check only for other errors. 165 */ 166 if ((m->m_flags & (M_BCAST|M_MCAST) || 167 IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) && 168 (type != ICMP6_PACKET_TOO_BIG && 169 (type != ICMP6_PARAM_PROB || 170 code != ICMP6_PARAMPROB_OPTION))) 171 goto freeit; 172 173 /* Source address check. XXX: the case of anycast source? */ 174 if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) || 175 IN6_IS_ADDR_MULTICAST(&oip6->ip6_src)) 176 goto freeit; 177 178 /* 179 * If the erroneous packet is also an ICMP error, discard it. 180 */ 181 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), ); 182 off = sizeof(struct ip6_hdr); 183 nxt = oip6->ip6_nxt; 184 while(1) { /* XXX: should avoid inf. loop explicitly? */ 185 struct ip6_ext *ip6e; 186 struct icmp6_hdr *icp; 187 188 switch(nxt) { 189 case IPPROTO_IPV6: 190 case IPPROTO_IPV4: 191 case IPPROTO_UDP: 192 case IPPROTO_TCP: 193 case IPPROTO_ESP: 194 case IPPROTO_FRAGMENT: 195 /* 196 * ICMPv6 error must not be fragmented. 197 * XXX: but can we trust the sender? 198 */ 199 default: 200 /* What if unknown header followed by ICMP error? */ 201 goto generate; 202 case IPPROTO_ICMPV6: 203 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), ); 204 icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); 205 if (icp->icmp6_type < ICMP6_ECHO_REQUEST 206 || icp->icmp6_type == ND_REDIRECT) { 207 /* 208 * ICMPv6 error 209 * Special case: for redirect (which is 210 * informational) we must not send icmp6 error. 211 */ 212 icmp6stat.icp6s_canterror++; 213 goto freeit; 214 } else { 215 /* ICMPv6 informational */ 216 goto generate; 217 } 218 case IPPROTO_HOPOPTS: 219 case IPPROTO_DSTOPTS: 220 case IPPROTO_ROUTING: 221 case IPPROTO_AH: 222 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct ip6_ext), ); 223 ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); 224 if (nxt == IPPROTO_AH) 225 off += (ip6e->ip6e_len + 2) << 2; 226 else 227 off += (ip6e->ip6e_len + 1) << 3; 228 nxt = ip6e->ip6e_nxt; 229 break; 230 } 231 } 232 233 freeit: 234 /* 235 * If we can't tell wheter or not we can generate ICMP6, free it. 236 */ 237 m_freem(m); 238 return; 239 240 generate: 241 oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */ 242 243 /* Finally, do rate limitation check. */ 244 if (icmp6_ratelimit(&oip6->ip6_src, type, code)) { 245 icmp6stat.icp6s_toofreq++; 246 goto freeit; 247 } 248 249 /* 250 * OK, ICMP6 can be generated. 251 */ 252 253 if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN) 254 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len); 255 256 prep = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); 257 M_PREPEND(m, prep, M_DONTWAIT); 258 if (m && m->m_len < prep) 259 m = m_pullup(m, prep); 260 if (m == NULL) { 261 printf("ENOBUFS in icmp6_error %d\n", __LINE__); 262 return; 263 } 264 265 nip6 = mtod(m, struct ip6_hdr *); 266 nip6->ip6_src = oip6->ip6_src; 267 nip6->ip6_dst = oip6->ip6_dst; 268 269 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) 270 oip6->ip6_src.s6_addr16[1] = 0; 271 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) 272 oip6->ip6_dst.s6_addr16[1] = 0; 273 274 icmp6 = (struct icmp6_hdr *)(nip6 + 1); 275 icmp6->icmp6_type = type; 276 icmp6->icmp6_code = code; 277 icmp6->icmp6_pptr = htonl((u_long)param); 278 279 icmp6stat.icp6s_outhist[type]++; 280 icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/ 281} 282 283/* 284 * Process a received ICMP6 message. 285 */ 286int 287icmp6_input(mp, offp, proto) 288 struct mbuf **mp; 289 int *offp, proto; 290{ 291 struct mbuf *m = *mp, *n; 292 struct ip6_hdr *ip6, *nip6; 293 struct icmp6_hdr *icmp6, *nicmp6; 294 int off = *offp; 295 int icmp6len = m->m_pkthdr.len - *offp; 296 int code, sum, noff; 297 struct sockaddr_in6 icmp6src; 298 299 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE); 300 /* m might change if M_LOOP. So, call mtod after this */ 301 302 /* 303 * Locate icmp6 structure in mbuf, and check 304 * that not corrupted and of at least minimum length 305 */ 306 307 ip6 = mtod(m, struct ip6_hdr *); 308 if (icmp6len < sizeof(struct icmp6_hdr)) { 309 icmp6stat.icp6s_tooshort++; 310 goto freeit; 311 } 312 313 /* 314 * calculate the checksum 315 */ 316 317 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off); 318 code = icmp6->icmp6_code; 319 320 if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) { 321 log(LOG_ERR, 322 "ICMP6 checksum error(%d|%x) %s\n", 323 icmp6->icmp6_type, 324 sum, 325 ip6_sprintf(&ip6->ip6_src)); 326 icmp6stat.icp6s_checksum++; 327 goto freeit; 328 } 329 330#if defined(NFAITH) && 0 < NFAITH 331 if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 332 /* 333 * Deliver very specific ICMP6 type only. 334 * This is important to deilver TOOBIG. Otherwise PMTUD 335 * will not work. 336 */ 337 switch (icmp6->icmp6_type) { 338 case ICMP6_DST_UNREACH: 339 case ICMP6_PACKET_TOO_BIG: 340 case ICMP6_TIME_EXCEEDED: 341 break; 342 default: 343 goto freeit; 344 } 345 } 346#endif 347 348#ifdef IPSEC 349 /* drop it if it does not match the default policy */ 350 if (ipsec6_in_reject(m, NULL)) { 351 ipsecstat.in_polvio++; 352 goto freeit; 353 } 354#endif 355 356 icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; 357 358 switch (icmp6->icmp6_type) { 359 360 case ICMP6_DST_UNREACH: 361 switch (code) { 362 case ICMP6_DST_UNREACH_NOROUTE: 363 code = PRC_UNREACH_NET; 364 break; 365 case ICMP6_DST_UNREACH_ADMIN: 366 case ICMP6_DST_UNREACH_ADDR: 367 code = PRC_UNREACH_HOST; 368 break; 369 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 370 code = PRC_UNREACH_SRCFAIL; 371 break; 372 case ICMP6_DST_UNREACH_NOPORT: 373 code = PRC_UNREACH_PORT; 374 break; 375 default: 376 goto badcode; 377 } 378 goto deliver; 379 break; 380 381 case ICMP6_PACKET_TOO_BIG: 382 if (code != 0) 383 goto badcode; 384 { 385 u_int mtu = ntohl(icmp6->icmp6_mtu); 386 struct rtentry *rt; 387 struct sockaddr_in6 sin6; 388#ifdef __bsdi__ 389 struct route_in6 ro6; 390#endif 391 392 code = PRC_MSGSIZE; 393 bzero(&sin6, sizeof(sin6)); 394 sin6.sin6_family = PF_INET6; 395 sin6.sin6_len = sizeof(struct sockaddr_in6); 396 sin6.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; 397 rt = rtalloc1((struct sockaddr *)&sin6, 0 398#ifdef __FreeBSD__ 399 , RTF_CLONING | RTF_PRCLONING 400#endif /*__FreeBSD__*/ 401 ); 402#ifdef __bsdi__ 403 bcopy(&sin6, &ro6.ro_dst, sizeof(struct sockaddr_in6)); 404 ro6.ro_rt = 0; 405 rtcalloc((struct route *)&ro6); 406 rt = ro6.ro_rt; 407#endif /*__bsdi__*/ 408 if (rt && (rt->rt_flags & RTF_HOST) 409 && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { 410 if (mtu < IPV6_MMTU) { 411 /* xxx */ 412 rt->rt_rmx.rmx_locks |= RTV_MTU; 413 } else if (mtu < rt->rt_ifp->if_mtu && 414 rt->rt_rmx.rmx_mtu > mtu) { 415 rt->rt_rmx.rmx_mtu = mtu; 416 } 417 } 418 if (rt) 419 RTFREE(rt); 420 421 goto deliver; 422 } 423 break; 424 425 case ICMP6_TIME_EXCEEDED: 426 switch (code) { 427 case ICMP6_TIME_EXCEED_TRANSIT: 428 case ICMP6_TIME_EXCEED_REASSEMBLY: 429 code += PRC_TIMXCEED_INTRANS; 430 break; 431 default: 432 goto badcode; 433 } 434 goto deliver; 435 break; 436 437 case ICMP6_PARAM_PROB: 438 switch (code) { 439 case ICMP6_PARAMPROB_NEXTHEADER: 440 code = PRC_UNREACH_PROTOCOL; 441 break; 442 case ICMP6_PARAMPROB_HEADER: 443 case ICMP6_PARAMPROB_OPTION: 444 code = PRC_PARAMPROB; 445 break; 446 default: 447 goto badcode; 448 } 449 goto deliver; 450 break; 451 452 case ICMP6_ECHO_REQUEST: 453 if (code != 0) 454 goto badcode; 455 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) { 456 /* Give up remote */ 457 break; 458 } 459 if (n->m_flags & M_EXT) { 460 int gap, move; 461 struct mbuf *n0 = n; 462 463 /* 464 * Prepare an internal mbuf. m_pullup() doesn't 465 * always copy the length we specified. 466 */ 467 MGETHDR(n, M_DONTWAIT, n0->m_type); 468 if (n == NULL) { 469 /* Give up remote */ 470 m_freem(n0); 471 break; 472 } 473 M_COPY_PKTHDR(n, n0); 474 n0->m_flags &= ~M_PKTHDR; 475 n->m_next = n0; 476 /* 477 * Copy IPv6 and ICMPv6 only. 478 */ 479 nip6 = mtod(n, struct ip6_hdr *); 480 bcopy(ip6, nip6, sizeof(struct ip6_hdr)); 481 nicmp6 = (struct icmp6_hdr *)(nip6 + 1); 482 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); 483 /* 484 * Adjust mbuf. ip6_plen will be adjusted. 485 */ 486 noff = sizeof(struct ip6_hdr); 487 n->m_len = noff + sizeof(struct icmp6_hdr); 488 move = off + sizeof(struct icmp6_hdr); 489 n0->m_len -= move; 490 n0->m_data += move; 491 gap = off - noff; 492 n->m_pkthdr.len -= gap; 493 } else { 494 nip6 = mtod(n, struct ip6_hdr *); 495 nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off); 496 noff = off; 497 } 498 nicmp6->icmp6_type = ICMP6_ECHO_REPLY; 499 nicmp6->icmp6_code = 0; 500 icmp6stat.icp6s_reflect++; 501 icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++; 502 icmp6_reflect(n, noff); 503 break; 504 505 case ICMP6_ECHO_REPLY: 506 if (code != 0) 507 goto badcode; 508 break; 509 510 case MLD6_LISTENER_QUERY: 511 case MLD6_LISTENER_REPORT: 512 if (icmp6len < sizeof(struct mld6_hdr)) 513 goto badlen; 514 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE); 515 mld6_input(m, off); 516 /* m stays. */ 517 break; 518 519 case MLD6_LISTENER_DONE: 520 if (icmp6len < sizeof(struct mld6_hdr)) 521 goto badlen; 522 break; /* nothing to be done in kernel */ 523 524 case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */ 525 { 526 enum { WRU, FQDN } mode; 527 528 if (code != 0) 529 goto badcode; 530 if (icmp6len == sizeof(struct icmp6_hdr) + 4) 531 mode = WRU; 532 else if (icmp6len >= sizeof(struct icmp6_hdr) + 8) /* XXX */ 533 mode = FQDN; 534 else 535 goto badlen; 536 537#ifdef __FreeBSD__ 538#define hostnamelen strlen(hostname) 539#endif 540 if (mode == FQDN) { 541 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo), 542 IPPROTO_DONE); 543 n = ni6_input(m, off); 544 noff = sizeof(struct ip6_hdr); 545 } 546 else { 547 u_char *p; 548 549 MGETHDR(n, M_DONTWAIT, m->m_type); 550 if (n == NULL) { 551 /* Give up remote */ 552 break; 553 } 554 /* 555 * Copy IPv6 and ICMPv6 only. 556 */ 557 nip6 = mtod(n, struct ip6_hdr *); 558 bcopy(ip6, nip6, sizeof(struct ip6_hdr)); 559 nicmp6 = (struct icmp6_hdr *)(nip6 + 1); 560 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); 561 p = (u_char *)(nicmp6 + 1); 562 bzero(p, 4); 563 bcopy(hostname, p + 4, hostnamelen); 564 noff = sizeof(struct ip6_hdr); 565 M_COPY_PKTHDR(n, m); /* just for recvif */ 566 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + 567 sizeof(struct icmp6_hdr) + 4 + hostnamelen; 568 nicmp6->icmp6_type = ICMP6_WRUREPLY; 569 nicmp6->icmp6_code = 0; 570 } 571#undef hostnamelen 572 if (n) { 573 icmp6stat.icp6s_reflect++; 574 icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++; 575 icmp6_reflect(n, noff); 576 } 577 break; 578 } 579 580 case ICMP6_WRUREPLY: 581 if (code != 0) 582 goto badcode; 583 break; 584 585 case ND_ROUTER_SOLICIT: 586 if (code != 0) 587 goto badcode; 588 if (icmp6len < sizeof(struct nd_router_solicit)) 589 goto badlen; 590 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE); 591 nd6_rs_input(m, off, icmp6len); 592 /* m stays. */ 593 break; 594 595 case ND_ROUTER_ADVERT: 596 if (code != 0) 597 goto badcode; 598 if (icmp6len < sizeof(struct nd_router_advert)) 599 goto badlen; 600 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE); 601 nd6_ra_input(m, off, icmp6len); 602 /* m stays. */ 603 break; 604 605 case ND_NEIGHBOR_SOLICIT: 606 if (code != 0) 607 goto badcode; 608 if (icmp6len < sizeof(struct nd_neighbor_solicit)) 609 goto badlen; 610 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE); 611 nd6_ns_input(m, off, icmp6len); 612 /* m stays. */ 613 break; 614 615 case ND_NEIGHBOR_ADVERT: 616 if (code != 0) 617 goto badcode; 618 if (icmp6len < sizeof(struct nd_neighbor_advert)) 619 goto badlen; 620 IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE); 621 nd6_na_input(m, off, icmp6len); 622 /* m stays. */ 623 break; 624 625 case ND_REDIRECT: 626 if (code != 0) 627 goto badcode; 628 if (icmp6len < sizeof(struct nd_redirect)) 629 goto badlen; 630 icmp6_redirect_input(m, off); 631 /* m stays. */ 632 break; 633 634 case ICMP6_ROUTER_RENUMBERING: 635 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND && 636 code != ICMP6_ROUTER_RENUMBERING_RESULT) 637 goto badcode; 638 if (icmp6len < sizeof(struct icmp6_router_renum)) 639 goto badlen; 640 break; 641 642 default: 643 printf("icmp6_input: unknown type %d\n", icmp6->icmp6_type); 644 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { 645 /* ICMPv6 error: MUST deliver it by spec... */ 646 code = PRC_NCMDS; 647 /* deliver */ 648 } else { 649 /* ICMPv6 informational: MUST not deliver */ 650 break; 651 } 652 deliver: 653 if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { 654 icmp6stat.icp6s_tooshort++; 655 goto freeit; 656 } 657 IP6_EXTHDR_CHECK(m, off, 658 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), 659 IPPROTO_DONE); 660 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); 661 bzero(&icmp6src, sizeof(icmp6src)); 662 icmp6src.sin6_len = sizeof(struct sockaddr_in6); 663 icmp6src.sin6_family = AF_INET6; 664 icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; 665 666 /* Detect the upper level protocol */ 667 { 668 void (*ctlfunc) __P((int, struct sockaddr *, 669 struct ip6_hdr *, 670 struct mbuf *, int)); /* XXX */ 671 struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1); 672 u_int8_t nxt = eip6->ip6_nxt; 673 int eoff = off + sizeof(struct icmp6_hdr) + 674 sizeof(struct ip6_hdr); 675 676 while (1) { /* XXX: should avoid inf. loop explicitly? */ 677 struct ip6_ext *eh; 678 679 switch(nxt) { 680 case IPPROTO_ESP: 681 case IPPROTO_NONE: 682 goto passit; 683 case IPPROTO_HOPOPTS: 684 case IPPROTO_DSTOPTS: 685 case IPPROTO_ROUTING: 686 case IPPROTO_AH: 687 case IPPROTO_FRAGMENT: 688 IP6_EXTHDR_CHECK(m, 0, eoff + 689 sizeof(struct ip6_ext), 690 IPPROTO_DONE); 691 eh = (struct ip6_ext *)(mtod(m, caddr_t) 692 + eoff); 693 if (nxt == IPPROTO_AH) 694 eoff += (eh->ip6e_len + 2) << 2; 695 else if (nxt == IPPROTO_FRAGMENT) 696 eoff += sizeof(struct ip6_frag); 697 else 698 eoff += (eh->ip6e_len + 1) << 3; 699 nxt = eh->ip6e_nxt; 700 break; 701 default: 702 goto notify; 703 } 704 } 705 notify: 706 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); 707 ctlfunc = (void (*) __P((int, struct sockaddr *, 708 struct ip6_hdr *, 709 struct mbuf *, int))) 710 (inet6sw[ip6_protox[nxt]].pr_ctlinput); 711 if (ctlfunc) 712 (*ctlfunc)(code, (struct sockaddr *)&icmp6src, 713 (struct ip6_hdr *)(icmp6 + 1), 714 m, eoff); 715 } 716 break; 717 718 badcode: 719 icmp6stat.icp6s_badcode++; 720 break; 721 722 badlen: 723 icmp6stat.icp6s_badlen++; 724 break; 725 } 726 727 passit: 728 icmp6_rip6_input(&m, *offp); 729 return IPPROTO_DONE; 730 731 freeit: 732 m_freem(m); 733 return IPPROTO_DONE; 734} 735 736/* 737 * Process a Node Information Query 738 */ 739#ifdef __FreeBSD__ 740#define hostnamelen strlen(hostname) 741#endif 742#ifndef offsetof /* XXX */ 743#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 744#endif 745 746static struct mbuf * 747ni6_input(m, off) 748 struct mbuf *m; 749 int off; 750{ 751 struct icmp6_nodeinfo *ni6 = 752 (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off), *nni6; 753 struct mbuf *n = NULL; 754 u_int16_t qtype = ntohs(ni6->ni_qtype); 755 int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); 756 struct ni_reply_fqdn *fqdn; 757 int addrs; /* for NI_QTYPE_NODEADDR */ 758 struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ 759 760 switch(qtype) { 761 case NI_QTYPE_NOOP: 762 break; /* no reply data */ 763 case NI_QTYPE_SUPTYPES: 764 goto bad; /* xxx: to be implemented */ 765 break; 766 case NI_QTYPE_FQDN: 767 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) + 768 hostnamelen; 769 break; 770 case NI_QTYPE_NODEADDR: 771 addrs = ni6_addrs(ni6, m, &ifp); 772 if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES) 773 replylen = MCLBYTES; /* XXX: we'll truncate later */ 774 775 break; 776 default: 777 /* 778 * XXX: We must return a reply with the ICMP6 code 779 * `unknown Qtype' in this case. However we regard the case 780 * as an FQDN query for backward compatibility. 781 * Older versions set a random value to this field, 782 * so it rarely varies in the defined qtypes. 783 * But the mechanism is not reliable... 784 * maybe we should obsolete older versions. 785 */ 786 qtype = NI_QTYPE_FQDN; 787 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) + 788 hostnamelen; 789 break; 790 } 791 792 /* allocate a mbuf to reply. */ 793 MGETHDR(n, M_DONTWAIT, m->m_type); 794 if (n == NULL) 795 return(NULL); 796 M_COPY_PKTHDR(n, m); /* just for recvif */ 797 if (replylen > MHLEN) { 798 if (replylen > MCLBYTES) 799 /* 800 * XXX: should we try to allocate more? But MCLBYTES is 801 * probably much larger than IPV6_MMTU... 802 */ 803 goto bad; 804 MCLGET(n, M_DONTWAIT); 805 if ((n->m_flags & M_EXT) == 0) { 806 goto bad; 807 } 808 } 809 n->m_pkthdr.len = n->m_len = replylen; 810 811 /* copy mbuf header and IPv6 + Node Information base headers */ 812 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr)); 813 nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1); 814 bcopy(mtod(m, caddr_t) + off, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); 815 816 /* qtype dependent procedure */ 817 switch (qtype) { 818 case NI_QTYPE_NOOP: 819 nni6->ni_flags = 0; 820 break; 821 case NI_QTYPE_SUPTYPES: 822 goto bad; /* xxx: to be implemented */ 823 break; 824 case NI_QTYPE_FQDN: 825 if (hostnamelen > 255) { /* XXX: rare case, but may happen */ 826 printf("ni6_input: " 827 "hostname length(%d) is too large for reply\n", 828 hostnamelen); 829 goto bad; 830 } 831 fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) + 832 sizeof(struct ip6_hdr) + 833 sizeof(struct icmp6_nodeinfo)); 834 nni6->ni_flags = 0; /* XXX: meaningless TTL */ 835 fqdn->ni_fqdn_ttl = 0; /* ditto. */ 836 fqdn->ni_fqdn_namelen = hostnamelen; 837 bcopy(hostname, &fqdn->ni_fqdn_name[0], hostnamelen); 838 break; 839 case NI_QTYPE_NODEADDR: 840 { 841 int lenlim, copied; 842 843 if (n->m_flags & M_EXT) 844 lenlim = MCLBYTES - sizeof(struct ip6_hdr) - 845 sizeof(struct icmp6_nodeinfo); 846 else 847 lenlim = MHLEN - sizeof(struct ip6_hdr) - 848 sizeof(struct icmp6_nodeinfo); 849 copied = ni6_store_addrs(ni6, nni6, ifp, lenlim); 850 /* XXX: reset mbuf length */ 851 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + 852 sizeof(struct icmp6_nodeinfo) + copied; 853 break; 854 } 855 default: 856 break; /* XXX impossible! */ 857 } 858 859 nni6->ni_type = ICMP6_NI_REPLY; 860 nni6->ni_code = ICMP6_NI_SUCESS; 861 return(n); 862 863 bad: 864 if (n) 865 m_freem(n); 866 return(NULL); 867} 868#undef hostnamelen 869 870/* 871 * calculate the number of addresses to be returned in the node info reply. 872 */ 873static int 874ni6_addrs(ni6, m, ifpp) 875 struct icmp6_nodeinfo *ni6; 876 struct mbuf *m; 877 struct ifnet **ifpp; 878{ 879 register struct ifnet *ifp; 880 register struct in6_ifaddr *ifa6; 881 register struct ifaddr *ifa; 882 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 883 int addrs = 0, addrsofif, iffound = 0; 884 885#ifdef __NetBSD__ 886 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) 887#else 888 for (ifp = ifnet; ifp; ifp = ifp->if_next) 889#endif 890 { 891 addrsofif = 0; 892#ifdef __NetBSD__ 893 for (ifa = ifp->if_addrlist.tqh_first; ifa; 894 ifa = ifa->ifa_list.tqe_next) 895#else 896 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 897#endif 898 { 899 if (ifa->ifa_addr->sa_family != AF_INET6) 900 continue; 901 ifa6 = (struct in6_ifaddr *)ifa; 902 903 if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) && 904 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 905 &ifa6->ia_addr.sin6_addr)) 906 iffound = 1; 907 908 if (ifa6->ia6_flags & IN6_IFF_ANYCAST) 909 continue; /* we need only unicast addresses */ 910 911 if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL | 912 NI_NODEADDR_FLAG_SITELOCAL | 913 NI_NODEADDR_FLAG_GLOBAL)) == 0) 914 continue; 915 916 /* What do we have to do about ::1? */ 917 switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { 918 case IPV6_ADDR_SCOPE_LINKLOCAL: 919 if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) 920 addrsofif++; 921 break; 922 case IPV6_ADDR_SCOPE_SITELOCAL: 923 if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) 924 addrsofif++; 925 break; 926 case IPV6_ADDR_SCOPE_GLOBAL: 927 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) 928 addrsofif++; 929 break; 930 default: 931 continue; 932 } 933 } 934 if (iffound) { 935 *ifpp = ifp; 936 return(addrsofif); 937 } 938 939 addrs += addrsofif; 940 } 941 942 return(addrs); 943} 944 945static int 946ni6_store_addrs(ni6, nni6, ifp0, resid) 947 struct icmp6_nodeinfo *ni6, *nni6; 948 struct ifnet *ifp0; 949 int resid; 950{ 951#ifdef __NetBSD__ 952 register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); 953#else 954 register struct ifnet *ifp = ifp0 ? ifp0 : ifnet; 955#endif 956 register struct in6_ifaddr *ifa6; 957 register struct ifaddr *ifa; 958 int docopy, copied = 0; 959 u_char *cp = (u_char *)(nni6 + 1); 960 961 if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL)) 962 return(0); /* needless to copy */ 963 964#ifdef __NetBSD__ 965 for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) 966#else 967 for (; ifp; ifp = ifp->if_next) 968#endif 969 { 970#ifdef __NetBSD__ 971 for (ifa = ifp->if_addrlist.tqh_first; ifa; 972 ifa = ifa->ifa_list.tqe_next) 973#else 974 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 975#endif 976 { 977 docopy = 0; 978 979 if (ifa->ifa_addr->sa_family != AF_INET6) 980 continue; 981 ifa6 = (struct in6_ifaddr *)ifa; 982 983 if (ifa6->ia6_flags & IN6_IFF_ANYCAST) 984 continue; /* we need only unicast addresses */ 985 986 /* What do we have to do about ::1? */ 987 switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { 988 case IPV6_ADDR_SCOPE_LINKLOCAL: 989 if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) 990 docopy = 1; 991 break; 992 case IPV6_ADDR_SCOPE_SITELOCAL: 993 if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) 994 docopy = 1; 995 break; 996 case IPV6_ADDR_SCOPE_GLOBAL: 997 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) 998 docopy = 1; 999 break; 1000 default: 1001 continue; 1002 } 1003 1004 if (docopy) { 1005 if (resid < sizeof(struct in6_addr)) { 1006 /* 1007 * We give up much more copy. 1008 * Set the truncate flag and return. 1009 */ 1010 nni6->ni_flags |= 1011 NI_NODEADDR_FLAG_TRUNCATE; 1012 return(copied); 1013 } 1014 bcopy(&ifa6->ia_addr.sin6_addr, cp, 1015 sizeof(struct in6_addr)); 1016 /* XXX: KAME link-local hack; remove ifindex */ 1017 if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) 1018 ((struct in6_addr *)cp)->s6_addr16[1] = 0; 1019 cp += sizeof(struct in6_addr); 1020 resid -= sizeof(struct in6_addr); 1021 copied += sizeof(struct in6_addr); 1022 } 1023 } 1024 if (ifp0) /* we need search only on the specified IF */ 1025 break; 1026 } 1027 1028 return(copied); 1029} 1030 1031/* 1032 * XXX almost dup'ed code with rip6_input. 1033 */ 1034static int 1035icmp6_rip6_input(mp, off) 1036 struct mbuf **mp; 1037 int off; 1038{ 1039 struct mbuf *m = *mp; 1040 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1041 register struct in6pcb *in6p; 1042 struct in6pcb *last = NULL; 1043 struct sockaddr_in6 rip6src; 1044 struct icmp6_hdr *icmp6; 1045 struct mbuf *opts = NULL; 1046 1047 /* this is assumed to be safe. */ 1048 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off); 1049 1050 bzero(&rip6src, sizeof(rip6src)); 1051 rip6src.sin6_len = sizeof(struct sockaddr_in6); 1052 rip6src.sin6_family = AF_INET6; 1053 rip6src.sin6_addr = ip6->ip6_src; 1054 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr)) 1055 rip6src.sin6_addr.s6_addr16[1] = 0; 1056 if (m->m_pkthdr.rcvif) { 1057 if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr)) 1058 rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index; 1059 else 1060 rip6src.sin6_scope_id = 0; 1061 } else 1062 rip6src.sin6_scope_id = 0; 1063 1064#if !defined(__FreeBSD__) || __FreeBSD__ < 3 1065 for (in6p = rawin6pcb.in6p_next; 1066 in6p != &rawin6pcb; in6p = in6p->in6p_next) 1067#else 1068 LIST_FOREACH(in6p, &ripcb, inp_list) 1069#endif 1070 { 1071#if defined(__FreeBSD__) && __FreeBSD__ >= 3 1072 if ((in6p->inp_vflag & INP_IPV6) == NULL) 1073 continue; 1074#endif 1075 if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) 1076 continue; 1077 if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr) && 1078 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) 1079 continue; 1080 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr) && 1081 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) 1082 continue; 1083 if (in6p->in6p_icmp6filt 1084 && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type, 1085 in6p->in6p_icmp6filt)) 1086 continue; 1087 if (last) { 1088 struct mbuf *n; 1089 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 1090 if (last->in6p_flags & IN6P_CONTROLOPTS) 1091 ip6_savecontrol(last, &opts, ip6, n); 1092 /* strip intermediate headers */ 1093 m_adj(n, off); 1094 if (sbappendaddr(&last->in6p_socket->so_rcv, 1095 (struct sockaddr *)&rip6src, 1096 n, opts) == 0) { 1097 /* should notify about lost packet */ 1098 m_freem(n); 1099 if (opts) 1100 m_freem(opts); 1101 } else 1102 sorwakeup(last->in6p_socket); 1103 opts = NULL; 1104 } 1105 } 1106 last = in6p; 1107 } 1108 if (last) { 1109 if (last->in6p_flags & IN6P_CONTROLOPTS) 1110 ip6_savecontrol(last, &opts, ip6, m); 1111 /* strip intermediate headers */ 1112 m_adj(m, off); 1113 if (sbappendaddr(&last->in6p_socket->so_rcv, 1114 (struct sockaddr *)&rip6src, m, opts) == 0) { 1115 m_freem(m); 1116 if (opts) 1117 m_freem(opts); 1118 } else 1119 sorwakeup(last->in6p_socket); 1120 } else { 1121 m_freem(m); 1122 ip6stat.ip6s_delivered--; 1123 } 1124 return IPPROTO_DONE; 1125} 1126 1127/* 1128 * Reflect the ip6 packet back to the source. 1129 * The caller MUST check if the destination is multicast or not. 1130 * This function is usually called with a unicast destination which 1131 * can be safely the source of the reply packet. But some exceptions 1132 * exist(e.g. ECHOREPLY, PATCKET_TOOBIG, "10" in OPTION type). 1133 * ``off'' points to the icmp6 header, counted from the top of the mbuf. 1134 */ 1135void 1136icmp6_reflect(m, off) 1137 struct mbuf *m; 1138 size_t off; 1139{ 1140 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1141 struct icmp6_hdr *icmp6; 1142 struct in6_ifaddr *ia; 1143 struct in6_addr t, *src = 0; 1144 int plen = m->m_pkthdr.len - sizeof(struct ip6_hdr); 1145#ifdef COMPAT_RFC1885 1146 int mtu = IPV6_MMTU; 1147 struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst; 1148#endif 1149 1150 /* 1151 * If there are extra headers between IPv6 and ICMPv6, strip 1152 * off that header first. 1153 */ 1154 if (off != sizeof(struct ip6_hdr)) { 1155 size_t siz; 1156 1157 /* sanity checks */ 1158 if (off < sizeof(struct ip6_hdr)) { 1159 printf("sanity fail: off=%x, sizeof(ip6)=%x in %s:%d\n", 1160 (unsigned int)off, 1161 (unsigned int)sizeof(struct ip6_hdr), 1162 __FILE__, __LINE__); 1163 goto bad; 1164 } 1165 siz = off - sizeof(struct ip6_hdr); 1166 if (plen < siz) { 1167 printf("sanity fail: siz=%x, payloadlen=%x in %s:%d\n", 1168 (unsigned int)siz, plen, __FILE__, __LINE__); 1169 goto bad; 1170 } 1171 IP6_EXTHDR_CHECK(m, 0, off, /*nothing*/); 1172 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), /*nothing*/); 1173 1174 bcopy((caddr_t)ip6, 1175 (caddr_t)(mtod(m, u_char *) + siz), 1176 sizeof(struct ip6_hdr)); 1177 m->m_data += siz; 1178 m->m_len -= siz; 1179 m->m_pkthdr.len -= siz; 1180 ip6 = mtod(m, struct ip6_hdr *); 1181 ip6->ip6_nxt = IPPROTO_ICMPV6; 1182 plen -= siz; 1183 } 1184 1185 icmp6 = (struct icmp6_hdr *)(ip6 + 1); 1186 1187 t = ip6->ip6_dst; 1188 /* 1189 * ip6_input() drops a packet if its src is multicast. 1190 * So, the src is never multicast. 1191 */ 1192 ip6->ip6_dst = ip6->ip6_src; 1193 1194 /* XXX hack for link-local addresses */ 1195 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) 1196 ip6->ip6_dst.s6_addr16[1] = 1197 htons(m->m_pkthdr.rcvif->if_index); 1198 if (IN6_IS_ADDR_LINKLOCAL(&t)) 1199 t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 1200 1201#ifdef COMPAT_RFC1885 1202 /* 1203 * xxx guess MTU 1204 * RFC 1885 requires that echo reply should be truncated if it 1205 * does not fit in with (return) path MTU, but the description was 1206 * removed in the new spec. 1207 */ 1208 if (icmp6_reflect_rt.ro_rt == 0 || 1209 ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) { 1210 if (icmp6_reflect_rt.ro_rt) { 1211#ifdef __FreeBSD__ 1212 RTFREE(icmp6_reflect_rt.ro_rt); 1213#endif 1214#ifdef __bsdi__ 1215 rtfree(icmp6_reflect_rt.ro_rt); 1216#endif 1217 icmp6_reflect_rt.ro_rt = 0; 1218 } 1219 bzero(sin6, sizeof(*sin6)); 1220 sin6->sin6_family = PF_INET6; 1221 sin6->sin6_len = sizeof(struct sockaddr_in6); 1222 sin6->sin6_addr = ip6->ip6_dst; 1223 1224#ifdef __NetBSD__ 1225 rtalloc((struct route *)&icmp6_reflect_rt.ro_rt); 1226#else 1227 rtalloc_ign((struct route *)&icmp6_reflect_rt.ro_rt, 1228 RTF_PRCLONING); 1229#endif 1230 } 1231 1232 if (icmp6_reflect_rt.ro_rt == 0) 1233 goto bad; 1234 1235 if ((icmp6_reflect_rt.ro_rt->rt_flags & RTF_HOST) 1236 && mtu < icmp6_reflect_rt.ro_rt->rt_ifp->if_mtu) 1237 mtu = icmp6_reflect_rt.ro_rt->rt_rmx.rmx_mtu; 1238 1239 if (mtu < m->m_pkthdr.len) { 1240 plen -= (m->m_pkthdr.len - mtu); 1241 m_adj(m, mtu - m->m_pkthdr.len); 1242 } 1243#endif 1244 /* 1245 * If the incoming packet was addressed directly to us(i.e. unicast), 1246 * use dst as the src for the reply. 1247 */ 1248 for (ia = in6_ifaddr; ia; ia = ia->ia_next) 1249 if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) && 1250 (ia->ia6_flags & IN6_IFF_ANYCAST) == 0) { 1251 src = &t; 1252 break; 1253 } 1254 if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) { 1255 /* 1256 * This is the case if the dst is our link-local address 1257 * and the sender is also ourseleves. 1258 */ 1259 src = &t; 1260 } 1261 1262 if (src == 0) 1263 /* 1264 * We have not multicast routing yet. So this case matches 1265 * to our multicast, our anycast or not to our unicast. 1266 * Select a source address which has the same scope. 1267 */ 1268 if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0) 1269 src = &IA6_SIN6(ia)->sin6_addr; 1270 1271 if (src == 0) 1272 goto bad; 1273 1274 ip6->ip6_src = *src; 1275 1276 ip6->ip6_flow = 0; 1277 ip6->ip6_vfc = IPV6_VERSION; 1278 ip6->ip6_nxt = IPPROTO_ICMPV6; 1279 if (m->m_pkthdr.rcvif) { 1280 /* XXX: This may not be the outgoing interface */ 1281 ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim; 1282 } 1283 1284 icmp6->icmp6_cksum = 0; 1285 icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, 1286 sizeof(struct ip6_hdr), plen); 1287 1288 /* 1289 * xxx option handling 1290 */ 1291 1292 m->m_flags &= ~(M_BCAST|M_MCAST); 1293#ifdef IPSEC 1294 m->m_pkthdr.rcvif = NULL; 1295#endif /*IPSEC*/ 1296 1297#ifdef COMPAT_RFC1885 1298 ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL); 1299#else 1300 ip6_output(m, NULL, NULL, 0, NULL); 1301#endif 1302 1303 return; 1304 1305 bad: 1306 m_freem(m); 1307 return; 1308} 1309 1310void 1311icmp6_fasttimo() 1312{ 1313 mld6_fasttimeo(); 1314} 1315 1316void 1317icmp6_redirect_input(m, off) 1318 register struct mbuf *m; 1319 int off; 1320{ 1321 struct ifnet *ifp = m->m_pkthdr.rcvif; 1322 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1323 struct nd_redirect *nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off); 1324 int icmp6len = ntohs(ip6->ip6_plen); 1325 char *lladdr = NULL; 1326 int lladdrlen = 0; 1327 u_char *redirhdr = NULL; 1328 int redirhdrlen = 0; 1329 struct rtentry *rt = NULL; 1330 int is_router; 1331 int is_onlink; 1332 struct in6_addr src6 = ip6->ip6_src; 1333 struct in6_addr redtgt6 = nd_rd->nd_rd_target; 1334 struct in6_addr reddst6 = nd_rd->nd_rd_dst; 1335 union nd_opts ndopts; 1336 1337 if (!m || !ifp) 1338 return; 1339 1340 /* XXX if we are router, we don't update route by icmp6 redirect */ 1341 if (ip6_forwarding) 1342 return; 1343 if (!icmp6_rediraccept) 1344 return; 1345 1346 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) 1347 redtgt6.s6_addr16[1] = htons(ifp->if_index); 1348 if (IN6_IS_ADDR_LINKLOCAL(&reddst6)) 1349 reddst6.s6_addr16[1] = htons(ifp->if_index); 1350 1351 /* validation */ 1352 if (!IN6_IS_ADDR_LINKLOCAL(&src6)) { 1353 log(LOG_ERR, 1354 "ICMP6 redirect sent from %s rejected; " 1355 "must be from linklocal\n", ip6_sprintf(&src6)); 1356 return; 1357 } 1358 if (ip6->ip6_hlim != 255) { 1359 log(LOG_ERR, 1360 "ICMP6 redirect sent from %s rejected; " 1361 "hlim=%d (must be 255)\n", 1362 ip6_sprintf(&src6), ip6->ip6_hlim); 1363 return; 1364 } 1365 { 1366 /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */ 1367 struct sockaddr_in6 sin6; 1368 struct in6_addr *gw6; 1369 1370 bzero(&sin6, sizeof(sin6)); 1371 sin6.sin6_family = AF_INET6; 1372 sin6.sin6_len = sizeof(struct sockaddr_in6); 1373 bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6)); 1374 rt = rtalloc1((struct sockaddr *)&sin6, 0 1375#ifdef __FreeBSD__ 1376 , 0UL 1377#endif 1378 ); 1379 if (rt) { 1380 gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr); 1381 if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) { 1382 log(LOG_ERR, 1383 "ICMP6 redirect sent from %s rejected; " 1384 "ip src=%s, gw for %s=%s (must be same)\n", 1385 ip6_sprintf(&src6), ip6_sprintf(&src6), 1386 ip6_sprintf(&reddst6), ip6_sprintf(gw6)); 1387 RTFREE(rt); 1388 return; 1389 } 1390 } else { 1391 log(LOG_ERR, 1392 "ICMP6 redirect sent from %s rejected; " 1393 "no route found for redirect destination %s\n", 1394 ip6_sprintf(&src6), ip6_sprintf(&reddst6)); 1395 return; 1396 } 1397 RTFREE(rt); 1398 rt = NULL; 1399 } 1400 if (IN6_IS_ADDR_MULTICAST(&reddst6)) { 1401 log(LOG_ERR, 1402 "ICMP6 redirect sent from %s rejected; " 1403 "redirect destination=%s (must be unicast)\n", 1404 ip6_sprintf(&src6), ip6_sprintf(&reddst6)); 1405 return; 1406 } 1407 1408 is_router = is_onlink = 0; 1409 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) 1410 is_router = 1; /* router case */ 1411 if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) 1412 is_onlink = 1; /* on-link destination case */ 1413 if (!is_router && !is_onlink) { 1414 log(LOG_ERR, 1415 "ICMP6 redirect sent from %s rejected; " 1416 "redirect target=%s, destination=%s\n", 1417 ip6_sprintf(&src6), ip6_sprintf(&redtgt6), 1418 ip6_sprintf(&reddst6)); 1419 return; 1420 } 1421 /* validation passed */ 1422 1423 icmp6len -= sizeof(*nd_rd); 1424 nd6_option_init(nd_rd + 1, icmp6len, &ndopts); 1425 if (nd6_options(&ndopts) < 0) { 1426 log(LOG_INFO, "icmp6_redirect_input: " 1427 "invalid ND option, rejected\n"); 1428 return; 1429 } 1430 1431 if (ndopts.nd_opts_tgt_lladdr) { 1432 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); 1433 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; 1434 } 1435 1436 if (ndopts.nd_opts_rh) { 1437 redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len; 1438 redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */ 1439 } 1440 1441 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 1442 log(LOG_INFO, 1443 "icmp6_redirect_input: lladdrlen mismatch for %s " 1444 "(if %d, icmp6 packet %d)\n", 1445 ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2); 1446 } 1447 1448 /* RFC 2461 8.3 */ 1449 nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT); 1450 1451 if (!is_onlink) { /* better router case. perform rtredirect. */ 1452 /* perform rtredirect */ 1453 struct sockaddr_in6 sdst; 1454 struct sockaddr_in6 sgw; 1455 struct sockaddr_in6 ssrc; 1456#ifdef __bsdi__ 1457 extern int icmp_redirtimeout; /*XXX*/ 1458#endif 1459 1460 bzero(&sdst, sizeof(sdst)); 1461 bzero(&sgw, sizeof(sgw)); 1462 bzero(&ssrc, sizeof(ssrc)); 1463 sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6; 1464 sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len = 1465 sizeof(struct sockaddr_in6); 1466 bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr)); 1467 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); 1468 bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr)); 1469 rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw, 1470 (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST, 1471 (struct sockaddr *)&ssrc, 1472#if defined(__FreeBSD__) || defined(__NetBSD__) 1473 (struct rtentry **)NULL 1474#elif defined(__bsdi__) 1475 icmp_redirtimeout /*XXX*/ 1476#endif /*__FreeBSD__, __NetBSD__, __bsdi__*/ 1477 ); 1478 } 1479 /* finally update cached route in each socket via pfctlinput */ 1480 { 1481 struct sockaddr_in6 sdst; 1482 1483 bzero(&sdst, sizeof(sdst)); 1484 sdst.sin6_family = AF_INET6; 1485 sdst.sin6_len = sizeof(struct sockaddr_in6); 1486 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); 1487 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); 1488#ifdef IPSEC 1489 key_sa_routechange((struct sockaddr *)&sdst); 1490#endif 1491 } 1492} 1493 1494void 1495icmp6_redirect_output(m0, rt) 1496 struct mbuf *m0; 1497 struct rtentry *rt; 1498{ 1499 struct ifnet *ifp; /* my outgoing interface */ 1500 struct in6_addr *ifp_ll6; 1501 struct in6_addr *router_ll6; 1502 struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */ 1503 struct mbuf *m = NULL; /* newly allocated one */ 1504 struct ip6_hdr *ip6; /* m as struct ip6_hdr */ 1505 struct nd_redirect *nd_rd; 1506 size_t maxlen; 1507 u_char *p; 1508 1509 /* if we are not router, we don't send icmp6 redirect */ 1510 if (!ip6_forwarding || ip6_accept_rtadv) 1511 goto fail; 1512 1513 /* sanity check */ 1514 if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp)) 1515 goto fail; 1516 1517 /* 1518 * Address check: 1519 * the source address must identify a neighbor, and 1520 * the destination address must not be a multicast address 1521 * [RFC 2461, sec 8.2] 1522 */ 1523 sip6 = mtod(m0, struct ip6_hdr *); 1524 if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0) 1525 goto fail; 1526 if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) 1527 goto fail; /* what should we do here? */ 1528 1529 /* rate limit */ 1530 if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0)) 1531 goto fail; 1532 1533 /* 1534 * Since we are going to append up to 1280 bytes (= IPV6_MMTU), 1535 * we almost always ask for an mbuf cluster for simplicity. 1536 * (MHLEN < IPV6_MMTU is almost always true) 1537 */ 1538 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1539 if (!m) 1540 goto fail; 1541 if (MHLEN < IPV6_MMTU) 1542 MCLGET(m, M_DONTWAIT); 1543 maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; 1544 maxlen = min(IPV6_MMTU, maxlen); 1545 /* just for safety */ 1546 if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) 1547 goto fail; 1548 1549 { 1550 /* get ip6 linklocal address for ifp(my outgoing interface). */ 1551 struct in6_ifaddr *ia = in6ifa_ifpforlinklocal(ifp); 1552 if (ia == NULL) 1553 goto fail; 1554 ifp_ll6 = &ia->ia_addr.sin6_addr; 1555 } 1556 1557 /* get ip6 linklocal address for the router. */ 1558 if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) { 1559 struct sockaddr_in6 *sin6; 1560 sin6 = (struct sockaddr_in6 *)rt->rt_gateway; 1561 router_ll6 = &sin6->sin6_addr; 1562 if (!IN6_IS_ADDR_LINKLOCAL(router_ll6)) 1563 router_ll6 = (struct in6_addr *)NULL; 1564 } else 1565 router_ll6 = (struct in6_addr *)NULL; 1566 1567 /* ip6 */ 1568 ip6 = mtod(m, struct ip6_hdr *); 1569 ip6->ip6_flow = 0; 1570 ip6->ip6_vfc = IPV6_VERSION; 1571 /* ip6->ip6_plen will be set later */ 1572 ip6->ip6_nxt = IPPROTO_ICMPV6; 1573 ip6->ip6_hlim = 255; 1574 /* ip6->ip6_src must be linklocal addr for my outgoing if. */ 1575 bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr)); 1576 bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr)); 1577 1578 /* ND Redirect */ 1579 nd_rd = (struct nd_redirect *)(ip6 + 1); 1580 nd_rd->nd_rd_type = ND_REDIRECT; 1581 nd_rd->nd_rd_code = 0; 1582 nd_rd->nd_rd_reserved = 0; 1583 if (rt->rt_flags & RTF_GATEWAY) { 1584 /* 1585 * nd_rd->nd_rd_target must be a link-local address in 1586 * better router cases. 1587 */ 1588 if (!router_ll6) 1589 goto fail; 1590 bcopy(router_ll6, &nd_rd->nd_rd_target, 1591 sizeof(nd_rd->nd_rd_target)); 1592 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst, 1593 sizeof(nd_rd->nd_rd_dst)); 1594 } else { 1595 /* make sure redtgt == reddst */ 1596 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target, 1597 sizeof(nd_rd->nd_rd_target)); 1598 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst, 1599 sizeof(nd_rd->nd_rd_dst)); 1600 } 1601 1602 p = (u_char *)(nd_rd + 1); 1603 1604 if (!router_ll6) 1605 goto nolladdropt; 1606 1607 { 1608 /* target lladdr option */ 1609 struct rtentry *rt_router = NULL; 1610 int len; 1611 struct sockaddr_dl *sdl; 1612 struct nd_opt_hdr *nd_opt; 1613 char *lladdr; 1614 1615 rt_router = nd6_lookup(router_ll6, 0, ifp); 1616 if (!rt_router) 1617 goto nolladdropt; 1618 if (!(rt_router->rt_flags & RTF_GATEWAY) 1619 && (rt_router->rt_flags & RTF_LLINFO) 1620 && (rt_router->rt_gateway->sa_family == AF_LINK) 1621 && (sdl = (struct sockaddr_dl *)rt_router->rt_gateway)) { 1622 nd_opt = (struct nd_opt_hdr *)p; 1623 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; 1624 len = 2 + ifp->if_addrlen; 1625 len = (len + 7) & ~7; /*round by 8*/ 1626 nd_opt->nd_opt_len = len >> 3; 1627 p += len; 1628 lladdr = (char *)(nd_opt + 1); 1629 bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen); 1630 } 1631 } 1632nolladdropt:; 1633 1634 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; 1635 1636 /* just to be safe */ 1637 if (m0->m_flags & M_DECRYPTED) 1638 goto noredhdropt; 1639 1640 { 1641 /* redirected header option */ 1642 int len; 1643 struct nd_opt_rd_hdr *nd_opt_rh; 1644 1645 /* 1646 * compute the maximum size for icmp6 redirect header option. 1647 * XXX room for auth header? 1648 */ 1649 len = maxlen - (p - (u_char *)ip6); 1650 len &= ~7; 1651 1652 /* This is just for simplicity. */ 1653 if (m0->m_pkthdr.len != m0->m_len) { 1654 if (m0->m_next) { 1655 m_freem(m0->m_next); 1656 m0->m_next = NULL; 1657 } 1658 m0->m_pkthdr.len = m0->m_len; 1659 } 1660 1661 /* 1662 * Redirected header option spec (RFC2461 4.6.3) talks nothing 1663 * about padding/trancate rule for the original IP packet. 1664 * From the discussion on IPv6imp in Feb 1999, the consensus was: 1665 * - "attach as much as possible" is the goal 1666 * - pad if not aligned (original size can be guessed by original 1667 * ip6 header) 1668 * Following code adds the padding if it is simple enough, 1669 * and truncates if not. 1670 */ 1671 if (m0->m_next || m0->m_pkthdr.len != m0->m_len) 1672 panic("assumption failed in %s:%d\n", __FILE__, __LINE__); 1673 1674 if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) { 1675 /* not enough room, truncate */ 1676 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh); 1677 } else { 1678 /* enough room, pad or truncate */ 1679 size_t extra; 1680 1681 extra = m0->m_pkthdr.len % 8; 1682 if (extra) { 1683 /* pad if easy enough, truncate if not */ 1684 if (8 - extra <= M_TRAILINGSPACE(m0)) { 1685 /* pad */ 1686 m0->m_len += (8 - extra); 1687 m0->m_pkthdr.len += (8 - extra); 1688 } else { 1689 /* truncate */ 1690 m0->m_pkthdr.len -= extra; 1691 m0->m_len -= extra; 1692 } 1693 } 1694 len = m0->m_pkthdr.len + sizeof(*nd_opt_rh); 1695 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh); 1696 } 1697 1698 nd_opt_rh = (struct nd_opt_rd_hdr *)p; 1699 bzero(nd_opt_rh, sizeof(*nd_opt_rh)); 1700 nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; 1701 nd_opt_rh->nd_opt_rh_len = len >> 3; 1702 p += sizeof(*nd_opt_rh); 1703 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; 1704 1705 /* connect m0 to m */ 1706 m->m_next = m0; 1707 m->m_pkthdr.len = m->m_len + m0->m_len; 1708 } 1709noredhdropt:; 1710 1711 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src)) 1712 sip6->ip6_src.s6_addr16[1] = 0; 1713 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst)) 1714 sip6->ip6_dst.s6_addr16[1] = 0; 1715#if 0 1716 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) 1717 ip6->ip6_src.s6_addr16[1] = 0; 1718 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) 1719 ip6->ip6_dst.s6_addr16[1] = 0; 1720#endif 1721 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target)) 1722 nd_rd->nd_rd_target.s6_addr16[1] = 0; 1723 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst)) 1724 nd_rd->nd_rd_dst.s6_addr16[1] = 0; 1725 1726 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 1727 1728 nd_rd->nd_rd_cksum = 0; 1729 nd_rd->nd_rd_cksum 1730 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen)); 1731 1732 /* send the packet to outside... */ 1733#ifdef IPSEC 1734 m->m_pkthdr.rcvif = NULL; 1735#endif /*IPSEC*/ 1736 ip6_output(m, NULL, NULL, 0, NULL); 1737 icmp6stat.icp6s_outhist[ND_REDIRECT]++; 1738 1739 return; 1740 1741fail: 1742 if (m) 1743 m_freem(m); 1744 if (m0) 1745 m_freem(m0); 1746} 1747 1748/* 1749 * ICMPv6 socket option processing. 1750 */ 1751int 1752icmp6_ctloutput(op, so, level, optname, mp) 1753 int op; 1754 struct socket *so; 1755 int level, optname; 1756 struct mbuf **mp; 1757{ 1758 register struct in6pcb *in6p = sotoin6pcb(so); 1759 register struct mbuf *m = *mp; 1760 int error = 0; 1761 1762 if (level != IPPROTO_ICMPV6) { 1763 error = EINVAL; 1764 if (op == PRCO_SETOPT && m) 1765 (void)m_free(m); 1766 } else switch(op) { 1767 case PRCO_SETOPT: 1768 switch (optname) { 1769 case ICMP6_FILTER: 1770 { 1771 struct icmp6_filter *p; 1772 1773 p = mtod(m, struct icmp6_filter *); 1774 if (!p || !in6p->in6p_icmp6filt) { 1775 error = EINVAL; 1776 break; 1777 } 1778 bcopy(p, in6p->in6p_icmp6filt, 1779 sizeof(struct icmp6_filter)); 1780 error = 0; 1781 break; 1782 } 1783 1784 default: 1785 error = ENOPROTOOPT; 1786 break; 1787 } 1788 if (m) 1789 (void)m_free(m); 1790 break; 1791 1792 case PRCO_GETOPT: 1793 switch (optname) { 1794 case ICMP6_FILTER: 1795 { 1796 struct icmp6_filter *p; 1797 1798 p = mtod(m, struct icmp6_filter *); 1799 if (!p || !in6p->in6p_icmp6filt) { 1800 error = EINVAL; 1801 break; 1802 } 1803 bcopy(in6p->in6p_icmp6filt, p, 1804 sizeof(struct icmp6_filter)); 1805 error = 0; 1806 break; 1807 } 1808 1809 default: 1810 error = ENOPROTOOPT; 1811 break; 1812 } 1813 break; 1814 } 1815 1816 return(error); 1817} 1818 1819/* 1820 * Perform rate limit check. 1821 * Returns 0 if it is okay to send the icmp6 packet. 1822 * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate 1823 * limitation. 1824 * 1825 * XXX per-destination/type check necessary? 1826 */ 1827static int 1828icmp6_ratelimit(dst, type, code) 1829 const struct in6_addr *dst; /* not used at this moment */ 1830 const int type; /* not used at this moment */ 1831 const int code; /* not used at this moment */ 1832{ 1833 struct timeval tp; 1834 long sec_diff, usec_diff; 1835 1836 /* If we are not doing rate limitation, it is always okay to send */ 1837 if (!icmp6errratelim) 1838 return 0; 1839 1840#if defined(__FreeBSD__) && __FreeBSD__ >= 3 1841 microtime(&tp); 1842 tp.tv_sec = time_second; 1843#else 1844 tp = time; 1845#endif 1846 if (tp.tv_sec < icmp6_nextsend.tv_sec 1847 || (tp.tv_sec == icmp6_nextsend.tv_sec 1848 && tp.tv_usec < icmp6_nextsend.tv_usec)) { 1849 /* The packet is subject to rate limit */ 1850 return 1; 1851 } 1852 sec_diff = icmp6errratelim / 1000000; 1853 usec_diff = icmp6errratelim % 1000000; 1854 icmp6_nextsend.tv_sec = tp.tv_sec + sec_diff; 1855 if ((tp.tv_usec = tp.tv_usec + usec_diff) >= 1000000) { 1856 icmp6_nextsend.tv_sec++; 1857 icmp6_nextsend.tv_usec -= 1000000; 1858 } 1859 1860 /* it is okay to send this */ 1861 return 0; 1862} 1863 1864#ifdef __bsdi__ 1865void 1866icmp6_mtuexpire(rt, rtt) 1867 struct rtentry *rt; 1868 struct rttimer *rtt; 1869{ 1870 rt->rt_flags |= RTF_PROBEMTU; 1871 Free(rtt); 1872} 1873 1874int *icmp6_sysvars[] = ICMPV6CTL_VARS; 1875 1876int 1877icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 1878 int *name; 1879 u_int namelen; 1880 void *oldp; 1881 size_t *oldlenp; 1882 void *newp; 1883 size_t newlen; 1884{ 1885 if (name[0] >= ICMPV6CTL_MAXID) 1886 return (EOPNOTSUPP); 1887 switch (name[0]) { 1888#if 0 1889 ICMPV6CTL_ND6_PRUNE: 1890 ICMPV6CTL_ND6_DELAY: 1891 ICMPV6CTL_ND6_UMAXTRIES: 1892 ICMPV6CTL_ND6_MMAXTRIES: 1893 ICMPV6CTL_ND6_USELOOPBACK: 1894 ICMPV6CTL_ND6_PROXYALL: 1895 /* need to check the value. */ 1896#endif 1897 case ICMPV6CTL_STATS: 1898 return sysctl_rdtrunc(oldp, oldlenp, newp, &icmp6stat, 1899 sizeof(icmp6stat)); 1900 1901 default: 1902 return (sysctl_int_arr(icmp6_sysvars, name, namelen, 1903 oldp, oldlenp, newp, newlen)); 1904 } 1905} 1906#endif /*__bsdi__*/ 1907 1908#ifdef __NetBSD__ 1909#include <vm/vm.h> 1910#include <sys/sysctl.h> 1911int 1912icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 1913 int *name; 1914 u_int namelen; 1915 void *oldp; 1916 size_t *oldlenp; 1917 void *newp; 1918 size_t newlen; 1919{ 1920 1921 /* All sysctl names at this level are terminal. */ 1922 if (namelen != 1) 1923 return ENOTDIR; 1924 1925 switch (name[0]) { 1926 1927 case ICMPV6CTL_REDIRACCEPT: 1928 return sysctl_int(oldp, oldlenp, newp, newlen, 1929 &icmp6_rediraccept); 1930 case ICMPV6CTL_REDIRTIMEOUT: 1931 return sysctl_int(oldp, oldlenp, newp, newlen, 1932 &icmp6_redirtimeout); 1933 case ICMPV6CTL_STATS: 1934 return sysctl_rdstruct(oldp, oldlenp, newp, 1935 &icmp6stat, sizeof(icmp6stat)); 1936 case ICMPV6CTL_ERRRATELIMIT: 1937 return sysctl_int(oldp, oldlenp, newp, newlen, 1938 &icmp6errratelim); 1939 case ICMPV6CTL_ND6_PRUNE: 1940 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_prune); 1941 case ICMPV6CTL_ND6_DELAY: 1942 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_delay); 1943 case ICMPV6CTL_ND6_UMAXTRIES: 1944 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_umaxtries); 1945 case ICMPV6CTL_ND6_MMAXTRIES: 1946 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_mmaxtries); 1947 case ICMPV6CTL_ND6_USELOOPBACK: 1948 return sysctl_int(oldp, oldlenp, newp, newlen, 1949 &nd6_useloopback); 1950 case ICMPV6CTL_ND6_PROXYALL: 1951 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_proxyall); 1952 default: 1953 return ENOPROTOOPT; 1954 } 1955 /* NOTREACHED */ 1956} 1957#endif /* __NetBSD__ */ 1958