icmp6.c revision 1.3
1/* $NetBSD: icmp6.c,v 1.3 1999/07/03 21:30:18 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#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 off, sizeof(struct ip6_hdr), __FILE__, __LINE__); 1160 goto bad; 1161 } 1162 siz = off - sizeof(struct ip6_hdr); 1163 if (plen < siz) { 1164 printf("sanity fail: siz=%x, payloadlen=%x in %s:%d\n", 1165 siz, plen, __FILE__, __LINE__); 1166 goto bad; 1167 } 1168 IP6_EXTHDR_CHECK(m, 0, off, /*nothing*/); 1169 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), /*nothing*/); 1170 1171 bcopy((caddr_t)ip6, 1172 (caddr_t)(mtod(m, u_char *) + siz), 1173 sizeof(struct ip6_hdr)); 1174 m->m_data += siz; 1175 m->m_len -= siz; 1176 m->m_pkthdr.len -= siz; 1177 ip6 = mtod(m, struct ip6_hdr *); 1178 ip6->ip6_nxt = IPPROTO_ICMPV6; 1179 plen -= siz; 1180 } 1181 1182 icmp6 = (struct icmp6_hdr *)(ip6 + 1); 1183 1184 t = ip6->ip6_dst; 1185 /* 1186 * ip6_input() drops a packet if its src is multicast. 1187 * So, the src is never multicast. 1188 */ 1189 ip6->ip6_dst = ip6->ip6_src; 1190 1191 /* XXX hack for link-local addresses */ 1192 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) 1193 ip6->ip6_dst.s6_addr16[1] = 1194 htons(m->m_pkthdr.rcvif->if_index); 1195 if (IN6_IS_ADDR_LINKLOCAL(&t)) 1196 t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); 1197 1198#ifdef COMPAT_RFC1885 1199 /* 1200 * xxx guess MTU 1201 * RFC 1885 requires that echo reply should be truncated if it 1202 * does not fit in with (return) path MTU, but the description was 1203 * removed in the new spec. 1204 */ 1205 if (icmp6_reflect_rt.ro_rt == 0 || 1206 ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) { 1207 if (icmp6_reflect_rt.ro_rt) { 1208#ifdef __FreeBSD__ 1209 RTFREE(icmp6_reflect_rt.ro_rt); 1210#endif 1211#ifdef __bsdi__ 1212 rtfree(icmp6_reflect_rt.ro_rt); 1213#endif 1214 icmp6_reflect_rt.ro_rt = 0; 1215 } 1216 bzero(sin6, sizeof(*sin6)); 1217 sin6->sin6_family = PF_INET6; 1218 sin6->sin6_len = sizeof(struct sockaddr_in6); 1219 sin6->sin6_addr = ip6->ip6_dst; 1220 1221#ifdef __NetBSD__ 1222 rtalloc((struct route *)&icmp6_reflect_rt.ro_rt); 1223#else 1224 rtalloc_ign((struct route *)&icmp6_reflect_rt.ro_rt, 1225 RTF_PRCLONING); 1226#endif 1227 } 1228 1229 if (icmp6_reflect_rt.ro_rt == 0) 1230 goto bad; 1231 1232 if ((icmp6_reflect_rt.ro_rt->rt_flags & RTF_HOST) 1233 && mtu < icmp6_reflect_rt.ro_rt->rt_ifp->if_mtu) 1234 mtu = icmp6_reflect_rt.ro_rt->rt_rmx.rmx_mtu; 1235 1236 if (mtu < m->m_pkthdr.len) { 1237 plen -= (m->m_pkthdr.len - mtu); 1238 m_adj(m, mtu - m->m_pkthdr.len); 1239 } 1240#endif 1241 /* 1242 * If the incoming packet was addressed directly to us(i.e. unicast), 1243 * use dst as the src for the reply. 1244 */ 1245 for (ia = in6_ifaddr; ia; ia = ia->ia_next) 1246 if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) && 1247 (ia->ia6_flags & IN6_IFF_ANYCAST) == 0) { 1248 src = &t; 1249 break; 1250 } 1251 if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) { 1252 /* 1253 * This is the case if the dst is our link-local address 1254 * and the sender is also ourseleves. 1255 */ 1256 src = &t; 1257 } 1258 1259 if (src == 0) 1260 /* 1261 * We have not multicast routing yet. So this case matches 1262 * to our multicast, our anycast or not to our unicast. 1263 * Select a source address which has the same scope. 1264 */ 1265 if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0) 1266 src = &IA6_SIN6(ia)->sin6_addr; 1267 1268 if (src == 0) 1269 goto bad; 1270 1271 ip6->ip6_src = *src; 1272 1273 ip6->ip6_flow = 0; 1274 ip6->ip6_vfc = IPV6_VERSION; 1275 ip6->ip6_nxt = IPPROTO_ICMPV6; 1276 if (m->m_pkthdr.rcvif) { 1277 /* XXX: This may not be the outgoing interface */ 1278 ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim; 1279 } 1280 1281 icmp6->icmp6_cksum = 0; 1282 icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, 1283 sizeof(struct ip6_hdr), plen); 1284 1285 /* 1286 * xxx option handling 1287 */ 1288 1289 m->m_flags &= ~(M_BCAST|M_MCAST); 1290#ifdef IPSEC 1291 m->m_pkthdr.rcvif = NULL; 1292#endif /*IPSEC*/ 1293 1294#ifdef COMPAT_RFC1885 1295 ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL); 1296#else 1297 ip6_output(m, NULL, NULL, 0, NULL); 1298#endif 1299 1300 return; 1301 1302 bad: 1303 m_freem(m); 1304 return; 1305} 1306 1307void 1308icmp6_fasttimo() 1309{ 1310 mld6_fasttimeo(); 1311} 1312 1313void 1314icmp6_redirect_input(m, off) 1315 register struct mbuf *m; 1316 int off; 1317{ 1318 struct ifnet *ifp = m->m_pkthdr.rcvif; 1319 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1320 struct nd_redirect *nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off); 1321 int icmp6len = ntohs(ip6->ip6_plen); 1322 char *lladdr = NULL; 1323 int lladdrlen = 0; 1324 u_char *redirhdr = NULL; 1325 int redirhdrlen = 0; 1326 struct rtentry *rt = NULL; 1327 int is_router; 1328 int is_onlink; 1329 struct in6_addr src6 = ip6->ip6_src; 1330 struct in6_addr redtgt6 = nd_rd->nd_rd_target; 1331 struct in6_addr reddst6 = nd_rd->nd_rd_dst; 1332 union nd_opts ndopts; 1333 1334 if (!m || !ifp) 1335 return; 1336 1337 /* XXX if we are router, we don't update route by icmp6 redirect */ 1338 if (ip6_forwarding) 1339 return; 1340 if (!icmp6_rediraccept) 1341 return; 1342 1343 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) 1344 redtgt6.s6_addr16[1] = htons(ifp->if_index); 1345 if (IN6_IS_ADDR_LINKLOCAL(&reddst6)) 1346 reddst6.s6_addr16[1] = htons(ifp->if_index); 1347 1348 /* validation */ 1349 if (!IN6_IS_ADDR_LINKLOCAL(&src6)) { 1350 log(LOG_ERR, 1351 "ICMP6 redirect sent from %s rejected; " 1352 "must be from linklocal\n", ip6_sprintf(&src6)); 1353 return; 1354 } 1355 if (ip6->ip6_hlim != 255) { 1356 log(LOG_ERR, 1357 "ICMP6 redirect sent from %s rejected; " 1358 "hlim=%d (must be 255)\n", 1359 ip6_sprintf(&src6), ip6->ip6_hlim); 1360 return; 1361 } 1362 { 1363 /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */ 1364 struct sockaddr_in6 sin6; 1365 struct in6_addr *gw6; 1366 1367 bzero(&sin6, sizeof(sin6)); 1368 sin6.sin6_family = AF_INET6; 1369 sin6.sin6_len = sizeof(struct sockaddr_in6); 1370 bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6)); 1371 rt = rtalloc1((struct sockaddr *)&sin6, 0 1372#ifdef __FreeBSD__ 1373 , 0UL 1374#endif 1375 ); 1376 if (rt) { 1377 gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr); 1378 if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) { 1379 log(LOG_ERR, 1380 "ICMP6 redirect sent from %s rejected; " 1381 "ip src=%s, gw for %s=%s (must be same)\n", 1382 ip6_sprintf(&src6), ip6_sprintf(&src6), 1383 ip6_sprintf(&reddst6), ip6_sprintf(gw6)); 1384 RTFREE(rt); 1385 return; 1386 } 1387 } else { 1388 log(LOG_ERR, 1389 "ICMP6 redirect sent from %s rejected; " 1390 "no route found for redirect destination %s\n", 1391 ip6_sprintf(&src6), ip6_sprintf(&reddst6)); 1392 return; 1393 } 1394 RTFREE(rt); 1395 rt = NULL; 1396 } 1397 if (IN6_IS_ADDR_MULTICAST(&reddst6)) { 1398 log(LOG_ERR, 1399 "ICMP6 redirect sent from %s rejected; " 1400 "redirect destination=%s (must be unicast)\n", 1401 ip6_sprintf(&src6), ip6_sprintf(&reddst6)); 1402 return; 1403 } 1404 1405 is_router = is_onlink = 0; 1406 if (IN6_IS_ADDR_LINKLOCAL(&redtgt6)) 1407 is_router = 1; /* router case */ 1408 if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0) 1409 is_onlink = 1; /* on-link destination case */ 1410 if (!is_router && !is_onlink) { 1411 log(LOG_ERR, 1412 "ICMP6 redirect sent from %s rejected; " 1413 "redirect target=%s, destination=%s\n", 1414 ip6_sprintf(&src6), ip6_sprintf(&redtgt6), 1415 ip6_sprintf(&reddst6)); 1416 return; 1417 } 1418 /* validation passed */ 1419 1420 icmp6len -= sizeof(*nd_rd); 1421 nd6_option_init(nd_rd + 1, icmp6len, &ndopts); 1422 if (nd6_options(&ndopts) < 0) { 1423 log(LOG_INFO, "icmp6_redirect_input: " 1424 "invalid ND option, rejected\n"); 1425 return; 1426 } 1427 1428 if (ndopts.nd_opts_tgt_lladdr) { 1429 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); 1430 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; 1431 } 1432 1433 if (ndopts.nd_opts_rh) { 1434 redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len; 1435 redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */ 1436 } 1437 1438 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 1439 log(LOG_INFO, 1440 "icmp6_redirect_input: lladdrlen mismatch for %s " 1441 "(if %d, icmp6 packet %d)\n", 1442 ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2); 1443 } 1444 1445 /* RFC 2461 8.3 */ 1446 nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT); 1447 1448 if (!is_onlink) { /* better router case. perform rtredirect. */ 1449 /* perform rtredirect */ 1450 struct sockaddr_in6 sdst; 1451 struct sockaddr_in6 sgw; 1452 struct sockaddr_in6 ssrc; 1453#ifdef __bsdi__ 1454 extern int icmp_redirtimeout; /*XXX*/ 1455#endif 1456 1457 bzero(&sdst, sizeof(sdst)); 1458 bzero(&sgw, sizeof(sgw)); 1459 bzero(&ssrc, sizeof(ssrc)); 1460 sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6; 1461 sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len = 1462 sizeof(struct sockaddr_in6); 1463 bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr)); 1464 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); 1465 bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr)); 1466 rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw, 1467 (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST, 1468 (struct sockaddr *)&ssrc, 1469#if defined(__FreeBSD__) || defined(__NetBSD__) 1470 (struct rtentry **)NULL 1471#elif defined(__bsdi__) 1472 icmp_redirtimeout /*XXX*/ 1473#endif /*__FreeBSD__, __NetBSD__, __bsdi__*/ 1474 ); 1475 } 1476 /* finally update cached route in each socket via pfctlinput */ 1477 { 1478 struct sockaddr_in6 sdst; 1479 1480 bzero(&sdst, sizeof(sdst)); 1481 sdst.sin6_family = AF_INET6; 1482 sdst.sin6_len = sizeof(struct sockaddr_in6); 1483 bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); 1484 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); 1485#ifdef IPSEC 1486 key_sa_routechange((struct sockaddr *)&sdst); 1487#endif 1488 } 1489} 1490 1491void 1492icmp6_redirect_output(m0, rt) 1493 struct mbuf *m0; 1494 struct rtentry *rt; 1495{ 1496 struct ifnet *ifp; /* my outgoing interface */ 1497 struct in6_addr *ifp_ll6; 1498 struct in6_addr *router_ll6; 1499 struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */ 1500 struct mbuf *m = NULL; /* newly allocated one */ 1501 struct ip6_hdr *ip6; /* m as struct ip6_hdr */ 1502 struct nd_redirect *nd_rd; 1503 size_t maxlen; 1504 u_char *p; 1505 1506 /* if we are not router, we don't send icmp6 redirect */ 1507 if (!ip6_forwarding || ip6_accept_rtadv) 1508 goto fail; 1509 1510 /* sanity check */ 1511 if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp)) 1512 goto fail; 1513 sip6 = mtod(m0, struct ip6_hdr *); 1514 if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) 1515 goto fail; /* what should we do here? */ 1516 1517 /* rate limit */ 1518 if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0)) 1519 goto fail; 1520 1521 /* 1522 * Since we are going to append up to 1280 bytes (= IPV6_MMTU), 1523 * we almost always ask for an mbuf cluster for simplicity. 1524 * (MHLEN < IPV6_MMTU is almost always true) 1525 */ 1526 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1527 if (!m) 1528 goto fail; 1529 if (MHLEN < IPV6_MMTU) 1530 MCLGET(m, M_DONTWAIT); 1531 maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; 1532 maxlen = min(IPV6_MMTU, maxlen); 1533 /* just for safety */ 1534 if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) 1535 goto fail; 1536 1537 { 1538 /* get ip6 linklocal address for ifp(my outgoing interface). */ 1539 struct in6_ifaddr *ia = in6ifa_ifpforlinklocal(ifp); 1540 if (ia == NULL) 1541 goto fail; 1542 ifp_ll6 = &ia->ia_addr.sin6_addr; 1543 } 1544 1545 /* get ip6 linklocal address for the router. */ 1546 if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) { 1547 struct sockaddr_in6 *sin6; 1548 sin6 = (struct sockaddr_in6 *)rt->rt_gateway; 1549 router_ll6 = &sin6->sin6_addr; 1550 if (!IN6_IS_ADDR_LINKLOCAL(router_ll6)) 1551 router_ll6 = (struct in6_addr *)NULL; 1552 } else 1553 router_ll6 = (struct in6_addr *)NULL; 1554 1555 /* ip6 */ 1556 ip6 = mtod(m, struct ip6_hdr *); 1557 ip6->ip6_flow = 0; 1558 ip6->ip6_vfc = IPV6_VERSION; 1559 /* ip6->ip6_plen will be set later */ 1560 ip6->ip6_nxt = IPPROTO_ICMPV6; 1561 ip6->ip6_hlim = 255; 1562 /* ip6->ip6_src must be linklocal addr for my outgoing if. */ 1563 bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr)); 1564 bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr)); 1565 1566 /* ND Redirect */ 1567 nd_rd = (struct nd_redirect *)(ip6 + 1); 1568 nd_rd->nd_rd_type = ND_REDIRECT; 1569 nd_rd->nd_rd_code = 0; 1570 nd_rd->nd_rd_reserved = 0; 1571 if (rt->rt_flags & RTF_GATEWAY) { 1572 /* 1573 * nd_rd->nd_rd_target must be a link-local address in 1574 * better router cases. 1575 */ 1576 if (!router_ll6) 1577 goto fail; 1578 bcopy(router_ll6, &nd_rd->nd_rd_target, 1579 sizeof(nd_rd->nd_rd_target)); 1580 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst, 1581 sizeof(nd_rd->nd_rd_dst)); 1582 } else { 1583 /* make sure redtgt == reddst */ 1584 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target, 1585 sizeof(nd_rd->nd_rd_target)); 1586 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst, 1587 sizeof(nd_rd->nd_rd_dst)); 1588 } 1589 1590 p = (u_char *)(nd_rd + 1); 1591 1592 if (!router_ll6) 1593 goto nolladdropt; 1594 1595 { 1596 /* target lladdr option */ 1597 struct rtentry *rt_router = NULL; 1598 int len; 1599 struct sockaddr_dl *sdl; 1600 struct nd_opt_hdr *nd_opt; 1601 char *lladdr; 1602 1603 rt_router = nd6_lookup(router_ll6, 0, ifp); 1604 if (!rt_router) 1605 goto nolladdropt; 1606 if (!(rt_router->rt_flags & RTF_GATEWAY) 1607 && (rt_router->rt_flags & RTF_LLINFO) 1608 && (rt_router->rt_gateway->sa_family == AF_LINK) 1609 && (sdl = (struct sockaddr_dl *)rt_router->rt_gateway)) { 1610 nd_opt = (struct nd_opt_hdr *)p; 1611 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; 1612 len = 2 + ifp->if_addrlen; 1613 len = (len + 7) & ~7; /*round by 8*/ 1614 nd_opt->nd_opt_len = len >> 3; 1615 p += len; 1616 lladdr = (char *)(nd_opt + 1); 1617 bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen); 1618 } 1619 } 1620nolladdropt:; 1621 1622 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; 1623 1624 /* just to be safe */ 1625 if (m0->m_flags & M_DECRYPTED) 1626 goto noredhdropt; 1627 1628 { 1629 /* redirected header option */ 1630 int len; 1631 struct nd_opt_rd_hdr *nd_opt_rh; 1632 1633 /* 1634 * compute the maximum size for icmp6 redirect header option. 1635 * XXX room for auth header? 1636 */ 1637 len = maxlen - (p - (u_char *)ip6); 1638 len &= ~7; 1639 1640 /* This is just for simplicity. */ 1641 if (m0->m_pkthdr.len != m0->m_len) { 1642 if (m0->m_next) { 1643 m_freem(m0->m_next); 1644 m0->m_next = NULL; 1645 } 1646 m0->m_pkthdr.len = m0->m_len; 1647 } 1648 1649 /* 1650 * Redirected header option spec (RFC2461 4.6.3) talks nothing 1651 * about padding/trancate rule for the original IP packet. 1652 * From the discussion on IPv6imp in Feb 1999, the consensus was: 1653 * - "attach as much as possible" is the goal 1654 * - pad if not aligned (original size can be guessed by original 1655 * ip6 header) 1656 * Following code adds the padding if it is simple enough, 1657 * and truncates if not. 1658 */ 1659 if (m0->m_next || m0->m_pkthdr.len != m0->m_len) 1660 panic("assumption failed in %s:%d\n", __FILE__, __LINE__); 1661 1662 if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) { 1663 /* not enough room, truncate */ 1664 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh); 1665 } else { 1666 /* enough room, pad or truncate */ 1667 size_t extra; 1668 1669 extra = m0->m_pkthdr.len % 8; 1670 if (extra) { 1671 /* pad if easy enough, truncate if not */ 1672 if (8 - extra <= M_TRAILINGSPACE(m0)) { 1673 /* pad */ 1674 m0->m_len += (8 - extra); 1675 m0->m_pkthdr.len += (8 - extra); 1676 } else { 1677 /* truncate */ 1678 m0->m_pkthdr.len -= extra; 1679 m0->m_len -= extra; 1680 } 1681 } 1682 len = m0->m_pkthdr.len + sizeof(*nd_opt_rh); 1683 m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh); 1684 } 1685 1686 nd_opt_rh = (struct nd_opt_rd_hdr *)p; 1687 bzero(nd_opt_rh, sizeof(*nd_opt_rh)); 1688 nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; 1689 nd_opt_rh->nd_opt_rh_len = len >> 3; 1690 p += sizeof(*nd_opt_rh); 1691 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; 1692 1693 /* connect m0 to m */ 1694 m->m_next = m0; 1695 m->m_pkthdr.len = m->m_len + m0->m_len; 1696 } 1697noredhdropt:; 1698 1699 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src)) 1700 sip6->ip6_src.s6_addr16[1] = 0; 1701 if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst)) 1702 sip6->ip6_dst.s6_addr16[1] = 0; 1703#if 0 1704 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) 1705 ip6->ip6_src.s6_addr16[1] = 0; 1706 if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) 1707 ip6->ip6_dst.s6_addr16[1] = 0; 1708#endif 1709 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target)) 1710 nd_rd->nd_rd_target.s6_addr16[1] = 0; 1711 if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst)) 1712 nd_rd->nd_rd_dst.s6_addr16[1] = 0; 1713 1714 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 1715 1716 nd_rd->nd_rd_cksum = 0; 1717 nd_rd->nd_rd_cksum 1718 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen)); 1719 1720 /* send the packet to outside... */ 1721#ifdef IPSEC 1722 m->m_pkthdr.rcvif = NULL; 1723#endif /*IPSEC*/ 1724 ip6_output(m, NULL, NULL, 0, NULL); 1725 icmp6stat.icp6s_outhist[ND_REDIRECT]++; 1726 1727 return; 1728 1729fail: 1730 if (m) 1731 m_freem(m); 1732 if (m0) 1733 m_freem(m0); 1734} 1735 1736/* 1737 * ICMPv6 socket option processing. 1738 */ 1739int 1740icmp6_ctloutput(op, so, level, optname, mp) 1741 int op; 1742 struct socket *so; 1743 int level, optname; 1744 struct mbuf **mp; 1745{ 1746 register struct in6pcb *in6p = sotoin6pcb(so); 1747 register struct mbuf *m = *mp; 1748 int error = 0; 1749 1750 if (level != IPPROTO_ICMPV6) { 1751 error = EINVAL; 1752 if (op == PRCO_SETOPT && m) 1753 (void)m_free(m); 1754 } else switch(op) { 1755 case PRCO_SETOPT: 1756 switch (optname) { 1757 case ICMP6_FILTER: 1758 { 1759 struct icmp6_filter *p; 1760 1761 p = mtod(m, struct icmp6_filter *); 1762 if (!p || !in6p->in6p_icmp6filt) { 1763 error = EINVAL; 1764 break; 1765 } 1766 bcopy(p, in6p->in6p_icmp6filt, 1767 sizeof(struct icmp6_filter)); 1768 error = 0; 1769 break; 1770 } 1771 1772 default: 1773 error = ENOPROTOOPT; 1774 break; 1775 } 1776 if (m) 1777 (void)m_free(m); 1778 break; 1779 1780 case PRCO_GETOPT: 1781 switch (optname) { 1782 case ICMP6_FILTER: 1783 { 1784 struct icmp6_filter *p; 1785 1786 p = mtod(m, struct icmp6_filter *); 1787 if (!p || !in6p->in6p_icmp6filt) { 1788 error = EINVAL; 1789 break; 1790 } 1791 bcopy(in6p->in6p_icmp6filt, p, 1792 sizeof(struct icmp6_filter)); 1793 error = 0; 1794 break; 1795 } 1796 1797 default: 1798 error = ENOPROTOOPT; 1799 break; 1800 } 1801 break; 1802 } 1803 1804 return(error); 1805} 1806 1807/* 1808 * Perform rate limit check. 1809 * Returns 0 if it is okay to send the icmp6 packet. 1810 * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate 1811 * limitation. 1812 * 1813 * XXX per-destination/type check necessary? 1814 */ 1815static int 1816icmp6_ratelimit(dst, type, code) 1817 const struct in6_addr *dst; /* not used at this moment */ 1818 const int type; /* not used at this moment */ 1819 const int code; /* not used at this moment */ 1820{ 1821 struct timeval tp; 1822 long sec_diff, usec_diff; 1823 1824 /* If we are not doing rate limitation, it is always okay to send */ 1825 if (!icmp6errratelim) 1826 return 0; 1827 1828#if defined(__FreeBSD__) && __FreeBSD__ >= 3 1829 microtime(&tp); 1830 tp.tv_sec = time_second; 1831#else 1832 tp = time; 1833#endif 1834 if (tp.tv_sec < icmp6_nextsend.tv_sec 1835 || (tp.tv_sec == icmp6_nextsend.tv_sec 1836 && tp.tv_usec < icmp6_nextsend.tv_usec)) { 1837 /* The packet is subject to rate limit */ 1838 return 1; 1839 } 1840 sec_diff = icmp6errratelim / 1000000; 1841 usec_diff = icmp6errratelim % 1000000; 1842 icmp6_nextsend.tv_sec = tp.tv_sec + sec_diff; 1843 if ((tp.tv_usec = tp.tv_usec + usec_diff) >= 1000000) { 1844 icmp6_nextsend.tv_sec++; 1845 icmp6_nextsend.tv_usec -= 1000000; 1846 } 1847 1848 /* it is okay to send this */ 1849 return 0; 1850} 1851 1852#ifdef __bsdi__ 1853void 1854icmp6_mtuexpire(rt, rtt) 1855 struct rtentry *rt; 1856 struct rttimer *rtt; 1857{ 1858 rt->rt_flags |= RTF_PROBEMTU; 1859 Free(rtt); 1860} 1861 1862int *icmp6_sysvars[] = ICMPV6CTL_VARS; 1863 1864int 1865icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 1866 int *name; 1867 u_int namelen; 1868 void *oldp; 1869 size_t *oldlenp; 1870 void *newp; 1871 size_t newlen; 1872{ 1873 if (name[0] >= ICMPV6CTL_MAXID) 1874 return (EOPNOTSUPP); 1875 switch (name[0]) { 1876#if 0 1877 ICMPV6CTL_ND6_PRUNE: 1878 ICMPV6CTL_ND6_DELAY: 1879 ICMPV6CTL_ND6_UMAXTRIES: 1880 ICMPV6CTL_ND6_MMAXTRIES: 1881 ICMPV6CTL_ND6_USELOOPBACK: 1882 ICMPV6CTL_ND6_PROXYALL: 1883 /* need to check the value. */ 1884#endif 1885 case ICMPV6CTL_STATS: 1886 return sysctl_rdtrunc(oldp, oldlenp, newp, &icmp6stat, 1887 sizeof(icmp6stat)); 1888 1889 default: 1890 return (sysctl_int_arr(icmp6_sysvars, name, namelen, 1891 oldp, oldlenp, newp, newlen)); 1892 } 1893} 1894#endif /*__bsdi__*/ 1895 1896#ifdef __NetBSD__ 1897#include <vm/vm.h> 1898#include <sys/sysctl.h> 1899int 1900icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 1901 int *name; 1902 u_int namelen; 1903 void *oldp; 1904 size_t *oldlenp; 1905 void *newp; 1906 size_t newlen; 1907{ 1908 1909 /* All sysctl names at this level are terminal. */ 1910 if (namelen != 1) 1911 return ENOTDIR; 1912 1913 switch (name[0]) { 1914 1915 case ICMPV6CTL_REDIRACCEPT: 1916 return sysctl_int(oldp, oldlenp, newp, newlen, 1917 &icmp6_rediraccept); 1918 case ICMPV6CTL_REDIRTIMEOUT: 1919 return sysctl_int(oldp, oldlenp, newp, newlen, 1920 &icmp6_redirtimeout); 1921 case ICMPV6CTL_STATS: 1922 return sysctl_rdstruct(oldp, oldlenp, newp, 1923 &icmp6stat, sizeof(icmp6stat)); 1924 case ICMPV6CTL_ERRRATELIMIT: 1925 return sysctl_int(oldp, oldlenp, newp, newlen, 1926 &icmp6errratelim); 1927 case ICMPV6CTL_ND6_PRUNE: 1928 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_prune); 1929 case ICMPV6CTL_ND6_DELAY: 1930 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_delay); 1931 case ICMPV6CTL_ND6_UMAXTRIES: 1932 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_umaxtries); 1933 case ICMPV6CTL_ND6_MMAXTRIES: 1934 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_mmaxtries); 1935 case ICMPV6CTL_ND6_USELOOPBACK: 1936 return sysctl_int(oldp, oldlenp, newp, newlen, 1937 &nd6_useloopback); 1938 case ICMPV6CTL_ND6_PROXYALL: 1939 return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_proxyall); 1940 default: 1941 return ENOPROTOOPT; 1942 } 1943 /* NOTREACHED */ 1944} 1945#endif /* __NetBSD__ */ 1946