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
27*a36f6bdeSDan McDonald /*
28*a36f6bdeSDan McDonald * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
29*a36f6bdeSDan McDonald */
30*a36f6bdeSDan 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 *
find_ancillary(struct msghdr * msg,int cmsg_type)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
in_data(struct phyint * pi)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
incoming_rs(struct phyint * pi,struct nd_router_solicit * rs,int len,struct sockaddr_in6 * from)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
dhcp_op(struct phyint * pi,int type)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
start_dhcp(struct phyint * pi)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
release_dhcp(struct phyint * pi)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 /*
411*a36f6bdeSDan McDonald * Globals to check if we're seeing unusual hop counts in Router
412*a36f6bdeSDan McDonald * Advertisements (RAs). We record the hopcounts in the kernel using
413*a36f6bdeSDan McDonald * SIOCSLIFLNKINFO, but the kernel ignores these when actually setting IPv6
414*a36f6bdeSDan McDonald * hop counts for packets.
415*a36f6bdeSDan McDonald *
416*a36f6bdeSDan McDonald * RFC 3756 does mention the possibility of an adversary throttling down
417*a36f6bdeSDan McDonald * hopcounts using unsolicited RAs. These variables can be tuned with 'mdb -p'
418*a36f6bdeSDan McDonald * to reduce/increase our logging threshholds.
419*a36f6bdeSDan McDonald */
420*a36f6bdeSDan McDonald /* Really a boolean... if set, also log the offending sending address. */
421*a36f6bdeSDan McDonald int bad_hopcount_record_addr = 0;
422*a36f6bdeSDan McDonald /* Anything less triggers a warning. Set to 0 to disable. */
423*a36f6bdeSDan McDonald int bad_hopcount_threshhold = 16;
424*a36f6bdeSDan McDonald /* Number of packets received below the threshhold. */
425*a36f6bdeSDan McDonald uint64_t bad_hopcount_packets;
426*a36f6bdeSDan McDonald
427*a36f6bdeSDan 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
incoming_ra(struct phyint * pi,struct nd_router_advert * ra,int len,struct sockaddr_in6 * from,boolean_t loopback)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;
457*a36f6bdeSDan McDonald
458*a36f6bdeSDan McDonald if (pi->pi_CurHopLimit < bad_hopcount_threshhold) {
459*a36f6bdeSDan McDonald char abuf[INET6_ADDRSTRLEN];
460*a36f6bdeSDan McDonald
461*a36f6bdeSDan McDonald bad_hopcount_packets++;
462*a36f6bdeSDan McDonald logmsg(LOG_ALERT,
463*a36f6bdeSDan McDonald "Low hopcount %d received on %s%s%s\n",
464*a36f6bdeSDan McDonald pi->pi_CurHopLimit, pi->pi_name,
465*a36f6bdeSDan McDonald bad_hopcount_record_addr ? " from " : "",
466*a36f6bdeSDan McDonald bad_hopcount_record_addr ?
467*a36f6bdeSDan McDonald inet_ntop(AF_INET6, &from->sin6_addr, abuf,
468*a36f6bdeSDan McDonald INET6_ADDRSTRLEN) : "");
469*a36f6bdeSDan 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
incoming_prefix_opt(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from,boolean_t loopback)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
incoming_prefix_onlink(struct phyint * pi,uchar_t * opt)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
incoming_prefix_onlink_process(struct prefix * pr,uchar_t * opt)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
incoming_prefix_stateful(struct phyint * pi,uchar_t * opt)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
incoming_prefix_addrconf(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from,boolean_t loopback)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
incoming_prefix_addrconf_process(struct phyint * pi,struct prefix * pr,uchar_t * opt,struct sockaddr_in6 * from,boolean_t loopback,boolean_t new_prefix)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
incoming_mtu_opt(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from)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
incoming_lla_opt(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from,int isrouter)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
verify_ra_consistency(struct phyint * pi,struct nd_router_advert * ra,int len,struct sockaddr_in6 * from)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
verify_prefix_opt(struct phyint * pi,uchar_t * opt,char * frombuf)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
verify_mtu_opt(struct phyint * pi,uchar_t * opt,char * frombuf)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
verify_opt_len(struct nd_opt_hdr * opt,int optlen,struct phyint * pi,struct sockaddr_in6 * from)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
update_ra_flag(const struct phyint * pi,const struct sockaddr_in6 * from,int isrouter)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,
1557b0f490f4Smh138676 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER");
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