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 * 21*6e91bba0SGirish Moodalbail * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 227c478bd9Sstevel@tonic-gate * Use is subject to license terms. 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 */ 94*6e91bba0SGirish Moodalbail 95*6e91bba0SGirish Moodalbail /* 96*6e91bba0SGirish Moodalbail * These sockets are used internally in this file. 97*6e91bba0SGirish Moodalbail */ 98*6e91bba0SGirish Moodalbail static int mibsock = -1; /* mib request socket */ 99*6e91bba0SGirish Moodalbail static int cmdsock = -1; /* command socket */ 100*6e91bba0SGirish Moodalbail 101*6e91bba0SGirish Moodalbail static int ndpd_setup_cmd_listener(void); 102*6e91bba0SGirish Moodalbail static void ndpd_cmd_handler(int); 103*6e91bba0SGirish Moodalbail static int ndpd_process_cmd(int, ipadm_ndpd_msg_t *); 104*6e91bba0SGirish Moodalbail static int ndpd_send_error(int, int); 105*6e91bba0SGirish Moodalbail static int ndpd_set_autoconf(const char *, boolean_t); 106*6e91bba0SGirish Moodalbail static int ndpd_create_addrs(const char *, struct sockaddr_in6, int, 107*6e91bba0SGirish Moodalbail boolean_t, boolean_t, char *); 108*6e91bba0SGirish Moodalbail static int ndpd_delete_addrs(const char *); 109*6e91bba0SGirish 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 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 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 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 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 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 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) { 379*6e91bba0SGirish 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 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 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 } 472*6e91bba0SGirish Moodalbail /* 473*6e91bba0SGirish Moodalbail * if in.ndpd is restarted, check with ipmgmtd if there is any 474*6e91bba0SGirish Moodalbail * interface id to be configured for this interface. 475*6e91bba0SGirish Moodalbail */ 476*6e91bba0SGirish Moodalbail if (first) { 477*6e91bba0SGirish Moodalbail if (phyint_check_ipadm_intfid(pi) == -1) 478*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "Could not get ipadm info\n"); 479*6e91bba0SGirish Moodalbail } 480*6e91bba0SGirish Moodalbail } else { 481*6e91bba0SGirish Moodalbail /* 482*6e91bba0SGirish Moodalbail * if the phyint already exists, synchronize it with 483*6e91bba0SGirish Moodalbail * the kernel state. For a newly created phyint, phyint_create 484*6e91bba0SGirish Moodalbail * calls phyint_init_from_k(). 485*6e91bba0SGirish Moodalbail */ 486*6e91bba0SGirish 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); 60469bb4bb4Scarlsonj } 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate static int ifsock = -1; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* 6107c478bd9Sstevel@tonic-gate * Scan all interfaces to detect changes as well as new and deleted intefaces 6117c478bd9Sstevel@tonic-gate * 'first' is set for the initial call only. Do not effect anything. 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate static void 6147c478bd9Sstevel@tonic-gate initifs(boolean_t first) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate char *buf; 6177c478bd9Sstevel@tonic-gate int bufsize; 6187c478bd9Sstevel@tonic-gate int numifs; 6197c478bd9Sstevel@tonic-gate int n; 6207c478bd9Sstevel@tonic-gate struct lifnum lifn; 6217c478bd9Sstevel@tonic-gate struct lifconf lifc; 6227c478bd9Sstevel@tonic-gate struct lifreq *lifr; 6237c478bd9Sstevel@tonic-gate struct phyint *pi; 6247c478bd9Sstevel@tonic-gate struct phyint *next_pi; 6257c478bd9Sstevel@tonic-gate struct prefix *pr; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) 6287c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Reading interface configuration\n"); 6297c478bd9Sstevel@tonic-gate if (ifsock < 0) { 6307c478bd9Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 6317c478bd9Sstevel@tonic-gate if (ifsock < 0) { 6327c478bd9Sstevel@tonic-gate logperror("initifs: socket"); 6337c478bd9Sstevel@tonic-gate return; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate lifn.lifn_family = AF_INET6; 6377c478bd9Sstevel@tonic-gate lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6387c478bd9Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFNUM, (char *)&lifn) < 0) { 6397c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get interface numbers)"); 6407c478bd9Sstevel@tonic-gate return; 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate numifs = lifn.lifn_count; 6437c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct lifreq); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate buf = (char *)malloc(bufsize); 6467c478bd9Sstevel@tonic-gate if (buf == NULL) { 6477c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "initifs: out of memory\n"); 6487c478bd9Sstevel@tonic-gate return; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* 6527c478bd9Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 6537c478bd9Sstevel@tonic-gate * which have disappeared from the kernel. 6547c478bd9Sstevel@tonic-gate * if_process will set pr_in_use when it finds the interface 6557c478bd9Sstevel@tonic-gate * in the kernel. 6567c478bd9Sstevel@tonic-gate */ 6577c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 6587c478bd9Sstevel@tonic-gate /* 6597c478bd9Sstevel@tonic-gate * Before re-examining the state of the interfaces, 6607c478bd9Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 6617c478bd9Sstevel@tonic-gate */ 6627c478bd9Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 6637c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 6647c478bd9Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate lifc.lifc_family = AF_INET6; 6697c478bd9Sstevel@tonic-gate lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6707c478bd9Sstevel@tonic-gate lifc.lifc_len = bufsize; 6717c478bd9Sstevel@tonic-gate lifc.lifc_buf = buf; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFCONF, (char *)&lifc) < 0) { 6747c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get interface configuration)"); 6757c478bd9Sstevel@tonic-gate free(buf); 6767c478bd9Sstevel@tonic-gate return; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate lifr = (struct lifreq *)lifc.lifc_req; 6807c478bd9Sstevel@tonic-gate for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifr++) 6817c478bd9Sstevel@tonic-gate if_process(ifsock, lifr->lifr_name, first); 6827c478bd9Sstevel@tonic-gate free(buf); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * Detect phyints that have been removed from the kernel. 6867c478bd9Sstevel@tonic-gate * Since we can't recreate it here (would require ifconfig plumb 6877c478bd9Sstevel@tonic-gate * logic) we just terminate use of that phyint. 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 6907c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * If interface (still) exists in kernel, set 6937c478bd9Sstevel@tonic-gate * pi_state to indicate that. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 6967c478bd9Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate check_if_removed(pi); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate if (show_ifs) 7027c478bd9Sstevel@tonic-gate phyint_print_all(); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * Router advertisement state machine. Used for everything but timer 7087c478bd9Sstevel@tonic-gate * events which use advertise_event directly. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate void 7117c478bd9Sstevel@tonic-gate check_to_advertise(struct phyint *pi, enum adv_events event) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate uint_t delay; 7147c478bd9Sstevel@tonic-gate enum adv_states old_state = pi->pi_adv_state; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 7177c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d\n", 7187c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate delay = advertise_event(pi, event, 0); 7217c478bd9Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 7227c478bd9Sstevel@tonic-gate /* Make sure the global next event is updated */ 7237c478bd9Sstevel@tonic-gate timer_schedule(delay); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 7277c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d -> %d\n", 7287c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 7297c478bd9Sstevel@tonic-gate (int)pi->pi_adv_state); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * Router advertisement state machine. 7357c478bd9Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 7367c478bd9Sstevel@tonic-gate * if never). 7377c478bd9Sstevel@tonic-gate * For the ADV_TIMER event the caller passes in the number of milliseconds 7387c478bd9Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate uint_t 7417c478bd9Sstevel@tonic-gate advertise_event(struct phyint *pi, enum adv_events event, uint_t elapsed) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate uint_t delay; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 7467c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "advertise_event(%s, %d, %d) state %d\n", 7477c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_adv_state); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate check_daemonize(); 7507c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 7517c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7527c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 7537c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 7547c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RA packet on %s " 7557c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 7567c478bd9Sstevel@tonic-gate pi->pi_name); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate switch (event) { 7627c478bd9Sstevel@tonic-gate case ADV_OFF: 7637c478bd9Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 7647c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate case START_INIT_ADV: 7677c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == INIT_ADV) 7687c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7697c478bd9Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_INITIAL_RTR_ADVERTISEMENTS; 7707c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7717c478bd9Sstevel@tonic-gate pi->pi_adv_state = INIT_ADV; 7727c478bd9Sstevel@tonic-gate break; /* send advertisement */ 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate case START_FINAL_ADV: 7757c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7767c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7777c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 7787c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7797c478bd9Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_FINAL_RTR_ADVERTISEMENTS; 7807c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7817c478bd9Sstevel@tonic-gate pi->pi_adv_state = FINAL_ADV; 7827c478bd9Sstevel@tonic-gate break; /* send advertisement */ 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate case RECEIVED_SOLICIT: 7857c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7867c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7877c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == SOLICIT_ADV) { 7887c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 7897c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7907c478bd9Sstevel@tonic-gate break; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate delay = GET_RANDOM(0, ND_MAX_RA_DELAY_TIME); 7937c478bd9Sstevel@tonic-gate if (delay < pi->pi_adv_time_left) 7947c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = delay; 7957c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_since_sent < ND_MIN_DELAY_BETWEEN_RAS) { 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * Send an advertisement (ND_MIN_DELAY_BETWEEN_RAS 7987c478bd9Sstevel@tonic-gate * plus random delay) after the previous 7997c478bd9Sstevel@tonic-gate * advertisement was sent. 8007c478bd9Sstevel@tonic-gate */ 8017c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = delay + 8027c478bd9Sstevel@tonic-gate ND_MIN_DELAY_BETWEEN_RAS - 8037c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate pi->pi_adv_state = SOLICIT_ADV; 8067c478bd9Sstevel@tonic-gate break; 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate case ADV_TIMER: 8097c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 8107c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8117c478bd9Sstevel@tonic-gate /* Decrease time left */ 8127c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_left >= elapsed) 8137c478bd9Sstevel@tonic-gate pi->pi_adv_time_left -= elapsed; 8147c478bd9Sstevel@tonic-gate else 8157c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 0; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* Increase time since last advertisement was sent */ 8187c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent += elapsed; 8197c478bd9Sstevel@tonic-gate break; 8207c478bd9Sstevel@tonic-gate default: 8217c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "advertise_event: Unknown event %d\n", 8227c478bd9Sstevel@tonic-gate (int)event); 8237c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 8277c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* Send advertisement and calculate next time to send */ 8307c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 8317c478bd9Sstevel@tonic-gate /* Omit the prefixes */ 8327c478bd9Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_TRUE); 8337c478bd9Sstevel@tonic-gate } else { 8347c478bd9Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_FALSE); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent = 0; 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate switch (pi->pi_adv_state) { 8397c478bd9Sstevel@tonic-gate case SOLICIT_ADV: 8407c478bd9Sstevel@tonic-gate /* 8417c478bd9Sstevel@tonic-gate * The solicited advertisement has been sent. 8427c478bd9Sstevel@tonic-gate * Revert to periodic advertisements. 8437c478bd9Sstevel@tonic-gate */ 8447c478bd9Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 8457c478bd9Sstevel@tonic-gate /* FALLTHRU */ 8467c478bd9Sstevel@tonic-gate case REG_ADV: 8477c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 8487c478bd9Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8497c478bd9Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8507c478bd9Sstevel@tonic-gate break; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate case INIT_ADV: 8537c478bd9Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8547c478bd9Sstevel@tonic-gate delay = GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8557c478bd9Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8567c478bd9Sstevel@tonic-gate if (delay > ND_MAX_INITIAL_RTR_ADVERT_INTERVAL) 8577c478bd9Sstevel@tonic-gate delay = ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8587c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = delay; 8597c478bd9Sstevel@tonic-gate } else { 8607c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 8617c478bd9Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8627c478bd9Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8637c478bd9Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate break; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate case FINAL_ADV: 8687c478bd9Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8697c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 8707c478bd9Sstevel@tonic-gate ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8717c478bd9Sstevel@tonic-gate } else { 8727c478bd9Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate break; 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) 8777c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 8787c478bd9Sstevel@tonic-gate else 8797c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * Router solicitation state machine. Used for everything but timer 8847c478bd9Sstevel@tonic-gate * events which use solicit_event directly. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate void 8877c478bd9Sstevel@tonic-gate check_to_solicit(struct phyint *pi, enum solicit_events event) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate uint_t delay; 8907c478bd9Sstevel@tonic-gate enum solicit_states old_state = pi->pi_sol_state; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 8937c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d\n", 8947c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate delay = solicit_event(pi, event, 0); 8977c478bd9Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 8987c478bd9Sstevel@tonic-gate /* Make sure the global next event is updated */ 8997c478bd9Sstevel@tonic-gate timer_schedule(delay); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 9037c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d -> %d\n", 9047c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 9057c478bd9Sstevel@tonic-gate (int)pi->pi_sol_state); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate static void 9107c478bd9Sstevel@tonic-gate daemonize_ndpd(void) 9117c478bd9Sstevel@tonic-gate { 9127c478bd9Sstevel@tonic-gate FILE *pidfp; 9137c478bd9Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 9147c478bd9Sstevel@tonic-gate struct itimerval it; 9157c478bd9Sstevel@tonic-gate boolean_t timerval = _B_TRUE; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate * Need to get current timer settings so they can be restored 9197c478bd9Sstevel@tonic-gate * after the fork(), as the it_value and it_interval values for 9207c478bd9Sstevel@tonic-gate * the ITIMER_REAL timer are reset to 0 in the child process. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate if (getitimer(ITIMER_REAL, &it) < 0) { 9237c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 9247c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 9257c478bd9Sstevel@tonic-gate "daemonize_ndpd: failed to get itimerval\n"); 9267c478bd9Sstevel@tonic-gate timerval = _B_FALSE; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* Daemonize. */ 9307c478bd9Sstevel@tonic-gate switch (fork()) { 9317c478bd9Sstevel@tonic-gate case 0: 9327c478bd9Sstevel@tonic-gate /* Child */ 9337c478bd9Sstevel@tonic-gate break; 9347c478bd9Sstevel@tonic-gate case -1: 9357c478bd9Sstevel@tonic-gate logperror("fork"); 9367c478bd9Sstevel@tonic-gate exit(1); 9377c478bd9Sstevel@tonic-gate default: 9387c478bd9Sstevel@tonic-gate /* Parent */ 9397c478bd9Sstevel@tonic-gate _exit(0); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 9437c478bd9Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 9447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n", 9457c478bd9Sstevel@tonic-gate argv0[0], strerror(errno)); 9467c478bd9Sstevel@tonic-gate } else { 9477c478bd9Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 9487c478bd9Sstevel@tonic-gate (void) fclose(pidfp); 9497c478bd9Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate (void) close(0); 9537c478bd9Sstevel@tonic-gate (void) close(1); 9547c478bd9Sstevel@tonic-gate (void) close(2); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate (void) chdir("/"); 9577c478bd9Sstevel@tonic-gate (void) open("/dev/null", O_RDWR); 9587c478bd9Sstevel@tonic-gate (void) dup2(0, 1); 9597c478bd9Sstevel@tonic-gate (void) dup2(0, 2); 9607c478bd9Sstevel@tonic-gate (void) setsid(); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate already_daemonized = _B_TRUE; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* 9657c478bd9Sstevel@tonic-gate * Restore timer values, if we were able to save them; if not, 9667c478bd9Sstevel@tonic-gate * check and set the right value by calling run_timeouts(). 9677c478bd9Sstevel@tonic-gate */ 9687c478bd9Sstevel@tonic-gate if (timerval) { 9697c478bd9Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 9707c478bd9Sstevel@tonic-gate logperror("daemonize_ndpd: setitimer"); 9717c478bd9Sstevel@tonic-gate exit(2); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate } else { 9747c478bd9Sstevel@tonic-gate run_timeouts(); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * Check to see if the time is right to daemonize. The right time is when: 9807c478bd9Sstevel@tonic-gate * 9817c478bd9Sstevel@tonic-gate * 1. We haven't already daemonized. 9827c478bd9Sstevel@tonic-gate * 2. We are not in debug mode. 9837c478bd9Sstevel@tonic-gate * 3. All interfaces are marked IFF_NOXMIT. 9847c478bd9Sstevel@tonic-gate * 4. All non-router interfaces have their prefixes set up and we're 9857c478bd9Sstevel@tonic-gate * done sending router solicitations on those interfaces without 9867c478bd9Sstevel@tonic-gate * prefixes. 9877c478bd9Sstevel@tonic-gate */ 9887c478bd9Sstevel@tonic-gate static void 9897c478bd9Sstevel@tonic-gate check_daemonize(void) 9907c478bd9Sstevel@tonic-gate { 9917c478bd9Sstevel@tonic-gate struct phyint *pi; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate if (already_daemonized || debug != 0) 9947c478bd9Sstevel@tonic-gate return; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 9977c478bd9Sstevel@tonic-gate if (!(pi->pi_flags & IFF_NOXMIT)) 9987c478bd9Sstevel@tonic-gate break; 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * If we can't transmit on any of the interfaces there is no reason 10037c478bd9Sstevel@tonic-gate * to hold up progress. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate if (pi == NULL) { 10067c478bd9Sstevel@tonic-gate daemonize_ndpd(); 10077c478bd9Sstevel@tonic-gate return; 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* Check all interfaces. If any are still soliciting, just return. */ 10117c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 10127c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements || 10137c478bd9Sstevel@tonic-gate !(pi->pi_kernel_state & PI_PRESENT)) 10147c478bd9Sstevel@tonic-gate continue; 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 10177c478bd9Sstevel@tonic-gate return; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate daemonize_ndpd(); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * Router solicitation state machine. 10257c478bd9Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 10267c478bd9Sstevel@tonic-gate * if never). 10277c478bd9Sstevel@tonic-gate * For the SOL_TIMER event the caller passes in the number of milliseconds 10287c478bd9Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate uint_t 10317c478bd9Sstevel@tonic-gate solicit_event(struct phyint *pi, enum solicit_events event, uint_t elapsed) 10327c478bd9Sstevel@tonic-gate { 10337c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 10347c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "solicit_event(%s, %d, %d) state %d\n", 10357c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_sol_state); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 10397c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10407c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 10417c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 10427c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RS packet on %s " 10437c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 10447c478bd9Sstevel@tonic-gate pi->pi_name); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate switch (event) { 10507c478bd9Sstevel@tonic-gate case SOLICIT_OFF: 10517c478bd9Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 10527c478bd9Sstevel@tonic-gate check_daemonize(); 10537c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate case SOLICIT_DONE: 10567c478bd9Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 10577c478bd9Sstevel@tonic-gate check_daemonize(); 10587c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10597c478bd9Sstevel@tonic-gate 1060d04ccbb3Scarlsonj case RESTART_INIT_SOLICIT: 1061d04ccbb3Scarlsonj /* 1062d04ccbb3Scarlsonj * This event allows us to start solicitation over again 1063d04ccbb3Scarlsonj * without losing the RA flags. We start solicitation over 1064d04ccbb3Scarlsonj * when we are missing an interface prefix for a newly- 1065d04ccbb3Scarlsonj * encountered DHCP interface. 1066d04ccbb3Scarlsonj */ 1067d04ccbb3Scarlsonj if (pi->pi_sol_state == INIT_SOLICIT) 1068d04ccbb3Scarlsonj return (pi->pi_sol_time_left); 1069d04ccbb3Scarlsonj pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 1070d04ccbb3Scarlsonj pi->pi_sol_time_left = 1071d04ccbb3Scarlsonj GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 1072d04ccbb3Scarlsonj pi->pi_sol_state = INIT_SOLICIT; 1073d04ccbb3Scarlsonj break; 1074d04ccbb3Scarlsonj 10757c478bd9Sstevel@tonic-gate case START_INIT_SOLICIT: 10767c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 10777c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 1078d04ccbb3Scarlsonj pi->pi_ra_flags = 0; 10797c478bd9Sstevel@tonic-gate pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 10807c478bd9Sstevel@tonic-gate pi->pi_sol_time_left = 10817c478bd9Sstevel@tonic-gate GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 10827c478bd9Sstevel@tonic-gate pi->pi_sol_state = INIT_SOLICIT; 10837c478bd9Sstevel@tonic-gate break; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate case SOL_TIMER: 10867c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 10877c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10887c478bd9Sstevel@tonic-gate /* Decrease time left */ 10897c478bd9Sstevel@tonic-gate if (pi->pi_sol_time_left >= elapsed) 10907c478bd9Sstevel@tonic-gate pi->pi_sol_time_left -= elapsed; 10917c478bd9Sstevel@tonic-gate else 10927c478bd9Sstevel@tonic-gate pi->pi_sol_time_left = 0; 10937c478bd9Sstevel@tonic-gate break; 10947c478bd9Sstevel@tonic-gate default: 10957c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "solicit_event: Unknown event %d\n", 10967c478bd9Sstevel@tonic-gate (int)event); 10977c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate if (pi->pi_sol_time_left != 0) 11017c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate /* Send solicitation and calculate next time */ 11047c478bd9Sstevel@tonic-gate switch (pi->pi_sol_state) { 11057c478bd9Sstevel@tonic-gate case INIT_SOLICIT: 11067c478bd9Sstevel@tonic-gate solicit(&v6allrouters, pi); 11077c478bd9Sstevel@tonic-gate if (--pi->pi_sol_count == 0) { 1108cfb9c9abScarlsonj if (debug & D_STATE) { 1109cfb9c9abScarlsonj logmsg(LOG_DEBUG, "solicit_event: no routers " 1110cfb9c9abScarlsonj "found on %s; assuming default flags\n", 1111cfb9c9abScarlsonj pi->pi_name); 1112cfb9c9abScarlsonj } 1113*6e91bba0SGirish Moodalbail if (pi->pi_autoconf && pi->pi_StatefulAddrConf) { 1114d04ccbb3Scarlsonj pi->pi_ra_flags |= ND_RA_FLAG_MANAGED | 1115d04ccbb3Scarlsonj ND_RA_FLAG_OTHER; 1116d04ccbb3Scarlsonj start_dhcp(pi); 1117d04ccbb3Scarlsonj } 11187c478bd9Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 11197c478bd9Sstevel@tonic-gate check_daemonize(); 11207c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate pi->pi_sol_time_left = ND_RTR_SOLICITATION_INTERVAL; 11237c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 11247c478bd9Sstevel@tonic-gate case NO_SOLICIT: 11257c478bd9Sstevel@tonic-gate case DONE_SOLICIT: 11267c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 11277c478bd9Sstevel@tonic-gate default: 11287c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate /* 11337c478bd9Sstevel@tonic-gate * Timer mechanism using relative time (in milliseconds) from the 11347c478bd9Sstevel@tonic-gate * previous timer event. Timers exceeding TIMER_INFINITY milliseconds 11357c478bd9Sstevel@tonic-gate * will fire after TIMER_INFINITY milliseconds. 11367c478bd9Sstevel@tonic-gate */ 11377c478bd9Sstevel@tonic-gate static uint_t timer_previous; /* When last SIGALRM occurred */ 11387c478bd9Sstevel@tonic-gate static uint_t timer_next; /* Currently scheduled timeout */ 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate static void 11417c478bd9Sstevel@tonic-gate timer_init(void) 11427c478bd9Sstevel@tonic-gate { 11437c478bd9Sstevel@tonic-gate timer_previous = getcurrenttime(); 11447c478bd9Sstevel@tonic-gate timer_next = TIMER_INFINITY; 11457c478bd9Sstevel@tonic-gate run_timeouts(); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * Make sure the next SIGALRM occurs delay milliseconds from the current 11507c478bd9Sstevel@tonic-gate * time if not earlier. 11517c478bd9Sstevel@tonic-gate * Handles getcurrenttime (32 bit integer holding milliseconds) wraparound 11527c478bd9Sstevel@tonic-gate * by treating differences greater than 0x80000000 as negative. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate void 11557c478bd9Sstevel@tonic-gate timer_schedule(uint_t delay) 11567c478bd9Sstevel@tonic-gate { 11577c478bd9Sstevel@tonic-gate uint_t now; 11587c478bd9Sstevel@tonic-gate struct itimerval itimerval; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate now = getcurrenttime(); 11617c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11627c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): now %u next %u\n", 11637c478bd9Sstevel@tonic-gate delay, now, timer_next); 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate /* Will this timer occur before the currently scheduled SIGALRM? */ 11667c478bd9Sstevel@tonic-gate if (delay >= timer_next - now) { 11677c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11687c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): no action - " 11697c478bd9Sstevel@tonic-gate "next in %u ms\n", 11707c478bd9Sstevel@tonic-gate delay, timer_next - now); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate return; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate if (delay == 0) { 11757c478bd9Sstevel@tonic-gate /* Minimum allowed delay */ 11767c478bd9Sstevel@tonic-gate delay = 1; 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate timer_next = now + delay; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate itimerval.it_value.tv_sec = delay / 1000; 11817c478bd9Sstevel@tonic-gate itimerval.it_value.tv_usec = (delay % 1000) * 1000; 11827c478bd9Sstevel@tonic-gate itimerval.it_interval.tv_sec = 0; 11837c478bd9Sstevel@tonic-gate itimerval.it_interval.tv_usec = 0; 11847c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11857c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): sec %lu usec %lu\n", 11867c478bd9Sstevel@tonic-gate delay, 11877c478bd9Sstevel@tonic-gate itimerval.it_value.tv_sec, itimerval.it_value.tv_usec); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) { 11907c478bd9Sstevel@tonic-gate logperror("timer_schedule: setitimer"); 11917c478bd9Sstevel@tonic-gate exit(2); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* 11967c478bd9Sstevel@tonic-gate * Conditional running of timer. If more than 'minimal_time' millseconds 11977c478bd9Sstevel@tonic-gate * since the timer routines were last run we run them. 11987c478bd9Sstevel@tonic-gate * Used when packets arrive. 11997c478bd9Sstevel@tonic-gate */ 12007c478bd9Sstevel@tonic-gate static void 12017c478bd9Sstevel@tonic-gate conditional_run_timeouts(uint_t minimal_time) 12027c478bd9Sstevel@tonic-gate { 12037c478bd9Sstevel@tonic-gate uint_t now; 12047c478bd9Sstevel@tonic-gate uint_t elapsed; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate now = getcurrenttime(); 12077c478bd9Sstevel@tonic-gate elapsed = now - timer_previous; 12087c478bd9Sstevel@tonic-gate if (elapsed > minimal_time) { 12097c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12107c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "conditional_run_timeouts: " 12117c478bd9Sstevel@tonic-gate "elapsed %d\n", elapsed); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate run_timeouts(); 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate /* 12187c478bd9Sstevel@tonic-gate * Timer has fired. 12197c478bd9Sstevel@tonic-gate * Determine when the next timer event will occur by asking all 12207c478bd9Sstevel@tonic-gate * the timer routines. 12217c478bd9Sstevel@tonic-gate * Should not be called from a timer routine but in some cases this is 12227c478bd9Sstevel@tonic-gate * done because the code doesn't know that e.g. it was called from 12237c478bd9Sstevel@tonic-gate * ifconfig_timer(). In this case the nested run_timeouts will just return but 12247c478bd9Sstevel@tonic-gate * the running run_timeouts will ensure to call all the timer functions by 12257c478bd9Sstevel@tonic-gate * looping once more. 12267c478bd9Sstevel@tonic-gate */ 12277c478bd9Sstevel@tonic-gate static void 12287c478bd9Sstevel@tonic-gate run_timeouts(void) 12297c478bd9Sstevel@tonic-gate { 12307c478bd9Sstevel@tonic-gate uint_t now; 12317c478bd9Sstevel@tonic-gate uint_t elapsed; 12327c478bd9Sstevel@tonic-gate uint_t next; 12337c478bd9Sstevel@tonic-gate uint_t nexti; 12347c478bd9Sstevel@tonic-gate struct phyint *pi; 12357c478bd9Sstevel@tonic-gate struct phyint *next_pi; 12367c478bd9Sstevel@tonic-gate struct prefix *pr; 12377c478bd9Sstevel@tonic-gate struct prefix *next_pr; 12387c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 12397c478bd9Sstevel@tonic-gate struct adv_prefix *next_adv_pr; 12407c478bd9Sstevel@tonic-gate struct router *dr; 12417c478bd9Sstevel@tonic-gate struct router *next_dr; 12427c478bd9Sstevel@tonic-gate static boolean_t timeout_running; 12437c478bd9Sstevel@tonic-gate static boolean_t do_retry; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate if (timeout_running) { 12467c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 12477c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: nested call\n"); 12487c478bd9Sstevel@tonic-gate do_retry = _B_TRUE; 12497c478bd9Sstevel@tonic-gate return; 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate timeout_running = _B_TRUE; 12527c478bd9Sstevel@tonic-gate retry: 12537c478bd9Sstevel@tonic-gate /* How much time since the last time we were called? */ 12547c478bd9Sstevel@tonic-gate now = getcurrenttime(); 12557c478bd9Sstevel@tonic-gate elapsed = now - timer_previous; 12567c478bd9Sstevel@tonic-gate timer_previous = now; 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 12597c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: elapsed %d\n", elapsed); 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate next = TIMER_INFINITY; 12627c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 12637c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 12647c478bd9Sstevel@tonic-gate nexti = phyint_timer(pi, elapsed); 12657c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12667c478bd9Sstevel@tonic-gate next = nexti; 12677c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12687c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pi %s): %d -> %u ms\n", 12697c478bd9Sstevel@tonic-gate pi->pi_name, nexti, next); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 12727c478bd9Sstevel@tonic-gate next_pr = pr->pr_next; 12737c478bd9Sstevel@tonic-gate nexti = prefix_timer(pr, elapsed); 12747c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12757c478bd9Sstevel@tonic-gate next = nexti; 12767c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12777c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pr %s): " 12787c478bd9Sstevel@tonic-gate "%d -> %u ms\n", pr->pr_name, nexti, next); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 12827c478bd9Sstevel@tonic-gate adv_pr = next_adv_pr) { 12837c478bd9Sstevel@tonic-gate next_adv_pr = adv_pr->adv_pr_next; 12847c478bd9Sstevel@tonic-gate nexti = adv_prefix_timer(adv_pr, elapsed); 12857c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12867c478bd9Sstevel@tonic-gate next = nexti; 12877c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12887c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts " 12897c478bd9Sstevel@tonic-gate "(adv pr on %s): %d -> %u ms\n", 12907c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 12917c478bd9Sstevel@tonic-gate nexti, next); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) { 12957c478bd9Sstevel@tonic-gate next_dr = dr->dr_next; 12967c478bd9Sstevel@tonic-gate nexti = router_timer(dr, elapsed); 12977c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12987c478bd9Sstevel@tonic-gate next = nexti; 12997c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 13007c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (dr): " 13017c478bd9Sstevel@tonic-gate "%d -> %u ms\n", nexti, next); 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 13057c478bd9Sstevel@tonic-gate nexti = tmptoken_timer(pi, elapsed); 13067c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 13077c478bd9Sstevel@tonic-gate next = nexti; 13087c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 13097c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (tmp on %s): " 13107c478bd9Sstevel@tonic-gate "%d -> %u ms\n", pi->pi_name, nexti, next); 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * Make sure the timer functions are run at least once 13167c478bd9Sstevel@tonic-gate * an hour. 13177c478bd9Sstevel@tonic-gate */ 13187c478bd9Sstevel@tonic-gate if (next == TIMER_INFINITY) 13197c478bd9Sstevel@tonic-gate next = 3600 * 1000; /* 1 hour */ 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 13227c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: %u ms\n", next); 13237c478bd9Sstevel@tonic-gate timer_schedule(next); 13247c478bd9Sstevel@tonic-gate if (do_retry) { 13257c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 13267c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: retry\n"); 13277c478bd9Sstevel@tonic-gate do_retry = _B_FALSE; 13287c478bd9Sstevel@tonic-gate goto retry; 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate timeout_running = _B_FALSE; 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate static int eventpipe_read = -1; /* Used for synchronous signal delivery */ 13347c478bd9Sstevel@tonic-gate static int eventpipe_write = -1; 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate /* 13377c478bd9Sstevel@tonic-gate * Ensure that signals are processed synchronously with the rest of 13387c478bd9Sstevel@tonic-gate * the code by just writing a one character signal number on the pipe. 13397c478bd9Sstevel@tonic-gate * The poll loop will pick this up and process the signal event. 13407c478bd9Sstevel@tonic-gate */ 13417c478bd9Sstevel@tonic-gate static void 13427c478bd9Sstevel@tonic-gate sig_handler(int signo) 13437c478bd9Sstevel@tonic-gate { 13447c478bd9Sstevel@tonic-gate uchar_t buf = (uchar_t)signo; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (eventpipe_write == -1) { 13477c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "sig_handler: no pipe\n"); 13487c478bd9Sstevel@tonic-gate return; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate if (write(eventpipe_write, &buf, sizeof (buf)) < 0) 13517c478bd9Sstevel@tonic-gate logperror("sig_handler: write"); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * Pick up a signal "byte" from the pipe and process it. 13567c478bd9Sstevel@tonic-gate */ 13577c478bd9Sstevel@tonic-gate static void 13587c478bd9Sstevel@tonic-gate in_signal(int fd) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate uchar_t buf; 13617c478bd9Sstevel@tonic-gate struct phyint *pi; 13627c478bd9Sstevel@tonic-gate struct phyint *next_pi; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate switch (read(fd, &buf, sizeof (buf))) { 13657c478bd9Sstevel@tonic-gate case -1: 13667c478bd9Sstevel@tonic-gate logperror("in_signal: read"); 13677c478bd9Sstevel@tonic-gate exit(1); 13687c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13697c478bd9Sstevel@tonic-gate case 1: 13707c478bd9Sstevel@tonic-gate break; 13717c478bd9Sstevel@tonic-gate case 0: 13727c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read eof\n"); 13737c478bd9Sstevel@tonic-gate exit(1); 13747c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13757c478bd9Sstevel@tonic-gate default: 13767c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read > 1\n"); 13777c478bd9Sstevel@tonic-gate exit(1); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 13817c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal() got %d\n", buf); 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate switch (buf) { 13847c478bd9Sstevel@tonic-gate case SIGALRM: 13857c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 13867c478bd9Sstevel@tonic-gate uint_t now = getcurrenttime(); 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal(SIGALRM) delta %u\n", 13897c478bd9Sstevel@tonic-gate now - timer_next); 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate timer_next = TIMER_INFINITY; 13927c478bd9Sstevel@tonic-gate run_timeouts(); 13937c478bd9Sstevel@tonic-gate break; 13947c478bd9Sstevel@tonic-gate case SIGHUP: 13957c478bd9Sstevel@tonic-gate /* Re-read config file by exec'ing ourselves */ 13967c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 13977c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 13987c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 13997c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 14007c478bd9Sstevel@tonic-gate 1401*6e91bba0SGirish Moodalbail /* 1402*6e91bba0SGirish Moodalbail * Remove all the configured addresses. 1403*6e91bba0SGirish Moodalbail * Remove the addrobj names created with ipmgmtd. 1404*6e91bba0SGirish Moodalbail * Release the dhcpv6 addresses if any. 1405*6e91bba0SGirish Moodalbail * Cleanup the phyints. 1406*6e91bba0SGirish Moodalbail */ 14077c478bd9Sstevel@tonic-gate phyint_delete(pi); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Prevent fd leaks. Everything gets re-opened at start-up 14127c478bd9Sstevel@tonic-gate * time. 0, 1, and 2 are closed and re-opened as 14137c478bd9Sstevel@tonic-gate * /dev/null, so we'll leave those open. 14147c478bd9Sstevel@tonic-gate */ 14157c478bd9Sstevel@tonic-gate closefrom(3); 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "SIGHUP: restart and reread config file\n"); 14187c478bd9Sstevel@tonic-gate (void) execv(argv0[0], argv0); 14197c478bd9Sstevel@tonic-gate (void) unlink(PATH_PID); 14207c478bd9Sstevel@tonic-gate _exit(0177); 14217c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14227c478bd9Sstevel@tonic-gate case SIGUSR1: 14237c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Printing configuration:\n"); 14247c478bd9Sstevel@tonic-gate phyint_print_all(); 14257c478bd9Sstevel@tonic-gate break; 14267c478bd9Sstevel@tonic-gate case SIGINT: 14277c478bd9Sstevel@tonic-gate case SIGTERM: 14287c478bd9Sstevel@tonic-gate case SIGQUIT: 14297c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 14307c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 14317c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 14327c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate phyint_delete(pi); 14357c478bd9Sstevel@tonic-gate } 14363173664eSapersson (void) unlink(NDPD_SNMP_SOCKET); 14377c478bd9Sstevel@tonic-gate (void) unlink(PATH_PID); 14387c478bd9Sstevel@tonic-gate exit(0); 14397c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14407c478bd9Sstevel@tonic-gate case 255: 14417c478bd9Sstevel@tonic-gate /* 1442*6e91bba0SGirish Moodalbail * Special "signal" from loopback_ra_enqueue. 14437c478bd9Sstevel@tonic-gate * Handle any queued loopback router advertisements. 14447c478bd9Sstevel@tonic-gate */ 14457c478bd9Sstevel@tonic-gate loopback_ra_dequeue(); 14467c478bd9Sstevel@tonic-gate break; 14477c478bd9Sstevel@tonic-gate default: 14487c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: unknown signal: %d\n", buf); 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate /* 14537c478bd9Sstevel@tonic-gate * Create pipe for signal delivery and set up signal handlers. 14547c478bd9Sstevel@tonic-gate */ 14557c478bd9Sstevel@tonic-gate static void 14567c478bd9Sstevel@tonic-gate setup_eventpipe(void) 14577c478bd9Sstevel@tonic-gate { 14587c478bd9Sstevel@tonic-gate int fds[2]; 14597c478bd9Sstevel@tonic-gate struct sigaction act; 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate if ((pipe(fds)) < 0) { 14627c478bd9Sstevel@tonic-gate logperror("setup_eventpipe: pipe"); 14637c478bd9Sstevel@tonic-gate exit(1); 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate eventpipe_read = fds[0]; 14667c478bd9Sstevel@tonic-gate eventpipe_write = fds[1]; 14677c478bd9Sstevel@tonic-gate if (poll_add(eventpipe_read) == -1) { 14687c478bd9Sstevel@tonic-gate exit(1); 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate act.sa_handler = sig_handler; 14717c478bd9Sstevel@tonic-gate act.sa_flags = SA_RESTART; 14727c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, sig_handler); 14757c478bd9Sstevel@tonic-gate (void) sigset(SIGUSR1, sig_handler); 14767c478bd9Sstevel@tonic-gate (void) sigset(SIGTERM, sig_handler); 14777c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, sig_handler); 14787c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, sig_handler); 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate /* 14827c478bd9Sstevel@tonic-gate * Create a routing socket for receiving RTM_IFINFO messages and initialize 14837c478bd9Sstevel@tonic-gate * the routing socket message header and as much of the sockaddrs as possible. 14847c478bd9Sstevel@tonic-gate */ 14857c478bd9Sstevel@tonic-gate static int 14867c478bd9Sstevel@tonic-gate setup_rtsock(void) 14877c478bd9Sstevel@tonic-gate { 14887c478bd9Sstevel@tonic-gate int s; 14897c478bd9Sstevel@tonic-gate int ret; 14907c478bd9Sstevel@tonic-gate char *cp; 14917c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, AF_INET6); 14947c478bd9Sstevel@tonic-gate if (s == -1) { 14957c478bd9Sstevel@tonic-gate logperror("socket(PF_ROUTE)"); 14967c478bd9Sstevel@tonic-gate exit(1); 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate ret = fcntl(s, F_SETFL, O_NDELAY|O_NONBLOCK); 14997c478bd9Sstevel@tonic-gate if (ret < 0) { 15007c478bd9Sstevel@tonic-gate logperror("fcntl(O_NDELAY)"); 15017c478bd9Sstevel@tonic-gate exit(1); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate if (poll_add(s) == -1) { 15047c478bd9Sstevel@tonic-gate exit(1); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate /* 15087c478bd9Sstevel@tonic-gate * Allocate storage for the routing socket message. 15097c478bd9Sstevel@tonic-gate */ 15107c478bd9Sstevel@tonic-gate rt_msg = (struct rt_msghdr *)malloc(NDP_RTM_MSGLEN); 15117c478bd9Sstevel@tonic-gate if (rt_msg == NULL) { 15127c478bd9Sstevel@tonic-gate logperror("malloc"); 15137c478bd9Sstevel@tonic-gate exit(1); 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate /* 15177c478bd9Sstevel@tonic-gate * Initialize the routing socket message by zero-filling it and then 15187c478bd9Sstevel@tonic-gate * setting the fields where are constant through the lifetime of the 15197c478bd9Sstevel@tonic-gate * process. 15207c478bd9Sstevel@tonic-gate */ 15217c478bd9Sstevel@tonic-gate bzero(rt_msg, NDP_RTM_MSGLEN); 15227c478bd9Sstevel@tonic-gate rt_msg->rtm_msglen = NDP_RTM_MSGLEN; 15237c478bd9Sstevel@tonic-gate rt_msg->rtm_version = RTM_VERSION; 15247c478bd9Sstevel@tonic-gate rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP; 15257c478bd9Sstevel@tonic-gate rt_msg->rtm_pid = getpid(); 15267c478bd9Sstevel@tonic-gate if (rt_msg->rtm_pid < 0) { 15277c478bd9Sstevel@tonic-gate logperror("getpid"); 15287c478bd9Sstevel@tonic-gate exit(1); 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate /* 15327c478bd9Sstevel@tonic-gate * The RTA_DST sockaddr does not change during the lifetime of the 15337c478bd9Sstevel@tonic-gate * process so it can be completely initialized at this time. 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate cp = (char *)rt_msg + sizeof (struct rt_msghdr); 15367c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 15377c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15387c478bd9Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_GATEWAY sockaddr. 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15447c478bd9Sstevel@tonic-gate rta_gateway = (struct sockaddr_in6 *)cp; 15457c478bd9Sstevel@tonic-gate rta_gateway->sin6_family = AF_INET6; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate /* 15487c478bd9Sstevel@tonic-gate * The RTA_NETMASK sockaddr does not change during the lifetime of the 15497c478bd9Sstevel@tonic-gate * process so it can be completely initialized at this time. 15507c478bd9Sstevel@tonic-gate */ 15517c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15527c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 15537c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15547c478bd9Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_IFP sockaddr. 15587c478bd9Sstevel@tonic-gate */ 15597c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15607c478bd9Sstevel@tonic-gate rta_ifp = (struct sockaddr_dl *)cp; 15617c478bd9Sstevel@tonic-gate rta_ifp->sdl_family = AF_LINK; 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate return (s); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15663173664eSapersson static int 15673173664eSapersson setup_mibsock(void) 15683173664eSapersson { 15693173664eSapersson int sock; 15703173664eSapersson int ret; 15713173664eSapersson int len; 15723173664eSapersson struct sockaddr_un laddr; 15733173664eSapersson 15743173664eSapersson sock = socket(AF_UNIX, SOCK_DGRAM, 0); 15753173664eSapersson if (sock == -1) { 15763173664eSapersson logperror("setup_mibsock: socket(AF_UNIX)"); 15773173664eSapersson exit(1); 15783173664eSapersson } 15793173664eSapersson 15803173664eSapersson bzero(&laddr, sizeof (laddr)); 15813173664eSapersson laddr.sun_family = AF_UNIX; 15823173664eSapersson 15833173664eSapersson (void) strncpy(laddr.sun_path, NDPD_SNMP_SOCKET, 15843173664eSapersson sizeof (laddr.sun_path)); 15853173664eSapersson len = sizeof (struct sockaddr_un); 15863173664eSapersson 15873173664eSapersson (void) unlink(NDPD_SNMP_SOCKET); 15883173664eSapersson ret = bind(sock, (struct sockaddr *)&laddr, len); 15893173664eSapersson if (ret < 0) { 15903173664eSapersson logperror("setup_mibsock: bind\n"); 15913173664eSapersson exit(1); 15923173664eSapersson } 15933173664eSapersson 15943173664eSapersson ret = fcntl(sock, F_SETFL, O_NONBLOCK); 15953173664eSapersson if (ret < 0) { 15963173664eSapersson logperror("fcntl(O_NONBLOCK)"); 15973173664eSapersson exit(1); 15983173664eSapersson } 15993173664eSapersson if (poll_add(sock) == -1) { 16003173664eSapersson exit(1); 16013173664eSapersson } 16023173664eSapersson return (sock); 16033173664eSapersson } 16043173664eSapersson 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * Retrieve one routing socket message. If RTM_IFINFO indicates 16077c478bd9Sstevel@tonic-gate * new phyint do a full scan of the interfaces. If RTM_IFINFO 160869bb4bb4Scarlsonj * indicates an existing phyint, only scan that phyint and associated 16097c478bd9Sstevel@tonic-gate * prefixes. 16107c478bd9Sstevel@tonic-gate */ 16117c478bd9Sstevel@tonic-gate static void 16127c478bd9Sstevel@tonic-gate process_rtsock(int rtsock) 16137c478bd9Sstevel@tonic-gate { 16147c478bd9Sstevel@tonic-gate int n; 16157c478bd9Sstevel@tonic-gate #define MSG_SIZE 2048/8 16167c478bd9Sstevel@tonic-gate int64_t msg[MSG_SIZE]; 16177c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 16187c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 16197c478bd9Sstevel@tonic-gate struct phyint *pi; 16207c478bd9Sstevel@tonic-gate struct prefix *pr; 16217c478bd9Sstevel@tonic-gate boolean_t need_initifs = _B_FALSE; 16227c478bd9Sstevel@tonic-gate boolean_t need_ifscan = _B_FALSE; 16237c478bd9Sstevel@tonic-gate int64_t ifscan_msg[10][MSG_SIZE]; 16247c478bd9Sstevel@tonic-gate int ifscan_index = 0; 16257c478bd9Sstevel@tonic-gate int i; 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate /* Empty the rtsock and coealesce all the work that we have */ 16287c478bd9Sstevel@tonic-gate while (ifscan_index < 10) { 16297c478bd9Sstevel@tonic-gate n = read(rtsock, msg, sizeof (msg)); 16307c478bd9Sstevel@tonic-gate if (n <= 0) { 16317c478bd9Sstevel@tonic-gate /* No more messages */ 16327c478bd9Sstevel@tonic-gate break; 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 16357c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 16367c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, 16377c478bd9Sstevel@tonic-gate "process_rtsock: version %d not understood\n", 16387c478bd9Sstevel@tonic-gate rtm->rtm_version); 16397c478bd9Sstevel@tonic-gate return; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 16427c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 16437c478bd9Sstevel@tonic-gate case RTM_DELADDR: 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * Some logical interface has changed - have to scan 16467c478bd9Sstevel@tonic-gate * everything to determine what actually changed. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) { 16497c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: " 16507c478bd9Sstevel@tonic-gate "message %d\n", rtm->rtm_type); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate need_initifs = _B_TRUE; 16537c478bd9Sstevel@tonic-gate break; 16547c478bd9Sstevel@tonic-gate case RTM_IFINFO: 16557c478bd9Sstevel@tonic-gate need_ifscan = _B_TRUE; 16567c478bd9Sstevel@tonic-gate (void) memcpy(ifscan_msg[ifscan_index], rtm, 16577c478bd9Sstevel@tonic-gate sizeof (msg)); 16587c478bd9Sstevel@tonic-gate ifscan_index++; 16597c478bd9Sstevel@tonic-gate /* Handled below */ 16607c478bd9Sstevel@tonic-gate break; 16617c478bd9Sstevel@tonic-gate default: 16627c478bd9Sstevel@tonic-gate /* Not interesting */ 16637c478bd9Sstevel@tonic-gate break; 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate /* 16677c478bd9Sstevel@tonic-gate * If we do full scan i.e initifs, we don't need to 16687c478bd9Sstevel@tonic-gate * scan a particular interface as we should have 16697c478bd9Sstevel@tonic-gate * done that as part of initifs. 16707c478bd9Sstevel@tonic-gate */ 16717c478bd9Sstevel@tonic-gate if (need_initifs) { 16727c478bd9Sstevel@tonic-gate initifs(_B_FALSE); 16737c478bd9Sstevel@tonic-gate return; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate if (!need_ifscan) 16777c478bd9Sstevel@tonic-gate return; 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate for (i = 0; i < ifscan_index; i++) { 16807c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)ifscan_msg[i]; 16817c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) 16827c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: index %d\n", 16837c478bd9Sstevel@tonic-gate ifm->ifm_index); 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate pi = phyint_lookup_on_index(ifm->ifm_index); 16867c478bd9Sstevel@tonic-gate if (pi == NULL) { 16877c478bd9Sstevel@tonic-gate /* 16887c478bd9Sstevel@tonic-gate * A new physical interface. Do a full scan of the 16897c478bd9Sstevel@tonic-gate * to catch any new logical interfaces. 16907c478bd9Sstevel@tonic-gate */ 16917c478bd9Sstevel@tonic-gate initifs(_B_FALSE); 16927c478bd9Sstevel@tonic-gate return; 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate 1695e11c3f44Smeem if (ifm->ifm_flags != (uint_t)pi->pi_flags) { 16967c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) { 16977c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: clr for " 1698e11c3f44Smeem "%s old flags 0x%llx new flags 0x%x\n", 16997c478bd9Sstevel@tonic-gate pi->pi_name, pi->pi_flags, ifm->ifm_flags); 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate } 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate /* 17057c478bd9Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 17067c478bd9Sstevel@tonic-gate * which have disappeared from the kernel. 17077c478bd9Sstevel@tonic-gate * if_process will set pr_in_use when it finds the 17087c478bd9Sstevel@tonic-gate * interface in the kernel. 17097c478bd9Sstevel@tonic-gate * Before re-examining the state of the interfaces, 17107c478bd9Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 17137c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 17147c478bd9Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate if (ifsock < 0) { 17187c478bd9Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 17197c478bd9Sstevel@tonic-gate if (ifsock < 0) { 17207c478bd9Sstevel@tonic-gate logperror("process_rtsock: socket"); 17217c478bd9Sstevel@tonic-gate return; 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate if_process(ifsock, pi->pi_name, _B_FALSE); 17257c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 17267c478bd9Sstevel@tonic-gate if_process(ifsock, pr->pr_name, _B_FALSE); 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate /* 17297c478bd9Sstevel@tonic-gate * If interface (still) exists in kernel, set 17307c478bd9Sstevel@tonic-gate * pi_state to indicate that. 17317c478bd9Sstevel@tonic-gate */ 17327c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 17337c478bd9Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate check_if_removed(pi); 17367c478bd9Sstevel@tonic-gate if (show_ifs) 17377c478bd9Sstevel@tonic-gate phyint_print_all(); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate 17413173664eSapersson static void 17423173664eSapersson process_mibsock(int mibsock) 17433173664eSapersson { 17443173664eSapersson struct phyint *pi; 17453173664eSapersson socklen_t fromlen; 17463173664eSapersson struct sockaddr_un from; 17473173664eSapersson ndpd_info_t ndpd_info; 17483173664eSapersson ssize_t len; 17493173664eSapersson int command; 17503173664eSapersson 17513173664eSapersson fromlen = (socklen_t)sizeof (from); 17523173664eSapersson len = recvfrom(mibsock, &command, sizeof (int), 0, 17533173664eSapersson (struct sockaddr *)&from, &fromlen); 17543173664eSapersson 17553173664eSapersson if (len < sizeof (int) || command != NDPD_SNMP_INFO_REQ) { 17563173664eSapersson logperror("process_mibsock: bad command \n"); 17573173664eSapersson return; 17583173664eSapersson } 17593173664eSapersson 17603173664eSapersson ndpd_info.info_type = NDPD_SNMP_INFO_RESPONSE; 17613173664eSapersson ndpd_info.info_version = NDPD_SNMP_INFO_VER; 17623173664eSapersson ndpd_info.info_num_of_phyints = num_of_phyints; 17633173664eSapersson 17643173664eSapersson (void) sendto(mibsock, &ndpd_info, sizeof (ndpd_info_t), 0, 17653173664eSapersson (struct sockaddr *)&from, fromlen); 17663173664eSapersson 17673173664eSapersson for (pi = phyints; pi != NULL; pi = pi->pi_next) { 17683173664eSapersson int prefixes; 17693173664eSapersson int routers; 17703173664eSapersson struct prefix *prefix_list; 17713173664eSapersson struct router *router_list; 17723173664eSapersson ndpd_phyint_info_t phyint; 17733173664eSapersson ndpd_prefix_info_t prefix; 17743173664eSapersson ndpd_router_info_t router; 17753173664eSapersson /* 17763173664eSapersson * get number of prefixes 17773173664eSapersson */ 17783173664eSapersson routers = 0; 17793173664eSapersson prefixes = 0; 17803173664eSapersson prefix_list = pi->pi_prefix_list; 17813173664eSapersson while (prefix_list != NULL) { 17823173664eSapersson prefixes++; 17833173664eSapersson prefix_list = prefix_list->pr_next; 17843173664eSapersson } 17853173664eSapersson 17863173664eSapersson /* 17873173664eSapersson * get number of routers 17883173664eSapersson */ 17893173664eSapersson router_list = pi->pi_router_list; 17903173664eSapersson while (router_list != NULL) { 17913173664eSapersson routers++; 17923173664eSapersson router_list = router_list->dr_next; 17933173664eSapersson } 17943173664eSapersson 17953173664eSapersson phyint.phyint_info_type = NDPD_PHYINT_INFO; 17963173664eSapersson phyint.phyint_info_version = NDPD_PHYINT_INFO_VER; 17973173664eSapersson phyint.phyint_index = pi->pi_index; 17983173664eSapersson bcopy(pi->pi_config, 17993173664eSapersson phyint.phyint_config, I_IFSIZE); 18003173664eSapersson phyint.phyint_num_of_prefixes = prefixes; 18013173664eSapersson phyint.phyint_num_of_routers = routers; 18023173664eSapersson (void) sendto(mibsock, &phyint, sizeof (phyint), 0, 18033173664eSapersson (struct sockaddr *)&from, fromlen); 18043173664eSapersson 18053173664eSapersson /* 18063173664eSapersson * Copy prefix information 18073173664eSapersson */ 18083173664eSapersson 18093173664eSapersson prefix_list = pi->pi_prefix_list; 18103173664eSapersson while (prefix_list != NULL) { 18113173664eSapersson prefix.prefix_info_type = NDPD_PREFIX_INFO; 18123173664eSapersson prefix.prefix_info_version = NDPD_PREFIX_INFO_VER; 18133173664eSapersson prefix.prefix_prefix = prefix_list->pr_prefix; 18143173664eSapersson prefix.prefix_len = prefix_list->pr_prefix_len; 18153173664eSapersson prefix.prefix_flags = prefix_list->pr_flags; 18163173664eSapersson prefix.prefix_phyint_index = pi->pi_index; 18173173664eSapersson prefix.prefix_ValidLifetime = 18183173664eSapersson prefix_list->pr_ValidLifetime; 18193173664eSapersson prefix.prefix_PreferredLifetime = 18203173664eSapersson prefix_list->pr_PreferredLifetime; 18213173664eSapersson prefix.prefix_OnLinkLifetime = 18223173664eSapersson prefix_list->pr_OnLinkLifetime; 18233173664eSapersson prefix.prefix_OnLinkFlag = 18243173664eSapersson prefix_list->pr_OnLinkFlag; 18253173664eSapersson prefix.prefix_AutonomousFlag = 18263173664eSapersson prefix_list->pr_AutonomousFlag; 18273173664eSapersson (void) sendto(mibsock, &prefix, sizeof (prefix), 0, 18283173664eSapersson (struct sockaddr *)&from, fromlen); 18293173664eSapersson prefix_list = prefix_list->pr_next; 18303173664eSapersson } 18313173664eSapersson /* 18323173664eSapersson * Copy router information 18333173664eSapersson */ 18343173664eSapersson router_list = pi->pi_router_list; 18353173664eSapersson while (router_list != NULL) { 18363173664eSapersson router.router_info_type = NDPD_ROUTER_INFO; 18373173664eSapersson router.router_info_version = NDPD_ROUTER_INFO_VER; 18383173664eSapersson router.router_address = router_list->dr_address; 18393173664eSapersson router.router_lifetime = router_list->dr_lifetime; 18403173664eSapersson router.router_phyint_index = pi->pi_index; 18413173664eSapersson (void) sendto(mibsock, &router, sizeof (router), 0, 18423173664eSapersson (struct sockaddr *)&from, fromlen); 18433173664eSapersson router_list = router_list->dr_next; 18443173664eSapersson } 18453173664eSapersson } 18463173664eSapersson } 18473173664eSapersson 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * Look if the phyint or one of its prefixes have been removed from 18507c478bd9Sstevel@tonic-gate * the kernel and take appropriate action. 1851e11c3f44Smeem * Uses pr_in_use and pi{,_kernel}_state. 18527c478bd9Sstevel@tonic-gate */ 18537c478bd9Sstevel@tonic-gate static void 18547c478bd9Sstevel@tonic-gate check_if_removed(struct phyint *pi) 18557c478bd9Sstevel@tonic-gate { 1856e11c3f44Smeem struct prefix *pr, *next_pr; 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * Detect prefixes which are removed. 1860e11c3f44Smeem * Static prefixes are just removed from our tables. 1861e11c3f44Smeem * Non-static prefixes are recreated i.e. in.ndpd takes precedence 1862e11c3f44Smeem * over manually removing prefixes via ifconfig. 18637c478bd9Sstevel@tonic-gate */ 18647c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 18657c478bd9Sstevel@tonic-gate next_pr = pr->pr_next; 18667c478bd9Sstevel@tonic-gate if (!pr->pr_in_use) { 1867e11c3f44Smeem /* Clear everything except PR_STATIC */ 18687c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= PR_STATIC; 1869*6e91bba0SGirish Moodalbail if (pr->pr_state & PR_STATIC) 1870*6e91bba0SGirish Moodalbail prefix_update_ipadm_addrobj(pr, _B_FALSE); 1871e11c3f44Smeem pr->pr_name[0] = '\0'; 1872e11c3f44Smeem if (pr->pr_state & PR_STATIC) { 18737c478bd9Sstevel@tonic-gate prefix_delete(pr); 1874e11c3f44Smeem } else if (!(pi->pi_kernel_state & PI_PRESENT)) { 1875e11c3f44Smeem /* 1876e11c3f44Smeem * Ensure that there are no future attempts to 1877e11c3f44Smeem * run prefix_update_k since the phyint is gone. 1878e11c3f44Smeem */ 1879e11c3f44Smeem pr->pr_state = pr->pr_kernel_state; 1880e11c3f44Smeem } else if (pr->pr_state != pr->pr_kernel_state) { 18817c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Prefix manually removed " 1882e11c3f44Smeem "on %s; recreating\n", pi->pi_name); 18837c478bd9Sstevel@tonic-gate prefix_update_k(pr); 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate } 1887e11c3f44Smeem 1888e11c3f44Smeem /* 1889e11c3f44Smeem * Detect phyints that have been removed from the kernel, and tear 1890e11c3f44Smeem * down any prefixes we created that are associated with that phyint. 1891e11c3f44Smeem * (NOTE: IPMP depends on in.ndpd tearing down these prefixes so an 1892e11c3f44Smeem * administrator can easily place an IP interface with ADDRCONF'd 1893e11c3f44Smeem * addresses into an IPMP group.) 1894e11c3f44Smeem */ 1895e11c3f44Smeem if (!(pi->pi_kernel_state & PI_PRESENT) && 1896e11c3f44Smeem (pi->pi_state & PI_PRESENT)) { 1897e11c3f44Smeem logmsg(LOG_ERR, "Interface %s has been removed from kernel. " 1898e11c3f44Smeem "in.ndpd will no longer use it\n", pi->pi_name); 1899e11c3f44Smeem 1900e11c3f44Smeem for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 1901e11c3f44Smeem next_pr = pr->pr_next; 1902e11c3f44Smeem if (pr->pr_state & PR_AUTO) 1903*6e91bba0SGirish Moodalbail prefix_update_ipadm_addrobj(pr, _B_FALSE); 1904e11c3f44Smeem prefix_delete(pr); 1905e11c3f44Smeem } 1906e11c3f44Smeem 1907e11c3f44Smeem /* 1908e11c3f44Smeem * Clear state so that should the phyint reappear we will 1909e11c3f44Smeem * start with initial advertisements or solicitations. 1910e11c3f44Smeem */ 1911e11c3f44Smeem phyint_cleanup(pi); 1912e11c3f44Smeem } 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate /* 19177c478bd9Sstevel@tonic-gate * Queuing mechanism for router advertisements that are sent by in.ndpd 19187c478bd9Sstevel@tonic-gate * and that also need to be processed by in.ndpd. 19197c478bd9Sstevel@tonic-gate * Uses "signal number" 255 to indicate to the main poll loop 19207c478bd9Sstevel@tonic-gate * that there is something to dequeue and send to incomining_ra(). 19217c478bd9Sstevel@tonic-gate */ 19227c478bd9Sstevel@tonic-gate struct raq { 19237c478bd9Sstevel@tonic-gate struct raq *raq_next; 19247c478bd9Sstevel@tonic-gate struct phyint *raq_pi; 19257c478bd9Sstevel@tonic-gate int raq_packetlen; 19267c478bd9Sstevel@tonic-gate uchar_t *raq_packet; 19277c478bd9Sstevel@tonic-gate }; 19287c478bd9Sstevel@tonic-gate static struct raq *raq_head = NULL; 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * Allocate a struct raq and memory for the packet. 19327c478bd9Sstevel@tonic-gate * Send signal 255 to have poll dequeue. 19337c478bd9Sstevel@tonic-gate */ 19347c478bd9Sstevel@tonic-gate static void 19357c478bd9Sstevel@tonic-gate loopback_ra_enqueue(struct phyint *pi, struct nd_router_advert *ra, int len) 19367c478bd9Sstevel@tonic-gate { 19377c478bd9Sstevel@tonic-gate struct raq *raq; 19387c478bd9Sstevel@tonic-gate struct raq **raqp; 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate if (no_loopback) 19417c478bd9Sstevel@tonic-gate return; 19427c478bd9Sstevel@tonic-gate 19437c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) 19447c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_enqueue for %s\n", pi->pi_name); 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate raq = calloc(sizeof (struct raq), 1); 19477c478bd9Sstevel@tonic-gate if (raq == NULL) { 19487c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 19497c478bd9Sstevel@tonic-gate return; 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate raq->raq_packet = malloc(len); 19527c478bd9Sstevel@tonic-gate if (raq->raq_packet == NULL) { 19537c478bd9Sstevel@tonic-gate free(raq); 19547c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 19557c478bd9Sstevel@tonic-gate return; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate bcopy(ra, raq->raq_packet, len); 19587c478bd9Sstevel@tonic-gate raq->raq_packetlen = len; 19597c478bd9Sstevel@tonic-gate raq->raq_pi = pi; 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate /* Tail insert */ 19627c478bd9Sstevel@tonic-gate raqp = &raq_head; 19637c478bd9Sstevel@tonic-gate while (*raqp != NULL) 19647c478bd9Sstevel@tonic-gate raqp = &((*raqp)->raq_next); 19657c478bd9Sstevel@tonic-gate *raqp = raq; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate /* Signal for poll loop */ 19687c478bd9Sstevel@tonic-gate sig_handler(255); 19697c478bd9Sstevel@tonic-gate } 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate /* 19727c478bd9Sstevel@tonic-gate * Dequeue and process all queued advertisements. 19737c478bd9Sstevel@tonic-gate */ 19747c478bd9Sstevel@tonic-gate static void 19757c478bd9Sstevel@tonic-gate loopback_ra_dequeue(void) 19767c478bd9Sstevel@tonic-gate { 19777c478bd9Sstevel@tonic-gate struct sockaddr_in6 from = IN6ADDR_LOOPBACK_INIT; 19787c478bd9Sstevel@tonic-gate struct raq *raq; 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) 19817c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue()\n"); 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate while ((raq = raq_head) != NULL) { 19847c478bd9Sstevel@tonic-gate raq_head = raq->raq_next; 19857c478bd9Sstevel@tonic-gate raq->raq_next = NULL; 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 19887c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue for %s\n", 19897c478bd9Sstevel@tonic-gate raq->raq_pi->pi_name); 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate incoming_ra(raq->raq_pi, 19937c478bd9Sstevel@tonic-gate (struct nd_router_advert *)raq->raq_packet, 19947c478bd9Sstevel@tonic-gate raq->raq_packetlen, &from, _B_TRUE); 19957c478bd9Sstevel@tonic-gate free(raq->raq_packet); 19967c478bd9Sstevel@tonic-gate free(raq); 19977c478bd9Sstevel@tonic-gate } 19987c478bd9Sstevel@tonic-gate } 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate static void 20027c478bd9Sstevel@tonic-gate usage(char *cmd) 20037c478bd9Sstevel@tonic-gate { 20047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 20057c478bd9Sstevel@tonic-gate "usage: %s [ -adt ] [-f <config file>]\n", cmd); 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate int 20097c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 20107c478bd9Sstevel@tonic-gate { 20117c478bd9Sstevel@tonic-gate int i; 20127c478bd9Sstevel@tonic-gate struct phyint *pi; 20137c478bd9Sstevel@tonic-gate int c; 20147c478bd9Sstevel@tonic-gate char *config_file = PATH_NDPD_CONF; 20157c478bd9Sstevel@tonic-gate boolean_t file_required = _B_FALSE; 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate argv0 = argv; 20187c478bd9Sstevel@tonic-gate srandom(gethostid()); 20197c478bd9Sstevel@tonic-gate (void) umask(0022); 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "adD:ntIf:")) != EOF) { 20227c478bd9Sstevel@tonic-gate switch (c) { 20237c478bd9Sstevel@tonic-gate case 'a': 20247c478bd9Sstevel@tonic-gate /* 20257c478bd9Sstevel@tonic-gate * The StatelessAddrConf variable in ndpd.conf, if 20267c478bd9Sstevel@tonic-gate * present, will override this setting. 20277c478bd9Sstevel@tonic-gate */ 20287c478bd9Sstevel@tonic-gate ifdefaults[I_StatelessAddrConf].cf_value = 0; 20297c478bd9Sstevel@tonic-gate break; 20307c478bd9Sstevel@tonic-gate case 'd': 20317c478bd9Sstevel@tonic-gate debug = D_ALL; 20327c478bd9Sstevel@tonic-gate break; 20337c478bd9Sstevel@tonic-gate case 'D': 20347c478bd9Sstevel@tonic-gate i = strtol((char *)optarg, NULL, 0); 20357c478bd9Sstevel@tonic-gate if (i == 0) { 20367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Bad debug flags: %s\n", 20377c478bd9Sstevel@tonic-gate (char *)optarg); 20387c478bd9Sstevel@tonic-gate exit(1); 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate debug |= i; 20417c478bd9Sstevel@tonic-gate break; 20427c478bd9Sstevel@tonic-gate case 'n': 20437c478bd9Sstevel@tonic-gate no_loopback = 1; 20447c478bd9Sstevel@tonic-gate break; 20457c478bd9Sstevel@tonic-gate case 'I': 20467c478bd9Sstevel@tonic-gate show_ifs = 1; 20477c478bd9Sstevel@tonic-gate break; 20487c478bd9Sstevel@tonic-gate case 't': 20497c478bd9Sstevel@tonic-gate debug |= D_PKTIN | D_PKTOUT | D_PKTBAD; 20507c478bd9Sstevel@tonic-gate break; 20517c478bd9Sstevel@tonic-gate case 'f': 20527c478bd9Sstevel@tonic-gate config_file = (char *)optarg; 20537c478bd9Sstevel@tonic-gate file_required = _B_TRUE; 20547c478bd9Sstevel@tonic-gate break; 20557c478bd9Sstevel@tonic-gate case '?': 20567c478bd9Sstevel@tonic-gate usage(argv[0]); 20577c478bd9Sstevel@tonic-gate exit(1); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate } 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate if (parse_config(config_file, file_required) == -1) 20627c478bd9Sstevel@tonic-gate exit(2); 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate if (show_ifs) 20657c478bd9Sstevel@tonic-gate phyint_print_all(); 20667c478bd9Sstevel@tonic-gate 2067*6e91bba0SGirish Moodalbail if (debug == 0) 20687c478bd9Sstevel@tonic-gate initlog(); 20697c478bd9Sstevel@tonic-gate 2070*6e91bba0SGirish Moodalbail cmdsock = ndpd_setup_cmd_listener(); 20717c478bd9Sstevel@tonic-gate setup_eventpipe(); 20727c478bd9Sstevel@tonic-gate rtsock = setup_rtsock(); 20733173664eSapersson mibsock = setup_mibsock(); 20747c478bd9Sstevel@tonic-gate timer_init(); 20757c478bd9Sstevel@tonic-gate initifs(_B_TRUE); 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate check_daemonize(); 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate for (;;) { 20807c478bd9Sstevel@tonic-gate if (poll(pollfds, pollfd_num, -1) < 0) { 20817c478bd9Sstevel@tonic-gate if (errno == EINTR) 20827c478bd9Sstevel@tonic-gate continue; 20837c478bd9Sstevel@tonic-gate logperror("main: poll"); 20847c478bd9Sstevel@tonic-gate exit(1); 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 20877c478bd9Sstevel@tonic-gate if (!(pollfds[i].revents & POLLIN)) 20887c478bd9Sstevel@tonic-gate continue; 20897c478bd9Sstevel@tonic-gate if (pollfds[i].fd == eventpipe_read) { 20907c478bd9Sstevel@tonic-gate in_signal(eventpipe_read); 20917c478bd9Sstevel@tonic-gate break; 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate if (pollfds[i].fd == rtsock) { 20947c478bd9Sstevel@tonic-gate process_rtsock(rtsock); 20957c478bd9Sstevel@tonic-gate break; 20967c478bd9Sstevel@tonic-gate } 20973173664eSapersson if (pollfds[i].fd == mibsock) { 20983173664eSapersson process_mibsock(mibsock); 20993173664eSapersson break; 21003173664eSapersson } 2101*6e91bba0SGirish Moodalbail if (pollfds[i].fd == cmdsock) { 2102*6e91bba0SGirish Moodalbail ndpd_cmd_handler(cmdsock); 2103*6e91bba0SGirish Moodalbail break; 2104*6e91bba0SGirish Moodalbail } 21057c478bd9Sstevel@tonic-gate /* 21067c478bd9Sstevel@tonic-gate * Run timer routine to advance clock if more than 21077c478bd9Sstevel@tonic-gate * half a second since the clock was advanced. 21087c478bd9Sstevel@tonic-gate * This limits CPU usage under severe packet 21097c478bd9Sstevel@tonic-gate * arrival rates but it creates a slight inaccuracy 21107c478bd9Sstevel@tonic-gate * in the timer mechanism. 21117c478bd9Sstevel@tonic-gate */ 21127c478bd9Sstevel@tonic-gate conditional_run_timeouts(500U); 21137c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 21147c478bd9Sstevel@tonic-gate if (pollfds[i].fd == pi->pi_sock) { 21157c478bd9Sstevel@tonic-gate in_data(pi); 21167c478bd9Sstevel@tonic-gate break; 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21227c478bd9Sstevel@tonic-gate return (0); 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate /* 21267c478bd9Sstevel@tonic-gate * LOGGER 21277c478bd9Sstevel@tonic-gate */ 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate static boolean_t logging = _B_FALSE; 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate static void 21327c478bd9Sstevel@tonic-gate initlog(void) 21337c478bd9Sstevel@tonic-gate { 21347c478bd9Sstevel@tonic-gate logging = _B_TRUE; 21357c478bd9Sstevel@tonic-gate openlog("in.ndpd", LOG_PID | LOG_CONS, LOG_DAEMON); 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate /* Print the date/time without a trailing carridge return */ 21397c478bd9Sstevel@tonic-gate static void 21407c478bd9Sstevel@tonic-gate fprintdate(FILE *file) 21417c478bd9Sstevel@tonic-gate { 21427c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 21437c478bd9Sstevel@tonic-gate struct tm tms; 21447c478bd9Sstevel@tonic-gate time_t now; 21457c478bd9Sstevel@tonic-gate 21467c478bd9Sstevel@tonic-gate now = time(NULL); 21477c478bd9Sstevel@tonic-gate (void) localtime_r(&now, &tms); 21487c478bd9Sstevel@tonic-gate (void) strftime(buf, sizeof (buf), "%h %d %X", &tms); 21497c478bd9Sstevel@tonic-gate (void) fprintf(file, "%s ", buf); 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate 215269bb4bb4Scarlsonj /* PRINTFLIKE2 */ 21537c478bd9Sstevel@tonic-gate void 2154b0f490f4Smh logmsg(int level, const char *fmt, ...) 21557c478bd9Sstevel@tonic-gate { 21567c478bd9Sstevel@tonic-gate va_list ap; 21577c478bd9Sstevel@tonic-gate va_start(ap, fmt); 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate if (logging) { 21607c478bd9Sstevel@tonic-gate vsyslog(level, fmt, ap); 21617c478bd9Sstevel@tonic-gate } else { 21627c478bd9Sstevel@tonic-gate fprintdate(stderr); 21637c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate va_end(ap); 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate void 2169b0f490f4Smh logperror(const char *str) 21707c478bd9Sstevel@tonic-gate { 21717c478bd9Sstevel@tonic-gate if (logging) { 21727c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 21737c478bd9Sstevel@tonic-gate } else { 21747c478bd9Sstevel@tonic-gate fprintdate(stderr); 21757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate void 2180b0f490f4Smh logperror_pi(const struct phyint *pi, const char *str) 21817c478bd9Sstevel@tonic-gate { 21827c478bd9Sstevel@tonic-gate if (logging) { 21837c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s (interface %s): %m\n", 21847c478bd9Sstevel@tonic-gate str, pi->pi_name); 21857c478bd9Sstevel@tonic-gate } else { 21867c478bd9Sstevel@tonic-gate fprintdate(stderr); 21877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s (interface %s): %s\n", 21887c478bd9Sstevel@tonic-gate str, pi->pi_name, strerror(errno)); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate } 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate void 2193b0f490f4Smh logperror_pr(const struct prefix *pr, const char *str) 21947c478bd9Sstevel@tonic-gate { 21957c478bd9Sstevel@tonic-gate if (logging) { 21967c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s (prefix %s if %s): %m\n", 21977c478bd9Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name); 21987c478bd9Sstevel@tonic-gate } else { 21997c478bd9Sstevel@tonic-gate fprintdate(stderr); 22007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s (prefix %s if %s): %s\n", 22017c478bd9Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name, 22027c478bd9Sstevel@tonic-gate strerror(errno)); 22037c478bd9Sstevel@tonic-gate } 22047c478bd9Sstevel@tonic-gate } 2205*6e91bba0SGirish Moodalbail 2206*6e91bba0SGirish Moodalbail static int 2207*6e91bba0SGirish Moodalbail ndpd_setup_cmd_listener(void) 2208*6e91bba0SGirish Moodalbail { 2209*6e91bba0SGirish Moodalbail int sock; 2210*6e91bba0SGirish Moodalbail int ret; 2211*6e91bba0SGirish Moodalbail struct sockaddr_un servaddr; 2212*6e91bba0SGirish Moodalbail 2213*6e91bba0SGirish Moodalbail sock = socket(AF_UNIX, SOCK_STREAM, 0); 2214*6e91bba0SGirish Moodalbail if (sock < 0) { 2215*6e91bba0SGirish Moodalbail logperror("socket"); 2216*6e91bba0SGirish Moodalbail exit(1); 2217*6e91bba0SGirish Moodalbail } 2218*6e91bba0SGirish Moodalbail 2219*6e91bba0SGirish Moodalbail bzero(&servaddr, sizeof (servaddr)); 2220*6e91bba0SGirish Moodalbail servaddr.sun_family = AF_UNIX; 2221*6e91bba0SGirish Moodalbail (void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH, 2222*6e91bba0SGirish Moodalbail sizeof (servaddr.sun_path)); 2223*6e91bba0SGirish Moodalbail (void) unlink(servaddr.sun_path); 2224*6e91bba0SGirish Moodalbail ret = bind(sock, (struct sockaddr *)&servaddr, sizeof (servaddr)); 2225*6e91bba0SGirish Moodalbail if (ret < 0) { 2226*6e91bba0SGirish Moodalbail logperror("bind"); 2227*6e91bba0SGirish Moodalbail exit(1); 2228*6e91bba0SGirish Moodalbail } 2229*6e91bba0SGirish Moodalbail if (listen(sock, 30) < 0) { 2230*6e91bba0SGirish Moodalbail logperror("listen"); 2231*6e91bba0SGirish Moodalbail exit(1); 2232*6e91bba0SGirish Moodalbail } 2233*6e91bba0SGirish Moodalbail if (poll_add(sock) == -1) { 2234*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "command socket could not be added to the " 2235*6e91bba0SGirish Moodalbail "polling set\n"); 2236*6e91bba0SGirish Moodalbail exit(1); 2237*6e91bba0SGirish Moodalbail } 2238*6e91bba0SGirish Moodalbail 2239*6e91bba0SGirish Moodalbail return (sock); 2240*6e91bba0SGirish Moodalbail } 2241*6e91bba0SGirish Moodalbail 2242*6e91bba0SGirish Moodalbail /* 2243*6e91bba0SGirish Moodalbail * Commands received over the command socket come here 2244*6e91bba0SGirish Moodalbail */ 2245*6e91bba0SGirish Moodalbail static void 2246*6e91bba0SGirish Moodalbail ndpd_cmd_handler(int sock) 2247*6e91bba0SGirish Moodalbail { 2248*6e91bba0SGirish Moodalbail int newfd; 2249*6e91bba0SGirish Moodalbail struct sockaddr_storage peer; 2250*6e91bba0SGirish Moodalbail socklen_t peerlen; 2251*6e91bba0SGirish Moodalbail ipadm_ndpd_msg_t ndpd_msg; 2252*6e91bba0SGirish Moodalbail int retval; 2253*6e91bba0SGirish Moodalbail 2254*6e91bba0SGirish Moodalbail peerlen = sizeof (peer); 2255*6e91bba0SGirish Moodalbail newfd = accept(sock, (struct sockaddr *)&peer, &peerlen); 2256*6e91bba0SGirish Moodalbail if (newfd < 0) { 2257*6e91bba0SGirish Moodalbail logperror("accept"); 2258*6e91bba0SGirish Moodalbail return; 2259*6e91bba0SGirish Moodalbail } 2260*6e91bba0SGirish Moodalbail 2261*6e91bba0SGirish Moodalbail retval = ipadm_ndpd_read(newfd, &ndpd_msg, sizeof (ndpd_msg)); 2262*6e91bba0SGirish Moodalbail if (retval != 0) 2263*6e91bba0SGirish Moodalbail logperror("Could not read ndpd command"); 2264*6e91bba0SGirish Moodalbail 2265*6e91bba0SGirish Moodalbail retval = ndpd_process_cmd(newfd, &ndpd_msg); 2266*6e91bba0SGirish Moodalbail if (retval != 0) { 2267*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "ndpd command on interface %s failed with " 2268*6e91bba0SGirish Moodalbail "error %s\n", ndpd_msg.inm_ifname, strerror(retval)); 2269*6e91bba0SGirish Moodalbail } 2270*6e91bba0SGirish Moodalbail (void) close(newfd); 2271*6e91bba0SGirish Moodalbail } 2272*6e91bba0SGirish Moodalbail 2273*6e91bba0SGirish Moodalbail /* 2274*6e91bba0SGirish Moodalbail * Process the commands received from the cmd listener socket. 2275*6e91bba0SGirish Moodalbail */ 2276*6e91bba0SGirish Moodalbail static int 2277*6e91bba0SGirish Moodalbail ndpd_process_cmd(int newfd, ipadm_ndpd_msg_t *msg) 2278*6e91bba0SGirish Moodalbail { 2279*6e91bba0SGirish Moodalbail int err; 2280*6e91bba0SGirish Moodalbail 2281*6e91bba0SGirish Moodalbail if (!ipadm_check_auth()) { 2282*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "User not authorized to send the command\n"); 2283*6e91bba0SGirish Moodalbail (void) ndpd_send_error(newfd, EPERM); 2284*6e91bba0SGirish Moodalbail return (EPERM); 2285*6e91bba0SGirish Moodalbail } 2286*6e91bba0SGirish Moodalbail switch (msg->inm_cmd) { 2287*6e91bba0SGirish Moodalbail case IPADM_DISABLE_AUTOCONF: 2288*6e91bba0SGirish Moodalbail err = ndpd_set_autoconf(msg->inm_ifname, _B_FALSE); 2289*6e91bba0SGirish Moodalbail break; 2290*6e91bba0SGirish Moodalbail 2291*6e91bba0SGirish Moodalbail case IPADM_ENABLE_AUTOCONF: 2292*6e91bba0SGirish Moodalbail err = ndpd_set_autoconf(msg->inm_ifname, _B_TRUE); 2293*6e91bba0SGirish Moodalbail break; 2294*6e91bba0SGirish Moodalbail 2295*6e91bba0SGirish Moodalbail case IPADM_CREATE_ADDRS: 2296*6e91bba0SGirish Moodalbail err = ndpd_create_addrs(msg->inm_ifname, msg->inm_intfid, 2297*6e91bba0SGirish Moodalbail msg->inm_intfidlen, msg->inm_stateless, 2298*6e91bba0SGirish Moodalbail msg->inm_stateful, msg->inm_aobjname); 2299*6e91bba0SGirish Moodalbail break; 2300*6e91bba0SGirish Moodalbail 2301*6e91bba0SGirish Moodalbail case IPADM_DELETE_ADDRS: 2302*6e91bba0SGirish Moodalbail err = ndpd_delete_addrs(msg->inm_ifname); 2303*6e91bba0SGirish Moodalbail break; 2304*6e91bba0SGirish Moodalbail 2305*6e91bba0SGirish Moodalbail default: 2306*6e91bba0SGirish Moodalbail err = EINVAL; 2307*6e91bba0SGirish Moodalbail break; 2308*6e91bba0SGirish Moodalbail } 2309*6e91bba0SGirish Moodalbail 2310*6e91bba0SGirish Moodalbail (void) ndpd_send_error(newfd, err); 2311*6e91bba0SGirish Moodalbail 2312*6e91bba0SGirish Moodalbail return (err); 2313*6e91bba0SGirish Moodalbail } 2314*6e91bba0SGirish Moodalbail 2315*6e91bba0SGirish Moodalbail static int 2316*6e91bba0SGirish Moodalbail ndpd_send_error(int fd, int error) 2317*6e91bba0SGirish Moodalbail { 2318*6e91bba0SGirish Moodalbail return (ipadm_ndpd_write(fd, &error, sizeof (error))); 2319*6e91bba0SGirish Moodalbail } 2320*6e91bba0SGirish Moodalbail 2321*6e91bba0SGirish Moodalbail /* 2322*6e91bba0SGirish Moodalbail * Disables/Enables autoconfiguration of addresses on the 2323*6e91bba0SGirish Moodalbail * given physical interface. 2324*6e91bba0SGirish Moodalbail * This is provided to support the legacy method of configuring IPv6 2325*6e91bba0SGirish Moodalbail * addresses. i.e. `ifconfig bge0 inet6 plumb` will plumb the interface 2326*6e91bba0SGirish Moodalbail * and start stateless and stateful autoconfiguration. If this function is 2327*6e91bba0SGirish Moodalbail * not called with enable=_B_FALSE, no autoconfiguration will be done until 2328*6e91bba0SGirish Moodalbail * ndpd_create_addrs() is called with an Interface ID. 2329*6e91bba0SGirish Moodalbail */ 2330*6e91bba0SGirish Moodalbail static int 2331*6e91bba0SGirish Moodalbail ndpd_set_autoconf(const char *ifname, boolean_t enable) 2332*6e91bba0SGirish Moodalbail { 2333*6e91bba0SGirish Moodalbail struct phyint *pi; 2334*6e91bba0SGirish Moodalbail 2335*6e91bba0SGirish Moodalbail pi = phyint_lookup((char *)ifname); 2336*6e91bba0SGirish Moodalbail if (pi == NULL) { 2337*6e91bba0SGirish Moodalbail /* 2338*6e91bba0SGirish Moodalbail * If the physical interface was plumbed but no 2339*6e91bba0SGirish Moodalbail * addresses were configured yet, phyint will not exist. 2340*6e91bba0SGirish Moodalbail */ 2341*6e91bba0SGirish Moodalbail pi = phyint_create((char *)ifname); 2342*6e91bba0SGirish Moodalbail if (pi == NULL) { 2343*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "could not create phyint for " 2344*6e91bba0SGirish Moodalbail "interface %s", ifname); 2345*6e91bba0SGirish Moodalbail return (ENOMEM); 2346*6e91bba0SGirish Moodalbail } 2347*6e91bba0SGirish Moodalbail } 2348*6e91bba0SGirish Moodalbail pi->pi_autoconf = enable; 2349*6e91bba0SGirish Moodalbail 2350*6e91bba0SGirish Moodalbail if (debug & D_PHYINT) { 2351*6e91bba0SGirish Moodalbail logmsg(LOG_DEBUG, "ndpd_set_autoconf: %s autoconf for " 2352*6e91bba0SGirish Moodalbail "interface %s\n", (enable ? "enabled" : "disabled"), 2353*6e91bba0SGirish Moodalbail pi->pi_name); 2354*6e91bba0SGirish Moodalbail } 2355*6e91bba0SGirish Moodalbail return (0); 2356*6e91bba0SGirish Moodalbail } 2357*6e91bba0SGirish Moodalbail 2358*6e91bba0SGirish Moodalbail /* 2359*6e91bba0SGirish Moodalbail * Create auto-configured addresses on the given interface using 2360*6e91bba0SGirish Moodalbail * the given token as the interface id during the next Router Advertisement. 2361*6e91bba0SGirish Moodalbail * Currently, only one token per interface is supported. 2362*6e91bba0SGirish Moodalbail */ 2363*6e91bba0SGirish Moodalbail static int 2364*6e91bba0SGirish Moodalbail ndpd_create_addrs(const char *ifname, struct sockaddr_in6 intfid, int intfidlen, 2365*6e91bba0SGirish Moodalbail boolean_t stateless, boolean_t stateful, char *addrobj) 2366*6e91bba0SGirish Moodalbail { 2367*6e91bba0SGirish Moodalbail struct phyint *pi; 2368*6e91bba0SGirish Moodalbail struct lifreq lifr; 2369*6e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 2370*6e91bba0SGirish Moodalbail int err; 2371*6e91bba0SGirish Moodalbail 2372*6e91bba0SGirish Moodalbail pi = phyint_lookup((char *)ifname); 2373*6e91bba0SGirish Moodalbail if (pi == NULL) { 2374*6e91bba0SGirish Moodalbail /* 2375*6e91bba0SGirish Moodalbail * If the physical interface was plumbed but no 2376*6e91bba0SGirish Moodalbail * addresses were configured yet, phyint will not exist. 2377*6e91bba0SGirish Moodalbail */ 2378*6e91bba0SGirish Moodalbail pi = phyint_create((char *)ifname); 2379*6e91bba0SGirish Moodalbail if (pi == NULL) { 2380*6e91bba0SGirish Moodalbail if (debug & D_PHYINT) 2381*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "could not create phyint " 2382*6e91bba0SGirish Moodalbail "for interface %s", ifname); 2383*6e91bba0SGirish Moodalbail return (ENOMEM); 2384*6e91bba0SGirish Moodalbail } 2385*6e91bba0SGirish Moodalbail } else if (pi->pi_autoconf) { 2386*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "autoconfiguration already in progress\n"); 2387*6e91bba0SGirish Moodalbail return (EEXIST); 2388*6e91bba0SGirish Moodalbail } 2389*6e91bba0SGirish Moodalbail check_autoconf_var_consistency(pi, stateless, stateful); 2390*6e91bba0SGirish Moodalbail 2391*6e91bba0SGirish Moodalbail if (intfidlen == 0) { 2392*6e91bba0SGirish Moodalbail pi->pi_default_token = _B_TRUE; 2393*6e91bba0SGirish Moodalbail if (ifsock < 0) { 2394*6e91bba0SGirish Moodalbail ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 2395*6e91bba0SGirish Moodalbail if (ifsock < 0) { 2396*6e91bba0SGirish Moodalbail err = errno; 2397*6e91bba0SGirish Moodalbail logperror("ndpd_create_addrs: socket"); 2398*6e91bba0SGirish Moodalbail return (err); 2399*6e91bba0SGirish Moodalbail } 2400*6e91bba0SGirish Moodalbail } 2401*6e91bba0SGirish Moodalbail (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2402*6e91bba0SGirish Moodalbail sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 2403*6e91bba0SGirish Moodalbail if (ioctl(ifsock, SIOCGLIFTOKEN, (char *)&lifr) < 0) { 2404*6e91bba0SGirish Moodalbail err = errno; 2405*6e91bba0SGirish Moodalbail logperror("SIOCGLIFTOKEN"); 2406*6e91bba0SGirish Moodalbail return (err); 2407*6e91bba0SGirish Moodalbail } 2408*6e91bba0SGirish Moodalbail pi->pi_token = sin6->sin6_addr; 2409*6e91bba0SGirish Moodalbail pi->pi_token_length = lifr.lifr_addrlen; 2410*6e91bba0SGirish Moodalbail } else { 2411*6e91bba0SGirish Moodalbail pi->pi_default_token = _B_FALSE; 2412*6e91bba0SGirish Moodalbail pi->pi_token = intfid.sin6_addr; 2413*6e91bba0SGirish Moodalbail pi->pi_token_length = intfidlen; 2414*6e91bba0SGirish Moodalbail } 2415*6e91bba0SGirish Moodalbail pi->pi_stateless = stateless; 2416*6e91bba0SGirish Moodalbail pi->pi_stateful = stateful; 2417*6e91bba0SGirish Moodalbail (void) strlcpy(pi->pi_ipadm_aobjname, addrobj, 2418*6e91bba0SGirish Moodalbail sizeof (pi->pi_ipadm_aobjname)); 2419*6e91bba0SGirish Moodalbail 2420*6e91bba0SGirish Moodalbail /* We can allow autoconfiguration now. */ 2421*6e91bba0SGirish Moodalbail pi->pi_autoconf = _B_TRUE; 2422*6e91bba0SGirish Moodalbail 2423*6e91bba0SGirish Moodalbail /* Restart the solicitations. */ 2424*6e91bba0SGirish Moodalbail if (pi->pi_sol_state == DONE_SOLICIT) 2425*6e91bba0SGirish Moodalbail pi->pi_sol_state = NO_SOLICIT; 2426*6e91bba0SGirish Moodalbail if (pi->pi_sol_state == NO_SOLICIT) 2427*6e91bba0SGirish Moodalbail check_to_solicit(pi, START_INIT_SOLICIT); 2428*6e91bba0SGirish Moodalbail if (debug & D_PHYINT) 2429*6e91bba0SGirish Moodalbail logmsg(LOG_DEBUG, "ndpd_create_addrs: " 2430*6e91bba0SGirish Moodalbail "added token to interface %s\n", pi->pi_name); 2431*6e91bba0SGirish Moodalbail return (0); 2432*6e91bba0SGirish Moodalbail } 2433*6e91bba0SGirish Moodalbail 2434*6e91bba0SGirish Moodalbail /* 2435*6e91bba0SGirish Moodalbail * This function deletes all addresses on the given interface 2436*6e91bba0SGirish Moodalbail * with the given Interface ID. 2437*6e91bba0SGirish Moodalbail */ 2438*6e91bba0SGirish Moodalbail static int 2439*6e91bba0SGirish Moodalbail ndpd_delete_addrs(const char *ifname) 2440*6e91bba0SGirish Moodalbail { 2441*6e91bba0SGirish Moodalbail struct phyint *pi; 2442*6e91bba0SGirish Moodalbail struct prefix *pr, *next_pr; 2443*6e91bba0SGirish Moodalbail struct lifreq lifr; 2444*6e91bba0SGirish Moodalbail int err; 2445*6e91bba0SGirish Moodalbail 2446*6e91bba0SGirish Moodalbail pi = phyint_lookup((char *)ifname); 2447*6e91bba0SGirish Moodalbail if (pi == NULL) { 2448*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "no phyint found for %s", ifname); 2449*6e91bba0SGirish Moodalbail return (ENXIO); 2450*6e91bba0SGirish Moodalbail } 2451*6e91bba0SGirish Moodalbail if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_token)) { 2452*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "token does not exist for %s", ifname); 2453*6e91bba0SGirish Moodalbail return (EINVAL); 2454*6e91bba0SGirish Moodalbail } 2455*6e91bba0SGirish Moodalbail 2456*6e91bba0SGirish Moodalbail if (ifsock < 0) { 2457*6e91bba0SGirish Moodalbail ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 2458*6e91bba0SGirish Moodalbail if (ifsock < 0) { 2459*6e91bba0SGirish Moodalbail err = errno; 2460*6e91bba0SGirish Moodalbail logperror("ndpd_create_addrs: socket"); 2461*6e91bba0SGirish Moodalbail return (err); 2462*6e91bba0SGirish Moodalbail } 2463*6e91bba0SGirish Moodalbail } 2464*6e91bba0SGirish Moodalbail /* Remove the prefixes for this phyint if they exist */ 2465*6e91bba0SGirish Moodalbail for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 2466*6e91bba0SGirish Moodalbail next_pr = pr->pr_next; 2467*6e91bba0SGirish Moodalbail if (pr->pr_name[0] == '\0') { 2468*6e91bba0SGirish Moodalbail prefix_delete(pr); 2469*6e91bba0SGirish Moodalbail continue; 2470*6e91bba0SGirish Moodalbail } 2471*6e91bba0SGirish Moodalbail /* 2472*6e91bba0SGirish Moodalbail * Delete all the prefixes for the auto-configured 2473*6e91bba0SGirish Moodalbail * addresses as well as the DHCPv6 addresses. 2474*6e91bba0SGirish Moodalbail */ 2475*6e91bba0SGirish Moodalbail (void) strncpy(lifr.lifr_name, pr->pr_name, 2476*6e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 2477*6e91bba0SGirish Moodalbail if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 2478*6e91bba0SGirish Moodalbail err = errno; 2479*6e91bba0SGirish Moodalbail logperror("SIOCGLIFFLAGS"); 2480*6e91bba0SGirish Moodalbail return (err); 2481*6e91bba0SGirish Moodalbail } 2482*6e91bba0SGirish Moodalbail if ((lifr.lifr_flags & IFF_ADDRCONF) || 2483*6e91bba0SGirish Moodalbail (lifr.lifr_flags & IFF_DHCPRUNNING)) { 2484*6e91bba0SGirish Moodalbail prefix_update_ipadm_addrobj(pr, _B_FALSE); 2485*6e91bba0SGirish Moodalbail } 2486*6e91bba0SGirish Moodalbail prefix_delete(pr); 2487*6e91bba0SGirish Moodalbail } 2488*6e91bba0SGirish Moodalbail 2489*6e91bba0SGirish Moodalbail /* 2490*6e91bba0SGirish Moodalbail * If we had started dhcpagent, we need to release the leases 2491*6e91bba0SGirish Moodalbail * if any are required. 2492*6e91bba0SGirish Moodalbail */ 2493*6e91bba0SGirish Moodalbail if (pi->pi_stateful) { 2494*6e91bba0SGirish Moodalbail (void) strncpy(lifr.lifr_name, pi->pi_name, 2495*6e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 2496*6e91bba0SGirish Moodalbail if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 2497*6e91bba0SGirish Moodalbail err = errno; 2498*6e91bba0SGirish Moodalbail logperror("SIOCGLIFFLAGS"); 2499*6e91bba0SGirish Moodalbail return (err); 2500*6e91bba0SGirish Moodalbail } 2501*6e91bba0SGirish Moodalbail if (lifr.lifr_flags & IFF_DHCPRUNNING) 2502*6e91bba0SGirish Moodalbail release_dhcp(pi); 2503*6e91bba0SGirish Moodalbail } 2504*6e91bba0SGirish Moodalbail 2505*6e91bba0SGirish Moodalbail /* 2506*6e91bba0SGirish Moodalbail * Reset the Interface ID on this phyint and stop autoconfigurations 2507*6e91bba0SGirish Moodalbail * until a new interface ID is provided. 2508*6e91bba0SGirish Moodalbail */ 2509*6e91bba0SGirish Moodalbail pi->pi_token = in6addr_any; 2510*6e91bba0SGirish Moodalbail pi->pi_token_length = 0; 2511*6e91bba0SGirish Moodalbail pi->pi_autoconf = _B_FALSE; 2512*6e91bba0SGirish Moodalbail pi->pi_ipadm_aobjname[0] = '\0'; 2513*6e91bba0SGirish Moodalbail 2514*6e91bba0SGirish Moodalbail /* Reset the stateless and stateful settings to default. */ 2515*6e91bba0SGirish Moodalbail pi->pi_stateless = pi->pi_StatelessAddrConf; 2516*6e91bba0SGirish Moodalbail pi->pi_stateful = pi->pi_StatefulAddrConf; 2517*6e91bba0SGirish Moodalbail 2518*6e91bba0SGirish Moodalbail if (debug & D_PHYINT) { 2519*6e91bba0SGirish Moodalbail logmsg(LOG_DEBUG, "ndpd_delete_addrs: " 2520*6e91bba0SGirish Moodalbail "removed token from interface %s\n", pi->pi_name); 2521*6e91bba0SGirish Moodalbail } 2522*6e91bba0SGirish Moodalbail return (0); 2523*6e91bba0SGirish Moodalbail } 2524*6e91bba0SGirish Moodalbail 2525*6e91bba0SGirish Moodalbail void 2526*6e91bba0SGirish Moodalbail check_autoconf_var_consistency(struct phyint *pi, boolean_t stateless, 2527*6e91bba0SGirish Moodalbail boolean_t stateful) 2528*6e91bba0SGirish Moodalbail { 2529*6e91bba0SGirish Moodalbail /* 2530*6e91bba0SGirish Moodalbail * If StatelessAddrConf and StatelessAddrConf are set in 2531*6e91bba0SGirish Moodalbail * /etc/inet/ndpd.conf, check if the new values override those 2532*6e91bba0SGirish Moodalbail * settings. If so, log a warning. 2533*6e91bba0SGirish Moodalbail */ 2534*6e91bba0SGirish Moodalbail if ((pi->pi_StatelessAddrConf != 2535*6e91bba0SGirish Moodalbail ifdefaults[I_StatelessAddrConf].cf_value && 2536*6e91bba0SGirish Moodalbail stateless != pi->pi_StatelessAddrConf) || 2537*6e91bba0SGirish Moodalbail (pi->pi_StatefulAddrConf != 2538*6e91bba0SGirish Moodalbail ifdefaults[I_StatefulAddrConf].cf_value && 2539*6e91bba0SGirish Moodalbail stateful != pi->pi_StatefulAddrConf)) { 2540*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "check_autoconf_var_consistency: " 2541*6e91bba0SGirish Moodalbail "Overriding the StatelessAddrConf or StatefulAddrConf " 2542*6e91bba0SGirish Moodalbail "settings in ndpd.conf with the new values for " 2543*6e91bba0SGirish Moodalbail "interface %s\n", pi->pi_name); 2544*6e91bba0SGirish Moodalbail } 2545*6e91bba0SGirish Moodalbail } 2546*6e91bba0SGirish Moodalbail 2547*6e91bba0SGirish Moodalbail /* 2548*6e91bba0SGirish Moodalbail * If ipadm was used to start autoconfiguration and in.ndpd was restarted 2549*6e91bba0SGirish Moodalbail * for some reason, in.ndpd has to resume autoconfiguration when it comes up. 2550*6e91bba0SGirish Moodalbail * In this function, it scans the ipadm_addr_info() output to find a link-local 2551*6e91bba0SGirish Moodalbail * on this interface with address type "addrconf" and extracts the interface id. 2552*6e91bba0SGirish Moodalbail * It also stores the addrobj name to be used later when new addresses are 2553*6e91bba0SGirish Moodalbail * created for the prefixes advertised by the router. 2554*6e91bba0SGirish Moodalbail * If autoconfiguration was never started on this interface before in.ndpd 2555*6e91bba0SGirish Moodalbail * was killed, then in.ndpd should refrain from configuring prefixes, even if 2556*6e91bba0SGirish Moodalbail * there is a valid link-local on this interface, created by ipadm (identified 2557*6e91bba0SGirish Moodalbail * if there is a valid addrobj name). 2558*6e91bba0SGirish Moodalbail */ 2559*6e91bba0SGirish Moodalbail static int 2560*6e91bba0SGirish Moodalbail phyint_check_ipadm_intfid(struct phyint *pi) 2561*6e91bba0SGirish Moodalbail { 2562*6e91bba0SGirish Moodalbail ipadm_status_t status; 2563*6e91bba0SGirish Moodalbail ipadm_addr_info_t *addrinfo; 2564*6e91bba0SGirish Moodalbail struct ifaddrs *ifap; 2565*6e91bba0SGirish Moodalbail ipadm_addr_info_t *ainfop; 2566*6e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 2567*6e91bba0SGirish Moodalbail ipadm_handle_t iph; 2568*6e91bba0SGirish Moodalbail 2569*6e91bba0SGirish Moodalbail if (ipadm_open(&iph, 0) != IPADM_SUCCESS) { 2570*6e91bba0SGirish Moodalbail logmsg(LOG_ERR, "could not open handle to libipadm\n"); 2571*6e91bba0SGirish Moodalbail return (-1); 2572*6e91bba0SGirish Moodalbail } 2573*6e91bba0SGirish Moodalbail 2574*6e91bba0SGirish Moodalbail status = ipadm_addr_info(iph, pi->pi_name, &addrinfo, 2575*6e91bba0SGirish Moodalbail IPADM_OPT_ZEROADDR, LIFC_NOXMIT|LIFC_TEMPORARY); 2576*6e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) { 2577*6e91bba0SGirish Moodalbail ipadm_close(iph); 2578*6e91bba0SGirish Moodalbail return (-1); 2579*6e91bba0SGirish Moodalbail } 2580*6e91bba0SGirish Moodalbail pi->pi_autoconf = _B_TRUE; 2581*6e91bba0SGirish Moodalbail for (ainfop = addrinfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) { 2582*6e91bba0SGirish Moodalbail ifap = &ainfop->ia_ifa; 2583*6e91bba0SGirish Moodalbail if (ifap->ifa_addr->ss_family != AF_INET6 || 2584*6e91bba0SGirish Moodalbail ainfop->ia_state == IFA_DISABLED) 2585*6e91bba0SGirish Moodalbail continue; 2586*6e91bba0SGirish Moodalbail sin6 = (struct sockaddr_in6 *)ifap->ifa_addr; 2587*6e91bba0SGirish Moodalbail if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 2588*6e91bba0SGirish Moodalbail if (ainfop->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) { 2589*6e91bba0SGirish Moodalbail pi->pi_token = sin6->sin6_addr; 2590*6e91bba0SGirish Moodalbail pi->pi_token._S6_un._S6_u32[0] = 0; 2591*6e91bba0SGirish Moodalbail pi->pi_token._S6_un._S6_u32[1] = 0; 2592*6e91bba0SGirish Moodalbail pi->pi_autoconf = _B_TRUE; 2593*6e91bba0SGirish Moodalbail (void) strlcpy(pi->pi_ipadm_aobjname, 2594*6e91bba0SGirish Moodalbail ainfop->ia_aobjname, 2595*6e91bba0SGirish Moodalbail sizeof (pi->pi_ipadm_aobjname)); 2596*6e91bba0SGirish Moodalbail break; 2597*6e91bba0SGirish Moodalbail } 2598*6e91bba0SGirish Moodalbail /* 2599*6e91bba0SGirish Moodalbail * If IFF_NOLINKLOCAL is set, then the link-local 2600*6e91bba0SGirish Moodalbail * was created using ipadm. Do not autoconfigure until 2601*6e91bba0SGirish Moodalbail * ipadm is explicitly used for autoconfiguration. 2602*6e91bba0SGirish Moodalbail */ 2603*6e91bba0SGirish Moodalbail if (ifap->ifa_flags & IFF_NOLINKLOCAL) 2604*6e91bba0SGirish Moodalbail pi->pi_autoconf = _B_FALSE; 2605*6e91bba0SGirish Moodalbail } else if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 2606*6e91bba0SGirish Moodalbail strrchr(ifap->ifa_name, ':') == NULL) { 2607*6e91bba0SGirish Moodalbail /* The interface was created using ipadm. */ 2608*6e91bba0SGirish Moodalbail pi->pi_autoconf = _B_FALSE; 2609*6e91bba0SGirish Moodalbail } 2610*6e91bba0SGirish Moodalbail } 2611*6e91bba0SGirish Moodalbail ipadm_free_addr_info(addrinfo); 2612*6e91bba0SGirish Moodalbail if (!pi->pi_autoconf) { 2613*6e91bba0SGirish Moodalbail pi->pi_token = in6addr_any; 2614*6e91bba0SGirish Moodalbail pi->pi_token_length = 0; 2615*6e91bba0SGirish Moodalbail } 2616*6e91bba0SGirish Moodalbail ipadm_close(iph); 2617*6e91bba0SGirish Moodalbail return (0); 2618*6e91bba0SGirish Moodalbail } 2619