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 /* 236e91bba0SGirish Moodalbail * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27a36f6bdeSDan McDonald /* 28a36f6bdeSDan McDonald * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. 29a36f6bdeSDan McDonald */ 30a36f6bdeSDan McDonald 317c478bd9Sstevel@tonic-gate #include "defs.h" 327c478bd9Sstevel@tonic-gate #include "tables.h" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 357c478bd9Sstevel@tonic-gate 36d04ccbb3Scarlsonj #include <dhcpagent_ipc.h> 37d04ccbb3Scarlsonj #include <dhcpagent_util.h> 38d04ccbb3Scarlsonj 397c478bd9Sstevel@tonic-gate static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen, 407c478bd9Sstevel@tonic-gate struct phyint *pi, struct sockaddr_in6 *from); 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate static void incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, 437c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from); 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate void incoming_ra(struct phyint *pi, struct nd_router_advert *ra, 467c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from, boolean_t loopback); 477c478bd9Sstevel@tonic-gate static void incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 487c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback); 49d04ccbb3Scarlsonj static void incoming_prefix_onlink(struct phyint *pi, uchar_t *opt); 507c478bd9Sstevel@tonic-gate void incoming_prefix_onlink_process(struct prefix *pr, 517c478bd9Sstevel@tonic-gate uchar_t *opt); 52d04ccbb3Scarlsonj static void incoming_prefix_stateful(struct phyint *, uchar_t *); 537c478bd9Sstevel@tonic-gate static boolean_t incoming_prefix_addrconf(struct phyint *pi, 547c478bd9Sstevel@tonic-gate uchar_t *opt, struct sockaddr_in6 *from, 557c478bd9Sstevel@tonic-gate boolean_t loopback); 567c478bd9Sstevel@tonic-gate boolean_t incoming_prefix_addrconf_process(struct phyint *pi, 577c478bd9Sstevel@tonic-gate struct prefix *pr, uchar_t *opt, 587c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback, 597c478bd9Sstevel@tonic-gate boolean_t new_prefix); 607c478bd9Sstevel@tonic-gate static void incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 617c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from); 627c478bd9Sstevel@tonic-gate static void incoming_lla_opt(struct phyint *pi, uchar_t *opt, 637c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, int isrouter); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static void verify_ra_consistency(struct phyint *pi, 667c478bd9Sstevel@tonic-gate struct nd_router_advert *ra, 677c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from); 687c478bd9Sstevel@tonic-gate static void verify_prefix_opt(struct phyint *pi, uchar_t *opt, 697c478bd9Sstevel@tonic-gate char *frombuf); 707c478bd9Sstevel@tonic-gate static void verify_mtu_opt(struct phyint *pi, uchar_t *opt, 717c478bd9Sstevel@tonic-gate char *frombuf); 727c478bd9Sstevel@tonic-gate 73b0f490f4Smh138676 static void update_ra_flag(const struct phyint *pi, 746b27086dSdd193516 const struct sockaddr_in6 *from, int isrouter); 756b27086dSdd193516 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * Return a pointer to the specified option buffer. 787c478bd9Sstevel@tonic-gate * If not found return NULL. 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate static void * 817c478bd9Sstevel@tonic-gate find_ancillary(struct msghdr *msg, int cmsg_type) 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 867c478bd9Sstevel@tonic-gate cmsg = CMSG_NXTHDR(msg, cmsg)) { 877c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == IPPROTO_IPV6 && 887c478bd9Sstevel@tonic-gate cmsg->cmsg_type == cmsg_type) { 897c478bd9Sstevel@tonic-gate return (CMSG_DATA(cmsg)); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate return (NULL); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate void 967c478bd9Sstevel@tonic-gate in_data(struct phyint *pi) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate struct sockaddr_in6 from; 997c478bd9Sstevel@tonic-gate struct icmp6_hdr *icmp; 1007c478bd9Sstevel@tonic-gate struct nd_router_solicit *rs; 1017c478bd9Sstevel@tonic-gate struct nd_router_advert *ra; 1027c478bd9Sstevel@tonic-gate static uint64_t in_packet[(IP_MAXPACKET + 1)/8]; 1037c478bd9Sstevel@tonic-gate static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8]; 1047c478bd9Sstevel@tonic-gate int len; 1057c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1067c478bd9Sstevel@tonic-gate const char *msgbuf; 1077c478bd9Sstevel@tonic-gate struct msghdr msg; 1087c478bd9Sstevel@tonic-gate struct iovec iov; 1097c478bd9Sstevel@tonic-gate uchar_t *opt; 1107c478bd9Sstevel@tonic-gate uint_t hoplimit; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate iov.iov_base = (char *)in_packet; 1137c478bd9Sstevel@tonic-gate iov.iov_len = sizeof (in_packet); 1147c478bd9Sstevel@tonic-gate msg.msg_iov = &iov; 1157c478bd9Sstevel@tonic-gate msg.msg_iovlen = 1; 1167c478bd9Sstevel@tonic-gate msg.msg_name = (struct sockaddr *)&from; 1177c478bd9Sstevel@tonic-gate msg.msg_namelen = sizeof (from); 1187c478bd9Sstevel@tonic-gate msg.msg_control = ancillary_data; 1197c478bd9Sstevel@tonic-gate msg.msg_controllen = sizeof (ancillary_data); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) { 1227c478bd9Sstevel@tonic-gate logperror_pi(pi, "in_data: recvfrom"); 1237c478bd9Sstevel@tonic-gate return; 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate if (len == 0) 1267c478bd9Sstevel@tonic-gate return; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&from.sin6_addr, 1297c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)) == NULL) 1307c478bd9Sstevel@tonic-gate msgbuf = "Unspecified Router"; 1317c478bd9Sstevel@tonic-gate else 1327c478bd9Sstevel@tonic-gate msgbuf = abuf; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* Ignore packets > 64k or control buffers that don't fit */ 1357c478bd9Sstevel@tonic-gate if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 1367c478bd9Sstevel@tonic-gate if (debug & D_PKTBAD) { 1377c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x " 1387c478bd9Sstevel@tonic-gate "from %s\n", msg.msg_flags, msgbuf); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate return; 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate icmp = (struct icmp6_hdr *)in_packet; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (len < ICMP6_MINLEN) { 1467c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Too short ICMP packet: %d bytes " 1477c478bd9Sstevel@tonic-gate "from %s on %s\n", 1487c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 1497c478bd9Sstevel@tonic-gate return; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate opt = find_ancillary(&msg, IPV6_HOPLIMIT); 1537c478bd9Sstevel@tonic-gate if (opt == NULL) { 1547c478bd9Sstevel@tonic-gate /* Unknown hoplimit - must drop */ 1557c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n", 1567c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 1577c478bd9Sstevel@tonic-gate return; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate hoplimit = *(uint_t *)opt; 1607c478bd9Sstevel@tonic-gate opt = find_ancillary(&msg, IPV6_RTHDR); 1617c478bd9Sstevel@tonic-gate if (opt != NULL) { 1627c478bd9Sstevel@tonic-gate /* Can't allow routing headers in ND messages */ 1637c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "ND message with routing header " 1647c478bd9Sstevel@tonic-gate "from %s on %s\n", 1657c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 1667c478bd9Sstevel@tonic-gate return; 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate switch (icmp->icmp6_type) { 1697c478bd9Sstevel@tonic-gate case ND_ROUTER_SOLICIT: 1707c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 1717c478bd9Sstevel@tonic-gate return; 1727c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 1737c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 1747c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Ignore received RS packet " 1757c478bd9Sstevel@tonic-gate "on %s (no route exchange on interface)\n", 1767c478bd9Sstevel@tonic-gate pi->pi_name); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate return; 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Assumes that the kernel has verified the AH (if present) 1837c478bd9Sstevel@tonic-gate * and the ICMP checksum. 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate if (hoplimit != IPV6_MAX_HOPS) { 1869ba4fd8dSrshoaib logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n", 1877c478bd9Sstevel@tonic-gate hoplimit, msgbuf, pi->pi_name); 1887c478bd9Sstevel@tonic-gate return; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (icmp->icmp6_code != 0) { 1927c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS code: %d from %s on %s\n", 1937c478bd9Sstevel@tonic-gate icmp->icmp6_code, msgbuf, pi->pi_name); 1947c478bd9Sstevel@tonic-gate return; 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate if (len < sizeof (struct nd_router_solicit)) { 1987c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS too short: %d bytes " 1997c478bd9Sstevel@tonic-gate "from %s on %s\n", 2007c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 2017c478bd9Sstevel@tonic-gate return; 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate rs = (struct nd_router_solicit *)icmp; 2047c478bd9Sstevel@tonic-gate if (len > sizeof (struct nd_router_solicit)) { 2057c478bd9Sstevel@tonic-gate if (!verify_opt_len((struct nd_opt_hdr *)&rs[1], 2067c478bd9Sstevel@tonic-gate len - sizeof (struct nd_router_solicit), pi, &from)) 2077c478bd9Sstevel@tonic-gate return; 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 2107c478bd9Sstevel@tonic-gate print_route_sol("Received valid solicit from ", pi, 2117c478bd9Sstevel@tonic-gate rs, len, &from); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate incoming_rs(pi, rs, len, &from); 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate case ND_ROUTER_ADVERT: 2177c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) { 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * Router advt. must have address! 2207c478bd9Sstevel@tonic-gate * Logging the news and returning. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 2237c478bd9Sstevel@tonic-gate "Router's address unspecified in advertisement\n"); 2247c478bd9Sstevel@tonic-gate return; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 2277c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 2287c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Ignore received RA packet " 2297c478bd9Sstevel@tonic-gate "on %s (no route exchange on interface)\n", 2307c478bd9Sstevel@tonic-gate pi->pi_name); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate return; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Assumes that the kernel has verified the AH (if present) 2377c478bd9Sstevel@tonic-gate * and the ICMP checksum. 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 2409ba4fd8dSrshoaib logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n", 2417c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 2427c478bd9Sstevel@tonic-gate return; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (hoplimit != IPV6_MAX_HOPS) { 2467c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n", 2477c478bd9Sstevel@tonic-gate hoplimit, msgbuf, pi->pi_name); 2487c478bd9Sstevel@tonic-gate return; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (icmp->icmp6_code != 0) { 2527c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA code: %d from %s on %s\n", 2537c478bd9Sstevel@tonic-gate icmp->icmp6_code, msgbuf, pi->pi_name); 2547c478bd9Sstevel@tonic-gate return; 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate if (len < sizeof (struct nd_router_advert)) { 2587c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA too short: %d bytes " 2597c478bd9Sstevel@tonic-gate "from %s on %s\n", 2607c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 2617c478bd9Sstevel@tonic-gate return; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate ra = (struct nd_router_advert *)icmp; 2647c478bd9Sstevel@tonic-gate if (len > sizeof (struct nd_router_advert)) { 2657c478bd9Sstevel@tonic-gate if (!verify_opt_len((struct nd_opt_hdr *)&ra[1], 2667c478bd9Sstevel@tonic-gate len - sizeof (struct nd_router_advert), pi, &from)) 2677c478bd9Sstevel@tonic-gate return; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 2707c478bd9Sstevel@tonic-gate print_route_adv("Received valid advert from ", pi, 2717c478bd9Sstevel@tonic-gate ra, len, &from); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 2747c478bd9Sstevel@tonic-gate verify_ra_consistency(pi, ra, len, &from); 2757c478bd9Sstevel@tonic-gate else 2767c478bd9Sstevel@tonic-gate incoming_ra(pi, ra, len, &from, _B_FALSE); 2777c478bd9Sstevel@tonic-gate break; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * Process a received router solicitation. 2837c478bd9Sstevel@tonic-gate * Check for source link-layer address option and check if it 2847c478bd9Sstevel@tonic-gate * is time to advertise. 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate static void 2877c478bd9Sstevel@tonic-gate incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len, 2887c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 2897c478bd9Sstevel@tonic-gate { 2907c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 2917c478bd9Sstevel@tonic-gate int optlen; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* Process any options */ 2947c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_solicit); 2957c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&rs[1]; 2967c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 2977c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 2987c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 2997c478bd9Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 3007c478bd9Sstevel@tonic-gate incoming_lla_opt(pi, (uchar_t *)opt, 3017c478bd9Sstevel@tonic-gate from, NDF_ISROUTER_OFF); 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate default: 3047c478bd9Sstevel@tonic-gate break; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 3077c478bd9Sstevel@tonic-gate len -= optlen; 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate /* Simple algorithm: treat unicast and multicast RSs the same */ 3107c478bd9Sstevel@tonic-gate check_to_advertise(pi, RECEIVED_SOLICIT); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* 3146e91bba0SGirish Moodalbail * Function that sends commands to dhcpagent daemon. 315d04ccbb3Scarlsonj */ 3166e91bba0SGirish Moodalbail int 3176e91bba0SGirish Moodalbail dhcp_op(struct phyint *pi, int type) 318d04ccbb3Scarlsonj { 319d04ccbb3Scarlsonj dhcp_ipc_request_t *request; 320d04ccbb3Scarlsonj dhcp_ipc_reply_t *reply = NULL; 321d04ccbb3Scarlsonj int error; 322d04ccbb3Scarlsonj 323d04ccbb3Scarlsonj request = dhcp_ipc_alloc_request(type | DHCP_V6, pi->pi_name, NULL, 0, 324d04ccbb3Scarlsonj DHCP_TYPE_NONE); 325d04ccbb3Scarlsonj if (request == NULL) { 3266e91bba0SGirish Moodalbail logmsg(LOG_ERR, "dhcp_op: out of memory\n"); 327d04ccbb3Scarlsonj /* make sure we try again next time there's a chance */ 3286e91bba0SGirish Moodalbail if (type != DHCP_RELEASE) { 3296e91bba0SGirish Moodalbail pi->pi_ra_flags &= 3306e91bba0SGirish Moodalbail ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER; 3316e91bba0SGirish Moodalbail } 3326e91bba0SGirish Moodalbail return (DHCP_IPC_E_MEMORY); 333d04ccbb3Scarlsonj } 334d04ccbb3Scarlsonj 335d04ccbb3Scarlsonj error = dhcp_ipc_make_request(request, &reply, 0); 336d04ccbb3Scarlsonj free(request); 337d04ccbb3Scarlsonj if (error != 0) { 3386e91bba0SGirish Moodalbail logmsg(LOG_ERR, "could not send request to dhcpagent: " 3396e91bba0SGirish Moodalbail "%s: %s\n", pi->pi_name, dhcp_ipc_strerror(error)); 3406e91bba0SGirish Moodalbail return (error); 341d04ccbb3Scarlsonj } 342d04ccbb3Scarlsonj 343d04ccbb3Scarlsonj error = reply->return_code; 344d04ccbb3Scarlsonj free(reply); 345d04ccbb3Scarlsonj 3466e91bba0SGirish Moodalbail return (error); 3476e91bba0SGirish Moodalbail } 3486e91bba0SGirish Moodalbail 3496e91bba0SGirish Moodalbail /* 3506e91bba0SGirish Moodalbail * Start up DHCPv6 on a given physical interface. Does not wait for 3516e91bba0SGirish Moodalbail * a message to be returned from the daemon. 3526e91bba0SGirish Moodalbail */ 3536e91bba0SGirish Moodalbail void 3546e91bba0SGirish Moodalbail start_dhcp(struct phyint *pi) 3556e91bba0SGirish Moodalbail { 3566e91bba0SGirish Moodalbail int error; 3576e91bba0SGirish Moodalbail int type; 3586e91bba0SGirish Moodalbail 3596e91bba0SGirish Moodalbail if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) { 3606e91bba0SGirish Moodalbail logmsg(LOG_ERR, "unable to start %s\n", DHCP_AGENT_PATH); 3616e91bba0SGirish Moodalbail /* make sure we try again next time there's a chance */ 3626e91bba0SGirish Moodalbail pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER; 3636e91bba0SGirish Moodalbail return; 3646e91bba0SGirish Moodalbail } 3656e91bba0SGirish Moodalbail 3666e91bba0SGirish Moodalbail else if (pi->pi_ra_flags & ND_RA_FLAG_MANAGED) 3676e91bba0SGirish Moodalbail type = DHCP_START; 3686e91bba0SGirish Moodalbail else 3696e91bba0SGirish Moodalbail type = DHCP_INFORM; 3706e91bba0SGirish Moodalbail 3716e91bba0SGirish Moodalbail error = dhcp_op(pi, type); 372d04ccbb3Scarlsonj /* 373d04ccbb3Scarlsonj * Timeout is considered to be "success" because we don't wait for DHCP 374d04ccbb3Scarlsonj * to do its exchange. 375d04ccbb3Scarlsonj */ 376d04ccbb3Scarlsonj if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING && 377d04ccbb3Scarlsonj error != DHCP_IPC_E_TIMEOUT) { 3786e91bba0SGirish Moodalbail logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n", 3796e91bba0SGirish Moodalbail pi->pi_name, dhcp_ipc_strerror(error)); 3806e91bba0SGirish Moodalbail } 3816e91bba0SGirish Moodalbail } 3826e91bba0SGirish Moodalbail 3836e91bba0SGirish Moodalbail /* 3846e91bba0SGirish Moodalbail * Release the acquired DHCPv6 lease on a given physical interface. 3856e91bba0SGirish Moodalbail * Does not wait for a message to be returned from the daemon. 3866e91bba0SGirish Moodalbail */ 3876e91bba0SGirish Moodalbail void 3886e91bba0SGirish Moodalbail release_dhcp(struct phyint *pi) 3896e91bba0SGirish Moodalbail { 3906e91bba0SGirish Moodalbail int error; 3916e91bba0SGirish Moodalbail int type; 3926e91bba0SGirish Moodalbail 3936e91bba0SGirish Moodalbail type = DHCP_RELEASE; 3946e91bba0SGirish Moodalbail retry: 3956e91bba0SGirish Moodalbail error = dhcp_op(pi, type); 3966e91bba0SGirish Moodalbail if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING && 3976e91bba0SGirish Moodalbail error != DHCP_IPC_E_TIMEOUT) { 3986e91bba0SGirish Moodalbail if (type == DHCP_RELEASE && error == DHCP_IPC_E_OUTSTATE) { 3996e91bba0SGirish Moodalbail /* 4006e91bba0SGirish Moodalbail * Drop the dhcp control if we cannot release it. 4016e91bba0SGirish Moodalbail */ 4026e91bba0SGirish Moodalbail type = DHCP_DROP; 4036e91bba0SGirish Moodalbail goto retry; 4046e91bba0SGirish Moodalbail } 4056e91bba0SGirish Moodalbail logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n", 4066e91bba0SGirish Moodalbail pi->pi_name, dhcp_ipc_strerror(error)); 407d04ccbb3Scarlsonj } 408d04ccbb3Scarlsonj } 409d04ccbb3Scarlsonj 410d04ccbb3Scarlsonj /* 411a36f6bdeSDan McDonald * Globals to check if we're seeing unusual hop counts in Router 412a36f6bdeSDan McDonald * Advertisements (RAs). We record the hopcounts in the kernel using 413a36f6bdeSDan McDonald * SIOCSLIFLNKINFO, but the kernel ignores these when actually setting IPv6 414a36f6bdeSDan McDonald * hop counts for packets. 415a36f6bdeSDan McDonald * 416a36f6bdeSDan McDonald * RFC 3756 does mention the possibility of an adversary throttling down 417a36f6bdeSDan McDonald * hopcounts using unsolicited RAs. These variables can be tuned with 'mdb -p' 418a36f6bdeSDan McDonald * to reduce/increase our logging threshholds. 419a36f6bdeSDan McDonald */ 420a36f6bdeSDan McDonald /* Really a boolean... if set, also log the offending sending address. */ 421a36f6bdeSDan McDonald int bad_hopcount_record_addr = 0; 422a36f6bdeSDan McDonald /* Anything less triggers a warning. Set to 0 to disable. */ 423a36f6bdeSDan McDonald int bad_hopcount_threshhold = 16; 424a36f6bdeSDan McDonald /* Number of packets received below the threshhold. */ 425a36f6bdeSDan McDonald uint64_t bad_hopcount_packets; 426a36f6bdeSDan McDonald 427a36f6bdeSDan McDonald /* 4287c478bd9Sstevel@tonic-gate * Process a received router advertisement. 4297c478bd9Sstevel@tonic-gate * Called both when packets arrive as well as when we send RAs. 4307c478bd9Sstevel@tonic-gate * In the latter case 'loopback' is set. 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate void 4337c478bd9Sstevel@tonic-gate incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len, 4347c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 4377c478bd9Sstevel@tonic-gate int optlen; 4387c478bd9Sstevel@tonic-gate struct lifreq lifr; 4397c478bd9Sstevel@tonic-gate boolean_t set_needed = _B_FALSE; 4407c478bd9Sstevel@tonic-gate struct router *dr; 4417c478bd9Sstevel@tonic-gate uint16_t router_lifetime; 4427c478bd9Sstevel@tonic-gate uint_t reachable, retrans; 4437c478bd9Sstevel@tonic-gate boolean_t reachable_time_changed = _B_FALSE; 4446b27086dSdd193516 boolean_t slla_opt_present = _B_FALSE; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate if (no_loopback && loopback) 4477c478bd9Sstevel@tonic-gate return; 4487c478bd9Sstevel@tonic-gate 449e11c3f44Smeem bzero(&lifr, sizeof (lifr)); 450e11c3f44Smeem (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 4517c478bd9Sstevel@tonic-gate 4520a12cda4Sdd193516 if (ra->nd_ra_curhoplimit != CURHOP_UNSPECIFIED && 4530a12cda4Sdd193516 ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) { 4547c478bd9Sstevel@tonic-gate pi->pi_CurHopLimit = ra->nd_ra_curhoplimit; 4557c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 4567c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 457a36f6bdeSDan McDonald 458a36f6bdeSDan McDonald if (pi->pi_CurHopLimit < bad_hopcount_threshhold) { 459a36f6bdeSDan McDonald char abuf[INET6_ADDRSTRLEN]; 460a36f6bdeSDan McDonald 461a36f6bdeSDan McDonald bad_hopcount_packets++; 462a36f6bdeSDan McDonald logmsg(LOG_ALERT, 463a36f6bdeSDan McDonald "Low hopcount %d received on %s%s%s\n", 464a36f6bdeSDan McDonald pi->pi_CurHopLimit, pi->pi_name, 465a36f6bdeSDan McDonald bad_hopcount_record_addr ? " from " : "", 466a36f6bdeSDan McDonald bad_hopcount_record_addr ? 467a36f6bdeSDan McDonald inet_ntop(AF_INET6, &from->sin6_addr, abuf, 468a36f6bdeSDan McDonald INET6_ADDRSTRLEN) : ""); 469a36f6bdeSDan McDonald } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate reachable = ntohl(ra->nd_ra_reachable); 4737c478bd9Sstevel@tonic-gate if (reachable != 0 && 4747c478bd9Sstevel@tonic-gate reachable != pi->pi_BaseReachableTime) { 4757c478bd9Sstevel@tonic-gate pi->pi_BaseReachableTime = reachable; 4767c478bd9Sstevel@tonic-gate reachable_time_changed = _B_TRUE; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL || 4807c478bd9Sstevel@tonic-gate reachable_time_changed) { 4817c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_FALSE); 4827c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate retrans = ntohl(ra->nd_ra_retransmit); 4877c478bd9Sstevel@tonic-gate if (retrans != 0 && 4887c478bd9Sstevel@tonic-gate pi->pi_RetransTimer != retrans) { 4897c478bd9Sstevel@tonic-gate pi->pi_RetransTimer = retrans; 4907c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 4917c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate if (set_needed) { 4957c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 4967c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO"); 4977c478bd9Sstevel@tonic-gate return; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 501d04ccbb3Scarlsonj /* 502d04ccbb3Scarlsonj * If the "managed" flag is set, then just assume that the "other" flag 503d04ccbb3Scarlsonj * is set as well. It's not legal to get addresses alone without 504d04ccbb3Scarlsonj * getting other data. 505d04ccbb3Scarlsonj */ 506d04ccbb3Scarlsonj if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) 507d04ccbb3Scarlsonj ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; 508d04ccbb3Scarlsonj 509d04ccbb3Scarlsonj /* 510d04ccbb3Scarlsonj * If either the "managed" or "other" bits have turned on, then it's 511d04ccbb3Scarlsonj * now time to invoke DHCP. If only the "other" bit is set, then don't 512d04ccbb3Scarlsonj * get addresses via DHCP; only "other" data. If "managed" is set, 513d04ccbb3Scarlsonj * then we must always get both addresses and "other" data. 514d04ccbb3Scarlsonj */ 5156e91bba0SGirish Moodalbail if (pi->pi_autoconf && pi->pi_stateful && 516d04ccbb3Scarlsonj (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags & 517d04ccbb3Scarlsonj (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))) { 518d04ccbb3Scarlsonj if (debug & D_DHCP) { 519d04ccbb3Scarlsonj logmsg(LOG_DEBUG, 520d04ccbb3Scarlsonj "incoming_ra: trigger dhcp %s on %s\n", 521d04ccbb3Scarlsonj (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags & 522d04ccbb3Scarlsonj ND_RA_FLAG_MANAGED) ? "MANAGED" : "OTHER", 523d04ccbb3Scarlsonj pi->pi_name); 5247c478bd9Sstevel@tonic-gate } 525d04ccbb3Scarlsonj pi->pi_ra_flags |= ra->nd_ra_flags_reserved; 526d04ccbb3Scarlsonj start_dhcp(pi); 5277c478bd9Sstevel@tonic-gate } 528d04ccbb3Scarlsonj 5297c478bd9Sstevel@tonic-gate /* Skip default router code if sent from ourselves */ 5307c478bd9Sstevel@tonic-gate if (!loopback) { 5317c478bd9Sstevel@tonic-gate /* Find and update or add default router in list */ 5327c478bd9Sstevel@tonic-gate dr = router_lookup(pi, from->sin6_addr); 5337c478bd9Sstevel@tonic-gate router_lifetime = ntohs(ra->nd_ra_router_lifetime); 5347c478bd9Sstevel@tonic-gate if (dr == NULL) { 5357c478bd9Sstevel@tonic-gate if (router_lifetime != 0) { 5367c478bd9Sstevel@tonic-gate dr = router_create(pi, from->sin6_addr, 5377c478bd9Sstevel@tonic-gate MILLISEC * router_lifetime); 5387c478bd9Sstevel@tonic-gate timer_schedule(dr->dr_lifetime); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate } else { 5417c478bd9Sstevel@tonic-gate dr->dr_lifetime = MILLISEC * router_lifetime; 5427c478bd9Sstevel@tonic-gate if (dr->dr_lifetime != 0) 5437c478bd9Sstevel@tonic-gate timer_schedule(dr->dr_lifetime); 5447c478bd9Sstevel@tonic-gate if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) || 5457c478bd9Sstevel@tonic-gate (dr->dr_lifetime == 0 && dr->dr_inkernel)) 5467c478bd9Sstevel@tonic-gate router_update_k(dr); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate /* Process any options */ 5507c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_advert); 5517c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&ra[1]; 5527c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 5537c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 5547c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 5557c478bd9Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: 5567c478bd9Sstevel@tonic-gate incoming_prefix_opt(pi, (uchar_t *)opt, from, 5577c478bd9Sstevel@tonic-gate loopback); 5587c478bd9Sstevel@tonic-gate break; 5597c478bd9Sstevel@tonic-gate case ND_OPT_MTU: 5607c478bd9Sstevel@tonic-gate incoming_mtu_opt(pi, (uchar_t *)opt, from); 5617c478bd9Sstevel@tonic-gate break; 5627c478bd9Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 5637c478bd9Sstevel@tonic-gate /* skip lla option if sent from ourselves! */ 5647c478bd9Sstevel@tonic-gate if (!loopback) { 5657c478bd9Sstevel@tonic-gate incoming_lla_opt(pi, (uchar_t *)opt, 5667c478bd9Sstevel@tonic-gate from, NDF_ISROUTER_ON); 5676b27086dSdd193516 slla_opt_present = _B_TRUE; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate break; 5707c478bd9Sstevel@tonic-gate default: 5717c478bd9Sstevel@tonic-gate break; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 5747c478bd9Sstevel@tonic-gate len -= optlen; 5757c478bd9Sstevel@tonic-gate } 576b0f490f4Smh138676 if (!loopback && !slla_opt_present) 5776b27086dSdd193516 update_ra_flag(pi, from, NDF_ISROUTER_ON); 5787c478bd9Sstevel@tonic-gate /* Stop sending solicitations */ 5797c478bd9Sstevel@tonic-gate check_to_solicit(pi, SOLICIT_DONE); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * Process a received prefix option. 5847c478bd9Sstevel@tonic-gate * Unless addrconf is turned off we process both the addrconf and the 5857c478bd9Sstevel@tonic-gate * onlink aspects of the prefix option. 5867c478bd9Sstevel@tonic-gate * 5877c478bd9Sstevel@tonic-gate * Note that when a flag (onlink or auto) is turned off we do nothing - 5887c478bd9Sstevel@tonic-gate * the prefix will time out. 5897c478bd9Sstevel@tonic-gate */ 5907c478bd9Sstevel@tonic-gate static void 5917c478bd9Sstevel@tonic-gate incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 5927c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 5957c478bd9Sstevel@tonic-gate boolean_t good_prefix = _B_TRUE; 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate if (8 * po->nd_opt_pi_len != sizeof (*po)) { 5987c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 6017c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 6027c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option from %s on %s wrong size " 6037c478bd9Sstevel@tonic-gate "(%d bytes)\n", 6047c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 6057c478bd9Sstevel@tonic-gate 8 * (int)po->nd_opt_pi_len); 6067c478bd9Sstevel@tonic-gate return; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 6097c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 6127c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 6137c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix " 6147c478bd9Sstevel@tonic-gate "- ignored\n", 6157c478bd9Sstevel@tonic-gate abuf, pi->pi_name); 6167c478bd9Sstevel@tonic-gate return; 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && 6196e91bba0SGirish Moodalbail pi->pi_stateless && pi->pi_autoconf) { 6207c478bd9Sstevel@tonic-gate good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && 6237c478bd9Sstevel@tonic-gate good_prefix) { 624d04ccbb3Scarlsonj incoming_prefix_onlink(pi, opt); 6257c478bd9Sstevel@tonic-gate } 6266e91bba0SGirish Moodalbail if (pi->pi_stateful && pi->pi_autoconf) 627d04ccbb3Scarlsonj incoming_prefix_stateful(pi, opt); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate /* 6317c478bd9Sstevel@tonic-gate * Process prefix options with the onlink flag set. 6327c478bd9Sstevel@tonic-gate * 6337c478bd9Sstevel@tonic-gate * If there are no routers ndpd will add an onlink 6347c478bd9Sstevel@tonic-gate * default route which will allow communication 6357c478bd9Sstevel@tonic-gate * between neighbors. 6367c478bd9Sstevel@tonic-gate * 6377c478bd9Sstevel@tonic-gate * This function needs to loop to find the same prefix multiple times 6387c478bd9Sstevel@tonic-gate * as if a failover happened earlier, the addresses belonging to 6397c478bd9Sstevel@tonic-gate * a different interface may be found here on this interface. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate static void 642d04ccbb3Scarlsonj incoming_prefix_onlink(struct phyint *pi, uchar_t *opt) 6437c478bd9Sstevel@tonic-gate { 6447c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 6457c478bd9Sstevel@tonic-gate int plen; 6467c478bd9Sstevel@tonic-gate struct prefix *pr; 6477c478bd9Sstevel@tonic-gate uint32_t validtime; /* Without 2 hour rule */ 6487c478bd9Sstevel@tonic-gate boolean_t found_one = _B_FALSE; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 6517c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 6527c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == plen && 6537c478bd9Sstevel@tonic-gate prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 6547c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 6557c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 6567c478bd9Sstevel@tonic-gate continue; 6577c478bd9Sstevel@tonic-gate found_one = _B_TRUE; 6587c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(pr, opt); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * If we have found a matching prefix already or validtime 6657c478bd9Sstevel@tonic-gate * is zero, we have nothing to do. 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate if (validtime == 0 || found_one) 6687c478bd9Sstevel@tonic-gate return; 6697c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 6707c478bd9Sstevel@tonic-gate if (pr == NULL) 6717c478bd9Sstevel@tonic-gate return; 6727c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(pr, opt); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 6797c478bd9Sstevel@tonic-gate uint32_t validtime; /* Without 2 hour rule */ 6807c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 6837c478bd9Sstevel@tonic-gate if (validtime != 0) 6847c478bd9Sstevel@tonic-gate pr->pr_state |= PR_ONLINK; 6857c478bd9Sstevel@tonic-gate else 6867c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_ONLINK; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * Convert from seconds to milliseconds avoiding overflow. 6907c478bd9Sstevel@tonic-gate * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 6917c478bd9Sstevel@tonic-gate * (4 billion seconds - about 130 years) we will in fact time 6927c478bd9Sstevel@tonic-gate * out the prefix after 4 billion milliseconds - 46 days). 6937c478bd9Sstevel@tonic-gate * Thus the longest lifetime (apart from infinity) is 46 days. 6947c478bd9Sstevel@tonic-gate * Note that this ensures that PREFIX_INFINITY still means "forever". 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 6977c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = pr->pr_ValidLifetime; 6987c478bd9Sstevel@tonic-gate } else { 6997c478bd9Sstevel@tonic-gate if (validtime >= PREFIX_INFINITY / MILLISEC) 7007c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1; 7017c478bd9Sstevel@tonic-gate else 7027c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = validtime * MILLISEC; 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate pr->pr_OnLinkFlag = _B_TRUE; 7057c478bd9Sstevel@tonic-gate if (debug & (D_PREFIX|D_TMP)) { 7067c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) " 7077c478bd9Sstevel@tonic-gate "onlink %u state 0x%x, kstate 0x%x\n", 7087c478bd9Sstevel@tonic-gate pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 7097c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 7107c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) { 7147c478bd9Sstevel@tonic-gate prefix_update_k(pr); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime != 0) 7187c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_OnLinkLifetime); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate /* 722d04ccbb3Scarlsonj * Process all prefix options by locating the DHCPv6-configured interfaces, and 723d04ccbb3Scarlsonj * applying the netmasks as needed. 724d04ccbb3Scarlsonj */ 725d04ccbb3Scarlsonj static void 726d04ccbb3Scarlsonj incoming_prefix_stateful(struct phyint *pi, uchar_t *opt) 727d04ccbb3Scarlsonj { 728d04ccbb3Scarlsonj struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 729d04ccbb3Scarlsonj struct prefix *pr; 730d04ccbb3Scarlsonj boolean_t foundpref; 731d04ccbb3Scarlsonj char abuf[INET6_ADDRSTRLEN]; 732d04ccbb3Scarlsonj 733d04ccbb3Scarlsonj /* Make sure it's a valid prefix. */ 734d04ccbb3Scarlsonj if (ntohl(po->nd_opt_pi_valid_time) == 0) { 735d04ccbb3Scarlsonj if (debug & D_DHCP) 736d04ccbb3Scarlsonj logmsg(LOG_DEBUG, "incoming_prefix_stateful: ignoring " 737d04ccbb3Scarlsonj "prefix with no valid time\n"); 738d04ccbb3Scarlsonj return; 739d04ccbb3Scarlsonj } 740d04ccbb3Scarlsonj 741d04ccbb3Scarlsonj if (debug & D_DHCP) 742d04ccbb3Scarlsonj logmsg(LOG_DEBUG, "incoming_prefix_stateful(%s, %s/%d)\n", 743d04ccbb3Scarlsonj pi->pi_name, inet_ntop(AF_INET6, 744d04ccbb3Scarlsonj (void *)&po->nd_opt_pi_prefix, abuf, sizeof (abuf)), 745d04ccbb3Scarlsonj po->nd_opt_pi_prefix_len); 746d04ccbb3Scarlsonj foundpref = _B_FALSE; 747d04ccbb3Scarlsonj for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 7480ea48bbfSRamesh Kumar Katla if (prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, 749d04ccbb3Scarlsonj po->nd_opt_pi_prefix_len)) { 750d04ccbb3Scarlsonj if ((pr->pr_flags & IFF_DHCPRUNNING) && 751d04ccbb3Scarlsonj pr->pr_prefix_len != po->nd_opt_pi_prefix_len) { 752d04ccbb3Scarlsonj pr->pr_prefix_len = po->nd_opt_pi_prefix_len; 753d04ccbb3Scarlsonj if (pr->pr_flags & IFF_UP) { 754d04ccbb3Scarlsonj if (debug & D_DHCP) 755d04ccbb3Scarlsonj logmsg(LOG_DEBUG, 756d04ccbb3Scarlsonj "incoming_prefix_stateful:" 757d04ccbb3Scarlsonj " set mask on DHCP %s\n", 758d04ccbb3Scarlsonj pr->pr_name); 759d04ccbb3Scarlsonj prefix_update_dhcp(pr); 760d04ccbb3Scarlsonj } 761d04ccbb3Scarlsonj } 762d04ccbb3Scarlsonj if (pr->pr_prefix_len == po->nd_opt_pi_prefix_len && 763d04ccbb3Scarlsonj (!(pr->pr_state & PR_STATIC) || 764d04ccbb3Scarlsonj (pr->pr_flags & IFF_DHCPRUNNING))) 765d04ccbb3Scarlsonj foundpref = _B_TRUE; 766d04ccbb3Scarlsonj } 767d04ccbb3Scarlsonj } 768d04ccbb3Scarlsonj /* 769d04ccbb3Scarlsonj * If there's no matching DHCPv6 prefix present, then create an empty 770d04ccbb3Scarlsonj * one so that we'll be able to configure it later. 771d04ccbb3Scarlsonj */ 772d04ccbb3Scarlsonj if (!foundpref) { 773d04ccbb3Scarlsonj pr = prefix_create(pi, po->nd_opt_pi_prefix, 774d04ccbb3Scarlsonj po->nd_opt_pi_prefix_len, IFF_DHCPRUNNING); 775d04ccbb3Scarlsonj if (pr != NULL) { 776d04ccbb3Scarlsonj pr->pr_state = PR_STATIC; 777d04ccbb3Scarlsonj if (debug & D_DHCP) 778d04ccbb3Scarlsonj logmsg(LOG_DEBUG, 779d04ccbb3Scarlsonj "incoming_prefix_stateful: created dummy " 780d04ccbb3Scarlsonj "prefix for later\n"); 781d04ccbb3Scarlsonj } 782d04ccbb3Scarlsonj } 783d04ccbb3Scarlsonj } 784d04ccbb3Scarlsonj 785d04ccbb3Scarlsonj /* 7867c478bd9Sstevel@tonic-gate * Process prefix options with the autonomous flag set. 7877c478bd9Sstevel@tonic-gate * Returns false if this prefix results in a bad address (duplicate) 7887c478bd9Sstevel@tonic-gate * This function needs to loop to find the same prefix multiple times 7897c478bd9Sstevel@tonic-gate * as if a failover happened earlier, the addresses belonging to 7907c478bd9Sstevel@tonic-gate * a different interface may be found here on this interface. 7917c478bd9Sstevel@tonic-gate */ 7927c478bd9Sstevel@tonic-gate static boolean_t 7937c478bd9Sstevel@tonic-gate incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt, 7947c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 7957c478bd9Sstevel@tonic-gate { 7967c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 7977c478bd9Sstevel@tonic-gate int plen; 7987c478bd9Sstevel@tonic-gate struct prefix *pr; 7997c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; /* In seconds */ 8007c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 8017c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 8027c478bd9Sstevel@tonic-gate boolean_t found_pub = _B_FALSE; 8037c478bd9Sstevel@tonic-gate boolean_t found_tmp = _B_FALSE; 8047c478bd9Sstevel@tonic-gate boolean_t ret; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 8077c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 8087c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /* Sanity checks */ 8117c478bd9Sstevel@tonic-gate if (validtime < preftime) { 8127c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 8137c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 8147c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 8157c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 8167c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 8177c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: " 8187c478bd9Sstevel@tonic-gate "valid %u < pref %u ignored\n", 8197c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 8207c478bd9Sstevel@tonic-gate validtime, preftime); 8217c478bd9Sstevel@tonic-gate return (_B_FALSE); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 8257c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == plen && 8267c478bd9Sstevel@tonic-gate prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 8277c478bd9Sstevel@tonic-gate 828d04ccbb3Scarlsonj /* Exclude static prefixes and DHCP */ 829d04ccbb3Scarlsonj if ((pr->pr_state & PR_STATIC) || 830d04ccbb3Scarlsonj (pr->pr_flags & IFF_DHCPRUNNING)) 8317c478bd9Sstevel@tonic-gate continue; 8327c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * If this address is deprecated and its token 8357c478bd9Sstevel@tonic-gate * doesn't match the current tmp token, we want 8367c478bd9Sstevel@tonic-gate * to create a new address with the current 8377c478bd9Sstevel@tonic-gate * token. So don't count this addr as a match. 8387c478bd9Sstevel@tonic-gate */ 8397c478bd9Sstevel@tonic-gate if (!((pr->pr_flags & IFF_DEPRECATED) && 8407c478bd9Sstevel@tonic-gate !token_equal(pi->pi_tmp_token, 8417c478bd9Sstevel@tonic-gate pr->pr_address, TMP_TOKEN_BITS))) 8427c478bd9Sstevel@tonic-gate found_tmp = _B_TRUE; 8437c478bd9Sstevel@tonic-gate } else { 8447c478bd9Sstevel@tonic-gate found_pub = _B_TRUE; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate (void) incoming_prefix_addrconf_process(pi, pr, opt, 8477c478bd9Sstevel@tonic-gate from, loopback, _B_FALSE); 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * If we have found a matching prefix (for public and, if temp addrs 8537c478bd9Sstevel@tonic-gate * are enabled, for temporary) already or validtime is zero, we have 8547c478bd9Sstevel@tonic-gate * nothing to do. 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate if (validtime == 0 || 8577c478bd9Sstevel@tonic-gate (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp))) 8587c478bd9Sstevel@tonic-gate return (_B_TRUE); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate if (!found_pub) { 8617c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 8627c478bd9Sstevel@tonic-gate if (pr == NULL) 8637c478bd9Sstevel@tonic-gate return (_B_TRUE); 8647c478bd9Sstevel@tonic-gate ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 8657c478bd9Sstevel@tonic-gate loopback, _B_TRUE); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * if processing of the public address failed, 8697c478bd9Sstevel@tonic-gate * don't bother with the temporary address. 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate if (ret == _B_FALSE) 8727c478bd9Sstevel@tonic-gate return (_B_FALSE); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled && !found_tmp) { 8757c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 8767c478bd9Sstevel@tonic-gate IFF_TEMPORARY); 8777c478bd9Sstevel@tonic-gate if (pr == NULL) 8787c478bd9Sstevel@tonic-gate return (_B_TRUE); 8797c478bd9Sstevel@tonic-gate ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 8807c478bd9Sstevel@tonic-gate loopback, _B_TRUE); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate return (ret); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate boolean_t 8877c478bd9Sstevel@tonic-gate incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr, 8887c478bd9Sstevel@tonic-gate uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback, 8897c478bd9Sstevel@tonic-gate boolean_t new_prefix) 8907c478bd9Sstevel@tonic-gate { 8917c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 8927c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 8937c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 8947c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; /* In seconds */ 8957c478bd9Sstevel@tonic-gate uint32_t recorded_validtime; /* In seconds */ 89669bb4bb4Scarlsonj int plen; 8977c478bd9Sstevel@tonic-gate struct prefix *other_pr; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 9007c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 9017c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 9027c478bd9Sstevel@tonic-gate if (!new_prefix) { 9037c478bd9Sstevel@tonic-gate /* 9047c478bd9Sstevel@tonic-gate * Check 2 hour rule on valid lifetime. 9057c478bd9Sstevel@tonic-gate * Follows: RFC 2462 9067c478bd9Sstevel@tonic-gate * If we advertised this prefix ourselves we skip 9077c478bd9Sstevel@tonic-gate * these checks. They are also skipped if we did not 9087c478bd9Sstevel@tonic-gate * previously do addrconf on this prefix. 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate recorded_validtime = pr->pr_ValidLifetime / MILLISEC; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (loopback || !(pr->pr_state & PR_AUTO) || 9137c478bd9Sstevel@tonic-gate validtime >= MIN_VALID_LIFETIME || 9147c478bd9Sstevel@tonic-gate /* LINTED - statement has no consequent */ 9157c478bd9Sstevel@tonic-gate validtime >= recorded_validtime) { 9167c478bd9Sstevel@tonic-gate /* OK */ 9177c478bd9Sstevel@tonic-gate } else if (recorded_validtime < MIN_VALID_LIFETIME && 9187c478bd9Sstevel@tonic-gate validtime < recorded_validtime) { 9197c478bd9Sstevel@tonic-gate /* Ignore the prefix */ 9207c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 9217c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 9227c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 9237c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 9247c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 9257c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 9267c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 9277c478bd9Sstevel@tonic-gate "too short valid lifetime %u stored %u " 9287c478bd9Sstevel@tonic-gate "- ignored\n", 9297c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 9307c478bd9Sstevel@tonic-gate validtime, recorded_validtime); 9317c478bd9Sstevel@tonic-gate return (_B_TRUE); 9327c478bd9Sstevel@tonic-gate } else { 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * If the router clock runs slower than the 9357c478bd9Sstevel@tonic-gate * host by 1 second over 2 hours then this 9367c478bd9Sstevel@tonic-gate * test will set the lifetime back to 2 hours 9377c478bd9Sstevel@tonic-gate * once i.e. a lifetime decrementing in 9387c478bd9Sstevel@tonic-gate * realtime might cause the prefix to live an 9397c478bd9Sstevel@tonic-gate * extra 2 hours on the host. 9407c478bd9Sstevel@tonic-gate */ 9417c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 9427c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 9437c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 9447c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 9457c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 9467c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 9477c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 9487c478bd9Sstevel@tonic-gate "valid time %u stored %u rounded up " 9497c478bd9Sstevel@tonic-gate "to %u\n", 9507c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 9517c478bd9Sstevel@tonic-gate validtime, recorded_validtime, 9527c478bd9Sstevel@tonic-gate MIN_VALID_LIFETIME); 9537c478bd9Sstevel@tonic-gate validtime = MIN_VALID_LIFETIME; 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* 9587c478bd9Sstevel@tonic-gate * For RFC3041 addresses, need to take token lifetime 9597c478bd9Sstevel@tonic-gate * into account, too. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 9627c478bd9Sstevel@tonic-gate uint_t cur_tpreftime = 9637c478bd9Sstevel@tonic-gate pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate if (new_prefix) { 9667c478bd9Sstevel@tonic-gate validtime = MIN(validtime, pi->pi_TmpValidLifetime); 9677c478bd9Sstevel@tonic-gate preftime = MIN(preftime, cur_tpreftime); 9687c478bd9Sstevel@tonic-gate } else { 9697c478bd9Sstevel@tonic-gate uint_t cur_vexp, cur_pexp, curtime; 9707c478bd9Sstevel@tonic-gate curtime = getcurrenttime() / MILLISEC; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime; 9737c478bd9Sstevel@tonic-gate cur_pexp = pr->pr_CreateTime + cur_tpreftime; 9747c478bd9Sstevel@tonic-gate if (curtime > cur_vexp) 9757c478bd9Sstevel@tonic-gate validtime = 0; 9767c478bd9Sstevel@tonic-gate else if ((curtime + validtime) > cur_vexp) 9777c478bd9Sstevel@tonic-gate validtime = cur_vexp - curtime; 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * If this is an existing address which was deprecated 9807c478bd9Sstevel@tonic-gate * because of a bad token, we don't want to update its 9817c478bd9Sstevel@tonic-gate * preferred lifetime! 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate if ((pr->pr_PreferredLifetime == 0) && 9847c478bd9Sstevel@tonic-gate !token_equal(pr->pr_address, pi->pi_tmp_token, 9857c478bd9Sstevel@tonic-gate TMP_TOKEN_BITS)) 9867c478bd9Sstevel@tonic-gate preftime = 0; 9877c478bd9Sstevel@tonic-gate else if (curtime > cur_pexp) 9887c478bd9Sstevel@tonic-gate preftime = 0; 9897c478bd9Sstevel@tonic-gate else if ((curtime + preftime) > cur_pexp) 9907c478bd9Sstevel@tonic-gate preftime = cur_pexp - curtime; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) { 9937c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 9947c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 9957c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 9967c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 9977c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 9987c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 9997c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: " 10007c478bd9Sstevel@tonic-gate "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n", 10017c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, preftime, 10027c478bd9Sstevel@tonic-gate pi->pi_TmpRegenAdvance); 10036e91bba0SGirish Moodalbail if (new_prefix) { 10046e91bba0SGirish Moodalbail prefix_update_ipadm_addrobj(pr, _B_FALSE); 10057c478bd9Sstevel@tonic-gate prefix_delete(pr); 10066e91bba0SGirish Moodalbail } 10077c478bd9Sstevel@tonic-gate return (_B_TRUE); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate if (debug & D_TMP) 10117c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, " 10127c478bd9Sstevel@tonic-gate "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime); 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO)) { 10157c478bd9Sstevel@tonic-gate int i, tokenlen; 10167c478bd9Sstevel@tonic-gate in6_addr_t *token; 10177c478bd9Sstevel@tonic-gate /* 10187c478bd9Sstevel@tonic-gate * Form a new local address if the lengths match. 10197c478bd9Sstevel@tonic-gate */ 10206e91bba0SGirish Moodalbail if (pr->pr_flags & IFF_TEMPORARY) { 10217c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) { 10227c478bd9Sstevel@tonic-gate if (!tmptoken_create(pi)) { 10237c478bd9Sstevel@tonic-gate prefix_delete(pr); 10247c478bd9Sstevel@tonic-gate return (_B_TRUE); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate tokenlen = TMP_TOKEN_BITS; 10287c478bd9Sstevel@tonic-gate token = &pi->pi_tmp_token; 10297c478bd9Sstevel@tonic-gate } else { 10307c478bd9Sstevel@tonic-gate tokenlen = pi->pi_token_length; 10317c478bd9Sstevel@tonic-gate token = &pi->pi_token; 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) { 10347c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 10357c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 10367c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 10377c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 10387c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 10397c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 10407c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 10417c478bd9Sstevel@tonic-gate "mismatched length %d token length %d\n", 10427c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 10437c478bd9Sstevel@tonic-gate pr->pr_prefix_len, tokenlen); 10447c478bd9Sstevel@tonic-gate return (_B_TRUE); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 10477c478bd9Sstevel@tonic-gate /* 10487c478bd9Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 10497c478bd9Sstevel@tonic-gate * bits after prefixlen. 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | 10527c478bd9Sstevel@tonic-gate token->s6_addr[i]; 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * Check if any other physical interface has the same 10567c478bd9Sstevel@tonic-gate * address configured already 10577c478bd9Sstevel@tonic-gate */ 10587c478bd9Sstevel@tonic-gate if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) { 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * Delete this prefix structure as kernel 10617c478bd9Sstevel@tonic-gate * does not allow duplicated addresses 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 10647c478bd9Sstevel@tonic-gate "Duplicate prefix %s received on interface %s\n", 1065e11c3f44Smeem inet_ntop(AF_INET6, &po->nd_opt_pi_prefix, abuf, 10667c478bd9Sstevel@tonic-gate sizeof (abuf)), pi->pi_name); 10677c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 10687c478bd9Sstevel@tonic-gate "Prefix already exists in interface %s\n", 10697c478bd9Sstevel@tonic-gate other_pr->pr_physical->pi_name); 10707c478bd9Sstevel@tonic-gate if (new_prefix) { 10716e91bba0SGirish Moodalbail prefix_update_ipadm_addrobj(pr, _B_FALSE); 10727c478bd9Sstevel@tonic-gate prefix_delete(pr); 10737c478bd9Sstevel@tonic-gate return (_B_FALSE); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate /* Ignore for addrconf purposes */ 10767c478bd9Sstevel@tonic-gate validtime = preftime = 0; 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) { 10797c478bd9Sstevel@tonic-gate pr->pr_CreateTime = getcurrenttime() / MILLISEC; 10807c478bd9Sstevel@tonic-gate if (debug & D_TMP) 10817c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 10827c478bd9Sstevel@tonic-gate "created tmp addr(%s v %d p %d)\n", 10837c478bd9Sstevel@tonic-gate pr->pr_name, validtime, preftime); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate if (validtime != 0) 10887c478bd9Sstevel@tonic-gate pr->pr_state |= PR_AUTO; 10897c478bd9Sstevel@tonic-gate else 10907c478bd9Sstevel@tonic-gate pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 10917c478bd9Sstevel@tonic-gate if (preftime != 0 || !(pr->pr_state & PR_AUTO)) 10927c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_DEPRECATED; 10937c478bd9Sstevel@tonic-gate else 10947c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * Convert from seconds to milliseconds avoiding overflow. 10987c478bd9Sstevel@tonic-gate * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 10997c478bd9Sstevel@tonic-gate * (4 billion seconds - about 130 years) we will in fact time 11007c478bd9Sstevel@tonic-gate * out the prefix after 4 billion milliseconds - 46 days). 11017c478bd9Sstevel@tonic-gate * Thus the longest lifetime (apart from infinity) is 46 days. 11027c478bd9Sstevel@tonic-gate * Note that this ensures that PREFIX_INFINITY still means "forever". 11037c478bd9Sstevel@tonic-gate */ 11047c478bd9Sstevel@tonic-gate if (validtime >= PREFIX_INFINITY / MILLISEC) 11057c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = PREFIX_INFINITY - 1; 11067c478bd9Sstevel@tonic-gate else 11077c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = validtime * MILLISEC; 11087c478bd9Sstevel@tonic-gate if (preftime >= PREFIX_INFINITY / MILLISEC) 11097c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = PREFIX_INFINITY - 1; 11107c478bd9Sstevel@tonic-gate else 11117c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = preftime * MILLISEC; 11127c478bd9Sstevel@tonic-gate pr->pr_AutonomousFlag = _B_TRUE; 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 11157c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) " 11167c478bd9Sstevel@tonic-gate "valid %u pref %u\n", 11177c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 11187c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 11197c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 11207c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime, pr->pr_PreferredLifetime); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_AUTO) { 11247c478bd9Sstevel@tonic-gate /* Take the min of the two timeouts by calling it twice */ 11257c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime != 0) 11267c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_ValidLifetime); 11277c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime != 0) 11287c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_PreferredLifetime); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) { 11317c478bd9Sstevel@tonic-gate /* Log a message when an addrconf prefix goes away */ 11327c478bd9Sstevel@tonic-gate if ((pr->pr_kernel_state & PR_AUTO) && 11337c478bd9Sstevel@tonic-gate !(pr->pr_state & PR_AUTO)) { 11347c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "Address removed due to zero " 11377c478bd9Sstevel@tonic-gate "valid lifetime %s\n", 11387c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 11397c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate prefix_update_k(pr); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate return (_B_TRUE); 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * Process an MTU option received in a router advertisement. 11487c478bd9Sstevel@tonic-gate */ 11497c478bd9Sstevel@tonic-gate static void 11507c478bd9Sstevel@tonic-gate incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 11517c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 11547c478bd9Sstevel@tonic-gate struct lifreq lifr; 11557c478bd9Sstevel@tonic-gate uint32_t mtu; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 11587c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 11617c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 11627c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 11637c478bd9Sstevel@tonic-gate "(%d bytes)\n", 11647c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 11657c478bd9Sstevel@tonic-gate 8 * (int)mo->nd_opt_mtu_len); 11667c478bd9Sstevel@tonic-gate return; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate mtu = ntohl(mo->nd_opt_mtu_mtu); 11697c478bd9Sstevel@tonic-gate if (pi->pi_LinkMTU == mtu) 11707c478bd9Sstevel@tonic-gate return; /* No change */ 11717c478bd9Sstevel@tonic-gate if (mtu > pi->pi_mtu) { 11727c478bd9Sstevel@tonic-gate /* Can't exceed physical MTU */ 11737c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 11767c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 11777c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s too large " 11787c478bd9Sstevel@tonic-gate "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu); 11797c478bd9Sstevel@tonic-gate return; 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate if (mtu < IPV6_MIN_MTU) { 11827c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 11857c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 11867c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s too small " 11877c478bd9Sstevel@tonic-gate "MTU (%d)\n", abuf, pi->pi_name, mtu); 11887c478bd9Sstevel@tonic-gate return; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate pi->pi_LinkMTU = mtu; 1192e11c3f44Smeem bzero(&lifr, sizeof (lifr)); 1193e11c3f44Smeem (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 11947c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU; 11957c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 11967c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO"); 11977c478bd9Sstevel@tonic-gate return; 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * Process a source link-layer address option received in a router 12037c478bd9Sstevel@tonic-gate * advertisement or solicitation. 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate static void 12067c478bd9Sstevel@tonic-gate incoming_lla_opt(struct phyint *pi, uchar_t *opt, 12077c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, int isrouter) 12087c478bd9Sstevel@tonic-gate { 12097c478bd9Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)opt; 12107c478bd9Sstevel@tonic-gate struct lifreq lifr; 12117c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 12127c478bd9Sstevel@tonic-gate int max_content_len; 12137c478bd9Sstevel@tonic-gate 1214e11c3f44Smeem /* 1215e11c3f44Smeem * Get our link-layer address length. We may not have one, in which 1216e11c3f44Smeem * case we can just bail. 1217e11c3f44Smeem */ 1218e11c3f44Smeem if (phyint_get_lla(pi, &lifr) != 0) 12197c478bd9Sstevel@tonic-gate return; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * Can't remove padding since it is link type specific. 1223e11c3f44Smeem * However, we check against the length of our link-layer address. 1224e11c3f44Smeem * Note: assumes that all links have a fixed length address. 12257c478bd9Sstevel@tonic-gate */ 12267c478bd9Sstevel@tonic-gate max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr); 1227e11c3f44Smeem if (max_content_len < lifr.lifr_nd.lnr_hdw_len || 12287c478bd9Sstevel@tonic-gate (max_content_len >= 8 && 1229e11c3f44Smeem max_content_len - 7 > lifr.lifr_nd.lnr_hdw_len)) { 12307c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 12337c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 12347c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "lla option from %s on %s too long with bad " 1235e11c3f44Smeem "physaddr length (%d vs. %d bytes)\n", abuf, pi->pi_name, 1236e11c3f44Smeem max_content_len, lifr.lifr_nd.lnr_hdw_len); 12377c478bd9Sstevel@tonic-gate return; 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 1240e11c3f44Smeem bcopy(lo->nd_opt_lla_hdw_addr, lifr.lifr_nd.lnr_hdw_addr, 12417c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 12447c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 12457c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 12467c478bd9Sstevel@tonic-gate sin6->sin6_addr = from->sin6_addr; 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate /* 12497c478bd9Sstevel@tonic-gate * Set IsRouter flag if RA; clear if RS. 12507c478bd9Sstevel@tonic-gate */ 12517c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_create = ND_STALE; 12527c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 12537c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 12547c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_flags = isrouter; 1255e11c3f44Smeem (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 12567c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) { 12577c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND"); 12587c478bd9Sstevel@tonic-gate return; 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * Verify the content of the received router advertisement against our 12647c478bd9Sstevel@tonic-gate * own configuration as specified in RFC 2461. 12657c478bd9Sstevel@tonic-gate */ 12667c478bd9Sstevel@tonic-gate static void 12677c478bd9Sstevel@tonic-gate verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len, 12687c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 12697c478bd9Sstevel@tonic-gate { 12707c478bd9Sstevel@tonic-gate char frombuf[INET6_ADDRSTRLEN]; 12717c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 12727c478bd9Sstevel@tonic-gate int optlen; 12737c478bd9Sstevel@tonic-gate uint_t reachable, retrans; 12747c478bd9Sstevel@tonic-gate boolean_t pktflag, myflag; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 12777c478bd9Sstevel@tonic-gate frombuf, sizeof (frombuf)); 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate if (ra->nd_ra_curhoplimit != 0 && 12807c478bd9Sstevel@tonic-gate pi->pi_AdvCurHopLimit != 0 && 12817c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) { 12827c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop " 12837c478bd9Sstevel@tonic-gate "limit:\n\treceived %d configuration %d\n", 12847c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 12857c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit); 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate reachable = ntohl(ra->nd_ra_reachable); 12897c478bd9Sstevel@tonic-gate if (reachable != 0 && pi->pi_AdvReachableTime != 0 && 12907c478bd9Sstevel@tonic-gate reachable != pi->pi_AdvReachableTime) { 12917c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable " 12927c478bd9Sstevel@tonic-gate "time:\n\treceived %d configuration %d\n", 12937c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 12947c478bd9Sstevel@tonic-gate reachable, pi->pi_AdvReachableTime); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate retrans = ntohl(ra->nd_ra_retransmit); 12987c478bd9Sstevel@tonic-gate if (retrans != 0 && pi->pi_AdvRetransTimer != 0 && 12997c478bd9Sstevel@tonic-gate retrans != pi->pi_AdvRetransTimer) { 13007c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit " 13017c478bd9Sstevel@tonic-gate "timer:\n\treceived %d configuration %d\n", 13027c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 13037c478bd9Sstevel@tonic-gate retrans, pi->pi_AdvRetransTimer); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0); 13077c478bd9Sstevel@tonic-gate myflag = (pi->pi_AdvManagedFlag != 0); 13087c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 13097c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent managed " 13107c478bd9Sstevel@tonic-gate "flag:\n\treceived %s configuration %s\n", 13117c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 13127c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 13137c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0); 13167c478bd9Sstevel@tonic-gate myflag = (pi->pi_AdvOtherConfigFlag != 0); 13177c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 13187c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent other config " 13197c478bd9Sstevel@tonic-gate "flag:\n\treceived %s configuration %s\n", 13207c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 13217c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 13227c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* Process any options */ 13267c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_advert); 13277c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&ra[1]; 13287c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 13297c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 13307c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 13317c478bd9Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: 13327c478bd9Sstevel@tonic-gate verify_prefix_opt(pi, (uchar_t *)opt, frombuf); 13337c478bd9Sstevel@tonic-gate break; 13347c478bd9Sstevel@tonic-gate case ND_OPT_MTU: 13357c478bd9Sstevel@tonic-gate verify_mtu_opt(pi, (uchar_t *)opt, frombuf); 13367c478bd9Sstevel@tonic-gate break; 13377c478bd9Sstevel@tonic-gate default: 13387c478bd9Sstevel@tonic-gate break; 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 13417c478bd9Sstevel@tonic-gate len -= optlen; 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate /* 13467c478bd9Sstevel@tonic-gate * Verify that the lifetimes and onlink/auto flags are consistent 13477c478bd9Sstevel@tonic-gate * with our settings. 13487c478bd9Sstevel@tonic-gate */ 13497c478bd9Sstevel@tonic-gate static void 13507c478bd9Sstevel@tonic-gate verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 13517c478bd9Sstevel@tonic-gate { 13527c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 13537c478bd9Sstevel@tonic-gate int plen; 13547c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 13557c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; 13567c478bd9Sstevel@tonic-gate char prefixbuf[INET6_ADDRSTRLEN]; 13577c478bd9Sstevel@tonic-gate int pktflag, myflag; 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate if (8 * po->nd_opt_pi_len != sizeof (*po)) { 13607c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size " 13617c478bd9Sstevel@tonic-gate "(%d bytes)\n", 13627c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 13637c478bd9Sstevel@tonic-gate 8 * (int)po->nd_opt_pi_len); 13647c478bd9Sstevel@tonic-gate return; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 13677c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s contains link-local " 13687c478bd9Sstevel@tonic-gate "prefix - ignored\n", 13697c478bd9Sstevel@tonic-gate frombuf, pi->pi_name); 13707c478bd9Sstevel@tonic-gate return; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 13737c478bd9Sstevel@tonic-gate adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen); 13747c478bd9Sstevel@tonic-gate if (adv_pr == NULL) 13757c478bd9Sstevel@tonic-gate return; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* Ignore prefixes which we do not advertise */ 13787c478bd9Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag) 13797c478bd9Sstevel@tonic-gate return; 13807c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 13817c478bd9Sstevel@tonic-gate prefixbuf, sizeof (prefixbuf)); 13827c478bd9Sstevel@tonic-gate pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0); 13837c478bd9Sstevel@tonic-gate myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0); 13847c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 13857c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, 1386d04ccbb3Scarlsonj "RA from %s on %s inconsistent autonomous flag for \n\t" 13877c478bd9Sstevel@tonic-gate "prefix %s/%u: received %s configuration %s\n", 13887c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 13897c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 13907c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0); 13947c478bd9Sstevel@tonic-gate myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0); 13957c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 13967c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag " 13977c478bd9Sstevel@tonic-gate "for \n\tprefix %s/%u: received %s configuration %s\n", 13987c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 13997c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 14007c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 14037c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate /* 14067c478bd9Sstevel@tonic-gate * Take into account variation for lifetimes decrementing 14077c478bd9Sstevel@tonic-gate * in real time. Allow +/- 10 percent and +/- 10 seconds. 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate #define LOWER_LIMIT(val) ((val) - (val)/10 - 10) 14107c478bd9Sstevel@tonic-gate #define UPPER_LIMIT(val) ((val) + (val)/10 + 10) 14117c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 14127c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidExpiration > 0 && 14137c478bd9Sstevel@tonic-gate (validtime < 14147c478bd9Sstevel@tonic-gate LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) || 14157c478bd9Sstevel@tonic-gate validtime > 14167c478bd9Sstevel@tonic-gate UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) { 14177c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 14187c478bd9Sstevel@tonic-gate "lifetime for\n\tprefix %s/%u: received %d " 14197c478bd9Sstevel@tonic-gate "configuration %d\n", 14207c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 14217c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 14227c478bd9Sstevel@tonic-gate validtime, adv_pr->adv_pr_AdvValidExpiration); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate } else { 14257c478bd9Sstevel@tonic-gate if (validtime != adv_pr->adv_pr_AdvValidLifetime) { 14267c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 14277c478bd9Sstevel@tonic-gate "lifetime for\n\tprefix %s/%u: received %d " 14287c478bd9Sstevel@tonic-gate "configuration %d\n", 14297c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 14307c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 14317c478bd9Sstevel@tonic-gate validtime, adv_pr->adv_pr_AdvValidLifetime); 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 14367c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredExpiration > 0 && 14377c478bd9Sstevel@tonic-gate (preftime < 14387c478bd9Sstevel@tonic-gate LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) || 14397c478bd9Sstevel@tonic-gate preftime > 14407c478bd9Sstevel@tonic-gate UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) { 14417c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent " 14427c478bd9Sstevel@tonic-gate "preferred lifetime for\n\tprefix %s/%u: " 14437c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 14447c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 14457c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 14467c478bd9Sstevel@tonic-gate preftime, adv_pr->adv_pr_AdvPreferredExpiration); 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate } else { 14497c478bd9Sstevel@tonic-gate if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) { 14507c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent " 14517c478bd9Sstevel@tonic-gate "preferred lifetime for\n\tprefix %s/%u: " 14527c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 14537c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 14547c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 14557c478bd9Sstevel@tonic-gate preftime, adv_pr->adv_pr_AdvPreferredLifetime); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* 14617c478bd9Sstevel@tonic-gate * Verify the received MTU against our own configuration. 14627c478bd9Sstevel@tonic-gate */ 14637c478bd9Sstevel@tonic-gate static void 14647c478bd9Sstevel@tonic-gate verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 14657c478bd9Sstevel@tonic-gate { 14667c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 14677c478bd9Sstevel@tonic-gate uint32_t mtu; 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 14707c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 14717c478bd9Sstevel@tonic-gate "(%d bytes)\n", 14727c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 14737c478bd9Sstevel@tonic-gate 8 * (int)mo->nd_opt_mtu_len); 14747c478bd9Sstevel@tonic-gate return; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate mtu = ntohl(mo->nd_opt_mtu_mtu); 14777c478bd9Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0 && 14787c478bd9Sstevel@tonic-gate pi->pi_AdvLinkMTU != mtu) { 14797c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: " 14807c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 14817c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 14827c478bd9Sstevel@tonic-gate mtu, pi->pi_AdvLinkMTU); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* 14877c478bd9Sstevel@tonic-gate * Verify that all options have a non-zero length and that 14887c478bd9Sstevel@tonic-gate * the options fit within the total length of the packet (optlen). 14897c478bd9Sstevel@tonic-gate */ 14907c478bd9Sstevel@tonic-gate static boolean_t 14917c478bd9Sstevel@tonic-gate verify_opt_len(struct nd_opt_hdr *opt, int optlen, 14927c478bd9Sstevel@tonic-gate struct phyint *pi, struct sockaddr_in6 *from) 14937c478bd9Sstevel@tonic-gate { 14947c478bd9Sstevel@tonic-gate while (optlen > 0) { 14957c478bd9Sstevel@tonic-gate if (opt->nd_opt_len == 0) { 14967c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 14997c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 15007c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Zero length option type 0x%x " 15037c478bd9Sstevel@tonic-gate "from %s on %s\n", 15047c478bd9Sstevel@tonic-gate opt->nd_opt_type, abuf, pi->pi_name); 15057c478bd9Sstevel@tonic-gate return (_B_FALSE); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate optlen -= 8 * opt->nd_opt_len; 15087c478bd9Sstevel@tonic-gate if (optlen < 0) { 15097c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 15127c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 15137c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Too large option: type 0x%x len %u " 15167c478bd9Sstevel@tonic-gate "from %s on %s\n", 15177c478bd9Sstevel@tonic-gate opt->nd_opt_type, opt->nd_opt_len, 15187c478bd9Sstevel@tonic-gate abuf, pi->pi_name); 15197c478bd9Sstevel@tonic-gate return (_B_FALSE); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + 15227c478bd9Sstevel@tonic-gate 8 * opt->nd_opt_len); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate return (_B_TRUE); 15257c478bd9Sstevel@tonic-gate } 15266b27086dSdd193516 15276b27086dSdd193516 /* 15286b27086dSdd193516 * Update IsRouter Flag for Host turning into a router or vice-versa. 15296b27086dSdd193516 */ 15306b27086dSdd193516 static void 1531b0f490f4Smh138676 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from, 1532b0f490f4Smh138676 int isrouter) 15336b27086dSdd193516 { 15346b27086dSdd193516 struct lifreq lifr; 15356b27086dSdd193516 char abuf[INET6_ADDRSTRLEN]; 15366b27086dSdd193516 struct sockaddr_in6 *sin6; 15376b27086dSdd193516 15386b27086dSdd193516 /* check if valid flag is being set */ 15396b27086dSdd193516 if ((isrouter != NDF_ISROUTER_ON) && 15406b27086dSdd193516 (isrouter != NDF_ISROUTER_OFF)) { 15416b27086dSdd193516 logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter " 15426b27086dSdd193516 "flag %d\n", isrouter); 15436b27086dSdd193516 return; 15446b27086dSdd193516 } 15456b27086dSdd193516 15466b27086dSdd193516 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 15476b27086dSdd193516 bzero(sin6, sizeof (*sin6)); 15486b27086dSdd193516 sin6->sin6_family = AF_INET6; 15496b27086dSdd193516 sin6->sin6_addr = from->sin6_addr; 15506b27086dSdd193516 15516b27086dSdd193516 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 15526b27086dSdd193516 15536b27086dSdd193516 if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) { 1554b0f490f4Smh138676 if (errno == ESRCH) { 1555b0f490f4Smh138676 if (debug & D_IFSCAN) { 1556b0f490f4Smh138676 logmsg(LOG_DEBUG, 1557*ddadf64dSJanne Savikko "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER\n"); 1558b0f490f4Smh138676 } 1559b0f490f4Smh138676 } else { 15606b27086dSdd193516 logperror_pi(pi, "update_ra_flag: SIOCLIFGETND"); 1561b0f490f4Smh138676 } 15626b27086dSdd193516 } else { 15636b27086dSdd193516 /* 15646b27086dSdd193516 * The lif_nd_req structure has three state values to be used 15656b27086dSdd193516 * when changing/updating nces : 15666b27086dSdd193516 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla. 15676b27086dSdd193516 * 15686b27086dSdd193516 * In this case, we're updating an nce, without changing lla; 15696b27086dSdd193516 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that 15706b27086dSdd193516 * nce's state should not be affected by our flag change. 15716b27086dSdd193516 * 15726b27086dSdd193516 * The kernel implementation also expects the lnr_state_create 15736b27086dSdd193516 * field be always set, before processing ioctl request for NCE 15746b27086dSdd193516 * update. 15756b27086dSdd193516 * We use the state as STALE, while addressing the possibility 15766b27086dSdd193516 * of NCE deletion when ioctl with SIOCLIFGETND argument 15776b27086dSdd193516 * in earlier step is returned - further in such case we don't 15786b27086dSdd193516 * want to re-create the entry in the reachable state. 15796b27086dSdd193516 */ 15806b27086dSdd193516 lifr.lifr_nd.lnr_state_create = ND_STALE; 15816b27086dSdd193516 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 15826b27086dSdd193516 lifr.lifr_nd.lnr_flags = isrouter; 15836b27086dSdd193516 if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) { 15846b27086dSdd193516 logperror_pi(pi, "update_ra_flag: SIOCLIFSETND"); 15856b27086dSdd193516 } else { 15866b27086dSdd193516 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 15876b27086dSdd193516 abuf, sizeof (abuf)); 15886b27086dSdd193516 logmsg(LOG_INFO, "update_ra_flag: IsRouter flag " 15896b27086dSdd193516 "updated for %s\n", abuf); 15906b27086dSdd193516 } 15916b27086dSdd193516 } 15926b27086dSdd193516 } 1593