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