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 *
ifname_to_hostconf(const char * ifname,boolean_t isv6)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
remove_hostconf(const char * ifname,boolean_t isv6)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
read_hostconf(const char * ifname,PKT_LIST ** plpp,uint_t plplen,boolean_t isv6)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;
175*d04ccbb3Scarlsonj
1767c478bd9Sstevel@tonic-gate /*
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 {
267*d04ccbb3Scarlsonj
268*d04ccbb3Scarlsonj /*
269*d04ccbb3Scarlsonj * make sure the IPv4 DHCP lease is still valid.
2707c478bd9Sstevel@tonic-gate */
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate if (plp->opts[CD_LEASE_TIME] != NULL &&
273*d04ccbb3Scarlsonj plp->opts[CD_LEASE_TIME]->len ==
274*d04ccbb3Scarlsonj sizeof (lease_t)) {
2757c478bd9Sstevel@tonic-gate
276*d04ccbb3Scarlsonj (void) memcpy(&lease,
277*d04ccbb3Scarlsonj plp->opts[CD_LEASE_TIME]->value,
2787c478bd9Sstevel@tonic-gate sizeof (lease_t));
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate lease = ntohl(lease);
2817c478bd9Sstevel@tonic-gate if ((lease != DHCP_PERM) &&
2827c478bd9Sstevel@tonic-gate (orig_time + lease) <= current_time)
2837c478bd9Sstevel@tonic-gate goto failure;
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
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);
2907c478bd9Sstevel@tonic-gate relativize_time(plp->opts[CD_LEASE_TIME], orig_time,
2917c478bd9Sstevel@tonic-gate current_time);
2927c478bd9Sstevel@tonic-gate }
293*d04ccbb3Scarlsonj }
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
write_hostconf(const char * ifname,PKT_LIST * pl[],uint_t pllen,time_t relative_to,boolean_t isv6)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
relativize_time(DHCP_OPT * option,time_t orig_time,time_t current_time)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
relativize_v6(uint32_t * val,time_t orig_time,time_t current_time)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