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