17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 59ba4fd8dSrshoaib * Common Development and Distribution License (the "License"). 69ba4fd8dSrshoaib * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 219ba4fd8dSrshoaib 227c478bd9Sstevel@tonic-gate /* 239ba4fd8dSrshoaib * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include "defs.h" 307c478bd9Sstevel@tonic-gate #include "tables.h" 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen, 357c478bd9Sstevel@tonic-gate struct phyint *pi, struct sockaddr_in6 *from); 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate static void incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, 387c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from); 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate void incoming_ra(struct phyint *pi, struct nd_router_advert *ra, 417c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from, boolean_t loopback); 427c478bd9Sstevel@tonic-gate static void incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 437c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback); 447c478bd9Sstevel@tonic-gate static void incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 457c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback); 467c478bd9Sstevel@tonic-gate void incoming_prefix_onlink_process(struct prefix *pr, 477c478bd9Sstevel@tonic-gate uchar_t *opt); 487c478bd9Sstevel@tonic-gate static boolean_t incoming_prefix_addrconf(struct phyint *pi, 497c478bd9Sstevel@tonic-gate uchar_t *opt, struct sockaddr_in6 *from, 507c478bd9Sstevel@tonic-gate boolean_t loopback); 517c478bd9Sstevel@tonic-gate boolean_t incoming_prefix_addrconf_process(struct phyint *pi, 527c478bd9Sstevel@tonic-gate struct prefix *pr, uchar_t *opt, 537c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback, 547c478bd9Sstevel@tonic-gate boolean_t new_prefix); 557c478bd9Sstevel@tonic-gate static void incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 567c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from); 577c478bd9Sstevel@tonic-gate static void incoming_lla_opt(struct phyint *pi, uchar_t *opt, 587c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, int isrouter); 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static void verify_ra_consistency(struct phyint *pi, 617c478bd9Sstevel@tonic-gate struct nd_router_advert *ra, 627c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from); 637c478bd9Sstevel@tonic-gate static void verify_prefix_opt(struct phyint *pi, uchar_t *opt, 647c478bd9Sstevel@tonic-gate char *frombuf); 657c478bd9Sstevel@tonic-gate static void verify_mtu_opt(struct phyint *pi, uchar_t *opt, 667c478bd9Sstevel@tonic-gate char *frombuf); 677c478bd9Sstevel@tonic-gate 68*b0f490f4Smh static void update_ra_flag(const struct phyint *pi, 696b27086dSdd const struct sockaddr_in6 *from, int isrouter); 706b27086dSdd 717c478bd9Sstevel@tonic-gate static uint_t ra_flags; /* Global to detect when to trigger DHCP */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Return a pointer to the specified option buffer. 757c478bd9Sstevel@tonic-gate * If not found return NULL. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate static void * 787c478bd9Sstevel@tonic-gate find_ancillary(struct msghdr *msg, int cmsg_type) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 837c478bd9Sstevel@tonic-gate cmsg = CMSG_NXTHDR(msg, cmsg)) { 847c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == IPPROTO_IPV6 && 857c478bd9Sstevel@tonic-gate cmsg->cmsg_type == cmsg_type) { 867c478bd9Sstevel@tonic-gate return (CMSG_DATA(cmsg)); 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate return (NULL); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate void 937c478bd9Sstevel@tonic-gate in_data(struct phyint *pi) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate struct sockaddr_in6 from; 967c478bd9Sstevel@tonic-gate struct icmp6_hdr *icmp; 977c478bd9Sstevel@tonic-gate struct nd_router_solicit *rs; 987c478bd9Sstevel@tonic-gate struct nd_router_advert *ra; 997c478bd9Sstevel@tonic-gate static uint64_t in_packet[(IP_MAXPACKET + 1)/8]; 1007c478bd9Sstevel@tonic-gate static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8]; 1017c478bd9Sstevel@tonic-gate int len; 1027c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1037c478bd9Sstevel@tonic-gate const char *msgbuf; 1047c478bd9Sstevel@tonic-gate struct msghdr msg; 1057c478bd9Sstevel@tonic-gate struct iovec iov; 1067c478bd9Sstevel@tonic-gate uchar_t *opt; 1077c478bd9Sstevel@tonic-gate uint_t hoplimit; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate iov.iov_base = (char *)in_packet; 1107c478bd9Sstevel@tonic-gate iov.iov_len = sizeof (in_packet); 1117c478bd9Sstevel@tonic-gate msg.msg_iov = &iov; 1127c478bd9Sstevel@tonic-gate msg.msg_iovlen = 1; 1137c478bd9Sstevel@tonic-gate msg.msg_name = (struct sockaddr *)&from; 1147c478bd9Sstevel@tonic-gate msg.msg_namelen = sizeof (from); 1157c478bd9Sstevel@tonic-gate msg.msg_control = ancillary_data; 1167c478bd9Sstevel@tonic-gate msg.msg_controllen = sizeof (ancillary_data); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) { 1197c478bd9Sstevel@tonic-gate logperror_pi(pi, "in_data: recvfrom"); 1207c478bd9Sstevel@tonic-gate return; 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate if (len == 0) 1237c478bd9Sstevel@tonic-gate return; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&from.sin6_addr, 1267c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)) == NULL) 1277c478bd9Sstevel@tonic-gate msgbuf = "Unspecified Router"; 1287c478bd9Sstevel@tonic-gate else 1297c478bd9Sstevel@tonic-gate msgbuf = abuf; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* Ignore packets > 64k or control buffers that don't fit */ 1327c478bd9Sstevel@tonic-gate if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 1337c478bd9Sstevel@tonic-gate if (debug & D_PKTBAD) { 1347c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x " 1357c478bd9Sstevel@tonic-gate "from %s\n", msg.msg_flags, msgbuf); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate return; 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate icmp = (struct icmp6_hdr *)in_packet; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (len < ICMP6_MINLEN) { 1437c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Too short ICMP packet: %d bytes " 1447c478bd9Sstevel@tonic-gate "from %s on %s\n", 1457c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 1467c478bd9Sstevel@tonic-gate return; 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate opt = find_ancillary(&msg, IPV6_HOPLIMIT); 1507c478bd9Sstevel@tonic-gate if (opt == NULL) { 1517c478bd9Sstevel@tonic-gate /* Unknown hoplimit - must drop */ 1527c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n", 1537c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 1547c478bd9Sstevel@tonic-gate return; 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate hoplimit = *(uint_t *)opt; 1577c478bd9Sstevel@tonic-gate opt = find_ancillary(&msg, IPV6_RTHDR); 1587c478bd9Sstevel@tonic-gate if (opt != NULL) { 1597c478bd9Sstevel@tonic-gate /* Can't allow routing headers in ND messages */ 1607c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "ND message with routing header " 1617c478bd9Sstevel@tonic-gate "from %s on %s\n", 1627c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 1637c478bd9Sstevel@tonic-gate return; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate switch (icmp->icmp6_type) { 1667c478bd9Sstevel@tonic-gate case ND_ROUTER_SOLICIT: 1677c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 1687c478bd9Sstevel@tonic-gate return; 1697c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 1707c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 1717c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Ignore received RS packet " 1727c478bd9Sstevel@tonic-gate "on %s (no route exchange on interface)\n", 1737c478bd9Sstevel@tonic-gate pi->pi_name); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate return; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * Assumes that the kernel has verified the AH (if present) 1807c478bd9Sstevel@tonic-gate * and the ICMP checksum. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate if (hoplimit != IPV6_MAX_HOPS) { 1839ba4fd8dSrshoaib logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n", 1847c478bd9Sstevel@tonic-gate hoplimit, msgbuf, pi->pi_name); 1857c478bd9Sstevel@tonic-gate return; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (icmp->icmp6_code != 0) { 1897c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS code: %d from %s on %s\n", 1907c478bd9Sstevel@tonic-gate icmp->icmp6_code, msgbuf, pi->pi_name); 1917c478bd9Sstevel@tonic-gate return; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (len < sizeof (struct nd_router_solicit)) { 1957c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS too short: %d bytes " 1967c478bd9Sstevel@tonic-gate "from %s on %s\n", 1977c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 1987c478bd9Sstevel@tonic-gate return; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate rs = (struct nd_router_solicit *)icmp; 2017c478bd9Sstevel@tonic-gate if (len > sizeof (struct nd_router_solicit)) { 2027c478bd9Sstevel@tonic-gate if (!verify_opt_len((struct nd_opt_hdr *)&rs[1], 2037c478bd9Sstevel@tonic-gate len - sizeof (struct nd_router_solicit), pi, &from)) 2047c478bd9Sstevel@tonic-gate return; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 2077c478bd9Sstevel@tonic-gate print_route_sol("Received valid solicit from ", pi, 2087c478bd9Sstevel@tonic-gate rs, len, &from); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate incoming_rs(pi, rs, len, &from); 2117c478bd9Sstevel@tonic-gate break; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate case ND_ROUTER_ADVERT: 2147c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) { 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Router advt. must have address! 2177c478bd9Sstevel@tonic-gate * Logging the news and returning. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 2207c478bd9Sstevel@tonic-gate "Router's address unspecified in advertisement\n"); 2217c478bd9Sstevel@tonic-gate return; 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 2247c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 2257c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Ignore received RA packet " 2267c478bd9Sstevel@tonic-gate "on %s (no route exchange on interface)\n", 2277c478bd9Sstevel@tonic-gate pi->pi_name); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate return; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* 2337c478bd9Sstevel@tonic-gate * Assumes that the kernel has verified the AH (if present) 2347c478bd9Sstevel@tonic-gate * and the ICMP checksum. 2357c478bd9Sstevel@tonic-gate */ 2367c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 2379ba4fd8dSrshoaib logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n", 2387c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 2397c478bd9Sstevel@tonic-gate return; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if (hoplimit != IPV6_MAX_HOPS) { 2437c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n", 2447c478bd9Sstevel@tonic-gate hoplimit, msgbuf, pi->pi_name); 2457c478bd9Sstevel@tonic-gate return; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (icmp->icmp6_code != 0) { 2497c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA code: %d from %s on %s\n", 2507c478bd9Sstevel@tonic-gate icmp->icmp6_code, msgbuf, pi->pi_name); 2517c478bd9Sstevel@tonic-gate return; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (len < sizeof (struct nd_router_advert)) { 2557c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA too short: %d bytes " 2567c478bd9Sstevel@tonic-gate "from %s on %s\n", 2577c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 2587c478bd9Sstevel@tonic-gate return; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate ra = (struct nd_router_advert *)icmp; 2617c478bd9Sstevel@tonic-gate if (len > sizeof (struct nd_router_advert)) { 2627c478bd9Sstevel@tonic-gate if (!verify_opt_len((struct nd_opt_hdr *)&ra[1], 2637c478bd9Sstevel@tonic-gate len - sizeof (struct nd_router_advert), pi, &from)) 2647c478bd9Sstevel@tonic-gate return; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 2677c478bd9Sstevel@tonic-gate print_route_adv("Received valid advert from ", pi, 2687c478bd9Sstevel@tonic-gate ra, len, &from); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 2717c478bd9Sstevel@tonic-gate verify_ra_consistency(pi, ra, len, &from); 2727c478bd9Sstevel@tonic-gate else 2737c478bd9Sstevel@tonic-gate incoming_ra(pi, ra, len, &from, _B_FALSE); 2747c478bd9Sstevel@tonic-gate break; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Process a received router solicitation. 2807c478bd9Sstevel@tonic-gate * Check for source link-layer address option and check if it 2817c478bd9Sstevel@tonic-gate * is time to advertise. 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate static void 2847c478bd9Sstevel@tonic-gate incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len, 2857c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 2887c478bd9Sstevel@tonic-gate int optlen; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* Process any options */ 2917c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_solicit); 2927c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&rs[1]; 2937c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 2947c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 2957c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 2967c478bd9Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 2977c478bd9Sstevel@tonic-gate incoming_lla_opt(pi, (uchar_t *)opt, 2987c478bd9Sstevel@tonic-gate from, NDF_ISROUTER_OFF); 2997c478bd9Sstevel@tonic-gate break; 3007c478bd9Sstevel@tonic-gate default: 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 3047c478bd9Sstevel@tonic-gate len -= optlen; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate /* Simple algorithm: treat unicast and multicast RSs the same */ 3077c478bd9Sstevel@tonic-gate check_to_advertise(pi, RECEIVED_SOLICIT); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Process a received router advertisement. 3127c478bd9Sstevel@tonic-gate * Called both when packets arrive as well as when we send RAs. 3137c478bd9Sstevel@tonic-gate * In the latter case 'loopback' is set. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate void 3167c478bd9Sstevel@tonic-gate incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len, 3177c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 3187c478bd9Sstevel@tonic-gate { 3197c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 3207c478bd9Sstevel@tonic-gate int optlen; 3217c478bd9Sstevel@tonic-gate struct lifreq lifr; 3227c478bd9Sstevel@tonic-gate boolean_t set_needed = _B_FALSE; 3237c478bd9Sstevel@tonic-gate struct router *dr; 3247c478bd9Sstevel@tonic-gate uint16_t router_lifetime; 3257c478bd9Sstevel@tonic-gate uint_t reachable, retrans; 3267c478bd9Sstevel@tonic-gate boolean_t reachable_time_changed = _B_FALSE; 3276b27086dSdd boolean_t slla_opt_present = _B_FALSE; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (no_loopback && loopback) 3307c478bd9Sstevel@tonic-gate return; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * If the interface is FAILED or INACTIVE or OFFLINE, don't 3347c478bd9Sstevel@tonic-gate * create any addresses on them. in.mpathd assumes that no new 3357c478bd9Sstevel@tonic-gate * addresses will appear on these. This implies that we 3367c478bd9Sstevel@tonic-gate * won't create any new prefixes advertised by the router 3377c478bd9Sstevel@tonic-gate * on FAILED/INACTIVE/OFFLINE interfaces. When the state changes, 3387c478bd9Sstevel@tonic-gate * the next RA will create the prefix on this interface. 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate if (pi->pi_flags & (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) 3417c478bd9Sstevel@tonic-gate return; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 3447c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 3457c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 3467c478bd9Sstevel@tonic-gate if (errno == ENXIO) 3477c478bd9Sstevel@tonic-gate return; 3487c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_ra: SIOCGLIFLNKINFO"); 3497c478bd9Sstevel@tonic-gate return; 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate if (ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) { 3527c478bd9Sstevel@tonic-gate pi->pi_CurHopLimit = ra->nd_ra_curhoplimit; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 3557c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate reachable = ntohl(ra->nd_ra_reachable); 3597c478bd9Sstevel@tonic-gate if (reachable != 0 && 3607c478bd9Sstevel@tonic-gate reachable != pi->pi_BaseReachableTime) { 3617c478bd9Sstevel@tonic-gate pi->pi_BaseReachableTime = reachable; 3627c478bd9Sstevel@tonic-gate reachable_time_changed = _B_TRUE; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL || 3667c478bd9Sstevel@tonic-gate reachable_time_changed) { 3677c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_FALSE); 3687c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate retrans = ntohl(ra->nd_ra_retransmit); 3737c478bd9Sstevel@tonic-gate if (retrans != 0 && 3747c478bd9Sstevel@tonic-gate pi->pi_RetransTimer != retrans) { 3757c478bd9Sstevel@tonic-gate pi->pi_RetransTimer = retrans; 3767c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 3777c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (set_needed) { 3817c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 3827c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO"); 3837c478bd9Sstevel@tonic-gate return; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && 3887c478bd9Sstevel@tonic-gate !(ra_flags & ND_RA_FLAG_MANAGED)) { 3897c478bd9Sstevel@tonic-gate ra_flags |= ND_RA_FLAG_MANAGED; 3907c478bd9Sstevel@tonic-gate /* TODO trigger dhcpv6 */ 3919ba4fd8dSrshoaib logmsg(LOG_DEBUG, "incoming_ra: trigger dhcp MANAGED\n"); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && 3947c478bd9Sstevel@tonic-gate !(ra_flags & ND_RA_FLAG_OTHER)) { 3957c478bd9Sstevel@tonic-gate ra_flags |= ND_RA_FLAG_OTHER; 3967c478bd9Sstevel@tonic-gate if (!(ra_flags & ND_RA_FLAG_MANAGED)) { 3977c478bd9Sstevel@tonic-gate /* TODO trigger dhcpv6 for non-address info */ 3989ba4fd8dSrshoaib logmsg(LOG_DEBUG, "incoming_ra: trigger dhcp OTHER\n"); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate /* Skip default router code if sent from ourselves */ 4027c478bd9Sstevel@tonic-gate if (!loopback) { 4037c478bd9Sstevel@tonic-gate /* Find and update or add default router in list */ 4047c478bd9Sstevel@tonic-gate dr = router_lookup(pi, from->sin6_addr); 4057c478bd9Sstevel@tonic-gate router_lifetime = ntohs(ra->nd_ra_router_lifetime); 4067c478bd9Sstevel@tonic-gate if (dr == NULL) { 4077c478bd9Sstevel@tonic-gate if (router_lifetime != 0) { 4087c478bd9Sstevel@tonic-gate dr = router_create(pi, from->sin6_addr, 4097c478bd9Sstevel@tonic-gate MILLISEC * router_lifetime); 4107c478bd9Sstevel@tonic-gate timer_schedule(dr->dr_lifetime); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate } else { 4137c478bd9Sstevel@tonic-gate dr->dr_lifetime = MILLISEC * router_lifetime; 4147c478bd9Sstevel@tonic-gate if (dr->dr_lifetime != 0) 4157c478bd9Sstevel@tonic-gate timer_schedule(dr->dr_lifetime); 4167c478bd9Sstevel@tonic-gate if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) || 4177c478bd9Sstevel@tonic-gate (dr->dr_lifetime == 0 && dr->dr_inkernel)) 4187c478bd9Sstevel@tonic-gate router_update_k(dr); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate /* Process any options */ 4227c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_advert); 4237c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&ra[1]; 4247c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 4257c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 4267c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 4277c478bd9Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: 4287c478bd9Sstevel@tonic-gate incoming_prefix_opt(pi, (uchar_t *)opt, from, 4297c478bd9Sstevel@tonic-gate loopback); 4307c478bd9Sstevel@tonic-gate break; 4317c478bd9Sstevel@tonic-gate case ND_OPT_MTU: 4327c478bd9Sstevel@tonic-gate incoming_mtu_opt(pi, (uchar_t *)opt, from); 4337c478bd9Sstevel@tonic-gate break; 4347c478bd9Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 4357c478bd9Sstevel@tonic-gate /* skip lla option if sent from ourselves! */ 4367c478bd9Sstevel@tonic-gate if (!loopback) { 4377c478bd9Sstevel@tonic-gate incoming_lla_opt(pi, (uchar_t *)opt, 4387c478bd9Sstevel@tonic-gate from, NDF_ISROUTER_ON); 4396b27086dSdd slla_opt_present = _B_TRUE; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate break; 4427c478bd9Sstevel@tonic-gate default: 4437c478bd9Sstevel@tonic-gate break; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 4467c478bd9Sstevel@tonic-gate len -= optlen; 4477c478bd9Sstevel@tonic-gate } 448*b0f490f4Smh if (!loopback && !slla_opt_present) 4496b27086dSdd update_ra_flag(pi, from, NDF_ISROUTER_ON); 4507c478bd9Sstevel@tonic-gate /* Stop sending solicitations */ 4517c478bd9Sstevel@tonic-gate check_to_solicit(pi, SOLICIT_DONE); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Process a received prefix option. 4567c478bd9Sstevel@tonic-gate * Unless addrconf is turned off we process both the addrconf and the 4577c478bd9Sstevel@tonic-gate * onlink aspects of the prefix option. 4587c478bd9Sstevel@tonic-gate * 4597c478bd9Sstevel@tonic-gate * Note that when a flag (onlink or auto) is turned off we do nothing - 4607c478bd9Sstevel@tonic-gate * the prefix will time out. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate static void 4637c478bd9Sstevel@tonic-gate incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 4647c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 4657c478bd9Sstevel@tonic-gate { 4667c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 4677c478bd9Sstevel@tonic-gate boolean_t good_prefix = _B_TRUE; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (8 * po->nd_opt_pi_len != sizeof (*po)) { 4707c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 4737c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 4747c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option from %s on %s wrong size " 4757c478bd9Sstevel@tonic-gate "(%d bytes)\n", 4767c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 4777c478bd9Sstevel@tonic-gate 8 * (int)po->nd_opt_pi_len); 4787c478bd9Sstevel@tonic-gate return; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 4817c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 4847c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 4857c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix " 4867c478bd9Sstevel@tonic-gate "- ignored\n", 4877c478bd9Sstevel@tonic-gate abuf, pi->pi_name); 4887c478bd9Sstevel@tonic-gate return; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && 4917c478bd9Sstevel@tonic-gate pi->pi_StatelessAddrConf) { 4927c478bd9Sstevel@tonic-gate good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && 4957c478bd9Sstevel@tonic-gate good_prefix) { 4967c478bd9Sstevel@tonic-gate incoming_prefix_onlink(pi, opt, from, loopback); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Process prefix options with the onlink flag set. 5027c478bd9Sstevel@tonic-gate * 5037c478bd9Sstevel@tonic-gate * If there are no routers ndpd will add an onlink 5047c478bd9Sstevel@tonic-gate * default route which will allow communication 5057c478bd9Sstevel@tonic-gate * between neighbors. 5067c478bd9Sstevel@tonic-gate * 5077c478bd9Sstevel@tonic-gate * This function needs to loop to find the same prefix multiple times 5087c478bd9Sstevel@tonic-gate * as if a failover happened earlier, the addresses belonging to 5097c478bd9Sstevel@tonic-gate * a different interface may be found here on this interface. 5107c478bd9Sstevel@tonic-gate */ 5117c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 5127c478bd9Sstevel@tonic-gate static void 5137c478bd9Sstevel@tonic-gate incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 5147c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 5177c478bd9Sstevel@tonic-gate int plen; 5187c478bd9Sstevel@tonic-gate struct prefix *pr; 5197c478bd9Sstevel@tonic-gate uint32_t validtime; /* Without 2 hour rule */ 5207c478bd9Sstevel@tonic-gate boolean_t found_one = _B_FALSE; 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 5237c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 5247c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == plen && 5257c478bd9Sstevel@tonic-gate prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 5267c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 5277c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 5287c478bd9Sstevel@tonic-gate continue; 5297c478bd9Sstevel@tonic-gate found_one = _B_TRUE; 5307c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(pr, opt); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * If we have found a matching prefix already or validtime 5377c478bd9Sstevel@tonic-gate * is zero, we have nothing to do. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate if (validtime == 0 || found_one) 5407c478bd9Sstevel@tonic-gate return; 5417c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 5427c478bd9Sstevel@tonic-gate if (pr == NULL) 5437c478bd9Sstevel@tonic-gate return; 5447c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(pr, opt); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate void 5487c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 5517c478bd9Sstevel@tonic-gate uint32_t validtime; /* Without 2 hour rule */ 5527c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 5557c478bd9Sstevel@tonic-gate if (validtime != 0) 5567c478bd9Sstevel@tonic-gate pr->pr_state |= PR_ONLINK; 5577c478bd9Sstevel@tonic-gate else 5587c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_ONLINK; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * Convert from seconds to milliseconds avoiding overflow. 5627c478bd9Sstevel@tonic-gate * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 5637c478bd9Sstevel@tonic-gate * (4 billion seconds - about 130 years) we will in fact time 5647c478bd9Sstevel@tonic-gate * out the prefix after 4 billion milliseconds - 46 days). 5657c478bd9Sstevel@tonic-gate * Thus the longest lifetime (apart from infinity) is 46 days. 5667c478bd9Sstevel@tonic-gate * Note that this ensures that PREFIX_INFINITY still means "forever". 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 5697c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = pr->pr_ValidLifetime; 5707c478bd9Sstevel@tonic-gate } else { 5717c478bd9Sstevel@tonic-gate if (validtime >= PREFIX_INFINITY / MILLISEC) 5727c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1; 5737c478bd9Sstevel@tonic-gate else 5747c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = validtime * MILLISEC; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate pr->pr_OnLinkFlag = _B_TRUE; 5777c478bd9Sstevel@tonic-gate if (debug & (D_PREFIX|D_TMP)) { 5787c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) " 5797c478bd9Sstevel@tonic-gate "onlink %u state 0x%x, kstate 0x%x\n", 5807c478bd9Sstevel@tonic-gate pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 5817c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 5827c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) { 5867c478bd9Sstevel@tonic-gate prefix_update_k(pr); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime != 0) 5907c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_OnLinkLifetime); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Process prefix options with the autonomous flag set. 5957c478bd9Sstevel@tonic-gate * Returns false if this prefix results in a bad address (duplicate) 5967c478bd9Sstevel@tonic-gate * This function needs to loop to find the same prefix multiple times 5977c478bd9Sstevel@tonic-gate * as if a failover happened earlier, the addresses belonging to 5987c478bd9Sstevel@tonic-gate * a different interface may be found here on this interface. 5997c478bd9Sstevel@tonic-gate */ 6007c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 6017c478bd9Sstevel@tonic-gate static boolean_t 6027c478bd9Sstevel@tonic-gate incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt, 6037c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 6047c478bd9Sstevel@tonic-gate { 6057c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 6067c478bd9Sstevel@tonic-gate int plen; 6077c478bd9Sstevel@tonic-gate struct prefix *pr; 6087c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; /* In seconds */ 6097c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 6107c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 6117c478bd9Sstevel@tonic-gate boolean_t found_pub = _B_FALSE; 6127c478bd9Sstevel@tonic-gate boolean_t found_tmp = _B_FALSE; 6137c478bd9Sstevel@tonic-gate boolean_t ret; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 6167c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 6177c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* Sanity checks */ 6207c478bd9Sstevel@tonic-gate if (validtime < preftime) { 6217c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 6227c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 6237c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 6247c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 6257c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 6267c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: " 6277c478bd9Sstevel@tonic-gate "valid %u < pref %u ignored\n", 6287c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 6297c478bd9Sstevel@tonic-gate validtime, preftime); 6307c478bd9Sstevel@tonic-gate return (_B_FALSE); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 6347c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == plen && 6357c478bd9Sstevel@tonic-gate prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 6387c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 6397c478bd9Sstevel@tonic-gate continue; 6407c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * If this address is deprecated and its token 6437c478bd9Sstevel@tonic-gate * doesn't match the current tmp token, we want 6447c478bd9Sstevel@tonic-gate * to create a new address with the current 6457c478bd9Sstevel@tonic-gate * token. So don't count this addr as a match. 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate if (!((pr->pr_flags & IFF_DEPRECATED) && 6487c478bd9Sstevel@tonic-gate !token_equal(pi->pi_tmp_token, 6497c478bd9Sstevel@tonic-gate pr->pr_address, TMP_TOKEN_BITS))) 6507c478bd9Sstevel@tonic-gate found_tmp = _B_TRUE; 6517c478bd9Sstevel@tonic-gate } else { 6527c478bd9Sstevel@tonic-gate found_pub = _B_TRUE; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate (void) incoming_prefix_addrconf_process(pi, pr, opt, 6557c478bd9Sstevel@tonic-gate from, loopback, _B_FALSE); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * If we have found a matching prefix (for public and, if temp addrs 6617c478bd9Sstevel@tonic-gate * are enabled, for temporary) already or validtime is zero, we have 6627c478bd9Sstevel@tonic-gate * nothing to do. 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate if (validtime == 0 || 6657c478bd9Sstevel@tonic-gate (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp))) 6667c478bd9Sstevel@tonic-gate return (_B_TRUE); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate if (!found_pub) { 6697c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 6707c478bd9Sstevel@tonic-gate if (pr == NULL) 6717c478bd9Sstevel@tonic-gate return (_B_TRUE); 6727c478bd9Sstevel@tonic-gate ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 6737c478bd9Sstevel@tonic-gate loopback, _B_TRUE); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate /* 6767c478bd9Sstevel@tonic-gate * if processing of the public address failed, 6777c478bd9Sstevel@tonic-gate * don't bother with the temporary address. 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate if (ret == _B_FALSE) 6807c478bd9Sstevel@tonic-gate return (_B_FALSE); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled && !found_tmp) { 6837c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 6847c478bd9Sstevel@tonic-gate IFF_TEMPORARY); 6857c478bd9Sstevel@tonic-gate if (pr == NULL) 6867c478bd9Sstevel@tonic-gate return (_B_TRUE); 6877c478bd9Sstevel@tonic-gate ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 6887c478bd9Sstevel@tonic-gate loopback, _B_TRUE); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate return (ret); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate boolean_t 6957c478bd9Sstevel@tonic-gate incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr, 6967c478bd9Sstevel@tonic-gate uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback, 6977c478bd9Sstevel@tonic-gate boolean_t new_prefix) 6987c478bd9Sstevel@tonic-gate { 6997c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 7007c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 7017c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 7027c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; /* In seconds */ 7037c478bd9Sstevel@tonic-gate uint32_t recorded_validtime; /* In seconds */ 7047c478bd9Sstevel@tonic-gate int plen, dadfails = 0; 7057c478bd9Sstevel@tonic-gate struct prefix *other_pr; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 7087c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 7097c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 7107c478bd9Sstevel@tonic-gate if (!new_prefix) { 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * Check 2 hour rule on valid lifetime. 7137c478bd9Sstevel@tonic-gate * Follows: RFC 2462 7147c478bd9Sstevel@tonic-gate * If we advertised this prefix ourselves we skip 7157c478bd9Sstevel@tonic-gate * these checks. They are also skipped if we did not 7167c478bd9Sstevel@tonic-gate * previously do addrconf on this prefix. 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate recorded_validtime = pr->pr_ValidLifetime / MILLISEC; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate if (loopback || !(pr->pr_state & PR_AUTO) || 7217c478bd9Sstevel@tonic-gate validtime >= MIN_VALID_LIFETIME || 7227c478bd9Sstevel@tonic-gate /* LINTED - statement has no consequent */ 7237c478bd9Sstevel@tonic-gate validtime >= recorded_validtime) { 7247c478bd9Sstevel@tonic-gate /* OK */ 7257c478bd9Sstevel@tonic-gate } else if (recorded_validtime < MIN_VALID_LIFETIME && 7267c478bd9Sstevel@tonic-gate validtime < recorded_validtime) { 7277c478bd9Sstevel@tonic-gate /* Ignore the prefix */ 7287c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 7297c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 7307c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 7317c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 7327c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 7337c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 7347c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 7357c478bd9Sstevel@tonic-gate "too short valid lifetime %u stored %u " 7367c478bd9Sstevel@tonic-gate "- ignored\n", 7377c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 7387c478bd9Sstevel@tonic-gate validtime, recorded_validtime); 7397c478bd9Sstevel@tonic-gate return (_B_TRUE); 7407c478bd9Sstevel@tonic-gate } else { 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * If the router clock runs slower than the 7437c478bd9Sstevel@tonic-gate * host by 1 second over 2 hours then this 7447c478bd9Sstevel@tonic-gate * test will set the lifetime back to 2 hours 7457c478bd9Sstevel@tonic-gate * once i.e. a lifetime decrementing in 7467c478bd9Sstevel@tonic-gate * realtime might cause the prefix to live an 7477c478bd9Sstevel@tonic-gate * extra 2 hours on the host. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 7507c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 7517c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 7527c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 7537c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 7547c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 7557c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 7567c478bd9Sstevel@tonic-gate "valid time %u stored %u rounded up " 7577c478bd9Sstevel@tonic-gate "to %u\n", 7587c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 7597c478bd9Sstevel@tonic-gate validtime, recorded_validtime, 7607c478bd9Sstevel@tonic-gate MIN_VALID_LIFETIME); 7617c478bd9Sstevel@tonic-gate validtime = MIN_VALID_LIFETIME; 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * For RFC3041 addresses, need to take token lifetime 7677c478bd9Sstevel@tonic-gate * into account, too. 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 7707c478bd9Sstevel@tonic-gate uint_t cur_tpreftime = 7717c478bd9Sstevel@tonic-gate pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if (new_prefix) { 7747c478bd9Sstevel@tonic-gate validtime = MIN(validtime, pi->pi_TmpValidLifetime); 7757c478bd9Sstevel@tonic-gate preftime = MIN(preftime, cur_tpreftime); 7767c478bd9Sstevel@tonic-gate } else { 7777c478bd9Sstevel@tonic-gate uint_t cur_vexp, cur_pexp, curtime; 7787c478bd9Sstevel@tonic-gate curtime = getcurrenttime() / MILLISEC; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime; 7817c478bd9Sstevel@tonic-gate cur_pexp = pr->pr_CreateTime + cur_tpreftime; 7827c478bd9Sstevel@tonic-gate if (curtime > cur_vexp) 7837c478bd9Sstevel@tonic-gate validtime = 0; 7847c478bd9Sstevel@tonic-gate else if ((curtime + validtime) > cur_vexp) 7857c478bd9Sstevel@tonic-gate validtime = cur_vexp - curtime; 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * If this is an existing address which was deprecated 7887c478bd9Sstevel@tonic-gate * because of a bad token, we don't want to update its 7897c478bd9Sstevel@tonic-gate * preferred lifetime! 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate if ((pr->pr_PreferredLifetime == 0) && 7927c478bd9Sstevel@tonic-gate !token_equal(pr->pr_address, pi->pi_tmp_token, 7937c478bd9Sstevel@tonic-gate TMP_TOKEN_BITS)) 7947c478bd9Sstevel@tonic-gate preftime = 0; 7957c478bd9Sstevel@tonic-gate else if (curtime > cur_pexp) 7967c478bd9Sstevel@tonic-gate preftime = 0; 7977c478bd9Sstevel@tonic-gate else if ((curtime + preftime) > cur_pexp) 7987c478bd9Sstevel@tonic-gate preftime = cur_pexp - curtime; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) { 8017c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 8027c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 8037c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 8047c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 8057c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 8067c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 8077c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: " 8087c478bd9Sstevel@tonic-gate "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n", 8097c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, preftime, 8107c478bd9Sstevel@tonic-gate pi->pi_TmpRegenAdvance); 8117c478bd9Sstevel@tonic-gate if (new_prefix) 8127c478bd9Sstevel@tonic-gate prefix_delete(pr); 8137c478bd9Sstevel@tonic-gate return (_B_TRUE); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate if (debug & D_TMP) 8177c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, " 8187c478bd9Sstevel@tonic-gate "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO)) { 8217c478bd9Sstevel@tonic-gate int i, tokenlen; 8227c478bd9Sstevel@tonic-gate in6_addr_t *token; 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * Form a new local address if the lengths match. 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate if (pr->pr_flags && IFF_TEMPORARY) { 8277c478bd9Sstevel@tonic-gate RETRY_TOKEN: 8287c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) { 8297c478bd9Sstevel@tonic-gate if (!tmptoken_create(pi)) { 8307c478bd9Sstevel@tonic-gate prefix_delete(pr); 8317c478bd9Sstevel@tonic-gate return (_B_TRUE); 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate tokenlen = TMP_TOKEN_BITS; 8357c478bd9Sstevel@tonic-gate token = &pi->pi_tmp_token; 8367c478bd9Sstevel@tonic-gate } else { 8377c478bd9Sstevel@tonic-gate tokenlen = pi->pi_token_length; 8387c478bd9Sstevel@tonic-gate token = &pi->pi_token; 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) { 8417c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 8427c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 8437c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 8447c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 8457c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 8467c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 8477c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 8487c478bd9Sstevel@tonic-gate "mismatched length %d token length %d\n", 8497c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 8507c478bd9Sstevel@tonic-gate pr->pr_prefix_len, tokenlen); 8517c478bd9Sstevel@tonic-gate return (_B_TRUE); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 8567c478bd9Sstevel@tonic-gate * bits after prefixlen. 8577c478bd9Sstevel@tonic-gate */ 8587c478bd9Sstevel@tonic-gate pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | 8597c478bd9Sstevel@tonic-gate token->s6_addr[i]; 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * Check if any other physical interface has the same 8637c478bd9Sstevel@tonic-gate * address configured already 8647c478bd9Sstevel@tonic-gate */ 8657c478bd9Sstevel@tonic-gate if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) { 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * Delete this prefix structure as kernel 8687c478bd9Sstevel@tonic-gate * does not allow duplicated addresses 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 8727c478bd9Sstevel@tonic-gate "Duplicate prefix %s received on interface %s\n", 8737c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, 8747c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, abuf, 8757c478bd9Sstevel@tonic-gate sizeof (abuf)), pi->pi_name); 8767c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 8777c478bd9Sstevel@tonic-gate "Prefix already exists in interface %s\n", 8787c478bd9Sstevel@tonic-gate other_pr->pr_physical->pi_name); 8797c478bd9Sstevel@tonic-gate if (new_prefix) { 8807c478bd9Sstevel@tonic-gate prefix_delete(pr); 8817c478bd9Sstevel@tonic-gate return (_B_FALSE); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate /* Ignore for addrconf purposes */ 8847c478bd9Sstevel@tonic-gate validtime = preftime = 0; 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) { 8877c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 8887c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 8897c478bd9Sstevel@tonic-gate sin6.sin6_addr = pr->pr_address; 8907c478bd9Sstevel@tonic-gate if (do_dad(pi->pi_name, &sin6) != 0) { 8917c478bd9Sstevel@tonic-gate /* DAD failed, need a new token */ 8927c478bd9Sstevel@tonic-gate dadfails++; 8937c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 8947c478bd9Sstevel@tonic-gate "incoming_prefix_addrconf_process: " 8957c478bd9Sstevel@tonic-gate "deprecating temporary token %s\n", 8967c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, 8977c478bd9Sstevel@tonic-gate (void *)&pi->pi_tmp_token, abuf, 8987c478bd9Sstevel@tonic-gate sizeof (abuf))); 8997c478bd9Sstevel@tonic-gate tmptoken_delete(pi); 9007c478bd9Sstevel@tonic-gate if (dadfails == MAX_DAD_FAILURES) { 9017c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "Too many DAD " 9027c478bd9Sstevel@tonic-gate "failures; disabling temporary " 9037c478bd9Sstevel@tonic-gate "addresses on %s\n", pi->pi_name); 9047c478bd9Sstevel@tonic-gate pi->pi_TmpAddrsEnabled = 0; 9057c478bd9Sstevel@tonic-gate prefix_delete(pr); 9067c478bd9Sstevel@tonic-gate return (_B_TRUE); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate goto RETRY_TOKEN; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate pr->pr_CreateTime = getcurrenttime() / MILLISEC; 9117c478bd9Sstevel@tonic-gate if (debug & D_TMP) 9127c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 9137c478bd9Sstevel@tonic-gate "created tmp addr(%s v %d p %d)\n", 9147c478bd9Sstevel@tonic-gate pr->pr_name, validtime, preftime); 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate if (validtime != 0) 9197c478bd9Sstevel@tonic-gate pr->pr_state |= PR_AUTO; 9207c478bd9Sstevel@tonic-gate else 9217c478bd9Sstevel@tonic-gate pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 9227c478bd9Sstevel@tonic-gate if (preftime != 0 || !(pr->pr_state & PR_AUTO)) 9237c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_DEPRECATED; 9247c478bd9Sstevel@tonic-gate else 9257c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate /* 9287c478bd9Sstevel@tonic-gate * Convert from seconds to milliseconds avoiding overflow. 9297c478bd9Sstevel@tonic-gate * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 9307c478bd9Sstevel@tonic-gate * (4 billion seconds - about 130 years) we will in fact time 9317c478bd9Sstevel@tonic-gate * out the prefix after 4 billion milliseconds - 46 days). 9327c478bd9Sstevel@tonic-gate * Thus the longest lifetime (apart from infinity) is 46 days. 9337c478bd9Sstevel@tonic-gate * Note that this ensures that PREFIX_INFINITY still means "forever". 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate if (validtime >= PREFIX_INFINITY / MILLISEC) 9367c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = PREFIX_INFINITY - 1; 9377c478bd9Sstevel@tonic-gate else 9387c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = validtime * MILLISEC; 9397c478bd9Sstevel@tonic-gate if (preftime >= PREFIX_INFINITY / MILLISEC) 9407c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = PREFIX_INFINITY - 1; 9417c478bd9Sstevel@tonic-gate else 9427c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = preftime * MILLISEC; 9437c478bd9Sstevel@tonic-gate pr->pr_AutonomousFlag = _B_TRUE; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 9467c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) " 9477c478bd9Sstevel@tonic-gate "valid %u pref %u\n", 9487c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 9497c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 9507c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 9517c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime, pr->pr_PreferredLifetime); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_AUTO) { 9557c478bd9Sstevel@tonic-gate /* Take the min of the two timeouts by calling it twice */ 9567c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime != 0) 9577c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_ValidLifetime); 9587c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime != 0) 9597c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_PreferredLifetime); 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) { 9627c478bd9Sstevel@tonic-gate /* Log a message when an addrconf prefix goes away */ 9637c478bd9Sstevel@tonic-gate if ((pr->pr_kernel_state & PR_AUTO) && 9647c478bd9Sstevel@tonic-gate !(pr->pr_state & PR_AUTO)) { 9657c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "Address removed due to zero " 9687c478bd9Sstevel@tonic-gate "valid lifetime %s\n", 9697c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 9707c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate prefix_update_k(pr); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate return (_B_TRUE); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * Process an MTU option received in a router advertisement. 9797c478bd9Sstevel@tonic-gate */ 9807c478bd9Sstevel@tonic-gate static void 9817c478bd9Sstevel@tonic-gate incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 9827c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 9857c478bd9Sstevel@tonic-gate struct lifreq lifr; 9867c478bd9Sstevel@tonic-gate uint32_t mtu; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 9897c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 9927c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 9937c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 9947c478bd9Sstevel@tonic-gate "(%d bytes)\n", 9957c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 9967c478bd9Sstevel@tonic-gate 8 * (int)mo->nd_opt_mtu_len); 9977c478bd9Sstevel@tonic-gate return; 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate mtu = ntohl(mo->nd_opt_mtu_mtu); 10007c478bd9Sstevel@tonic-gate if (pi->pi_LinkMTU == mtu) 10017c478bd9Sstevel@tonic-gate return; /* No change */ 10027c478bd9Sstevel@tonic-gate if (mtu > pi->pi_mtu) { 10037c478bd9Sstevel@tonic-gate /* Can't exceed physical MTU */ 10047c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 10077c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 10087c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s too large " 10097c478bd9Sstevel@tonic-gate "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu); 10107c478bd9Sstevel@tonic-gate return; 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate if (mtu < IPV6_MIN_MTU) { 10137c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 10167c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 10177c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s too small " 10187c478bd9Sstevel@tonic-gate "MTU (%d)\n", abuf, pi->pi_name, mtu); 10197c478bd9Sstevel@tonic-gate return; 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate pi->pi_LinkMTU = mtu; 10237c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 10247c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 10257c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 10267c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_mtu_opt: SIOCGLIFLNKINFO"); 10277c478bd9Sstevel@tonic-gate return; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU; 10307c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 10317c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO"); 10327c478bd9Sstevel@tonic-gate return; 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * Process a source link-layer address option received in a router 10387c478bd9Sstevel@tonic-gate * advertisement or solicitation. 10397c478bd9Sstevel@tonic-gate */ 10407c478bd9Sstevel@tonic-gate static void 10417c478bd9Sstevel@tonic-gate incoming_lla_opt(struct phyint *pi, uchar_t *opt, 10427c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, int isrouter) 10437c478bd9Sstevel@tonic-gate { 10447c478bd9Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)opt; 10457c478bd9Sstevel@tonic-gate struct lifreq lifr; 10467c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 10477c478bd9Sstevel@tonic-gate int max_content_len; 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate if (pi->pi_hdw_addr_len == 0) 10507c478bd9Sstevel@tonic-gate return; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate * Can't remove padding since it is link type specific. 10547c478bd9Sstevel@tonic-gate * However, we check against the length of our link-layer 10557c478bd9Sstevel@tonic-gate * address. 10567c478bd9Sstevel@tonic-gate * Note: assumes that all links have a fixed lengh address. 10577c478bd9Sstevel@tonic-gate */ 10587c478bd9Sstevel@tonic-gate max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr); 10597c478bd9Sstevel@tonic-gate if (max_content_len < pi->pi_hdw_addr_len || 10607c478bd9Sstevel@tonic-gate (max_content_len >= 8 && 10617c478bd9Sstevel@tonic-gate max_content_len - 7 > pi->pi_hdw_addr_len)) { 10627c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 10657c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 10667c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "lla option from %s on %s too long with bad " 10677c478bd9Sstevel@tonic-gate "physaddr length (%d vs. %d bytes)\n", 10687c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 10697c478bd9Sstevel@tonic-gate max_content_len, pi->pi_hdw_addr_len); 10707c478bd9Sstevel@tonic-gate return; 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len = pi->pi_hdw_addr_len; 10747c478bd9Sstevel@tonic-gate bcopy((char *)lo->nd_opt_lla_hdw_addr, 10757c478bd9Sstevel@tonic-gate (char *)lifr.lifr_nd.lnr_hdw_addr, 10767c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 10797c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 10807c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 10817c478bd9Sstevel@tonic-gate sin6->sin6_addr = from->sin6_addr; 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate /* 10847c478bd9Sstevel@tonic-gate * Set IsRouter flag if RA; clear if RS. 10857c478bd9Sstevel@tonic-gate */ 10867c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_create = ND_STALE; 10877c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 10887c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 10897c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_flags = isrouter; 10907c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 10917c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 10927c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) { 10937c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND"); 10947c478bd9Sstevel@tonic-gate return; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * Verify the content of the received router advertisement against our 11007c478bd9Sstevel@tonic-gate * own configuration as specified in RFC 2461. 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate static void 11037c478bd9Sstevel@tonic-gate verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len, 11047c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 11057c478bd9Sstevel@tonic-gate { 11067c478bd9Sstevel@tonic-gate char frombuf[INET6_ADDRSTRLEN]; 11077c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 11087c478bd9Sstevel@tonic-gate int optlen; 11097c478bd9Sstevel@tonic-gate uint_t reachable, retrans; 11107c478bd9Sstevel@tonic-gate boolean_t pktflag, myflag; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 11137c478bd9Sstevel@tonic-gate frombuf, sizeof (frombuf)); 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate if (ra->nd_ra_curhoplimit != 0 && 11167c478bd9Sstevel@tonic-gate pi->pi_AdvCurHopLimit != 0 && 11177c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) { 11187c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop " 11197c478bd9Sstevel@tonic-gate "limit:\n\treceived %d configuration %d\n", 11207c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 11217c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate reachable = ntohl(ra->nd_ra_reachable); 11257c478bd9Sstevel@tonic-gate if (reachable != 0 && pi->pi_AdvReachableTime != 0 && 11267c478bd9Sstevel@tonic-gate reachable != pi->pi_AdvReachableTime) { 11277c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable " 11287c478bd9Sstevel@tonic-gate "time:\n\treceived %d configuration %d\n", 11297c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 11307c478bd9Sstevel@tonic-gate reachable, pi->pi_AdvReachableTime); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate retrans = ntohl(ra->nd_ra_retransmit); 11347c478bd9Sstevel@tonic-gate if (retrans != 0 && pi->pi_AdvRetransTimer != 0 && 11357c478bd9Sstevel@tonic-gate retrans != pi->pi_AdvRetransTimer) { 11367c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit " 11377c478bd9Sstevel@tonic-gate "timer:\n\treceived %d configuration %d\n", 11387c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 11397c478bd9Sstevel@tonic-gate retrans, pi->pi_AdvRetransTimer); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0); 11437c478bd9Sstevel@tonic-gate myflag = (pi->pi_AdvManagedFlag != 0); 11447c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 11457c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent managed " 11467c478bd9Sstevel@tonic-gate "flag:\n\treceived %s configuration %s\n", 11477c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 11487c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 11497c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0); 11527c478bd9Sstevel@tonic-gate myflag = (pi->pi_AdvOtherConfigFlag != 0); 11537c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 11547c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent other config " 11557c478bd9Sstevel@tonic-gate "flag:\n\treceived %s configuration %s\n", 11567c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 11577c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 11587c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate /* Process any options */ 11627c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_advert); 11637c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&ra[1]; 11647c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 11657c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 11667c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 11677c478bd9Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: 11687c478bd9Sstevel@tonic-gate verify_prefix_opt(pi, (uchar_t *)opt, frombuf); 11697c478bd9Sstevel@tonic-gate break; 11707c478bd9Sstevel@tonic-gate case ND_OPT_MTU: 11717c478bd9Sstevel@tonic-gate verify_mtu_opt(pi, (uchar_t *)opt, frombuf); 11727c478bd9Sstevel@tonic-gate break; 11737c478bd9Sstevel@tonic-gate default: 11747c478bd9Sstevel@tonic-gate break; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 11777c478bd9Sstevel@tonic-gate len -= optlen; 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* 11827c478bd9Sstevel@tonic-gate * Verify that the lifetimes and onlink/auto flags are consistent 11837c478bd9Sstevel@tonic-gate * with our settings. 11847c478bd9Sstevel@tonic-gate */ 11857c478bd9Sstevel@tonic-gate static void 11867c478bd9Sstevel@tonic-gate verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 11877c478bd9Sstevel@tonic-gate { 11887c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 11897c478bd9Sstevel@tonic-gate int plen; 11907c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 11917c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; 11927c478bd9Sstevel@tonic-gate char prefixbuf[INET6_ADDRSTRLEN]; 11937c478bd9Sstevel@tonic-gate int pktflag, myflag; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate if (8 * po->nd_opt_pi_len != sizeof (*po)) { 11967c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size " 11977c478bd9Sstevel@tonic-gate "(%d bytes)\n", 11987c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 11997c478bd9Sstevel@tonic-gate 8 * (int)po->nd_opt_pi_len); 12007c478bd9Sstevel@tonic-gate return; 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 12037c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s contains link-local " 12047c478bd9Sstevel@tonic-gate "prefix - ignored\n", 12057c478bd9Sstevel@tonic-gate frombuf, pi->pi_name); 12067c478bd9Sstevel@tonic-gate return; 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 12097c478bd9Sstevel@tonic-gate adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen); 12107c478bd9Sstevel@tonic-gate if (adv_pr == NULL) 12117c478bd9Sstevel@tonic-gate return; 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /* Ignore prefixes which we do not advertise */ 12147c478bd9Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag) 12157c478bd9Sstevel@tonic-gate return; 12167c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 12177c478bd9Sstevel@tonic-gate prefixbuf, sizeof (prefixbuf)); 12187c478bd9Sstevel@tonic-gate pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0); 12197c478bd9Sstevel@tonic-gate myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0); 12207c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 12217c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, 12227c478bd9Sstevel@tonic-gate "RA from %s on %s inconsistent autonumous flag for \n\t" 12237c478bd9Sstevel@tonic-gate "prefix %s/%u: received %s configuration %s\n", 12247c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 12257c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 12267c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0); 12307c478bd9Sstevel@tonic-gate myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0); 12317c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 12327c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag " 12337c478bd9Sstevel@tonic-gate "for \n\tprefix %s/%u: received %s configuration %s\n", 12347c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 12357c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 12367c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 12397c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* 12427c478bd9Sstevel@tonic-gate * Take into account variation for lifetimes decrementing 12437c478bd9Sstevel@tonic-gate * in real time. Allow +/- 10 percent and +/- 10 seconds. 12447c478bd9Sstevel@tonic-gate */ 12457c478bd9Sstevel@tonic-gate #define LOWER_LIMIT(val) ((val) - (val)/10 - 10) 12467c478bd9Sstevel@tonic-gate #define UPPER_LIMIT(val) ((val) + (val)/10 + 10) 12477c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 12487c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidExpiration > 0 && 12497c478bd9Sstevel@tonic-gate (validtime < 12507c478bd9Sstevel@tonic-gate LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) || 12517c478bd9Sstevel@tonic-gate validtime > 12527c478bd9Sstevel@tonic-gate UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) { 12537c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 12547c478bd9Sstevel@tonic-gate "lifetime for\n\tprefix %s/%u: received %d " 12557c478bd9Sstevel@tonic-gate "configuration %d\n", 12567c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 12577c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 12587c478bd9Sstevel@tonic-gate validtime, adv_pr->adv_pr_AdvValidExpiration); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate } else { 12617c478bd9Sstevel@tonic-gate if (validtime != adv_pr->adv_pr_AdvValidLifetime) { 12627c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 12637c478bd9Sstevel@tonic-gate "lifetime for\n\tprefix %s/%u: received %d " 12647c478bd9Sstevel@tonic-gate "configuration %d\n", 12657c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 12667c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 12677c478bd9Sstevel@tonic-gate validtime, adv_pr->adv_pr_AdvValidLifetime); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 12727c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredExpiration > 0 && 12737c478bd9Sstevel@tonic-gate (preftime < 12747c478bd9Sstevel@tonic-gate LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) || 12757c478bd9Sstevel@tonic-gate preftime > 12767c478bd9Sstevel@tonic-gate UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) { 12777c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent " 12787c478bd9Sstevel@tonic-gate "preferred lifetime for\n\tprefix %s/%u: " 12797c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 12807c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 12817c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 12827c478bd9Sstevel@tonic-gate preftime, adv_pr->adv_pr_AdvPreferredExpiration); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate } else { 12857c478bd9Sstevel@tonic-gate if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) { 12867c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent " 12877c478bd9Sstevel@tonic-gate "preferred lifetime for\n\tprefix %s/%u: " 12887c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 12897c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 12907c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 12917c478bd9Sstevel@tonic-gate preftime, adv_pr->adv_pr_AdvPreferredLifetime); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * Verify the received MTU against our own configuration. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate static void 13007c478bd9Sstevel@tonic-gate verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 13017c478bd9Sstevel@tonic-gate { 13027c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 13037c478bd9Sstevel@tonic-gate uint32_t mtu; 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 13067c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 13077c478bd9Sstevel@tonic-gate "(%d bytes)\n", 13087c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 13097c478bd9Sstevel@tonic-gate 8 * (int)mo->nd_opt_mtu_len); 13107c478bd9Sstevel@tonic-gate return; 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate mtu = ntohl(mo->nd_opt_mtu_mtu); 13137c478bd9Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0 && 13147c478bd9Sstevel@tonic-gate pi->pi_AdvLinkMTU != mtu) { 13157c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: " 13167c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 13177c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 13187c478bd9Sstevel@tonic-gate mtu, pi->pi_AdvLinkMTU); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * Verify that all options have a non-zero length and that 13247c478bd9Sstevel@tonic-gate * the options fit within the total length of the packet (optlen). 13257c478bd9Sstevel@tonic-gate */ 13267c478bd9Sstevel@tonic-gate static boolean_t 13277c478bd9Sstevel@tonic-gate verify_opt_len(struct nd_opt_hdr *opt, int optlen, 13287c478bd9Sstevel@tonic-gate struct phyint *pi, struct sockaddr_in6 *from) 13297c478bd9Sstevel@tonic-gate { 13307c478bd9Sstevel@tonic-gate while (optlen > 0) { 13317c478bd9Sstevel@tonic-gate if (opt->nd_opt_len == 0) { 13327c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 13357c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 13367c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Zero length option type 0x%x " 13397c478bd9Sstevel@tonic-gate "from %s on %s\n", 13407c478bd9Sstevel@tonic-gate opt->nd_opt_type, abuf, pi->pi_name); 13417c478bd9Sstevel@tonic-gate return (_B_FALSE); 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate optlen -= 8 * opt->nd_opt_len; 13447c478bd9Sstevel@tonic-gate if (optlen < 0) { 13457c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 13487c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 13497c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Too large option: type 0x%x len %u " 13527c478bd9Sstevel@tonic-gate "from %s on %s\n", 13537c478bd9Sstevel@tonic-gate opt->nd_opt_type, opt->nd_opt_len, 13547c478bd9Sstevel@tonic-gate abuf, pi->pi_name); 13557c478bd9Sstevel@tonic-gate return (_B_FALSE); 13567c478bd9Sstevel@tonic-gate } 13577c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + 13587c478bd9Sstevel@tonic-gate 8 * opt->nd_opt_len); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate return (_B_TRUE); 13617c478bd9Sstevel@tonic-gate } 13626b27086dSdd 13636b27086dSdd /* 13646b27086dSdd * Update IsRouter Flag for Host turning into a router or vice-versa. 13656b27086dSdd */ 13666b27086dSdd static void 1367*b0f490f4Smh update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from, 1368*b0f490f4Smh int isrouter) 13696b27086dSdd { 13706b27086dSdd struct lifreq lifr; 13716b27086dSdd char abuf[INET6_ADDRSTRLEN]; 13726b27086dSdd struct sockaddr_in6 *sin6; 13736b27086dSdd 13746b27086dSdd /* check if valid flag is being set */ 13756b27086dSdd if ((isrouter != NDF_ISROUTER_ON) && 13766b27086dSdd (isrouter != NDF_ISROUTER_OFF)) { 13776b27086dSdd logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter " 13786b27086dSdd "flag %d\n", isrouter); 13796b27086dSdd return; 13806b27086dSdd } 13816b27086dSdd 13826b27086dSdd sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 13836b27086dSdd bzero(sin6, sizeof (*sin6)); 13846b27086dSdd sin6->sin6_family = AF_INET6; 13856b27086dSdd sin6->sin6_addr = from->sin6_addr; 13866b27086dSdd 13876b27086dSdd (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 13886b27086dSdd 13896b27086dSdd if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) { 1390*b0f490f4Smh if (errno == ESRCH) { 1391*b0f490f4Smh if (debug & D_IFSCAN) { 1392*b0f490f4Smh logmsg(LOG_DEBUG, 1393*b0f490f4Smh "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER"); 1394*b0f490f4Smh } 1395*b0f490f4Smh } else { 1396*b0f490f4Smh logperror_pi(pi, "update_ra_flag: SIOCLIFGETND"); 1397*b0f490f4Smh } 13986b27086dSdd } else { 13996b27086dSdd /* 14006b27086dSdd * The lif_nd_req structure has three state values to be used 14016b27086dSdd * when changing/updating nces : 14026b27086dSdd * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla. 14036b27086dSdd * 14046b27086dSdd * In this case, we're updating an nce, without changing lla; 14056b27086dSdd * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that 14066b27086dSdd * nce's state should not be affected by our flag change. 14076b27086dSdd * 14086b27086dSdd * The kernel implementation also expects the lnr_state_create 14096b27086dSdd * field be always set, before processing ioctl request for NCE 14106b27086dSdd * update. 14116b27086dSdd * We use the state as STALE, while addressing the possibility 14126b27086dSdd * of NCE deletion when ioctl with SIOCLIFGETND argument 14136b27086dSdd * in earlier step is returned - further in such case we don't 14146b27086dSdd * want to re-create the entry in the reachable state. 14156b27086dSdd */ 14166b27086dSdd lifr.lifr_nd.lnr_state_create = ND_STALE; 14176b27086dSdd lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 14186b27086dSdd lifr.lifr_nd.lnr_flags = isrouter; 14196b27086dSdd if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) { 14206b27086dSdd logperror_pi(pi, "update_ra_flag: SIOCLIFSETND"); 14216b27086dSdd } else { 14226b27086dSdd (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 14236b27086dSdd abuf, sizeof (abuf)); 14246b27086dSdd logmsg(LOG_INFO, "update_ra_flag: IsRouter flag " 14256b27086dSdd "updated for %s\n", abuf); 14266b27086dSdd } 14276b27086dSdd } 14286b27086dSdd } 1429