1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "defs.h"
30*0Sstevel@tonic-gate #include "tables.h"
31*0Sstevel@tonic-gate #include <fcntl.h>
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate static void	initlog(void);
34*0Sstevel@tonic-gate static void	run_timeouts(void);
35*0Sstevel@tonic-gate static void	check_fallback(void);
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate static void	advertise(struct sockaddr_in6 *sin6, struct phyint *pi,
38*0Sstevel@tonic-gate 		    boolean_t no_prefixes);
39*0Sstevel@tonic-gate static void	solicit(struct sockaddr_in6 *sin6, struct phyint *pi);
40*0Sstevel@tonic-gate static void	initifs(boolean_t first);
41*0Sstevel@tonic-gate static void	check_if_removed(struct phyint *pi);
42*0Sstevel@tonic-gate static void	loopback_ra_enqueue(struct phyint *pi,
43*0Sstevel@tonic-gate 		    struct nd_router_advert *ra, int len);
44*0Sstevel@tonic-gate static void	loopback_ra_dequeue(void);
45*0Sstevel@tonic-gate static void	check_daemonize(void);
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate struct in6_addr all_nodes_mcast = { { 0xff, 0x2, 0x0, 0x0,
48*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
49*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
50*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x1 } };
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate struct in6_addr all_routers_mcast = { { 0xff, 0x2, 0x0, 0x0,
53*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
54*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
55*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x2 } };
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate static struct sockaddr_in6 v6allnodes = { AF_INET6, 0, 0,
58*0Sstevel@tonic-gate 				    { 0xff, 0x2, 0x0, 0x0,
59*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
60*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
61*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x1 } };
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate static struct sockaddr_in6 v6allrouters = { AF_INET6, 0, 0,
64*0Sstevel@tonic-gate 				    { 0xff, 0x2, 0x0, 0x0,
65*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
66*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x0,
67*0Sstevel@tonic-gate 				    0x0, 0x0, 0x0, 0x2 } };
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate static char **argv0;		/* Saved for re-exec on SIGHUP */
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static uint64_t packet[(IP_MAXPACKET + 1)/8];
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static int	show_ifs = 0;
74*0Sstevel@tonic-gate static boolean_t	already_daemonized = _B_FALSE;
75*0Sstevel@tonic-gate int		debug = 0;
76*0Sstevel@tonic-gate int		no_loopback = 0; /* Do not send RA packets to ourselves */
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /*
79*0Sstevel@tonic-gate  * Size of routing socket message used by in.ndpd which includes the header,
80*0Sstevel@tonic-gate  * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6)
81*0Sstevel@tonic-gate  * plus space for the RTA_IFP (a sockaddr_dl).
82*0Sstevel@tonic-gate  */
83*0Sstevel@tonic-gate #define	NDP_RTM_MSGLEN	sizeof (struct rt_msghdr) +	\
84*0Sstevel@tonic-gate 			sizeof (struct sockaddr_in6) +	\
85*0Sstevel@tonic-gate 			sizeof (struct sockaddr_in6) +	\
86*0Sstevel@tonic-gate 			sizeof (struct sockaddr_in6) +	\
87*0Sstevel@tonic-gate 			sizeof (struct sockaddr_dl)
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * These are referenced externally in tables.c in order to fill in the
91*0Sstevel@tonic-gate  * dynamic portions of the routing socket message and then to send the message
92*0Sstevel@tonic-gate  * itself.
93*0Sstevel@tonic-gate  */
94*0Sstevel@tonic-gate int	rtsock = -1;			/* Routing socket */
95*0Sstevel@tonic-gate struct	rt_msghdr	*rt_msg;	/* Routing socket message */
96*0Sstevel@tonic-gate struct	sockaddr_in6	*rta_gateway;	/* RTA_GATEWAY sockaddr */
97*0Sstevel@tonic-gate struct	sockaddr_dl	*rta_ifp;	/* RTA_IFP sockaddr */
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * Return the current time in milliseconds truncated to
101*0Sstevel@tonic-gate  * fit in an integer.
102*0Sstevel@tonic-gate  */
103*0Sstevel@tonic-gate uint_t
104*0Sstevel@tonic-gate getcurrenttime(void)
105*0Sstevel@tonic-gate {
106*0Sstevel@tonic-gate 	struct timeval tp;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 	if (gettimeofday(&tp, NULL) < 0) {
109*0Sstevel@tonic-gate 		logperror("getcurrenttime: gettimeofday failed");
110*0Sstevel@tonic-gate 		exit(1);
111*0Sstevel@tonic-gate 	}
112*0Sstevel@tonic-gate 	return (tp.tv_sec * 1000 + tp.tv_usec / 1000);
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate /*
116*0Sstevel@tonic-gate  * Output a preformated packet from the packet[] buffer.
117*0Sstevel@tonic-gate  */
118*0Sstevel@tonic-gate static void
119*0Sstevel@tonic-gate sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	int cc;
122*0Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	cc = sendto(sock, (char *)packet, size, flags,
125*0Sstevel@tonic-gate 		(struct sockaddr *)sin6, sizeof (*sin6));
126*0Sstevel@tonic-gate 	if (cc < 0 || cc != size) {
127*0Sstevel@tonic-gate 		if (cc < 0) {
128*0Sstevel@tonic-gate 			logperror("sendpacket: sendto");
129*0Sstevel@tonic-gate 		}
130*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "sendpacket: wrote %s %d chars, ret=%d\n",
131*0Sstevel@tonic-gate 		    inet_ntop(sin6->sin6_family,
132*0Sstevel@tonic-gate 		    (void *)&sin6->sin6_addr,
133*0Sstevel@tonic-gate 		    abuf, sizeof (abuf)),
134*0Sstevel@tonic-gate 		    size, cc);
135*0Sstevel@tonic-gate 	}
136*0Sstevel@tonic-gate }
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate /* Send a Router Solicitation */
139*0Sstevel@tonic-gate static void
140*0Sstevel@tonic-gate solicit(struct sockaddr_in6 *sin6, struct phyint *pi)
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	int packetlen = 0;
143*0Sstevel@tonic-gate 	struct	nd_router_solicit *rs = (struct nd_router_solicit *)packet;
144*0Sstevel@tonic-gate 	char *pptr = (char *)packet;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	rs->nd_rs_type = ND_ROUTER_SOLICIT;
147*0Sstevel@tonic-gate 	rs->nd_rs_code = 0;
148*0Sstevel@tonic-gate 	rs->nd_rs_cksum = htons(0);
149*0Sstevel@tonic-gate 	rs->nd_rs_reserved = htonl(0);
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	packetlen += sizeof (*rs);
152*0Sstevel@tonic-gate 	pptr += sizeof (*rs);
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	/* Attach any options */
155*0Sstevel@tonic-gate 	if (pi->pi_hdw_addr_len != 0) {
156*0Sstevel@tonic-gate 		struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr;
157*0Sstevel@tonic-gate 		int optlen;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 		/* roundup to multiple of 8 and make padding zero */
160*0Sstevel@tonic-gate 		optlen = ((sizeof (struct nd_opt_hdr) +
161*0Sstevel@tonic-gate 		    pi->pi_hdw_addr_len + 7) / 8) * 8;
162*0Sstevel@tonic-gate 		bzero(pptr, optlen);
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 		lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
165*0Sstevel@tonic-gate 		lo->nd_opt_lla_len = optlen / 8;
166*0Sstevel@tonic-gate 		bcopy((char *)pi->pi_hdw_addr,
167*0Sstevel@tonic-gate 		    (char *)lo->nd_opt_lla_hdw_addr,
168*0Sstevel@tonic-gate 		    pi->pi_hdw_addr_len);
169*0Sstevel@tonic-gate 		packetlen += optlen;
170*0Sstevel@tonic-gate 		pptr += optlen;
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	if (debug & D_PKTOUT) {
174*0Sstevel@tonic-gate 		print_route_sol("Sending solicitation to ", pi, rs, packetlen,
175*0Sstevel@tonic-gate 		    sin6);
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 	sendpacket(sin6, pi->pi_sock, packetlen, 0);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  * Send a (set of) Router Advertisements and feed them back to ourselves
182*0Sstevel@tonic-gate  * for processing. Unless no_prefixes is set all prefixes are included.
183*0Sstevel@tonic-gate  * If there are too many prefix options to fit in one packet multiple
184*0Sstevel@tonic-gate  * packets will be sent - each containing a subset of the prefix options.
185*0Sstevel@tonic-gate  */
186*0Sstevel@tonic-gate static void
187*0Sstevel@tonic-gate advertise(struct sockaddr_in6 *sin6, struct phyint *pi, boolean_t no_prefixes)
188*0Sstevel@tonic-gate {
189*0Sstevel@tonic-gate 	struct	nd_opt_prefix_info *po;
190*0Sstevel@tonic-gate 	char *pptr = (char *)packet;
191*0Sstevel@tonic-gate 	struct nd_router_advert *ra;
192*0Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
193*0Sstevel@tonic-gate 	int packetlen = 0;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	ra = (struct nd_router_advert *)pptr;
196*0Sstevel@tonic-gate 	ra->nd_ra_type = ND_ROUTER_ADVERT;
197*0Sstevel@tonic-gate 	ra->nd_ra_code = 0;
198*0Sstevel@tonic-gate 	ra->nd_ra_cksum = htons(0);
199*0Sstevel@tonic-gate 	ra->nd_ra_curhoplimit = pi->pi_AdvCurHopLimit;
200*0Sstevel@tonic-gate 	ra->nd_ra_flags_reserved = 0;
201*0Sstevel@tonic-gate 	if (pi->pi_AdvManagedFlag)
202*0Sstevel@tonic-gate 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
203*0Sstevel@tonic-gate 	if (pi->pi_AdvOtherConfigFlag)
204*0Sstevel@tonic-gate 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	if (pi->pi_adv_state == FINAL_ADV)
207*0Sstevel@tonic-gate 		ra->nd_ra_router_lifetime = htons(0);
208*0Sstevel@tonic-gate 	else
209*0Sstevel@tonic-gate 		ra->nd_ra_router_lifetime = htons(pi->pi_AdvDefaultLifetime);
210*0Sstevel@tonic-gate 	ra->nd_ra_reachable = htonl(pi->pi_AdvReachableTime);
211*0Sstevel@tonic-gate 	ra->nd_ra_retransmit = htonl(pi->pi_AdvRetransTimer);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	packetlen = sizeof (*ra);
214*0Sstevel@tonic-gate 	pptr += sizeof (*ra);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	if (pi->pi_adv_state == FINAL_ADV) {
217*0Sstevel@tonic-gate 		if (debug & D_PKTOUT) {
218*0Sstevel@tonic-gate 			print_route_adv("Sending advert (FINAL) to ", pi,
219*0Sstevel@tonic-gate 			    ra, packetlen, sin6);
220*0Sstevel@tonic-gate 		}
221*0Sstevel@tonic-gate 		sendpacket(sin6, pi->pi_sock, packetlen, 0);
222*0Sstevel@tonic-gate 		/* Feed packet back in for router operation */
223*0Sstevel@tonic-gate 		loopback_ra_enqueue(pi, ra, packetlen);
224*0Sstevel@tonic-gate 		return;
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* Attach any options */
228*0Sstevel@tonic-gate 	if (pi->pi_hdw_addr_len != 0) {
229*0Sstevel@tonic-gate 		struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr;
230*0Sstevel@tonic-gate 		int optlen;
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 		/* roundup to multiple of 8 and make padding zero */
233*0Sstevel@tonic-gate 		optlen = ((sizeof (struct nd_opt_hdr) +
234*0Sstevel@tonic-gate 		    pi->pi_hdw_addr_len + 7) / 8) * 8;
235*0Sstevel@tonic-gate 		bzero(pptr, optlen);
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 		lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
238*0Sstevel@tonic-gate 		lo->nd_opt_lla_len = optlen / 8;
239*0Sstevel@tonic-gate 		bcopy((char *)pi->pi_hdw_addr,
240*0Sstevel@tonic-gate 		    (char *)lo->nd_opt_lla_hdw_addr,
241*0Sstevel@tonic-gate 		    pi->pi_hdw_addr_len);
242*0Sstevel@tonic-gate 		packetlen += optlen;
243*0Sstevel@tonic-gate 		pptr += optlen;
244*0Sstevel@tonic-gate 	}
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	if (pi->pi_AdvLinkMTU != 0) {
247*0Sstevel@tonic-gate 		struct nd_opt_mtu *mo = (struct nd_opt_mtu *)pptr;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 		mo->nd_opt_mtu_type = ND_OPT_MTU;
250*0Sstevel@tonic-gate 		mo->nd_opt_mtu_len = sizeof (struct nd_opt_mtu) / 8;
251*0Sstevel@tonic-gate 		mo->nd_opt_mtu_reserved = 0;
252*0Sstevel@tonic-gate 		mo->nd_opt_mtu_mtu = htonl(pi->pi_AdvLinkMTU);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 		packetlen += sizeof (struct nd_opt_mtu);
255*0Sstevel@tonic-gate 		pptr += sizeof (struct nd_opt_mtu);
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	if (no_prefixes) {
259*0Sstevel@tonic-gate 		if (debug & D_PKTOUT) {
260*0Sstevel@tonic-gate 			print_route_adv("Sending advert to ", pi,
261*0Sstevel@tonic-gate 			    ra, packetlen, sin6);
262*0Sstevel@tonic-gate 		}
263*0Sstevel@tonic-gate 		sendpacket(sin6, pi->pi_sock, packetlen, 0);
264*0Sstevel@tonic-gate 		/* Feed packet back in for router operation */
265*0Sstevel@tonic-gate 		loopback_ra_enqueue(pi, ra, packetlen);
266*0Sstevel@tonic-gate 		return;
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	po = (struct nd_opt_prefix_info *)pptr;
270*0Sstevel@tonic-gate 	for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL;
271*0Sstevel@tonic-gate 	    adv_pr = adv_pr->adv_pr_next) {
272*0Sstevel@tonic-gate 		if (!adv_pr->adv_pr_AdvOnLinkFlag &&
273*0Sstevel@tonic-gate 		    !adv_pr->adv_pr_AdvAutonomousFlag) {
274*0Sstevel@tonic-gate 			continue;
275*0Sstevel@tonic-gate 		}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 		/*
278*0Sstevel@tonic-gate 		 * If the prefix doesn't fit in packet send
279*0Sstevel@tonic-gate 		 * what we have so far and start with new packet.
280*0Sstevel@tonic-gate 		 */
281*0Sstevel@tonic-gate 		if (packetlen + sizeof (*po) >
282*0Sstevel@tonic-gate 		    pi->pi_LinkMTU - sizeof (struct ip6_hdr)) {
283*0Sstevel@tonic-gate 			if (debug & D_PKTOUT) {
284*0Sstevel@tonic-gate 				print_route_adv("Sending advert "
285*0Sstevel@tonic-gate 				    "(FRAG) to ",
286*0Sstevel@tonic-gate 				    pi, ra, packetlen, sin6);
287*0Sstevel@tonic-gate 			}
288*0Sstevel@tonic-gate 			sendpacket(sin6, pi->pi_sock, packetlen, 0);
289*0Sstevel@tonic-gate 			/* Feed packet back in for router operation */
290*0Sstevel@tonic-gate 			loopback_ra_enqueue(pi, ra, packetlen);
291*0Sstevel@tonic-gate 			packetlen = sizeof (*ra);
292*0Sstevel@tonic-gate 			pptr = (char *)packet + sizeof (*ra);
293*0Sstevel@tonic-gate 			po = (struct nd_opt_prefix_info *)pptr;
294*0Sstevel@tonic-gate 		}
295*0Sstevel@tonic-gate 		po->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
296*0Sstevel@tonic-gate 		po->nd_opt_pi_len = sizeof (*po)/8;
297*0Sstevel@tonic-gate 		po->nd_opt_pi_flags_reserved = 0;
298*0Sstevel@tonic-gate 		if (adv_pr->adv_pr_AdvOnLinkFlag) {
299*0Sstevel@tonic-gate 			po->nd_opt_pi_flags_reserved |=
300*0Sstevel@tonic-gate 			    ND_OPT_PI_FLAG_ONLINK;
301*0Sstevel@tonic-gate 		}
302*0Sstevel@tonic-gate 		if (adv_pr->adv_pr_AdvAutonomousFlag) {
303*0Sstevel@tonic-gate 			po->nd_opt_pi_flags_reserved |=
304*0Sstevel@tonic-gate 			    ND_OPT_PI_FLAG_AUTO;
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 		po->nd_opt_pi_prefix_len = adv_pr->adv_pr_prefix_len;
307*0Sstevel@tonic-gate 		/*
308*0Sstevel@tonic-gate 		 * If both Adv*Expiration and Adv*Lifetime are
309*0Sstevel@tonic-gate 		 * set we prefer the former and make the lifetime
310*0Sstevel@tonic-gate 		 * decrement in real time.
311*0Sstevel@tonic-gate 		 */
312*0Sstevel@tonic-gate 		if (adv_pr->adv_pr_AdvValidRealTime) {
313*0Sstevel@tonic-gate 			po->nd_opt_pi_valid_time =
314*0Sstevel@tonic-gate 			    htonl(adv_pr->adv_pr_AdvValidExpiration);
315*0Sstevel@tonic-gate 		} else {
316*0Sstevel@tonic-gate 			po->nd_opt_pi_valid_time =
317*0Sstevel@tonic-gate 			    htonl(adv_pr->adv_pr_AdvValidLifetime);
318*0Sstevel@tonic-gate 		}
319*0Sstevel@tonic-gate 		if (adv_pr->adv_pr_AdvPreferredRealTime) {
320*0Sstevel@tonic-gate 			po->nd_opt_pi_preferred_time =
321*0Sstevel@tonic-gate 			    htonl(adv_pr->adv_pr_AdvPreferredExpiration);
322*0Sstevel@tonic-gate 		} else {
323*0Sstevel@tonic-gate 			po->nd_opt_pi_preferred_time =
324*0Sstevel@tonic-gate 			    htonl(adv_pr->adv_pr_AdvPreferredLifetime);
325*0Sstevel@tonic-gate 		}
326*0Sstevel@tonic-gate 		po->nd_opt_pi_reserved2 = htonl(0);
327*0Sstevel@tonic-gate 		po->nd_opt_pi_prefix = adv_pr->adv_pr_prefix;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 		po++;
330*0Sstevel@tonic-gate 		packetlen += sizeof (*po);
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate 	if (debug & D_PKTOUT) {
333*0Sstevel@tonic-gate 		print_route_adv("Sending advert to ", pi,
334*0Sstevel@tonic-gate 		    ra, packetlen, sin6);
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 	sendpacket(sin6, pi->pi_sock, packetlen, 0);
337*0Sstevel@tonic-gate 	/* Feed packet back in for router operation */
338*0Sstevel@tonic-gate 	loopback_ra_enqueue(pi, ra, packetlen);
339*0Sstevel@tonic-gate }
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate /* Poll support */
342*0Sstevel@tonic-gate static int		pollfd_num = 0;	/* Allocated and initialized */
343*0Sstevel@tonic-gate static struct pollfd	*pollfds = NULL;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate /*
346*0Sstevel@tonic-gate  * Add fd to the set being polled. Returns 0 if ok; -1 if failed.
347*0Sstevel@tonic-gate  */
348*0Sstevel@tonic-gate int
349*0Sstevel@tonic-gate poll_add(int fd)
350*0Sstevel@tonic-gate {
351*0Sstevel@tonic-gate 	int i;
352*0Sstevel@tonic-gate 	int new_num;
353*0Sstevel@tonic-gate 	struct pollfd *newfds;
354*0Sstevel@tonic-gate retry:
355*0Sstevel@tonic-gate 	/* Check if already present */
356*0Sstevel@tonic-gate 	for (i = 0; i < pollfd_num; i++) {
357*0Sstevel@tonic-gate 		if (pollfds[i].fd == fd)
358*0Sstevel@tonic-gate 			return (0);
359*0Sstevel@tonic-gate 	}
360*0Sstevel@tonic-gate 	/* Check for empty spot already present */
361*0Sstevel@tonic-gate 	for (i = 0; i < pollfd_num; i++) {
362*0Sstevel@tonic-gate 		if (pollfds[i].fd == -1) {
363*0Sstevel@tonic-gate 			pollfds[i].fd = fd;
364*0Sstevel@tonic-gate 			return (0);
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	/* Allocate space for 32 more fds and initialize to -1 */
369*0Sstevel@tonic-gate 	new_num = pollfd_num + 32;
370*0Sstevel@tonic-gate 	newfds = realloc(pollfds, new_num * sizeof (struct pollfd));
371*0Sstevel@tonic-gate 	if (newfds == NULL) {
372*0Sstevel@tonic-gate 		logperror("poll_add: realloc");
373*0Sstevel@tonic-gate 		return (-1);
374*0Sstevel@tonic-gate 	}
375*0Sstevel@tonic-gate 	for (i = pollfd_num; i < new_num; i++) {
376*0Sstevel@tonic-gate 		newfds[i].fd = -1;
377*0Sstevel@tonic-gate 		newfds[i].events = POLLIN;
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate 	pollfd_num = new_num;
380*0Sstevel@tonic-gate 	pollfds = newfds;
381*0Sstevel@tonic-gate 	goto retry;
382*0Sstevel@tonic-gate }
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate /*
385*0Sstevel@tonic-gate  * Remove fd from the set being polled. Returns 0 if ok; -1 if failed.
386*0Sstevel@tonic-gate  */
387*0Sstevel@tonic-gate int
388*0Sstevel@tonic-gate poll_remove(int fd)
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate 	int i;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	/* Check if already present */
393*0Sstevel@tonic-gate 	for (i = 0; i < pollfd_num; i++) {
394*0Sstevel@tonic-gate 		if (pollfds[i].fd == fd) {
395*0Sstevel@tonic-gate 			pollfds[i].fd = -1;
396*0Sstevel@tonic-gate 			return (0);
397*0Sstevel@tonic-gate 		}
398*0Sstevel@tonic-gate 	}
399*0Sstevel@tonic-gate 	return (-1);
400*0Sstevel@tonic-gate }
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate /*
403*0Sstevel@tonic-gate  * Extract information about the ifname (either a physical interface and
404*0Sstevel@tonic-gate  * the ":0" logical interface or just a logical interface).
405*0Sstevel@tonic-gate  * If the interface (still) exists in kernel set pr_in_use
406*0Sstevel@tonic-gate  * for caller to be able to detect interfaces that are removed.
407*0Sstevel@tonic-gate  * Starts sending advertisements/solicitations when new physical interfaces
408*0Sstevel@tonic-gate  * are detected.
409*0Sstevel@tonic-gate  */
410*0Sstevel@tonic-gate static void
411*0Sstevel@tonic-gate if_process(int s, char *ifname, boolean_t first)
412*0Sstevel@tonic-gate {
413*0Sstevel@tonic-gate 	struct lifreq lifr;
414*0Sstevel@tonic-gate 	struct phyint *pi;
415*0Sstevel@tonic-gate 	struct prefix *pr;
416*0Sstevel@tonic-gate 	char *cp;
417*0Sstevel@tonic-gate 	char phyintname[LIFNAMSIZ + 1];
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	if (debug & D_IFSCAN)
420*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "if_process(%s)\n", ifname);
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
423*0Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
424*0Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
425*0Sstevel@tonic-gate 		if (errno == ENXIO) {
426*0Sstevel@tonic-gate 			/*
427*0Sstevel@tonic-gate 			 * Interface has disappeared
428*0Sstevel@tonic-gate 			 */
429*0Sstevel@tonic-gate 			return;
430*0Sstevel@tonic-gate 		}
431*0Sstevel@tonic-gate 		logperror("if_process: ioctl (get interface flags)");
432*0Sstevel@tonic-gate 		return;
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	/*
436*0Sstevel@tonic-gate 	 * Ignore loopback and point-to-multipoint interfaces.
437*0Sstevel@tonic-gate 	 * Point-to-point interfaces always have IFF_MULTICAST set.
438*0Sstevel@tonic-gate 	 */
439*0Sstevel@tonic-gate 	if (!(lifr.lifr_flags & IFF_MULTICAST) ||
440*0Sstevel@tonic-gate 	    (lifr.lifr_flags & IFF_LOOPBACK)) {
441*0Sstevel@tonic-gate 		return;
442*0Sstevel@tonic-gate 	}
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	if (!(lifr.lifr_flags & IFF_IPV6))
445*0Sstevel@tonic-gate 		return;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	(void) strncpy(phyintname, ifname, sizeof (phyintname));
448*0Sstevel@tonic-gate 	phyintname[sizeof (phyintname) - 1] = '\0';
449*0Sstevel@tonic-gate 	if ((cp = strchr(phyintname, IF_SEPARATOR)) != NULL) {
450*0Sstevel@tonic-gate 		*cp = '\0';
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	pi = phyint_lookup(phyintname);
454*0Sstevel@tonic-gate 	if (pi == NULL) {
455*0Sstevel@tonic-gate 		/*
456*0Sstevel@tonic-gate 		 * Do not add anything for new interfaces until they are UP.
457*0Sstevel@tonic-gate 		 * For existing interfaces we track the up flag.
458*0Sstevel@tonic-gate 		 */
459*0Sstevel@tonic-gate 		if (!(lifr.lifr_flags & IFF_UP))
460*0Sstevel@tonic-gate 			return;
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 		pi = phyint_create(phyintname);
463*0Sstevel@tonic-gate 		if (pi == NULL) {
464*0Sstevel@tonic-gate 			logmsg(LOG_ERR, "if_process: out of memory\n");
465*0Sstevel@tonic-gate 			return;
466*0Sstevel@tonic-gate 		}
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate 	(void) phyint_init_from_k(pi);
469*0Sstevel@tonic-gate 	if (pi->pi_sock == -1 && !(pi->pi_kernel_state & PI_PRESENT)) {
470*0Sstevel@tonic-gate 		/* Interface is not yet present */
471*0Sstevel@tonic-gate 		if (debug & D_PHYINT) {
472*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "if_process: interface not yet "
473*0Sstevel@tonic-gate 			    "present %s\n", pi->pi_name);
474*0Sstevel@tonic-gate 		}
475*0Sstevel@tonic-gate 		return;
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	if (pi->pi_sock != -1) {
479*0Sstevel@tonic-gate 		if (poll_add(pi->pi_sock) == -1) {
480*0Sstevel@tonic-gate 			/*
481*0Sstevel@tonic-gate 			 * reset state.
482*0Sstevel@tonic-gate 			 */
483*0Sstevel@tonic-gate 			phyint_cleanup(pi);
484*0Sstevel@tonic-gate 		}
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/*
488*0Sstevel@tonic-gate 	 * Check if IFF_ROUTER has been turned off in kernel in which
489*0Sstevel@tonic-gate 	 * case we have to turn off AdvSendAdvertisements.
490*0Sstevel@tonic-gate 	 * The kernel will automatically turn off IFF_ROUTER if
491*0Sstevel@tonic-gate 	 * ip6_forwarding is turned off.
492*0Sstevel@tonic-gate 	 * Note that we do not switch back should IFF_ROUTER be turned on.
493*0Sstevel@tonic-gate 	 */
494*0Sstevel@tonic-gate 	if (!first &&
495*0Sstevel@tonic-gate 	    pi->pi_AdvSendAdvertisements && !(pi->pi_flags & IFF_ROUTER)) {
496*0Sstevel@tonic-gate 		logmsg(LOG_INFO, "No longer a router on %s\n", pi->pi_name);
497*0Sstevel@tonic-gate 		check_to_advertise(pi, START_FINAL_ADV);
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 		pi->pi_AdvSendAdvertisements = 0;
500*0Sstevel@tonic-gate 		pi->pi_sol_state = NO_SOLICIT;
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	/*
504*0Sstevel@tonic-gate 	 * Send advertisments and solicitation only if the interface is
505*0Sstevel@tonic-gate 	 * present in the kernel.
506*0Sstevel@tonic-gate 	 */
507*0Sstevel@tonic-gate 	if (pi->pi_kernel_state & PI_PRESENT) {
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 		if (pi->pi_AdvSendAdvertisements) {
510*0Sstevel@tonic-gate 			if (pi->pi_adv_state == NO_ADV)
511*0Sstevel@tonic-gate 				check_to_advertise(pi, START_INIT_ADV);
512*0Sstevel@tonic-gate 		} else {
513*0Sstevel@tonic-gate 			if (pi->pi_sol_state == NO_SOLICIT)
514*0Sstevel@tonic-gate 				check_to_solicit(pi, START_INIT_SOLICIT);
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	/*
519*0Sstevel@tonic-gate 	 * Track static kernel prefixes to prevent in.ndpd from clobbering
520*0Sstevel@tonic-gate 	 * them by creating a struct prefix for each prefix detected in the
521*0Sstevel@tonic-gate 	 * kernel.
522*0Sstevel@tonic-gate 	 */
523*0Sstevel@tonic-gate 	pr = prefix_lookup_name(pi, ifname);
524*0Sstevel@tonic-gate 	if (pr == NULL) {
525*0Sstevel@tonic-gate 		pr = prefix_create_name(pi, ifname);
526*0Sstevel@tonic-gate 		if (pr == NULL) {
527*0Sstevel@tonic-gate 			logmsg(LOG_ERR, "if_process: out of memory\n");
528*0Sstevel@tonic-gate 			return;
529*0Sstevel@tonic-gate 		}
530*0Sstevel@tonic-gate 		if (prefix_init_from_k(pr) == -1) {
531*0Sstevel@tonic-gate 			prefix_delete(pr);
532*0Sstevel@tonic-gate 			return;
533*0Sstevel@tonic-gate 		}
534*0Sstevel@tonic-gate 	}
535*0Sstevel@tonic-gate 	/* Detect prefixes which are removed */
536*0Sstevel@tonic-gate 	if (pr->pr_kernel_state != 0)
537*0Sstevel@tonic-gate 		pr->pr_in_use = _B_TRUE;
538*0Sstevel@tonic-gate }
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate static int ifsock = -1;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate /*
543*0Sstevel@tonic-gate  * Scan all interfaces to detect changes as well as new and deleted intefaces
544*0Sstevel@tonic-gate  * 'first' is set for the initial call only. Do not effect anything.
545*0Sstevel@tonic-gate  */
546*0Sstevel@tonic-gate static void
547*0Sstevel@tonic-gate initifs(boolean_t first)
548*0Sstevel@tonic-gate {
549*0Sstevel@tonic-gate 	char *buf;
550*0Sstevel@tonic-gate 	int bufsize;
551*0Sstevel@tonic-gate 	int numifs;
552*0Sstevel@tonic-gate 	int n;
553*0Sstevel@tonic-gate 	struct lifnum lifn;
554*0Sstevel@tonic-gate 	struct lifconf lifc;
555*0Sstevel@tonic-gate 	struct lifreq *lifr;
556*0Sstevel@tonic-gate 	struct phyint *pi;
557*0Sstevel@tonic-gate 	struct phyint *next_pi;
558*0Sstevel@tonic-gate 	struct prefix *pr;
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	if (debug & D_IFSCAN)
561*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "Reading interface configuration\n");
562*0Sstevel@tonic-gate 	if (ifsock < 0) {
563*0Sstevel@tonic-gate 		ifsock = socket(AF_INET6, SOCK_DGRAM, 0);
564*0Sstevel@tonic-gate 		if (ifsock < 0) {
565*0Sstevel@tonic-gate 			logperror("initifs: socket");
566*0Sstevel@tonic-gate 			return;
567*0Sstevel@tonic-gate 		}
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 	lifn.lifn_family = AF_INET6;
570*0Sstevel@tonic-gate 	lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY;
571*0Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFNUM, (char *)&lifn) < 0) {
572*0Sstevel@tonic-gate 		logperror("initifs: ioctl (get interface numbers)");
573*0Sstevel@tonic-gate 		return;
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate 	numifs = lifn.lifn_count;
576*0Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct lifreq);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	buf = (char *)malloc(bufsize);
579*0Sstevel@tonic-gate 	if (buf == NULL) {
580*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "initifs: out of memory\n");
581*0Sstevel@tonic-gate 		return;
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	/*
585*0Sstevel@tonic-gate 	 * Mark the interfaces so that we can find phyints and prefixes
586*0Sstevel@tonic-gate 	 * which have disappeared from the kernel.
587*0Sstevel@tonic-gate 	 * if_process will set pr_in_use when it finds the interface
588*0Sstevel@tonic-gate 	 * in the kernel.
589*0Sstevel@tonic-gate 	 */
590*0Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
591*0Sstevel@tonic-gate 		/*
592*0Sstevel@tonic-gate 		 * Before re-examining the state of the interfaces,
593*0Sstevel@tonic-gate 		 * PI_PRESENT should be cleared from pi_kernel_state.
594*0Sstevel@tonic-gate 		 */
595*0Sstevel@tonic-gate 		pi->pi_kernel_state &= ~PI_PRESENT;
596*0Sstevel@tonic-gate 		for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
597*0Sstevel@tonic-gate 			pr->pr_in_use = _B_FALSE;
598*0Sstevel@tonic-gate 		}
599*0Sstevel@tonic-gate 	}
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	lifc.lifc_family = AF_INET6;
602*0Sstevel@tonic-gate 	lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY;
603*0Sstevel@tonic-gate 	lifc.lifc_len = bufsize;
604*0Sstevel@tonic-gate 	lifc.lifc_buf = buf;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFCONF, (char *)&lifc) < 0) {
607*0Sstevel@tonic-gate 		logperror("initifs: ioctl (get interface configuration)");
608*0Sstevel@tonic-gate 		free(buf);
609*0Sstevel@tonic-gate 		return;
610*0Sstevel@tonic-gate 	}
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	lifr = (struct lifreq *)lifc.lifc_req;
613*0Sstevel@tonic-gate 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifr++)
614*0Sstevel@tonic-gate 		if_process(ifsock, lifr->lifr_name, first);
615*0Sstevel@tonic-gate 	free(buf);
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	/*
618*0Sstevel@tonic-gate 	 * Detect phyints that have been removed from the kernel.
619*0Sstevel@tonic-gate 	 * Since we can't recreate it here (would require ifconfig plumb
620*0Sstevel@tonic-gate 	 * logic) we just terminate use of that phyint.
621*0Sstevel@tonic-gate 	 */
622*0Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = next_pi) {
623*0Sstevel@tonic-gate 		next_pi = pi->pi_next;
624*0Sstevel@tonic-gate 		/*
625*0Sstevel@tonic-gate 		 * If interface (still) exists in kernel, set
626*0Sstevel@tonic-gate 		 * pi_state to indicate that.
627*0Sstevel@tonic-gate 		 */
628*0Sstevel@tonic-gate 		if (pi->pi_kernel_state & PI_PRESENT) {
629*0Sstevel@tonic-gate 			pi->pi_state |= PI_PRESENT;
630*0Sstevel@tonic-gate 		}
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 		check_if_removed(pi);
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 	if (show_ifs)
635*0Sstevel@tonic-gate 		phyint_print_all();
636*0Sstevel@tonic-gate }
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate /*
640*0Sstevel@tonic-gate  * Router advertisement state machine. Used for everything but timer
641*0Sstevel@tonic-gate  * events which use advertise_event directly.
642*0Sstevel@tonic-gate  */
643*0Sstevel@tonic-gate void
644*0Sstevel@tonic-gate check_to_advertise(struct phyint *pi, enum adv_events event)
645*0Sstevel@tonic-gate {
646*0Sstevel@tonic-gate 	uint_t delay;
647*0Sstevel@tonic-gate 	enum adv_states old_state = pi->pi_adv_state;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	if (debug & D_STATE) {
650*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d\n",
651*0Sstevel@tonic-gate 		    pi->pi_name, (int)event, (int)old_state);
652*0Sstevel@tonic-gate 	}
653*0Sstevel@tonic-gate 	delay = advertise_event(pi, event, 0);
654*0Sstevel@tonic-gate 	if (delay != TIMER_INFINITY) {
655*0Sstevel@tonic-gate 		/* Make sure the global next event is updated */
656*0Sstevel@tonic-gate 		timer_schedule(delay);
657*0Sstevel@tonic-gate 	}
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	if (debug & D_STATE) {
660*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "check_to_advertise(%s, %d) state %d -> %d\n",
661*0Sstevel@tonic-gate 		    pi->pi_name, (int)event, (int)old_state,
662*0Sstevel@tonic-gate 		    (int)pi->pi_adv_state);
663*0Sstevel@tonic-gate 	}
664*0Sstevel@tonic-gate }
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate /*
667*0Sstevel@tonic-gate  * Router advertisement state machine.
668*0Sstevel@tonic-gate  * Return the number of milliseconds until next timeout (TIMER_INFINITY
669*0Sstevel@tonic-gate  * if never).
670*0Sstevel@tonic-gate  * For the ADV_TIMER event the caller passes in the number of milliseconds
671*0Sstevel@tonic-gate  * since the last timer event in the 'elapsed' parameter.
672*0Sstevel@tonic-gate  */
673*0Sstevel@tonic-gate uint_t
674*0Sstevel@tonic-gate advertise_event(struct phyint *pi, enum adv_events event, uint_t elapsed)
675*0Sstevel@tonic-gate {
676*0Sstevel@tonic-gate 	uint_t delay;
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	if (debug & D_STATE) {
679*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "advertise_event(%s, %d, %d) state %d\n",
680*0Sstevel@tonic-gate 		    pi->pi_name, (int)event, elapsed, (int)pi->pi_adv_state);
681*0Sstevel@tonic-gate 	}
682*0Sstevel@tonic-gate 	check_daemonize();
683*0Sstevel@tonic-gate 	if (!pi->pi_AdvSendAdvertisements)
684*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
685*0Sstevel@tonic-gate 	if (pi->pi_flags & IFF_NORTEXCH) {
686*0Sstevel@tonic-gate 		if (debug & D_PKTOUT) {
687*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "Suppress sending RA packet on %s "
688*0Sstevel@tonic-gate 			    "(no route exchange on interface)\n",
689*0Sstevel@tonic-gate 			    pi->pi_name);
690*0Sstevel@tonic-gate 		}
691*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
692*0Sstevel@tonic-gate 	}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	switch (event) {
695*0Sstevel@tonic-gate 	case ADV_OFF:
696*0Sstevel@tonic-gate 		pi->pi_adv_state = NO_ADV;
697*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	case START_INIT_ADV:
700*0Sstevel@tonic-gate 		if (pi->pi_adv_state == INIT_ADV)
701*0Sstevel@tonic-gate 			return (pi->pi_adv_time_left);
702*0Sstevel@tonic-gate 		pi->pi_adv_count = ND_MAX_INITIAL_RTR_ADVERTISEMENTS;
703*0Sstevel@tonic-gate 		pi->pi_adv_time_left = 0;
704*0Sstevel@tonic-gate 		pi->pi_adv_state = INIT_ADV;
705*0Sstevel@tonic-gate 		break;	/* send advertisement */
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	case START_FINAL_ADV:
708*0Sstevel@tonic-gate 		if (pi->pi_adv_state == NO_ADV)
709*0Sstevel@tonic-gate 			return (TIMER_INFINITY);
710*0Sstevel@tonic-gate 		if (pi->pi_adv_state == FINAL_ADV)
711*0Sstevel@tonic-gate 			return (pi->pi_adv_time_left);
712*0Sstevel@tonic-gate 		pi->pi_adv_count = ND_MAX_FINAL_RTR_ADVERTISEMENTS;
713*0Sstevel@tonic-gate 		pi->pi_adv_time_left = 0;
714*0Sstevel@tonic-gate 		pi->pi_adv_state = FINAL_ADV;
715*0Sstevel@tonic-gate 		break;	/* send advertisement */
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	case RECEIVED_SOLICIT:
718*0Sstevel@tonic-gate 		if (pi->pi_adv_state == NO_ADV)
719*0Sstevel@tonic-gate 			return (TIMER_INFINITY);
720*0Sstevel@tonic-gate 		if (pi->pi_adv_state == SOLICIT_ADV) {
721*0Sstevel@tonic-gate 			if (pi->pi_adv_time_left != 0)
722*0Sstevel@tonic-gate 				return (pi->pi_adv_time_left);
723*0Sstevel@tonic-gate 			break;
724*0Sstevel@tonic-gate 		}
725*0Sstevel@tonic-gate 		delay = GET_RANDOM(0, ND_MAX_RA_DELAY_TIME);
726*0Sstevel@tonic-gate 		if (delay < pi->pi_adv_time_left)
727*0Sstevel@tonic-gate 			pi->pi_adv_time_left = delay;
728*0Sstevel@tonic-gate 		if (pi->pi_adv_time_since_sent < ND_MIN_DELAY_BETWEEN_RAS) {
729*0Sstevel@tonic-gate 			/*
730*0Sstevel@tonic-gate 			 * Send an advertisement (ND_MIN_DELAY_BETWEEN_RAS
731*0Sstevel@tonic-gate 			 * plus random delay) after the previous
732*0Sstevel@tonic-gate 			 * advertisement was sent.
733*0Sstevel@tonic-gate 			 */
734*0Sstevel@tonic-gate 			pi->pi_adv_time_left = delay +
735*0Sstevel@tonic-gate 			    ND_MIN_DELAY_BETWEEN_RAS -
736*0Sstevel@tonic-gate 			    pi->pi_adv_time_since_sent;
737*0Sstevel@tonic-gate 		}
738*0Sstevel@tonic-gate 		pi->pi_adv_state = SOLICIT_ADV;
739*0Sstevel@tonic-gate 		break;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	case ADV_TIMER:
742*0Sstevel@tonic-gate 		if (pi->pi_adv_state == NO_ADV)
743*0Sstevel@tonic-gate 			return (TIMER_INFINITY);
744*0Sstevel@tonic-gate 		/* Decrease time left */
745*0Sstevel@tonic-gate 		if (pi->pi_adv_time_left >= elapsed)
746*0Sstevel@tonic-gate 			pi->pi_adv_time_left -= elapsed;
747*0Sstevel@tonic-gate 		else
748*0Sstevel@tonic-gate 			pi->pi_adv_time_left = 0;
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 		/* Increase time since last advertisement was sent */
751*0Sstevel@tonic-gate 		pi->pi_adv_time_since_sent += elapsed;
752*0Sstevel@tonic-gate 		break;
753*0Sstevel@tonic-gate 	default:
754*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "advertise_event: Unknown event %d\n",
755*0Sstevel@tonic-gate 		    (int)event);
756*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
757*0Sstevel@tonic-gate 	}
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate 	if (pi->pi_adv_time_left != 0)
760*0Sstevel@tonic-gate 		return (pi->pi_adv_time_left);
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate 	/* Send advertisement and calculate next time to send */
763*0Sstevel@tonic-gate 	if (pi->pi_adv_state == FINAL_ADV) {
764*0Sstevel@tonic-gate 		/* Omit the prefixes */
765*0Sstevel@tonic-gate 		advertise(&v6allnodes, pi, _B_TRUE);
766*0Sstevel@tonic-gate 	} else {
767*0Sstevel@tonic-gate 		advertise(&v6allnodes, pi, _B_FALSE);
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 	pi->pi_adv_time_since_sent = 0;
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 	switch (pi->pi_adv_state) {
772*0Sstevel@tonic-gate 	case SOLICIT_ADV:
773*0Sstevel@tonic-gate 		/*
774*0Sstevel@tonic-gate 		 * The solicited advertisement has been sent.
775*0Sstevel@tonic-gate 		 * Revert to periodic advertisements.
776*0Sstevel@tonic-gate 		 */
777*0Sstevel@tonic-gate 		pi->pi_adv_state = REG_ADV;
778*0Sstevel@tonic-gate 		/* FALLTHRU */
779*0Sstevel@tonic-gate 	case REG_ADV:
780*0Sstevel@tonic-gate 		pi->pi_adv_time_left =
781*0Sstevel@tonic-gate 		    GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval,
782*0Sstevel@tonic-gate 		    1000 * pi->pi_MaxRtrAdvInterval);
783*0Sstevel@tonic-gate 		break;
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	case INIT_ADV:
786*0Sstevel@tonic-gate 		if (--pi->pi_adv_count > 0) {
787*0Sstevel@tonic-gate 			delay = GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval,
788*0Sstevel@tonic-gate 			    1000 * pi->pi_MaxRtrAdvInterval);
789*0Sstevel@tonic-gate 			if (delay > ND_MAX_INITIAL_RTR_ADVERT_INTERVAL)
790*0Sstevel@tonic-gate 				delay = ND_MAX_INITIAL_RTR_ADVERT_INTERVAL;
791*0Sstevel@tonic-gate 			pi->pi_adv_time_left = delay;
792*0Sstevel@tonic-gate 		} else {
793*0Sstevel@tonic-gate 			pi->pi_adv_time_left =
794*0Sstevel@tonic-gate 			    GET_RANDOM(1000 * pi->pi_MinRtrAdvInterval,
795*0Sstevel@tonic-gate 			    1000 * pi->pi_MaxRtrAdvInterval);
796*0Sstevel@tonic-gate 			pi->pi_adv_state = REG_ADV;
797*0Sstevel@tonic-gate 		}
798*0Sstevel@tonic-gate 		break;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	case FINAL_ADV:
801*0Sstevel@tonic-gate 		if (--pi->pi_adv_count > 0) {
802*0Sstevel@tonic-gate 			pi->pi_adv_time_left =
803*0Sstevel@tonic-gate 			    ND_MAX_INITIAL_RTR_ADVERT_INTERVAL;
804*0Sstevel@tonic-gate 		} else {
805*0Sstevel@tonic-gate 			pi->pi_adv_state = NO_ADV;
806*0Sstevel@tonic-gate 		}
807*0Sstevel@tonic-gate 		break;
808*0Sstevel@tonic-gate 	}
809*0Sstevel@tonic-gate 	if (pi->pi_adv_state != NO_ADV)
810*0Sstevel@tonic-gate 		return (pi->pi_adv_time_left);
811*0Sstevel@tonic-gate 	else
812*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
813*0Sstevel@tonic-gate }
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate /*
816*0Sstevel@tonic-gate  * Router solicitation state machine. Used for everything but timer
817*0Sstevel@tonic-gate  * events which use solicit_event directly.
818*0Sstevel@tonic-gate  */
819*0Sstevel@tonic-gate void
820*0Sstevel@tonic-gate check_to_solicit(struct phyint *pi, enum solicit_events event)
821*0Sstevel@tonic-gate {
822*0Sstevel@tonic-gate 	uint_t delay;
823*0Sstevel@tonic-gate 	enum solicit_states old_state = pi->pi_sol_state;
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	if (debug & D_STATE) {
826*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d\n",
827*0Sstevel@tonic-gate 		    pi->pi_name, (int)event, (int)old_state);
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 	delay = solicit_event(pi, event, 0);
830*0Sstevel@tonic-gate 	if (delay != TIMER_INFINITY) {
831*0Sstevel@tonic-gate 		/* Make sure the global next event is updated */
832*0Sstevel@tonic-gate 		timer_schedule(delay);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	if (debug & D_STATE) {
836*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "check_to_solicit(%s, %d) state %d -> %d\n",
837*0Sstevel@tonic-gate 		    pi->pi_name, (int)event, (int)old_state,
838*0Sstevel@tonic-gate 		    (int)pi->pi_sol_state);
839*0Sstevel@tonic-gate 	}
840*0Sstevel@tonic-gate }
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate static void
843*0Sstevel@tonic-gate daemonize_ndpd(void)
844*0Sstevel@tonic-gate {
845*0Sstevel@tonic-gate 	FILE *pidfp;
846*0Sstevel@tonic-gate 	mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */
847*0Sstevel@tonic-gate 	struct itimerval it;
848*0Sstevel@tonic-gate 	boolean_t timerval = _B_TRUE;
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 	/*
851*0Sstevel@tonic-gate 	 * Need to get current timer settings so they can be restored
852*0Sstevel@tonic-gate 	 * after the fork(), as the it_value and it_interval values for
853*0Sstevel@tonic-gate 	 * the ITIMER_REAL timer are reset to 0 in the child process.
854*0Sstevel@tonic-gate 	 */
855*0Sstevel@tonic-gate 	if (getitimer(ITIMER_REAL, &it) < 0) {
856*0Sstevel@tonic-gate 		if (debug & D_TIMER)
857*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG,
858*0Sstevel@tonic-gate 			    "daemonize_ndpd: failed to get itimerval\n");
859*0Sstevel@tonic-gate 		timerval = _B_FALSE;
860*0Sstevel@tonic-gate 	}
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	/* Daemonize. */
863*0Sstevel@tonic-gate 	switch (fork()) {
864*0Sstevel@tonic-gate 	case 0:
865*0Sstevel@tonic-gate 		/* Child */
866*0Sstevel@tonic-gate 		break;
867*0Sstevel@tonic-gate 	case -1:
868*0Sstevel@tonic-gate 		logperror("fork");
869*0Sstevel@tonic-gate 		exit(1);
870*0Sstevel@tonic-gate 	default:
871*0Sstevel@tonic-gate 		/* Parent */
872*0Sstevel@tonic-gate 		_exit(0);
873*0Sstevel@tonic-gate 	}
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	/* Store our process id, blow away any existing file if it exists. */
876*0Sstevel@tonic-gate 	if ((pidfp = fopen(PATH_PID, "w")) == NULL) {
877*0Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n",
878*0Sstevel@tonic-gate 		    argv0[0], strerror(errno));
879*0Sstevel@tonic-gate 	} else {
880*0Sstevel@tonic-gate 		(void) fprintf(pidfp, "%ld\n", getpid());
881*0Sstevel@tonic-gate 		(void) fclose(pidfp);
882*0Sstevel@tonic-gate 		(void) chmod(PATH_PID, pidmode);
883*0Sstevel@tonic-gate 	}
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	(void) close(0);
886*0Sstevel@tonic-gate 	(void) close(1);
887*0Sstevel@tonic-gate 	(void) close(2);
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 	(void) chdir("/");
890*0Sstevel@tonic-gate 	(void) open("/dev/null", O_RDWR);
891*0Sstevel@tonic-gate 	(void) dup2(0, 1);
892*0Sstevel@tonic-gate 	(void) dup2(0, 2);
893*0Sstevel@tonic-gate 	(void) setsid();
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	already_daemonized = _B_TRUE;
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 	/*
898*0Sstevel@tonic-gate 	 * Restore timer values, if we were able to save them; if not,
899*0Sstevel@tonic-gate 	 * check and set the right value by calling run_timeouts().
900*0Sstevel@tonic-gate 	 */
901*0Sstevel@tonic-gate 	if (timerval) {
902*0Sstevel@tonic-gate 		if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
903*0Sstevel@tonic-gate 			logperror("daemonize_ndpd: setitimer");
904*0Sstevel@tonic-gate 			exit(2);
905*0Sstevel@tonic-gate 		}
906*0Sstevel@tonic-gate 	} else {
907*0Sstevel@tonic-gate 		run_timeouts();
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate }
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate /*
912*0Sstevel@tonic-gate  * Check to see if the time is right to daemonize.  The right time is when:
913*0Sstevel@tonic-gate  *
914*0Sstevel@tonic-gate  * 1.  We haven't already daemonized.
915*0Sstevel@tonic-gate  * 2.  We are not in debug mode.
916*0Sstevel@tonic-gate  * 3.  All interfaces are marked IFF_NOXMIT.
917*0Sstevel@tonic-gate  * 4.  All non-router interfaces have their prefixes set up and we're
918*0Sstevel@tonic-gate  *     done sending router solicitations on those interfaces without
919*0Sstevel@tonic-gate  *     prefixes.
920*0Sstevel@tonic-gate  */
921*0Sstevel@tonic-gate static void
922*0Sstevel@tonic-gate check_daemonize(void)
923*0Sstevel@tonic-gate {
924*0Sstevel@tonic-gate 	struct phyint		*pi;
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	if (already_daemonized || debug != 0)
927*0Sstevel@tonic-gate 		return;
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
930*0Sstevel@tonic-gate 		if (!(pi->pi_flags & IFF_NOXMIT))
931*0Sstevel@tonic-gate 			break;
932*0Sstevel@tonic-gate 	}
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	/*
935*0Sstevel@tonic-gate 	 * If we can't transmit on any of the interfaces there is no reason
936*0Sstevel@tonic-gate 	 * to hold up progress.
937*0Sstevel@tonic-gate 	 */
938*0Sstevel@tonic-gate 	if (pi == NULL) {
939*0Sstevel@tonic-gate 		daemonize_ndpd();
940*0Sstevel@tonic-gate 		return;
941*0Sstevel@tonic-gate 	}
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 	/* Check all interfaces.  If any are still soliciting, just return. */
944*0Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
945*0Sstevel@tonic-gate 		if (pi->pi_AdvSendAdvertisements ||
946*0Sstevel@tonic-gate 		    !(pi->pi_kernel_state & PI_PRESENT))
947*0Sstevel@tonic-gate 			continue;
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate 		if (pi->pi_sol_state == INIT_SOLICIT)
950*0Sstevel@tonic-gate 			return;
951*0Sstevel@tonic-gate 	}
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	daemonize_ndpd();
954*0Sstevel@tonic-gate }
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate /*
957*0Sstevel@tonic-gate  * Router solicitation state machine.
958*0Sstevel@tonic-gate  * Return the number of milliseconds until next timeout (TIMER_INFINITY
959*0Sstevel@tonic-gate  * if never).
960*0Sstevel@tonic-gate  * For the SOL_TIMER event the caller passes in the number of milliseconds
961*0Sstevel@tonic-gate  * since the last timer event in the 'elapsed' parameter.
962*0Sstevel@tonic-gate  */
963*0Sstevel@tonic-gate uint_t
964*0Sstevel@tonic-gate solicit_event(struct phyint *pi, enum solicit_events event, uint_t elapsed)
965*0Sstevel@tonic-gate {
966*0Sstevel@tonic-gate 	if (debug & D_STATE) {
967*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "solicit_event(%s, %d, %d) state %d\n",
968*0Sstevel@tonic-gate 		    pi->pi_name, (int)event, elapsed, (int)pi->pi_sol_state);
969*0Sstevel@tonic-gate 	}
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	if (pi->pi_AdvSendAdvertisements)
972*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
973*0Sstevel@tonic-gate 	if (pi->pi_flags & IFF_NORTEXCH) {
974*0Sstevel@tonic-gate 		if (debug & D_PKTOUT) {
975*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "Suppress sending RS packet on %s "
976*0Sstevel@tonic-gate 			    "(no route exchange on interface)\n",
977*0Sstevel@tonic-gate 			    pi->pi_name);
978*0Sstevel@tonic-gate 		}
979*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
980*0Sstevel@tonic-gate 	}
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 	switch (event) {
983*0Sstevel@tonic-gate 	case SOLICIT_OFF:
984*0Sstevel@tonic-gate 		pi->pi_sol_state = NO_SOLICIT;
985*0Sstevel@tonic-gate 		check_daemonize();
986*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 	case SOLICIT_DONE:
989*0Sstevel@tonic-gate 		pi->pi_sol_state = DONE_SOLICIT;
990*0Sstevel@tonic-gate 		check_daemonize();
991*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 	case START_INIT_SOLICIT:
994*0Sstevel@tonic-gate 		if (pi->pi_sol_state == INIT_SOLICIT)
995*0Sstevel@tonic-gate 			return (pi->pi_sol_time_left);
996*0Sstevel@tonic-gate 		pi->pi_sol_count = ND_MAX_RTR_SOLICITATIONS;
997*0Sstevel@tonic-gate 		pi->pi_sol_time_left =
998*0Sstevel@tonic-gate 		    GET_RANDOM(0, ND_MAX_RTR_SOLICITATION_DELAY);
999*0Sstevel@tonic-gate 		pi->pi_sol_state = INIT_SOLICIT;
1000*0Sstevel@tonic-gate 		break;
1001*0Sstevel@tonic-gate 
1002*0Sstevel@tonic-gate 	case SOL_TIMER:
1003*0Sstevel@tonic-gate 		if (pi->pi_sol_state == NO_SOLICIT)
1004*0Sstevel@tonic-gate 			return (TIMER_INFINITY);
1005*0Sstevel@tonic-gate 		/* Decrease time left */
1006*0Sstevel@tonic-gate 		if (pi->pi_sol_time_left >= elapsed)
1007*0Sstevel@tonic-gate 			pi->pi_sol_time_left -= elapsed;
1008*0Sstevel@tonic-gate 		else
1009*0Sstevel@tonic-gate 			pi->pi_sol_time_left = 0;
1010*0Sstevel@tonic-gate 		break;
1011*0Sstevel@tonic-gate 	default:
1012*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "solicit_event: Unknown event %d\n",
1013*0Sstevel@tonic-gate 		    (int)event);
1014*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	if (pi->pi_sol_time_left != 0)
1018*0Sstevel@tonic-gate 		return (pi->pi_sol_time_left);
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	/* Send solicitation and calculate next time */
1021*0Sstevel@tonic-gate 	switch (pi->pi_sol_state) {
1022*0Sstevel@tonic-gate 	case INIT_SOLICIT:
1023*0Sstevel@tonic-gate 		solicit(&v6allrouters, pi);
1024*0Sstevel@tonic-gate 		if (--pi->pi_sol_count == 0) {
1025*0Sstevel@tonic-gate 			pi->pi_sol_state = DONE_SOLICIT;
1026*0Sstevel@tonic-gate 			/* check if default route needs to be installed */
1027*0Sstevel@tonic-gate 			check_fallback();
1028*0Sstevel@tonic-gate 			check_daemonize();
1029*0Sstevel@tonic-gate 			return (TIMER_INFINITY);
1030*0Sstevel@tonic-gate 		}
1031*0Sstevel@tonic-gate 		pi->pi_sol_time_left = ND_RTR_SOLICITATION_INTERVAL;
1032*0Sstevel@tonic-gate 		return (pi->pi_sol_time_left);
1033*0Sstevel@tonic-gate 	case NO_SOLICIT:
1034*0Sstevel@tonic-gate 	case DONE_SOLICIT:
1035*0Sstevel@tonic-gate 		return (TIMER_INFINITY);
1036*0Sstevel@tonic-gate 	default:
1037*0Sstevel@tonic-gate 		return (pi->pi_sol_time_left);
1038*0Sstevel@tonic-gate 	}
1039*0Sstevel@tonic-gate }
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate /*
1042*0Sstevel@tonic-gate  * If no interfaces are advertising and have gone to DONE_SOLICIT
1043*0Sstevel@tonic-gate  * and there are no default routers:
1044*0Sstevel@tonic-gate  *	We add an "everything is on-link" default route if there
1045*0Sstevel@tonic-gate  *	is only one non-point-to-point phyint in the kernel.
1046*0Sstevel@tonic-gate  *	XXX What to do when there are multiple phyints?
1047*0Sstevel@tonic-gate  *	XXX The router_delete_onlink checks only operate on one phyint!
1048*0Sstevel@tonic-gate  */
1049*0Sstevel@tonic-gate void
1050*0Sstevel@tonic-gate check_fallback(void)
1051*0Sstevel@tonic-gate {
1052*0Sstevel@tonic-gate 	struct phyint *pi;
1053*0Sstevel@tonic-gate 	struct router *dr;
1054*0Sstevel@tonic-gate 	boolean_t add_default;
1055*0Sstevel@tonic-gate 	int	num_phyints;
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1058*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "check_fallback()\n");
1059*0Sstevel@tonic-gate 	}
1060*0Sstevel@tonic-gate 	add_default = _B_TRUE;
1061*0Sstevel@tonic-gate 	num_phyints = 0;
1062*0Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
1063*0Sstevel@tonic-gate 		if (pi->pi_AdvSendAdvertisements ||
1064*0Sstevel@tonic-gate 		    pi->pi_sol_state != DONE_SOLICIT) {
1065*0Sstevel@tonic-gate 			add_default = _B_FALSE;
1066*0Sstevel@tonic-gate 			break;
1067*0Sstevel@tonic-gate 		}
1068*0Sstevel@tonic-gate 		if (!(pi->pi_kernel_state & PI_PRESENT))
1069*0Sstevel@tonic-gate 			continue;
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 		if (!(pi->pi_flags & IFF_POINTOPOINT))
1072*0Sstevel@tonic-gate 			num_phyints++;
1073*0Sstevel@tonic-gate 		for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) {
1074*0Sstevel@tonic-gate 			if (dr->dr_inkernel) {
1075*0Sstevel@tonic-gate 				add_default = _B_FALSE;
1076*0Sstevel@tonic-gate 				break;
1077*0Sstevel@tonic-gate 			}
1078*0Sstevel@tonic-gate 		}
1079*0Sstevel@tonic-gate 		if (!add_default)
1080*0Sstevel@tonic-gate 			break;
1081*0Sstevel@tonic-gate 	}
1082*0Sstevel@tonic-gate 	if (num_phyints == 1 && add_default) {
1083*0Sstevel@tonic-gate 		if (debug & D_ROUTER) {
1084*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG,
1085*0Sstevel@tonic-gate 			    "check_fallback: create default router\n");
1086*0Sstevel@tonic-gate 		}
1087*0Sstevel@tonic-gate 		for (pi = phyints; pi != NULL; pi = pi->pi_next) {
1088*0Sstevel@tonic-gate 			if (!(pi->pi_kernel_state & PI_PRESENT))
1089*0Sstevel@tonic-gate 				continue;
1090*0Sstevel@tonic-gate 			if (debug & D_ROUTER) {
1091*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "check_fallback: "
1092*0Sstevel@tonic-gate 				    "%s default router\n", pi->pi_name);
1093*0Sstevel@tonic-gate 			}
1094*0Sstevel@tonic-gate 			if (!(pi->pi_flags & IFF_POINTOPOINT))
1095*0Sstevel@tonic-gate 				(void) router_create_onlink(pi);
1096*0Sstevel@tonic-gate 		}
1097*0Sstevel@tonic-gate 	}
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate }
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate /*
1102*0Sstevel@tonic-gate  * Timer mechanism using relative time (in milliseconds) from the
1103*0Sstevel@tonic-gate  * previous timer event. Timers exceeding TIMER_INFINITY milliseconds
1104*0Sstevel@tonic-gate  * will fire after TIMER_INFINITY milliseconds.
1105*0Sstevel@tonic-gate  */
1106*0Sstevel@tonic-gate static uint_t timer_previous;	/* When last SIGALRM occurred */
1107*0Sstevel@tonic-gate static uint_t timer_next;	/* Currently scheduled timeout */
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate static void
1110*0Sstevel@tonic-gate timer_init(void)
1111*0Sstevel@tonic-gate {
1112*0Sstevel@tonic-gate 	timer_previous = getcurrenttime();
1113*0Sstevel@tonic-gate 	timer_next = TIMER_INFINITY;
1114*0Sstevel@tonic-gate 	run_timeouts();
1115*0Sstevel@tonic-gate }
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate /*
1118*0Sstevel@tonic-gate  * Make sure the next SIGALRM occurs delay milliseconds from the current
1119*0Sstevel@tonic-gate  * time if not earlier.
1120*0Sstevel@tonic-gate  * Handles getcurrenttime (32 bit integer holding milliseconds) wraparound
1121*0Sstevel@tonic-gate  * by treating differences greater than 0x80000000 as negative.
1122*0Sstevel@tonic-gate  */
1123*0Sstevel@tonic-gate void
1124*0Sstevel@tonic-gate timer_schedule(uint_t delay)
1125*0Sstevel@tonic-gate {
1126*0Sstevel@tonic-gate 	uint_t now;
1127*0Sstevel@tonic-gate 	struct itimerval itimerval;
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate 	now = getcurrenttime();
1130*0Sstevel@tonic-gate 	if (debug & D_TIMER) {
1131*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "timer_schedule(%u): now %u next %u\n",
1132*0Sstevel@tonic-gate 		    delay, now, timer_next);
1133*0Sstevel@tonic-gate 	}
1134*0Sstevel@tonic-gate 	/* Will this timer occur before the currently scheduled SIGALRM? */
1135*0Sstevel@tonic-gate 	if (delay >= timer_next - now) {
1136*0Sstevel@tonic-gate 		if (debug & D_TIMER) {
1137*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "timer_schedule(%u): no action - "
1138*0Sstevel@tonic-gate 			    "next in %u ms\n",
1139*0Sstevel@tonic-gate 			    delay, timer_next - now);
1140*0Sstevel@tonic-gate 		}
1141*0Sstevel@tonic-gate 		return;
1142*0Sstevel@tonic-gate 	}
1143*0Sstevel@tonic-gate 	if (delay == 0) {
1144*0Sstevel@tonic-gate 		/* Minimum allowed delay */
1145*0Sstevel@tonic-gate 		delay = 1;
1146*0Sstevel@tonic-gate 	}
1147*0Sstevel@tonic-gate 	timer_next = now + delay;
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate 	itimerval.it_value.tv_sec = delay / 1000;
1150*0Sstevel@tonic-gate 	itimerval.it_value.tv_usec = (delay % 1000) * 1000;
1151*0Sstevel@tonic-gate 	itimerval.it_interval.tv_sec = 0;
1152*0Sstevel@tonic-gate 	itimerval.it_interval.tv_usec = 0;
1153*0Sstevel@tonic-gate 	if (debug & D_TIMER) {
1154*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "timer_schedule(%u): sec %lu usec %lu\n",
1155*0Sstevel@tonic-gate 		    delay,
1156*0Sstevel@tonic-gate 		    itimerval.it_value.tv_sec, itimerval.it_value.tv_usec);
1157*0Sstevel@tonic-gate 	}
1158*0Sstevel@tonic-gate 	if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) {
1159*0Sstevel@tonic-gate 		logperror("timer_schedule: setitimer");
1160*0Sstevel@tonic-gate 		exit(2);
1161*0Sstevel@tonic-gate 	}
1162*0Sstevel@tonic-gate }
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate /*
1165*0Sstevel@tonic-gate  * Conditional running of timer. If more than 'minimal_time' millseconds
1166*0Sstevel@tonic-gate  * since the timer routines were last run we run them.
1167*0Sstevel@tonic-gate  * Used when packets arrive.
1168*0Sstevel@tonic-gate  */
1169*0Sstevel@tonic-gate static void
1170*0Sstevel@tonic-gate conditional_run_timeouts(uint_t minimal_time)
1171*0Sstevel@tonic-gate {
1172*0Sstevel@tonic-gate 	uint_t now;
1173*0Sstevel@tonic-gate 	uint_t elapsed;
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 	now = getcurrenttime();
1176*0Sstevel@tonic-gate 	elapsed = now - timer_previous;
1177*0Sstevel@tonic-gate 	if (elapsed > minimal_time) {
1178*0Sstevel@tonic-gate 		if (debug & D_TIMER) {
1179*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "conditional_run_timeouts: "
1180*0Sstevel@tonic-gate 			    "elapsed %d\n", elapsed);
1181*0Sstevel@tonic-gate 		}
1182*0Sstevel@tonic-gate 		run_timeouts();
1183*0Sstevel@tonic-gate 	}
1184*0Sstevel@tonic-gate }
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate /*
1187*0Sstevel@tonic-gate  * Timer has fired.
1188*0Sstevel@tonic-gate  * Determine when the next timer event will occur by asking all
1189*0Sstevel@tonic-gate  * the timer routines.
1190*0Sstevel@tonic-gate  * Should not be called from a timer routine but in some cases this is
1191*0Sstevel@tonic-gate  * done because the code doesn't know that e.g. it was called from
1192*0Sstevel@tonic-gate  * ifconfig_timer(). In this case the nested run_timeouts will just return but
1193*0Sstevel@tonic-gate  * the running run_timeouts will ensure to call all the timer functions by
1194*0Sstevel@tonic-gate  * looping once more.
1195*0Sstevel@tonic-gate  */
1196*0Sstevel@tonic-gate static void
1197*0Sstevel@tonic-gate run_timeouts(void)
1198*0Sstevel@tonic-gate {
1199*0Sstevel@tonic-gate 	uint_t now;
1200*0Sstevel@tonic-gate 	uint_t elapsed;
1201*0Sstevel@tonic-gate 	uint_t next;
1202*0Sstevel@tonic-gate 	uint_t nexti;
1203*0Sstevel@tonic-gate 	struct phyint *pi;
1204*0Sstevel@tonic-gate 	struct phyint *next_pi;
1205*0Sstevel@tonic-gate 	struct prefix *pr;
1206*0Sstevel@tonic-gate 	struct prefix *next_pr;
1207*0Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
1208*0Sstevel@tonic-gate 	struct adv_prefix *next_adv_pr;
1209*0Sstevel@tonic-gate 	struct router *dr;
1210*0Sstevel@tonic-gate 	struct router *next_dr;
1211*0Sstevel@tonic-gate 	static boolean_t timeout_running;
1212*0Sstevel@tonic-gate 	static boolean_t do_retry;
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 	if (timeout_running) {
1215*0Sstevel@tonic-gate 		if (debug & D_TIMER)
1216*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "run_timeouts: nested call\n");
1217*0Sstevel@tonic-gate 		do_retry = _B_TRUE;
1218*0Sstevel@tonic-gate 		return;
1219*0Sstevel@tonic-gate 	}
1220*0Sstevel@tonic-gate 	timeout_running = _B_TRUE;
1221*0Sstevel@tonic-gate retry:
1222*0Sstevel@tonic-gate 	/* How much time since the last time we were called? */
1223*0Sstevel@tonic-gate 	now = getcurrenttime();
1224*0Sstevel@tonic-gate 	elapsed = now - timer_previous;
1225*0Sstevel@tonic-gate 	timer_previous = now;
1226*0Sstevel@tonic-gate 
1227*0Sstevel@tonic-gate 	if (debug & D_TIMER)
1228*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "run_timeouts: elapsed %d\n", elapsed);
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 	next = TIMER_INFINITY;
1231*0Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = next_pi) {
1232*0Sstevel@tonic-gate 		next_pi = pi->pi_next;
1233*0Sstevel@tonic-gate 		nexti = phyint_timer(pi, elapsed);
1234*0Sstevel@tonic-gate 		if (nexti != TIMER_INFINITY && nexti < next)
1235*0Sstevel@tonic-gate 			next = nexti;
1236*0Sstevel@tonic-gate 		if (debug & D_TIMER) {
1237*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "run_timeouts (pi %s): %d -> %u ms\n",
1238*0Sstevel@tonic-gate 			    pi->pi_name, nexti, next);
1239*0Sstevel@tonic-gate 		}
1240*0Sstevel@tonic-gate 		for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) {
1241*0Sstevel@tonic-gate 			next_pr = pr->pr_next;
1242*0Sstevel@tonic-gate 			nexti = prefix_timer(pr, elapsed);
1243*0Sstevel@tonic-gate 			if (nexti != TIMER_INFINITY && nexti < next)
1244*0Sstevel@tonic-gate 				next = nexti;
1245*0Sstevel@tonic-gate 			if (debug & D_TIMER) {
1246*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "run_timeouts (pr %s): "
1247*0Sstevel@tonic-gate 				    "%d -> %u ms\n", pr->pr_name, nexti, next);
1248*0Sstevel@tonic-gate 			}
1249*0Sstevel@tonic-gate 		}
1250*0Sstevel@tonic-gate 		for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL;
1251*0Sstevel@tonic-gate 		    adv_pr = next_adv_pr) {
1252*0Sstevel@tonic-gate 			next_adv_pr = adv_pr->adv_pr_next;
1253*0Sstevel@tonic-gate 			nexti = adv_prefix_timer(adv_pr, elapsed);
1254*0Sstevel@tonic-gate 			if (nexti != TIMER_INFINITY && nexti < next)
1255*0Sstevel@tonic-gate 				next = nexti;
1256*0Sstevel@tonic-gate 			if (debug & D_TIMER) {
1257*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "run_timeouts "
1258*0Sstevel@tonic-gate 				    "(adv pr on %s): %d -> %u ms\n",
1259*0Sstevel@tonic-gate 				    adv_pr->adv_pr_physical->pi_name,
1260*0Sstevel@tonic-gate 				    nexti, next);
1261*0Sstevel@tonic-gate 			}
1262*0Sstevel@tonic-gate 		}
1263*0Sstevel@tonic-gate 		for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) {
1264*0Sstevel@tonic-gate 			next_dr = dr->dr_next;
1265*0Sstevel@tonic-gate 			nexti = router_timer(dr, elapsed);
1266*0Sstevel@tonic-gate 			if (nexti != TIMER_INFINITY && nexti < next)
1267*0Sstevel@tonic-gate 				next = nexti;
1268*0Sstevel@tonic-gate 			if (debug & D_TIMER) {
1269*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "run_timeouts (dr): "
1270*0Sstevel@tonic-gate 				    "%d -> %u ms\n", nexti, next);
1271*0Sstevel@tonic-gate 			}
1272*0Sstevel@tonic-gate 		}
1273*0Sstevel@tonic-gate 		if (pi->pi_TmpAddrsEnabled) {
1274*0Sstevel@tonic-gate 			nexti = tmptoken_timer(pi, elapsed);
1275*0Sstevel@tonic-gate 			if (nexti != TIMER_INFINITY && nexti < next)
1276*0Sstevel@tonic-gate 				next = nexti;
1277*0Sstevel@tonic-gate 			if (debug & D_TIMER) {
1278*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "run_timeouts (tmp on %s): "
1279*0Sstevel@tonic-gate 				    "%d -> %u ms\n", pi->pi_name, nexti, next);
1280*0Sstevel@tonic-gate 			}
1281*0Sstevel@tonic-gate 		}
1282*0Sstevel@tonic-gate 	}
1283*0Sstevel@tonic-gate 	/*
1284*0Sstevel@tonic-gate 	 * Make sure the timer functions are run at least once
1285*0Sstevel@tonic-gate 	 * an hour.
1286*0Sstevel@tonic-gate 	 */
1287*0Sstevel@tonic-gate 	if (next == TIMER_INFINITY)
1288*0Sstevel@tonic-gate 		next = 3600 * 1000;	/* 1 hour */
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 	if (debug & D_TIMER)
1291*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "run_timeouts: %u ms\n", next);
1292*0Sstevel@tonic-gate 	timer_schedule(next);
1293*0Sstevel@tonic-gate 	if (do_retry) {
1294*0Sstevel@tonic-gate 		if (debug & D_TIMER)
1295*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "run_timeouts: retry\n");
1296*0Sstevel@tonic-gate 		do_retry = _B_FALSE;
1297*0Sstevel@tonic-gate 		goto retry;
1298*0Sstevel@tonic-gate 	}
1299*0Sstevel@tonic-gate 	timeout_running = _B_FALSE;
1300*0Sstevel@tonic-gate }
1301*0Sstevel@tonic-gate 
1302*0Sstevel@tonic-gate static int eventpipe_read = -1;	/* Used for synchronous signal delivery */
1303*0Sstevel@tonic-gate static int eventpipe_write = -1;
1304*0Sstevel@tonic-gate 
1305*0Sstevel@tonic-gate /*
1306*0Sstevel@tonic-gate  * Ensure that signals are processed synchronously with the rest of
1307*0Sstevel@tonic-gate  * the code by just writing a one character signal number on the pipe.
1308*0Sstevel@tonic-gate  * The poll loop will pick this up and process the signal event.
1309*0Sstevel@tonic-gate  */
1310*0Sstevel@tonic-gate static void
1311*0Sstevel@tonic-gate sig_handler(int signo)
1312*0Sstevel@tonic-gate {
1313*0Sstevel@tonic-gate 	uchar_t buf = (uchar_t)signo;
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 	if (eventpipe_write == -1) {
1316*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "sig_handler: no pipe\n");
1317*0Sstevel@tonic-gate 		return;
1318*0Sstevel@tonic-gate 	}
1319*0Sstevel@tonic-gate 	if (write(eventpipe_write, &buf, sizeof (buf)) < 0)
1320*0Sstevel@tonic-gate 		logperror("sig_handler: write");
1321*0Sstevel@tonic-gate }
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate /*
1324*0Sstevel@tonic-gate  * Pick up a signal "byte" from the pipe and process it.
1325*0Sstevel@tonic-gate  */
1326*0Sstevel@tonic-gate static void
1327*0Sstevel@tonic-gate in_signal(int fd)
1328*0Sstevel@tonic-gate {
1329*0Sstevel@tonic-gate 	uchar_t buf;
1330*0Sstevel@tonic-gate 	struct phyint *pi;
1331*0Sstevel@tonic-gate 	struct phyint *next_pi;
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate 	switch (read(fd, &buf, sizeof (buf))) {
1334*0Sstevel@tonic-gate 	case -1:
1335*0Sstevel@tonic-gate 		logperror("in_signal: read");
1336*0Sstevel@tonic-gate 		exit(1);
1337*0Sstevel@tonic-gate 		/* NOTREACHED */
1338*0Sstevel@tonic-gate 	case 1:
1339*0Sstevel@tonic-gate 		break;
1340*0Sstevel@tonic-gate 	case 0:
1341*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "in_signal: read eof\n");
1342*0Sstevel@tonic-gate 		exit(1);
1343*0Sstevel@tonic-gate 		/* NOTREACHED */
1344*0Sstevel@tonic-gate 	default:
1345*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "in_signal: read > 1\n");
1346*0Sstevel@tonic-gate 		exit(1);
1347*0Sstevel@tonic-gate 	}
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	if (debug & D_TIMER)
1350*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "in_signal() got %d\n", buf);
1351*0Sstevel@tonic-gate 
1352*0Sstevel@tonic-gate 	switch (buf) {
1353*0Sstevel@tonic-gate 	case SIGALRM:
1354*0Sstevel@tonic-gate 		if (debug & D_TIMER) {
1355*0Sstevel@tonic-gate 			uint_t now = getcurrenttime();
1356*0Sstevel@tonic-gate 
1357*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "in_signal(SIGALRM) delta %u\n",
1358*0Sstevel@tonic-gate 			    now - timer_next);
1359*0Sstevel@tonic-gate 		}
1360*0Sstevel@tonic-gate 		timer_next = TIMER_INFINITY;
1361*0Sstevel@tonic-gate 		run_timeouts();
1362*0Sstevel@tonic-gate 		break;
1363*0Sstevel@tonic-gate 	case SIGHUP:
1364*0Sstevel@tonic-gate 		/* Re-read config file by exec'ing ourselves */
1365*0Sstevel@tonic-gate 		for (pi = phyints; pi != NULL; pi = next_pi) {
1366*0Sstevel@tonic-gate 			next_pi = pi->pi_next;
1367*0Sstevel@tonic-gate 			if (pi->pi_AdvSendAdvertisements)
1368*0Sstevel@tonic-gate 				check_to_advertise(pi, START_FINAL_ADV);
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate 			phyint_delete(pi);
1371*0Sstevel@tonic-gate 		}
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 		/*
1374*0Sstevel@tonic-gate 		 * Prevent fd leaks.  Everything gets re-opened at start-up
1375*0Sstevel@tonic-gate 		 * time.  0, 1, and 2 are closed and re-opened as
1376*0Sstevel@tonic-gate 		 * /dev/null, so we'll leave those open.
1377*0Sstevel@tonic-gate 		 */
1378*0Sstevel@tonic-gate 		closefrom(3);
1379*0Sstevel@tonic-gate 
1380*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "SIGHUP: restart and reread config file\n");
1381*0Sstevel@tonic-gate 		(void) execv(argv0[0], argv0);
1382*0Sstevel@tonic-gate 		(void) unlink(PATH_PID);
1383*0Sstevel@tonic-gate 		_exit(0177);
1384*0Sstevel@tonic-gate 		/* NOTREACHED */
1385*0Sstevel@tonic-gate 	case SIGUSR1:
1386*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "Printing configuration:\n");
1387*0Sstevel@tonic-gate 		phyint_print_all();
1388*0Sstevel@tonic-gate 		break;
1389*0Sstevel@tonic-gate 	case SIGINT:
1390*0Sstevel@tonic-gate 	case SIGTERM:
1391*0Sstevel@tonic-gate 	case SIGQUIT:
1392*0Sstevel@tonic-gate 		for (pi = phyints; pi != NULL; pi = next_pi) {
1393*0Sstevel@tonic-gate 			next_pi = pi->pi_next;
1394*0Sstevel@tonic-gate 			if (pi->pi_AdvSendAdvertisements)
1395*0Sstevel@tonic-gate 				check_to_advertise(pi, START_FINAL_ADV);
1396*0Sstevel@tonic-gate 
1397*0Sstevel@tonic-gate 			phyint_delete(pi);
1398*0Sstevel@tonic-gate 		}
1399*0Sstevel@tonic-gate 		(void) unlink(PATH_PID);
1400*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "terminated\n");
1401*0Sstevel@tonic-gate 		exit(0);
1402*0Sstevel@tonic-gate 		/* NOTREACHED */
1403*0Sstevel@tonic-gate 	case 255:
1404*0Sstevel@tonic-gate 		/*
1405*0Sstevel@tonic-gate 		 * Special "signal" from looback_ra_enqueue.
1406*0Sstevel@tonic-gate 		 * Handle any queued loopback router advertisements.
1407*0Sstevel@tonic-gate 		 */
1408*0Sstevel@tonic-gate 		loopback_ra_dequeue();
1409*0Sstevel@tonic-gate 		break;
1410*0Sstevel@tonic-gate 	default:
1411*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "in_signal: unknown signal: %d\n", buf);
1412*0Sstevel@tonic-gate 	}
1413*0Sstevel@tonic-gate }
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate /*
1416*0Sstevel@tonic-gate  * Create pipe for signal delivery and set up signal handlers.
1417*0Sstevel@tonic-gate  */
1418*0Sstevel@tonic-gate static void
1419*0Sstevel@tonic-gate setup_eventpipe(void)
1420*0Sstevel@tonic-gate {
1421*0Sstevel@tonic-gate 	int fds[2];
1422*0Sstevel@tonic-gate 	struct sigaction act;
1423*0Sstevel@tonic-gate 
1424*0Sstevel@tonic-gate 	if ((pipe(fds)) < 0) {
1425*0Sstevel@tonic-gate 		logperror("setup_eventpipe: pipe");
1426*0Sstevel@tonic-gate 		exit(1);
1427*0Sstevel@tonic-gate 	}
1428*0Sstevel@tonic-gate 	eventpipe_read = fds[0];
1429*0Sstevel@tonic-gate 	eventpipe_write = fds[1];
1430*0Sstevel@tonic-gate 	if (poll_add(eventpipe_read) == -1) {
1431*0Sstevel@tonic-gate 		exit(1);
1432*0Sstevel@tonic-gate 	}
1433*0Sstevel@tonic-gate 	act.sa_handler = sig_handler;
1434*0Sstevel@tonic-gate 	act.sa_flags = SA_RESTART;
1435*0Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &act, NULL);
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 	(void) sigset(SIGHUP, sig_handler);
1438*0Sstevel@tonic-gate 	(void) sigset(SIGUSR1, sig_handler);
1439*0Sstevel@tonic-gate 	(void) sigset(SIGTERM, sig_handler);
1440*0Sstevel@tonic-gate 	(void) sigset(SIGINT, sig_handler);
1441*0Sstevel@tonic-gate 	(void) sigset(SIGQUIT, sig_handler);
1442*0Sstevel@tonic-gate }
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate /*
1445*0Sstevel@tonic-gate  * Create a routing socket for receiving RTM_IFINFO messages and initialize
1446*0Sstevel@tonic-gate  * the routing socket message header and as much of the sockaddrs as possible.
1447*0Sstevel@tonic-gate  */
1448*0Sstevel@tonic-gate static int
1449*0Sstevel@tonic-gate setup_rtsock(void)
1450*0Sstevel@tonic-gate {
1451*0Sstevel@tonic-gate 	int s;
1452*0Sstevel@tonic-gate 	int ret;
1453*0Sstevel@tonic-gate 	char *cp;
1454*0Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate 	s = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
1457*0Sstevel@tonic-gate 	if (s == -1) {
1458*0Sstevel@tonic-gate 		logperror("socket(PF_ROUTE)");
1459*0Sstevel@tonic-gate 		exit(1);
1460*0Sstevel@tonic-gate 	}
1461*0Sstevel@tonic-gate 	ret = fcntl(s, F_SETFL, O_NDELAY|O_NONBLOCK);
1462*0Sstevel@tonic-gate 	if (ret < 0) {
1463*0Sstevel@tonic-gate 		logperror("fcntl(O_NDELAY)");
1464*0Sstevel@tonic-gate 		exit(1);
1465*0Sstevel@tonic-gate 	}
1466*0Sstevel@tonic-gate 	if (poll_add(s) == -1) {
1467*0Sstevel@tonic-gate 		exit(1);
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 	/*
1471*0Sstevel@tonic-gate 	 * Allocate storage for the routing socket message.
1472*0Sstevel@tonic-gate 	 */
1473*0Sstevel@tonic-gate 	rt_msg = (struct rt_msghdr *)malloc(NDP_RTM_MSGLEN);
1474*0Sstevel@tonic-gate 	if (rt_msg == NULL) {
1475*0Sstevel@tonic-gate 		logperror("malloc");
1476*0Sstevel@tonic-gate 		exit(1);
1477*0Sstevel@tonic-gate 	}
1478*0Sstevel@tonic-gate 
1479*0Sstevel@tonic-gate 	/*
1480*0Sstevel@tonic-gate 	 * Initialize the routing socket message by zero-filling it and then
1481*0Sstevel@tonic-gate 	 * setting the fields where are constant through the lifetime of the
1482*0Sstevel@tonic-gate 	 * process.
1483*0Sstevel@tonic-gate 	 */
1484*0Sstevel@tonic-gate 	bzero(rt_msg, NDP_RTM_MSGLEN);
1485*0Sstevel@tonic-gate 	rt_msg->rtm_msglen = NDP_RTM_MSGLEN;
1486*0Sstevel@tonic-gate 	rt_msg->rtm_version = RTM_VERSION;
1487*0Sstevel@tonic-gate 	rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP;
1488*0Sstevel@tonic-gate 	rt_msg->rtm_pid = getpid();
1489*0Sstevel@tonic-gate 	if (rt_msg->rtm_pid < 0) {
1490*0Sstevel@tonic-gate 		logperror("getpid");
1491*0Sstevel@tonic-gate 		exit(1);
1492*0Sstevel@tonic-gate 	}
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate 	/*
1495*0Sstevel@tonic-gate 	 * The RTA_DST sockaddr does not change during the lifetime of the
1496*0Sstevel@tonic-gate 	 * process so it can be completely initialized at this time.
1497*0Sstevel@tonic-gate 	 */
1498*0Sstevel@tonic-gate 	cp = (char *)rt_msg + sizeof (struct rt_msghdr);
1499*0Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)cp;
1500*0Sstevel@tonic-gate 	sin6->sin6_family = AF_INET6;
1501*0Sstevel@tonic-gate 	sin6->sin6_addr = in6addr_any;
1502*0Sstevel@tonic-gate 
1503*0Sstevel@tonic-gate 	/*
1504*0Sstevel@tonic-gate 	 * Initialize the constant portion of the RTA_GATEWAY sockaddr.
1505*0Sstevel@tonic-gate 	 */
1506*0Sstevel@tonic-gate 	cp += sizeof (struct sockaddr_in6);
1507*0Sstevel@tonic-gate 	rta_gateway = (struct sockaddr_in6 *)cp;
1508*0Sstevel@tonic-gate 	rta_gateway->sin6_family = AF_INET6;
1509*0Sstevel@tonic-gate 
1510*0Sstevel@tonic-gate 	/*
1511*0Sstevel@tonic-gate 	 * The RTA_NETMASK sockaddr does not change during the lifetime of the
1512*0Sstevel@tonic-gate 	 * process so it can be completely initialized at this time.
1513*0Sstevel@tonic-gate 	 */
1514*0Sstevel@tonic-gate 	cp += sizeof (struct sockaddr_in6);
1515*0Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)cp;
1516*0Sstevel@tonic-gate 	sin6->sin6_family = AF_INET6;
1517*0Sstevel@tonic-gate 	sin6->sin6_addr = in6addr_any;
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate 	/*
1520*0Sstevel@tonic-gate 	 * Initialize the constant portion of the RTA_IFP sockaddr.
1521*0Sstevel@tonic-gate 	 */
1522*0Sstevel@tonic-gate 	cp += sizeof (struct sockaddr_in6);
1523*0Sstevel@tonic-gate 	rta_ifp = (struct sockaddr_dl *)cp;
1524*0Sstevel@tonic-gate 	rta_ifp->sdl_family = AF_LINK;
1525*0Sstevel@tonic-gate 
1526*0Sstevel@tonic-gate 	return (s);
1527*0Sstevel@tonic-gate }
1528*0Sstevel@tonic-gate 
1529*0Sstevel@tonic-gate /*
1530*0Sstevel@tonic-gate  * Retrieve one routing socket message. If RTM_IFINFO indicates
1531*0Sstevel@tonic-gate  * new phyint do a full scan of the interfaces. If RTM_IFINFO
1532*0Sstevel@tonic-gate  * indicates an existing phyint only scan that phyint and asociated
1533*0Sstevel@tonic-gate  * prefixes.
1534*0Sstevel@tonic-gate  */
1535*0Sstevel@tonic-gate static void
1536*0Sstevel@tonic-gate process_rtsock(int rtsock)
1537*0Sstevel@tonic-gate {
1538*0Sstevel@tonic-gate 	int n;
1539*0Sstevel@tonic-gate #define	MSG_SIZE	2048/8
1540*0Sstevel@tonic-gate 	int64_t msg[MSG_SIZE];
1541*0Sstevel@tonic-gate 	struct rt_msghdr *rtm;
1542*0Sstevel@tonic-gate 	struct if_msghdr *ifm;
1543*0Sstevel@tonic-gate 	struct phyint *pi;
1544*0Sstevel@tonic-gate 	struct prefix *pr;
1545*0Sstevel@tonic-gate 	boolean_t need_initifs = _B_FALSE;
1546*0Sstevel@tonic-gate 	boolean_t need_ifscan = _B_FALSE;
1547*0Sstevel@tonic-gate 	int64_t	ifscan_msg[10][MSG_SIZE];
1548*0Sstevel@tonic-gate 	int ifscan_index = 0;
1549*0Sstevel@tonic-gate 	int i;
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 	/* Empty the rtsock and coealesce all the work that we have */
1552*0Sstevel@tonic-gate 	while (ifscan_index < 10) {
1553*0Sstevel@tonic-gate 		n = read(rtsock, msg, sizeof (msg));
1554*0Sstevel@tonic-gate 		if (n <= 0) {
1555*0Sstevel@tonic-gate 			/* No more messages */
1556*0Sstevel@tonic-gate 			break;
1557*0Sstevel@tonic-gate 		}
1558*0Sstevel@tonic-gate 		rtm = (struct rt_msghdr *)msg;
1559*0Sstevel@tonic-gate 		if (rtm->rtm_version != RTM_VERSION) {
1560*0Sstevel@tonic-gate 			logmsg(LOG_ERR,
1561*0Sstevel@tonic-gate 			    "process_rtsock: version %d not understood\n",
1562*0Sstevel@tonic-gate 			    rtm->rtm_version);
1563*0Sstevel@tonic-gate 			return;
1564*0Sstevel@tonic-gate 		}
1565*0Sstevel@tonic-gate 		switch (rtm->rtm_type) {
1566*0Sstevel@tonic-gate 		case RTM_NEWADDR:
1567*0Sstevel@tonic-gate 		case RTM_DELADDR:
1568*0Sstevel@tonic-gate 			/*
1569*0Sstevel@tonic-gate 			 * Some logical interface has changed - have to scan
1570*0Sstevel@tonic-gate 			 * everything to determine what actually changed.
1571*0Sstevel@tonic-gate 			 */
1572*0Sstevel@tonic-gate 			if (debug & D_IFSCAN) {
1573*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "process_rtsock: "
1574*0Sstevel@tonic-gate 				    "message %d\n", rtm->rtm_type);
1575*0Sstevel@tonic-gate 			}
1576*0Sstevel@tonic-gate 			need_initifs = _B_TRUE;
1577*0Sstevel@tonic-gate 			break;
1578*0Sstevel@tonic-gate 		case RTM_IFINFO:
1579*0Sstevel@tonic-gate 			need_ifscan = _B_TRUE;
1580*0Sstevel@tonic-gate 			(void) memcpy(ifscan_msg[ifscan_index], rtm,
1581*0Sstevel@tonic-gate 			    sizeof (msg));
1582*0Sstevel@tonic-gate 			ifscan_index++;
1583*0Sstevel@tonic-gate 			/* Handled below */
1584*0Sstevel@tonic-gate 			break;
1585*0Sstevel@tonic-gate 		default:
1586*0Sstevel@tonic-gate 			/* Not interesting */
1587*0Sstevel@tonic-gate 			break;
1588*0Sstevel@tonic-gate 		}
1589*0Sstevel@tonic-gate 	}
1590*0Sstevel@tonic-gate 	/*
1591*0Sstevel@tonic-gate 	 * If we do full scan i.e initifs, we don't need to
1592*0Sstevel@tonic-gate 	 * scan a particular interface as we should have
1593*0Sstevel@tonic-gate 	 * done that as part of initifs.
1594*0Sstevel@tonic-gate 	 */
1595*0Sstevel@tonic-gate 	if (need_initifs) {
1596*0Sstevel@tonic-gate 		initifs(_B_FALSE);
1597*0Sstevel@tonic-gate 		return;
1598*0Sstevel@tonic-gate 	}
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 	if (!need_ifscan)
1601*0Sstevel@tonic-gate 		return;
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 	for (i = 0; i < ifscan_index; i++) {
1604*0Sstevel@tonic-gate 		ifm = (struct if_msghdr *)ifscan_msg[i];
1605*0Sstevel@tonic-gate 		if (debug & D_IFSCAN)
1606*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "process_rtsock: index %d\n",
1607*0Sstevel@tonic-gate 			    ifm->ifm_index);
1608*0Sstevel@tonic-gate 
1609*0Sstevel@tonic-gate 		pi = phyint_lookup_on_index(ifm->ifm_index);
1610*0Sstevel@tonic-gate 		if (pi == NULL) {
1611*0Sstevel@tonic-gate 			/*
1612*0Sstevel@tonic-gate 			 * A new physical interface. Do a full scan of the
1613*0Sstevel@tonic-gate 			 * to catch any new logical interfaces.
1614*0Sstevel@tonic-gate 			 */
1615*0Sstevel@tonic-gate 			initifs(_B_FALSE);
1616*0Sstevel@tonic-gate 			return;
1617*0Sstevel@tonic-gate 		}
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 		if (ifm->ifm_flags != pi->pi_flags) {
1620*0Sstevel@tonic-gate 			if (debug & D_IFSCAN) {
1621*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "process_rtsock: clr for "
1622*0Sstevel@tonic-gate 				    "%s old flags 0x%x new flags 0x%x\n",
1623*0Sstevel@tonic-gate 				    pi->pi_name, pi->pi_flags, ifm->ifm_flags);
1624*0Sstevel@tonic-gate 			}
1625*0Sstevel@tonic-gate 		}
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 
1628*0Sstevel@tonic-gate 		/*
1629*0Sstevel@tonic-gate 		 * Mark the interfaces so that we can find phyints and prefixes
1630*0Sstevel@tonic-gate 		 * which have disappeared from the kernel.
1631*0Sstevel@tonic-gate 		 * if_process will set pr_in_use when it finds the
1632*0Sstevel@tonic-gate 		 * interface in the kernel.
1633*0Sstevel@tonic-gate 		 * Before re-examining the state of the interfaces,
1634*0Sstevel@tonic-gate 		 * PI_PRESENT should be cleared from pi_kernel_state.
1635*0Sstevel@tonic-gate 		 */
1636*0Sstevel@tonic-gate 		pi->pi_kernel_state &= ~PI_PRESENT;
1637*0Sstevel@tonic-gate 		for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
1638*0Sstevel@tonic-gate 			pr->pr_in_use = _B_FALSE;
1639*0Sstevel@tonic-gate 		}
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 		if (ifsock < 0) {
1642*0Sstevel@tonic-gate 			ifsock = socket(AF_INET6, SOCK_DGRAM, 0);
1643*0Sstevel@tonic-gate 			if (ifsock < 0) {
1644*0Sstevel@tonic-gate 				logperror("process_rtsock: socket");
1645*0Sstevel@tonic-gate 				return;
1646*0Sstevel@tonic-gate 			}
1647*0Sstevel@tonic-gate 		}
1648*0Sstevel@tonic-gate 		if_process(ifsock, pi->pi_name, _B_FALSE);
1649*0Sstevel@tonic-gate 		for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
1650*0Sstevel@tonic-gate 			if_process(ifsock, pr->pr_name, _B_FALSE);
1651*0Sstevel@tonic-gate 		}
1652*0Sstevel@tonic-gate 		/*
1653*0Sstevel@tonic-gate 		 * If interface (still) exists in kernel, set
1654*0Sstevel@tonic-gate 		 * pi_state to indicate that.
1655*0Sstevel@tonic-gate 		 */
1656*0Sstevel@tonic-gate 		if (pi->pi_kernel_state & PI_PRESENT) {
1657*0Sstevel@tonic-gate 			pi->pi_state |= PI_PRESENT;
1658*0Sstevel@tonic-gate 		}
1659*0Sstevel@tonic-gate 		check_if_removed(pi);
1660*0Sstevel@tonic-gate 		if (show_ifs)
1661*0Sstevel@tonic-gate 			phyint_print_all();
1662*0Sstevel@tonic-gate 	}
1663*0Sstevel@tonic-gate }
1664*0Sstevel@tonic-gate 
1665*0Sstevel@tonic-gate /*
1666*0Sstevel@tonic-gate  * Check whether the address formed by pr->pr_prefix and pi_token
1667*0Sstevel@tonic-gate  * exists in the kernel. Cannot call SIOCTMYADDR/ONLINK as it
1668*0Sstevel@tonic-gate  * does not check for down addresses. This function should not
1669*0Sstevel@tonic-gate  * be called for onlink prefixes.
1670*0Sstevel@tonic-gate  */
1671*0Sstevel@tonic-gate static boolean_t
1672*0Sstevel@tonic-gate is_address_present(struct phyint *pi, struct prefix *pr, uint64_t flags)
1673*0Sstevel@tonic-gate {
1674*0Sstevel@tonic-gate 	int s;
1675*0Sstevel@tonic-gate 	in6_addr_t addr, *token;
1676*0Sstevel@tonic-gate 	int i;
1677*0Sstevel@tonic-gate 	int ret;
1678*0Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
1679*0Sstevel@tonic-gate 
1680*0Sstevel@tonic-gate 	s = socket(AF_INET6, SOCK_DGRAM, 0);
1681*0Sstevel@tonic-gate 	if (s < 0) {
1682*0Sstevel@tonic-gate 		logperror("is_address_present: socket");
1683*0Sstevel@tonic-gate 		/*
1684*0Sstevel@tonic-gate 		 * By returning B_TRUE, we make the caller delete
1685*0Sstevel@tonic-gate 		 * the prefix from the internal table. In the worst
1686*0Sstevel@tonic-gate 		 * case the next RA will create the prefix.
1687*0Sstevel@tonic-gate 		 */
1688*0Sstevel@tonic-gate 		return (_B_TRUE);
1689*0Sstevel@tonic-gate 	}
1690*0Sstevel@tonic-gate 	if (flags & IFF_TEMPORARY)
1691*0Sstevel@tonic-gate 		token = &pi->pi_tmp_token;
1692*0Sstevel@tonic-gate 	else
1693*0Sstevel@tonic-gate 		token = &pi->pi_token;
1694*0Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
1695*0Sstevel@tonic-gate 		/*
1696*0Sstevel@tonic-gate 		 * prefix_create ensures that pr_prefix has all-zero
1697*0Sstevel@tonic-gate 		 * bits after prefixlen.
1698*0Sstevel@tonic-gate 		 */
1699*0Sstevel@tonic-gate 		addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i];
1700*0Sstevel@tonic-gate 	}
1701*0Sstevel@tonic-gate 	(void) memset(&sin6, 0, sizeof (struct sockaddr_in6));
1702*0Sstevel@tonic-gate 	sin6.sin6_family = AF_INET6;
1703*0Sstevel@tonic-gate 	sin6.sin6_addr = addr;
1704*0Sstevel@tonic-gate 	ret = bind(s, (struct sockaddr *)&sin6, sizeof (struct sockaddr_in6));
1705*0Sstevel@tonic-gate 	(void) close(s);
1706*0Sstevel@tonic-gate 	if (ret < 0 && errno == EADDRNOTAVAIL)
1707*0Sstevel@tonic-gate 		return (_B_FALSE);
1708*0Sstevel@tonic-gate 	else
1709*0Sstevel@tonic-gate 		return (_B_TRUE);
1710*0Sstevel@tonic-gate }
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate /*
1713*0Sstevel@tonic-gate  * Look if the phyint or one of its prefixes have been removed from
1714*0Sstevel@tonic-gate  * the kernel and take appropriate action.
1715*0Sstevel@tonic-gate  * Uses {pi,pr}_in_use.
1716*0Sstevel@tonic-gate  */
1717*0Sstevel@tonic-gate static void
1718*0Sstevel@tonic-gate check_if_removed(struct phyint *pi)
1719*0Sstevel@tonic-gate {
1720*0Sstevel@tonic-gate 	struct prefix *pr;
1721*0Sstevel@tonic-gate 	struct prefix *next_pr;
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	/*
1724*0Sstevel@tonic-gate 	 * Detect phyints that have been removed from the kernel.
1725*0Sstevel@tonic-gate 	 * Since we can't recreate it here (would require ifconfig plumb
1726*0Sstevel@tonic-gate 	 * logic) we just terminate use of that phyint.
1727*0Sstevel@tonic-gate 	 */
1728*0Sstevel@tonic-gate 	if (!(pi->pi_kernel_state & PI_PRESENT) &&
1729*0Sstevel@tonic-gate 	    (pi->pi_state & PI_PRESENT)) {
1730*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "Interface %s has been removed from kernel. "
1731*0Sstevel@tonic-gate 		    "in.ndpd will no longer use it\n", pi->pi_name);
1732*0Sstevel@tonic-gate 		/*
1733*0Sstevel@tonic-gate 		 * Clear state so that should the phyint reappear
1734*0Sstevel@tonic-gate 		 * we will start with initial advertisements or
1735*0Sstevel@tonic-gate 		 * solicitations.
1736*0Sstevel@tonic-gate 		 */
1737*0Sstevel@tonic-gate 		phyint_cleanup(pi);
1738*0Sstevel@tonic-gate 	}
1739*0Sstevel@tonic-gate 	/*
1740*0Sstevel@tonic-gate 	 * Detect prefixes which are removed.
1741*0Sstevel@tonic-gate 	 *
1742*0Sstevel@tonic-gate 	 * We remove the prefix in all of the following cases :
1743*0Sstevel@tonic-gate 	 *
1744*0Sstevel@tonic-gate 	 * 1) Static prefixes are not the ones we create. So,
1745*0Sstevel@tonic-gate 	 *    just remove it from our tables.
1746*0Sstevel@tonic-gate 	 *
1747*0Sstevel@tonic-gate 	 * 2) On-link prefixes potentially move to a different
1748*0Sstevel@tonic-gate 	 *    phyint during failover. As it does not have
1749*0Sstevel@tonic-gate 	 *    an address, we can't use the logic in is_address_present
1750*0Sstevel@tonic-gate 	 *    to detect whether it is present in the kernel or not.
1751*0Sstevel@tonic-gate 	 *    Thus when it is manually removed we don't recreate it.
1752*0Sstevel@tonic-gate 	 *
1753*0Sstevel@tonic-gate 	 * 3) If there is a token mis-match and this prefix is not
1754*0Sstevel@tonic-gate 	 *    in the kernel, it means we don't need this prefix on
1755*0Sstevel@tonic-gate 	 *    this interface anymore. It must have been moved to a
1756*0Sstevel@tonic-gate 	 *    different interface by in.mpathd. This normally
1757*0Sstevel@tonic-gate 	 *    happens after a failover followed by a failback (or
1758*0Sstevel@tonic-gate 	 *    another failover) and we re-read the network
1759*0Sstevel@tonic-gate 	 *    configuration. For the failover from A to B, we would
1760*0Sstevel@tonic-gate 	 *    have created state on B about A's address, which will
1761*0Sstevel@tonic-gate 	 *    not be in use after the subsequent failback. So, we
1762*0Sstevel@tonic-gate 	 *    remove that prefix here.
1763*0Sstevel@tonic-gate 	 *
1764*0Sstevel@tonic-gate 	 * 4) If the physical interface is not present, then remove
1765*0Sstevel@tonic-gate 	 *    the prefix. In the cases where we are advertising
1766*0Sstevel@tonic-gate 	 *    prefixes, the state is kept in advertisement prefix and
1767*0Sstevel@tonic-gate 	 *    hence we can delete the prefix.
1768*0Sstevel@tonic-gate 	 *
1769*0Sstevel@tonic-gate 	 * 5) Similar to case (3), when we failover from A to B, the
1770*0Sstevel@tonic-gate 	 *    prefix in A will not be in use as it has been moved to B.
1771*0Sstevel@tonic-gate 	 *    We will delete it from our tables and recreate it when
1772*0Sstevel@tonic-gate 	 *    it fails back. is_address_present makes sure that the
1773*0Sstevel@tonic-gate 	 *    address is still valid in kernel.
1774*0Sstevel@tonic-gate 	 *
1775*0Sstevel@tonic-gate 	 * If none of the above is true, we recreate the prefix as it
1776*0Sstevel@tonic-gate 	 * has been manually removed. We do it only when the interface
1777*0Sstevel@tonic-gate 	 * is not FAILED or INACTIVE or OFFLINE.
1778*0Sstevel@tonic-gate 	 */
1779*0Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) {
1780*0Sstevel@tonic-gate 		next_pr = pr->pr_next;
1781*0Sstevel@tonic-gate 		if (!pr->pr_in_use) {
1782*0Sstevel@tonic-gate 			/* Clear PR_AUTO and PR_ONLINK */
1783*0Sstevel@tonic-gate 			pr->pr_kernel_state &= PR_STATIC;
1784*0Sstevel@tonic-gate 			if ((pr->pr_state & PR_STATIC) ||
1785*0Sstevel@tonic-gate 			    !(pr->pr_state & PR_AUTO) ||
1786*0Sstevel@tonic-gate 			    !(prefix_token_match(pi, pr, pr->pr_flags)) ||
1787*0Sstevel@tonic-gate 			    (!(pi->pi_kernel_state & PI_PRESENT)) ||
1788*0Sstevel@tonic-gate 			    (is_address_present(pi, pr, pr->pr_flags))) {
1789*0Sstevel@tonic-gate 				prefix_delete(pr);
1790*0Sstevel@tonic-gate 			} else if (!(pi->pi_flags &
1791*0Sstevel@tonic-gate 			    (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) &&
1792*0Sstevel@tonic-gate 			    pr->pr_state != pr->pr_kernel_state) {
1793*0Sstevel@tonic-gate 				pr->pr_name[0] = '\0';
1794*0Sstevel@tonic-gate 				logmsg(LOG_INFO, "Prefix manually removed "
1795*0Sstevel@tonic-gate 				    "on %s - recreating it!\n",
1796*0Sstevel@tonic-gate 				    pi->pi_name);
1797*0Sstevel@tonic-gate 				prefix_update_k(pr);
1798*0Sstevel@tonic-gate 			}
1799*0Sstevel@tonic-gate 		}
1800*0Sstevel@tonic-gate 	}
1801*0Sstevel@tonic-gate }
1802*0Sstevel@tonic-gate 
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate /*
1805*0Sstevel@tonic-gate  * Queuing mechanism for router advertisements that are sent by in.ndpd
1806*0Sstevel@tonic-gate  * and that also need to be processed by in.ndpd.
1807*0Sstevel@tonic-gate  * Uses "signal number" 255 to indicate to the main poll loop
1808*0Sstevel@tonic-gate  * that there is something to dequeue and send to incomining_ra().
1809*0Sstevel@tonic-gate  */
1810*0Sstevel@tonic-gate struct raq {
1811*0Sstevel@tonic-gate 	struct raq	*raq_next;
1812*0Sstevel@tonic-gate 	struct phyint	*raq_pi;
1813*0Sstevel@tonic-gate 	int		raq_packetlen;
1814*0Sstevel@tonic-gate 	uchar_t		*raq_packet;
1815*0Sstevel@tonic-gate };
1816*0Sstevel@tonic-gate static struct raq *raq_head = NULL;
1817*0Sstevel@tonic-gate 
1818*0Sstevel@tonic-gate /*
1819*0Sstevel@tonic-gate  * Allocate a struct raq and memory for the packet.
1820*0Sstevel@tonic-gate  * Send signal 255 to have poll dequeue.
1821*0Sstevel@tonic-gate  */
1822*0Sstevel@tonic-gate static void
1823*0Sstevel@tonic-gate loopback_ra_enqueue(struct phyint *pi, struct nd_router_advert *ra, int len)
1824*0Sstevel@tonic-gate {
1825*0Sstevel@tonic-gate 	struct raq *raq;
1826*0Sstevel@tonic-gate 	struct raq **raqp;
1827*0Sstevel@tonic-gate 
1828*0Sstevel@tonic-gate 	if (no_loopback)
1829*0Sstevel@tonic-gate 		return;
1830*0Sstevel@tonic-gate 
1831*0Sstevel@tonic-gate 	if (debug & D_PKTOUT)
1832*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "loopback_ra_enqueue for %s\n", pi->pi_name);
1833*0Sstevel@tonic-gate 
1834*0Sstevel@tonic-gate 	raq = calloc(sizeof (struct raq), 1);
1835*0Sstevel@tonic-gate 	if (raq == NULL) {
1836*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n");
1837*0Sstevel@tonic-gate 		return;
1838*0Sstevel@tonic-gate 	}
1839*0Sstevel@tonic-gate 	raq->raq_packet = malloc(len);
1840*0Sstevel@tonic-gate 	if (raq->raq_packet == NULL) {
1841*0Sstevel@tonic-gate 		free(raq);
1842*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "loopback_ra_enqueue: out of memory\n");
1843*0Sstevel@tonic-gate 		return;
1844*0Sstevel@tonic-gate 	}
1845*0Sstevel@tonic-gate 	bcopy(ra, raq->raq_packet, len);
1846*0Sstevel@tonic-gate 	raq->raq_packetlen = len;
1847*0Sstevel@tonic-gate 	raq->raq_pi = pi;
1848*0Sstevel@tonic-gate 
1849*0Sstevel@tonic-gate 	/* Tail insert */
1850*0Sstevel@tonic-gate 	raqp = &raq_head;
1851*0Sstevel@tonic-gate 	while (*raqp != NULL)
1852*0Sstevel@tonic-gate 		raqp = &((*raqp)->raq_next);
1853*0Sstevel@tonic-gate 	*raqp = raq;
1854*0Sstevel@tonic-gate 
1855*0Sstevel@tonic-gate 	/* Signal for poll loop */
1856*0Sstevel@tonic-gate 	sig_handler(255);
1857*0Sstevel@tonic-gate }
1858*0Sstevel@tonic-gate 
1859*0Sstevel@tonic-gate /*
1860*0Sstevel@tonic-gate  * Dequeue and process all queued advertisements.
1861*0Sstevel@tonic-gate  */
1862*0Sstevel@tonic-gate static void
1863*0Sstevel@tonic-gate loopback_ra_dequeue(void)
1864*0Sstevel@tonic-gate {
1865*0Sstevel@tonic-gate 	struct sockaddr_in6 from = IN6ADDR_LOOPBACK_INIT;
1866*0Sstevel@tonic-gate 	struct raq *raq;
1867*0Sstevel@tonic-gate 
1868*0Sstevel@tonic-gate 	if (debug & D_PKTIN)
1869*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "loopback_ra_dequeue()\n");
1870*0Sstevel@tonic-gate 
1871*0Sstevel@tonic-gate 	while ((raq = raq_head) != NULL) {
1872*0Sstevel@tonic-gate 		raq_head = raq->raq_next;
1873*0Sstevel@tonic-gate 		raq->raq_next = NULL;
1874*0Sstevel@tonic-gate 
1875*0Sstevel@tonic-gate 		if (debug & D_PKTIN) {
1876*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "loopback_ra_dequeue for %s\n",
1877*0Sstevel@tonic-gate 			    raq->raq_pi->pi_name);
1878*0Sstevel@tonic-gate 		}
1879*0Sstevel@tonic-gate 
1880*0Sstevel@tonic-gate 		incoming_ra(raq->raq_pi,
1881*0Sstevel@tonic-gate 		    (struct nd_router_advert *)raq->raq_packet,
1882*0Sstevel@tonic-gate 		    raq->raq_packetlen, &from, _B_TRUE);
1883*0Sstevel@tonic-gate 		free(raq->raq_packet);
1884*0Sstevel@tonic-gate 		free(raq);
1885*0Sstevel@tonic-gate 	}
1886*0Sstevel@tonic-gate }
1887*0Sstevel@tonic-gate 
1888*0Sstevel@tonic-gate 
1889*0Sstevel@tonic-gate static void
1890*0Sstevel@tonic-gate usage(char *cmd)
1891*0Sstevel@tonic-gate {
1892*0Sstevel@tonic-gate 	(void) fprintf(stderr,
1893*0Sstevel@tonic-gate 	    "usage: %s [ -adt ] [-f <config file>]\n", cmd);
1894*0Sstevel@tonic-gate }
1895*0Sstevel@tonic-gate 
1896*0Sstevel@tonic-gate int
1897*0Sstevel@tonic-gate main(int argc, char *argv[])
1898*0Sstevel@tonic-gate {
1899*0Sstevel@tonic-gate 	int i;
1900*0Sstevel@tonic-gate 	struct phyint *pi;
1901*0Sstevel@tonic-gate 	int c;
1902*0Sstevel@tonic-gate 	char *config_file = PATH_NDPD_CONF;
1903*0Sstevel@tonic-gate 	boolean_t file_required = _B_FALSE;
1904*0Sstevel@tonic-gate 
1905*0Sstevel@tonic-gate 	argv0 = argv;
1906*0Sstevel@tonic-gate 	srandom(gethostid());
1907*0Sstevel@tonic-gate 	(void) umask(0022);
1908*0Sstevel@tonic-gate 
1909*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "adD:ntIf:")) != EOF) {
1910*0Sstevel@tonic-gate 		switch (c) {
1911*0Sstevel@tonic-gate 		case 'a':
1912*0Sstevel@tonic-gate 			/*
1913*0Sstevel@tonic-gate 			 * The StatelessAddrConf variable in ndpd.conf, if
1914*0Sstevel@tonic-gate 			 * present, will override this setting.
1915*0Sstevel@tonic-gate 			 */
1916*0Sstevel@tonic-gate 			ifdefaults[I_StatelessAddrConf].cf_value = 0;
1917*0Sstevel@tonic-gate 			break;
1918*0Sstevel@tonic-gate 		case 'd':
1919*0Sstevel@tonic-gate 			debug = D_ALL;
1920*0Sstevel@tonic-gate 			break;
1921*0Sstevel@tonic-gate 		case 'D':
1922*0Sstevel@tonic-gate 			i = strtol((char *)optarg, NULL, 0);
1923*0Sstevel@tonic-gate 			if (i == 0) {
1924*0Sstevel@tonic-gate 				(void) fprintf(stderr, "Bad debug flags: %s\n",
1925*0Sstevel@tonic-gate 				    (char *)optarg);
1926*0Sstevel@tonic-gate 				exit(1);
1927*0Sstevel@tonic-gate 			}
1928*0Sstevel@tonic-gate 			debug |= i;
1929*0Sstevel@tonic-gate 			break;
1930*0Sstevel@tonic-gate 		case 'n':
1931*0Sstevel@tonic-gate 			no_loopback = 1;
1932*0Sstevel@tonic-gate 			break;
1933*0Sstevel@tonic-gate 		case 'I':
1934*0Sstevel@tonic-gate 			show_ifs = 1;
1935*0Sstevel@tonic-gate 			break;
1936*0Sstevel@tonic-gate 		case 't':
1937*0Sstevel@tonic-gate 			debug |= D_PKTIN | D_PKTOUT | D_PKTBAD;
1938*0Sstevel@tonic-gate 			break;
1939*0Sstevel@tonic-gate 		case 'f':
1940*0Sstevel@tonic-gate 			config_file = (char *)optarg;
1941*0Sstevel@tonic-gate 			file_required = _B_TRUE;
1942*0Sstevel@tonic-gate 			break;
1943*0Sstevel@tonic-gate 		case '?':
1944*0Sstevel@tonic-gate 			usage(argv[0]);
1945*0Sstevel@tonic-gate 			exit(1);
1946*0Sstevel@tonic-gate 		}
1947*0Sstevel@tonic-gate 	}
1948*0Sstevel@tonic-gate 
1949*0Sstevel@tonic-gate 	if (parse_config(config_file, file_required) == -1)
1950*0Sstevel@tonic-gate 		exit(2);
1951*0Sstevel@tonic-gate 
1952*0Sstevel@tonic-gate 	if (show_ifs)
1953*0Sstevel@tonic-gate 		phyint_print_all();
1954*0Sstevel@tonic-gate 
1955*0Sstevel@tonic-gate 	if (debug == 0) {
1956*0Sstevel@tonic-gate 		initlog();
1957*0Sstevel@tonic-gate 	}
1958*0Sstevel@tonic-gate 
1959*0Sstevel@tonic-gate 	setup_eventpipe();
1960*0Sstevel@tonic-gate 	rtsock = setup_rtsock();
1961*0Sstevel@tonic-gate 	timer_init();
1962*0Sstevel@tonic-gate 	initifs(_B_TRUE);
1963*0Sstevel@tonic-gate 
1964*0Sstevel@tonic-gate 	check_daemonize();
1965*0Sstevel@tonic-gate 
1966*0Sstevel@tonic-gate 	for (;;) {
1967*0Sstevel@tonic-gate 		if (poll(pollfds, pollfd_num, -1) < 0) {
1968*0Sstevel@tonic-gate 			if (errno == EINTR)
1969*0Sstevel@tonic-gate 				continue;
1970*0Sstevel@tonic-gate 			logperror("main: poll");
1971*0Sstevel@tonic-gate 			exit(1);
1972*0Sstevel@tonic-gate 		}
1973*0Sstevel@tonic-gate 		for (i = 0; i < pollfd_num; i++) {
1974*0Sstevel@tonic-gate 			if (!(pollfds[i].revents & POLLIN))
1975*0Sstevel@tonic-gate 				continue;
1976*0Sstevel@tonic-gate 			if (pollfds[i].fd == eventpipe_read) {
1977*0Sstevel@tonic-gate 				in_signal(eventpipe_read);
1978*0Sstevel@tonic-gate 				break;
1979*0Sstevel@tonic-gate 			}
1980*0Sstevel@tonic-gate 			if (pollfds[i].fd == rtsock) {
1981*0Sstevel@tonic-gate 				process_rtsock(rtsock);
1982*0Sstevel@tonic-gate 				break;
1983*0Sstevel@tonic-gate 			}
1984*0Sstevel@tonic-gate 			/*
1985*0Sstevel@tonic-gate 			 * Run timer routine to advance clock if more than
1986*0Sstevel@tonic-gate 			 * half a second since the clock was advanced.
1987*0Sstevel@tonic-gate 			 * This limits CPU usage under severe packet
1988*0Sstevel@tonic-gate 			 * arrival rates but it creates a slight inaccuracy
1989*0Sstevel@tonic-gate 			 * in the timer mechanism.
1990*0Sstevel@tonic-gate 			 */
1991*0Sstevel@tonic-gate 			conditional_run_timeouts(500U);
1992*0Sstevel@tonic-gate 			for (pi = phyints; pi != NULL; pi = pi->pi_next) {
1993*0Sstevel@tonic-gate 				if (pollfds[i].fd == pi->pi_sock) {
1994*0Sstevel@tonic-gate 					in_data(pi);
1995*0Sstevel@tonic-gate 					break;
1996*0Sstevel@tonic-gate 				}
1997*0Sstevel@tonic-gate 			}
1998*0Sstevel@tonic-gate 		}
1999*0Sstevel@tonic-gate 	}
2000*0Sstevel@tonic-gate 	/* NOTREACHED */
2001*0Sstevel@tonic-gate 	return (0);
2002*0Sstevel@tonic-gate }
2003*0Sstevel@tonic-gate 
2004*0Sstevel@tonic-gate /*
2005*0Sstevel@tonic-gate  * LOGGER
2006*0Sstevel@tonic-gate  */
2007*0Sstevel@tonic-gate 
2008*0Sstevel@tonic-gate static boolean_t logging = _B_FALSE;
2009*0Sstevel@tonic-gate 
2010*0Sstevel@tonic-gate static void
2011*0Sstevel@tonic-gate initlog(void)
2012*0Sstevel@tonic-gate {
2013*0Sstevel@tonic-gate 	logging = _B_TRUE;
2014*0Sstevel@tonic-gate 	openlog("in.ndpd", LOG_PID | LOG_CONS, LOG_DAEMON);
2015*0Sstevel@tonic-gate }
2016*0Sstevel@tonic-gate 
2017*0Sstevel@tonic-gate /* Print the date/time without a trailing carridge return */
2018*0Sstevel@tonic-gate static void
2019*0Sstevel@tonic-gate fprintdate(FILE *file)
2020*0Sstevel@tonic-gate {
2021*0Sstevel@tonic-gate 	char buf[BUFSIZ];
2022*0Sstevel@tonic-gate 	struct tm tms;
2023*0Sstevel@tonic-gate 	time_t now;
2024*0Sstevel@tonic-gate 
2025*0Sstevel@tonic-gate 	now = time(NULL);
2026*0Sstevel@tonic-gate 	(void) localtime_r(&now, &tms);
2027*0Sstevel@tonic-gate 	(void) strftime(buf, sizeof (buf), "%h %d %X", &tms);
2028*0Sstevel@tonic-gate 	(void) fprintf(file, "%s ", buf);
2029*0Sstevel@tonic-gate }
2030*0Sstevel@tonic-gate 
2031*0Sstevel@tonic-gate /* PRINTFLIKE1 */
2032*0Sstevel@tonic-gate void
2033*0Sstevel@tonic-gate logmsg(int level, char *fmt, ...)
2034*0Sstevel@tonic-gate {
2035*0Sstevel@tonic-gate 	va_list ap;
2036*0Sstevel@tonic-gate 	va_start(ap, fmt);
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate 	if (logging) {
2039*0Sstevel@tonic-gate 		vsyslog(level, fmt, ap);
2040*0Sstevel@tonic-gate 	} else {
2041*0Sstevel@tonic-gate 		fprintdate(stderr);
2042*0Sstevel@tonic-gate 		(void) vfprintf(stderr, fmt, ap);
2043*0Sstevel@tonic-gate 	}
2044*0Sstevel@tonic-gate 	va_end(ap);
2045*0Sstevel@tonic-gate }
2046*0Sstevel@tonic-gate 
2047*0Sstevel@tonic-gate void
2048*0Sstevel@tonic-gate logperror(char *str)
2049*0Sstevel@tonic-gate {
2050*0Sstevel@tonic-gate 	if (logging) {
2051*0Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: %m\n", str);
2052*0Sstevel@tonic-gate 	} else {
2053*0Sstevel@tonic-gate 		fprintdate(stderr);
2054*0Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
2055*0Sstevel@tonic-gate 	}
2056*0Sstevel@tonic-gate }
2057*0Sstevel@tonic-gate 
2058*0Sstevel@tonic-gate void
2059*0Sstevel@tonic-gate logperror_pi(struct phyint *pi, char *str)
2060*0Sstevel@tonic-gate {
2061*0Sstevel@tonic-gate 	if (logging) {
2062*0Sstevel@tonic-gate 		syslog(LOG_ERR, "%s (interface %s): %m\n",
2063*0Sstevel@tonic-gate 		    str, pi->pi_name);
2064*0Sstevel@tonic-gate 	} else {
2065*0Sstevel@tonic-gate 		fprintdate(stderr);
2066*0Sstevel@tonic-gate 		(void) fprintf(stderr, "%s (interface %s): %s\n",
2067*0Sstevel@tonic-gate 		    str, pi->pi_name, strerror(errno));
2068*0Sstevel@tonic-gate 	}
2069*0Sstevel@tonic-gate }
2070*0Sstevel@tonic-gate 
2071*0Sstevel@tonic-gate void
2072*0Sstevel@tonic-gate logperror_pr(struct prefix *pr, char *str)
2073*0Sstevel@tonic-gate {
2074*0Sstevel@tonic-gate 	if (logging) {
2075*0Sstevel@tonic-gate 		syslog(LOG_ERR, "%s (prefix %s if %s): %m\n",
2076*0Sstevel@tonic-gate 		    str, pr->pr_name, pr->pr_physical->pi_name);
2077*0Sstevel@tonic-gate 	} else {
2078*0Sstevel@tonic-gate 		fprintdate(stderr);
2079*0Sstevel@tonic-gate 		(void) fprintf(stderr, "%s (prefix %s if %s): %s\n",
2080*0Sstevel@tonic-gate 		    str, pr->pr_name, pr->pr_physical->pi_name,
2081*0Sstevel@tonic-gate 		    strerror(errno));
2082*0Sstevel@tonic-gate 	}
2083*0Sstevel@tonic-gate }
2084