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(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 != pi->pi_CurHopLimit) { 352 pi->pi_CurHopLimit = ra->nd_ra_curhoplimit; 353 354 lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 355 set_needed = _B_TRUE; 356 } 357 358 reachable = ntohl(ra->nd_ra_reachable); 359 if (reachable != 0 && 360 reachable != pi->pi_BaseReachableTime) { 361 pi->pi_BaseReachableTime = reachable; 362 reachable_time_changed = _B_TRUE; 363 } 364 365 if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL || 366 reachable_time_changed) { 367 phyint_reach_random(pi, _B_FALSE); 368 set_needed = _B_TRUE; 369 } 370 lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 371 372 retrans = ntohl(ra->nd_ra_retransmit); 373 if (retrans != 0 && 374 pi->pi_RetransTimer != retrans) { 375 pi->pi_RetransTimer = retrans; 376 lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 377 set_needed = _B_TRUE; 378 } 379 380 if (set_needed) { 381 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 382 logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO"); 383 return; 384 } 385 } 386 387 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && 388 !(ra_flags & ND_RA_FLAG_MANAGED)) { 389 ra_flags |= ND_RA_FLAG_MANAGED; 390 /* TODO trigger dhcpv6 */ 391 logmsg(LOG_DEBUG, "incoming_ra: trigger dhcp MANAGED\n"); 392 } 393 if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && 394 !(ra_flags & ND_RA_FLAG_OTHER)) { 395 ra_flags |= ND_RA_FLAG_OTHER; 396 if (!(ra_flags & ND_RA_FLAG_MANAGED)) { 397 /* TODO trigger dhcpv6 for non-address info */ 398 logmsg(LOG_DEBUG, "incoming_ra: trigger dhcp OTHER\n"); 399 } 400 } 401 /* Skip default router code if sent from ourselves */ 402 if (!loopback) { 403 /* Find and update or add default router in list */ 404 dr = router_lookup(pi, from->sin6_addr); 405 router_lifetime = ntohs(ra->nd_ra_router_lifetime); 406 if (dr == NULL) { 407 if (router_lifetime != 0) { 408 dr = router_create(pi, from->sin6_addr, 409 MILLISEC * router_lifetime); 410 timer_schedule(dr->dr_lifetime); 411 } 412 } else { 413 dr->dr_lifetime = MILLISEC * router_lifetime; 414 if (dr->dr_lifetime != 0) 415 timer_schedule(dr->dr_lifetime); 416 if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) || 417 (dr->dr_lifetime == 0 && dr->dr_inkernel)) 418 router_update_k(dr); 419 } 420 } 421 /* Process any options */ 422 len -= sizeof (struct nd_router_advert); 423 opt = (struct nd_opt_hdr *)&ra[1]; 424 while (len >= sizeof (struct nd_opt_hdr)) { 425 optlen = opt->nd_opt_len * 8; 426 switch (opt->nd_opt_type) { 427 case ND_OPT_PREFIX_INFORMATION: 428 incoming_prefix_opt(pi, (uchar_t *)opt, from, 429 loopback); 430 break; 431 case ND_OPT_MTU: 432 incoming_mtu_opt(pi, (uchar_t *)opt, from); 433 break; 434 case ND_OPT_SOURCE_LINKADDR: 435 /* skip lla option if sent from ourselves! */ 436 if (!loopback) { 437 incoming_lla_opt(pi, (uchar_t *)opt, 438 from, NDF_ISROUTER_ON); 439 slla_opt_present = _B_TRUE; 440 } 441 break; 442 default: 443 break; 444 } 445 opt = (struct nd_opt_hdr *)((char *)opt + optlen); 446 len -= optlen; 447 } 448 if (!slla_opt_present) 449 update_ra_flag(pi, from, NDF_ISROUTER_ON); 450 /* Stop sending solicitations */ 451 check_to_solicit(pi, SOLICIT_DONE); 452 } 453 454 /* 455 * Process a received prefix option. 456 * Unless addrconf is turned off we process both the addrconf and the 457 * onlink aspects of the prefix option. 458 * 459 * Note that when a flag (onlink or auto) is turned off we do nothing - 460 * the prefix will time out. 461 */ 462 static void 463 incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 464 struct sockaddr_in6 *from, boolean_t loopback) 465 { 466 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 467 boolean_t good_prefix = _B_TRUE; 468 469 if (8 * po->nd_opt_pi_len != sizeof (*po)) { 470 char abuf[INET6_ADDRSTRLEN]; 471 472 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 473 abuf, sizeof (abuf)); 474 logmsg(LOG_INFO, "prefix option from %s on %s wrong size " 475 "(%d bytes)\n", 476 abuf, pi->pi_name, 477 8 * (int)po->nd_opt_pi_len); 478 return; 479 } 480 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 481 char abuf[INET6_ADDRSTRLEN]; 482 483 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 484 abuf, sizeof (abuf)); 485 logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix " 486 "- ignored\n", 487 abuf, pi->pi_name); 488 return; 489 } 490 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && 491 pi->pi_StatelessAddrConf) { 492 good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback); 493 } 494 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && 495 good_prefix) { 496 incoming_prefix_onlink(pi, opt, from, loopback); 497 } 498 } 499 500 /* 501 * Process prefix options with the onlink flag set. 502 * 503 * If there are no routers ndpd will add an onlink 504 * default route which will allow communication 505 * between neighbors. 506 * 507 * This function needs to loop to find the same prefix multiple times 508 * as if a failover happened earlier, the addresses belonging to 509 * a different interface may be found here on this interface. 510 */ 511 /* ARGSUSED2 */ 512 static void 513 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 514 struct sockaddr_in6 *from, boolean_t loopback) 515 { 516 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 517 int plen; 518 struct prefix *pr; 519 uint32_t validtime; /* Without 2 hour rule */ 520 boolean_t found_one = _B_FALSE; 521 522 plen = po->nd_opt_pi_prefix_len; 523 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 524 if (pr->pr_prefix_len == plen && 525 prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 526 /* Exclude static prefixes */ 527 if (pr->pr_state & PR_STATIC) 528 continue; 529 found_one = _B_TRUE; 530 incoming_prefix_onlink_process(pr, opt); 531 } 532 } 533 534 validtime = ntohl(po->nd_opt_pi_valid_time); 535 /* 536 * If we have found a matching prefix already or validtime 537 * is zero, we have nothing to do. 538 */ 539 if (validtime == 0 || found_one) 540 return; 541 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 542 if (pr == NULL) 543 return; 544 incoming_prefix_onlink_process(pr, opt); 545 } 546 547 void 548 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt) 549 { 550 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 551 uint32_t validtime; /* Without 2 hour rule */ 552 char abuf[INET6_ADDRSTRLEN]; 553 554 validtime = ntohl(po->nd_opt_pi_valid_time); 555 if (validtime != 0) 556 pr->pr_state |= PR_ONLINK; 557 else 558 pr->pr_state &= ~PR_ONLINK; 559 560 /* 561 * Convert from seconds to milliseconds avoiding overflow. 562 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 563 * (4 billion seconds - about 130 years) we will in fact time 564 * out the prefix after 4 billion milliseconds - 46 days). 565 * Thus the longest lifetime (apart from infinity) is 46 days. 566 * Note that this ensures that PREFIX_INFINITY still means "forever". 567 */ 568 if (pr->pr_flags & IFF_TEMPORARY) { 569 pr->pr_OnLinkLifetime = pr->pr_ValidLifetime; 570 } else { 571 if (validtime >= PREFIX_INFINITY / MILLISEC) 572 pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1; 573 else 574 pr->pr_OnLinkLifetime = validtime * MILLISEC; 575 } 576 pr->pr_OnLinkFlag = _B_TRUE; 577 if (debug & (D_PREFIX|D_TMP)) { 578 logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) " 579 "onlink %u state 0x%x, kstate 0x%x\n", 580 pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 581 abuf, sizeof (abuf)), pr->pr_prefix_len, 582 pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state); 583 } 584 585 if (pr->pr_kernel_state != pr->pr_state) { 586 prefix_update_k(pr); 587 } 588 589 if (pr->pr_OnLinkLifetime != 0) 590 timer_schedule(pr->pr_OnLinkLifetime); 591 } 592 593 /* 594 * Process prefix options with the autonomous flag set. 595 * Returns false if this prefix results in a bad address (duplicate) 596 * This function needs to loop to find the same prefix multiple times 597 * as if a failover happened earlier, the addresses belonging to 598 * a different interface may be found here on this interface. 599 */ 600 /* ARGSUSED2 */ 601 static boolean_t 602 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt, 603 struct sockaddr_in6 *from, boolean_t loopback) 604 { 605 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 606 int plen; 607 struct prefix *pr; 608 uint32_t validtime, preftime; /* In seconds */ 609 char abuf[INET6_ADDRSTRLEN]; 610 char pbuf[INET6_ADDRSTRLEN]; 611 boolean_t found_pub = _B_FALSE; 612 boolean_t found_tmp = _B_FALSE; 613 boolean_t ret; 614 615 validtime = ntohl(po->nd_opt_pi_valid_time); 616 preftime = ntohl(po->nd_opt_pi_preferred_time); 617 plen = po->nd_opt_pi_prefix_len; 618 619 /* Sanity checks */ 620 if (validtime < preftime) { 621 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 622 abuf, sizeof (abuf)); 623 (void) inet_ntop(AF_INET6, 624 (void *)&po->nd_opt_pi_prefix, 625 pbuf, sizeof (pbuf)); 626 logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: " 627 "valid %u < pref %u ignored\n", 628 pbuf, plen, abuf, pi->pi_name, 629 validtime, preftime); 630 return (_B_FALSE); 631 } 632 633 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 634 if (pr->pr_prefix_len == plen && 635 prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 636 637 /* Exclude static prefixes */ 638 if (pr->pr_state & PR_STATIC) 639 continue; 640 if (pr->pr_flags & IFF_TEMPORARY) { 641 /* 642 * If this address is deprecated and its token 643 * doesn't match the current tmp token, we want 644 * to create a new address with the current 645 * token. So don't count this addr as a match. 646 */ 647 if (!((pr->pr_flags & IFF_DEPRECATED) && 648 !token_equal(pi->pi_tmp_token, 649 pr->pr_address, TMP_TOKEN_BITS))) 650 found_tmp = _B_TRUE; 651 } else { 652 found_pub = _B_TRUE; 653 } 654 (void) incoming_prefix_addrconf_process(pi, pr, opt, 655 from, loopback, _B_FALSE); 656 } 657 } 658 659 /* 660 * If we have found a matching prefix (for public and, if temp addrs 661 * are enabled, for temporary) already or validtime is zero, we have 662 * nothing to do. 663 */ 664 if (validtime == 0 || 665 (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp))) 666 return (_B_TRUE); 667 668 if (!found_pub) { 669 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 670 if (pr == NULL) 671 return (_B_TRUE); 672 ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 673 loopback, _B_TRUE); 674 } 675 /* 676 * if processing of the public address failed, 677 * don't bother with the temporary address. 678 */ 679 if (ret == _B_FALSE) 680 return (_B_FALSE); 681 682 if (pi->pi_TmpAddrsEnabled && !found_tmp) { 683 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 684 IFF_TEMPORARY); 685 if (pr == NULL) 686 return (_B_TRUE); 687 ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 688 loopback, _B_TRUE); 689 } 690 691 return (ret); 692 } 693 694 boolean_t 695 incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr, 696 uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback, 697 boolean_t new_prefix) 698 { 699 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 700 char abuf[INET6_ADDRSTRLEN]; 701 char pbuf[INET6_ADDRSTRLEN]; 702 uint32_t validtime, preftime; /* In seconds */ 703 uint32_t recorded_validtime; /* In seconds */ 704 int plen, dadfails = 0; 705 struct prefix *other_pr; 706 707 validtime = ntohl(po->nd_opt_pi_valid_time); 708 preftime = ntohl(po->nd_opt_pi_preferred_time); 709 plen = po->nd_opt_pi_prefix_len; 710 if (!new_prefix) { 711 /* 712 * Check 2 hour rule on valid lifetime. 713 * Follows: RFC 2462 714 * If we advertised this prefix ourselves we skip 715 * these checks. They are also skipped if we did not 716 * previously do addrconf on this prefix. 717 */ 718 recorded_validtime = pr->pr_ValidLifetime / MILLISEC; 719 720 if (loopback || !(pr->pr_state & PR_AUTO) || 721 validtime >= MIN_VALID_LIFETIME || 722 /* LINTED - statement has no consequent */ 723 validtime >= recorded_validtime) { 724 /* OK */ 725 } else if (recorded_validtime < MIN_VALID_LIFETIME && 726 validtime < recorded_validtime) { 727 /* Ignore the prefix */ 728 (void) inet_ntop(AF_INET6, 729 (void *)&from->sin6_addr, 730 abuf, sizeof (abuf)); 731 (void) inet_ntop(AF_INET6, 732 (void *)&po->nd_opt_pi_prefix, 733 pbuf, sizeof (pbuf)); 734 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 735 "too short valid lifetime %u stored %u " 736 "- ignored\n", 737 pbuf, plen, abuf, pi->pi_name, 738 validtime, recorded_validtime); 739 return (_B_TRUE); 740 } else { 741 /* 742 * If the router clock runs slower than the 743 * host by 1 second over 2 hours then this 744 * test will set the lifetime back to 2 hours 745 * once i.e. a lifetime decrementing in 746 * realtime might cause the prefix to live an 747 * extra 2 hours on the host. 748 */ 749 (void) inet_ntop(AF_INET6, 750 (void *)&from->sin6_addr, 751 abuf, sizeof (abuf)); 752 (void) inet_ntop(AF_INET6, 753 (void *)&po->nd_opt_pi_prefix, 754 pbuf, sizeof (pbuf)); 755 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 756 "valid time %u stored %u rounded up " 757 "to %u\n", 758 pbuf, plen, abuf, pi->pi_name, 759 validtime, recorded_validtime, 760 MIN_VALID_LIFETIME); 761 validtime = MIN_VALID_LIFETIME; 762 } 763 } 764 765 /* 766 * For RFC3041 addresses, need to take token lifetime 767 * into account, too. 768 */ 769 if (pr->pr_flags & IFF_TEMPORARY) { 770 uint_t cur_tpreftime = 771 pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor; 772 773 if (new_prefix) { 774 validtime = MIN(validtime, pi->pi_TmpValidLifetime); 775 preftime = MIN(preftime, cur_tpreftime); 776 } else { 777 uint_t cur_vexp, cur_pexp, curtime; 778 curtime = getcurrenttime() / MILLISEC; 779 780 cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime; 781 cur_pexp = pr->pr_CreateTime + cur_tpreftime; 782 if (curtime > cur_vexp) 783 validtime = 0; 784 else if ((curtime + validtime) > cur_vexp) 785 validtime = cur_vexp - curtime; 786 /* 787 * If this is an existing address which was deprecated 788 * because of a bad token, we don't want to update its 789 * preferred lifetime! 790 */ 791 if ((pr->pr_PreferredLifetime == 0) && 792 !token_equal(pr->pr_address, pi->pi_tmp_token, 793 TMP_TOKEN_BITS)) 794 preftime = 0; 795 else if (curtime > cur_pexp) 796 preftime = 0; 797 else if ((curtime + preftime) > cur_pexp) 798 preftime = cur_pexp - curtime; 799 } 800 if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) { 801 (void) inet_ntop(AF_INET6, 802 (void *)&from->sin6_addr, 803 abuf, sizeof (abuf)); 804 (void) inet_ntop(AF_INET6, 805 (void *)&po->nd_opt_pi_prefix, 806 pbuf, sizeof (pbuf)); 807 logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: " 808 "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n", 809 pbuf, plen, abuf, pi->pi_name, preftime, 810 pi->pi_TmpRegenAdvance); 811 if (new_prefix) 812 prefix_delete(pr); 813 return (_B_TRUE); 814 } 815 } 816 if (debug & D_TMP) 817 logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, " 818 "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime); 819 820 if (!(pr->pr_state & PR_AUTO)) { 821 int i, tokenlen; 822 in6_addr_t *token; 823 /* 824 * Form a new local address if the lengths match. 825 */ 826 if (pr->pr_flags && IFF_TEMPORARY) { 827 RETRY_TOKEN: 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 struct sockaddr_in6 sin6; 888 sin6.sin6_family = AF_INET6; 889 sin6.sin6_addr = pr->pr_address; 890 if (do_dad(pi->pi_name, &sin6) != 0) { 891 /* DAD failed, need a new token */ 892 dadfails++; 893 logmsg(LOG_WARNING, 894 "incoming_prefix_addrconf_process: " 895 "deprecating temporary token %s\n", 896 inet_ntop(AF_INET6, 897 (void *)&pi->pi_tmp_token, abuf, 898 sizeof (abuf))); 899 tmptoken_delete(pi); 900 if (dadfails == MAX_DAD_FAILURES) { 901 logmsg(LOG_ERR, "Too many DAD " 902 "failures; disabling temporary " 903 "addresses on %s\n", pi->pi_name); 904 pi->pi_TmpAddrsEnabled = 0; 905 prefix_delete(pr); 906 return (_B_TRUE); 907 } 908 goto RETRY_TOKEN; 909 } 910 pr->pr_CreateTime = getcurrenttime() / MILLISEC; 911 if (debug & D_TMP) 912 logmsg(LOG_DEBUG, 913 "created tmp addr(%s v %d p %d)\n", 914 pr->pr_name, validtime, preftime); 915 } 916 } 917 918 if (validtime != 0) 919 pr->pr_state |= PR_AUTO; 920 else 921 pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 922 if (preftime != 0 || !(pr->pr_state & PR_AUTO)) 923 pr->pr_state &= ~PR_DEPRECATED; 924 else 925 pr->pr_state |= PR_DEPRECATED; 926 927 /* 928 * Convert from seconds to milliseconds avoiding overflow. 929 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 930 * (4 billion seconds - about 130 years) we will in fact time 931 * out the prefix after 4 billion milliseconds - 46 days). 932 * Thus the longest lifetime (apart from infinity) is 46 days. 933 * Note that this ensures that PREFIX_INFINITY still means "forever". 934 */ 935 if (validtime >= PREFIX_INFINITY / MILLISEC) 936 pr->pr_ValidLifetime = PREFIX_INFINITY - 1; 937 else 938 pr->pr_ValidLifetime = validtime * MILLISEC; 939 if (preftime >= PREFIX_INFINITY / MILLISEC) 940 pr->pr_PreferredLifetime = PREFIX_INFINITY - 1; 941 else 942 pr->pr_PreferredLifetime = preftime * MILLISEC; 943 pr->pr_AutonomousFlag = _B_TRUE; 944 945 if (debug & D_PREFIX) { 946 logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) " 947 "valid %u pref %u\n", 948 pr->pr_physical->pi_name, 949 inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 950 abuf, sizeof (abuf)), pr->pr_prefix_len, 951 pr->pr_ValidLifetime, pr->pr_PreferredLifetime); 952 } 953 954 if (pr->pr_state & PR_AUTO) { 955 /* Take the min of the two timeouts by calling it twice */ 956 if (pr->pr_ValidLifetime != 0) 957 timer_schedule(pr->pr_ValidLifetime); 958 if (pr->pr_PreferredLifetime != 0) 959 timer_schedule(pr->pr_PreferredLifetime); 960 } 961 if (pr->pr_kernel_state != pr->pr_state) { 962 /* Log a message when an addrconf prefix goes away */ 963 if ((pr->pr_kernel_state & PR_AUTO) && 964 !(pr->pr_state & PR_AUTO)) { 965 char abuf[INET6_ADDRSTRLEN]; 966 967 logmsg(LOG_WARNING, "Address removed due to zero " 968 "valid lifetime %s\n", 969 inet_ntop(AF_INET6, (void *)&pr->pr_address, 970 abuf, sizeof (abuf))); 971 } 972 prefix_update_k(pr); 973 } 974 return (_B_TRUE); 975 } 976 977 /* 978 * Process an MTU option received in a router advertisement. 979 */ 980 static void 981 incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 982 struct sockaddr_in6 *from) 983 { 984 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 985 struct lifreq lifr; 986 uint32_t mtu; 987 988 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 989 char abuf[INET6_ADDRSTRLEN]; 990 991 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 992 abuf, sizeof (abuf)); 993 logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 994 "(%d bytes)\n", 995 abuf, pi->pi_name, 996 8 * (int)mo->nd_opt_mtu_len); 997 return; 998 } 999 mtu = ntohl(mo->nd_opt_mtu_mtu); 1000 if (pi->pi_LinkMTU == mtu) 1001 return; /* No change */ 1002 if (mtu > pi->pi_mtu) { 1003 /* Can't exceed physical MTU */ 1004 char abuf[INET6_ADDRSTRLEN]; 1005 1006 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1007 abuf, sizeof (abuf)); 1008 logmsg(LOG_INFO, "mtu option from %s on %s too large " 1009 "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu); 1010 return; 1011 } 1012 if (mtu < IPV6_MIN_MTU) { 1013 char abuf[INET6_ADDRSTRLEN]; 1014 1015 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1016 abuf, sizeof (abuf)); 1017 logmsg(LOG_INFO, "mtu option from %s on %s too small " 1018 "MTU (%d)\n", abuf, pi->pi_name, mtu); 1019 return; 1020 } 1021 1022 pi->pi_LinkMTU = mtu; 1023 (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1024 lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1025 if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 1026 logperror_pi(pi, "incoming_mtu_opt: SIOCGLIFLNKINFO"); 1027 return; 1028 } 1029 lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU; 1030 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 1031 logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO"); 1032 return; 1033 } 1034 } 1035 1036 /* 1037 * Process a source link-layer address option received in a router 1038 * advertisement or solicitation. 1039 */ 1040 static void 1041 incoming_lla_opt(struct phyint *pi, uchar_t *opt, 1042 struct sockaddr_in6 *from, int isrouter) 1043 { 1044 struct nd_opt_lla *lo = (struct nd_opt_lla *)opt; 1045 struct lifreq lifr; 1046 struct sockaddr_in6 *sin6; 1047 int max_content_len; 1048 1049 if (pi->pi_hdw_addr_len == 0) 1050 return; 1051 1052 /* 1053 * Can't remove padding since it is link type specific. 1054 * However, we check against the length of our link-layer 1055 * address. 1056 * Note: assumes that all links have a fixed lengh address. 1057 */ 1058 max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr); 1059 if (max_content_len < pi->pi_hdw_addr_len || 1060 (max_content_len >= 8 && 1061 max_content_len - 7 > pi->pi_hdw_addr_len)) { 1062 char abuf[INET6_ADDRSTRLEN]; 1063 1064 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1065 abuf, sizeof (abuf)); 1066 logmsg(LOG_INFO, "lla option from %s on %s too long with bad " 1067 "physaddr length (%d vs. %d bytes)\n", 1068 abuf, pi->pi_name, 1069 max_content_len, pi->pi_hdw_addr_len); 1070 return; 1071 } 1072 1073 lifr.lifr_nd.lnr_hdw_len = pi->pi_hdw_addr_len; 1074 bcopy((char *)lo->nd_opt_lla_hdw_addr, 1075 (char *)lifr.lifr_nd.lnr_hdw_addr, 1076 lifr.lifr_nd.lnr_hdw_len); 1077 1078 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 1079 bzero(sin6, sizeof (struct sockaddr_in6)); 1080 sin6->sin6_family = AF_INET6; 1081 sin6->sin6_addr = from->sin6_addr; 1082 1083 /* 1084 * Set IsRouter flag if RA; clear if RS. 1085 */ 1086 lifr.lifr_nd.lnr_state_create = ND_STALE; 1087 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 1088 lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 1089 lifr.lifr_nd.lnr_flags = isrouter; 1090 (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1091 lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1092 if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) { 1093 logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND"); 1094 return; 1095 } 1096 } 1097 1098 /* 1099 * Verify the content of the received router advertisement against our 1100 * own configuration as specified in RFC 2461. 1101 */ 1102 static void 1103 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len, 1104 struct sockaddr_in6 *from) 1105 { 1106 char frombuf[INET6_ADDRSTRLEN]; 1107 struct nd_opt_hdr *opt; 1108 int optlen; 1109 uint_t reachable, retrans; 1110 boolean_t pktflag, myflag; 1111 1112 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1113 frombuf, sizeof (frombuf)); 1114 1115 if (ra->nd_ra_curhoplimit != 0 && 1116 pi->pi_AdvCurHopLimit != 0 && 1117 ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) { 1118 logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop " 1119 "limit:\n\treceived %d configuration %d\n", 1120 frombuf, pi->pi_name, 1121 ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit); 1122 } 1123 1124 reachable = ntohl(ra->nd_ra_reachable); 1125 if (reachable != 0 && pi->pi_AdvReachableTime != 0 && 1126 reachable != pi->pi_AdvReachableTime) { 1127 logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable " 1128 "time:\n\treceived %d configuration %d\n", 1129 frombuf, pi->pi_name, 1130 reachable, pi->pi_AdvReachableTime); 1131 } 1132 1133 retrans = ntohl(ra->nd_ra_retransmit); 1134 if (retrans != 0 && pi->pi_AdvRetransTimer != 0 && 1135 retrans != pi->pi_AdvRetransTimer) { 1136 logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit " 1137 "timer:\n\treceived %d configuration %d\n", 1138 frombuf, pi->pi_name, 1139 retrans, pi->pi_AdvRetransTimer); 1140 } 1141 1142 pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0); 1143 myflag = (pi->pi_AdvManagedFlag != 0); 1144 if (pktflag != myflag) { 1145 logmsg(LOG_INFO, "RA from %s on %s inconsistent managed " 1146 "flag:\n\treceived %s configuration %s\n", 1147 frombuf, pi->pi_name, 1148 (pktflag ? "ON" : "OFF"), 1149 (myflag ? "ON" : "OFF")); 1150 } 1151 pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0); 1152 myflag = (pi->pi_AdvOtherConfigFlag != 0); 1153 if (pktflag != myflag) { 1154 logmsg(LOG_INFO, "RA from %s on %s inconsistent other config " 1155 "flag:\n\treceived %s configuration %s\n", 1156 frombuf, pi->pi_name, 1157 (pktflag ? "ON" : "OFF"), 1158 (myflag ? "ON" : "OFF")); 1159 } 1160 1161 /* Process any options */ 1162 len -= sizeof (struct nd_router_advert); 1163 opt = (struct nd_opt_hdr *)&ra[1]; 1164 while (len >= sizeof (struct nd_opt_hdr)) { 1165 optlen = opt->nd_opt_len * 8; 1166 switch (opt->nd_opt_type) { 1167 case ND_OPT_PREFIX_INFORMATION: 1168 verify_prefix_opt(pi, (uchar_t *)opt, frombuf); 1169 break; 1170 case ND_OPT_MTU: 1171 verify_mtu_opt(pi, (uchar_t *)opt, frombuf); 1172 break; 1173 default: 1174 break; 1175 } 1176 opt = (struct nd_opt_hdr *)((char *)opt + optlen); 1177 len -= optlen; 1178 } 1179 } 1180 1181 /* 1182 * Verify that the lifetimes and onlink/auto flags are consistent 1183 * with our settings. 1184 */ 1185 static void 1186 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 1187 { 1188 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 1189 int plen; 1190 struct adv_prefix *adv_pr; 1191 uint32_t validtime, preftime; 1192 char prefixbuf[INET6_ADDRSTRLEN]; 1193 int pktflag, myflag; 1194 1195 if (8 * po->nd_opt_pi_len != sizeof (*po)) { 1196 logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size " 1197 "(%d bytes)\n", 1198 frombuf, pi->pi_name, 1199 8 * (int)po->nd_opt_pi_len); 1200 return; 1201 } 1202 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 1203 logmsg(LOG_INFO, "RA from %s on %s contains link-local " 1204 "prefix - ignored\n", 1205 frombuf, pi->pi_name); 1206 return; 1207 } 1208 plen = po->nd_opt_pi_prefix_len; 1209 adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen); 1210 if (adv_pr == NULL) 1211 return; 1212 1213 /* Ignore prefixes which we do not advertise */ 1214 if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag) 1215 return; 1216 (void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 1217 prefixbuf, sizeof (prefixbuf)); 1218 pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0); 1219 myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0); 1220 if (pktflag != myflag) { 1221 logmsg(LOG_INFO, 1222 "RA from %s on %s inconsistent autonumous flag for \n\t" 1223 "prefix %s/%u: received %s configuration %s\n", 1224 frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 1225 (pktflag ? "ON" : "OFF"), 1226 (myflag ? "ON" : "OFF")); 1227 } 1228 1229 pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0); 1230 myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0); 1231 if (pktflag != myflag) { 1232 logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag " 1233 "for \n\tprefix %s/%u: received %s configuration %s\n", 1234 frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 1235 (pktflag ? "ON" : "OFF"), 1236 (myflag ? "ON" : "OFF")); 1237 } 1238 validtime = ntohl(po->nd_opt_pi_valid_time); 1239 preftime = ntohl(po->nd_opt_pi_preferred_time); 1240 1241 /* 1242 * Take into account variation for lifetimes decrementing 1243 * in real time. Allow +/- 10 percent and +/- 10 seconds. 1244 */ 1245 #define LOWER_LIMIT(val) ((val) - (val)/10 - 10) 1246 #define UPPER_LIMIT(val) ((val) + (val)/10 + 10) 1247 if (adv_pr->adv_pr_AdvValidRealTime) { 1248 if (adv_pr->adv_pr_AdvValidExpiration > 0 && 1249 (validtime < 1250 LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) || 1251 validtime > 1252 UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) { 1253 logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 1254 "lifetime for\n\tprefix %s/%u: received %d " 1255 "configuration %d\n", 1256 frombuf, pi->pi_name, prefixbuf, 1257 adv_pr->adv_pr_prefix_len, 1258 validtime, adv_pr->adv_pr_AdvValidExpiration); 1259 } 1260 } else { 1261 if (validtime != adv_pr->adv_pr_AdvValidLifetime) { 1262 logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 1263 "lifetime for\n\tprefix %s/%u: received %d " 1264 "configuration %d\n", 1265 frombuf, pi->pi_name, prefixbuf, 1266 adv_pr->adv_pr_prefix_len, 1267 validtime, adv_pr->adv_pr_AdvValidLifetime); 1268 } 1269 } 1270 1271 if (adv_pr->adv_pr_AdvPreferredRealTime) { 1272 if (adv_pr->adv_pr_AdvPreferredExpiration > 0 && 1273 (preftime < 1274 LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) || 1275 preftime > 1276 UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) { 1277 logmsg(LOG_INFO, "RA from %s on %s inconsistent " 1278 "preferred lifetime for\n\tprefix %s/%u: " 1279 "received %d configuration %d\n", 1280 frombuf, pi->pi_name, prefixbuf, 1281 adv_pr->adv_pr_prefix_len, 1282 preftime, adv_pr->adv_pr_AdvPreferredExpiration); 1283 } 1284 } else { 1285 if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) { 1286 logmsg(LOG_INFO, "RA from %s on %s inconsistent " 1287 "preferred lifetime for\n\tprefix %s/%u: " 1288 "received %d configuration %d\n", 1289 frombuf, pi->pi_name, prefixbuf, 1290 adv_pr->adv_pr_prefix_len, 1291 preftime, adv_pr->adv_pr_AdvPreferredLifetime); 1292 } 1293 } 1294 } 1295 1296 /* 1297 * Verify the received MTU against our own configuration. 1298 */ 1299 static void 1300 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 1301 { 1302 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 1303 uint32_t mtu; 1304 1305 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 1306 logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 1307 "(%d bytes)\n", 1308 frombuf, pi->pi_name, 1309 8 * (int)mo->nd_opt_mtu_len); 1310 return; 1311 } 1312 mtu = ntohl(mo->nd_opt_mtu_mtu); 1313 if (pi->pi_AdvLinkMTU != 0 && 1314 pi->pi_AdvLinkMTU != mtu) { 1315 logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: " 1316 "received %d configuration %d\n", 1317 frombuf, pi->pi_name, 1318 mtu, pi->pi_AdvLinkMTU); 1319 } 1320 } 1321 1322 /* 1323 * Verify that all options have a non-zero length and that 1324 * the options fit within the total length of the packet (optlen). 1325 */ 1326 static boolean_t 1327 verify_opt_len(struct nd_opt_hdr *opt, int optlen, 1328 struct phyint *pi, struct sockaddr_in6 *from) 1329 { 1330 while (optlen > 0) { 1331 if (opt->nd_opt_len == 0) { 1332 char abuf[INET6_ADDRSTRLEN]; 1333 1334 (void) inet_ntop(AF_INET6, 1335 (void *)&from->sin6_addr, 1336 abuf, sizeof (abuf)); 1337 1338 logmsg(LOG_INFO, "Zero length option type 0x%x " 1339 "from %s on %s\n", 1340 opt->nd_opt_type, abuf, pi->pi_name); 1341 return (_B_FALSE); 1342 } 1343 optlen -= 8 * opt->nd_opt_len; 1344 if (optlen < 0) { 1345 char abuf[INET6_ADDRSTRLEN]; 1346 1347 (void) inet_ntop(AF_INET6, 1348 (void *)&from->sin6_addr, 1349 abuf, sizeof (abuf)); 1350 1351 logmsg(LOG_INFO, "Too large option: type 0x%x len %u " 1352 "from %s on %s\n", 1353 opt->nd_opt_type, opt->nd_opt_len, 1354 abuf, pi->pi_name); 1355 return (_B_FALSE); 1356 } 1357 opt = (struct nd_opt_hdr *)((char *)opt + 1358 8 * opt->nd_opt_len); 1359 } 1360 return (_B_TRUE); 1361 } 1362 1363 /* 1364 * Update IsRouter Flag for Host turning into a router or vice-versa. 1365 */ 1366 static void 1367 update_ra_flag(struct phyint *pi, const struct sockaddr_in6 *from, int isrouter) 1368 { 1369 struct lifreq lifr; 1370 char abuf[INET6_ADDRSTRLEN]; 1371 struct sockaddr_in6 *sin6; 1372 1373 /* check if valid flag is being set */ 1374 if ((isrouter != NDF_ISROUTER_ON) && 1375 (isrouter != NDF_ISROUTER_OFF)) { 1376 logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter " 1377 "flag %d\n", isrouter); 1378 return; 1379 } 1380 1381 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 1382 bzero(sin6, sizeof (*sin6)); 1383 sin6->sin6_family = AF_INET6; 1384 sin6->sin6_addr = from->sin6_addr; 1385 1386 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1387 1388 if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) { 1389 logperror_pi(pi, "update_ra_flag: SIOCLIFGETND"); 1390 } else { 1391 /* 1392 * The lif_nd_req structure has three state values to be used 1393 * when changing/updating nces : 1394 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla. 1395 * 1396 * In this case, we're updating an nce, without changing lla; 1397 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that 1398 * nce's state should not be affected by our flag change. 1399 * 1400 * The kernel implementation also expects the lnr_state_create 1401 * field be always set, before processing ioctl request for NCE 1402 * update. 1403 * We use the state as STALE, while addressing the possibility 1404 * of NCE deletion when ioctl with SIOCLIFGETND argument 1405 * in earlier step is returned - further in such case we don't 1406 * want to re-create the entry in the reachable state. 1407 */ 1408 lifr.lifr_nd.lnr_state_create = ND_STALE; 1409 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 1410 lifr.lifr_nd.lnr_flags = isrouter; 1411 if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) { 1412 logperror_pi(pi, "update_ra_flag: SIOCLIFSETND"); 1413 } else { 1414 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1415 abuf, sizeof (abuf)); 1416 logmsg(LOG_INFO, "update_ra_flag: IsRouter flag " 1417 "updated for %s\n", abuf); 1418 } 1419 } 1420 } 1421