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
58121d73fSseb * Common Development and Distribution License (the "License").
68121d73fSseb * 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
20e11c3f44Smeem *
2164639aafSDarren Reed * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
22*2514b110SRyan Goodfellow * Copyright 2022 Oxide Computer Company
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate #include "defs.h"
267c478bd9Sstevel@tonic-gate #include "tables.h"
277c478bd9Sstevel@tonic-gate #include <fcntl.h>
283173664eSapersson #include <sys/un.h>
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate static void initlog(void);
317c478bd9Sstevel@tonic-gate static void run_timeouts(void);
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate static void advertise(struct sockaddr_in6 *sin6, struct phyint *pi,
347c478bd9Sstevel@tonic-gate boolean_t no_prefixes);
357c478bd9Sstevel@tonic-gate static void solicit(struct sockaddr_in6 *sin6, struct phyint *pi);
367c478bd9Sstevel@tonic-gate static void initifs(boolean_t first);
377c478bd9Sstevel@tonic-gate static void check_if_removed(struct phyint *pi);
387c478bd9Sstevel@tonic-gate static void loopback_ra_enqueue(struct phyint *pi,
397c478bd9Sstevel@tonic-gate struct nd_router_advert *ra, int len);
407c478bd9Sstevel@tonic-gate static void loopback_ra_dequeue(void);
417c478bd9Sstevel@tonic-gate static void check_daemonize(void);
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate struct in6_addr all_nodes_mcast = { { 0xff, 0x2, 0x0, 0x0,
447c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
457c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
467c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } };
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate struct in6_addr all_routers_mcast = { { 0xff, 0x2, 0x0, 0x0,
497c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
507c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
517c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } };
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate static struct sockaddr_in6 v6allnodes = { AF_INET6, 0, 0,
547c478bd9Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0,
557c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
567c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
577c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } };
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate static struct sockaddr_in6 v6allrouters = { AF_INET6, 0, 0,
607c478bd9Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0,
617c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
627c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0,
637c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } };
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate static char **argv0; /* Saved for re-exec on SIGHUP */
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate static uint64_t packet[(IP_MAXPACKET + 1)/8];
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate static int show_ifs = 0;
707c478bd9Sstevel@tonic-gate static boolean_t already_daemonized = _B_FALSE;
717c478bd9Sstevel@tonic-gate int debug = 0;
727c478bd9Sstevel@tonic-gate int no_loopback = 0; /* Do not send RA packets to ourselves */
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate * Size of routing socket message used by in.ndpd which includes the header,
767c478bd9Sstevel@tonic-gate * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6)
777c478bd9Sstevel@tonic-gate * plus space for the RTA_IFP (a sockaddr_dl).
787c478bd9Sstevel@tonic-gate */
797c478bd9Sstevel@tonic-gate #define NDP_RTM_MSGLEN sizeof (struct rt_msghdr) + \
807c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \
817c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \
827c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \
837c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl)
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * These are referenced externally in tables.c in order to fill in the
877c478bd9Sstevel@tonic-gate * dynamic portions of the routing socket message and then to send the message
887c478bd9Sstevel@tonic-gate * itself.
897c478bd9Sstevel@tonic-gate */
907c478bd9Sstevel@tonic-gate int rtsock = -1; /* Routing socket */
917c478bd9Sstevel@tonic-gate struct rt_msghdr *rt_msg; /* Routing socket message */
927c478bd9Sstevel@tonic-gate struct sockaddr_in6 *rta_gateway; /* RTA_GATEWAY sockaddr */
937c478bd9Sstevel@tonic-gate struct sockaddr_dl *rta_ifp; /* RTA_IFP sockaddr */
946e91bba0SGirish Moodalbail
956e91bba0SGirish Moodalbail /*
966e91bba0SGirish Moodalbail * These sockets are used internally in this file.
976e91bba0SGirish Moodalbail */
986e91bba0SGirish Moodalbail static int mibsock = -1; /* mib request socket */
996e91bba0SGirish Moodalbail static int cmdsock = -1; /* command socket */
1006e91bba0SGirish Moodalbail
1016e91bba0SGirish Moodalbail static int ndpd_setup_cmd_listener(void);
1026e91bba0SGirish Moodalbail static void ndpd_cmd_handler(int);
1036e91bba0SGirish Moodalbail static int ndpd_process_cmd(int, ipadm_ndpd_msg_t *);
1046e91bba0SGirish Moodalbail static int ndpd_send_error(int, int);
1056e91bba0SGirish Moodalbail static int ndpd_set_autoconf(const char *, boolean_t);
1066e91bba0SGirish Moodalbail static int ndpd_create_addrs(const char *, struct sockaddr_in6, int,
1076e91bba0SGirish Moodalbail boolean_t, boolean_t, char *);
1086e91bba0SGirish Moodalbail static int ndpd_delete_addrs(const char *);
1096e91bba0SGirish Moodalbail static int phyint_check_ipadm_intfid(struct phyint *);
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate * Return the current time in milliseconds truncated to
1137c478bd9Sstevel@tonic-gate * fit in an integer.
1147c478bd9Sstevel@tonic-gate */
1157c478bd9Sstevel@tonic-gate uint_t
getcurrenttime(void)1167c478bd9Sstevel@tonic-gate getcurrenttime(void)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate struct timeval tp;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate if (gettimeofday(&tp, NULL) < 0) {
1217c478bd9Sstevel@tonic-gate logperror("getcurrenttime: gettimeofday failed");
1227c478bd9Sstevel@tonic-gate exit(1);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate return (tp.tv_sec * 1000 + tp.tv_usec / 1000);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate * Output a preformated packet from the packet[] buffer.
1297c478bd9Sstevel@tonic-gate */
1307c478bd9Sstevel@tonic-gate static void
sendpacket(struct sockaddr_in6 * sin6,int sock,int size,int flags)1317c478bd9Sstevel@tonic-gate sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate int cc;
1347c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN];
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate cc = sendto(sock, (char *)packet, size, flags,
137e11c3f44Smeem (struct sockaddr *)sin6, sizeof (*sin6));
1387c478bd9Sstevel@tonic-gate if (cc < 0 || cc != size) {
1397c478bd9Sstevel@tonic-gate if (cc < 0) {
1407c478bd9Sstevel@tonic-gate logperror("sendpacket: sendto");
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "sendpacket: wrote %s %d chars, ret=%d\n",
1437c478bd9Sstevel@tonic-gate inet_ntop(sin6->sin6_family,
1447c478bd9Sstevel@tonic-gate (void *)&sin6->sin6_addr,
1457c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)),
1467c478bd9Sstevel@tonic-gate size, cc);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate
150e11c3f44Smeem /*
151e11c3f44Smeem * If possible, place an ND_OPT_SOURCE_LINKADDR option at `optp'.
152e11c3f44Smeem * Return the number of bytes placed in the option.
153e11c3f44Smeem */
154e11c3f44Smeem static uint_t
add_opt_lla(struct phyint * pi,struct nd_opt_lla * optp)155e11c3f44Smeem add_opt_lla(struct phyint *pi, struct nd_opt_lla *optp)
156e11c3f44Smeem {
157e11c3f44Smeem uint_t optlen;
158e11c3f44Smeem uint_t hwaddrlen;
159e11c3f44Smeem struct lifreq lifr;
160e11c3f44Smeem
161e11c3f44Smeem /* If this phyint doesn't have a link-layer address, bail */
162e11c3f44Smeem if (phyint_get_lla(pi, &lifr) == -1)
163e11c3f44Smeem return (0);
164e11c3f44Smeem
165e11c3f44Smeem hwaddrlen = lifr.lifr_nd.lnr_hdw_len;
166e11c3f44Smeem /* roundup to multiple of 8 and make padding zero */
167e11c3f44Smeem optlen = ((sizeof (struct nd_opt_hdr) + hwaddrlen + 7) / 8) * 8;
168e11c3f44Smeem bzero(optp, optlen);
169e11c3f44Smeem optp->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
170e11c3f44Smeem optp->nd_opt_lla_len = optlen / 8;
171e11c3f44Smeem bcopy(lifr.lifr_nd.lnr_hdw_addr, optp->nd_opt_lla_hdw_addr, hwaddrlen);
172e11c3f44Smeem
173e11c3f44Smeem return (optlen);
174e11c3f44Smeem }
175e11c3f44Smeem
1767c478bd9Sstevel@tonic-gate /* Send a Router Solicitation */
1777c478bd9Sstevel@tonic-gate static void
solicit(struct sockaddr_in6 * sin6,struct phyint * pi)1787c478bd9Sstevel@tonic-gate solicit(struct sockaddr_in6 *sin6, struct phyint *pi)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate int packetlen = 0;
1817c478bd9Sstevel@tonic-gate struct nd_router_solicit *rs = (struct nd_router_solicit *)packet;
1827c478bd9Sstevel@tonic-gate char *pptr = (char *)packet;
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate rs->nd_rs_type = ND_ROUTER_SOLICIT;
1857c478bd9Sstevel@tonic-gate rs->nd_rs_code = 0;
1867c478bd9Sstevel@tonic-gate rs->nd_rs_cksum = htons(0);
1877c478bd9Sstevel@tonic-gate rs->nd_rs_reserved = htonl(0);
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate packetlen += sizeof (*rs);
1907c478bd9Sstevel@tonic-gate pptr += sizeof (*rs);
1917c478bd9Sstevel@tonic-gate
192e11c3f44Smeem /* add options */
193e11c3f44Smeem packetlen += add_opt_lla(pi, (struct nd_opt_lla *)pptr);
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) {
1967c478bd9Sstevel@tonic-gate print_route_sol("Sending solicitation to ", pi, rs, packetlen,
1977c478bd9Sstevel@tonic-gate sin6);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate * Send a (set of) Router Advertisements and feed them back to ourselves
2047c478bd9Sstevel@tonic-gate * for processing. Unless no_prefixes is set all prefixes are included.
2057c478bd9Sstevel@tonic-gate * If there are too many prefix options to fit in one packet multiple
2067c478bd9Sstevel@tonic-gate * packets will be sent - each containing a subset of the prefix options.
2077c478bd9Sstevel@tonic-gate */
2087c478bd9Sstevel@tonic-gate static void
advertise(struct sockaddr_in6 * sin6,struct phyint * pi,boolean_t no_prefixes)2097c478bd9Sstevel@tonic-gate advertise(struct sockaddr_in6 *sin6, struct phyint *pi, boolean_t no_prefixes)
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po;
2127c478bd9Sstevel@tonic-gate char *pptr = (char *)packet;
2137c478bd9Sstevel@tonic-gate struct nd_router_advert *ra;
2147c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr;
2157c478bd9Sstevel@tonic-gate int packetlen = 0;
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate ra = (struct nd_router_advert *)pptr;
2187c478bd9Sstevel@tonic-gate ra->nd_ra_type = ND_ROUTER_ADVERT;
2197c478bd9Sstevel@tonic-gate ra->nd_ra_code = 0;
2207c478bd9Sstevel@tonic-gate ra->nd_ra_cksum = htons(0);
2217c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit = pi->pi_AdvCurHopLimit;
2227c478bd9Sstevel@tonic-gate ra->nd_ra_flags_reserved = 0;
2237c478bd9Sstevel@tonic-gate if (pi->pi_AdvManagedFlag)
2247c478bd9Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
2257c478bd9Sstevel@tonic-gate if (pi->pi_AdvOtherConfigFlag)
2267c478bd9Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV)
2297c478bd9Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(0);
2307c478bd9Sstevel@tonic-gate else
2317c478bd9Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(pi->pi_AdvDefaultLifetime);
2327c478bd9Sstevel@tonic-gate ra->nd_ra_reachable = htonl(pi->pi_AdvReachableTime);
2337c478bd9Sstevel@tonic-gate ra->nd_ra_retransmit = htonl(pi->pi_AdvRetransTimer);
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate packetlen = sizeof (*ra);
2367c478bd9Sstevel@tonic-gate pptr += sizeof (*ra);
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) {
2397c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) {
2407c478bd9Sstevel@tonic-gate print_route_adv("Sending advert (FINAL) to ", pi,
2417c478bd9Sstevel@tonic-gate ra, packetlen, sin6);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0);
2447c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */
2457c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen);
2467c478bd9Sstevel@tonic-gate return;
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate
249e11c3f44Smeem /* add options */
250e11c3f44Smeem packetlen += add_opt_lla(pi, (struct nd_opt_lla *)pptr);
251e11c3f44Smeem pptr = (char *)packet + packetlen;
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0) {
2547c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)pptr;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_type = ND_OPT_MTU;
2577c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_len = sizeof (struct nd_opt_mtu) / 8;
2587c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_reserved = 0;
2597c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_mtu = htonl(pi->pi_AdvLinkMTU);
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate packetlen += sizeof (struct nd_opt_mtu);
2627c478bd9Sstevel@tonic-gate pptr += sizeof (struct nd_opt_mtu);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate if (no_prefixes) {
2667c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) {
2677c478bd9Sstevel@tonic-gate print_route_adv("Sending advert to ", pi,
2687c478bd9Sstevel@tonic-gate ra, packetlen, sin6);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0);
2717c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */
2727c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen);
2737c478bd9Sstevel@tonic-gate return;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr;
2777c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL;
2787c478bd9Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) {
2797c478bd9Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvOnLinkFlag &&
2807c478bd9Sstevel@tonic-gate !adv_pr->adv_pr_AdvAutonomousFlag) {
2817c478bd9Sstevel@tonic-gate continue;
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate * If the prefix doesn't fit in packet send
2867c478bd9Sstevel@tonic-gate * what we have so far and start with new packet.
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate if (packetlen + sizeof (*po) >
2897c478bd9Sstevel@tonic-gate pi->pi_LinkMTU - sizeof (struct ip6_hdr)) {
2907c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) {
2917c478bd9Sstevel@tonic-gate print_route_adv("Sending advert "
2927c478bd9Sstevel@tonic-gate "(FRAG) to ",
2937c478bd9Sstevel@tonic-gate pi, ra, packetlen, sin6);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0);
2967c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */
2977c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen);
2987c478bd9Sstevel@tonic-gate packetlen = sizeof (*ra);
2997c478bd9Sstevel@tonic-gate pptr = (char *)packet + sizeof (*ra);
3007c478bd9Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr;
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate po->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
3037c478bd9Sstevel@tonic-gate po->nd_opt_pi_len = sizeof (*po)/8;
3047c478bd9Sstevel@tonic-gate po->nd_opt_pi_flags_reserved = 0;
3057c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvOnLinkFlag) {
3067c478bd9Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |=
3077c478bd9Sstevel@tonic-gate ND_OPT_PI_FLAG_ONLINK;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvAutonomousFlag) {
3107c478bd9Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |=
3117c478bd9Sstevel@tonic-gate ND_OPT_PI_FLAG_AUTO;
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate po->nd_opt_pi_prefix_len = adv_pr->adv_pr_prefix_len;
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate * If both Adv*Expiration and Adv*Lifetime are
3167c478bd9Sstevel@tonic-gate * set we prefer the former and make the lifetime
3177c478bd9Sstevel@tonic-gate * decrement in real time.
3187c478bd9Sstevel@tonic-gate */
3197c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) {
3207c478bd9Sstevel@tonic-gate po->nd_opt_pi_valid_time =
3217c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidExpiration);
3227c478bd9Sstevel@tonic-gate } else {
3237c478bd9Sstevel@tonic-gate po->nd_opt_pi_valid_time =
3247c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidLifetime);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) {
3277c478bd9Sstevel@tonic-gate po->nd_opt_pi_preferred_time =
3287c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredExpiration);
3297c478bd9Sstevel@tonic-gate } else {
3307c478bd9Sstevel@tonic-gate po->nd_opt_pi_preferred_time =
3317c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredLifetime);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate po->nd_opt_pi_reserved2 = htonl(0);
3347c478bd9Sstevel@tonic-gate po->nd_opt_pi_prefix = adv_pr->adv_pr_prefix;
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate po++;
3377c478bd9Sstevel@tonic-gate packetlen += sizeof (*po);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) {
3407c478bd9Sstevel@tonic-gate print_route_adv("Sending advert to ", pi,
3417c478bd9Sstevel@tonic-gate ra, packetlen, sin6);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0);
3447c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */
3457c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen);
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate /* Poll support */
3497c478bd9Sstevel@tonic-gate static int pollfd_num = 0; /* Allocated and initialized */
3507c478bd9Sstevel@tonic-gate static struct pollfd *pollfds = NULL;
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate * Add fd to the set being polled. Returns 0 if ok; -1 if failed.
3547c478bd9Sstevel@tonic-gate */
3557c478bd9Sstevel@tonic-gate int
poll_add(int fd)3567c478bd9Sstevel@tonic-gate poll_add(int fd)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate int i;
3597c478bd9Sstevel@tonic-gate int new_num;
3607c478bd9Sstevel@tonic-gate struct pollfd *newfds;
3613173664eSapersson
3627c478bd9Sstevel@tonic-gate /* Check if already present */
3637c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) {
3647c478bd9Sstevel@tonic-gate if (pollfds[i].fd == fd)
3657c478bd9Sstevel@tonic-gate return (0);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate /* Check for empty spot already present */
3687c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) {
3697c478bd9Sstevel@tonic-gate if (pollfds[i].fd == -1) {
3707c478bd9Sstevel@tonic-gate pollfds[i].fd = fd;
3717c478bd9Sstevel@tonic-gate return (0);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /* Allocate space for 32 more fds and initialize to -1 */
3767c478bd9Sstevel@tonic-gate new_num = pollfd_num + 32;
3777c478bd9Sstevel@tonic-gate newfds = realloc(pollfds, new_num * sizeof (struct pollfd));
3787c478bd9Sstevel@tonic-gate if (newfds == NULL) {
3796e91bba0SGirish Moodalbail logperror("realloc");
3807c478bd9Sstevel@tonic-gate return (-1);
3817c478bd9Sstevel@tonic-gate }
3823173664eSapersson
3833173664eSapersson newfds[pollfd_num].fd = fd;
3843173664eSapersson newfds[pollfd_num++].events = POLLIN;
3853173664eSapersson
3867c478bd9Sstevel@tonic-gate for (i = pollfd_num; i < new_num; i++) {
3877c478bd9Sstevel@tonic-gate newfds[i].fd = -1;
3887c478bd9Sstevel@tonic-gate newfds[i].events = POLLIN;
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate pollfd_num = new_num;
3917c478bd9Sstevel@tonic-gate pollfds = newfds;
3923173664eSapersson return (0);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate * Remove fd from the set being polled. Returns 0 if ok; -1 if failed.
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate int
poll_remove(int fd)3997c478bd9Sstevel@tonic-gate poll_remove(int fd)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate int i;
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate /* Check if already present */
4047c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) {
4057c478bd9Sstevel@tonic-gate if (pollfds[i].fd == fd) {
4067c478bd9Sstevel@tonic-gate pollfds[i].fd = -1;
4077c478bd9Sstevel@tonic-gate return (0);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate return (-1);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate * Extract information about the ifname (either a physical interface and
4157c478bd9Sstevel@tonic-gate * the ":0" logical interface or just a logical interface).
4167c478bd9Sstevel@tonic-gate * If the interface (still) exists in kernel set pr_in_use
4177c478bd9Sstevel@tonic-gate * for caller to be able to detect interfaces that are removed.
4187c478bd9Sstevel@tonic-gate * Starts sending advertisements/solicitations when new physical interfaces
4197c478bd9Sstevel@tonic-gate * are detected.
4207c478bd9Sstevel@tonic-gate */
4217c478bd9Sstevel@tonic-gate static void
if_process(int s,char * ifname,boolean_t first)4227c478bd9Sstevel@tonic-gate if_process(int s, char *ifname, boolean_t first)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate struct lifreq lifr;
4257c478bd9Sstevel@tonic-gate struct phyint *pi;
4267c478bd9Sstevel@tonic-gate struct prefix *pr;
4277c478bd9Sstevel@tonic-gate char *cp;
4287c478bd9Sstevel@tonic-gate char phyintname[LIFNAMSIZ + 1];
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN)
4317c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process(%s)\n", ifname);
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
4347c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
4357c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
4367c478bd9Sstevel@tonic-gate if (errno == ENXIO) {
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate * Interface has disappeared
4397c478bd9Sstevel@tonic-gate */
4407c478bd9Sstevel@tonic-gate return;
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate logperror("if_process: ioctl (get interface flags)");
4437c478bd9Sstevel@tonic-gate return;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate /*
4471cb875aeSCathy Zhou * Ignore loopback, point-to-multipoint and VRRP interfaces.
4481cb875aeSCathy Zhou * The IP addresses over VRRP interfaces cannot be auto-configured.
4497c478bd9Sstevel@tonic-gate * Point-to-point interfaces always have IFF_MULTICAST set.
4507c478bd9Sstevel@tonic-gate */
4517c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_MULTICAST) ||
4521cb875aeSCathy Zhou (lifr.lifr_flags & (IFF_LOOPBACK|IFF_VRRP))) {
4537c478bd9Sstevel@tonic-gate return;
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_IPV6))
4577c478bd9Sstevel@tonic-gate return;
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate (void) strncpy(phyintname, ifname, sizeof (phyintname));
4607c478bd9Sstevel@tonic-gate phyintname[sizeof (phyintname) - 1] = '\0';
4617c478bd9Sstevel@tonic-gate if ((cp = strchr(phyintname, IF_SEPARATOR)) != NULL) {
4627c478bd9Sstevel@tonic-gate *cp = '\0';
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate pi = phyint_lookup(phyintname);
4667c478bd9Sstevel@tonic-gate if (pi == NULL) {
4677c478bd9Sstevel@tonic-gate pi = phyint_create(phyintname);
4687c478bd9Sstevel@tonic-gate if (pi == NULL) {
4697c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n");
4707c478bd9Sstevel@tonic-gate return;
4717c478bd9Sstevel@tonic-gate }
4726e91bba0SGirish Moodalbail /*
4736e91bba0SGirish Moodalbail * if in.ndpd is restarted, check with ipmgmtd if there is any
4746e91bba0SGirish Moodalbail * interface id to be configured for this interface.
4756e91bba0SGirish Moodalbail */
4766e91bba0SGirish Moodalbail if (first) {
4776e91bba0SGirish Moodalbail if (phyint_check_ipadm_intfid(pi) == -1)
4786e91bba0SGirish Moodalbail logmsg(LOG_ERR, "Could not get ipadm info\n");
4796e91bba0SGirish Moodalbail }
4806e91bba0SGirish Moodalbail } else {
4816e91bba0SGirish Moodalbail /*
4826e91bba0SGirish Moodalbail * if the phyint already exists, synchronize it with
4836e91bba0SGirish Moodalbail * the kernel state. For a newly created phyint, phyint_create
4846e91bba0SGirish Moodalbail * calls phyint_init_from_k().
4856e91bba0SGirish Moodalbail */
4866e91bba0SGirish Moodalbail (void) phyint_init_from_k(pi);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate if (pi->pi_sock == -1 && !(pi->pi_kernel_state & PI_PRESENT)) {
4897c478bd9Sstevel@tonic-gate /* Interface is not yet present */
4907c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) {
4917c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process: interface not yet "
4927c478bd9Sstevel@tonic-gate "present %s\n", pi->pi_name);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate return;
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate if (pi->pi_sock != -1) {
4987c478bd9Sstevel@tonic-gate if (poll_add(pi->pi_sock) == -1) {
4997c478bd9Sstevel@tonic-gate /*
5007c478bd9Sstevel@tonic-gate * reset state.
5017c478bd9Sstevel@tonic-gate */
5027c478bd9Sstevel@tonic-gate phyint_cleanup(pi);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate * Check if IFF_ROUTER has been turned off in kernel in which
5087c478bd9Sstevel@tonic-gate * case we have to turn off AdvSendAdvertisements.
5097c478bd9Sstevel@tonic-gate * The kernel will automatically turn off IFF_ROUTER if
5107c478bd9Sstevel@tonic-gate * ip6_forwarding is turned off.
5117c478bd9Sstevel@tonic-gate * Note that we do not switch back should IFF_ROUTER be turned on.
5127c478bd9Sstevel@tonic-gate */
5137c478bd9Sstevel@tonic-gate if (!first &&
5147c478bd9Sstevel@tonic-gate pi->pi_AdvSendAdvertisements && !(pi->pi_flags & IFF_ROUTER)) {
5157c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "No longer a router on %s\n", pi->pi_name);
5167c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV);
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate pi->pi_AdvSendAdvertisements = 0;
5197c478bd9Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT;
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate * Send advertisments and solicitation only if the interface is
5247c478bd9Sstevel@tonic-gate * present in the kernel.
5257c478bd9Sstevel@tonic-gate */
5267c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) {
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) {
5297c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV)
5307c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_INIT_ADV);
5317c478bd9Sstevel@tonic-gate } else {
5327c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT)
5337c478bd9Sstevel@tonic-gate check_to_solicit(pi, START_INIT_SOLICIT);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * Track static kernel prefixes to prevent in.ndpd from clobbering
5397c478bd9Sstevel@tonic-gate * them by creating a struct prefix for each prefix detected in the
5407c478bd9Sstevel@tonic-gate * kernel.
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate pr = prefix_lookup_name(pi, ifname);
5437c478bd9Sstevel@tonic-gate if (pr == NULL) {
5447c478bd9Sstevel@tonic-gate pr = prefix_create_name(pi, ifname);
5457c478bd9Sstevel@tonic-gate if (pr == NULL) {
5467c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n");
5477c478bd9Sstevel@tonic-gate return;
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate if (prefix_init_from_k(pr) == -1) {
5507c478bd9Sstevel@tonic-gate prefix_delete(pr);
5517c478bd9Sstevel@tonic-gate return;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate /* Detect prefixes which are removed */
5557c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != 0)
5567c478bd9Sstevel@tonic-gate pr->pr_in_use = _B_TRUE;
55769bb4bb4Scarlsonj
55869bb4bb4Scarlsonj if ((lifr.lifr_flags & IFF_DUPLICATE) &&
559d04ccbb3Scarlsonj !(lifr.lifr_flags & IFF_DHCPRUNNING) &&
56069bb4bb4Scarlsonj (pr->pr_flags & IFF_TEMPORARY)) {
56169bb4bb4Scarlsonj in6_addr_t *token;
56269bb4bb4Scarlsonj int i;
56369bb4bb4Scarlsonj char abuf[INET6_ADDRSTRLEN];
56469bb4bb4Scarlsonj
56569bb4bb4Scarlsonj if (++pr->pr_attempts >= MAX_DAD_FAILURES) {
56669bb4bb4Scarlsonj logmsg(LOG_ERR, "%s: token %s is duplicate after %d "
56769bb4bb4Scarlsonj "attempts; disabling temporary addresses on %s",
56869bb4bb4Scarlsonj pr->pr_name, inet_ntop(AF_INET6,
56969bb4bb4Scarlsonj (void *)&pi->pi_tmp_token, abuf, sizeof (abuf)),
57069bb4bb4Scarlsonj pr->pr_attempts, pi->pi_name);
57169bb4bb4Scarlsonj pi->pi_TmpAddrsEnabled = 0;
57269bb4bb4Scarlsonj tmptoken_delete(pi);
57369bb4bb4Scarlsonj prefix_delete(pr);
57469bb4bb4Scarlsonj return;
57569bb4bb4Scarlsonj }
57669bb4bb4Scarlsonj logmsg(LOG_WARNING, "%s: token %s is duplicate; trying again",
57769bb4bb4Scarlsonj pr->pr_name, inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token,
57869bb4bb4Scarlsonj abuf, sizeof (abuf)));
57969bb4bb4Scarlsonj if (!tmptoken_create(pi)) {
58069bb4bb4Scarlsonj prefix_delete(pr);
58169bb4bb4Scarlsonj return;
58269bb4bb4Scarlsonj }
58369bb4bb4Scarlsonj token = &pi->pi_tmp_token;
58469bb4bb4Scarlsonj for (i = 0; i < 16; i++) {
58569bb4bb4Scarlsonj /*
58669bb4bb4Scarlsonj * prefix_create ensures that pr_prefix has all-zero
58769bb4bb4Scarlsonj * bits after prefixlen.
58869bb4bb4Scarlsonj */
58969bb4bb4Scarlsonj pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] |
59069bb4bb4Scarlsonj token->s6_addr[i];
59169bb4bb4Scarlsonj }
59269bb4bb4Scarlsonj if (prefix_lookup_addr_match(pr) != NULL) {
59369bb4bb4Scarlsonj prefix_delete(pr);
59469bb4bb4Scarlsonj return;
59569bb4bb4Scarlsonj }
59669bb4bb4Scarlsonj pr->pr_CreateTime = getcurrenttime() / MILLISEC;
59769bb4bb4Scarlsonj /*
59869bb4bb4Scarlsonj * We've got a new token. Clearing PR_AUTO causes
59969bb4bb4Scarlsonj * prefix_update_k to bring the interface up and set the
60069bb4bb4Scarlsonj * address.
60169bb4bb4Scarlsonj */
60269bb4bb4Scarlsonj pr->pr_kernel_state &= ~PR_AUTO;
60369bb4bb4Scarlsonj prefix_update_k(pr);
604