17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*8121d73fSseb * Common Development and Distribution License (the "License"). 6*8121d73fSseb * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*8121d73fSseb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include "defs.h" 297c478bd9Sstevel@tonic-gate #include "tables.h" 307c478bd9Sstevel@tonic-gate #include <fcntl.h> 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate static void initlog(void); 337c478bd9Sstevel@tonic-gate static void run_timeouts(void); 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate static void advertise(struct sockaddr_in6 *sin6, struct phyint *pi, 367c478bd9Sstevel@tonic-gate boolean_t no_prefixes); 377c478bd9Sstevel@tonic-gate static void solicit(struct sockaddr_in6 *sin6, struct phyint *pi); 387c478bd9Sstevel@tonic-gate static void initifs(boolean_t first); 397c478bd9Sstevel@tonic-gate static void check_if_removed(struct phyint *pi); 407c478bd9Sstevel@tonic-gate static void loopback_ra_enqueue(struct phyint *pi, 417c478bd9Sstevel@tonic-gate struct nd_router_advert *ra, int len); 427c478bd9Sstevel@tonic-gate static void loopback_ra_dequeue(void); 437c478bd9Sstevel@tonic-gate static void check_daemonize(void); 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate struct in6_addr all_nodes_mcast = { { 0xff, 0x2, 0x0, 0x0, 467c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 477c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 487c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } }; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate struct in6_addr all_routers_mcast = { { 0xff, 0x2, 0x0, 0x0, 517c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 527c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 537c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } }; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate static struct sockaddr_in6 v6allnodes = { AF_INET6, 0, 0, 567c478bd9Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 577c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 587c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 597c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x1 } }; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static struct sockaddr_in6 v6allrouters = { AF_INET6, 0, 0, 627c478bd9Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 637c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 647c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 657c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x2 } }; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static char **argv0; /* Saved for re-exec on SIGHUP */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static uint64_t packet[(IP_MAXPACKET + 1)/8]; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate static int show_ifs = 0; 727c478bd9Sstevel@tonic-gate static boolean_t already_daemonized = _B_FALSE; 737c478bd9Sstevel@tonic-gate int debug = 0; 747c478bd9Sstevel@tonic-gate int no_loopback = 0; /* Do not send RA packets to ourselves */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * Size of routing socket message used by in.ndpd which includes the header, 787c478bd9Sstevel@tonic-gate * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6) 797c478bd9Sstevel@tonic-gate * plus space for the RTA_IFP (a sockaddr_dl). 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate #define NDP_RTM_MSGLEN sizeof (struct rt_msghdr) + \ 827c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 837c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 847c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6) + \ 857c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl) 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * These are referenced externally in tables.c in order to fill in the 897c478bd9Sstevel@tonic-gate * dynamic portions of the routing socket message and then to send the message 907c478bd9Sstevel@tonic-gate * itself. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate int rtsock = -1; /* Routing socket */ 937c478bd9Sstevel@tonic-gate struct rt_msghdr *rt_msg; /* Routing socket message */ 947c478bd9Sstevel@tonic-gate struct sockaddr_in6 *rta_gateway; /* RTA_GATEWAY sockaddr */ 957c478bd9Sstevel@tonic-gate struct sockaddr_dl *rta_ifp; /* RTA_IFP sockaddr */ 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * Return the current time in milliseconds truncated to 997c478bd9Sstevel@tonic-gate * fit in an integer. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate uint_t 1027c478bd9Sstevel@tonic-gate getcurrenttime(void) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate struct timeval tp; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate if (gettimeofday(&tp, NULL) < 0) { 1077c478bd9Sstevel@tonic-gate logperror("getcurrenttime: gettimeofday failed"); 1087c478bd9Sstevel@tonic-gate exit(1); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate return (tp.tv_sec * 1000 + tp.tv_usec / 1000); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * Output a preformated packet from the packet[] buffer. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate static void 1177c478bd9Sstevel@tonic-gate sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate int cc; 1207c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate cc = sendto(sock, (char *)packet, size, flags, 1237c478bd9Sstevel@tonic-gate (struct sockaddr *)sin6, sizeof (*sin6)); 1247c478bd9Sstevel@tonic-gate if (cc < 0 || cc != size) { 1257c478bd9Sstevel@tonic-gate if (cc < 0) { 1267c478bd9Sstevel@tonic-gate logperror("sendpacket: sendto"); 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "sendpacket: wrote %s %d chars, ret=%d\n", 1297c478bd9Sstevel@tonic-gate inet_ntop(sin6->sin6_family, 1307c478bd9Sstevel@tonic-gate (void *)&sin6->sin6_addr, 1317c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), 1327c478bd9Sstevel@tonic-gate size, cc); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* Send a Router Solicitation */ 1377c478bd9Sstevel@tonic-gate static void 1387c478bd9Sstevel@tonic-gate solicit(struct sockaddr_in6 *sin6, struct phyint *pi) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate int packetlen = 0; 1417c478bd9Sstevel@tonic-gate struct nd_router_solicit *rs = (struct nd_router_solicit *)packet; 1427c478bd9Sstevel@tonic-gate char *pptr = (char *)packet; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate rs->nd_rs_type = ND_ROUTER_SOLICIT; 1457c478bd9Sstevel@tonic-gate rs->nd_rs_code = 0; 1467c478bd9Sstevel@tonic-gate rs->nd_rs_cksum = htons(0); 1477c478bd9Sstevel@tonic-gate rs->nd_rs_reserved = htonl(0); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate packetlen += sizeof (*rs); 1507c478bd9Sstevel@tonic-gate pptr += sizeof (*rs); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* Attach any options */ 1537c478bd9Sstevel@tonic-gate if (pi->pi_hdw_addr_len != 0) { 1547c478bd9Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr; 1557c478bd9Sstevel@tonic-gate int optlen; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* roundup to multiple of 8 and make padding zero */ 1587c478bd9Sstevel@tonic-gate optlen = ((sizeof (struct nd_opt_hdr) + 1597c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len + 7) / 8) * 8; 1607c478bd9Sstevel@tonic-gate bzero(pptr, optlen); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR; 1637c478bd9Sstevel@tonic-gate lo->nd_opt_lla_len = optlen / 8; 1647c478bd9Sstevel@tonic-gate bcopy((char *)pi->pi_hdw_addr, 1657c478bd9Sstevel@tonic-gate (char *)lo->nd_opt_lla_hdw_addr, 1667c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len); 1677c478bd9Sstevel@tonic-gate packetlen += optlen; 1687c478bd9Sstevel@tonic-gate pptr += optlen; 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 1727c478bd9Sstevel@tonic-gate print_route_sol("Sending solicitation to ", pi, rs, packetlen, 1737c478bd9Sstevel@tonic-gate sin6); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * Send a (set of) Router Advertisements and feed them back to ourselves 1807c478bd9Sstevel@tonic-gate * for processing. Unless no_prefixes is set all prefixes are included. 1817c478bd9Sstevel@tonic-gate * If there are too many prefix options to fit in one packet multiple 1827c478bd9Sstevel@tonic-gate * packets will be sent - each containing a subset of the prefix options. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate static void 1857c478bd9Sstevel@tonic-gate advertise(struct sockaddr_in6 *sin6, struct phyint *pi, boolean_t no_prefixes) 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po; 1887c478bd9Sstevel@tonic-gate char *pptr = (char *)packet; 1897c478bd9Sstevel@tonic-gate struct nd_router_advert *ra; 1907c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 1917c478bd9Sstevel@tonic-gate int packetlen = 0; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate ra = (struct nd_router_advert *)pptr; 1947c478bd9Sstevel@tonic-gate ra->nd_ra_type = ND_ROUTER_ADVERT; 1957c478bd9Sstevel@tonic-gate ra->nd_ra_code = 0; 1967c478bd9Sstevel@tonic-gate ra->nd_ra_cksum = htons(0); 1977c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit = pi->pi_AdvCurHopLimit; 1987c478bd9Sstevel@tonic-gate ra->nd_ra_flags_reserved = 0; 1997c478bd9Sstevel@tonic-gate if (pi->pi_AdvManagedFlag) 2007c478bd9Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; 2017c478bd9Sstevel@tonic-gate if (pi->pi_AdvOtherConfigFlag) 2027c478bd9Sstevel@tonic-gate ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 2057c478bd9Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(0); 2067c478bd9Sstevel@tonic-gate else 2077c478bd9Sstevel@tonic-gate ra->nd_ra_router_lifetime = htons(pi->pi_AdvDefaultLifetime); 2087c478bd9Sstevel@tonic-gate ra->nd_ra_reachable = htonl(pi->pi_AdvReachableTime); 2097c478bd9Sstevel@tonic-gate ra->nd_ra_retransmit = htonl(pi->pi_AdvRetransTimer); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate packetlen = sizeof (*ra); 2127c478bd9Sstevel@tonic-gate pptr += sizeof (*ra); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 2157c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 2167c478bd9Sstevel@tonic-gate print_route_adv("Sending advert (FINAL) to ", pi, 2177c478bd9Sstevel@tonic-gate ra, packetlen, sin6); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2207c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */ 2217c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2227c478bd9Sstevel@tonic-gate return; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* Attach any options */ 2267c478bd9Sstevel@tonic-gate if (pi->pi_hdw_addr_len != 0) { 2277c478bd9Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr; 2287c478bd9Sstevel@tonic-gate int optlen; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* roundup to multiple of 8 and make padding zero */ 2317c478bd9Sstevel@tonic-gate optlen = ((sizeof (struct nd_opt_hdr) + 2327c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len + 7) / 8) * 8; 2337c478bd9Sstevel@tonic-gate bzero(pptr, optlen); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR; 2367c478bd9Sstevel@tonic-gate lo->nd_opt_lla_len = optlen / 8; 2377c478bd9Sstevel@tonic-gate bcopy((char *)pi->pi_hdw_addr, 2387c478bd9Sstevel@tonic-gate (char *)lo->nd_opt_lla_hdw_addr, 2397c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len); 2407c478bd9Sstevel@tonic-gate packetlen += optlen; 2417c478bd9Sstevel@tonic-gate pptr += optlen; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0) { 2457c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)pptr; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_type = ND_OPT_MTU; 2487c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_len = sizeof (struct nd_opt_mtu) / 8; 2497c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_reserved = 0; 2507c478bd9Sstevel@tonic-gate mo->nd_opt_mtu_mtu = htonl(pi->pi_AdvLinkMTU); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate packetlen += sizeof (struct nd_opt_mtu); 2537c478bd9Sstevel@tonic-gate pptr += sizeof (struct nd_opt_mtu); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (no_prefixes) { 2577c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 2587c478bd9Sstevel@tonic-gate print_route_adv("Sending advert to ", pi, 2597c478bd9Sstevel@tonic-gate ra, packetlen, sin6); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2627c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */ 2637c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2647c478bd9Sstevel@tonic-gate return; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr; 2687c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 2697c478bd9Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 2707c478bd9Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvOnLinkFlag && 2717c478bd9Sstevel@tonic-gate !adv_pr->adv_pr_AdvAutonomousFlag) { 2727c478bd9Sstevel@tonic-gate continue; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * If the prefix doesn't fit in packet send 2777c478bd9Sstevel@tonic-gate * what we have so far and start with new packet. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate if (packetlen + sizeof (*po) > 2807c478bd9Sstevel@tonic-gate pi->pi_LinkMTU - sizeof (struct ip6_hdr)) { 2817c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 2827c478bd9Sstevel@tonic-gate print_route_adv("Sending advert " 2837c478bd9Sstevel@tonic-gate "(FRAG) to ", 2847c478bd9Sstevel@tonic-gate pi, ra, packetlen, sin6); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 2877c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */ 2887c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 2897c478bd9Sstevel@tonic-gate packetlen = sizeof (*ra); 2907c478bd9Sstevel@tonic-gate pptr = (char *)packet + sizeof (*ra); 2917c478bd9Sstevel@tonic-gate po = (struct nd_opt_prefix_info *)pptr; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate po->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 2947c478bd9Sstevel@tonic-gate po->nd_opt_pi_len = sizeof (*po)/8; 2957c478bd9Sstevel@tonic-gate po->nd_opt_pi_flags_reserved = 0; 2967c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvOnLinkFlag) { 2977c478bd9Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |= 2987c478bd9Sstevel@tonic-gate ND_OPT_PI_FLAG_ONLINK; 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvAutonomousFlag) { 3017c478bd9Sstevel@tonic-gate po->nd_opt_pi_flags_reserved |= 3027c478bd9Sstevel@tonic-gate ND_OPT_PI_FLAG_AUTO; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate po->nd_opt_pi_prefix_len = adv_pr->adv_pr_prefix_len; 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * If both Adv*Expiration and Adv*Lifetime are 3077c478bd9Sstevel@tonic-gate * set we prefer the former and make the lifetime 3087c478bd9Sstevel@tonic-gate * decrement in real time. 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 3117c478bd9Sstevel@tonic-gate po->nd_opt_pi_valid_time = 3127c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidExpiration); 3137c478bd9Sstevel@tonic-gate } else { 3147c478bd9Sstevel@tonic-gate po->nd_opt_pi_valid_time = 3157c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvValidLifetime); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 3187c478bd9Sstevel@tonic-gate po->nd_opt_pi_preferred_time = 3197c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredExpiration); 3207c478bd9Sstevel@tonic-gate } else { 3217c478bd9Sstevel@tonic-gate po->nd_opt_pi_preferred_time = 3227c478bd9Sstevel@tonic-gate htonl(adv_pr->adv_pr_AdvPreferredLifetime); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate po->nd_opt_pi_reserved2 = htonl(0); 3257c478bd9Sstevel@tonic-gate po->nd_opt_pi_prefix = adv_pr->adv_pr_prefix; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate po++; 3287c478bd9Sstevel@tonic-gate packetlen += sizeof (*po); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 3317c478bd9Sstevel@tonic-gate print_route_adv("Sending advert to ", pi, 3327c478bd9Sstevel@tonic-gate ra, packetlen, sin6); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate sendpacket(sin6, pi->pi_sock, packetlen, 0); 3357c478bd9Sstevel@tonic-gate /* Feed packet back in for router operation */ 3367c478bd9Sstevel@tonic-gate loopback_ra_enqueue(pi, ra, packetlen); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* Poll support */ 3407c478bd9Sstevel@tonic-gate static int pollfd_num = 0; /* Allocated and initialized */ 3417c478bd9Sstevel@tonic-gate static struct pollfd *pollfds = NULL; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* 3447c478bd9Sstevel@tonic-gate * Add fd to the set being polled. Returns 0 if ok; -1 if failed. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate int 3477c478bd9Sstevel@tonic-gate poll_add(int fd) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate int i; 3507c478bd9Sstevel@tonic-gate int new_num; 3517c478bd9Sstevel@tonic-gate struct pollfd *newfds; 3527c478bd9Sstevel@tonic-gate retry: 3537c478bd9Sstevel@tonic-gate /* Check if already present */ 3547c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3557c478bd9Sstevel@tonic-gate if (pollfds[i].fd == fd) 3567c478bd9Sstevel@tonic-gate return (0); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate /* Check for empty spot already present */ 3597c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3607c478bd9Sstevel@tonic-gate if (pollfds[i].fd == -1) { 3617c478bd9Sstevel@tonic-gate pollfds[i].fd = fd; 3627c478bd9Sstevel@tonic-gate return (0); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* Allocate space for 32 more fds and initialize to -1 */ 3677c478bd9Sstevel@tonic-gate new_num = pollfd_num + 32; 3687c478bd9Sstevel@tonic-gate newfds = realloc(pollfds, new_num * sizeof (struct pollfd)); 3697c478bd9Sstevel@tonic-gate if (newfds == NULL) { 3707c478bd9Sstevel@tonic-gate logperror("poll_add: realloc"); 3717c478bd9Sstevel@tonic-gate return (-1); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate for (i = pollfd_num; i < new_num; i++) { 3747c478bd9Sstevel@tonic-gate newfds[i].fd = -1; 3757c478bd9Sstevel@tonic-gate newfds[i].events = POLLIN; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate pollfd_num = new_num; 3787c478bd9Sstevel@tonic-gate pollfds = newfds; 3797c478bd9Sstevel@tonic-gate goto retry; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * Remove fd from the set being polled. Returns 0 if ok; -1 if failed. 3847c478bd9Sstevel@tonic-gate */ 3857c478bd9Sstevel@tonic-gate int 3867c478bd9Sstevel@tonic-gate poll_remove(int fd) 3877c478bd9Sstevel@tonic-gate { 3887c478bd9Sstevel@tonic-gate int i; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* Check if already present */ 3917c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 3927c478bd9Sstevel@tonic-gate if (pollfds[i].fd == fd) { 3937c478bd9Sstevel@tonic-gate pollfds[i].fd = -1; 3947c478bd9Sstevel@tonic-gate return (0); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate return (-1); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Extract information about the ifname (either a physical interface and 4027c478bd9Sstevel@tonic-gate * the ":0" logical interface or just a logical interface). 4037c478bd9Sstevel@tonic-gate * If the interface (still) exists in kernel set pr_in_use 4047c478bd9Sstevel@tonic-gate * for caller to be able to detect interfaces that are removed. 4057c478bd9Sstevel@tonic-gate * Starts sending advertisements/solicitations when new physical interfaces 4067c478bd9Sstevel@tonic-gate * are detected. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate static void 4097c478bd9Sstevel@tonic-gate if_process(int s, char *ifname, boolean_t first) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate struct lifreq lifr; 4127c478bd9Sstevel@tonic-gate struct phyint *pi; 4137c478bd9Sstevel@tonic-gate struct prefix *pr; 4147c478bd9Sstevel@tonic-gate char *cp; 4157c478bd9Sstevel@tonic-gate char phyintname[LIFNAMSIZ + 1]; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) 4187c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process(%s)\n", ifname); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 4217c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4227c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 4237c478bd9Sstevel@tonic-gate if (errno == ENXIO) { 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * Interface has disappeared 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate return; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate logperror("if_process: ioctl (get interface flags)"); 4307c478bd9Sstevel@tonic-gate return; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* 4347c478bd9Sstevel@tonic-gate * Ignore loopback and point-to-multipoint interfaces. 4357c478bd9Sstevel@tonic-gate * Point-to-point interfaces always have IFF_MULTICAST set. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_MULTICAST) || 4387c478bd9Sstevel@tonic-gate (lifr.lifr_flags & IFF_LOOPBACK)) { 4397c478bd9Sstevel@tonic-gate return; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_IPV6)) 4437c478bd9Sstevel@tonic-gate return; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate (void) strncpy(phyintname, ifname, sizeof (phyintname)); 4467c478bd9Sstevel@tonic-gate phyintname[sizeof (phyintname) - 1] = '\0'; 4477c478bd9Sstevel@tonic-gate if ((cp = strchr(phyintname, IF_SEPARATOR)) != NULL) { 4487c478bd9Sstevel@tonic-gate *cp = '\0'; 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate pi = phyint_lookup(phyintname); 4527c478bd9Sstevel@tonic-gate if (pi == NULL) { 4537c478bd9Sstevel@tonic-gate /* 4547c478bd9Sstevel@tonic-gate * Do not add anything for new interfaces until they are UP. 4557c478bd9Sstevel@tonic-gate * For existing interfaces we track the up flag. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_UP)) 4587c478bd9Sstevel@tonic-gate return; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate pi = phyint_create(phyintname); 4617c478bd9Sstevel@tonic-gate if (pi == NULL) { 4627c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n"); 4637c478bd9Sstevel@tonic-gate return; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate (void) phyint_init_from_k(pi); 4677c478bd9Sstevel@tonic-gate if (pi->pi_sock == -1 && !(pi->pi_kernel_state & PI_PRESENT)) { 4687c478bd9Sstevel@tonic-gate /* Interface is not yet present */ 4697c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 4707c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "if_process: interface not yet " 4717c478bd9Sstevel@tonic-gate "present %s\n", pi->pi_name); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate return; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (pi->pi_sock != -1) { 4777c478bd9Sstevel@tonic-gate if (poll_add(pi->pi_sock) == -1) { 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * reset state. 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate phyint_cleanup(pi); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Check if IFF_ROUTER has been turned off in kernel in which 4877c478bd9Sstevel@tonic-gate * case we have to turn off AdvSendAdvertisements. 4887c478bd9Sstevel@tonic-gate * The kernel will automatically turn off IFF_ROUTER if 4897c478bd9Sstevel@tonic-gate * ip6_forwarding is turned off. 4907c478bd9Sstevel@tonic-gate * Note that we do not switch back should IFF_ROUTER be turned on. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate if (!first && 4937c478bd9Sstevel@tonic-gate pi->pi_AdvSendAdvertisements && !(pi->pi_flags & IFF_ROUTER)) { 4947c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "No longer a router on %s\n", pi->pi_name); 4957c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate pi->pi_AdvSendAdvertisements = 0; 4987c478bd9Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Send advertisments and solicitation only if the interface is 5037c478bd9Sstevel@tonic-gate * present in the kernel. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 5087c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 5097c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_INIT_ADV); 5107c478bd9Sstevel@tonic-gate } else { 5117c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 5127c478bd9Sstevel@tonic-gate check_to_solicit(pi, START_INIT_SOLICIT); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * Track static kernel prefixes to prevent in.ndpd from clobbering 5187c478bd9Sstevel@tonic-gate * them by creating a struct prefix for each prefix detected in the 5197c478bd9Sstevel@tonic-gate * kernel. 5207c478bd9Sstevel@tonic-gate */ 5217c478bd9Sstevel@tonic-gate pr = prefix_lookup_name(pi, ifname); 5227c478bd9Sstevel@tonic-gate if (pr == NULL) { 5237c478bd9Sstevel@tonic-gate pr = prefix_create_name(pi, ifname); 5247c478bd9Sstevel@tonic-gate if (pr == NULL) { 5257c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "if_process: out of memory\n"); 5267c478bd9Sstevel@tonic-gate return; 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate if (prefix_init_from_k(pr) == -1) { 5297c478bd9Sstevel@tonic-gate prefix_delete(pr); 5307c478bd9Sstevel@tonic-gate return; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate /* Detect prefixes which are removed */ 5347c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != 0) 5357c478bd9Sstevel@tonic-gate pr->pr_in_use = _B_TRUE; 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate static int ifsock = -1; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Scan all interfaces to detect changes as well as new and deleted intefaces 5427c478bd9Sstevel@tonic-gate * 'first' is set for the initial call only. Do not effect anything. 5437c478bd9Sstevel@tonic-gate */ 5447c478bd9Sstevel@tonic-gate static void 5457c478bd9Sstevel@tonic-gate initifs(boolean_t first) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate char *buf; 5487c478bd9Sstevel@tonic-gate int bufsize; 5497c478bd9Sstevel@tonic-gate int numifs; 5507c478bd9Sstevel@tonic-gate int n; 5517c478bd9Sstevel@tonic-gate struct lifnum lifn; 5527c478bd9Sstevel@tonic-gate struct lifconf lifc; 5537c478bd9Sstevel@tonic-gate struct lifreq *lifr; 5547c478bd9Sstevel@tonic-gate struct phyint *pi; 5557c478bd9Sstevel@tonic-gate struct phyint *next_pi; 5567c478bd9Sstevel@tonic-gate struct prefix *pr; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) 5597c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Reading interface configuration\n"); 5607c478bd9Sstevel@tonic-gate if (ifsock < 0) { 5617c478bd9Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 5627c478bd9Sstevel@tonic-gate if (ifsock < 0) { 5637c478bd9Sstevel@tonic-gate logperror("initifs: socket"); 5647c478bd9Sstevel@tonic-gate return; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate lifn.lifn_family = AF_INET6; 5687c478bd9Sstevel@tonic-gate lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 5697c478bd9Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFNUM, (char *)&lifn) < 0) { 5707c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get interface numbers)"); 5717c478bd9Sstevel@tonic-gate return; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate numifs = lifn.lifn_count; 5747c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct lifreq); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate buf = (char *)malloc(bufsize); 5777c478bd9Sstevel@tonic-gate if (buf == NULL) { 5787c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "initifs: out of memory\n"); 5797c478bd9Sstevel@tonic-gate return; 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 5847c478bd9Sstevel@tonic-gate * which have disappeared from the kernel. 5857c478bd9Sstevel@tonic-gate * if_process will set pr_in_use when it finds the interface 5867c478bd9Sstevel@tonic-gate * in the kernel. 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * Before re-examining the state of the interfaces, 5917c478bd9Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 5947c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 5957c478bd9Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate lifc.lifc_family = AF_INET6; 6007c478bd9Sstevel@tonic-gate lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY; 6017c478bd9Sstevel@tonic-gate lifc.lifc_len = bufsize; 6027c478bd9Sstevel@tonic-gate lifc.lifc_buf = buf; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (ioctl(ifsock, SIOCGLIFCONF, (char *)&lifc) < 0) { 6057c478bd9Sstevel@tonic-gate logperror("initifs: ioctl (get interface configuration)"); 6067c478bd9Sstevel@tonic-gate free(buf); 6077c478bd9Sstevel@tonic-gate return; 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate lifr = (struct lifreq *)lifc.lifc_req; 6117c478bd9Sstevel@tonic-gate for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifr++) 6127c478bd9Sstevel@tonic-gate if_process(ifsock, lifr->lifr_name, first); 6137c478bd9Sstevel@tonic-gate free(buf); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate /* 6167c478bd9Sstevel@tonic-gate * Detect phyints that have been removed from the kernel. 6177c478bd9Sstevel@tonic-gate * Since we can't recreate it here (would require ifconfig plumb 6187c478bd9Sstevel@tonic-gate * logic) we just terminate use of that phyint. 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 6217c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 6227c478bd9Sstevel@tonic-gate /* 6237c478bd9Sstevel@tonic-gate * If interface (still) exists in kernel, set 6247c478bd9Sstevel@tonic-gate * pi_state to indicate that. 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 6277c478bd9Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate check_if_removed(pi); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate if (show_ifs) 6337c478bd9Sstevel@tonic-gate phyint_print_all(); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * Router advertisement state machine. Used for everything but timer 6397c478bd9Sstevel@tonic-gate * events which use advertise_event directly. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate void 6427c478bd9Sstevel@tonic-gate check_to_advertise(struct phyint *pi, enum adv_events event) 6437c478bd9Sstevel@tonic-gate { 6447c478bd9Sstevel@tonic-gate uint_t delay; 6457c478bd9Sstevel@tonic-gate enum adv_states old_state = pi->pi_adv_state; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 6487c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d\n", 6497c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate delay = advertise_event(pi, event, 0); 6527c478bd9Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 6537c478bd9Sstevel@tonic-gate /* Make sure the global next event is updated */ 6547c478bd9Sstevel@tonic-gate timer_schedule(delay); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 6587c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d -> %d\n", 6597c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 6607c478bd9Sstevel@tonic-gate (int)pi->pi_adv_state); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * Router advertisement state machine. 6667c478bd9Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 6677c478bd9Sstevel@tonic-gate * if never). 6687c478bd9Sstevel@tonic-gate * For the ADV_TIMER event the caller passes in the number of milliseconds 6697c478bd9Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate uint_t 6727c478bd9Sstevel@tonic-gate advertise_event(struct phyint *pi, enum adv_events event, uint_t elapsed) 6737c478bd9Sstevel@tonic-gate { 6747c478bd9Sstevel@tonic-gate uint_t delay; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 6777c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "advertise_event(%s, %d, %d) state %d\n", 6787c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_adv_state); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate check_daemonize(); 6817c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 6827c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 6837c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 6847c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 6857c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RA packet on %s " 6867c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 6877c478bd9Sstevel@tonic-gate pi->pi_name); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate switch (event) { 6937c478bd9Sstevel@tonic-gate case ADV_OFF: 6947c478bd9Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 6957c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate case START_INIT_ADV: 6987c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == INIT_ADV) 6997c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7007c478bd9Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_INITIAL_RTR_ADVERTISEMENTS; 7017c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7027c478bd9Sstevel@tonic-gate pi->pi_adv_state = INIT_ADV; 7037c478bd9Sstevel@tonic-gate break; /* send advertisement */ 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate case START_FINAL_ADV: 7067c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7077c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7087c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) 7097c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7107c478bd9Sstevel@tonic-gate pi->pi_adv_count = ND_MAX_FINAL_RTR_ADVERTISEMENTS; 7117c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7127c478bd9Sstevel@tonic-gate pi->pi_adv_state = FINAL_ADV; 7137c478bd9Sstevel@tonic-gate break; /* send advertisement */ 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate case RECEIVED_SOLICIT: 7167c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7177c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7187c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == SOLICIT_ADV) { 7197c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 7207c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7217c478bd9Sstevel@tonic-gate break; 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate delay = GET_RANDOM(0, ND_MAX_RA_DELAY_TIME); 7247c478bd9Sstevel@tonic-gate if (delay < pi->pi_adv_time_left) 7257c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = delay; 7267c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_since_sent < ND_MIN_DELAY_BETWEEN_RAS) { 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * Send an advertisement (ND_MIN_DELAY_BETWEEN_RAS 7297c478bd9Sstevel@tonic-gate * plus random delay) after the previous 7307c478bd9Sstevel@tonic-gate * advertisement was sent. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = delay + 7337c478bd9Sstevel@tonic-gate ND_MIN_DELAY_BETWEEN_RAS - 7347c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent; 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate pi->pi_adv_state = SOLICIT_ADV; 7377c478bd9Sstevel@tonic-gate break; 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate case ADV_TIMER: 7407c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == NO_ADV) 7417c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7427c478bd9Sstevel@tonic-gate /* Decrease time left */ 7437c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_left >= elapsed) 7447c478bd9Sstevel@tonic-gate pi->pi_adv_time_left -= elapsed; 7457c478bd9Sstevel@tonic-gate else 7467c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 0; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate /* Increase time since last advertisement was sent */ 7497c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent += elapsed; 7507c478bd9Sstevel@tonic-gate break; 7517c478bd9Sstevel@tonic-gate default: 7527c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "advertise_event: Unknown event %d\n", 7537c478bd9Sstevel@tonic-gate (int)event); 7547c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (pi->pi_adv_time_left != 0) 7587c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* Send advertisement and calculate next time to send */ 7617c478bd9Sstevel@tonic-gate if (pi->pi_adv_state == FINAL_ADV) { 7627c478bd9Sstevel@tonic-gate /* Omit the prefixes */ 7637c478bd9Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_TRUE); 7647c478bd9Sstevel@tonic-gate } else { 7657c478bd9Sstevel@tonic-gate advertise(&v6allnodes, pi, _B_FALSE); 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent = 0; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate switch (pi->pi_adv_state) { 7707c478bd9Sstevel@tonic-gate case SOLICIT_ADV: 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * The solicited advertisement has been sent. 7737c478bd9Sstevel@tonic-gate * Revert to periodic advertisements. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 7767c478bd9Sstevel@tonic-gate /* FALLTHRU */ 7777c478bd9Sstevel@tonic-gate case REG_ADV: 7787c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 7797c478bd9Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 7807c478bd9Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 7817c478bd9Sstevel@tonic-gate break; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate case INIT_ADV: 7847c478bd9Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 7857c478bd9Sstevel@tonic-gate delay = GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 7867c478bd9Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 7877c478bd9Sstevel@tonic-gate if (delay > ND_MAX_INITIAL_RTR_ADVERT_INTERVAL) 7887c478bd9Sstevel@tonic-gate delay = ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 7897c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = delay; 7907c478bd9Sstevel@tonic-gate } else { 7917c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 7927c478bd9Sstevel@tonic-gate GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval, 7937c478bd9Sstevel@tonic-gate 1000 * pi->pi_MaxRtrAdvInterval); 7947c478bd9Sstevel@tonic-gate pi->pi_adv_state = REG_ADV; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate break; 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate case FINAL_ADV: 7997c478bd9Sstevel@tonic-gate if (--pi->pi_adv_count > 0) { 8007c478bd9Sstevel@tonic-gate pi->pi_adv_time_left = 8017c478bd9Sstevel@tonic-gate ND_MAX_INITIAL_RTR_ADVERT_INTERVAL; 8027c478bd9Sstevel@tonic-gate } else { 8037c478bd9Sstevel@tonic-gate pi->pi_adv_state = NO_ADV; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate break; 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) 8087c478bd9Sstevel@tonic-gate return (pi->pi_adv_time_left); 8097c478bd9Sstevel@tonic-gate else 8107c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Router solicitation state machine. Used for everything but timer 8157c478bd9Sstevel@tonic-gate * events which use solicit_event directly. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate void 8187c478bd9Sstevel@tonic-gate check_to_solicit(struct phyint *pi, enum solicit_events event) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate uint_t delay; 8217c478bd9Sstevel@tonic-gate enum solicit_states old_state = pi->pi_sol_state; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 8247c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d\n", 8257c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state); 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate delay = solicit_event(pi, event, 0); 8287c478bd9Sstevel@tonic-gate if (delay != TIMER_INFINITY) { 8297c478bd9Sstevel@tonic-gate /* Make sure the global next event is updated */ 8307c478bd9Sstevel@tonic-gate timer_schedule(delay); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 8347c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d -> %d\n", 8357c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, (int)old_state, 8367c478bd9Sstevel@tonic-gate (int)pi->pi_sol_state); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate static void 8417c478bd9Sstevel@tonic-gate daemonize_ndpd(void) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate FILE *pidfp; 8447c478bd9Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 8457c478bd9Sstevel@tonic-gate struct itimerval it; 8467c478bd9Sstevel@tonic-gate boolean_t timerval = _B_TRUE; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* 8497c478bd9Sstevel@tonic-gate * Need to get current timer settings so they can be restored 8507c478bd9Sstevel@tonic-gate * after the fork(), as the it_value and it_interval values for 8517c478bd9Sstevel@tonic-gate * the ITIMER_REAL timer are reset to 0 in the child process. 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate if (getitimer(ITIMER_REAL, &it) < 0) { 8547c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 8557c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 8567c478bd9Sstevel@tonic-gate "daemonize_ndpd: failed to get itimerval\n"); 8577c478bd9Sstevel@tonic-gate timerval = _B_FALSE; 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate /* Daemonize. */ 8617c478bd9Sstevel@tonic-gate switch (fork()) { 8627c478bd9Sstevel@tonic-gate case 0: 8637c478bd9Sstevel@tonic-gate /* Child */ 8647c478bd9Sstevel@tonic-gate break; 8657c478bd9Sstevel@tonic-gate case -1: 8667c478bd9Sstevel@tonic-gate logperror("fork"); 8677c478bd9Sstevel@tonic-gate exit(1); 8687c478bd9Sstevel@tonic-gate default: 8697c478bd9Sstevel@tonic-gate /* Parent */ 8707c478bd9Sstevel@tonic-gate _exit(0); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 8747c478bd9Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 8757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n", 8767c478bd9Sstevel@tonic-gate argv0[0], strerror(errno)); 8777c478bd9Sstevel@tonic-gate } else { 8787c478bd9Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 8797c478bd9Sstevel@tonic-gate (void) fclose(pidfp); 8807c478bd9Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate (void) close(0); 8847c478bd9Sstevel@tonic-gate (void) close(1); 8857c478bd9Sstevel@tonic-gate (void) close(2); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate (void) chdir("/"); 8887c478bd9Sstevel@tonic-gate (void) open("/dev/null", O_RDWR); 8897c478bd9Sstevel@tonic-gate (void) dup2(0, 1); 8907c478bd9Sstevel@tonic-gate (void) dup2(0, 2); 8917c478bd9Sstevel@tonic-gate (void) setsid(); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate already_daemonized = _B_TRUE; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate /* 8967c478bd9Sstevel@tonic-gate * Restore timer values, if we were able to save them; if not, 8977c478bd9Sstevel@tonic-gate * check and set the right value by calling run_timeouts(). 8987c478bd9Sstevel@tonic-gate */ 8997c478bd9Sstevel@tonic-gate if (timerval) { 9007c478bd9Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 9017c478bd9Sstevel@tonic-gate logperror("daemonize_ndpd: setitimer"); 9027c478bd9Sstevel@tonic-gate exit(2); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate } else { 9057c478bd9Sstevel@tonic-gate run_timeouts(); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * Check to see if the time is right to daemonize. The right time is when: 9117c478bd9Sstevel@tonic-gate * 9127c478bd9Sstevel@tonic-gate * 1. We haven't already daemonized. 9137c478bd9Sstevel@tonic-gate * 2. We are not in debug mode. 9147c478bd9Sstevel@tonic-gate * 3. All interfaces are marked IFF_NOXMIT. 9157c478bd9Sstevel@tonic-gate * 4. All non-router interfaces have their prefixes set up and we're 9167c478bd9Sstevel@tonic-gate * done sending router solicitations on those interfaces without 9177c478bd9Sstevel@tonic-gate * prefixes. 9187c478bd9Sstevel@tonic-gate */ 9197c478bd9Sstevel@tonic-gate static void 9207c478bd9Sstevel@tonic-gate check_daemonize(void) 9217c478bd9Sstevel@tonic-gate { 9227c478bd9Sstevel@tonic-gate struct phyint *pi; 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate if (already_daemonized || debug != 0) 9257c478bd9Sstevel@tonic-gate return; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 9287c478bd9Sstevel@tonic-gate if (!(pi->pi_flags & IFF_NOXMIT)) 9297c478bd9Sstevel@tonic-gate break; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * If we can't transmit on any of the interfaces there is no reason 9347c478bd9Sstevel@tonic-gate * to hold up progress. 9357c478bd9Sstevel@tonic-gate */ 9367c478bd9Sstevel@tonic-gate if (pi == NULL) { 9377c478bd9Sstevel@tonic-gate daemonize_ndpd(); 9387c478bd9Sstevel@tonic-gate return; 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* Check all interfaces. If any are still soliciting, just return. */ 9427c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 9437c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements || 9447c478bd9Sstevel@tonic-gate !(pi->pi_kernel_state & PI_PRESENT)) 9457c478bd9Sstevel@tonic-gate continue; 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 9487c478bd9Sstevel@tonic-gate return; 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate daemonize_ndpd(); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Router solicitation state machine. 9567c478bd9Sstevel@tonic-gate * Return the number of milliseconds until next timeout (TIMER_INFINITY 9577c478bd9Sstevel@tonic-gate * if never). 9587c478bd9Sstevel@tonic-gate * For the SOL_TIMER event the caller passes in the number of milliseconds 9597c478bd9Sstevel@tonic-gate * since the last timer event in the 'elapsed' parameter. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate uint_t 9627c478bd9Sstevel@tonic-gate solicit_event(struct phyint *pi, enum solicit_events event, uint_t elapsed) 9637c478bd9Sstevel@tonic-gate { 9647c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 9657c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "solicit_event(%s, %d, %d) state %d\n", 9667c478bd9Sstevel@tonic-gate pi->pi_name, (int)event, elapsed, (int)pi->pi_sol_state); 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 9707c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 9717c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 9727c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) { 9737c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Suppress sending RS packet on %s " 9747c478bd9Sstevel@tonic-gate "(no route exchange on interface)\n", 9757c478bd9Sstevel@tonic-gate pi->pi_name); 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate switch (event) { 9817c478bd9Sstevel@tonic-gate case SOLICIT_OFF: 9827c478bd9Sstevel@tonic-gate pi->pi_sol_state = NO_SOLICIT; 9837c478bd9Sstevel@tonic-gate check_daemonize(); 9847c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate case SOLICIT_DONE: 9877c478bd9Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 9887c478bd9Sstevel@tonic-gate check_daemonize(); 9897c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate case START_INIT_SOLICIT: 9927c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == INIT_SOLICIT) 9937c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 9947c478bd9Sstevel@tonic-gate pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS; 9957c478bd9Sstevel@tonic-gate pi->pi_sol_time_left = 9967c478bd9Sstevel@tonic-gate GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY); 9977c478bd9Sstevel@tonic-gate pi->pi_sol_state = INIT_SOLICIT; 9987c478bd9Sstevel@tonic-gate break; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate case SOL_TIMER: 10017c478bd9Sstevel@tonic-gate if (pi->pi_sol_state == NO_SOLICIT) 10027c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10037c478bd9Sstevel@tonic-gate /* Decrease time left */ 10047c478bd9Sstevel@tonic-gate if (pi->pi_sol_time_left >= elapsed) 10057c478bd9Sstevel@tonic-gate pi->pi_sol_time_left -= elapsed; 10067c478bd9Sstevel@tonic-gate else 10077c478bd9Sstevel@tonic-gate pi->pi_sol_time_left = 0; 10087c478bd9Sstevel@tonic-gate break; 10097c478bd9Sstevel@tonic-gate default: 10107c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "solicit_event: Unknown event %d\n", 10117c478bd9Sstevel@tonic-gate (int)event); 10127c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate if (pi->pi_sol_time_left != 0) 10167c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* Send solicitation and calculate next time */ 10197c478bd9Sstevel@tonic-gate switch (pi->pi_sol_state) { 10207c478bd9Sstevel@tonic-gate case INIT_SOLICIT: 10217c478bd9Sstevel@tonic-gate solicit(&v6allrouters, pi); 10227c478bd9Sstevel@tonic-gate if (--pi->pi_sol_count == 0) { 10237c478bd9Sstevel@tonic-gate pi->pi_sol_state = DONE_SOLICIT; 10247c478bd9Sstevel@tonic-gate check_daemonize(); 10257c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate pi->pi_sol_time_left = ND_RTR_SOLICITATION_INTERVAL; 10287c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 10297c478bd9Sstevel@tonic-gate case NO_SOLICIT: 10307c478bd9Sstevel@tonic-gate case DONE_SOLICIT: 10317c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 10327c478bd9Sstevel@tonic-gate default: 10337c478bd9Sstevel@tonic-gate return (pi->pi_sol_time_left); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * Timer mechanism using relative time (in milliseconds) from the 10397c478bd9Sstevel@tonic-gate * previous timer event. Timers exceeding TIMER_INFINITY milliseconds 10407c478bd9Sstevel@tonic-gate * will fire after TIMER_INFINITY milliseconds. 10417c478bd9Sstevel@tonic-gate */ 10427c478bd9Sstevel@tonic-gate static uint_t timer_previous; /* When last SIGALRM occurred */ 10437c478bd9Sstevel@tonic-gate static uint_t timer_next; /* Currently scheduled timeout */ 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate static void 10467c478bd9Sstevel@tonic-gate timer_init(void) 10477c478bd9Sstevel@tonic-gate { 10487c478bd9Sstevel@tonic-gate timer_previous = getcurrenttime(); 10497c478bd9Sstevel@tonic-gate timer_next = TIMER_INFINITY; 10507c478bd9Sstevel@tonic-gate run_timeouts(); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate /* 10547c478bd9Sstevel@tonic-gate * Make sure the next SIGALRM occurs delay milliseconds from the current 10557c478bd9Sstevel@tonic-gate * time if not earlier. 10567c478bd9Sstevel@tonic-gate * Handles getcurrenttime (32 bit integer holding milliseconds) wraparound 10577c478bd9Sstevel@tonic-gate * by treating differences greater than 0x80000000 as negative. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate void 10607c478bd9Sstevel@tonic-gate timer_schedule(uint_t delay) 10617c478bd9Sstevel@tonic-gate { 10627c478bd9Sstevel@tonic-gate uint_t now; 10637c478bd9Sstevel@tonic-gate struct itimerval itimerval; 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate now = getcurrenttime(); 10667c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 10677c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): now %u next %u\n", 10687c478bd9Sstevel@tonic-gate delay, now, timer_next); 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate /* Will this timer occur before the currently scheduled SIGALRM? */ 10717c478bd9Sstevel@tonic-gate if (delay >= timer_next - now) { 10727c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 10737c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): no action - " 10747c478bd9Sstevel@tonic-gate "next in %u ms\n", 10757c478bd9Sstevel@tonic-gate delay, timer_next - now); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate return; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate if (delay == 0) { 10807c478bd9Sstevel@tonic-gate /* Minimum allowed delay */ 10817c478bd9Sstevel@tonic-gate delay = 1; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate timer_next = now + delay; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate itimerval.it_value.tv_sec = delay / 1000; 10867c478bd9Sstevel@tonic-gate itimerval.it_value.tv_usec = (delay % 1000) * 1000; 10877c478bd9Sstevel@tonic-gate itimerval.it_interval.tv_sec = 0; 10887c478bd9Sstevel@tonic-gate itimerval.it_interval.tv_usec = 0; 10897c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 10907c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "timer_schedule(%u): sec %lu usec %lu\n", 10917c478bd9Sstevel@tonic-gate delay, 10927c478bd9Sstevel@tonic-gate itimerval.it_value.tv_sec, itimerval.it_value.tv_usec); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) { 10957c478bd9Sstevel@tonic-gate logperror("timer_schedule: setitimer"); 10967c478bd9Sstevel@tonic-gate exit(2); 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate /* 11017c478bd9Sstevel@tonic-gate * Conditional running of timer. If more than 'minimal_time' millseconds 11027c478bd9Sstevel@tonic-gate * since the timer routines were last run we run them. 11037c478bd9Sstevel@tonic-gate * Used when packets arrive. 11047c478bd9Sstevel@tonic-gate */ 11057c478bd9Sstevel@tonic-gate static void 11067c478bd9Sstevel@tonic-gate conditional_run_timeouts(uint_t minimal_time) 11077c478bd9Sstevel@tonic-gate { 11087c478bd9Sstevel@tonic-gate uint_t now; 11097c478bd9Sstevel@tonic-gate uint_t elapsed; 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate now = getcurrenttime(); 11127c478bd9Sstevel@tonic-gate elapsed = now - timer_previous; 11137c478bd9Sstevel@tonic-gate if (elapsed > minimal_time) { 11147c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11157c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "conditional_run_timeouts: " 11167c478bd9Sstevel@tonic-gate "elapsed %d\n", elapsed); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate run_timeouts(); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate /* 11237c478bd9Sstevel@tonic-gate * Timer has fired. 11247c478bd9Sstevel@tonic-gate * Determine when the next timer event will occur by asking all 11257c478bd9Sstevel@tonic-gate * the timer routines. 11267c478bd9Sstevel@tonic-gate * Should not be called from a timer routine but in some cases this is 11277c478bd9Sstevel@tonic-gate * done because the code doesn't know that e.g. it was called from 11287c478bd9Sstevel@tonic-gate * ifconfig_timer(). In this case the nested run_timeouts will just return but 11297c478bd9Sstevel@tonic-gate * the running run_timeouts will ensure to call all the timer functions by 11307c478bd9Sstevel@tonic-gate * looping once more. 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate static void 11337c478bd9Sstevel@tonic-gate run_timeouts(void) 11347c478bd9Sstevel@tonic-gate { 11357c478bd9Sstevel@tonic-gate uint_t now; 11367c478bd9Sstevel@tonic-gate uint_t elapsed; 11377c478bd9Sstevel@tonic-gate uint_t next; 11387c478bd9Sstevel@tonic-gate uint_t nexti; 11397c478bd9Sstevel@tonic-gate struct phyint *pi; 11407c478bd9Sstevel@tonic-gate struct phyint *next_pi; 11417c478bd9Sstevel@tonic-gate struct prefix *pr; 11427c478bd9Sstevel@tonic-gate struct prefix *next_pr; 11437c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 11447c478bd9Sstevel@tonic-gate struct adv_prefix *next_adv_pr; 11457c478bd9Sstevel@tonic-gate struct router *dr; 11467c478bd9Sstevel@tonic-gate struct router *next_dr; 11477c478bd9Sstevel@tonic-gate static boolean_t timeout_running; 11487c478bd9Sstevel@tonic-gate static boolean_t do_retry; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate if (timeout_running) { 11517c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 11527c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: nested call\n"); 11537c478bd9Sstevel@tonic-gate do_retry = _B_TRUE; 11547c478bd9Sstevel@tonic-gate return; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate timeout_running = _B_TRUE; 11577c478bd9Sstevel@tonic-gate retry: 11587c478bd9Sstevel@tonic-gate /* How much time since the last time we were called? */ 11597c478bd9Sstevel@tonic-gate now = getcurrenttime(); 11607c478bd9Sstevel@tonic-gate elapsed = now - timer_previous; 11617c478bd9Sstevel@tonic-gate timer_previous = now; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 11647c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: elapsed %d\n", elapsed); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate next = TIMER_INFINITY; 11677c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 11687c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 11697c478bd9Sstevel@tonic-gate nexti = phyint_timer(pi, elapsed); 11707c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 11717c478bd9Sstevel@tonic-gate next = nexti; 11727c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11737c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pi %s): %d -> %u ms\n", 11747c478bd9Sstevel@tonic-gate pi->pi_name, nexti, next); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 11777c478bd9Sstevel@tonic-gate next_pr = pr->pr_next; 11787c478bd9Sstevel@tonic-gate nexti = prefix_timer(pr, elapsed); 11797c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 11807c478bd9Sstevel@tonic-gate next = nexti; 11817c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11827c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (pr %s): " 11837c478bd9Sstevel@tonic-gate "%d -> %u ms\n", pr->pr_name, nexti, next); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 11877c478bd9Sstevel@tonic-gate adv_pr = next_adv_pr) { 11887c478bd9Sstevel@tonic-gate next_adv_pr = adv_pr->adv_pr_next; 11897c478bd9Sstevel@tonic-gate nexti = adv_prefix_timer(adv_pr, elapsed); 11907c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 11917c478bd9Sstevel@tonic-gate next = nexti; 11927c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11937c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts " 11947c478bd9Sstevel@tonic-gate "(adv pr on %s): %d -> %u ms\n", 11957c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 11967c478bd9Sstevel@tonic-gate nexti, next); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) { 12007c478bd9Sstevel@tonic-gate next_dr = dr->dr_next; 12017c478bd9Sstevel@tonic-gate nexti = router_timer(dr, elapsed); 12027c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12037c478bd9Sstevel@tonic-gate next = nexti; 12047c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12057c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (dr): " 12067c478bd9Sstevel@tonic-gate "%d -> %u ms\n", nexti, next); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 12107c478bd9Sstevel@tonic-gate nexti = tmptoken_timer(pi, elapsed); 12117c478bd9Sstevel@tonic-gate if (nexti != TIMER_INFINITY && nexti < next) 12127c478bd9Sstevel@tonic-gate next = nexti; 12137c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12147c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts (tmp on %s): " 12157c478bd9Sstevel@tonic-gate "%d -> %u ms\n", pi->pi_name, nexti, next); 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * Make sure the timer functions are run at least once 12217c478bd9Sstevel@tonic-gate * an hour. 12227c478bd9Sstevel@tonic-gate */ 12237c478bd9Sstevel@tonic-gate if (next == TIMER_INFINITY) 12247c478bd9Sstevel@tonic-gate next = 3600 * 1000; /* 1 hour */ 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 12277c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: %u ms\n", next); 12287c478bd9Sstevel@tonic-gate timer_schedule(next); 12297c478bd9Sstevel@tonic-gate if (do_retry) { 12307c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 12317c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "run_timeouts: retry\n"); 12327c478bd9Sstevel@tonic-gate do_retry = _B_FALSE; 12337c478bd9Sstevel@tonic-gate goto retry; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate timeout_running = _B_FALSE; 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate static int eventpipe_read = -1; /* Used for synchronous signal delivery */ 12397c478bd9Sstevel@tonic-gate static int eventpipe_write = -1; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* 12427c478bd9Sstevel@tonic-gate * Ensure that signals are processed synchronously with the rest of 12437c478bd9Sstevel@tonic-gate * the code by just writing a one character signal number on the pipe. 12447c478bd9Sstevel@tonic-gate * The poll loop will pick this up and process the signal event. 12457c478bd9Sstevel@tonic-gate */ 12467c478bd9Sstevel@tonic-gate static void 12477c478bd9Sstevel@tonic-gate sig_handler(int signo) 12487c478bd9Sstevel@tonic-gate { 12497c478bd9Sstevel@tonic-gate uchar_t buf = (uchar_t)signo; 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate if (eventpipe_write == -1) { 12527c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "sig_handler: no pipe\n"); 12537c478bd9Sstevel@tonic-gate return; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate if (write(eventpipe_write, &buf, sizeof (buf)) < 0) 12567c478bd9Sstevel@tonic-gate logperror("sig_handler: write"); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * Pick up a signal "byte" from the pipe and process it. 12617c478bd9Sstevel@tonic-gate */ 12627c478bd9Sstevel@tonic-gate static void 12637c478bd9Sstevel@tonic-gate in_signal(int fd) 12647c478bd9Sstevel@tonic-gate { 12657c478bd9Sstevel@tonic-gate uchar_t buf; 12667c478bd9Sstevel@tonic-gate struct phyint *pi; 12677c478bd9Sstevel@tonic-gate struct phyint *next_pi; 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate switch (read(fd, &buf, sizeof (buf))) { 12707c478bd9Sstevel@tonic-gate case -1: 12717c478bd9Sstevel@tonic-gate logperror("in_signal: read"); 12727c478bd9Sstevel@tonic-gate exit(1); 12737c478bd9Sstevel@tonic-gate /* NOTREACHED */ 12747c478bd9Sstevel@tonic-gate case 1: 12757c478bd9Sstevel@tonic-gate break; 12767c478bd9Sstevel@tonic-gate case 0: 12777c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read eof\n"); 12787c478bd9Sstevel@tonic-gate exit(1); 12797c478bd9Sstevel@tonic-gate /* NOTREACHED */ 12807c478bd9Sstevel@tonic-gate default: 12817c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: read > 1\n"); 12827c478bd9Sstevel@tonic-gate exit(1); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 12867c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal() got %d\n", buf); 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate switch (buf) { 12897c478bd9Sstevel@tonic-gate case SIGALRM: 12907c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 12917c478bd9Sstevel@tonic-gate uint_t now = getcurrenttime(); 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "in_signal(SIGALRM) delta %u\n", 12947c478bd9Sstevel@tonic-gate now - timer_next); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate timer_next = TIMER_INFINITY; 12977c478bd9Sstevel@tonic-gate run_timeouts(); 12987c478bd9Sstevel@tonic-gate break; 12997c478bd9Sstevel@tonic-gate case SIGHUP: 13007c478bd9Sstevel@tonic-gate /* Re-read config file by exec'ing ourselves */ 13017c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 13027c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 13037c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 13047c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate phyint_delete(pi); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * Prevent fd leaks. Everything gets re-opened at start-up 13117c478bd9Sstevel@tonic-gate * time. 0, 1, and 2 are closed and re-opened as 13127c478bd9Sstevel@tonic-gate * /dev/null, so we'll leave those open. 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate closefrom(3); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "SIGHUP: restart and reread config file\n"); 13177c478bd9Sstevel@tonic-gate (void) execv(argv0[0], argv0); 13187c478bd9Sstevel@tonic-gate (void) unlink(PATH_PID); 13197c478bd9Sstevel@tonic-gate _exit(0177); 13207c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13217c478bd9Sstevel@tonic-gate case SIGUSR1: 13227c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Printing configuration:\n"); 13237c478bd9Sstevel@tonic-gate phyint_print_all(); 13247c478bd9Sstevel@tonic-gate break; 13257c478bd9Sstevel@tonic-gate case SIGINT: 13267c478bd9Sstevel@tonic-gate case SIGTERM: 13277c478bd9Sstevel@tonic-gate case SIGQUIT: 13287c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = next_pi) { 13297c478bd9Sstevel@tonic-gate next_pi = pi->pi_next; 13307c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 13317c478bd9Sstevel@tonic-gate check_to_advertise(pi, START_FINAL_ADV); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate phyint_delete(pi); 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate (void) unlink(PATH_PID); 13367c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "terminated\n"); 13377c478bd9Sstevel@tonic-gate exit(0); 13387c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13397c478bd9Sstevel@tonic-gate case 255: 13407c478bd9Sstevel@tonic-gate /* 13417c478bd9Sstevel@tonic-gate * Special "signal" from looback_ra_enqueue. 13427c478bd9Sstevel@tonic-gate * Handle any queued loopback router advertisements. 13437c478bd9Sstevel@tonic-gate */ 13447c478bd9Sstevel@tonic-gate loopback_ra_dequeue(); 13457c478bd9Sstevel@tonic-gate break; 13467c478bd9Sstevel@tonic-gate default: 13477c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "in_signal: unknown signal: %d\n", buf); 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* 13527c478bd9Sstevel@tonic-gate * Create pipe for signal delivery and set up signal handlers. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate static void 13557c478bd9Sstevel@tonic-gate setup_eventpipe(void) 13567c478bd9Sstevel@tonic-gate { 13577c478bd9Sstevel@tonic-gate int fds[2]; 13587c478bd9Sstevel@tonic-gate struct sigaction act; 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate if ((pipe(fds)) < 0) { 13617c478bd9Sstevel@tonic-gate logperror("setup_eventpipe: pipe"); 13627c478bd9Sstevel@tonic-gate exit(1); 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate eventpipe_read = fds[0]; 13657c478bd9Sstevel@tonic-gate eventpipe_write = fds[1]; 13667c478bd9Sstevel@tonic-gate if (poll_add(eventpipe_read) == -1) { 13677c478bd9Sstevel@tonic-gate exit(1); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate act.sa_handler = sig_handler; 13707c478bd9Sstevel@tonic-gate act.sa_flags = SA_RESTART; 13717c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, sig_handler); 13747c478bd9Sstevel@tonic-gate (void) sigset(SIGUSR1, sig_handler); 13757c478bd9Sstevel@tonic-gate (void) sigset(SIGTERM, sig_handler); 13767c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, sig_handler); 13777c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, sig_handler); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* 13817c478bd9Sstevel@tonic-gate * Create a routing socket for receiving RTM_IFINFO messages and initialize 13827c478bd9Sstevel@tonic-gate * the routing socket message header and as much of the sockaddrs as possible. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate static int 13857c478bd9Sstevel@tonic-gate setup_rtsock(void) 13867c478bd9Sstevel@tonic-gate { 13877c478bd9Sstevel@tonic-gate int s; 13887c478bd9Sstevel@tonic-gate int ret; 13897c478bd9Sstevel@tonic-gate char *cp; 13907c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, AF_INET6); 13937c478bd9Sstevel@tonic-gate if (s == -1) { 13947c478bd9Sstevel@tonic-gate logperror("socket(PF_ROUTE)"); 13957c478bd9Sstevel@tonic-gate exit(1); 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate ret = fcntl(s, F_SETFL, O_NDELAY|O_NONBLOCK); 13987c478bd9Sstevel@tonic-gate if (ret < 0) { 13997c478bd9Sstevel@tonic-gate logperror("fcntl(O_NDELAY)"); 14007c478bd9Sstevel@tonic-gate exit(1); 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate if (poll_add(s) == -1) { 14037c478bd9Sstevel@tonic-gate exit(1); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate /* 14077c478bd9Sstevel@tonic-gate * Allocate storage for the routing socket message. 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate rt_msg = (struct rt_msghdr *)malloc(NDP_RTM_MSGLEN); 14107c478bd9Sstevel@tonic-gate if (rt_msg == NULL) { 14117c478bd9Sstevel@tonic-gate logperror("malloc"); 14127c478bd9Sstevel@tonic-gate exit(1); 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * Initialize the routing socket message by zero-filling it and then 14177c478bd9Sstevel@tonic-gate * setting the fields where are constant through the lifetime of the 14187c478bd9Sstevel@tonic-gate * process. 14197c478bd9Sstevel@tonic-gate */ 14207c478bd9Sstevel@tonic-gate bzero(rt_msg, NDP_RTM_MSGLEN); 14217c478bd9Sstevel@tonic-gate rt_msg->rtm_msglen = NDP_RTM_MSGLEN; 14227c478bd9Sstevel@tonic-gate rt_msg->rtm_version = RTM_VERSION; 14237c478bd9Sstevel@tonic-gate rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP; 14247c478bd9Sstevel@tonic-gate rt_msg->rtm_pid = getpid(); 14257c478bd9Sstevel@tonic-gate if (rt_msg->rtm_pid < 0) { 14267c478bd9Sstevel@tonic-gate logperror("getpid"); 14277c478bd9Sstevel@tonic-gate exit(1); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * The RTA_DST sockaddr does not change during the lifetime of the 14327c478bd9Sstevel@tonic-gate * process so it can be completely initialized at this time. 14337c478bd9Sstevel@tonic-gate */ 14347c478bd9Sstevel@tonic-gate cp = (char *)rt_msg + sizeof (struct rt_msghdr); 14357c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 14367c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 14377c478bd9Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_GATEWAY sockaddr. 14417c478bd9Sstevel@tonic-gate */ 14427c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 14437c478bd9Sstevel@tonic-gate rta_gateway = (struct sockaddr_in6 *)cp; 14447c478bd9Sstevel@tonic-gate rta_gateway->sin6_family = AF_INET6; 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * The RTA_NETMASK sockaddr does not change during the lifetime of the 14487c478bd9Sstevel@tonic-gate * process so it can be completely initialized at this time. 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 14517c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cp; 14527c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 14537c478bd9Sstevel@tonic-gate sin6->sin6_addr = in6addr_any; 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * Initialize the constant portion of the RTA_IFP sockaddr. 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate cp += sizeof (struct sockaddr_in6); 14597c478bd9Sstevel@tonic-gate rta_ifp = (struct sockaddr_dl *)cp; 14607c478bd9Sstevel@tonic-gate rta_ifp->sdl_family = AF_LINK; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate return (s); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* 14667c478bd9Sstevel@tonic-gate * Retrieve one routing socket message. If RTM_IFINFO indicates 14677c478bd9Sstevel@tonic-gate * new phyint do a full scan of the interfaces. If RTM_IFINFO 14687c478bd9Sstevel@tonic-gate * indicates an existing phyint only scan that phyint and asociated 14697c478bd9Sstevel@tonic-gate * prefixes. 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate static void 14727c478bd9Sstevel@tonic-gate process_rtsock(int rtsock) 14737c478bd9Sstevel@tonic-gate { 14747c478bd9Sstevel@tonic-gate int n; 14757c478bd9Sstevel@tonic-gate #define MSG_SIZE 2048/8 14767c478bd9Sstevel@tonic-gate int64_t msg[MSG_SIZE]; 14777c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 14787c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 14797c478bd9Sstevel@tonic-gate struct phyint *pi; 14807c478bd9Sstevel@tonic-gate struct prefix *pr; 14817c478bd9Sstevel@tonic-gate boolean_t need_initifs = _B_FALSE; 14827c478bd9Sstevel@tonic-gate boolean_t need_ifscan = _B_FALSE; 14837c478bd9Sstevel@tonic-gate int64_t ifscan_msg[10][MSG_SIZE]; 14847c478bd9Sstevel@tonic-gate int ifscan_index = 0; 14857c478bd9Sstevel@tonic-gate int i; 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate /* Empty the rtsock and coealesce all the work that we have */ 14887c478bd9Sstevel@tonic-gate while (ifscan_index < 10) { 14897c478bd9Sstevel@tonic-gate n = read(rtsock, msg, sizeof (msg)); 14907c478bd9Sstevel@tonic-gate if (n <= 0) { 14917c478bd9Sstevel@tonic-gate /* No more messages */ 14927c478bd9Sstevel@tonic-gate break; 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 14957c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 14967c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, 14977c478bd9Sstevel@tonic-gate "process_rtsock: version %d not understood\n", 14987c478bd9Sstevel@tonic-gate rtm->rtm_version); 14997c478bd9Sstevel@tonic-gate return; 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 15027c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 15037c478bd9Sstevel@tonic-gate case RTM_DELADDR: 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate * Some logical interface has changed - have to scan 15067c478bd9Sstevel@tonic-gate * everything to determine what actually changed. 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) { 15097c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: " 15107c478bd9Sstevel@tonic-gate "message %d\n", rtm->rtm_type); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate need_initifs = _B_TRUE; 15137c478bd9Sstevel@tonic-gate break; 15147c478bd9Sstevel@tonic-gate case RTM_IFINFO: 15157c478bd9Sstevel@tonic-gate need_ifscan = _B_TRUE; 15167c478bd9Sstevel@tonic-gate (void) memcpy(ifscan_msg[ifscan_index], rtm, 15177c478bd9Sstevel@tonic-gate sizeof (msg)); 15187c478bd9Sstevel@tonic-gate ifscan_index++; 15197c478bd9Sstevel@tonic-gate /* Handled below */ 15207c478bd9Sstevel@tonic-gate break; 15217c478bd9Sstevel@tonic-gate default: 15227c478bd9Sstevel@tonic-gate /* Not interesting */ 15237c478bd9Sstevel@tonic-gate break; 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * If we do full scan i.e initifs, we don't need to 15287c478bd9Sstevel@tonic-gate * scan a particular interface as we should have 15297c478bd9Sstevel@tonic-gate * done that as part of initifs. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate if (need_initifs) { 15327c478bd9Sstevel@tonic-gate initifs(_B_FALSE); 15337c478bd9Sstevel@tonic-gate return; 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate if (!need_ifscan) 15377c478bd9Sstevel@tonic-gate return; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate for (i = 0; i < ifscan_index; i++) { 15407c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)ifscan_msg[i]; 15417c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) 15427c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: index %d\n", 15437c478bd9Sstevel@tonic-gate ifm->ifm_index); 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate pi = phyint_lookup_on_index(ifm->ifm_index); 15467c478bd9Sstevel@tonic-gate if (pi == NULL) { 15477c478bd9Sstevel@tonic-gate /* 15487c478bd9Sstevel@tonic-gate * A new physical interface. Do a full scan of the 15497c478bd9Sstevel@tonic-gate * to catch any new logical interfaces. 15507c478bd9Sstevel@tonic-gate */ 15517c478bd9Sstevel@tonic-gate initifs(_B_FALSE); 15527c478bd9Sstevel@tonic-gate return; 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate if (ifm->ifm_flags != pi->pi_flags) { 15567c478bd9Sstevel@tonic-gate if (debug & D_IFSCAN) { 15577c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "process_rtsock: clr for " 15587c478bd9Sstevel@tonic-gate "%s old flags 0x%x new flags 0x%x\n", 15597c478bd9Sstevel@tonic-gate pi->pi_name, pi->pi_flags, ifm->ifm_flags); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and prefixes 15667c478bd9Sstevel@tonic-gate * which have disappeared from the kernel. 15677c478bd9Sstevel@tonic-gate * if_process will set pr_in_use when it finds the 15687c478bd9Sstevel@tonic-gate * interface in the kernel. 15697c478bd9Sstevel@tonic-gate * Before re-examining the state of the interfaces, 15707c478bd9Sstevel@tonic-gate * PI_PRESENT should be cleared from pi_kernel_state. 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 15737c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 15747c478bd9Sstevel@tonic-gate pr->pr_in_use = _B_FALSE; 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate if (ifsock < 0) { 15787c478bd9Sstevel@tonic-gate ifsock = socket(AF_INET6, SOCK_DGRAM, 0); 15797c478bd9Sstevel@tonic-gate if (ifsock < 0) { 15807c478bd9Sstevel@tonic-gate logperror("process_rtsock: socket"); 15817c478bd9Sstevel@tonic-gate return; 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate if_process(ifsock, pi->pi_name, _B_FALSE); 15857c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 15867c478bd9Sstevel@tonic-gate if_process(ifsock, pr->pr_name, _B_FALSE); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * If interface (still) exists in kernel, set 15907c478bd9Sstevel@tonic-gate * pi_state to indicate that. 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 15937c478bd9Sstevel@tonic-gate pi->pi_state |= PI_PRESENT; 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate check_if_removed(pi); 15967c478bd9Sstevel@tonic-gate if (show_ifs) 15977c478bd9Sstevel@tonic-gate phyint_print_all(); 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate /* 16027c478bd9Sstevel@tonic-gate * Check whether the address formed by pr->pr_prefix and pi_token 16037c478bd9Sstevel@tonic-gate * exists in the kernel. Cannot call SIOCTMYADDR/ONLINK as it 16047c478bd9Sstevel@tonic-gate * does not check for down addresses. This function should not 16057c478bd9Sstevel@tonic-gate * be called for onlink prefixes. 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate static boolean_t 16087c478bd9Sstevel@tonic-gate is_address_present(struct phyint *pi, struct prefix *pr, uint64_t flags) 16097c478bd9Sstevel@tonic-gate { 16107c478bd9Sstevel@tonic-gate int s; 16117c478bd9Sstevel@tonic-gate in6_addr_t addr, *token; 16127c478bd9Sstevel@tonic-gate int i; 16137c478bd9Sstevel@tonic-gate int ret; 16147c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate s = socket(AF_INET6, SOCK_DGRAM, 0); 16177c478bd9Sstevel@tonic-gate if (s < 0) { 16187c478bd9Sstevel@tonic-gate logperror("is_address_present: socket"); 16197c478bd9Sstevel@tonic-gate /* 16207c478bd9Sstevel@tonic-gate * By returning B_TRUE, we make the caller delete 16217c478bd9Sstevel@tonic-gate * the prefix from the internal table. In the worst 16227c478bd9Sstevel@tonic-gate * case the next RA will create the prefix. 16237c478bd9Sstevel@tonic-gate */ 16247c478bd9Sstevel@tonic-gate return (_B_TRUE); 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate if (flags & IFF_TEMPORARY) 16277c478bd9Sstevel@tonic-gate token = &pi->pi_tmp_token; 16287c478bd9Sstevel@tonic-gate else 16297c478bd9Sstevel@tonic-gate token = &pi->pi_token; 16307c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 16317c478bd9Sstevel@tonic-gate /* 16327c478bd9Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 16337c478bd9Sstevel@tonic-gate * bits after prefixlen. 16347c478bd9Sstevel@tonic-gate */ 16357c478bd9Sstevel@tonic-gate addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i]; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (struct sockaddr_in6)); 16387c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 16397c478bd9Sstevel@tonic-gate sin6.sin6_addr = addr; 16407c478bd9Sstevel@tonic-gate ret = bind(s, (struct sockaddr *)&sin6, sizeof (struct sockaddr_in6)); 16417c478bd9Sstevel@tonic-gate (void) close(s); 16427c478bd9Sstevel@tonic-gate if (ret < 0 && errno == EADDRNOTAVAIL) 16437c478bd9Sstevel@tonic-gate return (_B_FALSE); 16447c478bd9Sstevel@tonic-gate else 16457c478bd9Sstevel@tonic-gate return (_B_TRUE); 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate /* 16497c478bd9Sstevel@tonic-gate * Look if the phyint or one of its prefixes have been removed from 16507c478bd9Sstevel@tonic-gate * the kernel and take appropriate action. 16517c478bd9Sstevel@tonic-gate * Uses {pi,pr}_in_use. 16527c478bd9Sstevel@tonic-gate */ 16537c478bd9Sstevel@tonic-gate static void 16547c478bd9Sstevel@tonic-gate check_if_removed(struct phyint *pi) 16557c478bd9Sstevel@tonic-gate { 16567c478bd9Sstevel@tonic-gate struct prefix *pr; 16577c478bd9Sstevel@tonic-gate struct prefix *next_pr; 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate /* 16607c478bd9Sstevel@tonic-gate * Detect phyints that have been removed from the kernel. 16617c478bd9Sstevel@tonic-gate * Since we can't recreate it here (would require ifconfig plumb 16627c478bd9Sstevel@tonic-gate * logic) we just terminate use of that phyint. 16637c478bd9Sstevel@tonic-gate */ 16647c478bd9Sstevel@tonic-gate if (!(pi->pi_kernel_state & PI_PRESENT) && 16657c478bd9Sstevel@tonic-gate (pi->pi_state & PI_PRESENT)) { 16667c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "Interface %s has been removed from kernel. " 16677c478bd9Sstevel@tonic-gate "in.ndpd will no longer use it\n", pi->pi_name); 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * Clear state so that should the phyint reappear 16707c478bd9Sstevel@tonic-gate * we will start with initial advertisements or 16717c478bd9Sstevel@tonic-gate * solicitations. 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate phyint_cleanup(pi); 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate /* 16767c478bd9Sstevel@tonic-gate * Detect prefixes which are removed. 16777c478bd9Sstevel@tonic-gate * 16787c478bd9Sstevel@tonic-gate * We remove the prefix in all of the following cases : 16797c478bd9Sstevel@tonic-gate * 16807c478bd9Sstevel@tonic-gate * 1) Static prefixes are not the ones we create. So, 16817c478bd9Sstevel@tonic-gate * just remove it from our tables. 16827c478bd9Sstevel@tonic-gate * 16837c478bd9Sstevel@tonic-gate * 2) On-link prefixes potentially move to a different 16847c478bd9Sstevel@tonic-gate * phyint during failover. As it does not have 16857c478bd9Sstevel@tonic-gate * an address, we can't use the logic in is_address_present 16867c478bd9Sstevel@tonic-gate * to detect whether it is present in the kernel or not. 16877c478bd9Sstevel@tonic-gate * Thus when it is manually removed we don't recreate it. 16887c478bd9Sstevel@tonic-gate * 16897c478bd9Sstevel@tonic-gate * 3) If there is a token mis-match and this prefix is not 16907c478bd9Sstevel@tonic-gate * in the kernel, it means we don't need this prefix on 16917c478bd9Sstevel@tonic-gate * this interface anymore. It must have been moved to a 16927c478bd9Sstevel@tonic-gate * different interface by in.mpathd. This normally 16937c478bd9Sstevel@tonic-gate * happens after a failover followed by a failback (or 16947c478bd9Sstevel@tonic-gate * another failover) and we re-read the network 16957c478bd9Sstevel@tonic-gate * configuration. For the failover from A to B, we would 16967c478bd9Sstevel@tonic-gate * have created state on B about A's address, which will 16977c478bd9Sstevel@tonic-gate * not be in use after the subsequent failback. So, we 16987c478bd9Sstevel@tonic-gate * remove that prefix here. 16997c478bd9Sstevel@tonic-gate * 17007c478bd9Sstevel@tonic-gate * 4) If the physical interface is not present, then remove 17017c478bd9Sstevel@tonic-gate * the prefix. In the cases where we are advertising 17027c478bd9Sstevel@tonic-gate * prefixes, the state is kept in advertisement prefix and 17037c478bd9Sstevel@tonic-gate * hence we can delete the prefix. 17047c478bd9Sstevel@tonic-gate * 17057c478bd9Sstevel@tonic-gate * 5) Similar to case (3), when we failover from A to B, the 17067c478bd9Sstevel@tonic-gate * prefix in A will not be in use as it has been moved to B. 17077c478bd9Sstevel@tonic-gate * We will delete it from our tables and recreate it when 17087c478bd9Sstevel@tonic-gate * it fails back. is_address_present makes sure that the 17097c478bd9Sstevel@tonic-gate * address is still valid in kernel. 17107c478bd9Sstevel@tonic-gate * 17117c478bd9Sstevel@tonic-gate * If none of the above is true, we recreate the prefix as it 17127c478bd9Sstevel@tonic-gate * has been manually removed. We do it only when the interface 17137c478bd9Sstevel@tonic-gate * is not FAILED or INACTIVE or OFFLINE. 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) { 17167c478bd9Sstevel@tonic-gate next_pr = pr->pr_next; 17177c478bd9Sstevel@tonic-gate if (!pr->pr_in_use) { 17187c478bd9Sstevel@tonic-gate /* Clear PR_AUTO and PR_ONLINK */ 17197c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= PR_STATIC; 17207c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_STATIC) || 17217c478bd9Sstevel@tonic-gate !(pr->pr_state & PR_AUTO) || 17227c478bd9Sstevel@tonic-gate !(prefix_token_match(pi, pr, pr->pr_flags)) || 17237c478bd9Sstevel@tonic-gate (!(pi->pi_kernel_state & PI_PRESENT)) || 17247c478bd9Sstevel@tonic-gate (is_address_present(pi, pr, pr->pr_flags))) { 17257c478bd9Sstevel@tonic-gate prefix_delete(pr); 17267c478bd9Sstevel@tonic-gate } else if (!(pi->pi_flags & 17277c478bd9Sstevel@tonic-gate (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) && 17287c478bd9Sstevel@tonic-gate pr->pr_state != pr->pr_kernel_state) { 17297c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 17307c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Prefix manually removed " 17317c478bd9Sstevel@tonic-gate "on %s - recreating it!\n", 17327c478bd9Sstevel@tonic-gate pi->pi_name); 17337c478bd9Sstevel@tonic-gate prefix_update_k(pr); 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate /* 17417c478bd9Sstevel@tonic-gate * Queuing mechanism for router advertisements that are sent by in.ndpd 17427c478bd9Sstevel@tonic-gate * and that also need to be processed by in.ndpd. 17437c478bd9Sstevel@tonic-gate * Uses "signal number" 255 to indicate to the main poll loop 17447c478bd9Sstevel@tonic-gate * that there is something to dequeue and send to incomining_ra(). 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate struct raq { 17477c478bd9Sstevel@tonic-gate struct raq *raq_next; 17487c478bd9Sstevel@tonic-gate struct phyint *raq_pi; 17497c478bd9Sstevel@tonic-gate int raq_packetlen; 17507c478bd9Sstevel@tonic-gate uchar_t *raq_packet; 17517c478bd9Sstevel@tonic-gate }; 17527c478bd9Sstevel@tonic-gate static struct raq *raq_head = NULL; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * Allocate a struct raq and memory for the packet. 17567c478bd9Sstevel@tonic-gate * Send signal 255 to have poll dequeue. 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate static void 17597c478bd9Sstevel@tonic-gate loopback_ra_enqueue(struct phyint *pi, struct nd_router_advert *ra, int len) 17607c478bd9Sstevel@tonic-gate { 17617c478bd9Sstevel@tonic-gate struct raq *raq; 17627c478bd9Sstevel@tonic-gate struct raq **raqp; 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate if (no_loopback) 17657c478bd9Sstevel@tonic-gate return; 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate if (debug & D_PKTOUT) 17687c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_enqueue for %s\n", pi->pi_name); 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate raq = calloc(sizeof (struct raq), 1); 17717c478bd9Sstevel@tonic-gate if (raq == NULL) { 17727c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 17737c478bd9Sstevel@tonic-gate return; 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate raq->raq_packet = malloc(len); 17767c478bd9Sstevel@tonic-gate if (raq->raq_packet == NULL) { 17777c478bd9Sstevel@tonic-gate free(raq); 17787c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n"); 17797c478bd9Sstevel@tonic-gate return; 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate bcopy(ra, raq->raq_packet, len); 17827c478bd9Sstevel@tonic-gate raq->raq_packetlen = len; 17837c478bd9Sstevel@tonic-gate raq->raq_pi = pi; 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate /* Tail insert */ 17867c478bd9Sstevel@tonic-gate raqp = &raq_head; 17877c478bd9Sstevel@tonic-gate while (*raqp != NULL) 17887c478bd9Sstevel@tonic-gate raqp = &((*raqp)->raq_next); 17897c478bd9Sstevel@tonic-gate *raqp = raq; 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate /* Signal for poll loop */ 17927c478bd9Sstevel@tonic-gate sig_handler(255); 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate /* 17967c478bd9Sstevel@tonic-gate * Dequeue and process all queued advertisements. 17977c478bd9Sstevel@tonic-gate */ 17987c478bd9Sstevel@tonic-gate static void 17997c478bd9Sstevel@tonic-gate loopback_ra_dequeue(void) 18007c478bd9Sstevel@tonic-gate { 18017c478bd9Sstevel@tonic-gate struct sockaddr_in6 from = IN6ADDR_LOOPBACK_INIT; 18027c478bd9Sstevel@tonic-gate struct raq *raq; 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) 18057c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue()\n"); 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate while ((raq = raq_head) != NULL) { 18087c478bd9Sstevel@tonic-gate raq_head = raq->raq_next; 18097c478bd9Sstevel@tonic-gate raq->raq_next = NULL; 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 18127c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "loopback_ra_dequeue for %s\n", 18137c478bd9Sstevel@tonic-gate raq->raq_pi->pi_name); 18147c478bd9Sstevel@tonic-gate } 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate incoming_ra(raq->raq_pi, 18177c478bd9Sstevel@tonic-gate (struct nd_router_advert *)raq->raq_packet, 18187c478bd9Sstevel@tonic-gate raq->raq_packetlen, &from, _B_TRUE); 18197c478bd9Sstevel@tonic-gate free(raq->raq_packet); 18207c478bd9Sstevel@tonic-gate free(raq); 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate static void 18267c478bd9Sstevel@tonic-gate usage(char *cmd) 18277c478bd9Sstevel@tonic-gate { 18287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 18297c478bd9Sstevel@tonic-gate "usage: %s [ -adt ] [-f <config file>]\n", cmd); 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate int 18337c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate int i; 18367c478bd9Sstevel@tonic-gate struct phyint *pi; 18377c478bd9Sstevel@tonic-gate int c; 18387c478bd9Sstevel@tonic-gate char *config_file = PATH_NDPD_CONF; 18397c478bd9Sstevel@tonic-gate boolean_t file_required = _B_FALSE; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate argv0 = argv; 18427c478bd9Sstevel@tonic-gate srandom(gethostid()); 18437c478bd9Sstevel@tonic-gate (void) umask(0022); 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "adD:ntIf:")) != EOF) { 18467c478bd9Sstevel@tonic-gate switch (c) { 18477c478bd9Sstevel@tonic-gate case 'a': 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * The StatelessAddrConf variable in ndpd.conf, if 18507c478bd9Sstevel@tonic-gate * present, will override this setting. 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate ifdefaults[I_StatelessAddrConf].cf_value = 0; 18537c478bd9Sstevel@tonic-gate break; 18547c478bd9Sstevel@tonic-gate case 'd': 18557c478bd9Sstevel@tonic-gate debug = D_ALL; 18567c478bd9Sstevel@tonic-gate break; 18577c478bd9Sstevel@tonic-gate case 'D': 18587c478bd9Sstevel@tonic-gate i = strtol((char *)optarg, NULL, 0); 18597c478bd9Sstevel@tonic-gate if (i == 0) { 18607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Bad debug flags: %s\n", 18617c478bd9Sstevel@tonic-gate (char *)optarg); 18627c478bd9Sstevel@tonic-gate exit(1); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate debug |= i; 18657c478bd9Sstevel@tonic-gate break; 18667c478bd9Sstevel@tonic-gate case 'n': 18677c478bd9Sstevel@tonic-gate no_loopback = 1; 18687c478bd9Sstevel@tonic-gate break; 18697c478bd9Sstevel@tonic-gate case 'I': 18707c478bd9Sstevel@tonic-gate show_ifs = 1; 18717c478bd9Sstevel@tonic-gate break; 18727c478bd9Sstevel@tonic-gate case 't': 18737c478bd9Sstevel@tonic-gate debug |= D_PKTIN | D_PKTOUT | D_PKTBAD; 18747c478bd9Sstevel@tonic-gate break; 18757c478bd9Sstevel@tonic-gate case 'f': 18767c478bd9Sstevel@tonic-gate config_file = (char *)optarg; 18777c478bd9Sstevel@tonic-gate file_required = _B_TRUE; 18787c478bd9Sstevel@tonic-gate break; 18797c478bd9Sstevel@tonic-gate case '?': 18807c478bd9Sstevel@tonic-gate usage(argv[0]); 18817c478bd9Sstevel@tonic-gate exit(1); 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate if (parse_config(config_file, file_required) == -1) 18867c478bd9Sstevel@tonic-gate exit(2); 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate if (show_ifs) 18897c478bd9Sstevel@tonic-gate phyint_print_all(); 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate if (debug == 0) { 18927c478bd9Sstevel@tonic-gate initlog(); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate setup_eventpipe(); 18967c478bd9Sstevel@tonic-gate rtsock = setup_rtsock(); 18977c478bd9Sstevel@tonic-gate timer_init(); 18987c478bd9Sstevel@tonic-gate initifs(_B_TRUE); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate check_daemonize(); 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate for (;;) { 19037c478bd9Sstevel@tonic-gate if (poll(pollfds, pollfd_num, -1) < 0) { 19047c478bd9Sstevel@tonic-gate if (errno == EINTR) 19057c478bd9Sstevel@tonic-gate continue; 19067c478bd9Sstevel@tonic-gate logperror("main: poll"); 19077c478bd9Sstevel@tonic-gate exit(1); 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 19107c478bd9Sstevel@tonic-gate if (!(pollfds[i].revents & POLLIN)) 19117c478bd9Sstevel@tonic-gate continue; 19127c478bd9Sstevel@tonic-gate if (pollfds[i].fd == eventpipe_read) { 19137c478bd9Sstevel@tonic-gate in_signal(eventpipe_read); 19147c478bd9Sstevel@tonic-gate break; 19157c478bd9Sstevel@tonic-gate } 19167c478bd9Sstevel@tonic-gate if (pollfds[i].fd == rtsock) { 19177c478bd9Sstevel@tonic-gate process_rtsock(rtsock); 19187c478bd9Sstevel@tonic-gate break; 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate /* 19217c478bd9Sstevel@tonic-gate * Run timer routine to advance clock if more than 19227c478bd9Sstevel@tonic-gate * half a second since the clock was advanced. 19237c478bd9Sstevel@tonic-gate * This limits CPU usage under severe packet 19247c478bd9Sstevel@tonic-gate * arrival rates but it creates a slight inaccuracy 19257c478bd9Sstevel@tonic-gate * in the timer mechanism. 19267c478bd9Sstevel@tonic-gate */ 19277c478bd9Sstevel@tonic-gate conditional_run_timeouts(500U); 19287c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 19297c478bd9Sstevel@tonic-gate if (pollfds[i].fd == pi->pi_sock) { 19307c478bd9Sstevel@tonic-gate in_data(pi); 19317c478bd9Sstevel@tonic-gate break; 19327c478bd9Sstevel@tonic-gate } 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate /* NOTREACHED */ 19377c478bd9Sstevel@tonic-gate return (0); 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate /* 19417c478bd9Sstevel@tonic-gate * LOGGER 19427c478bd9Sstevel@tonic-gate */ 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate static boolean_t logging = _B_FALSE; 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate static void 19477c478bd9Sstevel@tonic-gate initlog(void) 19487c478bd9Sstevel@tonic-gate { 19497c478bd9Sstevel@tonic-gate logging = _B_TRUE; 19507c478bd9Sstevel@tonic-gate openlog("in.ndpd", LOG_PID | LOG_CONS, LOG_DAEMON); 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate /* Print the date/time without a trailing carridge return */ 19547c478bd9Sstevel@tonic-gate static void 19557c478bd9Sstevel@tonic-gate fprintdate(FILE *file) 19567c478bd9Sstevel@tonic-gate { 19577c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 19587c478bd9Sstevel@tonic-gate struct tm tms; 19597c478bd9Sstevel@tonic-gate time_t now; 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate now = time(NULL); 19627c478bd9Sstevel@tonic-gate (void) localtime_r(&now, &tms); 19637c478bd9Sstevel@tonic-gate (void) strftime(buf, sizeof (buf), "%h %d %X", &tms); 19647c478bd9Sstevel@tonic-gate (void) fprintf(file, "%s ", buf); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */ 19687c478bd9Sstevel@tonic-gate void 19697c478bd9Sstevel@tonic-gate logmsg(int level, char *fmt, ...) 19707c478bd9Sstevel@tonic-gate { 19717c478bd9Sstevel@tonic-gate va_list ap; 19727c478bd9Sstevel@tonic-gate va_start(ap, fmt); 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate if (logging) { 19757c478bd9Sstevel@tonic-gate vsyslog(level, fmt, ap); 19767c478bd9Sstevel@tonic-gate } else { 19777c478bd9Sstevel@tonic-gate fprintdate(stderr); 19787c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate va_end(ap); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate void 19847c478bd9Sstevel@tonic-gate logperror(char *str) 19857c478bd9Sstevel@tonic-gate { 19867c478bd9Sstevel@tonic-gate if (logging) { 19877c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 19887c478bd9Sstevel@tonic-gate } else { 19897c478bd9Sstevel@tonic-gate fprintdate(stderr); 19907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 19917c478bd9Sstevel@tonic-gate } 19927c478bd9Sstevel@tonic-gate } 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate void 19957c478bd9Sstevel@tonic-gate logperror_pi(struct phyint *pi, char *str) 19967c478bd9Sstevel@tonic-gate { 19977c478bd9Sstevel@tonic-gate if (logging) { 19987c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s (interface %s): %m\n", 19997c478bd9Sstevel@tonic-gate str, pi->pi_name); 20007c478bd9Sstevel@tonic-gate } else { 20017c478bd9Sstevel@tonic-gate fprintdate(stderr); 20027c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s (interface %s): %s\n", 20037c478bd9Sstevel@tonic-gate str, pi->pi_name, strerror(errno)); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate } 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate void 20087c478bd9Sstevel@tonic-gate logperror_pr(struct prefix *pr, char *str) 20097c478bd9Sstevel@tonic-gate { 20107c478bd9Sstevel@tonic-gate if (logging) { 20117c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s (prefix %s if %s): %m\n", 20127c478bd9Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name); 20137c478bd9Sstevel@tonic-gate } else { 20147c478bd9Sstevel@tonic-gate fprintdate(stderr); 20157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s (prefix %s if %s): %s\n", 20167c478bd9Sstevel@tonic-gate str, pr->pr_name, pr->pr_physical->pi_name, 20177c478bd9Sstevel@tonic-gate strerror(errno)); 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate } 2020