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