xref: /titanic_51/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c (revision 0a3e1f6cea71f435162ce34b86d7b0ff30795ac6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5842620c7Smeem  * Common Development and Distribution License (the "License").
6842620c7Smeem  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*0a3e1f6cSVasumathi Sundaram  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <unistd.h>
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/stat.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <netinet/in.h>		/* struct in_addr */
307c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h>
317c478bd9Sstevel@tonic-gate #include <signal.h>
327c478bd9Sstevel@tonic-gate #include <sys/socket.h>
337c478bd9Sstevel@tonic-gate #include <net/route.h>
347c478bd9Sstevel@tonic-gate #include <net/if_arp.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <dhcpmsg.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <netdb.h>
397c478bd9Sstevel@tonic-gate #include <fcntl.h>
407c478bd9Sstevel@tonic-gate #include <stdio.h>
41*0a3e1f6cSVasumathi Sundaram #include <dhcp_hostconf.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include "states.h"
447c478bd9Sstevel@tonic-gate #include "agent.h"
457c478bd9Sstevel@tonic-gate #include "interface.h"
467c478bd9Sstevel@tonic-gate #include "util.h"
477c478bd9Sstevel@tonic-gate #include "packet.h"
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * this file contains utility functions that have no real better home
517c478bd9Sstevel@tonic-gate  * of their own.  they can largely be broken into six categories:
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  *  o  conversion functions -- functions to turn integers into strings,
547c478bd9Sstevel@tonic-gate  *     or to convert between units of a similar measure.
557c478bd9Sstevel@tonic-gate  *
56d04ccbb3Scarlsonj  *  o  time and timer functions -- functions to handle time measurement
57d04ccbb3Scarlsonj  *     and events.
58d04ccbb3Scarlsonj  *
597c478bd9Sstevel@tonic-gate  *  o  ipc-related functions -- functions to simplify the generation of
607c478bd9Sstevel@tonic-gate  *     ipc messages to the agent's clients.
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  *  o  signal-related functions -- functions to clean up the agent when
637c478bd9Sstevel@tonic-gate  *     it receives a signal.
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  *  o  routing table manipulation functions
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  *  o  true miscellany -- anything else
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * pkt_type_to_string(): stringifies a packet type
727c478bd9Sstevel@tonic-gate  *
73d04ccbb3Scarlsonj  *   input: uchar_t: a DHCP packet type value, RFC 2131 or 3315
74d04ccbb3Scarlsonj  *	    boolean_t: B_TRUE if IPv6
757c478bd9Sstevel@tonic-gate  *  output: const char *: the stringified packet type
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate const char *
79d04ccbb3Scarlsonj pkt_type_to_string(uchar_t type, boolean_t isv6)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate 	/*
82d04ccbb3Scarlsonj 	 * note: the ordering in these arrays allows direct indexing of the
83d04ccbb3Scarlsonj 	 *	 table based on the RFC packet type value passed in.
847c478bd9Sstevel@tonic-gate 	 */
857c478bd9Sstevel@tonic-gate 
86d04ccbb3Scarlsonj 	static const char *v4types[] = {
877c478bd9Sstevel@tonic-gate 		"BOOTP",  "DISCOVER", "OFFER",   "REQUEST", "DECLINE",
887c478bd9Sstevel@tonic-gate 		"ACK",    "NAK",      "RELEASE", "INFORM"
897c478bd9Sstevel@tonic-gate 	};
90d04ccbb3Scarlsonj 	static const char *v6types[] = {
91d04ccbb3Scarlsonj 		NULL, "SOLICIT", "ADVERTISE", "REQUEST",
92d04ccbb3Scarlsonj 		"CONFIRM", "RENEW", "REBIND", "REPLY",
93d04ccbb3Scarlsonj 		"RELEASE", "DECLINE", "RECONFIGURE", "INFORMATION-REQUEST",
94d04ccbb3Scarlsonj 		"RELAY-FORW", "RELAY-REPL"
95d04ccbb3Scarlsonj 	};
967c478bd9Sstevel@tonic-gate 
97d04ccbb3Scarlsonj 	if (isv6) {
98d04ccbb3Scarlsonj 		if (type >= sizeof (v6types) / sizeof (*v6types) ||
99d04ccbb3Scarlsonj 		    v6types[type] == NULL)
1007c478bd9Sstevel@tonic-gate 			return ("<unknown>");
101d04ccbb3Scarlsonj 		else
102d04ccbb3Scarlsonj 			return (v6types[type]);
103d04ccbb3Scarlsonj 	} else {
104d04ccbb3Scarlsonj 		if (type >= sizeof (v4types) / sizeof (*v4types) ||
105d04ccbb3Scarlsonj 		    v4types[type] == NULL)
106d04ccbb3Scarlsonj 			return ("<unknown>");
107d04ccbb3Scarlsonj 		else
108d04ccbb3Scarlsonj 			return (v4types[type]);
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * monosec_to_string(): converts a monosec_t into a date string
1147c478bd9Sstevel@tonic-gate  *
1157c478bd9Sstevel@tonic-gate  *   input: monosec_t: the monosec_t to convert
1167c478bd9Sstevel@tonic-gate  *  output: const char *: the corresponding date string
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate const char *
1207c478bd9Sstevel@tonic-gate monosec_to_string(monosec_t monosec)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	time_t	time = monosec_to_time(monosec);
1237c478bd9Sstevel@tonic-gate 	char	*time_string = ctime(&time);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/* strip off the newline -- ugh, why, why, why.. */
1267c478bd9Sstevel@tonic-gate 	time_string[strlen(time_string) - 1] = '\0';
1277c478bd9Sstevel@tonic-gate 	return (time_string);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * monosec(): returns a monotonically increasing time in seconds that
1327c478bd9Sstevel@tonic-gate  *            is not affected by stime(2) or adjtime(2).
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  *   input: void
1357c478bd9Sstevel@tonic-gate  *  output: monosec_t: the number of seconds since some time in the past
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate monosec_t
1397c478bd9Sstevel@tonic-gate monosec(void)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	return (gethrtime() / NANOSEC);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  * monosec_to_time(): converts a monosec_t into real wall time
1467c478bd9Sstevel@tonic-gate  *
1477c478bd9Sstevel@tonic-gate  *    input: monosec_t: the absolute monosec_t to convert
1487c478bd9Sstevel@tonic-gate  *   output: time_t: the absolute time that monosec_t represents in wall time
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate time_t
1527c478bd9Sstevel@tonic-gate monosec_to_time(monosec_t abs_monosec)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	return (abs_monosec - monosec()) + time(NULL);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
158d04ccbb3Scarlsonj  * hrtime_to_monosec(): converts a hrtime_t to monosec_t
1597c478bd9Sstevel@tonic-gate  *
160d04ccbb3Scarlsonj  *    input: hrtime_t: the time to convert
161d04ccbb3Scarlsonj  *   output: monosec_t: the time in monosec_t
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate 
164d04ccbb3Scarlsonj monosec_t
165d04ccbb3Scarlsonj hrtime_to_monosec(hrtime_t hrtime)
1667c478bd9Sstevel@tonic-gate {
167d04ccbb3Scarlsonj 	return (hrtime / NANOSEC);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * print_server_msg(): prints a message from a DHCP server
1727c478bd9Sstevel@tonic-gate  *
173d04ccbb3Scarlsonj  *   input: dhcp_smach_t *: the state machine the message is associated with
174d04ccbb3Scarlsonj  *	    const char *: the string to display
175d04ccbb3Scarlsonj  *	    uint_t: length of string
1767c478bd9Sstevel@tonic-gate  *  output: void
1777c478bd9Sstevel@tonic-gate  */
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate void
180d04ccbb3Scarlsonj print_server_msg(dhcp_smach_t *dsmp, const char *msg, uint_t msglen)
1817c478bd9Sstevel@tonic-gate {
182d04ccbb3Scarlsonj 	if (msglen > 0) {
183d04ccbb3Scarlsonj 		dhcpmsg(MSG_INFO, "%s: message from server: %.*s",
184d04ccbb3Scarlsonj 		    dsmp->dsm_name, msglen, msg);
185d04ccbb3Scarlsonj 	}
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * alrm_exit(): Signal handler for SIGARLM. terminates grandparent.
1907c478bd9Sstevel@tonic-gate  *
1917c478bd9Sstevel@tonic-gate  *    input: int: signal the handler was called with.
1927c478bd9Sstevel@tonic-gate  *
1937c478bd9Sstevel@tonic-gate  *   output: void
1947c478bd9Sstevel@tonic-gate  */
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate static void
1977c478bd9Sstevel@tonic-gate alrm_exit(int sig)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	int exitval;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (sig == SIGALRM && grandparent != 0)
2027c478bd9Sstevel@tonic-gate 		exitval = EXIT_SUCCESS;
2037c478bd9Sstevel@tonic-gate 	else
2047c478bd9Sstevel@tonic-gate 		exitval = EXIT_FAILURE;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	_exit(exitval);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate  * daemonize(): daemonizes the process
2117c478bd9Sstevel@tonic-gate  *
2127c478bd9Sstevel@tonic-gate  *   input: void
2137c478bd9Sstevel@tonic-gate  *  output: int: 1 on success, 0 on failure
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate int
2177c478bd9Sstevel@tonic-gate daemonize(void)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * We've found that adoption takes sufficiently long that
2217c478bd9Sstevel@tonic-gate 	 * a dhcpinfo run after dhcpagent -a is started may occur
2227c478bd9Sstevel@tonic-gate 	 * before the agent is ready to process the request.
2237c478bd9Sstevel@tonic-gate 	 * The result is an error message and an unhappy user.
2247c478bd9Sstevel@tonic-gate 	 *
2257c478bd9Sstevel@tonic-gate 	 * The initial process now sleeps for DHCP_ADOPT_SLEEP,
2267c478bd9Sstevel@tonic-gate 	 * unless interrupted by a SIGALRM, in which case it
2277c478bd9Sstevel@tonic-gate 	 * exits immediately. This has the effect that the
2287c478bd9Sstevel@tonic-gate 	 * grandparent doesn't exit until the dhcpagent is ready
2297c478bd9Sstevel@tonic-gate 	 * to process requests. This defers the the balance of
2307c478bd9Sstevel@tonic-gate 	 * the system start-up script processing until the
2317c478bd9Sstevel@tonic-gate 	 * dhcpagent is ready to field requests.
2327c478bd9Sstevel@tonic-gate 	 *
2337c478bd9Sstevel@tonic-gate 	 * grandparent is only set for the adopt case; other
2347c478bd9Sstevel@tonic-gate 	 * cases do not require the wait.
2357c478bd9Sstevel@tonic-gate 	 */
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if (grandparent != 0)
2387c478bd9Sstevel@tonic-gate 		(void) signal(SIGALRM, alrm_exit);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	switch (fork()) {
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	case -1:
2437c478bd9Sstevel@tonic-gate 		return (0);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	case  0:
2467c478bd9Sstevel@tonic-gate 		if (grandparent != 0)
2477c478bd9Sstevel@tonic-gate 			(void) signal(SIGALRM, SIG_DFL);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * setsid() makes us lose our controlling terminal,
2517c478bd9Sstevel@tonic-gate 		 * and become both a session leader and a process
2527c478bd9Sstevel@tonic-gate 		 * group leader.
2537c478bd9Sstevel@tonic-gate 		 */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 		(void) setsid();
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		/*
2587c478bd9Sstevel@tonic-gate 		 * under POSIX, a session leader can accidentally
2597c478bd9Sstevel@tonic-gate 		 * (through open(2)) acquire a controlling terminal if
2607c478bd9Sstevel@tonic-gate 		 * it does not have one.  just to be safe, fork again
2617c478bd9Sstevel@tonic-gate 		 * so we are not a session leader.
2627c478bd9Sstevel@tonic-gate 		 */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		switch (fork()) {
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		case -1:
2677c478bd9Sstevel@tonic-gate 			return (0);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 		case 0:
2707c478bd9Sstevel@tonic-gate 			(void) signal(SIGHUP, SIG_IGN);
2717c478bd9Sstevel@tonic-gate 			(void) chdir("/");
2727c478bd9Sstevel@tonic-gate 			(void) umask(022);
2737c478bd9Sstevel@tonic-gate 			closefrom(0);
2747c478bd9Sstevel@tonic-gate 			break;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		default:
2777c478bd9Sstevel@tonic-gate 			_exit(EXIT_SUCCESS);
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 		break;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	default:
2827c478bd9Sstevel@tonic-gate 		if (grandparent != 0) {
2837c478bd9Sstevel@tonic-gate 			(void) signal(SIGCHLD, SIG_IGN);
284d04ccbb3Scarlsonj 			/*
285d04ccbb3Scarlsonj 			 * Note that we're not the agent here, so the DHCP
286d04ccbb3Scarlsonj 			 * logging subsystem hasn't been configured yet.
287d04ccbb3Scarlsonj 			 */
288d04ccbb3Scarlsonj 			syslog(LOG_DEBUG | LOG_DAEMON, "dhcpagent: daemonize: "
2897c478bd9Sstevel@tonic-gate 			    "waiting for adoption to complete.");
2907c478bd9Sstevel@tonic-gate 			if (sleep(DHCP_ADOPT_SLEEP) == 0) {
291d04ccbb3Scarlsonj 				syslog(LOG_WARNING | LOG_DAEMON,
292d04ccbb3Scarlsonj 				    "dhcpagent: daemonize: timed out awaiting "
293d04ccbb3Scarlsonj 				    "adoption.");
2947c478bd9Sstevel@tonic-gate 			}
295d04ccbb3Scarlsonj 			syslog(LOG_DEBUG | LOG_DAEMON, "dhcpagent: daemonize: "
296d04ccbb3Scarlsonj 			    "wait finished");
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 		_exit(EXIT_SUCCESS);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	return (1);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * update_default_route(): update the interface's default route
3067c478bd9Sstevel@tonic-gate  *
3077c478bd9Sstevel@tonic-gate  *   input: int: the type of message; either RTM_ADD or RTM_DELETE
3087c478bd9Sstevel@tonic-gate  *	    struct in_addr: the default gateway to use
3097c478bd9Sstevel@tonic-gate  *	    const char *: the interface associated with the route
3107c478bd9Sstevel@tonic-gate  *	    int: any additional flags (besides RTF_STATIC and RTF_GATEWAY)
311d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
3127c478bd9Sstevel@tonic-gate  */
3137c478bd9Sstevel@tonic-gate 
314d04ccbb3Scarlsonj static boolean_t
315cfb9c9abScarlsonj update_default_route(uint32_t ifindex, int type, struct in_addr *gateway_nbo,
3167c478bd9Sstevel@tonic-gate     int flags)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	struct {
3197c478bd9Sstevel@tonic-gate 		struct rt_msghdr	rm_mh;
3207c478bd9Sstevel@tonic-gate 		struct sockaddr_in	rm_dst;
3217c478bd9Sstevel@tonic-gate 		struct sockaddr_in	rm_gw;
3227c478bd9Sstevel@tonic-gate 		struct sockaddr_in	rm_mask;
3237c478bd9Sstevel@tonic-gate 		struct sockaddr_dl	rm_ifp;
3247c478bd9Sstevel@tonic-gate 	} rtmsg;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	(void) memset(&rtmsg, 0, sizeof (rtmsg));
3277c478bd9Sstevel@tonic-gate 	rtmsg.rm_mh.rtm_version = RTM_VERSION;
3287c478bd9Sstevel@tonic-gate 	rtmsg.rm_mh.rtm_msglen	= sizeof (rtmsg);
3297c478bd9Sstevel@tonic-gate 	rtmsg.rm_mh.rtm_type	= type;
3307c478bd9Sstevel@tonic-gate 	rtmsg.rm_mh.rtm_pid	= getpid();
3317c478bd9Sstevel@tonic-gate 	rtmsg.rm_mh.rtm_flags	= RTF_GATEWAY | RTF_STATIC | flags;
3327c478bd9Sstevel@tonic-gate 	rtmsg.rm_mh.rtm_addrs	= RTA_GATEWAY | RTA_DST | RTA_NETMASK | RTA_IFP;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	rtmsg.rm_gw.sin_family	= AF_INET;
3357c478bd9Sstevel@tonic-gate 	rtmsg.rm_gw.sin_addr	= *gateway_nbo;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	rtmsg.rm_dst.sin_family = AF_INET;
3387c478bd9Sstevel@tonic-gate 	rtmsg.rm_dst.sin_addr.s_addr = htonl(INADDR_ANY);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	rtmsg.rm_mask.sin_family = AF_INET;
3417c478bd9Sstevel@tonic-gate 	rtmsg.rm_mask.sin_addr.s_addr = htonl(0);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	rtmsg.rm_ifp.sdl_family	= AF_LINK;
344cfb9c9abScarlsonj 	rtmsg.rm_ifp.sdl_index	= ifindex;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	return (write(rtsock_fd, &rtmsg, sizeof (rtmsg)) == sizeof (rtmsg));
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * add_default_route(): add the default route to the given gateway
3517c478bd9Sstevel@tonic-gate  *
3527c478bd9Sstevel@tonic-gate  *   input: const char *: the name of the interface associated with the route
3537c478bd9Sstevel@tonic-gate  *	    struct in_addr: the default gateway to add
354d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE otherwise
3557c478bd9Sstevel@tonic-gate  */
3567c478bd9Sstevel@tonic-gate 
357d04ccbb3Scarlsonj boolean_t
358cfb9c9abScarlsonj add_default_route(uint32_t ifindex, struct in_addr *gateway_nbo)
3597c478bd9Sstevel@tonic-gate {
360cfb9c9abScarlsonj 	return (update_default_route(ifindex, RTM_ADD, gateway_nbo, RTF_UP));
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate  * del_default_route(): deletes the default route to the given gateway
3657c478bd9Sstevel@tonic-gate  *
3667c478bd9Sstevel@tonic-gate  *   input: const char *: the name of the interface associated with the route
3677c478bd9Sstevel@tonic-gate  *	    struct in_addr: if not INADDR_ANY, the default gateway to remove
368d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate 
371d04ccbb3Scarlsonj boolean_t
372cfb9c9abScarlsonj del_default_route(uint32_t ifindex, struct in_addr *gateway_nbo)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	if (gateway_nbo->s_addr == htonl(INADDR_ANY)) /* no router */
375d04ccbb3Scarlsonj 		return (B_TRUE);
3767c478bd9Sstevel@tonic-gate 
377cfb9c9abScarlsonj 	return (update_default_route(ifindex, RTM_DELETE, gateway_nbo, 0));
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate /*
381d04ccbb3Scarlsonj  * inactivity_shutdown(): shuts down agent if there are no state machines left
382d04ccbb3Scarlsonj  *			  to manage
3837c478bd9Sstevel@tonic-gate  *
3847c478bd9Sstevel@tonic-gate  *   input: iu_tq_t *: unused
3857c478bd9Sstevel@tonic-gate  *	    void *: unused
3867c478bd9Sstevel@tonic-gate  *  output: void
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /* ARGSUSED */
3907c478bd9Sstevel@tonic-gate void
3917c478bd9Sstevel@tonic-gate inactivity_shutdown(iu_tq_t *tqp, void *arg)
3927c478bd9Sstevel@tonic-gate {
393d04ccbb3Scarlsonj 	if (smach_count() > 0)	/* shouldn't happen, but... */
3947c478bd9Sstevel@tonic-gate 		return;
3957c478bd9Sstevel@tonic-gate 
396d04ccbb3Scarlsonj 	dhcpmsg(MSG_VERBOSE, "inactivity_shutdown: timed out");
397d04ccbb3Scarlsonj 
3987c478bd9Sstevel@tonic-gate 	iu_stop_handling_events(eh, DHCP_REASON_INACTIVITY, NULL, NULL);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * graceful_shutdown(): shuts down the agent gracefully
4037c478bd9Sstevel@tonic-gate  *
4047c478bd9Sstevel@tonic-gate  *   input: int: the signal that caused graceful_shutdown to be called
4057c478bd9Sstevel@tonic-gate  *  output: void
4067c478bd9Sstevel@tonic-gate  */
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate void
4097c478bd9Sstevel@tonic-gate graceful_shutdown(int sig)
4107c478bd9Sstevel@tonic-gate {
411842620c7Smeem 	iu_stop_handling_events(eh, (sig == SIGTERM ? DHCP_REASON_TERMINATE :
412842620c7Smeem 	    DHCP_REASON_SIGNAL), drain_script, NULL);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  * bind_sock(): binds a socket to a given IP address and port number
4177c478bd9Sstevel@tonic-gate  *
4187c478bd9Sstevel@tonic-gate  *   input: int: the socket to bind
4197c478bd9Sstevel@tonic-gate  *	    in_port_t: the port number to bind to, host byte order
4207c478bd9Sstevel@tonic-gate  *	    in_addr_t: the address to bind to, host byte order
421d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate 
424d04ccbb3Scarlsonj boolean_t
4257c478bd9Sstevel@tonic-gate bind_sock(int fd, in_port_t port_hbo, in_addr_t addr_hbo)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	struct sockaddr_in	sin;
4287c478bd9Sstevel@tonic-gate 	int			on = 1;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	(void) memset(&sin, 0, sizeof (struct sockaddr_in));
4317c478bd9Sstevel@tonic-gate 	sin.sin_family = AF_INET;
4327c478bd9Sstevel@tonic-gate 	sin.sin_port   = htons(port_hbo);
4337c478bd9Sstevel@tonic-gate 	sin.sin_addr.s_addr = htonl(addr_hbo);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	(void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (int));
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	return (bind(fd, (struct sockaddr *)&sin, sizeof (sin)) == 0);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate /*
441d04ccbb3Scarlsonj  * bind_sock_v6(): binds a socket to a given IP address and port number
442d04ccbb3Scarlsonj  *
443d04ccbb3Scarlsonj  *   input: int: the socket to bind
444d04ccbb3Scarlsonj  *	    in_port_t: the port number to bind to, host byte order
445d04ccbb3Scarlsonj  *	    in6_addr_t: the address to bind to, network byte order
446d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE on failure
447d04ccbb3Scarlsonj  */
448d04ccbb3Scarlsonj 
449d04ccbb3Scarlsonj boolean_t
450d04ccbb3Scarlsonj bind_sock_v6(int fd, in_port_t port_hbo, const in6_addr_t *addr_nbo)
451d04ccbb3Scarlsonj {
452d04ccbb3Scarlsonj 	struct sockaddr_in6	sin6;
453d04ccbb3Scarlsonj 	int			on = 1;
454d04ccbb3Scarlsonj 
455d04ccbb3Scarlsonj 	(void) memset(&sin6, 0, sizeof (struct sockaddr_in6));
456d04ccbb3Scarlsonj 	sin6.sin6_family = AF_INET6;
457d04ccbb3Scarlsonj 	sin6.sin6_port   = htons(port_hbo);
458d04ccbb3Scarlsonj 	if (addr_nbo != NULL) {
459d04ccbb3Scarlsonj 		(void) memcpy(&sin6.sin6_addr, addr_nbo,
460d04ccbb3Scarlsonj 		    sizeof (sin6.sin6_addr));
461d04ccbb3Scarlsonj 	}
462d04ccbb3Scarlsonj 
463d04ccbb3Scarlsonj 	(void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (int));
464d04ccbb3Scarlsonj 
465d04ccbb3Scarlsonj 	return (bind(fd, (struct sockaddr *)&sin6, sizeof (sin6)) == 0);
466d04ccbb3Scarlsonj }
467d04ccbb3Scarlsonj 
468d04ccbb3Scarlsonj /*
4697c478bd9Sstevel@tonic-gate  * valid_hostname(): check whether a string is a valid hostname
4707c478bd9Sstevel@tonic-gate  *
4717c478bd9Sstevel@tonic-gate  *   input: const char *: the string to verify as a hostname
4727c478bd9Sstevel@tonic-gate  *  output: boolean_t: B_TRUE if the string is a valid hostname
4737c478bd9Sstevel@tonic-gate  *
4747c478bd9Sstevel@tonic-gate  * Note that we accept both host names beginning with a digit and
4757c478bd9Sstevel@tonic-gate  * those containing hyphens.  Neither is strictly legal according
4767c478bd9Sstevel@tonic-gate  * to the RFCs, but both are in common practice, so we endeavour
4777c478bd9Sstevel@tonic-gate  * to not break what customers are using.
4787c478bd9Sstevel@tonic-gate  */
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate static boolean_t
4817c478bd9Sstevel@tonic-gate valid_hostname(const char *hostname)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate 	unsigned int i;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	for (i = 0; hostname[i] != '\0'; i++) {
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		if (isalpha(hostname[i]) || isdigit(hostname[i]) ||
4887c478bd9Sstevel@tonic-gate 		    (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0)))
4897c478bd9Sstevel@tonic-gate 			continue;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 		return (B_FALSE);
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	return (i > 0);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate /*
4987c478bd9Sstevel@tonic-gate  * iffile_to_hostname(): return the hostname contained on a line of the form
4997c478bd9Sstevel@tonic-gate  *
5007c478bd9Sstevel@tonic-gate  * [ ^I]*inet[ ^I]+hostname[\n]*\0
5017c478bd9Sstevel@tonic-gate  *
5027c478bd9Sstevel@tonic-gate  * in the file located at the specified path
5037c478bd9Sstevel@tonic-gate  *
5047c478bd9Sstevel@tonic-gate  *   input: const char *: the path of the file to look in for the hostname
5057c478bd9Sstevel@tonic-gate  *  output: const char *: the hostname at that path, or NULL on failure
5067c478bd9Sstevel@tonic-gate  */
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate #define	IFLINE_MAX	1024	/* maximum length of a hostname.<if> line */
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate const char *
5117c478bd9Sstevel@tonic-gate iffile_to_hostname(const char *path)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	FILE		*fp;
5147c478bd9Sstevel@tonic-gate 	static char	ifline[IFLINE_MAX];
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	fp = fopen(path, "r");
5177c478bd9Sstevel@tonic-gate 	if (fp == NULL)
5187c478bd9Sstevel@tonic-gate 		return (NULL);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	/*
5217c478bd9Sstevel@tonic-gate 	 * /etc/hostname.<if> may contain multiple ifconfig commands, but each
5227c478bd9Sstevel@tonic-gate 	 * such command is on a separate line (see the "while read ifcmds" code
5237c478bd9Sstevel@tonic-gate 	 * in /etc/init.d/inetinit).  Thus we will read the file a line at a
5247c478bd9Sstevel@tonic-gate 	 * time, searching for a line of the form
5257c478bd9Sstevel@tonic-gate 	 *
5267c478bd9Sstevel@tonic-gate 	 * [ ^I]*inet[ ^I]+hostname[\n]*\0
5277c478bd9Sstevel@tonic-gate 	 *
5287c478bd9Sstevel@tonic-gate 	 * extract the host name from it, and check it for validity.
5297c478bd9Sstevel@tonic-gate 	 */
5307c478bd9Sstevel@tonic-gate 	while (fgets(ifline, sizeof (ifline), fp) != NULL) {
5317c478bd9Sstevel@tonic-gate 		char *p;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		if ((p = strstr(ifline, "inet")) != NULL) {
5347c478bd9Sstevel@tonic-gate 			if ((p != ifline) && !isspace(p[-1])) {
5357c478bd9Sstevel@tonic-gate 				(void) fclose(fp);
5367c478bd9Sstevel@tonic-gate 				return (NULL);
5377c478bd9Sstevel@tonic-gate 			}
5387c478bd9Sstevel@tonic-gate 			p += 4;	/* skip over "inet" and expect spaces or tabs */
5397c478bd9Sstevel@tonic-gate 			if ((*p == '\n') || (*p == '\0')) {
5407c478bd9Sstevel@tonic-gate 				(void) fclose(fp);
5417c478bd9Sstevel@tonic-gate 				return (NULL);
5427c478bd9Sstevel@tonic-gate 			}
5437c478bd9Sstevel@tonic-gate 			if (isspace(*p)) {
5447c478bd9Sstevel@tonic-gate 				char *nlptr;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 				/* no need to read more of the file */
5477c478bd9Sstevel@tonic-gate 				(void) fclose(fp);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 				while (isspace(*p))
5507c478bd9Sstevel@tonic-gate 					p++;
5517c478bd9Sstevel@tonic-gate 				if ((nlptr = strrchr(p, '\n')) != NULL)
5527c478bd9Sstevel@tonic-gate 					*nlptr = '\0';
5537c478bd9Sstevel@tonic-gate 				if (strlen(p) > MAXHOSTNAMELEN) {
5547c478bd9Sstevel@tonic-gate 					dhcpmsg(MSG_WARNING,
5557c478bd9Sstevel@tonic-gate 					    "iffile_to_hostname:"
5567c478bd9Sstevel@tonic-gate 					    " host name too long");
5577c478bd9Sstevel@tonic-gate 					return (NULL);
5587c478bd9Sstevel@tonic-gate 				}
5597c478bd9Sstevel@tonic-gate 				if (valid_hostname(p)) {
5607c478bd9Sstevel@tonic-gate 					return (p);
5617c478bd9Sstevel@tonic-gate 				} else {
5627c478bd9Sstevel@tonic-gate 					dhcpmsg(MSG_WARNING,
5637c478bd9Sstevel@tonic-gate 					    "iffile_to_hostname:"
5647c478bd9Sstevel@tonic-gate 					    " host name not valid");
5657c478bd9Sstevel@tonic-gate 					return (NULL);
5667c478bd9Sstevel@tonic-gate 				}
5677c478bd9Sstevel@tonic-gate 			} else {
5687c478bd9Sstevel@tonic-gate 				(void) fclose(fp);
5697c478bd9Sstevel@tonic-gate 				return (NULL);
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 		}
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
5757c478bd9Sstevel@tonic-gate 	return (NULL);
5767c478bd9Sstevel@tonic-gate }
577d04ccbb3Scarlsonj 
578d04ccbb3Scarlsonj /*
579d04ccbb3Scarlsonj  * init_timer(): set up a DHCP timer
580d04ccbb3Scarlsonj  *
581d04ccbb3Scarlsonj  *   input: dhcp_timer_t *: the timer to set up
582d04ccbb3Scarlsonj  *  output: void
583d04ccbb3Scarlsonj  */
584d04ccbb3Scarlsonj 
585d04ccbb3Scarlsonj void
586d04ccbb3Scarlsonj init_timer(dhcp_timer_t *dt, lease_t startval)
587d04ccbb3Scarlsonj {
588d04ccbb3Scarlsonj 	dt->dt_id = -1;
589d04ccbb3Scarlsonj 	dt->dt_start = startval;
590d04ccbb3Scarlsonj }
591d04ccbb3Scarlsonj 
592d04ccbb3Scarlsonj /*
593d04ccbb3Scarlsonj  * cancel_timer(): cancel a DHCP timer
594d04ccbb3Scarlsonj  *
595d04ccbb3Scarlsonj  *   input: dhcp_timer_t *: the timer to cancel
596d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE otherwise
597d04ccbb3Scarlsonj  */
598d04ccbb3Scarlsonj 
599d04ccbb3Scarlsonj boolean_t
600d04ccbb3Scarlsonj cancel_timer(dhcp_timer_t *dt)
601d04ccbb3Scarlsonj {
602d04ccbb3Scarlsonj 	if (dt->dt_id == -1)
603d04ccbb3Scarlsonj 		return (B_TRUE);
604d04ccbb3Scarlsonj 
605d04ccbb3Scarlsonj 	if (iu_cancel_timer(tq, dt->dt_id, NULL) == 1) {
606d04ccbb3Scarlsonj 		dt->dt_id = -1;
607d04ccbb3Scarlsonj 		return (B_TRUE);
608d04ccbb3Scarlsonj 	}
609d04ccbb3Scarlsonj 
610d04ccbb3Scarlsonj 	return (B_FALSE);
611d04ccbb3Scarlsonj }
612d04ccbb3Scarlsonj 
613d04ccbb3Scarlsonj /*
614d04ccbb3Scarlsonj  * schedule_timer(): schedule a DHCP timer.  Note that it must not be already
615d04ccbb3Scarlsonj  *		     running, and that we can't cancel here.  If it were, and
616d04ccbb3Scarlsonj  *		     we did, we'd leak a reference to the callback argument.
617d04ccbb3Scarlsonj  *
618d04ccbb3Scarlsonj  *   input: dhcp_timer_t *: the timer to schedule
619d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE on success, B_FALSE otherwise
620d04ccbb3Scarlsonj  */
621d04ccbb3Scarlsonj 
622d04ccbb3Scarlsonj boolean_t
623d04ccbb3Scarlsonj schedule_timer(dhcp_timer_t *dt, iu_tq_callback_t *cbfunc, void *arg)
624d04ccbb3Scarlsonj {
625d04ccbb3Scarlsonj 	if (dt->dt_id != -1)
626d04ccbb3Scarlsonj 		return (B_FALSE);
627d04ccbb3Scarlsonj 	dt->dt_id = iu_schedule_timer(tq, dt->dt_start, cbfunc, arg);
628d04ccbb3Scarlsonj 	return (dt->dt_id != -1);
629d04ccbb3Scarlsonj }
630d04ccbb3Scarlsonj 
631d04ccbb3Scarlsonj /*
632d04ccbb3Scarlsonj  * dhcpv6_status_code(): report on a DHCPv6 status code found in an option
633d04ccbb3Scarlsonj  *			 buffer.
634d04ccbb3Scarlsonj  *
635d04ccbb3Scarlsonj  *   input: const dhcpv6_option_t *: pointer to option
636d04ccbb3Scarlsonj  *	    uint_t: option length
637d04ccbb3Scarlsonj  *	    const char **: error string (nul-terminated)
638d04ccbb3Scarlsonj  *	    const char **: message from server (unterminated)
639d04ccbb3Scarlsonj  *	    uint_t *: length of server message
640d04ccbb3Scarlsonj  *  output: int: -1 on error, or >= 0 for a DHCPv6 status code
641d04ccbb3Scarlsonj  */
642d04ccbb3Scarlsonj 
643d04ccbb3Scarlsonj int
644d04ccbb3Scarlsonj dhcpv6_status_code(const dhcpv6_option_t *d6o, uint_t olen, const char **estr,
645d04ccbb3Scarlsonj     const char **msg, uint_t *msglenp)
646d04ccbb3Scarlsonj {
647d04ccbb3Scarlsonj 	uint16_t status;
648d04ccbb3Scarlsonj 	static const char *v6_status[] = {
649d04ccbb3Scarlsonj 		NULL,
650d04ccbb3Scarlsonj 		"Unknown reason",
651d04ccbb3Scarlsonj 		"Server has no addresses available",
652d04ccbb3Scarlsonj 		"Client record unavailable",
653d04ccbb3Scarlsonj 		"Prefix inappropriate for link",
654d04ccbb3Scarlsonj 		"Client must use multicast",
655d04ccbb3Scarlsonj 		"No prefix available"
656d04ccbb3Scarlsonj 	};
657d04ccbb3Scarlsonj 	static char sbuf[32];
658d04ccbb3Scarlsonj 
659d04ccbb3Scarlsonj 	*estr = "";
660d04ccbb3Scarlsonj 	*msg = "";
661d04ccbb3Scarlsonj 	*msglenp = 0;
662d04ccbb3Scarlsonj 	if (d6o == NULL)
663d04ccbb3Scarlsonj 		return (0);
664d04ccbb3Scarlsonj 	olen -= sizeof (*d6o);
665d04ccbb3Scarlsonj 	if (olen < 2) {
666d04ccbb3Scarlsonj 		*estr = "garbled status code";
667d04ccbb3Scarlsonj 		return (-1);
668d04ccbb3Scarlsonj 	}
669d04ccbb3Scarlsonj 
670d04ccbb3Scarlsonj 	*msg = (const char *)(d6o + 1) + 2;
671d04ccbb3Scarlsonj 	*msglenp = olen - 2;
672d04ccbb3Scarlsonj 
673d04ccbb3Scarlsonj 	(void) memcpy(&status, d6o + 1, sizeof (status));
674d04ccbb3Scarlsonj 	status = ntohs(status);
675d04ccbb3Scarlsonj 	if (status > 0) {
676d04ccbb3Scarlsonj 		if (status > DHCPV6_STAT_NOPREFIX) {
677d04ccbb3Scarlsonj 			(void) snprintf(sbuf, sizeof (sbuf), "status %u",
678d04ccbb3Scarlsonj 			    status);
679d04ccbb3Scarlsonj 			*estr = sbuf;
680d04ccbb3Scarlsonj 		} else {
681d04ccbb3Scarlsonj 			*estr = v6_status[status];
682d04ccbb3Scarlsonj 		}
683d04ccbb3Scarlsonj 	}
684d04ccbb3Scarlsonj 	return (status);
685d04ccbb3Scarlsonj }
686*0a3e1f6cSVasumathi Sundaram 
687*0a3e1f6cSVasumathi Sundaram void
688*0a3e1f6cSVasumathi Sundaram write_lease_to_hostconf(dhcp_smach_t *dsmp)
689*0a3e1f6cSVasumathi Sundaram {
690*0a3e1f6cSVasumathi Sundaram 	PKT_LIST *plp[2];
691*0a3e1f6cSVasumathi Sundaram 	const char *hcfile;
692*0a3e1f6cSVasumathi Sundaram 
693*0a3e1f6cSVasumathi Sundaram 	hcfile = ifname_to_hostconf(dsmp->dsm_name, dsmp->dsm_isv6);
694*0a3e1f6cSVasumathi Sundaram 	plp[0] = dsmp->dsm_ack;
695*0a3e1f6cSVasumathi Sundaram 	plp[1] = dsmp->dsm_orig_ack;
696*0a3e1f6cSVasumathi Sundaram 	if (write_hostconf(dsmp->dsm_name, plp, 2,
697*0a3e1f6cSVasumathi Sundaram 	    monosec_to_time(dsmp->dsm_curstart_monosec),
698*0a3e1f6cSVasumathi Sundaram 	    dsmp->dsm_isv6) != -1) {
699*0a3e1f6cSVasumathi Sundaram 		dhcpmsg(MSG_DEBUG, "wrote lease to %s", hcfile);
700*0a3e1f6cSVasumathi Sundaram 	} else if (errno == EROFS) {
701*0a3e1f6cSVasumathi Sundaram 		dhcpmsg(MSG_DEBUG, "%s is on a read-only file "
702*0a3e1f6cSVasumathi Sundaram 		    "system; not saving lease", hcfile);
703*0a3e1f6cSVasumathi Sundaram 	} else {
704*0a3e1f6cSVasumathi Sundaram 		dhcpmsg(MSG_ERR, "cannot write %s (reboot will "
705*0a3e1f6cSVasumathi Sundaram 		    "not use cached configuration)", hcfile);
706*0a3e1f6cSVasumathi Sundaram 	}
707*0a3e1f6cSVasumathi Sundaram }
708