17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*d04ccbb3Scarlsonj  * Common Development and Distribution License (the "License").
6*d04ccbb3Scarlsonj  * 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*d04ccbb3Scarlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <sys/socket.h>
327c478bd9Sstevel@tonic-gate #include <netinet/in.h>
337c478bd9Sstevel@tonic-gate #include <net/if.h>
347c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <time.h>
387c478bd9Sstevel@tonic-gate #include <string.h>			/* memcpy */
397c478bd9Sstevel@tonic-gate #include <fcntl.h>
407c478bd9Sstevel@tonic-gate #include <limits.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "dhcp_hostconf.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static void		relativize_time(DHCP_OPT *, time_t, time_t);
45*d04ccbb3Scarlsonj static void		relativize_v6(uint32_t *, time_t, time_t);
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * ifname_to_hostconf(): converts an interface name into a hostconf file for
497c478bd9Sstevel@tonic-gate  *			 that interface
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
52*d04ccbb3Scarlsonj  *	    boolean_t: B_TRUE if using DHCPv6
537c478bd9Sstevel@tonic-gate  *  output: char *: the hostconf filename
547c478bd9Sstevel@tonic-gate  *    note: uses an internal static buffer (not threadsafe)
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate char *
58*d04ccbb3Scarlsonj ifname_to_hostconf(const char *ifname, boolean_t isv6)
597c478bd9Sstevel@tonic-gate {
60*d04ccbb3Scarlsonj 	static char filename[sizeof (DHCP_HOSTCONF_TMPL6) + LIFNAMSIZ];
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	(void) snprintf(filename, sizeof (filename), "%s%s%s",
63*d04ccbb3Scarlsonj 	    DHCP_HOSTCONF_PREFIX, ifname,
64*d04ccbb3Scarlsonj 	    isv6 ? DHCP_HOSTCONF_SUFFIX6 : DHCP_HOSTCONF_SUFFIX);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	return (filename);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * remove_hostconf(): removes an interface.dhc file
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
73*d04ccbb3Scarlsonj  *	    boolean_t: B_TRUE if using DHCPv6
747c478bd9Sstevel@tonic-gate  *  output: int: 0 if the file is removed, -1 if it can't be removed
757c478bd9Sstevel@tonic-gate  *          (errno is set)
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate int
79*d04ccbb3Scarlsonj remove_hostconf(const char *ifname, boolean_t isv6)
807c478bd9Sstevel@tonic-gate {
81*d04ccbb3Scarlsonj 	return (unlink(ifname_to_hostconf(ifname, isv6)));
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * read_hostconf(): reads the contents of an <if>.dhc file into a PKT_LIST
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
887c478bd9Sstevel@tonic-gate  *	    PKT_LIST **: a pointer to a PKT_LIST * to store the info in
897c478bd9Sstevel@tonic-gate  *	    uint_t: the length of the list of PKT_LISTs
90*d04ccbb3Scarlsonj  *	    boolean_t: B_TRUE if using DHCPv6
91*d04ccbb3Scarlsonj  *  output: int: >0 if the file is read and loaded into the PKT_LIST *
927c478bd9Sstevel@tonic-gate  *	    successfully, -1 otherwise (errno is set)
937c478bd9Sstevel@tonic-gate  *    note: the PKT and PKT_LISTs are dynamically allocated here
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate int
97*d04ccbb3Scarlsonj read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen,
98*d04ccbb3Scarlsonj     boolean_t isv6)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	PKT_LIST	*plp = NULL;
1017c478bd9Sstevel@tonic-gate 	PKT		*pkt = NULL;
1027c478bd9Sstevel@tonic-gate 	int		fd;
1037c478bd9Sstevel@tonic-gate 	time_t		orig_time, current_time = time(NULL);
1047c478bd9Sstevel@tonic-gate 	uint32_t	lease;
1057c478bd9Sstevel@tonic-gate 	uint32_t	magic;
1067c478bd9Sstevel@tonic-gate 	int		pcnt = 0;
1077c478bd9Sstevel@tonic-gate 	int		retval;
1087c478bd9Sstevel@tonic-gate 
109*d04ccbb3Scarlsonj 	fd = open(ifname_to_hostconf(ifname, isv6), O_RDONLY);
1107c478bd9Sstevel@tonic-gate 	if (fd == -1)
1117c478bd9Sstevel@tonic-gate 		return (-1);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
1147c478bd9Sstevel@tonic-gate 		goto failure;
1157c478bd9Sstevel@tonic-gate 
116*d04ccbb3Scarlsonj 	if (magic != (isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC))
1177c478bd9Sstevel@tonic-gate 		goto failure;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time))
1207c478bd9Sstevel@tonic-gate 		goto failure;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/*
123*d04ccbb3Scarlsonj 	 * read the packet back in from disk, and for v4, run it through
124*d04ccbb3Scarlsonj 	 * dhcp_options_scan(). note that we use calloc() because
125*d04ccbb3Scarlsonj 	 * dhcp_options_scan() relies on the structure being zeroed.
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	for (pcnt = 0; pcnt < plplen; pcnt++) {
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 		plp = NULL;
1317c478bd9Sstevel@tonic-gate 		pkt = NULL;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		if ((plp = calloc(1, sizeof (PKT_LIST))) == NULL)
1347c478bd9Sstevel@tonic-gate 			goto failure;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 		retval = read(fd, &plp->len, sizeof (plp->len));
1377c478bd9Sstevel@tonic-gate 		if (retval == 0 && pcnt != 0) {
1387c478bd9Sstevel@tonic-gate 			/*
1397c478bd9Sstevel@tonic-gate 			 * Reached end of file on a boundary, but after
1407c478bd9Sstevel@tonic-gate 			 * we've read at least one packet, so we consider
1417c478bd9Sstevel@tonic-gate 			 * this successful, allowing us to use files from
1427c478bd9Sstevel@tonic-gate 			 * older versions of the agent happily.
1437c478bd9Sstevel@tonic-gate 			 */
1447c478bd9Sstevel@tonic-gate 			free(plp);
1457c478bd9Sstevel@tonic-gate 			break;
1467c478bd9Sstevel@tonic-gate 		} else if (retval != sizeof (plp->len))
1477c478bd9Sstevel@tonic-gate 			goto failure;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 		if ((pkt = malloc(plp->len)) == NULL)
1507c478bd9Sstevel@tonic-gate 			goto failure;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 		if (read(fd, pkt, plp->len) != plp->len)
1537c478bd9Sstevel@tonic-gate 			goto failure;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		plp->pkt = pkt;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		plpp[pcnt] = plp;
1587c478bd9Sstevel@tonic-gate 
159*d04ccbb3Scarlsonj 		if (!isv6 && dhcp_options_scan(plp, B_TRUE) != 0)
1607c478bd9Sstevel@tonic-gate 			goto failure;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		/*
1637c478bd9Sstevel@tonic-gate 		 * First packet used to validate that we're interested,
1647c478bd9Sstevel@tonic-gate 		 * the rest are presumed to be historical reference and
1657c478bd9Sstevel@tonic-gate 		 * are not relativized
1667c478bd9Sstevel@tonic-gate 		 */
1677c478bd9Sstevel@tonic-gate 		if (pcnt == 0)
1687c478bd9Sstevel@tonic-gate 			continue;
1697c478bd9Sstevel@tonic-gate 
170*d04ccbb3Scarlsonj 		if (isv6) {
171*d04ccbb3Scarlsonj 			dhcpv6_option_t	d6o;
172*d04ccbb3Scarlsonj 			dhcpv6_ia_na_t	d6in;
173*d04ccbb3Scarlsonj 			dhcpv6_iaaddr_t	d6ia;
174*d04ccbb3Scarlsonj 			uchar_t		*opts, *optmax, *subomax;
1757c478bd9Sstevel@tonic-gate 
176*d04ccbb3Scarlsonj 			/*
177*d04ccbb3Scarlsonj 			 * Loop over contents of the packet to find the address
178*d04ccbb3Scarlsonj 			 * options.
179*d04ccbb3Scarlsonj 			 */
180*d04ccbb3Scarlsonj 			opts = (uchar_t *)pkt + sizeof (dhcpv6_message_t);
181*d04ccbb3Scarlsonj 			optmax = (uchar_t *)pkt + plp->len;
182*d04ccbb3Scarlsonj 			while (opts + sizeof (d6o) <= optmax) {
183*d04ccbb3Scarlsonj 
184*d04ccbb3Scarlsonj 				/*
185*d04ccbb3Scarlsonj 				 * Extract option header and make sure option
186*d04ccbb3Scarlsonj 				 * is intact.
187*d04ccbb3Scarlsonj 				 */
188*d04ccbb3Scarlsonj 				(void) memcpy(&d6o, opts, sizeof (d6o));
189*d04ccbb3Scarlsonj 				d6o.d6o_code = ntohs(d6o.d6o_code);
190*d04ccbb3Scarlsonj 				d6o.d6o_len = ntohs(d6o.d6o_len);
191*d04ccbb3Scarlsonj 				subomax = opts + sizeof (d6o) + d6o.d6o_len;
192*d04ccbb3Scarlsonj 				if (subomax > optmax)
193*d04ccbb3Scarlsonj 					break;
194*d04ccbb3Scarlsonj 
195*d04ccbb3Scarlsonj 				/*
196*d04ccbb3Scarlsonj 				 * If this isn't an option that contains
197*d04ccbb3Scarlsonj 				 * address or prefix leases, then skip over it.
198*d04ccbb3Scarlsonj 				 */
199*d04ccbb3Scarlsonj 				if (d6o.d6o_code != DHCPV6_OPT_IA_NA &&
200*d04ccbb3Scarlsonj 				    d6o.d6o_code != DHCPV6_OPT_IA_TA &&
201*d04ccbb3Scarlsonj 				    d6o.d6o_code != DHCPV6_OPT_IA_PD) {
202*d04ccbb3Scarlsonj 					opts = subomax;
203*d04ccbb3Scarlsonj 					continue;
204*d04ccbb3Scarlsonj 				}
205*d04ccbb3Scarlsonj 
206*d04ccbb3Scarlsonj 				/*
207*d04ccbb3Scarlsonj 				 * Handle the option first.
208*d04ccbb3Scarlsonj 				 */
209*d04ccbb3Scarlsonj 				if (d6o.d6o_code == DHCPV6_OPT_IA_TA) {
210*d04ccbb3Scarlsonj 					/* no timers in this structure */
211*d04ccbb3Scarlsonj 					opts += sizeof (dhcpv6_ia_ta_t);
212*d04ccbb3Scarlsonj 				} else {
213*d04ccbb3Scarlsonj 					/* both na and pd */
214*d04ccbb3Scarlsonj 					if (opts + sizeof (d6in) > subomax) {
215*d04ccbb3Scarlsonj 						opts = subomax;
216*d04ccbb3Scarlsonj 						continue;
217*d04ccbb3Scarlsonj 					}
218*d04ccbb3Scarlsonj 					(void) memcpy(&d6in, opts,
219*d04ccbb3Scarlsonj 					    sizeof (d6in));
220*d04ccbb3Scarlsonj 					relativize_v6(&d6in.d6in_t1, orig_time,
221*d04ccbb3Scarlsonj 					    current_time);
222*d04ccbb3Scarlsonj 					relativize_v6(&d6in.d6in_t2, orig_time,
223*d04ccbb3Scarlsonj 					    current_time);
224*d04ccbb3Scarlsonj 					(void) memcpy(opts, &d6in,
225*d04ccbb3Scarlsonj 					    sizeof (d6in));
226*d04ccbb3Scarlsonj 					opts += sizeof (d6in);
227*d04ccbb3Scarlsonj 				}
228*d04ccbb3Scarlsonj 
229*d04ccbb3Scarlsonj 				/*
230*d04ccbb3Scarlsonj 				 * Now handle each suboption (address) inside.
231*d04ccbb3Scarlsonj 				 */
232*d04ccbb3Scarlsonj 				while (opts + sizeof (d6o) <= subomax) {
233*d04ccbb3Scarlsonj 					/*
234*d04ccbb3Scarlsonj 					 * Verify the suboption header first.
235*d04ccbb3Scarlsonj 					 */
236*d04ccbb3Scarlsonj 					(void) memcpy(&d6o, opts,
237*d04ccbb3Scarlsonj 					    sizeof (d6o));
238*d04ccbb3Scarlsonj 					d6o.d6o_code = ntohs(d6o.d6o_code);
239*d04ccbb3Scarlsonj 					d6o.d6o_len = ntohs(d6o.d6o_len);
240*d04ccbb3Scarlsonj 					if (opts + sizeof (d6o) + d6o.d6o_len >
241*d04ccbb3Scarlsonj 					    subomax)
242*d04ccbb3Scarlsonj 						break;
243*d04ccbb3Scarlsonj 					if (d6o.d6o_code != DHCPV6_OPT_IAADDR) {
244*d04ccbb3Scarlsonj 						opts += sizeof (d6o) +
245*d04ccbb3Scarlsonj 						    d6o.d6o_len;
246*d04ccbb3Scarlsonj 						continue;
247*d04ccbb3Scarlsonj 					}
248*d04ccbb3Scarlsonj 
249*d04ccbb3Scarlsonj 					/*
250*d04ccbb3Scarlsonj 					 * Now process the contents.
251*d04ccbb3Scarlsonj 					 */
252*d04ccbb3Scarlsonj 					if (opts + sizeof (d6ia) > subomax)
253*d04ccbb3Scarlsonj 						break;
254*d04ccbb3Scarlsonj 					(void) memcpy(&d6ia, opts,
255*d04ccbb3Scarlsonj 					    sizeof (d6ia));
256*d04ccbb3Scarlsonj 					relativize_v6(&d6ia.d6ia_preflife,
257*d04ccbb3Scarlsonj 					    orig_time, current_time);
258*d04ccbb3Scarlsonj 					relativize_v6(&d6ia.d6ia_vallife,
259*d04ccbb3Scarlsonj 					    orig_time, current_time);
260*d04ccbb3Scarlsonj 					(void) memcpy(opts, &d6ia,
261*d04ccbb3Scarlsonj 					    sizeof (d6ia));
262*d04ccbb3Scarlsonj 					opts += sizeof (d6o) + d6o.d6o_len;
263*d04ccbb3Scarlsonj 				}
264*d04ccbb3Scarlsonj 				opts = subomax;
265*d04ccbb3Scarlsonj 			}
266*d04ccbb3Scarlsonj 		} else {
2677c478bd9Sstevel@tonic-gate 
268*d04ccbb3Scarlsonj 			/*
269*d04ccbb3Scarlsonj 			 * make sure the IPv4 DHCP lease is still valid.
270*d04ccbb3Scarlsonj 			 */
2717c478bd9Sstevel@tonic-gate 
272*d04ccbb3Scarlsonj 			if (plp->opts[CD_LEASE_TIME] != NULL &&
273*d04ccbb3Scarlsonj 			    plp->opts[CD_LEASE_TIME]->len ==
274*d04ccbb3Scarlsonj 			    sizeof (lease_t)) {
275*d04ccbb3Scarlsonj 
276*d04ccbb3Scarlsonj 				(void) memcpy(&lease,
277*d04ccbb3Scarlsonj 				    plp->opts[CD_LEASE_TIME]->value,
278*d04ccbb3Scarlsonj 				    sizeof (lease_t));
279*d04ccbb3Scarlsonj 
280*d04ccbb3Scarlsonj 				lease = ntohl(lease);
281*d04ccbb3Scarlsonj 				if ((lease != DHCP_PERM) &&
282*d04ccbb3Scarlsonj 				    (orig_time + lease) <= current_time)
283*d04ccbb3Scarlsonj 					goto failure;
284*d04ccbb3Scarlsonj 			}
285*d04ccbb3Scarlsonj 
286*d04ccbb3Scarlsonj 			relativize_time(plp->opts[CD_T1_TIME], orig_time,
287*d04ccbb3Scarlsonj 			    current_time);
288*d04ccbb3Scarlsonj 			relativize_time(plp->opts[CD_T2_TIME], orig_time,
289*d04ccbb3Scarlsonj 			    current_time);
290*d04ccbb3Scarlsonj 			relativize_time(plp->opts[CD_LEASE_TIME], orig_time,
291*d04ccbb3Scarlsonj 			    current_time);
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	(void) close(fd);
2967c478bd9Sstevel@tonic-gate 	return (pcnt);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate failure:
2997c478bd9Sstevel@tonic-gate 	free(pkt);
3007c478bd9Sstevel@tonic-gate 	free(plp);
3017c478bd9Sstevel@tonic-gate 	while (pcnt-- > 0) {
3027c478bd9Sstevel@tonic-gate 		free(plpp[pcnt]->pkt);
3037c478bd9Sstevel@tonic-gate 		free(plpp[pcnt]);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	(void) close(fd);
3067c478bd9Sstevel@tonic-gate 	return (-1);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * write_hostconf(): writes the contents of a PKT_LIST into an <if>.dhc file
3117c478bd9Sstevel@tonic-gate  *
3127c478bd9Sstevel@tonic-gate  *   input: const char *: the interface name
3137c478bd9Sstevel@tonic-gate  *	    PKT_LIST **: a list of pointers to PKT_LIST to write
314*d04ccbb3Scarlsonj  *	    uint_t: length of the list of PKT_LIST pointers
3157c478bd9Sstevel@tonic-gate  *	    time_t: a starting time to treat the relative lease times
3167c478bd9Sstevel@tonic-gate  *		    in the first packet as relative to
317*d04ccbb3Scarlsonj  *	    boolean_t: B_TRUE if using DHCPv6
3187c478bd9Sstevel@tonic-gate  *  output: int: 0 if the file is written successfully, -1 otherwise
3197c478bd9Sstevel@tonic-gate  *	    (errno is set)
3207c478bd9Sstevel@tonic-gate  */
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate int
3237c478bd9Sstevel@tonic-gate write_hostconf(
3247c478bd9Sstevel@tonic-gate     const char *ifname,
3257c478bd9Sstevel@tonic-gate     PKT_LIST *pl[],
3267c478bd9Sstevel@tonic-gate     uint_t pllen,
327*d04ccbb3Scarlsonj     time_t relative_to,
328*d04ccbb3Scarlsonj     boolean_t isv6)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	int		fd;
3317c478bd9Sstevel@tonic-gate 	struct iovec	iov[IOV_MAX];
3327c478bd9Sstevel@tonic-gate 	int		retval;
333*d04ccbb3Scarlsonj 	uint32_t	magic;
3347c478bd9Sstevel@tonic-gate 	ssize_t		explen = 0; /* Expected length of write */
3357c478bd9Sstevel@tonic-gate 	int		i, iovlen = 0;
3367c478bd9Sstevel@tonic-gate 
337*d04ccbb3Scarlsonj 	fd = open(ifname_to_hostconf(ifname, isv6), O_WRONLY|O_CREAT|O_TRUNC,
338*d04ccbb3Scarlsonj 	    0600);
3397c478bd9Sstevel@tonic-gate 	if (fd == -1)
3407c478bd9Sstevel@tonic-gate 		return (-1);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * first write our magic number, then the relative time of the
3447c478bd9Sstevel@tonic-gate 	 * leases, then for each packet we write the length of the packet
3457c478bd9Sstevel@tonic-gate 	 * followed by the packet.  we will then use the relative time in
3467c478bd9Sstevel@tonic-gate 	 * read_hostconf() to recalculate the lease times for the first packet.
3477c478bd9Sstevel@tonic-gate 	 */
3487c478bd9Sstevel@tonic-gate 
349*d04ccbb3Scarlsonj 	magic = isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC;
3507c478bd9Sstevel@tonic-gate 	iov[iovlen].iov_base = (caddr_t)&magic;
3517c478bd9Sstevel@tonic-gate 	explen += iov[iovlen++].iov_len  = sizeof (magic);
3527c478bd9Sstevel@tonic-gate 	iov[iovlen].iov_base = (caddr_t)&relative_to;
3537c478bd9Sstevel@tonic-gate 	explen += iov[iovlen++].iov_len  = sizeof (relative_to);
3547c478bd9Sstevel@tonic-gate 	for (i = 0; i < pllen && iovlen < (IOV_MAX - 1); i++) {
3557c478bd9Sstevel@tonic-gate 		iov[iovlen].iov_base = (caddr_t)&pl[i]->len;
3567c478bd9Sstevel@tonic-gate 		explen += iov[iovlen++].iov_len  = sizeof (pl[i]->len);
3577c478bd9Sstevel@tonic-gate 		iov[iovlen].iov_base = (caddr_t)pl[i]->pkt;
3587c478bd9Sstevel@tonic-gate 		explen += iov[iovlen++].iov_len  = pl[i]->len;
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	retval = writev(fd, iov, iovlen);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	(void) close(fd);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (retval != explen)
3667c478bd9Sstevel@tonic-gate 		return (-1);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	return (0);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * relativize_time(): re-relativizes a time in a DHCP option
3737c478bd9Sstevel@tonic-gate  *
3747c478bd9Sstevel@tonic-gate  *   input: DHCP_OPT *: the DHCP option parameter to convert
3757c478bd9Sstevel@tonic-gate  *	    time_t: the time the leases in the packet are currently relative to
3767c478bd9Sstevel@tonic-gate  *	    time_t: the current time which leases will become relative to
3777c478bd9Sstevel@tonic-gate  *  output: void
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate static void
3817c478bd9Sstevel@tonic-gate relativize_time(DHCP_OPT *option, time_t orig_time, time_t current_time)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	uint32_t	pkt_time;
3847c478bd9Sstevel@tonic-gate 	time_t		time_diff = current_time - orig_time;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	if (option == NULL || option->len != sizeof (lease_t))
3877c478bd9Sstevel@tonic-gate 		return;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	(void) memcpy(&pkt_time, option->value, option->len);
3907c478bd9Sstevel@tonic-gate 	if (ntohl(pkt_time) != DHCP_PERM)
3917c478bd9Sstevel@tonic-gate 		pkt_time = htonl(ntohl(pkt_time) - time_diff);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	(void) memcpy(option->value, &pkt_time, option->len);
3947c478bd9Sstevel@tonic-gate }
395*d04ccbb3Scarlsonj 
396*d04ccbb3Scarlsonj /*
397*d04ccbb3Scarlsonj  * relativize_v6(): re-relativizes a time in a DHCPv6 option
398*d04ccbb3Scarlsonj  *
399*d04ccbb3Scarlsonj  *   input: uint32_t *: the time value to convert
400*d04ccbb3Scarlsonj  *	    time_t: the time the leases in the packet are currently relative to
401*d04ccbb3Scarlsonj  *	    time_t: the current time which leases will become relative to
402*d04ccbb3Scarlsonj  *  output: void
403*d04ccbb3Scarlsonj  */
404*d04ccbb3Scarlsonj 
405*d04ccbb3Scarlsonj static void
406*d04ccbb3Scarlsonj relativize_v6(uint32_t *val, time_t orig_time, time_t current_time)
407*d04ccbb3Scarlsonj {
408*d04ccbb3Scarlsonj 	uint32_t	hval;
409*d04ccbb3Scarlsonj 	time_t		time_diff = current_time - orig_time;
410*d04ccbb3Scarlsonj 
411*d04ccbb3Scarlsonj 	hval = ntohl(*val);
412*d04ccbb3Scarlsonj 	if (hval != DHCPV6_INFTIME) {
413*d04ccbb3Scarlsonj 		if (hval < time_diff)
414*d04ccbb3Scarlsonj 			*val = 0;
415*d04ccbb3Scarlsonj 		else
416*d04ccbb3Scarlsonj 			*val = htonl(hval - time_diff);
417*d04ccbb3Scarlsonj 	}
418*d04ccbb3Scarlsonj }
419