10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51577Sseb * Common Development and Distribution License (the "License"). 61577Sseb * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3431Scarlsonj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include "defs.h" 290Sstevel@tonic-gate #include "tables.h" 300Sstevel@tonic-gate #include <fcntl.h> 313284Sapersson #include <sys/un.h> 320Sstevel@tonic-gate 330Sstevel@tonic-gate static void initlog(void); 340Sstevel@tonic-gate static void run_timeouts(void); 350Sstevel@tonic-gate 360Sstevel@tonic-gate static void advertise(struct sockaddr_in6 *sin6, struct phyint *pi, 370Sstevel@tonic-gate boolean_t no_prefixes); 380Sstevel@tonic-gate static void solicit(struct sockaddr_in6 *sin6, struct phyint *pi); 390Sstevel@tonic-gate static void initifs(boolean_t first); 400Sstevel@tonic-gate static void check_if_removed(struct phyint *pi); 410Sstevel@tonic-gate static void loopback_ra_enqueue(struct phyint *pi, 420Sstevel@tonic-gate struct nd_router_advert *ra, int len); 430Sstevel@tonic-gate static void loopback_ra_dequeue(void); 440Sstevel@tonic-gate static void check_daemonize(void); 450Sstevel@tonic-gate 460Sstevel@tonic-gate struct in6_addr all_nodes_mcast = { { 0xff, 0x2, 0x0, 0x0, 470Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 480Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 490Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } }; 500Sstevel@tonic-gate 510Sstevel@tonic-gate struct in6_addr all_routers_mcast = { { 0xff, 0x2, 0x0, 0x0, 520Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 530Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 540Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } }; 550Sstevel@tonic-gate 560Sstevel@tonic-gate static struct sockaddr_in6 v6allnodes = { AF_INET6, 0, 0, 570Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 580Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 590Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 600Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } }; 610Sstevel@tonic-gate 620Sstevel@tonic-gate static struct sockaddr_in6 v6allrouters = { AF_INET6, 0, 0, 630Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 640Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 650Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 660Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } }; 670Sstevel@tonic-gate 680Sstevel@tonic-gate static char **argv0; /* Saved for re-exec on SIGHUP */ 690Sstevel@tonic-gate 700Sstevel@tonic-gate static uint64_t packet[(IP_MAXPACKET + 1)/8]; 710Sstevel@tonic-gate 720Sstevel@tonic-gate static int show_ifs = 0; 730Sstevel@tonic-gate static boolean_t already_daemonized = _B_FALSE; 740Sstevel@tonic-gate int debug = 0; 750Sstevel@tonic-gate int no_loopback = 0; /* Do not send RA packets to ourselves */ 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* 780Sstevel@tonic-gate * Size of routing socket message used by in.ndpd which includes the header, 790Sstevel@tonic-gate * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6) 800Sstevel@tonic-gate * plus space for the RTA_IFP (a sockaddr_dl). 810Sstevel@tonic-gate */ 820Sstevel@tonic-gate #define NDP_RTM_MSGLEN sizeof (struct rt_msghdr) + \ 830Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 840Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 850Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 860Sstevel@tonic-gate sizeof (struct sockaddr_dl) 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * These are referenced externally in tables.c in order to fill in the 900Sstevel@tonic-gate * dynamic portions of the routing socket message and then to send the message 910Sstevel@tonic-gate * itself. 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate int rtsock = -1; /* Routing socket */ 940Sstevel@tonic-gate struct rt_msghdr *rt_msg; /* Routing socket message */ 950Sstevel@tonic-gate struct sockaddr_in6 *rta_gateway; /* RTA_GATEWAY sockaddr */ 960Sstevel@tonic-gate struct sockaddr_dl *rta_ifp; /* RTA_IFP sockaddr */ 973284Sapersson int mibsock = -1; /* mib request socket */ 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * Return the current time in milliseconds truncated to 1010Sstevel@tonic-gate * fit in an integer. 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate uint_t 1040Sstevel@tonic-gate getcurrenttime(void) 1050Sstevel@tonic-gate { 1060Sstevel@tonic-gate struct timeval tp; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate if (gettimeofday(&tp, NULL) < 0) { 1090Sstevel@tonic-gate logperror("getcurrenttime: gettimeofday failed"); 1100Sstevel@tonic-gate exit(1); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate return (tp.tv_sec * 1000 + tp.tv_usec / 1000); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * Output a preformated packet from the packet[] buffer. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate static void 1190Sstevel@tonic-gate sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate int cc; 1220Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate cc = sendto(sock, (char *)packet, size, flags, 1250Sstevel@tonic-gate (struct sockaddr *)sin6, sizeof (*sin6)); 1260Sstevel@tonic-gate if (cc < 0 || cc != size) { 1270Sstevel@tonic-gate if (cc < 0) { 1280Sstevel@tonic-gate logperror("sendpacket: sendto"); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate logmsg(LOG_ERR, "sendpacket: wrote %s %d chars, ret=%d\n", 1310Sstevel@tonic-gate inet_ntop(sin6->sin6_family, 1320Sstevel@tonic-gate (void *)&sin6->sin6_addr, 1330Sstevel@tonic-gate abuf, sizeof (abuf)), 1340Sstevel@tonic-gate size, cc); 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* Send a Router Solicitation */ 1390Sstevel@tonic-gate static void 1400Sstevel@tonic-gate solicit(struct sockaddr_in6 *sin6, struct phyint *pi) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate int packetlen = 0; 1430Sstevel@tonic-gate struct nd_router_solicit *rs = (struct nd_router_solicit *)packet; 1440Sstevel@tonic-gate char *pptr = (char *)packet; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate rs->nd_rs_type = ND_ROUTER_SOLICIT; 1470Sstevel@tonic-gate rs->nd_rs_code = 0; 1480Sstevel@tonic-gate rs->nd_rs_cksum = htons(0); 1490Sstevel@tonic-gate rs->nd_rs_reserved = htonl(0); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate packetlen += sizeof (*rs); 1520Sstevel@tonic-gate pptr += sizeof (*rs); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* Attach any options */ 1550Sstevel@tonic-gate if (pi->pi_hdw_addr_len != 0) { 1560Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr; 1570Sstevel@tonic-gate int optlen; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate /* roundup to multiple of 8 and make padding zero */ 1600Sstevel@tonic-gate optlen = ((sizeof (struct nd_opt_hdr) + 1610Sstevel@tonic-gate pi->pi_hdw_addr_len + 7) / 8) * 8; 1620Sstevel@tonic-gate bzero(pptr, optlen); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR; 1650Sstevel@tonic-gate lo->nd_opt_lla_len = optlen / 8; 1660Sstevel@tonic-gate bcopy((char *)pi->pi_hdw_addr, 1670Sstevel@tonic-gate (char *)lo->nd_opt_lla_hdw_addr, 1680Sstevel@tonic-gate pi->pi_hdw_addr_len); 1690Sstevel@tonic-gate packetlen += optlen; 1700Sstevel@tonic-gate pptr += optlen; 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (debug & D_PKTOUT) { 1740Sstevel@tonic-gate print_route_sol("Sending solicitation to ", pi, rs, packetlen, 1750Sstevel@tonic-gate sin6); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* 1810Sstevel@tonic-gate * Send a (set of) Router Advertisements and feed them back to ourselves 1820Sstevel@tonic-gate * for processing. Unless no_prefixes is set all prefixes are included. 1830Sstevel@tonic-gate * If there are too many prefix options to fit in one packet multiple 1840Sstevel@tonic-gate * packets will be sent - each containing a subset of the prefix options. 1850Sstevel@tonic-gate */ 1860Sstevel@tonic-gate static void 1870Sstevel@tonic-gate advertise(struct sockaddr_in6 *sin6, struct phyint *pi, boolean_t no_prefixes) 1880Sstevel@tonic-gate { 1890Sstevel@tonic-gate struct nd_opt_prefix_info *po; 1900Sstevel@tonic-gate char *pptr = (char *)packet; 1910Sstevel@tonic-gate struct nd_router_advert *ra; 1920Sstevel@tonic-gate struct adv_prefix *adv_pr; 1930Sstevel@tonic-gate int packetlen = 0; 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate ra = (struct nd_router_advert *)pptr; 1960Sstevel@tonic-gate ra->nd_ra_type = ND_ROUTER_ADVERT; 1970Sstevel@tonic-gate ra->nd_ra_code = 0; 1980Sstevel@tonic-gate ra->nd_ra_cksum = htons(0); 1990Sstevel@tonic-gate ra->nd_ra_curhoplimit = pi->pi_AdvCurHopLimit; 2000Sstevel@tonic-gate ra->nd_ra_flags_reserved = 0; 2010Sstevel@tonic-gate if (pi->pi_AdvManagedFlag) 2020Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; 2030Sstevel@tonic-gate if (pi->pi_AdvOtherConfigFlag) 2040Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 2070Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(0); 2080Sstevel@tonic-gate else 2090Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(pi->pi_AdvDefaultLifetime); 2100Sstevel@tonic-gate ra->nd_ra_reachable = htonl(pi->pi_AdvReachableTime); 2110Sstevel@tonic-gate ra->nd_ra_retransmit = htonl(pi->pi_AdvRetransTimer); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate packetlen = sizeof (*ra); 2140Sstevel@tonic-gate pptr += sizeof (*ra); 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 2170Sstevel@tonic-gate if (debug & D_PKTOUT) { 2180Sstevel@tonic-gate print_route_adv("Sending advert (FINAL) to ", pi, 2190Sstevel@tonic-gate ra, packetlen, sin6); 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2220Sstevel@tonic-gate /* Feed packet back in for router operation */ 2230Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2240Sstevel@tonic-gate return; 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* Attach any options */ 2280Sstevel@tonic-gate if (pi->pi_hdw_addr_len != 0) { 2290Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr; 2300Sstevel@tonic-gate int optlen; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* roundup to multiple of 8 and make padding zero */ 2330Sstevel@tonic-gate optlen = ((sizeof (struct nd_opt_hdr) + 2340Sstevel@tonic-gate pi->pi_hdw_addr_len + 7) / 8) * 8; 2350Sstevel@tonic-gate bzero(pptr, optlen); 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR; 2380Sstevel@tonic-gate lo->nd_opt_lla_len = optlen / 8; 2390Sstevel@tonic-gate bcopy((char *)pi->pi_hdw_addr, 2400Sstevel@tonic-gate (char *)lo->nd_opt_lla_hdw_addr, 2410Sstevel@tonic-gate pi->pi_hdw_addr_len); 2420Sstevel@tonic-gate packetlen += optlen; 2430Sstevel@tonic-gate pptr += optlen; 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0) { 2470Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)pptr; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate mo->nd_opt_mtu_type = ND_OPT_MTU; 2500Sstevel@tonic-gate mo->nd_opt_mtu_len = sizeof (struct nd_opt_mtu) / 8; 2510Sstevel@tonic-gate mo->nd_opt_mtu_reserved = 0; 2520Sstevel@tonic-gate mo->nd_opt_mtu_mtu = htonl(pi->pi_AdvLinkMTU); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate packetlen += sizeof (struct nd_opt_mtu); 2550Sstevel@tonic-gate pptr += sizeof (struct nd_opt_mtu); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate if (no_prefixes) { 2590Sstevel@tonic-gate if (debug & D_PKTOUT) { 2600Sstevel@tonic-gate print_route_adv("Sending advert to ", pi, 2610Sstevel@tonic-gate ra, packetlen, sin6); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2640Sstevel@tonic-gate /* Feed packet back in for router operation */ 2650Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2660Sstevel@tonic-gate return; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr; 2700Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 2710Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 2720Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvOnLinkFlag && 2730Sstevel@tonic-gate !adv_pr->adv_pr_AdvAutonomousFlag) { 2740Sstevel@tonic-gate continue; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * If the prefix doesn't fit in packet send 2790Sstevel@tonic-gate * what we have so far and start with new packet. 2800Sstevel@tonic-gate */ 2810Sstevel@tonic-gate if (packetlen + sizeof (*po) > 2820Sstevel@tonic-gate pi->pi_LinkMTU - sizeof (struct ip6_hdr)) { 2830Sstevel@tonic-gate if (debug & D_PKTOUT) { 2840Sstevel@tonic-gate print_route_adv("Sending advert " 2850Sstevel@tonic-gate "(FRAG) to ", 2860Sstevel@tonic-gate pi, ra, packetlen, sin6); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2890Sstevel@tonic-gate /* Feed packet back in for router operation */ 2900Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2910Sstevel@tonic-gate packetlen = sizeof (*ra); 2920Sstevel@tonic-gate pptr = (char *)packet + sizeof (*ra); 2930Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate po->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 2960Sstevel@tonic-gate po->nd_opt_pi_len = sizeof (*po)/8; 2970Sstevel@tonic-gate po->nd_opt_pi_flags_reserved = 0; 2980Sstevel@tonic-gate if (adv_pr->adv_pr_AdvOnLinkFlag) { 2990Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |= 3000Sstevel@tonic-gate ND_OPT_PI_FLAG_ONLINK; 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate if (adv_pr->adv_pr_AdvAutonomousFlag) { 3030Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |= 3040Sstevel@tonic-gate ND_OPT_PI_FLAG_AUTO; 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate po->nd_opt_pi_prefix_len = adv_pr->adv_pr_prefix_len; 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * If both Adv*Expiration and Adv*Lifetime are 3090Sstevel@tonic-gate * set we prefer the former and make the lifetime 3100Sstevel@tonic-gate * decrement in real time. 3110Sstevel@tonic-gate */ 3120Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 3130Sstevel@tonic-gate po->nd_opt_pi_valid_time = 3140Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidExpiration); 3150Sstevel@tonic-gate } else { 3160Sstevel@tonic-gate po->nd_opt_pi_valid_time = 3170Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidLifetime); 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 3200Sstevel@tonic-gate po->nd_opt_pi_preferred_time = 3210Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredExpiration); 3220Sstevel@tonic-gate } else { 3230Sstevel@tonic-gate po->nd_opt_pi_preferred_time = 3240Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredLifetime); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate po->nd_opt_pi_reserved2 = htonl(0); 3270Sstevel@tonic-gate po->nd_opt_pi_prefix = adv_pr->adv_pr_prefix; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate po++; 3300Sstevel@tonic-gate packetlen += sizeof (*po); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate if (debug & D_PKTOUT) { 3330Sstevel@tonic-gate print_route_adv("Sending advert to ", pi, 3340Sstevel@tonic-gate ra, packetlen, sin6); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 3370Sstevel@tonic-gate /* Feed packet back in for router operation */ 3380Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* Poll support */ 3420Sstevel@tonic-gate static int pollfd_num = 0; /* Allocated and initialized */ 3430Sstevel@tonic-gate static struct pollfd *pollfds = NULL; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * Add fd to the set being polled. Returns 0 if ok; -1 if failed. 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate int 3490Sstevel@tonic-gate poll_add(int fd) 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate int i; 3520Sstevel@tonic-gate int new_num; 3530Sstevel@tonic-gate struct pollfd *newfds; 3543284Sapersson 3550Sstevel@tonic-gate /* Check if already present */ 3560Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3570Sstevel@tonic-gate if (pollfds[i].fd == fd) 3580Sstevel@tonic-gate return (0); 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate /* Check for empty spot already present */ 3610Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3620Sstevel@tonic-gate if (pollfds[i].fd == -1) { 3630Sstevel@tonic-gate pollfds[i].fd = fd; 3640Sstevel@tonic-gate return (0); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* Allocate space for 32 more fds and initialize to -1 */ 3690Sstevel@tonic-gate new_num = pollfd_num + 32; 3700Sstevel@tonic-gate newfds = realloc(pollfds, new_num * sizeof (struct pollfd)); 3710Sstevel@tonic-gate if (newfds == NULL) { 3720Sstevel@tonic-gate logperror("poll_add: realloc"); 3730Sstevel@tonic-gate return (-1); 3740Sstevel@tonic-gate } 3753284Sapersson 3763284Sapersson newfds[pollfd_num].fd = fd; 3773284Sapersson newfds[pollfd_num++].events = POLLIN; 3783284Sapersson 3790Sstevel@tonic-gate for (i = pollfd_num; i < new_num; i++) { 3800Sstevel@tonic-gate newfds[i].fd = -1; 3810Sstevel@tonic-gate newfds[i].events = POLLIN; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate pollfd_num = new_num; 3840Sstevel@tonic-gate pollfds = newfds; 3853284Sapersson return (0); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * Remove fd from the set being polled. Returns 0 if ok; -1 if failed. 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate int 3920Sstevel@tonic-gate poll_remove(int fd) 3930Sstevel@tonic-gate { 3940Sstevel@tonic-gate int i; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* Check if already present */ 3970Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3980Sstevel@tonic-gate if (pollfds[i].fd == fd) { 3990Sstevel@tonic-gate pollfds[i].fd = -1; 4000Sstevel@tonic-gate return (0); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate return (-1); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate /* 4070Sstevel@tonic-gate * Extract information about the ifname (either a physical interface and 4080Sstevel@tonic-gate * the ":0" logical interface or just a logical interface). 4090Sstevel@tonic-gate * If the interface (still) exists in kernel set pr_in_use 4100Sstevel@tonic-gate * for caller to be able to detect interfaces that are removed. 4110Sstevel@tonic-gate * Starts sending advertisements/solicitations when new physical interfaces 4120Sstevel@tonic-gate * are detected. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate static void 4150Sstevel@tonic-gate if_process(int s, char *ifname, boolean_t first) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate struct lifreq lifr; 4180Sstevel@tonic-gate struct phyint *pi; 4190Sstevel@tonic-gate struct prefix *pr; 4200Sstevel@tonic-gate char *cp; 4210Sstevel@tonic-gate char phyintname[LIFNAMSIZ + 1]; 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate if (debug & D_IFSCAN) 4240Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process(%s)\n", ifname); 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 4270Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4280Sstevel@tonic-gate if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 4290Sstevel@tonic-gate if (errno == ENXIO) { 4300Sstevel@tonic-gate /* 4310Sstevel@tonic-gate * Interface has disappeared 4320Sstevel@tonic-gate */ 4330Sstevel@tonic-gate return; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate logperror("if_process: ioctl (get interface flags)"); 4360Sstevel@tonic-gate return; 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * Ignore loopback and point-to-multipoint interfaces. 4410Sstevel@tonic-gate * Point-to-point interfaces always have IFF_MULTICAST set. 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_MULTICAST) || 4440Sstevel@tonic-gate (lifr.lifr_flags & IFF_LOOPBACK)) { 4450Sstevel@tonic-gate return; 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_IPV6)) 4490Sstevel@tonic-gate return; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate (void) strncpy(phyintname, ifname, sizeof (phyintname)); 4520Sstevel@tonic-gate phyintname[sizeof (phyintname) - 1] = '\0'; 4530Sstevel@tonic-gate if ((cp = strchr(phyintname, IF_SEPARATOR)) != NULL) { 4540Sstevel@tonic-gate *cp = '\0'; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate pi = phyint_lookup(phyintname); 4580Sstevel@tonic-gate if (pi == NULL) { 4590Sstevel@tonic-gate /* 4600Sstevel@tonic-gate * Do not add anything for new interfaces until they are UP. 4610Sstevel@tonic-gate * For existing interfaces we track the up flag. 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_UP)) 4640Sstevel@tonic-gate return; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate pi = phyint_create(phyintname); 4670Sstevel@tonic-gate if (pi == NULL) { 4680Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n"); 4690Sstevel@tonic-gate return; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate (void) phyint_init_from_k(pi); 4730Sstevel@tonic-gate if (pi->pi_sock == -1 && !(pi->pi_kernel_state & PI_PRESENT)) { 4740Sstevel@tonic-gate /* Interface is not yet present */ 4750Sstevel@tonic-gate if (debug & D_PHYINT) { 4760Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process: interface not yet " 4770Sstevel@tonic-gate "present %s\n", pi->pi_name); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate return; 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if (pi->pi_sock != -1) { 4830Sstevel@tonic-gate if (poll_add(pi->pi_sock) == -1) { 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * reset state. 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate phyint_cleanup(pi); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * Check if IFF_ROUTER has been turned off in kernel in which 4930Sstevel@tonic-gate * case we have to turn off AdvSendAdvertisements. 4940Sstevel@tonic-gate * The kernel will automatically turn off IFF_ROUTER if 4950Sstevel@tonic-gate * ip6_forwarding is turned off. 4960Sstevel@tonic-gate * Note that we do not switch back should IFF_ROUTER be turned on. 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate if (!first && 4990Sstevel@tonic-gate pi->pi_AdvSendAdvertisements && !(pi->pi_flags & IFF_ROUTER)) { 5000Sstevel@tonic-gate logmsg(LOG_INFO, "No longer a router on %s\n", pi->pi_name); 5010Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate pi->pi_AdvSendAdvertisements = 0; 5040Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate /* 5080Sstevel@tonic-gate * Send advertisments and solicitation only if the interface is 5090Sstevel@tonic-gate * present in the kernel. 5100Sstevel@tonic-gate */ 5110Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 5140Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 5150Sstevel@tonic-gate check_to_advertise(pi, START_INIT_ADV); 5160Sstevel@tonic-gate } else { 5170Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 5180Sstevel@tonic-gate check_to_solicit(pi, START_INIT_SOLICIT); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * Track static kernel prefixes to prevent in.ndpd from clobbering 5240Sstevel@tonic-gate * them by creating a struct prefix for each prefix detected in the 5250Sstevel@tonic-gate * kernel. 5260Sstevel@tonic-gate */ 5270Sstevel@tonic-gate pr = prefix_lookup_name(pi, ifname); 5280Sstevel@tonic-gate if (pr == NULL) { 5290Sstevel@tonic-gate pr = prefix_create_name(pi, ifname); 5300Sstevel@tonic-gate if (pr == NULL) { 5310Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n"); 5320Sstevel@tonic-gate return; 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate if (prefix_init_from_k(pr) == -1) { 5350Sstevel@tonic-gate prefix_delete(pr); 5360Sstevel@tonic-gate return; 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate /* Detect prefixes which are removed */ 5400Sstevel@tonic-gate if (pr->pr_kernel_state != 0) 5410Sstevel@tonic-gate pr->pr_in_use = _B_TRUE; 5422546Scarlsonj 5432546Scarlsonj if ((lifr.lifr_flags & IFF_DUPLICATE) && 544*3431Scarlsonj !(lifr.lifr_flags & IFF_DHCPRUNNING) && 5452546Scarlsonj (pr->pr_flags & IFF_TEMPORARY)) { 5462546Scarlsonj in6_addr_t *token; 5472546Scarlsonj int i; 5482546Scarlsonj char abuf[INET6_ADDRSTRLEN]; 5492546Scarlsonj 5502546Scarlsonj if (++pr->pr_attempts >= MAX_DAD_FAILURES) { 5512546Scarlsonj logmsg(LOG_ERR, "%s: token %s is duplicate after %d " 5522546Scarlsonj "attempts; disabling temporary addresses on %s", 5532546Scarlsonj pr->pr_name, inet_ntop(AF_INET6, 5542546Scarlsonj (void *)&pi->pi_tmp_token, abuf, sizeof (abuf)), 5552546Scarlsonj pr->pr_attempts, pi->pi_name); 5562546Scarlsonj pi->pi_TmpAddrsEnabled = 0; 5572546Scarlsonj tmptoken_delete(pi); 5582546Scarlsonj prefix_delete(pr); 5592546Scarlsonj return; 5602546Scarlsonj } 5612546Scarlsonj logmsg(LOG_WARNING, "%s: token %s is duplicate; trying again", 5622546Scarlsonj pr->pr_name, inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token, 5632546Scarlsonj abuf, sizeof (abuf))); 5642546Scarlsonj if (!tmptoken_create(pi)) { 5652546Scarlsonj prefix_delete(pr); 5662546Scarlsonj return; 5672546Scarlsonj } 5682546Scarlsonj token = &pi->pi_tmp_token; 5692546Scarlsonj for (i = 0; i < 16; i++) { 5702546Scarlsonj /* 5712546Scarlsonj * prefix_create ensures that pr_prefix has all-zero 5722546Scarlsonj * bits after prefixlen. 5732546Scarlsonj */ 5742546Scarlsonj pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | 5752546Scarlsonj token->s6_addr[i]; 5762546Scarlsonj } 5772546Scarlsonj if (prefix_lookup_addr_match(pr) != NULL) { 5782546Scarlsonj prefix_delete(pr); 5792546Scarlsonj return; 5802546Scarlsonj } 5812546Scarlsonj pr->pr_CreateTime = getcurrenttime() / MILLISEC; 5822546Scarlsonj /* 5832546Scarlsonj * We've got a new token. Clearing PR_AUTO causes 5842546Scarlsonj * prefix_update_k to bring the interface up and set the 5852546Scarlsonj * address. 5862546Scarlsonj */ 5872546Scarlsonj pr->pr_kernel_state &= ~PR_AUTO; 5882546Scarlsonj prefix_update_k(pr); 5892546Scarlsonj } 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate static int ifsock = -1; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * Scan all interfaces to detect changes as well as new and deleted intefaces 5960Sstevel@tonic-gate * 'first' is set for the initial call only. Do not effect anything. 5970Sstevel@tonic-gate */ 5980Sstevel@tonic-gate static void 5990Sstevel@tonic-gate initifs(boolean_t first) 6000Sstevel@tonic-gate { 6010Sstevel@tonic-gate char *buf; 6020Sstevel@tonic-gate int bufsize; 6030Sstevel@tonic-gate int numifs; 6040Sstevel@tonic-gate int n; 6050Sstevel@tonic-gate struct lifnum lifn; 6060Sstevel@tonic-gate struct lifconf lifc; 6070Sstevel@tonic-gate struct lifreq *lifr; 6080Sstevel@tonic-gate struct phyint *pi; 6090Sstevel@tonic-gate struct phyint *next_pi; 6100Sstevel@tonic-gate struct prefix *pr; 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate if (debug & D_IFSCAN) 6130Sstevel@tonic-gate logmsg(LOG_DEBUG, "Reading interface configuration\n"); 6140Sstevel@tonic-gate if (ifsock < 0) { 6150Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 6160Sstevel@tonic-gate if (ifsock < 0) { 6170Sstevel@tonic-gate logperror("initifs: socket"); 6180Sstevel@tonic-gate return; 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate lifn.lifn_family = AF_INET6; 6220Sstevel@tonic-gate lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6230Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFNUM, (char *)&lifn) < 0) { 6240Sstevel@tonic-gate logperror("initifs: ioctl (get interface numbers)"); 6250Sstevel@tonic-gate return; 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate numifs = lifn.lifn_count; 6280Sstevel@tonic-gate bufsize = numifs * sizeof (struct lifreq); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate buf = (char *)malloc(bufsize); 6310Sstevel@tonic-gate if (buf == NULL) { 6320Sstevel@tonic-gate logmsg(LOG_ERR, "initifs: out of memory\n"); 6330Sstevel@tonic-gate return; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate /* 6370Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 6380Sstevel@tonic-gate * which have disappeared from the kernel. 6390Sstevel@tonic-gate * if_process will set pr_in_use when it finds the interface 6400Sstevel@tonic-gate * in the kernel. 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 6430Sstevel@tonic-gate /* 6440Sstevel@tonic-gate * Before re-examining the state of the interfaces, 6450Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 6460Sstevel@tonic-gate */ 6470Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 6480Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 6490Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate lifc.lifc_family = AF_INET6; 6540Sstevel@tonic-gate lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6550Sstevel@tonic-gate lifc.lifc_len = bufsize; 6560Sstevel@tonic-gate lifc.lifc_buf = buf; 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFCONF, (char *)&lifc) < 0) { 6590Sstevel@tonic-gate logperror("initifs: ioctl (get interface configuration)"); 6600Sstevel@tonic-gate free(buf); 6610Sstevel@tonic-gate return; 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate lifr = (struct lifreq *)lifc.lifc_req; 6650Sstevel@tonic-gate for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifr++) 6660Sstevel@tonic-gate if_process(ifsock, lifr->lifr_name, first); 6670Sstevel@tonic-gate free(buf); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * Detect phyints that have been removed from the kernel. 6710Sstevel@tonic-gate * Since we can't recreate it here (would require ifconfig plumb 6720Sstevel@tonic-gate * logic) we just terminate use of that phyint. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 6750Sstevel@tonic-gate next_pi = pi->pi_next; 6760Sstevel@tonic-gate /* 6770Sstevel@tonic-gate * If interface (still) exists in kernel, set 6780Sstevel@tonic-gate * pi_state to indicate that. 6790Sstevel@tonic-gate */ 6800Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 6810Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate check_if_removed(pi); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate if (show_ifs) 6870Sstevel@tonic-gate phyint_print_all(); 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * Router advertisement state machine. Used for everything but timer 6930Sstevel@tonic-gate * events which use advertise_event directly. 6940Sstevel@tonic-gate */ 6950Sstevel@tonic-gate void 6960Sstevel@tonic-gate check_to_advertise(struct phyint *pi, enum adv_events event) 6970Sstevel@tonic-gate { 6980Sstevel@tonic-gate uint_t delay; 6990Sstevel@tonic-gate enum adv_states old_state = pi->pi_adv_state; 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate if (debug & D_STATE) { 7020Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d\n", 7030Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate delay = advertise_event(pi, event, 0); 7060Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 7070Sstevel@tonic-gate /* Make sure the global next event is updated */ 7080Sstevel@tonic-gate timer_schedule(delay); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (debug & D_STATE) { 7120Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d -> %d\n", 7130Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 7140Sstevel@tonic-gate (int)pi->pi_adv_state); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate /* 7190Sstevel@tonic-gate * Router advertisement state machine. 7200Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 7210Sstevel@tonic-gate * if never). 7220Sstevel@tonic-gate * For the ADV_TIMER event the caller passes in the number of milliseconds 7230Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate uint_t 7260Sstevel@tonic-gate advertise_event(struct phyint *pi, enum adv_events event, uint_t elapsed) 7270Sstevel@tonic-gate { 7280Sstevel@tonic-gate uint_t delay; 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate if (debug & D_STATE) { 7310Sstevel@tonic-gate logmsg(LOG_DEBUG, "advertise_event(%s, %d, %d) state %d\n", 7320Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_adv_state); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate check_daemonize(); 7350Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 7360Sstevel@tonic-gate return (TIMER_INFINITY); 7370Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 7380Sstevel@tonic-gate if (debug & D_PKTOUT) { 7390Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RA packet on %s " 7400Sstevel@tonic-gate "(no route exchange on interface)\n", 7410Sstevel@tonic-gate pi->pi_name); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate return (TIMER_INFINITY); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate switch (event) { 7470Sstevel@tonic-gate case ADV_OFF: 7480Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 7490Sstevel@tonic-gate return (TIMER_INFINITY); 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate case START_INIT_ADV: 7520Sstevel@tonic-gate if (pi->pi_adv_state == INIT_ADV) 7530Sstevel@tonic-gate return (pi->pi_adv_time_left); 7540Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_INITIAL_RTR_ADVERTISEMENTS; 7550Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7560Sstevel@tonic-gate pi->pi_adv_state = INIT_ADV; 7570Sstevel@tonic-gate break; /* send advertisement */ 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate case START_FINAL_ADV: 7600Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7610Sstevel@tonic-gate return (TIMER_INFINITY); 7620Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 7630Sstevel@tonic-gate return (pi->pi_adv_time_left); 7640Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_FINAL_RTR_ADVERTISEMENTS; 7650Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7660Sstevel@tonic-gate pi->pi_adv_state = FINAL_ADV; 7670Sstevel@tonic-gate break; /* send advertisement */ 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate case RECEIVED_SOLICIT: 7700Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7710Sstevel@tonic-gate return (TIMER_INFINITY); 7720Sstevel@tonic-gate if (pi->pi_adv_state == SOLICIT_ADV) { 7730Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 7740Sstevel@tonic-gate return (pi->pi_adv_time_left); 7750Sstevel@tonic-gate break; 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate delay = GET_RANDOM(0, ND_MAX_RA_DELAY_TIME); 7780Sstevel@tonic-gate if (delay < pi->pi_adv_time_left) 7790Sstevel@tonic-gate pi->pi_adv_time_left = delay; 7800Sstevel@tonic-gate if (pi->pi_adv_time_since_sent < ND_MIN_DELAY_BETWEEN_RAS) { 7810Sstevel@tonic-gate /* 7820Sstevel@tonic-gate * Send an advertisement (ND_MIN_DELAY_BETWEEN_RAS 7830Sstevel@tonic-gate * plus random delay) after the previous 7840Sstevel@tonic-gate * advertisement was sent. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate pi->pi_adv_time_left = delay + 7870Sstevel@tonic-gate ND_MIN_DELAY_BETWEEN_RAS - 7880Sstevel@tonic-gate pi->pi_adv_time_since_sent; 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate pi->pi_adv_state = SOLICIT_ADV; 7910Sstevel@tonic-gate break; 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate case ADV_TIMER: 7940Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7950Sstevel@tonic-gate return (TIMER_INFINITY); 7960Sstevel@tonic-gate /* Decrease time left */ 7970Sstevel@tonic-gate if (pi->pi_adv_time_left >= elapsed) 7980Sstevel@tonic-gate pi->pi_adv_time_left -= elapsed; 7990Sstevel@tonic-gate else 8000Sstevel@tonic-gate pi->pi_adv_time_left = 0; 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* Increase time since last advertisement was sent */ 8030Sstevel@tonic-gate pi->pi_adv_time_since_sent += elapsed; 8040Sstevel@tonic-gate break; 8050Sstevel@tonic-gate default: 8060Sstevel@tonic-gate logmsg(LOG_ERR, "advertise_event: Unknown event %d\n", 8070Sstevel@tonic-gate (int)event); 8080Sstevel@tonic-gate return (TIMER_INFINITY); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 8120Sstevel@tonic-gate return (pi->pi_adv_time_left); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* Send advertisement and calculate next time to send */ 8150Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 8160Sstevel@tonic-gate /* Omit the prefixes */ 8170Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_TRUE); 8180Sstevel@tonic-gate } else { 8190Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_FALSE); 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate pi->pi_adv_time_since_sent = 0; 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate switch (pi->pi_adv_state) { 8240Sstevel@tonic-gate case SOLICIT_ADV: 8250Sstevel@tonic-gate /* 8260Sstevel@tonic-gate * The solicited advertisement has been sent. 8270Sstevel@tonic-gate * Revert to periodic advertisements. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 8300Sstevel@tonic-gate /* FALLTHRU */ 8310Sstevel@tonic-gate case REG_ADV: 8320Sstevel@tonic-gate pi->pi_adv_time_left = 8330Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8340Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8350Sstevel@tonic-gate break; 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate case INIT_ADV: 8380Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8390Sstevel@tonic-gate delay = GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8400Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8410Sstevel@tonic-gate if (delay > ND_MAX_INITIAL_RTR_ADVERT_INTERVAL) 8420Sstevel@tonic-gate delay = ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8430Sstevel@tonic-gate pi->pi_adv_time_left = delay; 8440Sstevel@tonic-gate } else { 8450Sstevel@tonic-gate pi->pi_adv_time_left = 8460Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 8470Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 8480Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate break; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate case FINAL_ADV: 8530Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8540Sstevel@tonic-gate pi->pi_adv_time_left = 8550Sstevel@tonic-gate ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8560Sstevel@tonic-gate } else { 8570Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate break; 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) 8620Sstevel@tonic-gate return (pi->pi_adv_time_left); 8630Sstevel@tonic-gate else 8640Sstevel@tonic-gate return (TIMER_INFINITY); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * Router solicitation state machine. Used for everything but timer 8690Sstevel@tonic-gate * events which use solicit_event directly. 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate void 8720Sstevel@tonic-gate check_to_solicit(struct phyint *pi, enum solicit_events event) 8730Sstevel@tonic-gate { 8740Sstevel@tonic-gate uint_t delay; 8750Sstevel@tonic-gate enum solicit_states old_state = pi->pi_sol_state; 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate if (debug & D_STATE) { 8780Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d\n", 8790Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate delay = solicit_event(pi, event, 0); 8820Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 8830Sstevel@tonic-gate /* Make sure the global next event is updated */ 8840Sstevel@tonic-gate timer_schedule(delay); 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate if (debug & D_STATE) { 8880Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d -> %d\n", 8890Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 8900Sstevel@tonic-gate (int)pi->pi_sol_state); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate static void 8950Sstevel@tonic-gate daemonize_ndpd(void) 8960Sstevel@tonic-gate { 8970Sstevel@tonic-gate FILE *pidfp; 8980Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 8990Sstevel@tonic-gate struct itimerval it; 9000Sstevel@tonic-gate boolean_t timerval = _B_TRUE; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate /* 9030Sstevel@tonic-gate * Need to get current timer settings so they can be restored 9040Sstevel@tonic-gate * after the fork(), as the it_value and it_interval values for 9050Sstevel@tonic-gate * the ITIMER_REAL timer are reset to 0 in the child process. 9060Sstevel@tonic-gate */ 9070Sstevel@tonic-gate if (getitimer(ITIMER_REAL, &it) < 0) { 9080Sstevel@tonic-gate if (debug & D_TIMER) 9090Sstevel@tonic-gate logmsg(LOG_DEBUG, 9100Sstevel@tonic-gate "daemonize_ndpd: failed to get itimerval\n"); 9110Sstevel@tonic-gate timerval = _B_FALSE; 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate /* Daemonize. */ 9150Sstevel@tonic-gate switch (fork()) { 9160Sstevel@tonic-gate case 0: 9170Sstevel@tonic-gate /* Child */ 9180Sstevel@tonic-gate break; 9190Sstevel@tonic-gate case -1: 9200Sstevel@tonic-gate logperror("fork"); 9210Sstevel@tonic-gate exit(1); 9220Sstevel@tonic-gate default: 9230Sstevel@tonic-gate /* Parent */ 9240Sstevel@tonic-gate _exit(0); 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 9280Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 9290Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n", 9300Sstevel@tonic-gate argv0[0], strerror(errno)); 9310Sstevel@tonic-gate } else { 9320Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 9330Sstevel@tonic-gate (void) fclose(pidfp); 9340Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate (void) close(0); 9380Sstevel@tonic-gate (void) close(1); 9390Sstevel@tonic-gate (void) close(2); 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate (void) chdir("/"); 9420Sstevel@tonic-gate (void) open("/dev/null", O_RDWR); 9430Sstevel@tonic-gate (void) dup2(0, 1); 9440Sstevel@tonic-gate (void) dup2(0, 2); 9450Sstevel@tonic-gate (void) setsid(); 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate already_daemonized = _B_TRUE; 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate /* 9500Sstevel@tonic-gate * Restore timer values, if we were able to save them; if not, 9510Sstevel@tonic-gate * check and set the right value by calling run_timeouts(). 9520Sstevel@tonic-gate */ 9530Sstevel@tonic-gate if (timerval) { 9540Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 9550Sstevel@tonic-gate logperror("daemonize_ndpd: setitimer"); 9560Sstevel@tonic-gate exit(2); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate } else { 9590Sstevel@tonic-gate run_timeouts(); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate /* 9640Sstevel@tonic-gate * Check to see if the time is right to daemonize. The right time is when: 9650Sstevel@tonic-gate * 9660Sstevel@tonic-gate * 1. We haven't already daemonized. 9670Sstevel@tonic-gate * 2. We are not in debug mode. 9680Sstevel@tonic-gate * 3. All interfaces are marked IFF_NOXMIT. 9690Sstevel@tonic-gate * 4. All non-router interfaces have their prefixes set up and we're 9700Sstevel@tonic-gate * done sending router solicitations on those interfaces without 9710Sstevel@tonic-gate * prefixes. 9720Sstevel@tonic-gate */ 9730Sstevel@tonic-gate static void 9740Sstevel@tonic-gate check_daemonize(void) 9750Sstevel@tonic-gate { 9760Sstevel@tonic-gate struct phyint *pi; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate if (already_daemonized || debug != 0) 9790Sstevel@tonic-gate return; 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 9820Sstevel@tonic-gate if (!(pi->pi_flags & IFF_NOXMIT)) 9830Sstevel@tonic-gate break; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate /* 9870Sstevel@tonic-gate * If we can't transmit on any of the interfaces there is no reason 9880Sstevel@tonic-gate * to hold up progress. 9890Sstevel@tonic-gate */ 9900Sstevel@tonic-gate if (pi == NULL) { 9910Sstevel@tonic-gate daemonize_ndpd(); 9920Sstevel@tonic-gate return; 9930Sstevel@tonic-gate } 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate /* Check all interfaces. If any are still soliciting, just return. */ 9960Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 9970Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements || 9980Sstevel@tonic-gate !(pi->pi_kernel_state & PI_PRESENT)) 9990Sstevel@tonic-gate continue; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 10020Sstevel@tonic-gate return; 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate daemonize_ndpd(); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate /* 10090Sstevel@tonic-gate * Router solicitation state machine. 10100Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 10110Sstevel@tonic-gate * if never). 10120Sstevel@tonic-gate * For the SOL_TIMER event the caller passes in the number of milliseconds 10130Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate uint_t 10160Sstevel@tonic-gate solicit_event(struct phyint *pi, enum solicit_events event, uint_t elapsed) 10170Sstevel@tonic-gate { 10180Sstevel@tonic-gate if (debug & D_STATE) { 10190Sstevel@tonic-gate logmsg(LOG_DEBUG, "solicit_event(%s, %d, %d) state %d\n", 10200Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_sol_state); 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 10240Sstevel@tonic-gate return (TIMER_INFINITY); 10250Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 10260Sstevel@tonic-gate if (debug & D_PKTOUT) { 10270Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RS packet on %s " 10280Sstevel@tonic-gate "(no route exchange on interface)\n", 10290Sstevel@tonic-gate pi->pi_name); 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate return (TIMER_INFINITY); 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate switch (event) { 10350Sstevel@tonic-gate case SOLICIT_OFF: 10360Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 10370Sstevel@tonic-gate check_daemonize(); 10380Sstevel@tonic-gate return (TIMER_INFINITY); 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate case SOLICIT_DONE: 10410Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 10420Sstevel@tonic-gate check_daemonize(); 10430Sstevel@tonic-gate return (TIMER_INFINITY); 10440Sstevel@tonic-gate 1045*3431Scarlsonj case RESTART_INIT_SOLICIT: 1046*3431Scarlsonj /* 1047*3431Scarlsonj * This event allows us to start solicitation over again 1048*3431Scarlsonj * without losing the RA flags. We start solicitation over 1049*3431Scarlsonj * when we are missing an interface prefix for a newly- 1050*3431Scarlsonj * encountered DHCP interface. 1051*3431Scarlsonj */ 1052*3431Scarlsonj if (pi->pi_sol_state == INIT_SOLICIT) 1053*3431Scarlsonj return (pi->pi_sol_time_left); 1054*3431Scarlsonj pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 1055*3431Scarlsonj pi->pi_sol_time_left = 1056*3431Scarlsonj GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 1057*3431Scarlsonj pi->pi_sol_state = INIT_SOLICIT; 1058*3431Scarlsonj break; 1059*3431Scarlsonj 10600Sstevel@tonic-gate case START_INIT_SOLICIT: 10610Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 10620Sstevel@tonic-gate return (pi->pi_sol_time_left); 1063*3431Scarlsonj pi->pi_ra_flags = 0; 10640Sstevel@tonic-gate pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 10650Sstevel@tonic-gate pi->pi_sol_time_left = 10660Sstevel@tonic-gate GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 10670Sstevel@tonic-gate pi->pi_sol_state = INIT_SOLICIT; 10680Sstevel@tonic-gate break; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate case SOL_TIMER: 10710Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 10720Sstevel@tonic-gate return (TIMER_INFINITY); 10730Sstevel@tonic-gate /* Decrease time left */ 10740Sstevel@tonic-gate if (pi->pi_sol_time_left >= elapsed) 10750Sstevel@tonic-gate pi->pi_sol_time_left -= elapsed; 10760Sstevel@tonic-gate else 10770Sstevel@tonic-gate pi->pi_sol_time_left = 0; 10780Sstevel@tonic-gate break; 10790Sstevel@tonic-gate default: 10800Sstevel@tonic-gate logmsg(LOG_ERR, "solicit_event: Unknown event %d\n", 10810Sstevel@tonic-gate (int)event); 10820Sstevel@tonic-gate return (TIMER_INFINITY); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate if (pi->pi_sol_time_left != 0) 10860Sstevel@tonic-gate return (pi->pi_sol_time_left); 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate /* Send solicitation and calculate next time */ 10890Sstevel@tonic-gate switch (pi->pi_sol_state) { 10900Sstevel@tonic-gate case INIT_SOLICIT: 10910Sstevel@tonic-gate solicit(&v6allrouters, pi); 10920Sstevel@tonic-gate if (--pi->pi_sol_count == 0) { 1093*3431Scarlsonj logmsg(LOG_DEBUG, "solicit_event: giving up on %s\n", 1094*3431Scarlsonj pi->pi_name); 1095*3431Scarlsonj if (pi->pi_StatefulAddrConf) { 1096*3431Scarlsonj pi->pi_ra_flags |= ND_RA_FLAG_MANAGED | 1097*3431Scarlsonj ND_RA_FLAG_OTHER; 1098*3431Scarlsonj start_dhcp(pi); 1099*3431Scarlsonj } 11000Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 11010Sstevel@tonic-gate check_daemonize(); 11020Sstevel@tonic-gate return (TIMER_INFINITY); 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate pi->pi_sol_time_left = ND_RTR_SOLICITATION_INTERVAL; 11050Sstevel@tonic-gate return (pi->pi_sol_time_left); 11060Sstevel@tonic-gate case NO_SOLICIT: 11070Sstevel@tonic-gate case DONE_SOLICIT: 11080Sstevel@tonic-gate return (TIMER_INFINITY); 11090Sstevel@tonic-gate default: 11100Sstevel@tonic-gate return (pi->pi_sol_time_left); 11110Sstevel@tonic-gate } 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * Timer mechanism using relative time (in milliseconds) from the 11160Sstevel@tonic-gate * previous timer event. Timers exceeding TIMER_INFINITY milliseconds 11170Sstevel@tonic-gate * will fire after TIMER_INFINITY milliseconds. 11180Sstevel@tonic-gate */ 11190Sstevel@tonic-gate static uint_t timer_previous; /* When last SIGALRM occurred */ 11200Sstevel@tonic-gate static uint_t timer_next; /* Currently scheduled timeout */ 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate static void 11230Sstevel@tonic-gate timer_init(void) 11240Sstevel@tonic-gate { 11250Sstevel@tonic-gate timer_previous = getcurrenttime(); 11260Sstevel@tonic-gate timer_next = TIMER_INFINITY; 11270Sstevel@tonic-gate run_timeouts(); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate /* 11310Sstevel@tonic-gate * Make sure the next SIGALRM occurs delay milliseconds from the current 11320Sstevel@tonic-gate * time if not earlier. 11330Sstevel@tonic-gate * Handles getcurrenttime (32 bit integer holding milliseconds) wraparound 11340Sstevel@tonic-gate * by treating differences greater than 0x80000000 as negative. 11350Sstevel@tonic-gate */ 11360Sstevel@tonic-gate void 11370Sstevel@tonic-gate timer_schedule(uint_t delay) 11380Sstevel@tonic-gate { 11390Sstevel@tonic-gate uint_t now; 11400Sstevel@tonic-gate struct itimerval itimerval; 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate now = getcurrenttime(); 11430Sstevel@tonic-gate if (debug & D_TIMER) { 11440Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): now %u next %u\n", 11450Sstevel@tonic-gate delay, now, timer_next); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate /* Will this timer occur before the currently scheduled SIGALRM? */ 11480Sstevel@tonic-gate if (delay >= timer_next - now) { 11490Sstevel@tonic-gate if (debug & D_TIMER) { 11500Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): no action - " 11510Sstevel@tonic-gate "next in %u ms\n", 11520Sstevel@tonic-gate delay, timer_next - now); 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate return; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate if (delay == 0) { 11570Sstevel@tonic-gate /* Minimum allowed delay */ 11580Sstevel@tonic-gate delay = 1; 11590Sstevel@tonic-gate } 11600Sstevel@tonic-gate timer_next = now + delay; 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate itimerval.it_value.tv_sec = delay / 1000; 11630Sstevel@tonic-gate itimerval.it_value.tv_usec = (delay % 1000) * 1000; 11640Sstevel@tonic-gate itimerval.it_interval.tv_sec = 0; 11650Sstevel@tonic-gate itimerval.it_interval.tv_usec = 0; 11660Sstevel@tonic-gate if (debug & D_TIMER) { 11670Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): sec %lu usec %lu\n", 11680Sstevel@tonic-gate delay, 11690Sstevel@tonic-gate itimerval.it_value.tv_sec, itimerval.it_value.tv_usec); 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) { 11720Sstevel@tonic-gate logperror("timer_schedule: setitimer"); 11730Sstevel@tonic-gate exit(2); 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate /* 11780Sstevel@tonic-gate * Conditional running of timer. If more than 'minimal_time' millseconds 11790Sstevel@tonic-gate * since the timer routines were last run we run them. 11800Sstevel@tonic-gate * Used when packets arrive. 11810Sstevel@tonic-gate */ 11820Sstevel@tonic-gate static void 11830Sstevel@tonic-gate conditional_run_timeouts(uint_t minimal_time) 11840Sstevel@tonic-gate { 11850Sstevel@tonic-gate uint_t now; 11860Sstevel@tonic-gate uint_t elapsed; 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate now = getcurrenttime(); 11890Sstevel@tonic-gate elapsed = now - timer_previous; 11900Sstevel@tonic-gate if (elapsed > minimal_time) { 11910Sstevel@tonic-gate if (debug & D_TIMER) { 11920Sstevel@tonic-gate logmsg(LOG_DEBUG, "conditional_run_timeouts: " 11930Sstevel@tonic-gate "elapsed %d\n", elapsed); 11940Sstevel@tonic-gate } 11950Sstevel@tonic-gate run_timeouts(); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate } 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate /* 12000Sstevel@tonic-gate * Timer has fired. 12010Sstevel@tonic-gate * Determine when the next timer event will occur by asking all 12020Sstevel@tonic-gate * the timer routines. 12030Sstevel@tonic-gate * Should not be called from a timer routine but in some cases this is 12040Sstevel@tonic-gate * done because the code doesn't know that e.g. it was called from 12050Sstevel@tonic-gate * ifconfig_timer(). In this case the nested run_timeouts will just return but 12060Sstevel@tonic-gate * the running run_timeouts will ensure to call all the timer functions by 12070Sstevel@tonic-gate * looping once more. 12080Sstevel@tonic-gate */ 12090Sstevel@tonic-gate static void 12100Sstevel@tonic-gate run_timeouts(void) 12110Sstevel@tonic-gate { 12120Sstevel@tonic-gate uint_t now; 12130Sstevel@tonic-gate uint_t elapsed; 12140Sstevel@tonic-gate uint_t next; 12150Sstevel@tonic-gate uint_t nexti; 12160Sstevel@tonic-gate struct phyint *pi; 12170Sstevel@tonic-gate struct phyint *next_pi; 12180Sstevel@tonic-gate struct prefix *pr; 12190Sstevel@tonic-gate struct prefix *next_pr; 12200Sstevel@tonic-gate struct adv_prefix *adv_pr; 12210Sstevel@tonic-gate struct adv_prefix *next_adv_pr; 12220Sstevel@tonic-gate struct router *dr; 12230Sstevel@tonic-gate struct router *next_dr; 12240Sstevel@tonic-gate static boolean_t timeout_running; 12250Sstevel@tonic-gate static boolean_t do_retry; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate if (timeout_running) { 12280Sstevel@tonic-gate if (debug & D_TIMER) 12290Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: nested call\n"); 12300Sstevel@tonic-gate do_retry = _B_TRUE; 12310Sstevel@tonic-gate return; 12320Sstevel@tonic-gate } 12330Sstevel@tonic-gate timeout_running = _B_TRUE; 12340Sstevel@tonic-gate retry: 12350Sstevel@tonic-gate /* How much time since the last time we were called? */ 12360Sstevel@tonic-gate now = getcurrenttime(); 12370Sstevel@tonic-gate elapsed = now - timer_previous; 12380Sstevel@tonic-gate timer_previous = now; 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (debug & D_TIMER) 12410Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: elapsed %d\n", elapsed); 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate next = TIMER_INFINITY; 12440Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 12450Sstevel@tonic-gate next_pi = pi->pi_next; 12460Sstevel@tonic-gate nexti = phyint_timer(pi, elapsed); 12470Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12480Sstevel@tonic-gate next = nexti; 12490Sstevel@tonic-gate if (debug & D_TIMER) { 12500Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pi %s): %d -> %u ms\n", 12510Sstevel@tonic-gate pi->pi_name, nexti, next); 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 12540Sstevel@tonic-gate next_pr = pr->pr_next; 12550Sstevel@tonic-gate nexti = prefix_timer(pr, elapsed); 12560Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12570Sstevel@tonic-gate next = nexti; 12580Sstevel@tonic-gate if (debug & D_TIMER) { 12590Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pr %s): " 12600Sstevel@tonic-gate "%d -> %u ms\n", pr->pr_name, nexti, next); 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate } 12630Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 12640Sstevel@tonic-gate adv_pr = next_adv_pr) { 12650Sstevel@tonic-gate next_adv_pr = adv_pr->adv_pr_next; 12660Sstevel@tonic-gate nexti = adv_prefix_timer(adv_pr, elapsed); 12670Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12680Sstevel@tonic-gate next = nexti; 12690Sstevel@tonic-gate if (debug & D_TIMER) { 12700Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts " 12710Sstevel@tonic-gate "(adv pr on %s): %d -> %u ms\n", 12720Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 12730Sstevel@tonic-gate nexti, next); 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) { 12770Sstevel@tonic-gate next_dr = dr->dr_next; 12780Sstevel@tonic-gate nexti = router_timer(dr, elapsed); 12790Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12800Sstevel@tonic-gate next = nexti; 12810Sstevel@tonic-gate if (debug & D_TIMER) { 12820Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (dr): " 12830Sstevel@tonic-gate "%d -> %u ms\n", nexti, next); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate } 12860Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 12870Sstevel@tonic-gate nexti = tmptoken_timer(pi, elapsed); 12880Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12890Sstevel@tonic-gate next = nexti; 12900Sstevel@tonic-gate if (debug & D_TIMER) { 12910Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (tmp on %s): " 12920Sstevel@tonic-gate "%d -> %u ms\n", pi->pi_name, nexti, next); 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate } 12960Sstevel@tonic-gate /* 12970Sstevel@tonic-gate * Make sure the timer functions are run at least once 12980Sstevel@tonic-gate * an hour. 12990Sstevel@tonic-gate */ 13000Sstevel@tonic-gate if (next == TIMER_INFINITY) 13010Sstevel@tonic-gate next = 3600 * 1000; /* 1 hour */ 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate if (debug & D_TIMER) 13040Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: %u ms\n", next); 13050Sstevel@tonic-gate timer_schedule(next); 13060Sstevel@tonic-gate if (do_retry) { 13070Sstevel@tonic-gate if (debug & D_TIMER) 13080Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: retry\n"); 13090Sstevel@tonic-gate do_retry = _B_FALSE; 13100Sstevel@tonic-gate goto retry; 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate timeout_running = _B_FALSE; 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate static int eventpipe_read = -1; /* Used for synchronous signal delivery */ 13160Sstevel@tonic-gate static int eventpipe_write = -1; 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate /* 13190Sstevel@tonic-gate * Ensure that signals are processed synchronously with the rest of 13200Sstevel@tonic-gate * the code by just writing a one character signal number on the pipe. 13210Sstevel@tonic-gate * The poll loop will pick this up and process the signal event. 13220Sstevel@tonic-gate */ 13230Sstevel@tonic-gate static void 13240Sstevel@tonic-gate sig_handler(int signo) 13250Sstevel@tonic-gate { 13260Sstevel@tonic-gate uchar_t buf = (uchar_t)signo; 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate if (eventpipe_write == -1) { 13290Sstevel@tonic-gate logmsg(LOG_ERR, "sig_handler: no pipe\n"); 13300Sstevel@tonic-gate return; 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate if (write(eventpipe_write, &buf, sizeof (buf)) < 0) 13330Sstevel@tonic-gate logperror("sig_handler: write"); 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate /* 13370Sstevel@tonic-gate * Pick up a signal "byte" from the pipe and process it. 13380Sstevel@tonic-gate */ 13390Sstevel@tonic-gate static void 13400Sstevel@tonic-gate in_signal(int fd) 13410Sstevel@tonic-gate { 13420Sstevel@tonic-gate uchar_t buf; 13430Sstevel@tonic-gate struct phyint *pi; 13440Sstevel@tonic-gate struct phyint *next_pi; 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate switch (read(fd, &buf, sizeof (buf))) { 13470Sstevel@tonic-gate case -1: 13480Sstevel@tonic-gate logperror("in_signal: read"); 13490Sstevel@tonic-gate exit(1); 13500Sstevel@tonic-gate /* NOTREACHED */ 13510Sstevel@tonic-gate case 1: 13520Sstevel@tonic-gate break; 13530Sstevel@tonic-gate case 0: 13540Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read eof\n"); 13550Sstevel@tonic-gate exit(1); 13560Sstevel@tonic-gate /* NOTREACHED */ 13570Sstevel@tonic-gate default: 13580Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read > 1\n"); 13590Sstevel@tonic-gate exit(1); 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate if (debug & D_TIMER) 13630Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal() got %d\n", buf); 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate switch (buf) { 13660Sstevel@tonic-gate case SIGALRM: 13670Sstevel@tonic-gate if (debug & D_TIMER) { 13680Sstevel@tonic-gate uint_t now = getcurrenttime(); 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal(SIGALRM) delta %u\n", 13710Sstevel@tonic-gate now - timer_next); 13720Sstevel@tonic-gate } 13730Sstevel@tonic-gate timer_next = TIMER_INFINITY; 13740Sstevel@tonic-gate run_timeouts(); 13750Sstevel@tonic-gate break; 13760Sstevel@tonic-gate case SIGHUP: 13770Sstevel@tonic-gate /* Re-read config file by exec'ing ourselves */ 13780Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 13790Sstevel@tonic-gate next_pi = pi->pi_next; 13800Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 13810Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 13820Sstevel@tonic-gate 13830Sstevel@tonic-gate phyint_delete(pi); 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate /* 13870Sstevel@tonic-gate * Prevent fd leaks. Everything gets re-opened at start-up 13880Sstevel@tonic-gate * time. 0, 1, and 2 are closed and re-opened as 13890Sstevel@tonic-gate * /dev/null, so we'll leave those open. 13900Sstevel@tonic-gate */ 13910Sstevel@tonic-gate closefrom(3); 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate logmsg(LOG_ERR, "SIGHUP: restart and reread config file\n"); 13940Sstevel@tonic-gate (void) execv(argv0[0], argv0); 13950Sstevel@tonic-gate (void) unlink(PATH_PID); 13960Sstevel@tonic-gate _exit(0177); 13970Sstevel@tonic-gate /* NOTREACHED */ 13980Sstevel@tonic-gate case SIGUSR1: 13990Sstevel@tonic-gate logmsg(LOG_DEBUG, "Printing configuration:\n"); 14000Sstevel@tonic-gate phyint_print_all(); 14010Sstevel@tonic-gate break; 14020Sstevel@tonic-gate case SIGINT: 14030Sstevel@tonic-gate case SIGTERM: 14040Sstevel@tonic-gate case SIGQUIT: 14050Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 14060Sstevel@tonic-gate next_pi = pi->pi_next; 14070Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 14080Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate phyint_delete(pi); 14110Sstevel@tonic-gate } 14123284Sapersson (void) unlink(NDPD_SNMP_SOCKET); 14130Sstevel@tonic-gate (void) unlink(PATH_PID); 14140Sstevel@tonic-gate exit(0); 14150Sstevel@tonic-gate /* NOTREACHED */ 14160Sstevel@tonic-gate case 255: 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * Special "signal" from looback_ra_enqueue. 14190Sstevel@tonic-gate * Handle any queued loopback router advertisements. 14200Sstevel@tonic-gate */ 14210Sstevel@tonic-gate loopback_ra_dequeue(); 14220Sstevel@tonic-gate break; 14230Sstevel@tonic-gate default: 14240Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: unknown signal: %d\n", buf); 14250Sstevel@tonic-gate } 14260Sstevel@tonic-gate } 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate /* 14290Sstevel@tonic-gate * Create pipe for signal delivery and set up signal handlers. 14300Sstevel@tonic-gate */ 14310Sstevel@tonic-gate static void 14320Sstevel@tonic-gate setup_eventpipe(void) 14330Sstevel@tonic-gate { 14340Sstevel@tonic-gate int fds[2]; 14350Sstevel@tonic-gate struct sigaction act; 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate if ((pipe(fds)) < 0) { 14380Sstevel@tonic-gate logperror("setup_eventpipe: pipe"); 14390Sstevel@tonic-gate exit(1); 14400Sstevel@tonic-gate } 14410Sstevel@tonic-gate eventpipe_read = fds[0]; 14420Sstevel@tonic-gate eventpipe_write = fds[1]; 14430Sstevel@tonic-gate if (poll_add(eventpipe_read) == -1) { 14440Sstevel@tonic-gate exit(1); 14450Sstevel@tonic-gate } 14460Sstevel@tonic-gate act.sa_handler = sig_handler; 14470Sstevel@tonic-gate act.sa_flags = SA_RESTART; 14480Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate (void) sigset(SIGHUP, sig_handler); 14510Sstevel@tonic-gate (void) sigset(SIGUSR1, sig_handler); 14520Sstevel@tonic-gate (void) sigset(SIGTERM, sig_handler); 14530Sstevel@tonic-gate (void) sigset(SIGINT, sig_handler); 14540Sstevel@tonic-gate (void) sigset(SIGQUIT, sig_handler); 14550Sstevel@tonic-gate } 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate /* 14580Sstevel@tonic-gate * Create a routing socket for receiving RTM_IFINFO messages and initialize 14590Sstevel@tonic-gate * the routing socket message header and as much of the sockaddrs as possible. 14600Sstevel@tonic-gate */ 14610Sstevel@tonic-gate static int 14620Sstevel@tonic-gate setup_rtsock(void) 14630Sstevel@tonic-gate { 14640Sstevel@tonic-gate int s; 14650Sstevel@tonic-gate int ret; 14660Sstevel@tonic-gate char *cp; 14670Sstevel@tonic-gate struct sockaddr_in6 *sin6; 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, AF_INET6); 14700Sstevel@tonic-gate if (s == -1) { 14710Sstevel@tonic-gate logperror("socket(PF_ROUTE)"); 14720Sstevel@tonic-gate exit(1); 14730Sstevel@tonic-gate } 14740Sstevel@tonic-gate ret = fcntl(s, F_SETFL, O_NDELAY|O_NONBLOCK); 14750Sstevel@tonic-gate if (ret < 0) { 14760Sstevel@tonic-gate logperror("fcntl(O_NDELAY)"); 14770Sstevel@tonic-gate exit(1); 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate if (poll_add(s) == -1) { 14800Sstevel@tonic-gate exit(1); 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate /* 14840Sstevel@tonic-gate * Allocate storage for the routing socket message. 14850Sstevel@tonic-gate */ 14860Sstevel@tonic-gate rt_msg = (struct rt_msghdr *)malloc(NDP_RTM_MSGLEN); 14870Sstevel@tonic-gate if (rt_msg == NULL) { 14880Sstevel@tonic-gate logperror("malloc"); 14890Sstevel@tonic-gate exit(1); 14900Sstevel@tonic-gate } 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate /* 14930Sstevel@tonic-gate * Initialize the routing socket message by zero-filling it and then 14940Sstevel@tonic-gate * setting the fields where are constant through the lifetime of the 14950Sstevel@tonic-gate * process. 14960Sstevel@tonic-gate */ 14970Sstevel@tonic-gate bzero(rt_msg, NDP_RTM_MSGLEN); 14980Sstevel@tonic-gate rt_msg->rtm_msglen = NDP_RTM_MSGLEN; 14990Sstevel@tonic-gate rt_msg->rtm_version = RTM_VERSION; 15000Sstevel@tonic-gate rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP; 15010Sstevel@tonic-gate rt_msg->rtm_pid = getpid(); 15020Sstevel@tonic-gate if (rt_msg->rtm_pid < 0) { 15030Sstevel@tonic-gate logperror("getpid"); 15040Sstevel@tonic-gate exit(1); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate /* 15080Sstevel@tonic-gate * The RTA_DST sockaddr does not change during the lifetime of the 15090Sstevel@tonic-gate * process so it can be completely initialized at this time. 15100Sstevel@tonic-gate */ 15110Sstevel@tonic-gate cp = (char *)rt_msg + sizeof (struct rt_msghdr); 15120Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 15130Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15140Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate /* 15170Sstevel@tonic-gate * Initialize the constant portion of the RTA_GATEWAY sockaddr. 15180Sstevel@tonic-gate */ 15190Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15200Sstevel@tonic-gate rta_gateway = (struct sockaddr_in6 *)cp; 15210Sstevel@tonic-gate rta_gateway->sin6_family = AF_INET6; 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * The RTA_NETMASK sockaddr does not change during the lifetime of the 15250Sstevel@tonic-gate * process so it can be completely initialized at this time. 15260Sstevel@tonic-gate */ 15270Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15280Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 15290Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15300Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate /* 15330Sstevel@tonic-gate * Initialize the constant portion of the RTA_IFP sockaddr. 15340Sstevel@tonic-gate */ 15350Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 15360Sstevel@tonic-gate rta_ifp = (struct sockaddr_dl *)cp; 15370Sstevel@tonic-gate rta_ifp->sdl_family = AF_LINK; 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate return (s); 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate 15423284Sapersson static int 15433284Sapersson setup_mibsock(void) 15443284Sapersson { 15453284Sapersson int sock; 15463284Sapersson int ret; 15473284Sapersson int len; 15483284Sapersson struct sockaddr_un laddr; 15493284Sapersson 15503284Sapersson sock = socket(AF_UNIX, SOCK_DGRAM, 0); 15513284Sapersson if (sock == -1) { 15523284Sapersson logperror("setup_mibsock: socket(AF_UNIX)"); 15533284Sapersson exit(1); 15543284Sapersson } 15553284Sapersson 15563284Sapersson bzero(&laddr, sizeof (laddr)); 15573284Sapersson laddr.sun_family = AF_UNIX; 15583284Sapersson 15593284Sapersson (void) strncpy(laddr.sun_path, NDPD_SNMP_SOCKET, 15603284Sapersson sizeof (laddr.sun_path)); 15613284Sapersson len = sizeof (struct sockaddr_un); 15623284Sapersson 15633284Sapersson (void) unlink(NDPD_SNMP_SOCKET); 15643284Sapersson ret = bind(sock, (struct sockaddr *)&laddr, len); 15653284Sapersson if (ret < 0) { 15663284Sapersson logperror("setup_mibsock: bind\n"); 15673284Sapersson exit(1); 15683284Sapersson } 15693284Sapersson 15703284Sapersson ret = fcntl(sock, F_SETFL, O_NONBLOCK); 15713284Sapersson if (ret < 0) { 15723284Sapersson logperror("fcntl(O_NONBLOCK)"); 15733284Sapersson exit(1); 15743284Sapersson } 15753284Sapersson if (poll_add(sock) == -1) { 15763284Sapersson exit(1); 15773284Sapersson } 15783284Sapersson return (sock); 15793284Sapersson } 15803284Sapersson 15810Sstevel@tonic-gate /* 15820Sstevel@tonic-gate * Retrieve one routing socket message. If RTM_IFINFO indicates 15830Sstevel@tonic-gate * new phyint do a full scan of the interfaces. If RTM_IFINFO 15842546Scarlsonj * indicates an existing phyint, only scan that phyint and associated 15850Sstevel@tonic-gate * prefixes. 15860Sstevel@tonic-gate */ 15870Sstevel@tonic-gate static void 15880Sstevel@tonic-gate process_rtsock(int rtsock) 15890Sstevel@tonic-gate { 15900Sstevel@tonic-gate int n; 15910Sstevel@tonic-gate #define MSG_SIZE 2048/8 15920Sstevel@tonic-gate int64_t msg[MSG_SIZE]; 15930Sstevel@tonic-gate struct rt_msghdr *rtm; 15940Sstevel@tonic-gate struct if_msghdr *ifm; 15950Sstevel@tonic-gate struct phyint *pi; 15960Sstevel@tonic-gate struct prefix *pr; 15970Sstevel@tonic-gate boolean_t need_initifs = _B_FALSE; 15980Sstevel@tonic-gate boolean_t need_ifscan = _B_FALSE; 15990Sstevel@tonic-gate int64_t ifscan_msg[10][MSG_SIZE]; 16000Sstevel@tonic-gate int ifscan_index = 0; 16010Sstevel@tonic-gate int i; 16020Sstevel@tonic-gate 16030Sstevel@tonic-gate /* Empty the rtsock and coealesce all the work that we have */ 16040Sstevel@tonic-gate while (ifscan_index < 10) { 16050Sstevel@tonic-gate n = read(rtsock, msg, sizeof (msg)); 16060Sstevel@tonic-gate if (n <= 0) { 16070Sstevel@tonic-gate /* No more messages */ 16080Sstevel@tonic-gate break; 16090Sstevel@tonic-gate } 16100Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 16110Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 16120Sstevel@tonic-gate logmsg(LOG_ERR, 16130Sstevel@tonic-gate "process_rtsock: version %d not understood\n", 16140Sstevel@tonic-gate rtm->rtm_version); 16150Sstevel@tonic-gate return; 16160Sstevel@tonic-gate } 16170Sstevel@tonic-gate switch (rtm->rtm_type) { 16180Sstevel@tonic-gate case RTM_NEWADDR: 16190Sstevel@tonic-gate case RTM_DELADDR: 16200Sstevel@tonic-gate /* 16210Sstevel@tonic-gate * Some logical interface has changed - have to scan 16220Sstevel@tonic-gate * everything to determine what actually changed. 16230Sstevel@tonic-gate */ 16240Sstevel@tonic-gate if (debug & D_IFSCAN) { 16250Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: " 16260Sstevel@tonic-gate "message %d\n", rtm->rtm_type); 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate need_initifs = _B_TRUE; 16290Sstevel@tonic-gate break; 16300Sstevel@tonic-gate case RTM_IFINFO: 16310Sstevel@tonic-gate need_ifscan = _B_TRUE; 16320Sstevel@tonic-gate (void) memcpy(ifscan_msg[ifscan_index], rtm, 16330Sstevel@tonic-gate sizeof (msg)); 16340Sstevel@tonic-gate ifscan_index++; 16350Sstevel@tonic-gate /* Handled below */ 16360Sstevel@tonic-gate break; 16370Sstevel@tonic-gate default: 16380Sstevel@tonic-gate /* Not interesting */ 16390Sstevel@tonic-gate break; 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate } 16420Sstevel@tonic-gate /* 16430Sstevel@tonic-gate * If we do full scan i.e initifs, we don't need to 16440Sstevel@tonic-gate * scan a particular interface as we should have 16450Sstevel@tonic-gate * done that as part of initifs. 16460Sstevel@tonic-gate */ 16470Sstevel@tonic-gate if (need_initifs) { 16480Sstevel@tonic-gate initifs(_B_FALSE); 16490Sstevel@tonic-gate return; 16500Sstevel@tonic-gate } 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate if (!need_ifscan) 16530Sstevel@tonic-gate return; 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate for (i = 0; i < ifscan_index; i++) { 16560Sstevel@tonic-gate ifm = (struct if_msghdr *)ifscan_msg[i]; 16570Sstevel@tonic-gate if (debug & D_IFSCAN) 16580Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: index %d\n", 16590Sstevel@tonic-gate ifm->ifm_index); 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate pi = phyint_lookup_on_index(ifm->ifm_index); 16620Sstevel@tonic-gate if (pi == NULL) { 16630Sstevel@tonic-gate /* 16640Sstevel@tonic-gate * A new physical interface. Do a full scan of the 16650Sstevel@tonic-gate * to catch any new logical interfaces. 16660Sstevel@tonic-gate */ 16670Sstevel@tonic-gate initifs(_B_FALSE); 16680Sstevel@tonic-gate return; 16690Sstevel@tonic-gate } 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate if (ifm->ifm_flags != pi->pi_flags) { 16720Sstevel@tonic-gate if (debug & D_IFSCAN) { 16730Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: clr for " 16740Sstevel@tonic-gate "%s old flags 0x%x new flags 0x%x\n", 16750Sstevel@tonic-gate pi->pi_name, pi->pi_flags, ifm->ifm_flags); 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate /* 16810Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 16820Sstevel@tonic-gate * which have disappeared from the kernel. 16830Sstevel@tonic-gate * if_process will set pr_in_use when it finds the 16840Sstevel@tonic-gate * interface in the kernel. 16850Sstevel@tonic-gate * Before re-examining the state of the interfaces, 16860Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 16870Sstevel@tonic-gate */ 16880Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 16890Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 16900Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 16910Sstevel@tonic-gate } 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate if (ifsock < 0) { 16940Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 16950Sstevel@tonic-gate if (ifsock < 0) { 16960Sstevel@tonic-gate logperror("process_rtsock: socket"); 16970Sstevel@tonic-gate return; 16980Sstevel@tonic-gate } 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate if_process(ifsock, pi->pi_name, _B_FALSE); 17010Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 17020Sstevel@tonic-gate if_process(ifsock, pr->pr_name, _B_FALSE); 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate /* 17050Sstevel@tonic-gate * If interface (still) exists in kernel, set 17060Sstevel@tonic-gate * pi_state to indicate that. 17070Sstevel@tonic-gate */ 17080Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 17090Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 17100Sstevel@tonic-gate } 17110Sstevel@tonic-gate check_if_removed(pi); 17120Sstevel@tonic-gate if (show_ifs) 17130Sstevel@tonic-gate phyint_print_all(); 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate 17173284Sapersson static void 17183284Sapersson process_mibsock(int mibsock) 17193284Sapersson { 17203284Sapersson struct phyint *pi; 17213284Sapersson socklen_t fromlen; 17223284Sapersson struct sockaddr_un from; 17233284Sapersson ndpd_info_t ndpd_info; 17243284Sapersson ssize_t len; 17253284Sapersson int command; 17263284Sapersson 17273284Sapersson fromlen = (socklen_t)sizeof (from); 17283284Sapersson len = recvfrom(mibsock, &command, sizeof (int), 0, 17293284Sapersson (struct sockaddr *)&from, &fromlen); 17303284Sapersson 17313284Sapersson if (len < sizeof (int) || command != NDPD_SNMP_INFO_REQ) { 17323284Sapersson logperror("process_mibsock: bad command \n"); 17333284Sapersson return; 17343284Sapersson } 17353284Sapersson 17363284Sapersson ndpd_info.info_type = NDPD_SNMP_INFO_RESPONSE; 17373284Sapersson ndpd_info.info_version = NDPD_SNMP_INFO_VER; 17383284Sapersson ndpd_info.info_num_of_phyints = num_of_phyints; 17393284Sapersson 17403284Sapersson (void) sendto(mibsock, &ndpd_info, sizeof (ndpd_info_t), 0, 17413284Sapersson (struct sockaddr *)&from, fromlen); 17423284Sapersson 17433284Sapersson for (pi = phyints; pi != NULL; pi = pi->pi_next) { 17443284Sapersson int prefixes; 17453284Sapersson int routers; 17463284Sapersson struct prefix *prefix_list; 17473284Sapersson struct router *router_list; 17483284Sapersson ndpd_phyint_info_t phyint; 17493284Sapersson ndpd_prefix_info_t prefix; 17503284Sapersson ndpd_router_info_t router; 17513284Sapersson /* 17523284Sapersson * get number of prefixes 17533284Sapersson */ 17543284Sapersson routers = 0; 17553284Sapersson prefixes = 0; 17563284Sapersson prefix_list = pi->pi_prefix_list; 17573284Sapersson while (prefix_list != NULL) { 17583284Sapersson prefixes++; 17593284Sapersson prefix_list = prefix_list->pr_next; 17603284Sapersson } 17613284Sapersson 17623284Sapersson /* 17633284Sapersson * get number of routers 17643284Sapersson */ 17653284Sapersson router_list = pi->pi_router_list; 17663284Sapersson while (router_list != NULL) { 17673284Sapersson routers++; 17683284Sapersson router_list = router_list->dr_next; 17693284Sapersson } 17703284Sapersson 17713284Sapersson phyint.phyint_info_type = NDPD_PHYINT_INFO; 17723284Sapersson phyint.phyint_info_version = NDPD_PHYINT_INFO_VER; 17733284Sapersson phyint.phyint_index = pi->pi_index; 17743284Sapersson bcopy(pi->pi_config, 17753284Sapersson phyint.phyint_config, I_IFSIZE); 17763284Sapersson phyint.phyint_num_of_prefixes = prefixes; 17773284Sapersson phyint.phyint_num_of_routers = routers; 17783284Sapersson (void) sendto(mibsock, &phyint, sizeof (phyint), 0, 17793284Sapersson (struct sockaddr *)&from, fromlen); 17803284Sapersson 17813284Sapersson /* 17823284Sapersson * Copy prefix information 17833284Sapersson */ 17843284Sapersson 17853284Sapersson prefix_list = pi->pi_prefix_list; 17863284Sapersson while (prefix_list != NULL) { 17873284Sapersson prefix.prefix_info_type = NDPD_PREFIX_INFO; 17883284Sapersson prefix.prefix_info_version = NDPD_PREFIX_INFO_VER; 17893284Sapersson prefix.prefix_prefix = prefix_list->pr_prefix; 17903284Sapersson prefix.prefix_len = prefix_list->pr_prefix_len; 17913284Sapersson prefix.prefix_flags = prefix_list->pr_flags; 17923284Sapersson prefix.prefix_phyint_index = pi->pi_index; 17933284Sapersson prefix.prefix_ValidLifetime = 17943284Sapersson prefix_list->pr_ValidLifetime; 17953284Sapersson prefix.prefix_PreferredLifetime = 17963284Sapersson prefix_list->pr_PreferredLifetime; 17973284Sapersson prefix.prefix_OnLinkLifetime = 17983284Sapersson prefix_list->pr_OnLinkLifetime; 17993284Sapersson prefix.prefix_OnLinkFlag = 18003284Sapersson prefix_list->pr_OnLinkFlag; 18013284Sapersson prefix.prefix_AutonomousFlag = 18023284Sapersson prefix_list->pr_AutonomousFlag; 18033284Sapersson (void) sendto(mibsock, &prefix, sizeof (prefix), 0, 18043284Sapersson (struct sockaddr *)&from, fromlen); 18053284Sapersson prefix_list = prefix_list->pr_next; 18063284Sapersson } 18073284Sapersson /* 18083284Sapersson * Copy router information 18093284Sapersson */ 18103284Sapersson router_list = pi->pi_router_list; 18113284Sapersson while (router_list != NULL) { 18123284Sapersson router.router_info_type = NDPD_ROUTER_INFO; 18133284Sapersson router.router_info_version = NDPD_ROUTER_INFO_VER; 18143284Sapersson router.router_address = router_list->dr_address; 18153284Sapersson router.router_lifetime = router_list->dr_lifetime; 18163284Sapersson router.router_phyint_index = pi->pi_index; 18173284Sapersson (void) sendto(mibsock, &router, sizeof (router), 0, 18183284Sapersson (struct sockaddr *)&from, fromlen); 18193284Sapersson router_list = router_list->dr_next; 18203284Sapersson } 18213284Sapersson } 18223284Sapersson } 18233284Sapersson 18240Sstevel@tonic-gate /* 18250Sstevel@tonic-gate * Check whether the address formed by pr->pr_prefix and pi_token 18260Sstevel@tonic-gate * exists in the kernel. Cannot call SIOCTMYADDR/ONLINK as it 18270Sstevel@tonic-gate * does not check for down addresses. This function should not 18280Sstevel@tonic-gate * be called for onlink prefixes. 18290Sstevel@tonic-gate */ 18300Sstevel@tonic-gate static boolean_t 18310Sstevel@tonic-gate is_address_present(struct phyint *pi, struct prefix *pr, uint64_t flags) 18320Sstevel@tonic-gate { 18330Sstevel@tonic-gate int s; 18340Sstevel@tonic-gate in6_addr_t addr, *token; 18350Sstevel@tonic-gate int i; 18360Sstevel@tonic-gate int ret; 18370Sstevel@tonic-gate struct sockaddr_in6 sin6; 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate s = socket(AF_INET6, SOCK_DGRAM, 0); 18400Sstevel@tonic-gate if (s < 0) { 18410Sstevel@tonic-gate logperror("is_address_present: socket"); 18420Sstevel@tonic-gate /* 18430Sstevel@tonic-gate * By returning B_TRUE, we make the caller delete 18440Sstevel@tonic-gate * the prefix from the internal table. In the worst 18450Sstevel@tonic-gate * case the next RA will create the prefix. 18460Sstevel@tonic-gate */ 18470Sstevel@tonic-gate return (_B_TRUE); 18480Sstevel@tonic-gate } 18490Sstevel@tonic-gate if (flags & IFF_TEMPORARY) 18500Sstevel@tonic-gate token = &pi->pi_tmp_token; 18510Sstevel@tonic-gate else 18520Sstevel@tonic-gate token = &pi->pi_token; 18530Sstevel@tonic-gate for (i = 0; i < 16; i++) { 18540Sstevel@tonic-gate /* 18550Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 18560Sstevel@tonic-gate * bits after prefixlen. 18570Sstevel@tonic-gate */ 18580Sstevel@tonic-gate addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i]; 18590Sstevel@tonic-gate } 18600Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (struct sockaddr_in6)); 18610Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 18620Sstevel@tonic-gate sin6.sin6_addr = addr; 18630Sstevel@tonic-gate ret = bind(s, (struct sockaddr *)&sin6, sizeof (struct sockaddr_in6)); 18640Sstevel@tonic-gate (void) close(s); 18650Sstevel@tonic-gate if (ret < 0 && errno == EADDRNOTAVAIL) 18660Sstevel@tonic-gate return (_B_FALSE); 18670Sstevel@tonic-gate else 18680Sstevel@tonic-gate return (_B_TRUE); 18690Sstevel@tonic-gate } 18700Sstevel@tonic-gate 18710Sstevel@tonic-gate /* 18720Sstevel@tonic-gate * Look if the phyint or one of its prefixes have been removed from 18730Sstevel@tonic-gate * the kernel and take appropriate action. 18740Sstevel@tonic-gate * Uses {pi,pr}_in_use. 18750Sstevel@tonic-gate */ 18760Sstevel@tonic-gate static void 18770Sstevel@tonic-gate check_if_removed(struct phyint *pi) 18780Sstevel@tonic-gate { 18790Sstevel@tonic-gate struct prefix *pr; 18800Sstevel@tonic-gate struct prefix *next_pr; 18810Sstevel@tonic-gate 18820Sstevel@tonic-gate /* 18830Sstevel@tonic-gate * Detect phyints that have been removed from the kernel. 18840Sstevel@tonic-gate * Since we can't recreate it here (would require ifconfig plumb 18850Sstevel@tonic-gate * logic) we just terminate use of that phyint. 18860Sstevel@tonic-gate */ 18870Sstevel@tonic-gate if (!(pi->pi_kernel_state & PI_PRESENT) && 18880Sstevel@tonic-gate (pi->pi_state & PI_PRESENT)) { 18890Sstevel@tonic-gate logmsg(LOG_ERR, "Interface %s has been removed from kernel. " 18900Sstevel@tonic-gate "in.ndpd will no longer use it\n", pi->pi_name); 18910Sstevel@tonic-gate /* 18920Sstevel@tonic-gate * Clear state so that should the phyint reappear 18930Sstevel@tonic-gate * we will start with initial advertisements or 18940Sstevel@tonic-gate * solicitations. 18950Sstevel@tonic-gate */ 18960Sstevel@tonic-gate phyint_cleanup(pi); 18970Sstevel@tonic-gate } 18980Sstevel@tonic-gate /* 18990Sstevel@tonic-gate * Detect prefixes which are removed. 19000Sstevel@tonic-gate * 19010Sstevel@tonic-gate * We remove the prefix in all of the following cases : 19020Sstevel@tonic-gate * 19030Sstevel@tonic-gate * 1) Static prefixes are not the ones we create. So, 19040Sstevel@tonic-gate * just remove it from our tables. 19050Sstevel@tonic-gate * 19060Sstevel@tonic-gate * 2) On-link prefixes potentially move to a different 19070Sstevel@tonic-gate * phyint during failover. As it does not have 19080Sstevel@tonic-gate * an address, we can't use the logic in is_address_present 19090Sstevel@tonic-gate * to detect whether it is present in the kernel or not. 19100Sstevel@tonic-gate * Thus when it is manually removed we don't recreate it. 19110Sstevel@tonic-gate * 19120Sstevel@tonic-gate * 3) If there is a token mis-match and this prefix is not 19130Sstevel@tonic-gate * in the kernel, it means we don't need this prefix on 19140Sstevel@tonic-gate * this interface anymore. It must have been moved to a 19150Sstevel@tonic-gate * different interface by in.mpathd. This normally 19160Sstevel@tonic-gate * happens after a failover followed by a failback (or 19170Sstevel@tonic-gate * another failover) and we re-read the network 19180Sstevel@tonic-gate * configuration. For the failover from A to B, we would 19190Sstevel@tonic-gate * have created state on B about A's address, which will 19200Sstevel@tonic-gate * not be in use after the subsequent failback. So, we 19210Sstevel@tonic-gate * remove that prefix here. 19220Sstevel@tonic-gate * 19230Sstevel@tonic-gate * 4) If the physical interface is not present, then remove 19240Sstevel@tonic-gate * the prefix. In the cases where we are advertising 19250Sstevel@tonic-gate * prefixes, the state is kept in advertisement prefix and 19260Sstevel@tonic-gate * hence we can delete the prefix. 19270Sstevel@tonic-gate * 19280Sstevel@tonic-gate * 5) Similar to case (3), when we failover from A to B, the 19290Sstevel@tonic-gate * prefix in A will not be in use as it has been moved to B. 19300Sstevel@tonic-gate * We will delete it from our tables and recreate it when 19310Sstevel@tonic-gate * it fails back. is_address_present makes sure that the 19320Sstevel@tonic-gate * address is still valid in kernel. 19330Sstevel@tonic-gate * 19340Sstevel@tonic-gate * If none of the above is true, we recreate the prefix as it 19350Sstevel@tonic-gate * has been manually removed. We do it only when the interface 19360Sstevel@tonic-gate * is not FAILED or INACTIVE or OFFLINE. 19370Sstevel@tonic-gate */ 19380Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 19390Sstevel@tonic-gate next_pr = pr->pr_next; 19400Sstevel@tonic-gate if (!pr->pr_in_use) { 19410Sstevel@tonic-gate /* Clear PR_AUTO and PR_ONLINK */ 19420Sstevel@tonic-gate pr->pr_kernel_state &= PR_STATIC; 19430Sstevel@tonic-gate if ((pr->pr_state & PR_STATIC) || 19440Sstevel@tonic-gate !(pr->pr_state & PR_AUTO) || 19450Sstevel@tonic-gate !(prefix_token_match(pi, pr, pr->pr_flags)) || 19460Sstevel@tonic-gate (!(pi->pi_kernel_state & PI_PRESENT)) || 19470Sstevel@tonic-gate (is_address_present(pi, pr, pr->pr_flags))) { 19480Sstevel@tonic-gate prefix_delete(pr); 19490Sstevel@tonic-gate } else if (!(pi->pi_flags & 19500Sstevel@tonic-gate (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) && 19510Sstevel@tonic-gate pr->pr_state != pr->pr_kernel_state) { 19520Sstevel@tonic-gate pr->pr_name[0] = '\0'; 19530Sstevel@tonic-gate logmsg(LOG_INFO, "Prefix manually removed " 19540Sstevel@tonic-gate "on %s - recreating it!\n", 19550Sstevel@tonic-gate pi->pi_name); 19560Sstevel@tonic-gate prefix_update_k(pr); 19570Sstevel@tonic-gate } 19580Sstevel@tonic-gate } 19590Sstevel@tonic-gate } 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate 19620Sstevel@tonic-gate 19630Sstevel@tonic-gate /* 19640Sstevel@tonic-gate * Queuing mechanism for router advertisements that are sent by in.ndpd 19650Sstevel@tonic-gate * and that also need to be processed by in.ndpd. 19660Sstevel@tonic-gate * Uses "signal number" 255 to indicate to the main poll loop 19670Sstevel@tonic-gate * that there is something to dequeue and send to incomining_ra(). 19680Sstevel@tonic-gate */ 19690Sstevel@tonic-gate struct raq { 19700Sstevel@tonic-gate struct raq *raq_next; 19710Sstevel@tonic-gate struct phyint *raq_pi; 19720Sstevel@tonic-gate int raq_packetlen; 19730Sstevel@tonic-gate uchar_t *raq_packet; 19740Sstevel@tonic-gate }; 19750Sstevel@tonic-gate static struct raq *raq_head = NULL; 19760Sstevel@tonic-gate 19770Sstevel@tonic-gate /* 19780Sstevel@tonic-gate * Allocate a struct raq and memory for the packet. 19790Sstevel@tonic-gate * Send signal 255 to have poll dequeue. 19800Sstevel@tonic-gate */ 19810Sstevel@tonic-gate static void 19820Sstevel@tonic-gate loopback_ra_enqueue(struct phyint *pi, struct nd_router_advert *ra, int len) 19830Sstevel@tonic-gate { 19840Sstevel@tonic-gate struct raq *raq; 19850Sstevel@tonic-gate struct raq **raqp; 19860Sstevel@tonic-gate 19870Sstevel@tonic-gate if (no_loopback) 19880Sstevel@tonic-gate return; 19890Sstevel@tonic-gate 19900Sstevel@tonic-gate if (debug & D_PKTOUT) 19910Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_enqueue for %s\n", pi->pi_name); 19920Sstevel@tonic-gate 19930Sstevel@tonic-gate raq = calloc(sizeof (struct raq), 1); 19940Sstevel@tonic-gate if (raq == NULL) { 19950Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 19960Sstevel@tonic-gate return; 19970Sstevel@tonic-gate } 19980Sstevel@tonic-gate raq->raq_packet = malloc(len); 19990Sstevel@tonic-gate if (raq->raq_packet == NULL) { 20000Sstevel@tonic-gate free(raq); 20010Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 20020Sstevel@tonic-gate return; 20030Sstevel@tonic-gate } 20040Sstevel@tonic-gate bcopy(ra, raq->raq_packet, len); 20050Sstevel@tonic-gate raq->raq_packetlen = len; 20060Sstevel@tonic-gate raq->raq_pi = pi; 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate /* Tail insert */ 20090Sstevel@tonic-gate raqp = &raq_head; 20100Sstevel@tonic-gate while (*raqp != NULL) 20110Sstevel@tonic-gate raqp = &((*raqp)->raq_next); 20120Sstevel@tonic-gate *raqp = raq; 20130Sstevel@tonic-gate 20140Sstevel@tonic-gate /* Signal for poll loop */ 20150Sstevel@tonic-gate sig_handler(255); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate 20180Sstevel@tonic-gate /* 20190Sstevel@tonic-gate * Dequeue and process all queued advertisements. 20200Sstevel@tonic-gate */ 20210Sstevel@tonic-gate static void 20220Sstevel@tonic-gate loopback_ra_dequeue(void) 20230Sstevel@tonic-gate { 20240Sstevel@tonic-gate struct sockaddr_in6 from = IN6ADDR_LOOPBACK_INIT; 20250Sstevel@tonic-gate struct raq *raq; 20260Sstevel@tonic-gate 20270Sstevel@tonic-gate if (debug & D_PKTIN) 20280Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue()\n"); 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate while ((raq = raq_head) != NULL) { 20310Sstevel@tonic-gate raq_head = raq->raq_next; 20320Sstevel@tonic-gate raq->raq_next = NULL; 20330Sstevel@tonic-gate 20340Sstevel@tonic-gate if (debug & D_PKTIN) { 20350Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue for %s\n", 20360Sstevel@tonic-gate raq->raq_pi->pi_name); 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate incoming_ra(raq->raq_pi, 20400Sstevel@tonic-gate (struct nd_router_advert *)raq->raq_packet, 20410Sstevel@tonic-gate raq->raq_packetlen, &from, _B_TRUE); 20420Sstevel@tonic-gate free(raq->raq_packet); 20430Sstevel@tonic-gate free(raq); 20440Sstevel@tonic-gate } 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate 20480Sstevel@tonic-gate static void 20490Sstevel@tonic-gate usage(char *cmd) 20500Sstevel@tonic-gate { 20510Sstevel@tonic-gate (void) fprintf(stderr, 20520Sstevel@tonic-gate "usage: %s [ -adt ] [-f <config file>]\n", cmd); 20530Sstevel@tonic-gate } 20540Sstevel@tonic-gate 20550Sstevel@tonic-gate int 20560Sstevel@tonic-gate main(int argc, char *argv[]) 20570Sstevel@tonic-gate { 20580Sstevel@tonic-gate int i; 20590Sstevel@tonic-gate struct phyint *pi; 20600Sstevel@tonic-gate int c; 20610Sstevel@tonic-gate char *config_file = PATH_NDPD_CONF; 20620Sstevel@tonic-gate boolean_t file_required = _B_FALSE; 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate argv0 = argv; 20650Sstevel@tonic-gate srandom(gethostid()); 20660Sstevel@tonic-gate (void) umask(0022); 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate while ((c = getopt(argc, argv, "adD:ntIf:")) != EOF) { 20690Sstevel@tonic-gate switch (c) { 20700Sstevel@tonic-gate case 'a': 20710Sstevel@tonic-gate /* 20720Sstevel@tonic-gate * The StatelessAddrConf variable in ndpd.conf, if 20730Sstevel@tonic-gate * present, will override this setting. 20740Sstevel@tonic-gate */ 20750Sstevel@tonic-gate ifdefaults[I_StatelessAddrConf].cf_value = 0; 20760Sstevel@tonic-gate break; 20770Sstevel@tonic-gate case 'd': 20780Sstevel@tonic-gate debug = D_ALL; 20790Sstevel@tonic-gate break; 20800Sstevel@tonic-gate case 'D': 20810Sstevel@tonic-gate i = strtol((char *)optarg, NULL, 0); 20820Sstevel@tonic-gate if (i == 0) { 20830Sstevel@tonic-gate (void) fprintf(stderr, "Bad debug flags: %s\n", 20840Sstevel@tonic-gate (char *)optarg); 20850Sstevel@tonic-gate exit(1); 20860Sstevel@tonic-gate } 20870Sstevel@tonic-gate debug |= i; 20880Sstevel@tonic-gate break; 20890Sstevel@tonic-gate case 'n': 20900Sstevel@tonic-gate no_loopback = 1; 20910Sstevel@tonic-gate break; 20920Sstevel@tonic-gate case 'I': 20930Sstevel@tonic-gate show_ifs = 1; 20940Sstevel@tonic-gate break; 20950Sstevel@tonic-gate case 't': 20960Sstevel@tonic-gate debug |= D_PKTIN | D_PKTOUT | D_PKTBAD; 20970Sstevel@tonic-gate break; 20980Sstevel@tonic-gate case 'f': 20990Sstevel@tonic-gate config_file = (char *)optarg; 21000Sstevel@tonic-gate file_required = _B_TRUE; 21010Sstevel@tonic-gate break; 21020Sstevel@tonic-gate case '?': 21030Sstevel@tonic-gate usage(argv[0]); 21040Sstevel@tonic-gate exit(1); 21050Sstevel@tonic-gate } 21060Sstevel@tonic-gate } 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate if (parse_config(config_file, file_required) == -1) 21090Sstevel@tonic-gate exit(2); 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate if (show_ifs) 21120Sstevel@tonic-gate phyint_print_all(); 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate if (debug == 0) { 21150Sstevel@tonic-gate initlog(); 21160Sstevel@tonic-gate } 21170Sstevel@tonic-gate 21180Sstevel@tonic-gate setup_eventpipe(); 21190Sstevel@tonic-gate rtsock = setup_rtsock(); 21203284Sapersson mibsock = setup_mibsock(); 21210Sstevel@tonic-gate timer_init(); 21220Sstevel@tonic-gate initifs(_B_TRUE); 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate check_daemonize(); 21250Sstevel@tonic-gate 21260Sstevel@tonic-gate for (;;) { 21270Sstevel@tonic-gate if (poll(pollfds, pollfd_num, -1) < 0) { 21280Sstevel@tonic-gate if (errno == EINTR) 21290Sstevel@tonic-gate continue; 21300Sstevel@tonic-gate logperror("main: poll"); 21310Sstevel@tonic-gate exit(1); 21320Sstevel@tonic-gate } 21330Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 21340Sstevel@tonic-gate if (!(pollfds[i].revents & POLLIN)) 21350Sstevel@tonic-gate continue; 21360Sstevel@tonic-gate if (pollfds[i].fd == eventpipe_read) { 21370Sstevel@tonic-gate in_signal(eventpipe_read); 21380Sstevel@tonic-gate break; 21390Sstevel@tonic-gate } 21400Sstevel@tonic-gate if (pollfds[i].fd == rtsock) { 21410Sstevel@tonic-gate process_rtsock(rtsock); 21420Sstevel@tonic-gate break; 21430Sstevel@tonic-gate } 21443284Sapersson if (pollfds[i].fd == mibsock) { 21453284Sapersson process_mibsock(mibsock); 21463284Sapersson break; 21473284Sapersson } 21480Sstevel@tonic-gate /* 21490Sstevel@tonic-gate * Run timer routine to advance clock if more than 21500Sstevel@tonic-gate * half a second since the clock was advanced. 21510Sstevel@tonic-gate * This limits CPU usage under severe packet 21520Sstevel@tonic-gate * arrival rates but it creates a slight inaccuracy 21530Sstevel@tonic-gate * in the timer mechanism. 21540Sstevel@tonic-gate */ 21550Sstevel@tonic-gate conditional_run_timeouts(500U); 21560Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 21570Sstevel@tonic-gate if (pollfds[i].fd == pi->pi_sock) { 21580Sstevel@tonic-gate in_data(pi); 21590Sstevel@tonic-gate break; 21600Sstevel@tonic-gate } 21610Sstevel@tonic-gate } 21620Sstevel@tonic-gate } 21630Sstevel@tonic-gate } 21640Sstevel@tonic-gate /* NOTREACHED */ 21650Sstevel@tonic-gate return (0); 21660Sstevel@tonic-gate } 21670Sstevel@tonic-gate 21680Sstevel@tonic-gate /* 21690Sstevel@tonic-gate * LOGGER 21700Sstevel@tonic-gate */ 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate static boolean_t logging = _B_FALSE; 21730Sstevel@tonic-gate 21740Sstevel@tonic-gate static void 21750Sstevel@tonic-gate initlog(void) 21760Sstevel@tonic-gate { 21770Sstevel@tonic-gate logging = _B_TRUE; 21780Sstevel@tonic-gate openlog("in.ndpd", LOG_PID | LOG_CONS, LOG_DAEMON); 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate /* Print the date/time without a trailing carridge return */ 21820Sstevel@tonic-gate static void 21830Sstevel@tonic-gate fprintdate(FILE *file) 21840Sstevel@tonic-gate { 21850Sstevel@tonic-gate char buf[BUFSIZ]; 21860Sstevel@tonic-gate struct tm tms; 21870Sstevel@tonic-gate time_t now; 21880Sstevel@tonic-gate 21890Sstevel@tonic-gate now = time(NULL); 21900Sstevel@tonic-gate (void) localtime_r(&now, &tms); 21910Sstevel@tonic-gate (void) strftime(buf, sizeof (buf), "%h %d %X", &tms); 21920Sstevel@tonic-gate (void) fprintf(file, "%s ", buf); 21930Sstevel@tonic-gate } 21940Sstevel@tonic-gate 21952546Scarlsonj /* PRINTFLIKE2 */ 21960Sstevel@tonic-gate void 21972428Smh138676 logmsg(int level, const char *fmt, ...) 21980Sstevel@tonic-gate { 21990Sstevel@tonic-gate va_list ap; 22000Sstevel@tonic-gate va_start(ap, fmt); 22010Sstevel@tonic-gate 22020Sstevel@tonic-gate if (logging) { 22030Sstevel@tonic-gate vsyslog(level, fmt, ap); 22040Sstevel@tonic-gate } else { 22050Sstevel@tonic-gate fprintdate(stderr); 22060Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 22070Sstevel@tonic-gate } 22080Sstevel@tonic-gate va_end(ap); 22090Sstevel@tonic-gate } 22100Sstevel@tonic-gate 22110Sstevel@tonic-gate void 22122428Smh138676 logperror(const char *str) 22130Sstevel@tonic-gate { 22140Sstevel@tonic-gate if (logging) { 22150Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 22160Sstevel@tonic-gate } else { 22170Sstevel@tonic-gate fprintdate(stderr); 22180Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 22190Sstevel@tonic-gate } 22200Sstevel@tonic-gate } 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate void 22232428Smh138676 logperror_pi(const struct phyint *pi, const char *str) 22240Sstevel@tonic-gate { 22250Sstevel@tonic-gate if (logging) { 22260Sstevel@tonic-gate syslog(LOG_ERR, "%s (interface %s): %m\n", 22270Sstevel@tonic-gate str, pi->pi_name); 22280Sstevel@tonic-gate } else { 22290Sstevel@tonic-gate fprintdate(stderr); 22300Sstevel@tonic-gate (void) fprintf(stderr, "%s (interface %s): %s\n", 22310Sstevel@tonic-gate str, pi->pi_name, strerror(errno)); 22320Sstevel@tonic-gate } 22330Sstevel@tonic-gate } 22340Sstevel@tonic-gate 22350Sstevel@tonic-gate void 22362428Smh138676 logperror_pr(const struct prefix *pr, const char *str) 22370Sstevel@tonic-gate { 22380Sstevel@tonic-gate if (logging) { 22390Sstevel@tonic-gate syslog(LOG_ERR, "%s (prefix %s if %s): %m\n", 22400Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name); 22410Sstevel@tonic-gate } else { 22420Sstevel@tonic-gate fprintdate(stderr); 22430Sstevel@tonic-gate (void) fprintf(stderr, "%s (prefix %s if %s): %s\n", 22440Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name, 22450Sstevel@tonic-gate strerror(errno)); 22460Sstevel@tonic-gate } 22470Sstevel@tonic-gate } 2248