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