1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "defs.h" 30 #include "tables.h" 31 32 #include <sys/sysmacros.h> 33 34 static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen, 35 struct phyint *pi, struct sockaddr_in6 *from); 36 37 static void incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, 38 int len, struct sockaddr_in6 *from); 39 40 void incoming_ra(struct phyint *pi, struct nd_router_advert *ra, 41 int len, struct sockaddr_in6 *from, boolean_t loopback); 42 static void incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 43 struct sockaddr_in6 *from, boolean_t loopback); 44 static void incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 45 struct sockaddr_in6 *from, boolean_t loopback); 46 void incoming_prefix_onlink_process(struct prefix *pr, 47 uchar_t *opt); 48 static boolean_t incoming_prefix_addrconf(struct phyint *pi, 49 uchar_t *opt, struct sockaddr_in6 *from, 50 boolean_t loopback); 51 boolean_t incoming_prefix_addrconf_process(struct phyint *pi, 52 struct prefix *pr, uchar_t *opt, 53 struct sockaddr_in6 *from, boolean_t loopback, 54 boolean_t new_prefix); 55 static void incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 56 struct sockaddr_in6 *from); 57 static void incoming_lla_opt(struct phyint *pi, uchar_t *opt, 58 struct sockaddr_in6 *from, int isrouter); 59 60 static void verify_ra_consistency(struct phyint *pi, 61 struct nd_router_advert *ra, 62 int len, struct sockaddr_in6 *from); 63 static void verify_prefix_opt(struct phyint *pi, uchar_t *opt, 64 char *frombuf); 65 static void verify_mtu_opt(struct phyint *pi, uchar_t *opt, 66 char *frombuf); 67 68 static void update_ra_flag(const struct phyint *pi, 69 const struct sockaddr_in6 *from, int isrouter); 70 71 static uint_t ra_flags; /* Global to detect when to trigger DHCP */ 72 73 /* 74 * Return a pointer to the specified option buffer. 75 * If not found return NULL. 76 */ 77 static void * 78 find_ancillary(struct msghdr *msg, int cmsg_type) 79 { 80 struct cmsghdr *cmsg; 81 82 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 83 cmsg = CMSG_NXTHDR(msg, cmsg)) { 84 if (cmsg->cmsg_level == IPPROTO_IPV6 && 85 cmsg->cmsg_type == cmsg_type) { 86 return (CMSG_DATA(cmsg)); 87 } 88 } 89 return (NULL); 90 } 91 92 void 93 in_data(struct phyint *pi) 94 { 95 struct sockaddr_in6 from; 96 struct icmp6_hdr *icmp; 97 struct nd_router_solicit *rs; 98 struct nd_router_advert *ra; 99 static uint64_t in_packet[(IP_MAXPACKET + 1)/8]; 100 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8]; 101 int len; 102 char abuf[INET6_ADDRSTRLEN]; 103 const char *msgbuf; 104 struct msghdr msg; 105 struct iovec iov; 106 uchar_t *opt; 107 uint_t hoplimit; 108 109 iov.iov_base = (char *)in_packet; 110 iov.iov_len = sizeof (in_packet); 111 msg.msg_iov = &iov; 112 msg.msg_iovlen = 1; 113 msg.msg_name = (struct sockaddr *)&from; 114 msg.msg_namelen = sizeof (from); 115 msg.msg_control = ancillary_data; 116 msg.msg_controllen = sizeof (ancillary_data); 117 118 if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) { 119 logperror_pi(pi, "in_data: recvfrom"); 120 return; 121 } 122 if (len == 0) 123 return; 124 125 if (inet_ntop(AF_INET6, (void *)&from.sin6_addr, 126 abuf, sizeof (abuf)) == NULL) 127 msgbuf = "Unspecified Router"; 128 else 129 msgbuf = abuf; 130 131 /* Ignore packets > 64k or control buffers that don't fit */ 132 if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 133 if (debug & D_PKTBAD) { 134 logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x " 135 "from %s\n", msg.msg_flags, msgbuf); 136 } 137 return; 138 } 139 140 icmp = (struct icmp6_hdr *)in_packet; 141 142 if (len < ICMP6_MINLEN) { 143 logmsg(LOG_INFO, "Too short ICMP packet: %d bytes " 144 "from %s on %s\n", 145 len, msgbuf, pi->pi_name); 146 return; 147 } 148 149 opt = find_ancillary(&msg, IPV6_HOPLIMIT); 150 if (opt == NULL) { 151 /* Unknown hoplimit - must drop */ 152 logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n", 153 msgbuf, pi->pi_name); 154 return; 155 } 156 hoplimit = *(uint_t *)opt; 157 opt = find_ancillary(&msg, IPV6_RTHDR); 158 if (opt != NULL) { 159 /* Can't allow routing headers in ND messages */ 160 logmsg(LOG_INFO, "ND message with routing header " 161 "from %s on %s\n", 162 msgbuf, pi->pi_name); 163 return; 164 } 165 switch (icmp->icmp6_type) { 166 case ND_ROUTER_SOLICIT: 167 if (!pi->pi_AdvSendAdvertisements) 168 return; 169 if (pi->pi_flags & IFF_NORTEXCH) { 170 if (debug & D_PKTIN) { 171 logmsg(LOG_DEBUG, "Ignore received RS packet " 172 "on %s (no route exchange on interface)\n", 173 pi->pi_name); 174 } 175 return; 176 } 177 178 /* 179 * Assumes that the kernel has verified the AH (if present) 180 * and the ICMP checksum. 181 */ 182 if (hoplimit != IPV6_MAX_HOPS) { 183 logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n", 184 hoplimit, msgbuf, pi->pi_name); 185 return; 186 } 187 188 if (icmp->icmp6_code != 0) { 189 logmsg(LOG_INFO, "RS code: %d from %s on %s\n", 190 icmp->icmp6_code, msgbuf, pi->pi_name); 191 return; 192 } 193 194 if (len < sizeof (struct nd_router_solicit)) { 195 logmsg(LOG_INFO, "RS too short: %d bytes " 196 "from %s on %s\n", 197 len, msgbuf, pi->pi_name); 198 return; 199 } 200 rs = (struct nd_router_solicit *)icmp; 201 if (len > sizeof (struct nd_router_solicit)) { 202 if (!verify_opt_len((struct nd_opt_hdr *)&rs[1], 203 len - sizeof (struct nd_router_solicit), pi, &from)) 204 return; 205 } 206 if (debug & D_PKTIN) { 207 print_route_sol("Received valid solicit from ", pi, 208 rs, len, &from); 209 } 210 incoming_rs(pi, rs, len, &from); 211 break; 212 213 case ND_ROUTER_ADVERT: 214 if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) { 215 /* 216 * Router advt. must have address! 217 * Logging the news and returning. 218 */ 219 logmsg(LOG_DEBUG, 220 "Router's address unspecified in advertisement\n"); 221 return; 222 } 223 if (pi->pi_flags & IFF_NORTEXCH) { 224 if (debug & D_PKTIN) { 225 logmsg(LOG_DEBUG, "Ignore received RA packet " 226 "on %s (no route exchange on interface)\n", 227 pi->pi_name); 228 } 229 return; 230 } 231 232 /* 233 * Assumes that the kernel has verified the AH (if present) 234 * and the ICMP checksum. 235 */ 236 if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 237 logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n", 238 msgbuf, pi->pi_name); 239 return; 240 } 241 242 if (hoplimit != IPV6_MAX_HOPS) { 243 logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n", 244 hoplimit, msgbuf, pi->pi_name); 245 return; 246 } 247 248 if (icmp->icmp6_code != 0) { 249 logmsg(LOG_INFO, "RA code: %d from %s on %s\n", 250 icmp->icmp6_code, msgbuf, pi->pi_name); 251 return; 252 } 253 254 if (len < sizeof (struct nd_router_advert)) { 255 logmsg(LOG_INFO, "RA too short: %d bytes " 256 "from %s on %s\n", 257 len, msgbuf, pi->pi_name); 258 return; 259 } 260 ra = (struct nd_router_advert *)icmp; 261 if (len > sizeof (struct nd_router_advert)) { 262 if (!verify_opt_len((struct nd_opt_hdr *)&ra[1], 263 len - sizeof (struct nd_router_advert), pi, &from)) 264 return; 265 } 266 if (debug & D_PKTIN) { 267 print_route_adv("Received valid advert from ", pi, 268 ra, len, &from); 269 } 270 if (pi->pi_AdvSendAdvertisements) 271 verify_ra_consistency(pi, ra, len, &from); 272 else 273 incoming_ra(pi, ra, len, &from, _B_FALSE); 274 break; 275 } 276 } 277 278 /* 279 * Process a received router solicitation. 280 * Check for source link-layer address option and check if it 281 * is time to advertise. 282 */ 283 static void 284 incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len, 285 struct sockaddr_in6 *from) 286 { 287 struct nd_opt_hdr *opt; 288 int optlen; 289 290 /* Process any options */ 291 len -= sizeof (struct nd_router_solicit); 292 opt = (struct nd_opt_hdr *)&rs[1]; 293 while (len >= sizeof (struct nd_opt_hdr)) { 294 optlen = opt->nd_opt_len * 8; 295 switch (opt->nd_opt_type) { 296 case ND_OPT_SOURCE_LINKADDR: 297 incoming_lla_opt(pi, (uchar_t *)opt, 298 from, NDF_ISROUTER_OFF); 299 break; 300 default: 301 break; 302 } 303 opt = (struct nd_opt_hdr *)((char *)opt + optlen); 304 len -= optlen; 305 } 306 /* Simple algorithm: treat unicast and multicast RSs the same */ 307 check_to_advertise(pi, RECEIVED_SOLICIT); 308 } 309 310 /* 311 * Process a received router advertisement. 312 * Called both when packets arrive as well as when we send RAs. 313 * In the latter case 'loopback' is set. 314 */ 315 void 316 incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len, 317 struct sockaddr_in6 *from, boolean_t loopback) 318 { 319 struct nd_opt_hdr *opt; 320 int optlen; 321 struct lifreq lifr; 322 boolean_t set_needed = _B_FALSE; 323 struct router *dr; 324 uint16_t router_lifetime; 325 uint_t reachable, retrans; 326 boolean_t reachable_time_changed = _B_FALSE; 327 boolean_t slla_opt_present = _B_FALSE; 328 329 if (no_loopback && loopback) 330 return; 331 332 /* 333 * If the interface is FAILED or INACTIVE or OFFLINE, don't 334 * create any addresses on them. in.mpathd assumes that no new 335 * addresses will appear on these. This implies that we 336 * won't create any new prefixes advertised by the router 337 * on FAILED/INACTIVE/OFFLINE interfaces. When the state changes, 338 * the next RA will create the prefix on this interface. 339 */ 340 if (pi->pi_flags & (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) 341 return; 342 343 (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 344 lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 345 if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 346 if (errno == ENXIO) 347 return; 348 logperror_pi(pi, "incoming_ra: SIOCGLIFLNKINFO"); 349 return; 350 } 351 if (ra->nd_ra_curhoplimit != CURHOP_UNSPECIFIED && 352 ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) { 353 pi->pi_CurHopLimit = ra->nd_ra_curhoplimit; 354 355 lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 356 set_needed = _B_TRUE; 357 } 358 359 reachable = ntohl(ra->nd_ra_reachable); 360 if (reachable != 0 && 361 reachable != pi->pi_BaseReachableTime) { 362 pi->pi_BaseReachableTime = reachable; 363 reachable_time_changed = _B_TRUE; 364 } 365 366 if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL || 367 reachable_time_changed) { 368 phyint_reach_random(pi, _B_FALSE); 369 set_needed = _B_TRUE; 370 } 371 lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 372 373 retrans = ntohl(ra->nd_ra_retransmit); 374 if (retrans != 0 && 375 pi->pi_RetransTimer != retrans) { 376 pi->pi_RetransTimer = retrans; 377 lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 378 set_needed = _B_TRUE; 379 } 380 381 if (set_needed) { 382 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 383 logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO"); 384 return; 385 } 386 } 387 388 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && 389 !(ra_flags & ND_RA_FLAG_MANAGED)) { 390 ra_flags |= ND_RA_FLAG_MANAGED; 391 /* TODO trigger dhcpv6 */ 392 logmsg(LOG_DEBUG, "incoming_ra: trigger dhcp MANAGED\n"); 393 } 394 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && 395 !(ra_flags & ND_RA_FLAG_OTHER)) { 396 ra_flags |= ND_RA_FLAG_OTHER; 397 if (!(ra_flags & ND_RA_FLAG_MANAGED)) { 398 /* TODO trigger dhcpv6 for non-address info */ 399 logmsg(LOG_DEBUG, "incoming_ra: trigger dhcp OTHER\n"); 400 } 401 } 402 /* Skip default router code if sent from ourselves */ 403 if (!loopback) { 404 /* Find and update or add default router in list */ 405 dr = router_lookup(pi, from->sin6_addr); 406 router_lifetime = ntohs(ra->nd_ra_router_lifetime); 407 if (dr == NULL) { 408 if (router_lifetime != 0) { 409 dr = router_create(pi, from->sin6_addr, 410 MILLISEC * router_lifetime); 411 timer_schedule(dr->dr_lifetime); 412 } 413 } else { 414 dr->dr_lifetime = MILLISEC * router_lifetime; 415 if (dr->dr_lifetime != 0) 416 timer_schedule(dr->dr_lifetime); 417 if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) || 418 (dr->dr_lifetime == 0 && dr->dr_inkernel)) 419 router_update_k(dr); 420 } 421 } 422 /* Process any options */ 423 len -= sizeof (struct nd_router_advert); 424 opt = (struct nd_opt_hdr *)&ra[1]; 425 while (len >= sizeof (struct nd_opt_hdr)) { 426 optlen = opt->nd_opt_len * 8; 427 switch (opt->nd_opt_type) { 428 case ND_OPT_PREFIX_INFORMATION: 429 incoming_prefix_opt(pi, (uchar_t *)opt, from, 430 loopback); 431 break; 432 case ND_OPT_MTU: 433 incoming_mtu_opt(pi, (uchar_t *)opt, from); 434 break; 435 case ND_OPT_SOURCE_LINKADDR: 436 /* skip lla option if sent from ourselves! */ 437 if (!loopback) { 438 incoming_lla_opt(pi, (uchar_t *)opt, 439 from, NDF_ISROUTER_ON); 440 slla_opt_present = _B_TRUE; 441 } 442 break; 443 default: 444 break; 445 } 446 opt = (struct nd_opt_hdr *)((char *)opt + optlen); 447 len -= optlen; 448 } 449 if (!loopback && !slla_opt_present) 450 update_ra_flag(pi, from, NDF_ISROUTER_ON); 451 /* Stop sending solicitations */ 452 check_to_solicit(pi, SOLICIT_DONE); 453 } 454 455 /* 456 * Process a received prefix option. 457 * Unless addrconf is turned off we process both the addrconf and the 458 * onlink aspects of the prefix option. 459 * 460 * Note that when a flag (onlink or auto) is turned off we do nothing - 461 * the prefix will time out. 462 */ 463 static void 464 incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 465 struct sockaddr_in6 *from, boolean_t loopback) 466 { 467 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 468 boolean_t good_prefix = _B_TRUE; 469 470 if (8 * po->nd_opt_pi_len != sizeof (*po)) { 471 char abuf[INET6_ADDRSTRLEN]; 472 473 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 474 abuf, sizeof (abuf)); 475 logmsg(LOG_INFO, "prefix option from %s on %s wrong size " 476 "(%d bytes)\n", 477 abuf, pi->pi_name, 478 8 * (int)po->nd_opt_pi_len); 479 return; 480 } 481 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 482 char abuf[INET6_ADDRSTRLEN]; 483 484 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 485 abuf, sizeof (abuf)); 486 logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix " 487 "- ignored\n", 488 abuf, pi->pi_name); 489 return; 490 } 491 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && 492 pi->pi_StatelessAddrConf) { 493 good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback); 494 } 495 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && 496 good_prefix) { 497 incoming_prefix_onlink(pi, opt, from, loopback); 498 } 499 } 500 501 /* 502 * Process prefix options with the onlink flag set. 503 * 504 * If there are no routers ndpd will add an onlink 505 * default route which will allow communication 506 * between neighbors. 507 * 508 * This function needs to loop to find the same prefix multiple times 509 * as if a failover happened earlier, the addresses belonging to 510 * a different interface may be found here on this interface. 511 */ 512 /* ARGSUSED2 */ 513 static void 514 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 515 struct sockaddr_in6 *from, boolean_t loopback) 516 { 517 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 518 int plen; 519 struct prefix *pr; 520 uint32_t validtime; /* Without 2 hour rule */ 521 boolean_t found_one = _B_FALSE; 522 523 plen = po->nd_opt_pi_prefix_len; 524 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 525 if (pr->pr_prefix_len == plen && 526 prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 527 /* Exclude static prefixes */ 528 if (pr->pr_state & PR_STATIC) 529 continue; 530 found_one = _B_TRUE; 531 incoming_prefix_onlink_process(pr, opt); 532 } 533 } 534 535 validtime = ntohl(po->nd_opt_pi_valid_time); 536 /* 537 * If we have found a matching prefix already or validtime 538 * is zero, we have nothing to do. 539 */ 540 if (validtime == 0 || found_one) 541 return; 542 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 543 if (pr == NULL) 544 return; 545 incoming_prefix_onlink_process(pr, opt); 546 } 547 548 void 549 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt) 550 { 551 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 552 uint32_t validtime; /* Without 2 hour rule */ 553 char abuf[INET6_ADDRSTRLEN]; 554 555 validtime = ntohl(po->nd_opt_pi_valid_time); 556 if (validtime != 0) 557 pr->pr_state |= PR_ONLINK; 558 else 559 pr->pr_state &= ~PR_ONLINK; 560 561 /* 562 * Convert from seconds to milliseconds avoiding overflow. 563 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 564 * (4 billion seconds - about 130 years) we will in fact time 565 * out the prefix after 4 billion milliseconds - 46 days). 566 * Thus the longest lifetime (apart from infinity) is 46 days. 567 * Note that this ensures that PREFIX_INFINITY still means "forever". 568 */ 569 if (pr->pr_flags & IFF_TEMPORARY) { 570 pr->pr_OnLinkLifetime = pr->pr_ValidLifetime; 571 } else { 572 if (validtime >= PREFIX_INFINITY / MILLISEC) 573 pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1; 574 else 575 pr->pr_OnLinkLifetime = validtime * MILLISEC; 576 } 577 pr->pr_OnLinkFlag = _B_TRUE; 578 if (debug & (D_PREFIX|D_TMP)) { 579 logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) " 580 "onlink %u state 0x%x, kstate 0x%x\n", 581 pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 582 abuf, sizeof (abuf)), pr->pr_prefix_len, 583 pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state); 584 } 585 586 if (pr->pr_kernel_state != pr->pr_state) { 587 prefix_update_k(pr); 588 } 589 590 if (pr->pr_OnLinkLifetime != 0) 591 timer_schedule(pr->pr_OnLinkLifetime); 592 } 593 594 /* 595 * Process prefix options with the autonomous flag set. 596 * Returns false if this prefix results in a bad address (duplicate) 597 * This function needs to loop to find the same prefix multiple times 598 * as if a failover happened earlier, the addresses belonging to 599 * a different interface may be found here on this interface. 600 */ 601 /* ARGSUSED2 */ 602 static boolean_t 603 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt, 604 struct sockaddr_in6 *from, boolean_t loopback) 605 { 606 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 607 int plen; 608 struct prefix *pr; 609 uint32_t validtime, preftime; /* In seconds */ 610 char abuf[INET6_ADDRSTRLEN]; 611 char pbuf[INET6_ADDRSTRLEN]; 612 boolean_t found_pub = _B_FALSE; 613 boolean_t found_tmp = _B_FALSE; 614 boolean_t ret; 615 616 validtime = ntohl(po->nd_opt_pi_valid_time); 617 preftime = ntohl(po->nd_opt_pi_preferred_time); 618 plen = po->nd_opt_pi_prefix_len; 619 620 /* Sanity checks */ 621 if (validtime < preftime) { 622 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 623 abuf, sizeof (abuf)); 624 (void) inet_ntop(AF_INET6, 625 (void *)&po->nd_opt_pi_prefix, 626 pbuf, sizeof (pbuf)); 627 logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: " 628 "valid %u < pref %u ignored\n", 629 pbuf, plen, abuf, pi->pi_name, 630 validtime, preftime); 631 return (_B_FALSE); 632 } 633 634 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 635 if (pr->pr_prefix_len == plen && 636 prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 637 638 /* Exclude static prefixes */ 639 if (pr->pr_state & PR_STATIC) 640 continue; 641 if (pr->pr_flags & IFF_TEMPORARY) { 642 /* 643 * If this address is deprecated and its token 644 * doesn't match the current tmp token, we want 645 * to create a new address with the current 646 * token. So don't count this addr as a match. 647 */ 648 if (!((pr->pr_flags & IFF_DEPRECATED) && 649 !token_equal(pi->pi_tmp_token, 650 pr->pr_address, TMP_TOKEN_BITS))) 651 found_tmp = _B_TRUE; 652 } else { 653 found_pub = _B_TRUE; 654 } 655 (void) incoming_prefix_addrconf_process(pi, pr, opt, 656 from, loopback, _B_FALSE); 657 } 658 } 659 660 /* 661 * If we have found a matching prefix (for public and, if temp addrs 662 * are enabled, for temporary) already or validtime is zero, we have 663 * nothing to do. 664 */ 665 if (validtime == 0 || 666 (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp))) 667 return (_B_TRUE); 668 669 if (!found_pub) { 670 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 671 if (pr == NULL) 672 return (_B_TRUE); 673 ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 674 loopback, _B_TRUE); 675 } 676 /* 677 * if processing of the public address failed, 678 * don't bother with the temporary address. 679 */ 680 if (ret == _B_FALSE) 681 return (_B_FALSE); 682 683 if (pi->pi_TmpAddrsEnabled && !found_tmp) { 684 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 685 IFF_TEMPORARY); 686 if (pr == NULL) 687 return (_B_TRUE); 688 ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 689 loopback, _B_TRUE); 690 } 691 692 return (ret); 693 } 694 695 boolean_t 696 incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr, 697 uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback, 698 boolean_t new_prefix) 699 { 700 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 701 char abuf[INET6_ADDRSTRLEN]; 702 char pbuf[INET6_ADDRSTRLEN]; 703 uint32_t validtime, preftime; /* In seconds */ 704 uint32_t recorded_validtime; /* In seconds */ 705 int plen; 706 struct prefix *other_pr; 707 708 validtime = ntohl(po->nd_opt_pi_valid_time); 709 preftime = ntohl(po->nd_opt_pi_preferred_time); 710 plen = po->nd_opt_pi_prefix_len; 711 if (!new_prefix) { 712 /* 713 * Check 2 hour rule on valid lifetime. 714 * Follows: RFC 2462 715 * If we advertised this prefix ourselves we skip 716 * these checks. They are also skipped if we did not 717 * previously do addrconf on this prefix. 718 */ 719 recorded_validtime = pr->pr_ValidLifetime / MILLISEC; 720 721 if (loopback || !(pr->pr_state & PR_AUTO) || 722 validtime >= MIN_VALID_LIFETIME || 723 /* LINTED - statement has no consequent */ 724 validtime >= recorded_validtime) { 725 /* OK */ 726 } else if (recorded_validtime < MIN_VALID_LIFETIME && 727 validtime < recorded_validtime) { 728 /* Ignore the prefix */ 729 (void) inet_ntop(AF_INET6, 730 (void *)&from->sin6_addr, 731 abuf, sizeof (abuf)); 732 (void) inet_ntop(AF_INET6, 733 (void *)&po->nd_opt_pi_prefix, 734 pbuf, sizeof (pbuf)); 735 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 736 "too short valid lifetime %u stored %u " 737 "- ignored\n", 738 pbuf, plen, abuf, pi->pi_name, 739 validtime, recorded_validtime); 740 return (_B_TRUE); 741 } else { 742 /* 743 * If the router clock runs slower than the 744 * host by 1 second over 2 hours then this 745 * test will set the lifetime back to 2 hours 746 * once i.e. a lifetime decrementing in 747 * realtime might cause the prefix to live an 748 * extra 2 hours on the host. 749 */ 750 (void) inet_ntop(AF_INET6, 751 (void *)&from->sin6_addr, 752 abuf, sizeof (abuf)); 753 (void) inet_ntop(AF_INET6, 754 (void *)&po->nd_opt_pi_prefix, 755 pbuf, sizeof (pbuf)); 756 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 757 "valid time %u stored %u rounded up " 758 "to %u\n", 759 pbuf, plen, abuf, pi->pi_name, 760 validtime, recorded_validtime, 761 MIN_VALID_LIFETIME); 762 validtime = MIN_VALID_LIFETIME; 763 } 764 } 765 766 /* 767 * For RFC3041 addresses, need to take token lifetime 768 * into account, too. 769 */ 770 if (pr->pr_flags & IFF_TEMPORARY) { 771 uint_t cur_tpreftime = 772 pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor; 773 774 if (new_prefix) { 775 validtime = MIN(validtime, pi->pi_TmpValidLifetime); 776 preftime = MIN(preftime, cur_tpreftime); 777 } else { 778 uint_t cur_vexp, cur_pexp, curtime; 779 curtime = getcurrenttime() / MILLISEC; 780 781 cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime; 782 cur_pexp = pr->pr_CreateTime + cur_tpreftime; 783 if (curtime > cur_vexp) 784 validtime = 0; 785 else if ((curtime + validtime) > cur_vexp) 786 validtime = cur_vexp - curtime; 787 /* 788 * If this is an existing address which was deprecated 789 * because of a bad token, we don't want to update its 790 * preferred lifetime! 791 */ 792 if ((pr->pr_PreferredLifetime == 0) && 793 !token_equal(pr->pr_address, pi->pi_tmp_token, 794 TMP_TOKEN_BITS)) 795 preftime = 0; 796 else if (curtime > cur_pexp) 797 preftime = 0; 798 else if ((curtime + preftime) > cur_pexp) 799 preftime = cur_pexp - curtime; 800 } 801 if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) { 802 (void) inet_ntop(AF_INET6, 803 (void *)&from->sin6_addr, 804 abuf, sizeof (abuf)); 805 (void) inet_ntop(AF_INET6, 806 (void *)&po->nd_opt_pi_prefix, 807 pbuf, sizeof (pbuf)); 808 logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: " 809 "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n", 810 pbuf, plen, abuf, pi->pi_name, preftime, 811 pi->pi_TmpRegenAdvance); 812 if (new_prefix) 813 prefix_delete(pr); 814 return (_B_TRUE); 815 } 816 } 817 if (debug & D_TMP) 818 logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, " 819 "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime); 820 821 if (!(pr->pr_state & PR_AUTO)) { 822 int i, tokenlen; 823 in6_addr_t *token; 824 /* 825 * Form a new local address if the lengths match. 826 */ 827 if (pr->pr_flags && IFF_TEMPORARY) { 828 if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) { 829 if (!tmptoken_create(pi)) { 830 prefix_delete(pr); 831 return (_B_TRUE); 832 } 833 } 834 tokenlen = TMP_TOKEN_BITS; 835 token = &pi->pi_tmp_token; 836 } else { 837 tokenlen = pi->pi_token_length; 838 token = &pi->pi_token; 839 } 840 if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) { 841 (void) inet_ntop(AF_INET6, 842 (void *)&from->sin6_addr, 843 abuf, sizeof (abuf)); 844 (void) inet_ntop(AF_INET6, 845 (void *)&po->nd_opt_pi_prefix, 846 pbuf, sizeof (pbuf)); 847 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 848 "mismatched length %d token length %d\n", 849 pbuf, plen, abuf, pi->pi_name, 850 pr->pr_prefix_len, tokenlen); 851 return (_B_TRUE); 852 } 853 for (i = 0; i < 16; i++) { 854 /* 855 * prefix_create ensures that pr_prefix has all-zero 856 * bits after prefixlen. 857 */ 858 pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | 859 token->s6_addr[i]; 860 } 861 /* 862 * Check if any other physical interface has the same 863 * address configured already 864 */ 865 if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) { 866 /* 867 * Delete this prefix structure as kernel 868 * does not allow duplicated addresses 869 */ 870 871 logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 872 "Duplicate prefix %s received on interface %s\n", 873 inet_ntop(AF_INET6, 874 (void *)&po->nd_opt_pi_prefix, abuf, 875 sizeof (abuf)), pi->pi_name); 876 logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 877 "Prefix already exists in interface %s\n", 878 other_pr->pr_physical->pi_name); 879 if (new_prefix) { 880 prefix_delete(pr); 881 return (_B_FALSE); 882 } 883 /* Ignore for addrconf purposes */ 884 validtime = preftime = 0; 885 } 886 if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) { 887 pr->pr_CreateTime = getcurrenttime() / MILLISEC; 888 if (debug & D_TMP) 889 logmsg(LOG_DEBUG, 890 "created tmp addr(%s v %d p %d)\n", 891 pr->pr_name, validtime, preftime); 892 } 893 } 894 895 if (validtime != 0) 896 pr->pr_state |= PR_AUTO; 897 else 898 pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 899 if (preftime != 0 || !(pr->pr_state & PR_AUTO)) 900 pr->pr_state &= ~PR_DEPRECATED; 901 else 902 pr->pr_state |= PR_DEPRECATED; 903 904 /* 905 * Convert from seconds to milliseconds avoiding overflow. 906 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 907 * (4 billion seconds - about 130 years) we will in fact time 908 * out the prefix after 4 billion milliseconds - 46 days). 909 * Thus the longest lifetime (apart from infinity) is 46 days. 910 * Note that this ensures that PREFIX_INFINITY still means "forever". 911 */ 912 if (validtime >= PREFIX_INFINITY / MILLISEC) 913 pr->pr_ValidLifetime = PREFIX_INFINITY - 1; 914 else 915 pr->pr_ValidLifetime = validtime * MILLISEC; 916 if (preftime >= PREFIX_INFINITY / MILLISEC) 917 pr->pr_PreferredLifetime = PREFIX_INFINITY - 1; 918 else 919 pr->pr_PreferredLifetime = preftime * MILLISEC; 920 pr->pr_AutonomousFlag = _B_TRUE; 921 922 if (debug & D_PREFIX) { 923 logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) " 924 "valid %u pref %u\n", 925 pr->pr_physical->pi_name, 926 inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 927 abuf, sizeof (abuf)), pr->pr_prefix_len, 928 pr->pr_ValidLifetime, pr->pr_PreferredLifetime); 929 } 930 931 if (pr->pr_state & PR_AUTO) { 932 /* Take the min of the two timeouts by calling it twice */ 933 if (pr->pr_ValidLifetime != 0) 934 timer_schedule(pr->pr_ValidLifetime); 935 if (pr->pr_PreferredLifetime != 0) 936 timer_schedule(pr->pr_PreferredLifetime); 937 } 938 if (pr->pr_kernel_state != pr->pr_state) { 939 /* Log a message when an addrconf prefix goes away */ 940 if ((pr->pr_kernel_state & PR_AUTO) && 941 !(pr->pr_state & PR_AUTO)) { 942 char abuf[INET6_ADDRSTRLEN]; 943 944 logmsg(LOG_WARNING, "Address removed due to zero " 945 "valid lifetime %s\n", 946 inet_ntop(AF_INET6, (void *)&pr->pr_address, 947 abuf, sizeof (abuf))); 948 } 949 prefix_update_k(pr); 950 } 951 return (_B_TRUE); 952 } 953 954 /* 955 * Process an MTU option received in a router advertisement. 956 */ 957 static void 958 incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 959 struct sockaddr_in6 *from) 960 { 961 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 962 struct lifreq lifr; 963 uint32_t mtu; 964 965 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 966 char abuf[INET6_ADDRSTRLEN]; 967 968 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 969 abuf, sizeof (abuf)); 970 logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 971 "(%d bytes)\n", 972 abuf, pi->pi_name, 973 8 * (int)mo->nd_opt_mtu_len); 974 return; 975 } 976 mtu = ntohl(mo->nd_opt_mtu_mtu); 977 if (pi->pi_LinkMTU == mtu) 978 return; /* No change */ 979 if (mtu > pi->pi_mtu) { 980 /* Can't exceed physical MTU */ 981 char abuf[INET6_ADDRSTRLEN]; 982 983 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 984 abuf, sizeof (abuf)); 985 logmsg(LOG_INFO, "mtu option from %s on %s too large " 986 "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu); 987 return; 988 } 989 if (mtu < IPV6_MIN_MTU) { 990 char abuf[INET6_ADDRSTRLEN]; 991 992 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 993 abuf, sizeof (abuf)); 994 logmsg(LOG_INFO, "mtu option from %s on %s too small " 995 "MTU (%d)\n", abuf, pi->pi_name, mtu); 996 return; 997 } 998 999 pi->pi_LinkMTU = mtu; 1000 (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1001 lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1002 if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 1003 logperror_pi(pi, "incoming_mtu_opt: SIOCGLIFLNKINFO"); 1004 return; 1005 } 1006 lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU; 1007 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 1008 logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO"); 1009 return; 1010 } 1011 } 1012 1013 /* 1014 * Process a source link-layer address option received in a router 1015 * advertisement or solicitation. 1016 */ 1017 static void 1018 incoming_lla_opt(struct phyint *pi, uchar_t *opt, 1019 struct sockaddr_in6 *from, int isrouter) 1020 { 1021 struct nd_opt_lla *lo = (struct nd_opt_lla *)opt; 1022 struct lifreq lifr; 1023 struct sockaddr_in6 *sin6; 1024 int max_content_len; 1025 1026 if (pi->pi_hdw_addr_len == 0) 1027 return; 1028 1029 /* 1030 * Can't remove padding since it is link type specific. 1031 * However, we check against the length of our link-layer 1032 * address. 1033 * Note: assumes that all links have a fixed lengh address. 1034 */ 1035 max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr); 1036 if (max_content_len < pi->pi_hdw_addr_len || 1037 (max_content_len >= 8 && 1038 max_content_len - 7 > pi->pi_hdw_addr_len)) { 1039 char abuf[INET6_ADDRSTRLEN]; 1040 1041 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1042 abuf, sizeof (abuf)); 1043 logmsg(LOG_INFO, "lla option from %s on %s too long with bad " 1044 "physaddr length (%d vs. %d bytes)\n", 1045 abuf, pi->pi_name, 1046 max_content_len, pi->pi_hdw_addr_len); 1047 return; 1048 } 1049 1050 lifr.lifr_nd.lnr_hdw_len = pi->pi_hdw_addr_len; 1051 bcopy((char *)lo->nd_opt_lla_hdw_addr, 1052 (char *)lifr.lifr_nd.lnr_hdw_addr, 1053 lifr.lifr_nd.lnr_hdw_len); 1054 1055 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 1056 bzero(sin6, sizeof (struct sockaddr_in6)); 1057 sin6->sin6_family = AF_INET6; 1058 sin6->sin6_addr = from->sin6_addr; 1059 1060 /* 1061 * Set IsRouter flag if RA; clear if RS. 1062 */ 1063 lifr.lifr_nd.lnr_state_create = ND_STALE; 1064 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 1065 lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 1066 lifr.lifr_nd.lnr_flags = isrouter; 1067 (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1068 lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1069 if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) { 1070 logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND"); 1071 return; 1072 } 1073 } 1074 1075 /* 1076 * Verify the content of the received router advertisement against our 1077 * own configuration as specified in RFC 2461. 1078 */ 1079 static void 1080 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len, 1081 struct sockaddr_in6 *from) 1082 { 1083 char frombuf[INET6_ADDRSTRLEN]; 1084 struct nd_opt_hdr *opt; 1085 int optlen; 1086 uint_t reachable, retrans; 1087 boolean_t pktflag, myflag; 1088 1089 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1090 frombuf, sizeof (frombuf)); 1091 1092 if (ra->nd_ra_curhoplimit != 0 && 1093 pi->pi_AdvCurHopLimit != 0 && 1094 ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) { 1095 logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop " 1096 "limit:\n\treceived %d configuration %d\n", 1097 frombuf, pi->pi_name, 1098 ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit); 1099 } 1100 1101 reachable = ntohl(ra->nd_ra_reachable); 1102 if (reachable != 0 && pi->pi_AdvReachableTime != 0 && 1103 reachable != pi->pi_AdvReachableTime) { 1104 logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable " 1105 "time:\n\treceived %d configuration %d\n", 1106 frombuf, pi->pi_name, 1107 reachable, pi->pi_AdvReachableTime); 1108 } 1109 1110 retrans = ntohl(ra->nd_ra_retransmit); 1111 if (retrans != 0 && pi->pi_AdvRetransTimer != 0 && 1112 retrans != pi->pi_AdvRetransTimer) { 1113 logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit " 1114 "timer:\n\treceived %d configuration %d\n", 1115 frombuf, pi->pi_name, 1116 retrans, pi->pi_AdvRetransTimer); 1117 } 1118 1119 pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0); 1120 myflag = (pi->pi_AdvManagedFlag != 0); 1121 if (pktflag != myflag) { 1122 logmsg(LOG_INFO, "RA from %s on %s inconsistent managed " 1123 "flag:\n\treceived %s configuration %s\n", 1124 frombuf, pi->pi_name, 1125 (pktflag ? "ON" : "OFF"), 1126 (myflag ? "ON" : "OFF")); 1127 } 1128 pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0); 1129 myflag = (pi->pi_AdvOtherConfigFlag != 0); 1130 if (pktflag != myflag) { 1131 logmsg(LOG_INFO, "RA from %s on %s inconsistent other config " 1132 "flag:\n\treceived %s configuration %s\n", 1133 frombuf, pi->pi_name, 1134 (pktflag ? "ON" : "OFF"), 1135 (myflag ? "ON" : "OFF")); 1136 } 1137 1138 /* Process any options */ 1139 len -= sizeof (struct nd_router_advert); 1140 opt = (struct nd_opt_hdr *)&ra[1]; 1141 while (len >= sizeof (struct nd_opt_hdr)) { 1142 optlen = opt->nd_opt_len * 8; 1143 switch (opt->nd_opt_type) { 1144 case ND_OPT_PREFIX_INFORMATION: 1145 verify_prefix_opt(pi, (uchar_t *)opt, frombuf); 1146 break; 1147 case ND_OPT_MTU: 1148 verify_mtu_opt(pi, (uchar_t *)opt, frombuf); 1149 break; 1150 default: 1151 break; 1152 } 1153 opt = (struct nd_opt_hdr *)((char *)opt + optlen); 1154 len -= optlen; 1155 } 1156 } 1157 1158 /* 1159 * Verify that the lifetimes and onlink/auto flags are consistent 1160 * with our settings. 1161 */ 1162 static void 1163 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 1164 { 1165 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 1166 int plen; 1167 struct adv_prefix *adv_pr; 1168 uint32_t validtime, preftime; 1169 char prefixbuf[INET6_ADDRSTRLEN]; 1170 int pktflag, myflag; 1171 1172 if (8 * po->nd_opt_pi_len != sizeof (*po)) { 1173 logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size " 1174 "(%d bytes)\n", 1175 frombuf, pi->pi_name, 1176 8 * (int)po->nd_opt_pi_len); 1177 return; 1178 } 1179 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 1180 logmsg(LOG_INFO, "RA from %s on %s contains link-local " 1181 "prefix - ignored\n", 1182 frombuf, pi->pi_name); 1183 return; 1184 } 1185 plen = po->nd_opt_pi_prefix_len; 1186 adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen); 1187 if (adv_pr == NULL) 1188 return; 1189 1190 /* Ignore prefixes which we do not advertise */ 1191 if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag) 1192 return; 1193 (void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 1194 prefixbuf, sizeof (prefixbuf)); 1195 pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0); 1196 myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0); 1197 if (pktflag != myflag) { 1198 logmsg(LOG_INFO, 1199 "RA from %s on %s inconsistent autonumous flag for \n\t" 1200 "prefix %s/%u: received %s configuration %s\n", 1201 frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 1202 (pktflag ? "ON" : "OFF"), 1203 (myflag ? "ON" : "OFF")); 1204 } 1205 1206 pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0); 1207 myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0); 1208 if (pktflag != myflag) { 1209 logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag " 1210 "for \n\tprefix %s/%u: received %s configuration %s\n", 1211 frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 1212 (pktflag ? "ON" : "OFF"), 1213 (myflag ? "ON" : "OFF")); 1214 } 1215 validtime = ntohl(po->nd_opt_pi_valid_time); 1216 preftime = ntohl(po->nd_opt_pi_preferred_time); 1217 1218 /* 1219 * Take into account variation for lifetimes decrementing 1220 * in real time. Allow +/- 10 percent and +/- 10 seconds. 1221 */ 1222 #define LOWER_LIMIT(val) ((val) - (val)/10 - 10) 1223 #define UPPER_LIMIT(val) ((val) + (val)/10 + 10) 1224 if (adv_pr->adv_pr_AdvValidRealTime) { 1225 if (adv_pr->adv_pr_AdvValidExpiration > 0 && 1226 (validtime < 1227 LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) || 1228 validtime > 1229 UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) { 1230 logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 1231 "lifetime for\n\tprefix %s/%u: received %d " 1232 "configuration %d\n", 1233 frombuf, pi->pi_name, prefixbuf, 1234 adv_pr->adv_pr_prefix_len, 1235 validtime, adv_pr->adv_pr_AdvValidExpiration); 1236 } 1237 } else { 1238 if (validtime != adv_pr->adv_pr_AdvValidLifetime) { 1239 logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 1240 "lifetime for\n\tprefix %s/%u: received %d " 1241 "configuration %d\n", 1242 frombuf, pi->pi_name, prefixbuf, 1243 adv_pr->adv_pr_prefix_len, 1244 validtime, adv_pr->adv_pr_AdvValidLifetime); 1245 } 1246 } 1247 1248 if (adv_pr->adv_pr_AdvPreferredRealTime) { 1249 if (adv_pr->adv_pr_AdvPreferredExpiration > 0 && 1250 (preftime < 1251 LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) || 1252 preftime > 1253 UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) { 1254 logmsg(LOG_INFO, "RA from %s on %s inconsistent " 1255 "preferred lifetime for\n\tprefix %s/%u: " 1256 "received %d configuration %d\n", 1257 frombuf, pi->pi_name, prefixbuf, 1258 adv_pr->adv_pr_prefix_len, 1259 preftime, adv_pr->adv_pr_AdvPreferredExpiration); 1260 } 1261 } else { 1262 if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) { 1263 logmsg(LOG_INFO, "RA from %s on %s inconsistent " 1264 "preferred lifetime for\n\tprefix %s/%u: " 1265 "received %d configuration %d\n", 1266 frombuf, pi->pi_name, prefixbuf, 1267 adv_pr->adv_pr_prefix_len, 1268 preftime, adv_pr->adv_pr_AdvPreferredLifetime); 1269 } 1270 } 1271 } 1272 1273 /* 1274 * Verify the received MTU against our own configuration. 1275 */ 1276 static void 1277 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 1278 { 1279 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 1280 uint32_t mtu; 1281 1282 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 1283 logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 1284 "(%d bytes)\n", 1285 frombuf, pi->pi_name, 1286 8 * (int)mo->nd_opt_mtu_len); 1287 return; 1288 } 1289 mtu = ntohl(mo->nd_opt_mtu_mtu); 1290 if (pi->pi_AdvLinkMTU != 0 && 1291 pi->pi_AdvLinkMTU != mtu) { 1292 logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: " 1293 "received %d configuration %d\n", 1294 frombuf, pi->pi_name, 1295 mtu, pi->pi_AdvLinkMTU); 1296 } 1297 } 1298 1299 /* 1300 * Verify that all options have a non-zero length and that 1301 * the options fit within the total length of the packet (optlen). 1302 */ 1303 static boolean_t 1304 verify_opt_len(struct nd_opt_hdr *opt, int optlen, 1305 struct phyint *pi, struct sockaddr_in6 *from) 1306 { 1307 while (optlen > 0) { 1308 if (opt->nd_opt_len == 0) { 1309 char abuf[INET6_ADDRSTRLEN]; 1310 1311 (void) inet_ntop(AF_INET6, 1312 (void *)&from->sin6_addr, 1313 abuf, sizeof (abuf)); 1314 1315 logmsg(LOG_INFO, "Zero length option type 0x%x " 1316 "from %s on %s\n", 1317 opt->nd_opt_type, abuf, pi->pi_name); 1318 return (_B_FALSE); 1319 } 1320 optlen -= 8 * opt->nd_opt_len; 1321 if (optlen < 0) { 1322 char abuf[INET6_ADDRSTRLEN]; 1323 1324 (void) inet_ntop(AF_INET6, 1325 (void *)&from->sin6_addr, 1326 abuf, sizeof (abuf)); 1327 1328 logmsg(LOG_INFO, "Too large option: type 0x%x len %u " 1329 "from %s on %s\n", 1330 opt->nd_opt_type, opt->nd_opt_len, 1331 abuf, pi->pi_name); 1332 return (_B_FALSE); 1333 } 1334 opt = (struct nd_opt_hdr *)((char *)opt + 1335 8 * opt->nd_opt_len); 1336 } 1337 return (_B_TRUE); 1338 } 1339 1340 /* 1341 * Update IsRouter Flag for Host turning into a router or vice-versa. 1342 */ 1343 static void 1344 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from, 1345 int isrouter) 1346 { 1347 struct lifreq lifr; 1348 char abuf[INET6_ADDRSTRLEN]; 1349 struct sockaddr_in6 *sin6; 1350 1351 /* check if valid flag is being set */ 1352 if ((isrouter != NDF_ISROUTER_ON) && 1353 (isrouter != NDF_ISROUTER_OFF)) { 1354 logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter " 1355 "flag %d\n", isrouter); 1356 return; 1357 } 1358 1359 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 1360 bzero(sin6, sizeof (*sin6)); 1361 sin6->sin6_family = AF_INET6; 1362 sin6->sin6_addr = from->sin6_addr; 1363 1364 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1365 1366 if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) { 1367 if (errno == ESRCH) { 1368 if (debug & D_IFSCAN) { 1369 logmsg(LOG_DEBUG, 1370 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER"); 1371 } 1372 } else { 1373 logperror_pi(pi, "update_ra_flag: SIOCLIFGETND"); 1374 } 1375 } else { 1376 /* 1377 * The lif_nd_req structure has three state values to be used 1378 * when changing/updating nces : 1379 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla. 1380 * 1381 * In this case, we're updating an nce, without changing lla; 1382 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that 1383 * nce's state should not be affected by our flag change. 1384 * 1385 * The kernel implementation also expects the lnr_state_create 1386 * field be always set, before processing ioctl request for NCE 1387 * update. 1388 * We use the state as STALE, while addressing the possibility 1389 * of NCE deletion when ioctl with SIOCLIFGETND argument 1390 * in earlier step is returned - further in such case we don't 1391 * want to re-create the entry in the reachable state. 1392 */ 1393 lifr.lifr_nd.lnr_state_create = ND_STALE; 1394 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 1395 lifr.lifr_nd.lnr_flags = isrouter; 1396 if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) { 1397 logperror_pi(pi, "update_ra_flag: SIOCLIFSETND"); 1398 } else { 1399 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1400 abuf, sizeof (abuf)); 1401 logmsg(LOG_INFO, "update_ra_flag: IsRouter flag " 1402 "updated for %s\n", abuf); 1403 } 1404 } 1405 } 1406