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