xref: /minix/external/bsd/dhcp/dist/client/dhclient.c (revision 83ee113e)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: dhclient.c,v 1.9 2014/07/12 12:09:37 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* dhclient.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    DHCP Client. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 1995-2003 by Internet Software Consortium
9*83ee113eSDavid van Moolenbroek  *
10*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
11*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
12*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
13*83ee113eSDavid van Moolenbroek  *
14*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
17*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21*83ee113eSDavid van Moolenbroek  *
22*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
23*83ee113eSDavid van Moolenbroek  *   950 Charter Street
24*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
25*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
26*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
27*83ee113eSDavid van Moolenbroek  *
28*83ee113eSDavid van Moolenbroek  * This code is based on the original client state machine that was
29*83ee113eSDavid van Moolenbroek  * written by Elliot Poger.  The code has been extensively hacked on
30*83ee113eSDavid van Moolenbroek  * by Ted Lemon since then, so any mistakes you find are probably his
31*83ee113eSDavid van Moolenbroek  * fault and not Elliot's.
32*83ee113eSDavid van Moolenbroek  */
33*83ee113eSDavid van Moolenbroek 
34*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
35*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: dhclient.c,v 1.9 2014/07/12 12:09:37 spz Exp $");
36*83ee113eSDavid van Moolenbroek 
37*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
38*83ee113eSDavid van Moolenbroek #include <syslog.h>
39*83ee113eSDavid van Moolenbroek #include <signal.h>
40*83ee113eSDavid van Moolenbroek #include <errno.h>
41*83ee113eSDavid van Moolenbroek #include <sys/time.h>
42*83ee113eSDavid van Moolenbroek #include <sys/wait.h>
43*83ee113eSDavid van Moolenbroek #include <limits.h>
44*83ee113eSDavid van Moolenbroek #include <dns/result.h>
45*83ee113eSDavid van Moolenbroek 
46*83ee113eSDavid van Moolenbroek TIME default_lease_time = 43200; /* 12 hours... */
47*83ee113eSDavid van Moolenbroek TIME max_lease_time = 86400; /* 24 hours... */
48*83ee113eSDavid van Moolenbroek 
49*83ee113eSDavid van Moolenbroek const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
50*83ee113eSDavid van Moolenbroek const char *path_dhclient_db = NULL;
51*83ee113eSDavid van Moolenbroek const char *path_dhclient_pid = NULL;
52*83ee113eSDavid van Moolenbroek static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
53*83ee113eSDavid van Moolenbroek char *path_dhclient_script = path_dhclient_script_array;
54*83ee113eSDavid van Moolenbroek 
55*83ee113eSDavid van Moolenbroek /* False (default) => we write and use a pid file */
56*83ee113eSDavid van Moolenbroek isc_boolean_t no_pid_file = ISC_FALSE;
57*83ee113eSDavid van Moolenbroek isc_boolean_t hw_mismatch_drop = ISC_TRUE;
58*83ee113eSDavid van Moolenbroek 
59*83ee113eSDavid van Moolenbroek int dhcp_max_agent_option_packet_length = 0;
60*83ee113eSDavid van Moolenbroek 
61*83ee113eSDavid van Moolenbroek int interfaces_requested = 0;
62*83ee113eSDavid van Moolenbroek int interfaces_left = 0;
63*83ee113eSDavid van Moolenbroek 
64*83ee113eSDavid van Moolenbroek struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
65*83ee113eSDavid van Moolenbroek struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
66*83ee113eSDavid van Moolenbroek struct in_addr inaddr_any;
67*83ee113eSDavid van Moolenbroek struct sockaddr_in sockaddr_broadcast;
68*83ee113eSDavid van Moolenbroek struct in_addr giaddr;
69*83ee113eSDavid van Moolenbroek struct data_string default_duid;
70*83ee113eSDavid van Moolenbroek int duid_type = 0;
71*83ee113eSDavid van Moolenbroek int duid_v4 = 0;
72*83ee113eSDavid van Moolenbroek int std_dhcid = 0;
73*83ee113eSDavid van Moolenbroek 
74*83ee113eSDavid van Moolenbroek /* ASSERT_STATE() does nothing now; it used to be
75*83ee113eSDavid van Moolenbroek    assert (state_is == state_shouldbe). */
76*83ee113eSDavid van Moolenbroek #define ASSERT_STATE(state_is, state_shouldbe) {}
77*83ee113eSDavid van Moolenbroek 
78*83ee113eSDavid van Moolenbroek static const char copyright[] = "Copyright 2004-2014 Internet Systems Consortium.";
79*83ee113eSDavid van Moolenbroek static const char arr [] = "All rights reserved.";
80*83ee113eSDavid van Moolenbroek static const char message [] = "Internet Systems Consortium DHCP Client";
81*83ee113eSDavid van Moolenbroek static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/";
82*83ee113eSDavid van Moolenbroek 
83*83ee113eSDavid van Moolenbroek u_int16_t local_port = 0;
84*83ee113eSDavid van Moolenbroek u_int16_t remote_port = 0;
85*83ee113eSDavid van Moolenbroek int no_daemon = 0;
86*83ee113eSDavid van Moolenbroek struct string_list *client_env = NULL;
87*83ee113eSDavid van Moolenbroek int client_env_count = 0;
88*83ee113eSDavid van Moolenbroek int onetry = 0;
89*83ee113eSDavid van Moolenbroek int quiet = 1;
90*83ee113eSDavid van Moolenbroek int nowait = 0;
91*83ee113eSDavid van Moolenbroek int stateless = 0;
92*83ee113eSDavid van Moolenbroek int wanted_ia_na = -1;		/* the absolute value is the real one. */
93*83ee113eSDavid van Moolenbroek int wanted_ia_ta = 0;
94*83ee113eSDavid van Moolenbroek int wanted_ia_pd = 0;
95*83ee113eSDavid van Moolenbroek char *mockup_relay = NULL;
96*83ee113eSDavid van Moolenbroek 
97*83ee113eSDavid van Moolenbroek void run_stateless(int exit_mode);
98*83ee113eSDavid van Moolenbroek 
99*83ee113eSDavid van Moolenbroek static void usage(void);
100*83ee113eSDavid van Moolenbroek 
101*83ee113eSDavid van Moolenbroek static isc_result_t write_duid(struct data_string *duid);
102*83ee113eSDavid van Moolenbroek static void add_reject(struct packet *packet);
103*83ee113eSDavid van Moolenbroek 
104*83ee113eSDavid van Moolenbroek static int check_domain_name(const char *ptr, size_t len, int dots);
105*83ee113eSDavid van Moolenbroek static int check_domain_name_list(const char *ptr, size_t len, int dots);
106*83ee113eSDavid van Moolenbroek static int check_option_values(struct universe *universe, unsigned int opt,
107*83ee113eSDavid van Moolenbroek 			       const char *ptr, size_t len);
108*83ee113eSDavid van Moolenbroek 
109*83ee113eSDavid van Moolenbroek static void
setup(void)110*83ee113eSDavid van Moolenbroek setup(void) {
111*83ee113eSDavid van Moolenbroek 	isc_result_t status;
112*83ee113eSDavid van Moolenbroek 	/* Set up the isc and dns library managers */
113*83ee113eSDavid van Moolenbroek 	status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL);
114*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
115*83ee113eSDavid van Moolenbroek 		log_fatal("Can't initialize context: %s",
116*83ee113eSDavid van Moolenbroek 			isc_result_totext(status));
117*83ee113eSDavid van Moolenbroek 
118*83ee113eSDavid van Moolenbroek 	/* Set up the OMAPI. */
119*83ee113eSDavid van Moolenbroek 	status = omapi_init();
120*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
121*83ee113eSDavid van Moolenbroek 		log_fatal("Can't initialize OMAPI: %s",
122*83ee113eSDavid van Moolenbroek 			isc_result_totext(status));
123*83ee113eSDavid van Moolenbroek 
124*83ee113eSDavid van Moolenbroek 	/* Set up the OMAPI wrappers for various server database internal
125*83ee113eSDavid van Moolenbroek 	   objects. */
126*83ee113eSDavid van Moolenbroek 	dhcp_common_objects_setup();
127*83ee113eSDavid van Moolenbroek 
128*83ee113eSDavid van Moolenbroek 	dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
129*83ee113eSDavid van Moolenbroek 	dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
130*83ee113eSDavid van Moolenbroek 	dhcp_interface_startup_hook = dhclient_interface_startup_hook;
131*83ee113eSDavid van Moolenbroek }
132*83ee113eSDavid van Moolenbroek 
133*83ee113eSDavid van Moolenbroek 
134*83ee113eSDavid van Moolenbroek static void
add_interfaces(char ** ifaces,int nifaces)135*83ee113eSDavid van Moolenbroek add_interfaces(char **ifaces, int nifaces)
136*83ee113eSDavid van Moolenbroek {
137*83ee113eSDavid van Moolenbroek 	isc_result_t status;
138*83ee113eSDavid van Moolenbroek 
139*83ee113eSDavid van Moolenbroek 	for (int i = 0; i < nifaces; i++) {
140*83ee113eSDavid van Moolenbroek 		struct interface_info *tmp = NULL;
141*83ee113eSDavid van Moolenbroek 		status = interface_allocate(&tmp, MDL);
142*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
143*83ee113eSDavid van Moolenbroek 			log_fatal("Can't record interface %s:%s",
144*83ee113eSDavid van Moolenbroek 		ifaces[i], isc_result_totext(status));
145*83ee113eSDavid van Moolenbroek 		if (strlen(ifaces[i]) >= sizeof(tmp->name))
146*83ee113eSDavid van Moolenbroek 			log_fatal("%s: interface name too long (is %ld)",
147*83ee113eSDavid van Moolenbroek 		ifaces[i], (long)strlen(ifaces[i]));
148*83ee113eSDavid van Moolenbroek 		strcpy(tmp->name, ifaces[i]);
149*83ee113eSDavid van Moolenbroek 		if (interfaces) {
150*83ee113eSDavid van Moolenbroek 			interface_reference(&tmp->next, interfaces, MDL);
151*83ee113eSDavid van Moolenbroek 			interface_dereference(&interfaces, MDL);
152*83ee113eSDavid van Moolenbroek 		}
153*83ee113eSDavid van Moolenbroek 		interface_reference(&interfaces, tmp, MDL);
154*83ee113eSDavid van Moolenbroek 		tmp->flags = INTERFACE_REQUESTED;
155*83ee113eSDavid van Moolenbroek 	}
156*83ee113eSDavid van Moolenbroek }
157*83ee113eSDavid van Moolenbroek 
158*83ee113eSDavid van Moolenbroek 
159*83ee113eSDavid van Moolenbroek int
main(int argc,char ** argv)160*83ee113eSDavid van Moolenbroek main(int argc, char **argv) {
161*83ee113eSDavid van Moolenbroek 	int fd;
162*83ee113eSDavid van Moolenbroek 	int i;
163*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
164*83ee113eSDavid van Moolenbroek 	struct client_state *client;
165*83ee113eSDavid van Moolenbroek 	unsigned seed;
166*83ee113eSDavid van Moolenbroek 	char *server = NULL;
167*83ee113eSDavid van Moolenbroek 	int exit_mode = 0;
168*83ee113eSDavid van Moolenbroek 	int release_mode = 0;
169*83ee113eSDavid van Moolenbroek 	struct timeval tv;
170*83ee113eSDavid van Moolenbroek 	omapi_object_t *listener;
171*83ee113eSDavid van Moolenbroek 	isc_result_t result;
172*83ee113eSDavid van Moolenbroek 	int persist = 0;
173*83ee113eSDavid van Moolenbroek 	int no_dhclient_conf = 0;
174*83ee113eSDavid van Moolenbroek 	int no_dhclient_db = 0;
175*83ee113eSDavid van Moolenbroek 	int no_dhclient_pid = 0;
176*83ee113eSDavid van Moolenbroek 	int no_dhclient_script = 0;
177*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
178*83ee113eSDavid van Moolenbroek 	int local_family_set = 0;
179*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
180*83ee113eSDavid van Moolenbroek 	char *s;
181*83ee113eSDavid van Moolenbroek 	char **ifaces;
182*83ee113eSDavid van Moolenbroek 
183*83ee113eSDavid van Moolenbroek 	/* Initialize client globals. */
184*83ee113eSDavid van Moolenbroek 	memset(&default_duid, 0, sizeof(default_duid));
185*83ee113eSDavid van Moolenbroek 
186*83ee113eSDavid van Moolenbroek 	/* Make sure that file descriptors 0 (stdin), 1, (stdout), and
187*83ee113eSDavid van Moolenbroek 	   2 (stderr) are open. To do this, we assume that when we
188*83ee113eSDavid van Moolenbroek 	   open a file the lowest available file descriptor is used. */
189*83ee113eSDavid van Moolenbroek 	fd = open("/dev/null", O_RDWR);
190*83ee113eSDavid van Moolenbroek 	if (fd == 0)
191*83ee113eSDavid van Moolenbroek 		fd = open("/dev/null", O_RDWR);
192*83ee113eSDavid van Moolenbroek 	if (fd == 1)
193*83ee113eSDavid van Moolenbroek 		fd = open("/dev/null", O_RDWR);
194*83ee113eSDavid van Moolenbroek 	if (fd == 2)
195*83ee113eSDavid van Moolenbroek 		log_perror = 0; /* No sense logging to /dev/null. */
196*83ee113eSDavid van Moolenbroek 	else if (fd != -1)
197*83ee113eSDavid van Moolenbroek 		close(fd);
198*83ee113eSDavid van Moolenbroek 
199*83ee113eSDavid van Moolenbroek 	openlog("dhclient", LOG_NDELAY, LOG_DAEMON);
200*83ee113eSDavid van Moolenbroek 
201*83ee113eSDavid van Moolenbroek #if !(defined(DEBUG) || defined(__CYGWIN32__))
202*83ee113eSDavid van Moolenbroek 	setlogmask(LOG_UPTO(LOG_INFO));
203*83ee113eSDavid van Moolenbroek #endif
204*83ee113eSDavid van Moolenbroek 
205*83ee113eSDavid van Moolenbroek 	if ((ifaces = malloc(sizeof(*ifaces) * argc)) == NULL) {
206*83ee113eSDavid van Moolenbroek 		log_fatal("Can't allocate memory");
207*83ee113eSDavid van Moolenbroek 		return 1;
208*83ee113eSDavid van Moolenbroek 	}
209*83ee113eSDavid van Moolenbroek 
210*83ee113eSDavid van Moolenbroek 	for (i = 1; i < argc; i++) {
211*83ee113eSDavid van Moolenbroek 		if (!strcmp(argv[i], "-r")) {
212*83ee113eSDavid van Moolenbroek 			release_mode = 1;
213*83ee113eSDavid van Moolenbroek 			no_daemon = 1;
214*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
215*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-4")) {
216*83ee113eSDavid van Moolenbroek 			if (local_family_set && local_family != AF_INET)
217*83ee113eSDavid van Moolenbroek 				log_fatal("Client can only do v4 or v6, not "
218*83ee113eSDavid van Moolenbroek 					  "both.");
219*83ee113eSDavid van Moolenbroek 			local_family_set = 1;
220*83ee113eSDavid van Moolenbroek 			local_family = AF_INET;
221*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-6")) {
222*83ee113eSDavid van Moolenbroek 			if (local_family_set && local_family != AF_INET6)
223*83ee113eSDavid van Moolenbroek 				log_fatal("Client can only do v4 or v6, not "
224*83ee113eSDavid van Moolenbroek 					  "both.");
225*83ee113eSDavid van Moolenbroek 			local_family_set = 1;
226*83ee113eSDavid van Moolenbroek 			local_family = AF_INET6;
227*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
228*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-x")) { /* eXit, no release */
229*83ee113eSDavid van Moolenbroek 			release_mode = 0;
230*83ee113eSDavid van Moolenbroek 			no_daemon = 0;
231*83ee113eSDavid van Moolenbroek 			exit_mode = 1;
232*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-p")) {
233*83ee113eSDavid van Moolenbroek 			if (++i == argc)
234*83ee113eSDavid van Moolenbroek 				usage();
235*83ee113eSDavid van Moolenbroek 			local_port = validate_port(argv[i]);
236*83ee113eSDavid van Moolenbroek 			log_debug("binding to user-specified port %d",
237*83ee113eSDavid van Moolenbroek 				  ntohs(local_port));
238*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-d")) {
239*83ee113eSDavid van Moolenbroek 			no_daemon = 1;
240*83ee113eSDavid van Moolenbroek 			quiet = 0;
241*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-pf")) {
242*83ee113eSDavid van Moolenbroek 			if (++i == argc)
243*83ee113eSDavid van Moolenbroek 				usage();
244*83ee113eSDavid van Moolenbroek 			path_dhclient_pid = argv[i];
245*83ee113eSDavid van Moolenbroek 			no_dhclient_pid = 1;
246*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "--no-pid")) {
247*83ee113eSDavid van Moolenbroek 			no_pid_file = ISC_TRUE;
248*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-cf")) {
249*83ee113eSDavid van Moolenbroek 			if (++i == argc)
250*83ee113eSDavid van Moolenbroek 				usage();
251*83ee113eSDavid van Moolenbroek 			path_dhclient_conf = argv[i];
252*83ee113eSDavid van Moolenbroek 			no_dhclient_conf = 1;
253*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-lf")) {
254*83ee113eSDavid van Moolenbroek 			if (++i == argc)
255*83ee113eSDavid van Moolenbroek 				usage();
256*83ee113eSDavid van Moolenbroek 			path_dhclient_db = argv[i];
257*83ee113eSDavid van Moolenbroek 			no_dhclient_db = 1;
258*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-sf")) {
259*83ee113eSDavid van Moolenbroek 			if (++i == argc)
260*83ee113eSDavid van Moolenbroek 				usage();
261*83ee113eSDavid van Moolenbroek 			path_dhclient_script = argv[i];
262*83ee113eSDavid van Moolenbroek 			no_dhclient_script = 1;
263*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-1")) {
264*83ee113eSDavid van Moolenbroek 			onetry = 1;
265*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-q")) {
266*83ee113eSDavid van Moolenbroek 			quiet = 1;
267*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-s")) {
268*83ee113eSDavid van Moolenbroek 			if (++i == argc)
269*83ee113eSDavid van Moolenbroek 				usage();
270*83ee113eSDavid van Moolenbroek 			server = argv[i];
271*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-g")) {
272*83ee113eSDavid van Moolenbroek 			if (++i == argc)
273*83ee113eSDavid van Moolenbroek 				usage();
274*83ee113eSDavid van Moolenbroek 			mockup_relay = argv[i];
275*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-nw")) {
276*83ee113eSDavid van Moolenbroek 			nowait = 1;
277*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-n")) {
278*83ee113eSDavid van Moolenbroek 			/* do not start up any interfaces */
279*83ee113eSDavid van Moolenbroek 			interfaces_requested = -1;
280*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-w")) {
281*83ee113eSDavid van Moolenbroek 			/* do not exit if there are no broadcast interfaces. */
282*83ee113eSDavid van Moolenbroek 			persist = 1;
283*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-e")) {
284*83ee113eSDavid van Moolenbroek 			struct string_list *tmp;
285*83ee113eSDavid van Moolenbroek 			if (++i == argc)
286*83ee113eSDavid van Moolenbroek 				usage();
287*83ee113eSDavid van Moolenbroek 			tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL);
288*83ee113eSDavid van Moolenbroek 			if (!tmp)
289*83ee113eSDavid van Moolenbroek 				log_fatal("No memory for %s", argv[i]);
290*83ee113eSDavid van Moolenbroek 			strcpy(tmp->string, argv[i]);
291*83ee113eSDavid van Moolenbroek 			tmp->next = client_env;
292*83ee113eSDavid van Moolenbroek 			client_env = tmp;
293*83ee113eSDavid van Moolenbroek 			client_env_count++;
294*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
295*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-S")) {
296*83ee113eSDavid van Moolenbroek 			if (local_family_set && (local_family == AF_INET)) {
297*83ee113eSDavid van Moolenbroek 				usage();
298*83ee113eSDavid van Moolenbroek 			}
299*83ee113eSDavid van Moolenbroek 			local_family_set = 1;
300*83ee113eSDavid van Moolenbroek 			local_family = AF_INET6;
301*83ee113eSDavid van Moolenbroek 			wanted_ia_na = 0;
302*83ee113eSDavid van Moolenbroek 			stateless = 1;
303*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-N")) {
304*83ee113eSDavid van Moolenbroek 			if (local_family_set && (local_family == AF_INET)) {
305*83ee113eSDavid van Moolenbroek 				usage();
306*83ee113eSDavid van Moolenbroek 			}
307*83ee113eSDavid van Moolenbroek 			local_family_set = 1;
308*83ee113eSDavid van Moolenbroek 			local_family = AF_INET6;
309*83ee113eSDavid van Moolenbroek 			if (wanted_ia_na < 0) {
310*83ee113eSDavid van Moolenbroek 				wanted_ia_na = 0;
311*83ee113eSDavid van Moolenbroek 			}
312*83ee113eSDavid van Moolenbroek 			wanted_ia_na++;
313*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-T")) {
314*83ee113eSDavid van Moolenbroek 			if (local_family_set && (local_family == AF_INET)) {
315*83ee113eSDavid van Moolenbroek 				usage();
316*83ee113eSDavid van Moolenbroek 			}
317*83ee113eSDavid van Moolenbroek 			local_family_set = 1;
318*83ee113eSDavid van Moolenbroek 			local_family = AF_INET6;
319*83ee113eSDavid van Moolenbroek 			if (wanted_ia_na < 0) {
320*83ee113eSDavid van Moolenbroek 				wanted_ia_na = 0;
321*83ee113eSDavid van Moolenbroek 			}
322*83ee113eSDavid van Moolenbroek 			wanted_ia_ta++;
323*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-P")) {
324*83ee113eSDavid van Moolenbroek 			if (local_family_set && (local_family == AF_INET)) {
325*83ee113eSDavid van Moolenbroek 				usage();
326*83ee113eSDavid van Moolenbroek 			}
327*83ee113eSDavid van Moolenbroek 			local_family_set = 1;
328*83ee113eSDavid van Moolenbroek 			local_family = AF_INET6;
329*83ee113eSDavid van Moolenbroek 			if (wanted_ia_na < 0) {
330*83ee113eSDavid van Moolenbroek 				wanted_ia_na = 0;
331*83ee113eSDavid van Moolenbroek 			}
332*83ee113eSDavid van Moolenbroek 			wanted_ia_pd++;
333*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
334*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-D")) {
335*83ee113eSDavid van Moolenbroek 			duid_v4 = 1;
336*83ee113eSDavid van Moolenbroek 			if (++i == argc)
337*83ee113eSDavid van Moolenbroek 				usage();
338*83ee113eSDavid van Moolenbroek 			if (!strcasecmp(argv[i], "LL")) {
339*83ee113eSDavid van Moolenbroek 				duid_type = DUID_LL;
340*83ee113eSDavid van Moolenbroek 			} else if (!strcasecmp(argv[i], "LLT")) {
341*83ee113eSDavid van Moolenbroek 				duid_type = DUID_LLT;
342*83ee113eSDavid van Moolenbroek 			} else {
343*83ee113eSDavid van Moolenbroek 				usage();
344*83ee113eSDavid van Moolenbroek 			}
345*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-i")) {
346*83ee113eSDavid van Moolenbroek 			/* enable DUID support for DHCPv4 clients */
347*83ee113eSDavid van Moolenbroek 			duid_v4 = 1;
348*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-I")) {
349*83ee113eSDavid van Moolenbroek 			/* enable standard DHCID support for DDNS updates */
350*83ee113eSDavid van Moolenbroek 			std_dhcid = 1;
351*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-m")) {
352*83ee113eSDavid van Moolenbroek 			hw_mismatch_drop = ISC_FALSE;
353*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "-v")) {
354*83ee113eSDavid van Moolenbroek 			quiet = 0;
355*83ee113eSDavid van Moolenbroek 		} else if (!strcmp(argv[i], "--version")) {
356*83ee113eSDavid van Moolenbroek 			log_info("isc-dhclient-%s", PACKAGE_VERSION);
357*83ee113eSDavid van Moolenbroek 			exit(0);
358*83ee113eSDavid van Moolenbroek 		} else if (argv[i][0] == '-') {
359*83ee113eSDavid van Moolenbroek 		    usage();
360*83ee113eSDavid van Moolenbroek 		} else if (interfaces_requested < 0) {
361*83ee113eSDavid van Moolenbroek 		    usage();
362*83ee113eSDavid van Moolenbroek 		} else {
363*83ee113eSDavid van Moolenbroek 		    ifaces[interfaces_requested++] = argv[i];
364*83ee113eSDavid van Moolenbroek 		}
365*83ee113eSDavid van Moolenbroek 	}
366*83ee113eSDavid van Moolenbroek 
367*83ee113eSDavid van Moolenbroek 	/*
368*83ee113eSDavid van Moolenbroek 	 * Do this before setup, otherwise if we are using threads things
369*83ee113eSDavid van Moolenbroek 	 * are not going to work
370*83ee113eSDavid van Moolenbroek 	 */
371*83ee113eSDavid van Moolenbroek 	go_daemon();
372*83ee113eSDavid van Moolenbroek 	setup();
373*83ee113eSDavid van Moolenbroek 	if (interfaces_requested > 0) {
374*83ee113eSDavid van Moolenbroek 		add_interfaces(ifaces, interfaces_requested);
375*83ee113eSDavid van Moolenbroek 		interfaces_left = interfaces_requested;
376*83ee113eSDavid van Moolenbroek 	}
377*83ee113eSDavid van Moolenbroek 	free(ifaces);
378*83ee113eSDavid van Moolenbroek 
379*83ee113eSDavid van Moolenbroek 	if (wanted_ia_na < 0) {
380*83ee113eSDavid van Moolenbroek 		wanted_ia_na = 1;
381*83ee113eSDavid van Moolenbroek 	}
382*83ee113eSDavid van Moolenbroek 
383*83ee113eSDavid van Moolenbroek 	/* Support only one (requested) interface for Prefix Delegation. */
384*83ee113eSDavid van Moolenbroek 	if (wanted_ia_pd && (interfaces_requested != 1)) {
385*83ee113eSDavid van Moolenbroek 		usage();
386*83ee113eSDavid van Moolenbroek 	}
387*83ee113eSDavid van Moolenbroek 
388*83ee113eSDavid van Moolenbroek 	if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) {
389*83ee113eSDavid van Moolenbroek 		path_dhclient_conf = s;
390*83ee113eSDavid van Moolenbroek 	}
391*83ee113eSDavid van Moolenbroek 	if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) {
392*83ee113eSDavid van Moolenbroek 		path_dhclient_db = s;
393*83ee113eSDavid van Moolenbroek 	}
394*83ee113eSDavid van Moolenbroek 	if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) {
395*83ee113eSDavid van Moolenbroek 		path_dhclient_pid = s;
396*83ee113eSDavid van Moolenbroek 	}
397*83ee113eSDavid van Moolenbroek 	if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) {
398*83ee113eSDavid van Moolenbroek 		path_dhclient_script = s;
399*83ee113eSDavid van Moolenbroek 	}
400*83ee113eSDavid van Moolenbroek 
401*83ee113eSDavid van Moolenbroek 	/* Set up the initial dhcp option universe. */
402*83ee113eSDavid van Moolenbroek 	initialize_common_option_spaces();
403*83ee113eSDavid van Moolenbroek 
404*83ee113eSDavid van Moolenbroek 	/* Assign v4 or v6 specific running parameters. */
405*83ee113eSDavid van Moolenbroek 	if (local_family == AF_INET)
406*83ee113eSDavid van Moolenbroek 		dhcpv4_client_assignments();
407*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
408*83ee113eSDavid van Moolenbroek 	else if (local_family == AF_INET6)
409*83ee113eSDavid van Moolenbroek 		dhcpv6_client_assignments();
410*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
411*83ee113eSDavid van Moolenbroek 	else
412*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
413*83ee113eSDavid van Moolenbroek 
414*83ee113eSDavid van Moolenbroek 	/*
415*83ee113eSDavid van Moolenbroek 	 * convert relative path names to absolute, for files that need
416*83ee113eSDavid van Moolenbroek 	 * to be reopened after chdir() has been called
417*83ee113eSDavid van Moolenbroek 	 */
418*83ee113eSDavid van Moolenbroek 	if (path_dhclient_db[0] != '/') {
419*83ee113eSDavid van Moolenbroek 		const char *old_path = path_dhclient_db;
420*83ee113eSDavid van Moolenbroek 		path_dhclient_db = realpath(path_dhclient_db, NULL);
421*83ee113eSDavid van Moolenbroek 		if (path_dhclient_db == NULL)
422*83ee113eSDavid van Moolenbroek 			log_fatal("Failed to get realpath for %s: %s", old_path, strerror(errno));
423*83ee113eSDavid van Moolenbroek 	}
424*83ee113eSDavid van Moolenbroek 
425*83ee113eSDavid van Moolenbroek 	if (path_dhclient_script[0] != '/') {
426*83ee113eSDavid van Moolenbroek 		const char *old_path = path_dhclient_script;
427*83ee113eSDavid van Moolenbroek 		path_dhclient_script = realpath(path_dhclient_script, NULL);
428*83ee113eSDavid van Moolenbroek 		if (path_dhclient_script == NULL)
429*83ee113eSDavid van Moolenbroek 			log_fatal("Failed to get realpath for %s: %s", old_path, strerror(errno));
430*83ee113eSDavid van Moolenbroek 	}
431*83ee113eSDavid van Moolenbroek 
432*83ee113eSDavid van Moolenbroek 	/*
433*83ee113eSDavid van Moolenbroek 	 * See if we should  kill off any currently running client
434*83ee113eSDavid van Moolenbroek 	 * we don't try to kill it off if the user told us not
435*83ee113eSDavid van Moolenbroek 	 * to write a pid file - we assume they are controlling
436*83ee113eSDavid van Moolenbroek 	 * the process in some other fashion.
437*83ee113eSDavid van Moolenbroek 	 */
438*83ee113eSDavid van Moolenbroek 	if (path_dhclient_pid != NULL &&
439*83ee113eSDavid van Moolenbroek 	    (release_mode || exit_mode) && (no_pid_file == ISC_FALSE)) {
440*83ee113eSDavid van Moolenbroek 		FILE *pidfd;
441*83ee113eSDavid van Moolenbroek 		pid_t oldpid;
442*83ee113eSDavid van Moolenbroek 		long temp;
443*83ee113eSDavid van Moolenbroek 		int e;
444*83ee113eSDavid van Moolenbroek 
445*83ee113eSDavid van Moolenbroek 		if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
446*83ee113eSDavid van Moolenbroek 			e = fscanf(pidfd, "%ld\n", &temp);
447*83ee113eSDavid van Moolenbroek 			oldpid = (pid_t)temp;
448*83ee113eSDavid van Moolenbroek 
449*83ee113eSDavid van Moolenbroek 			if (e != 0 && e != EOF) {
450*83ee113eSDavid van Moolenbroek 				if (oldpid && (kill(oldpid, SIGTERM) == 0)) {
451*83ee113eSDavid van Moolenbroek 					/*
452*83ee113eSDavid van Moolenbroek 					 * wait for the old process to
453*83ee113eSDavid van Moolenbroek 					 * cleanly terminate.
454*83ee113eSDavid van Moolenbroek 					 * Note kill() with sig=0 could
455*83ee113eSDavid van Moolenbroek 					 * detect termination but only
456*83ee113eSDavid van Moolenbroek 					 * the parent can be signaled...
457*83ee113eSDavid van Moolenbroek 					 */
458*83ee113eSDavid van Moolenbroek 					sleep(1);
459*83ee113eSDavid van Moolenbroek 				}
460*83ee113eSDavid van Moolenbroek 			}
461*83ee113eSDavid van Moolenbroek 			fclose(pidfd);
462*83ee113eSDavid van Moolenbroek 		}
463*83ee113eSDavid van Moolenbroek 	}
464*83ee113eSDavid van Moolenbroek 
465*83ee113eSDavid van Moolenbroek 	if (!quiet) {
466*83ee113eSDavid van Moolenbroek 		log_info("%s %s", message, PACKAGE_VERSION);
467*83ee113eSDavid van Moolenbroek 		log_info(copyright);
468*83ee113eSDavid van Moolenbroek 		log_info(arr);
469*83ee113eSDavid van Moolenbroek 		log_info(url);
470*83ee113eSDavid van Moolenbroek 		log_info("%s", "");
471*83ee113eSDavid van Moolenbroek 	} else {
472*83ee113eSDavid van Moolenbroek 		log_perror = 0;
473*83ee113eSDavid van Moolenbroek 		quiet_interface_discovery = 1;
474*83ee113eSDavid van Moolenbroek 	}
475*83ee113eSDavid van Moolenbroek 
476*83ee113eSDavid van Moolenbroek 	/* If we're given a relay agent address to insert, for testing
477*83ee113eSDavid van Moolenbroek 	   purposes, figure out what it is. */
478*83ee113eSDavid van Moolenbroek 	if (mockup_relay) {
479*83ee113eSDavid van Moolenbroek 		if (!inet_aton(mockup_relay, &giaddr)) {
480*83ee113eSDavid van Moolenbroek 			struct hostent *he;
481*83ee113eSDavid van Moolenbroek 			he = gethostbyname(mockup_relay);
482*83ee113eSDavid van Moolenbroek 			if (he) {
483*83ee113eSDavid van Moolenbroek 				memcpy(&giaddr, he->h_addr_list[0],
484*83ee113eSDavid van Moolenbroek 				       sizeof giaddr);
485*83ee113eSDavid van Moolenbroek 			} else {
486*83ee113eSDavid van Moolenbroek 				log_fatal("%s: no such host", mockup_relay);
487*83ee113eSDavid van Moolenbroek 			}
488*83ee113eSDavid van Moolenbroek 		}
489*83ee113eSDavid van Moolenbroek 	}
490*83ee113eSDavid van Moolenbroek 
491*83ee113eSDavid van Moolenbroek 	/* Get the current time... */
492*83ee113eSDavid van Moolenbroek 	gettimeofday(&cur_tv, NULL);
493*83ee113eSDavid van Moolenbroek 
494*83ee113eSDavid van Moolenbroek 	sockaddr_broadcast.sin_family = AF_INET;
495*83ee113eSDavid van Moolenbroek 	sockaddr_broadcast.sin_port = remote_port;
496*83ee113eSDavid van Moolenbroek 	if (server) {
497*83ee113eSDavid van Moolenbroek 		if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) {
498*83ee113eSDavid van Moolenbroek 			struct hostent *he;
499*83ee113eSDavid van Moolenbroek 			he = gethostbyname(server);
500*83ee113eSDavid van Moolenbroek 			if (he) {
501*83ee113eSDavid van Moolenbroek 				memcpy(&sockaddr_broadcast.sin_addr,
502*83ee113eSDavid van Moolenbroek 				       he->h_addr_list[0],
503*83ee113eSDavid van Moolenbroek 				       sizeof sockaddr_broadcast.sin_addr);
504*83ee113eSDavid van Moolenbroek 			} else
505*83ee113eSDavid van Moolenbroek 				sockaddr_broadcast.sin_addr.s_addr =
506*83ee113eSDavid van Moolenbroek 					INADDR_BROADCAST;
507*83ee113eSDavid van Moolenbroek 		}
508*83ee113eSDavid van Moolenbroek 	} else {
509*83ee113eSDavid van Moolenbroek 		sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
510*83ee113eSDavid van Moolenbroek 	}
511*83ee113eSDavid van Moolenbroek 
512*83ee113eSDavid van Moolenbroek 	inaddr_any.s_addr = INADDR_ANY;
513*83ee113eSDavid van Moolenbroek 
514*83ee113eSDavid van Moolenbroek 	/* Stateless special case. */
515*83ee113eSDavid van Moolenbroek 	if (stateless) {
516*83ee113eSDavid van Moolenbroek 		if (release_mode || (wanted_ia_na > 0) ||
517*83ee113eSDavid van Moolenbroek 		    wanted_ia_ta || wanted_ia_pd ||
518*83ee113eSDavid van Moolenbroek 		    (interfaces_requested != 1)) {
519*83ee113eSDavid van Moolenbroek 			usage();
520*83ee113eSDavid van Moolenbroek 		}
521*83ee113eSDavid van Moolenbroek 		run_stateless(exit_mode);
522*83ee113eSDavid van Moolenbroek 		return 0;
523*83ee113eSDavid van Moolenbroek 	}
524*83ee113eSDavid van Moolenbroek 
525*83ee113eSDavid van Moolenbroek 	/* Discover all the network interfaces. */
526*83ee113eSDavid van Moolenbroek 	discover_interfaces(DISCOVER_UNCONFIGURED);
527*83ee113eSDavid van Moolenbroek 
528*83ee113eSDavid van Moolenbroek 	/* Parse the dhclient.conf file. */
529*83ee113eSDavid van Moolenbroek 	read_client_conf();
530*83ee113eSDavid van Moolenbroek 
531*83ee113eSDavid van Moolenbroek 	/* Parse the lease database. */
532*83ee113eSDavid van Moolenbroek 	read_client_leases();
533*83ee113eSDavid van Moolenbroek 
534*83ee113eSDavid van Moolenbroek 	/* Rewrite the lease database... */
535*83ee113eSDavid van Moolenbroek 	rewrite_client_leases();
536*83ee113eSDavid van Moolenbroek 
537*83ee113eSDavid van Moolenbroek 	/* XXX */
538*83ee113eSDavid van Moolenbroek /* 	config_counter(&snd_counter, &rcv_counter); */
539*83ee113eSDavid van Moolenbroek 
540*83ee113eSDavid van Moolenbroek 	/*
541*83ee113eSDavid van Moolenbroek 	 * If no broadcast interfaces were discovered, call the script
542*83ee113eSDavid van Moolenbroek 	 * and tell it so.
543*83ee113eSDavid van Moolenbroek 	 */
544*83ee113eSDavid van Moolenbroek 	if (!interfaces) {
545*83ee113eSDavid van Moolenbroek 		/*
546*83ee113eSDavid van Moolenbroek 		 * Call dhclient-script with the NBI flag,
547*83ee113eSDavid van Moolenbroek 		 * in case somebody cares.
548*83ee113eSDavid van Moolenbroek 		 */
549*83ee113eSDavid van Moolenbroek 		script_init(NULL, "NBI", NULL);
550*83ee113eSDavid van Moolenbroek 		script_go(NULL);
551*83ee113eSDavid van Moolenbroek 
552*83ee113eSDavid van Moolenbroek 		/*
553*83ee113eSDavid van Moolenbroek 		 * If we haven't been asked to persist, waiting for new
554*83ee113eSDavid van Moolenbroek 		 * interfaces, then just exit.
555*83ee113eSDavid van Moolenbroek 		 */
556*83ee113eSDavid van Moolenbroek 		if (!persist) {
557*83ee113eSDavid van Moolenbroek 			/* Nothing more to do. */
558*83ee113eSDavid van Moolenbroek 			log_info("No broadcast interfaces found - exiting.");
559*83ee113eSDavid van Moolenbroek 			exit(0);
560*83ee113eSDavid van Moolenbroek 		}
561*83ee113eSDavid van Moolenbroek 	} else if (!release_mode && !exit_mode) {
562*83ee113eSDavid van Moolenbroek 		/* Call the script with the list of interfaces. */
563*83ee113eSDavid van Moolenbroek 		for (ip = interfaces; ip; ip = ip->next) {
564*83ee113eSDavid van Moolenbroek 			/*
565*83ee113eSDavid van Moolenbroek 			 * If interfaces were specified, don't configure
566*83ee113eSDavid van Moolenbroek 			 * interfaces that weren't specified!
567*83ee113eSDavid van Moolenbroek 			 */
568*83ee113eSDavid van Moolenbroek 			if ((interfaces_requested > 0) &&
569*83ee113eSDavid van Moolenbroek 			    ((ip->flags & (INTERFACE_REQUESTED |
570*83ee113eSDavid van Moolenbroek 					   INTERFACE_AUTOMATIC)) !=
571*83ee113eSDavid van Moolenbroek 			     INTERFACE_REQUESTED))
572*83ee113eSDavid van Moolenbroek 				continue;
573*83ee113eSDavid van Moolenbroek 
574*83ee113eSDavid van Moolenbroek 			if (local_family == AF_INET6) {
575*83ee113eSDavid van Moolenbroek 				script_init(ip->client, "PREINIT6", NULL);
576*83ee113eSDavid van Moolenbroek 			} else {
577*83ee113eSDavid van Moolenbroek 				script_init(ip->client, "PREINIT", NULL);
578*83ee113eSDavid van Moolenbroek 			    	if (ip->client->alias != NULL)
579*83ee113eSDavid van Moolenbroek 					script_write_params(ip->client,
580*83ee113eSDavid van Moolenbroek 							    "alias_",
581*83ee113eSDavid van Moolenbroek 							    ip->client->alias);
582*83ee113eSDavid van Moolenbroek 			}
583*83ee113eSDavid van Moolenbroek 			script_go(ip->client);
584*83ee113eSDavid van Moolenbroek 		}
585*83ee113eSDavid van Moolenbroek 	}
586*83ee113eSDavid van Moolenbroek 
587*83ee113eSDavid van Moolenbroek 	/* At this point, all the interfaces that the script thinks
588*83ee113eSDavid van Moolenbroek 	   are relevant should be running, so now we once again call
589*83ee113eSDavid van Moolenbroek 	   discover_interfaces(), and this time ask it to actually set
590*83ee113eSDavid van Moolenbroek 	   up the interfaces. */
591*83ee113eSDavid van Moolenbroek 	discover_interfaces(interfaces_requested != 0
592*83ee113eSDavid van Moolenbroek 			    ? DISCOVER_REQUESTED
593*83ee113eSDavid van Moolenbroek 			    : DISCOVER_RUNNING);
594*83ee113eSDavid van Moolenbroek 
595*83ee113eSDavid van Moolenbroek 	/* Make up a seed for the random number generator from current
596*83ee113eSDavid van Moolenbroek 	   time plus the sum of the last four bytes of each
597*83ee113eSDavid van Moolenbroek 	   interface's hardware address interpreted as an integer.
598*83ee113eSDavid van Moolenbroek 	   Not much entropy, but we're booting, so we're not likely to
599*83ee113eSDavid van Moolenbroek 	   find anything better. */
600*83ee113eSDavid van Moolenbroek 	seed = 0;
601*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip->next) {
602*83ee113eSDavid van Moolenbroek 		int junk;
603*83ee113eSDavid van Moolenbroek 		memcpy(&junk,
604*83ee113eSDavid van Moolenbroek 		       &ip->hw_address.hbuf[ip->hw_address.hlen -
605*83ee113eSDavid van Moolenbroek 					    sizeof seed], sizeof seed);
606*83ee113eSDavid van Moolenbroek 		seed += junk;
607*83ee113eSDavid van Moolenbroek 	}
608*83ee113eSDavid van Moolenbroek 	srandom(seed + cur_time + (unsigned)getpid());
609*83ee113eSDavid van Moolenbroek 
610*83ee113eSDavid van Moolenbroek 
611*83ee113eSDavid van Moolenbroek 	/*
612*83ee113eSDavid van Moolenbroek 	 * Establish a default DUID.  We always do so for v6 and
613*83ee113eSDavid van Moolenbroek 	 * do so if desired for v4 via the -D or -i options
614*83ee113eSDavid van Moolenbroek 	 */
615*83ee113eSDavid van Moolenbroek 	if ((local_family == AF_INET6) ||
616*83ee113eSDavid van Moolenbroek 	    ((local_family == AF_INET) && (duid_v4 == 1))) {
617*83ee113eSDavid van Moolenbroek 		if (default_duid.len == 0) {
618*83ee113eSDavid van Moolenbroek 			if (default_duid.buffer != NULL)
619*83ee113eSDavid van Moolenbroek 				data_string_forget(&default_duid, MDL);
620*83ee113eSDavid van Moolenbroek 
621*83ee113eSDavid van Moolenbroek 			form_duid(&default_duid, MDL);
622*83ee113eSDavid van Moolenbroek 			write_duid(&default_duid);
623*83ee113eSDavid van Moolenbroek 		}
624*83ee113eSDavid van Moolenbroek 	}
625*83ee113eSDavid van Moolenbroek 
626*83ee113eSDavid van Moolenbroek 	/* Start a configuration state machine for each interface. */
627*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
628*83ee113eSDavid van Moolenbroek 	if (local_family == AF_INET6) {
629*83ee113eSDavid van Moolenbroek 		for (ip = interfaces ; ip != NULL ; ip = ip->next) {
630*83ee113eSDavid van Moolenbroek 			for (client = ip->client ; client != NULL ;
631*83ee113eSDavid van Moolenbroek 			     client = client->next) {
632*83ee113eSDavid van Moolenbroek 				if (release_mode) {
633*83ee113eSDavid van Moolenbroek 					start_release6(client);
634*83ee113eSDavid van Moolenbroek 					continue;
635*83ee113eSDavid van Moolenbroek 				} else if (exit_mode) {
636*83ee113eSDavid van Moolenbroek 					unconfigure6(client, "STOP6");
637*83ee113eSDavid van Moolenbroek 					continue;
638*83ee113eSDavid van Moolenbroek 				}
639*83ee113eSDavid van Moolenbroek 
640*83ee113eSDavid van Moolenbroek 				/* If we have a previous binding, Confirm
641*83ee113eSDavid van Moolenbroek 				 * that we can (or can't) still use it.
642*83ee113eSDavid van Moolenbroek 				 */
643*83ee113eSDavid van Moolenbroek 				if ((client->active_lease != NULL) &&
644*83ee113eSDavid van Moolenbroek 				    !client->active_lease->released)
645*83ee113eSDavid van Moolenbroek 					start_confirm6(client);
646*83ee113eSDavid van Moolenbroek 				else
647*83ee113eSDavid van Moolenbroek 					start_init6(client);
648*83ee113eSDavid van Moolenbroek 			}
649*83ee113eSDavid van Moolenbroek 		}
650*83ee113eSDavid van Moolenbroek 	} else
651*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
652*83ee113eSDavid van Moolenbroek 	{
653*83ee113eSDavid van Moolenbroek 		for (ip = interfaces ; ip ; ip = ip->next) {
654*83ee113eSDavid van Moolenbroek 			ip->flags |= INTERFACE_RUNNING;
655*83ee113eSDavid van Moolenbroek 			for (client = ip->client ; client ;
656*83ee113eSDavid van Moolenbroek 			     client = client->next) {
657*83ee113eSDavid van Moolenbroek 				if (exit_mode)
658*83ee113eSDavid van Moolenbroek 					state_stop(client);
659*83ee113eSDavid van Moolenbroek 				else if (release_mode)
660*83ee113eSDavid van Moolenbroek 					do_release(client);
661*83ee113eSDavid van Moolenbroek 				else {
662*83ee113eSDavid van Moolenbroek 					client->state = S_INIT;
663*83ee113eSDavid van Moolenbroek 
664*83ee113eSDavid van Moolenbroek 					if (top_level_config.initial_delay>0)
665*83ee113eSDavid van Moolenbroek 					{
666*83ee113eSDavid van Moolenbroek 						tv.tv_sec = 0;
667*83ee113eSDavid van Moolenbroek 						if (top_level_config.
668*83ee113eSDavid van Moolenbroek 						    initial_delay>1)
669*83ee113eSDavid van Moolenbroek 							tv.tv_sec = cur_time
670*83ee113eSDavid van Moolenbroek 							+ random()
671*83ee113eSDavid van Moolenbroek 							% (top_level_config.
672*83ee113eSDavid van Moolenbroek 							   initial_delay-1);
673*83ee113eSDavid van Moolenbroek 						tv.tv_usec = random()
674*83ee113eSDavid van Moolenbroek 							% 1000000;
675*83ee113eSDavid van Moolenbroek 						/*
676*83ee113eSDavid van Moolenbroek 						 * this gives better
677*83ee113eSDavid van Moolenbroek 						 * distribution than just
678*83ee113eSDavid van Moolenbroek 						 *whole seconds
679*83ee113eSDavid van Moolenbroek 						 */
680*83ee113eSDavid van Moolenbroek 						add_timeout(&tv, state_reboot,
681*83ee113eSDavid van Moolenbroek 						            client, 0, 0);
682*83ee113eSDavid van Moolenbroek 					} else {
683*83ee113eSDavid van Moolenbroek 						state_reboot(client);
684*83ee113eSDavid van Moolenbroek 					}
685*83ee113eSDavid van Moolenbroek 				}
686*83ee113eSDavid van Moolenbroek 			}
687*83ee113eSDavid van Moolenbroek 		}
688*83ee113eSDavid van Moolenbroek 	}
689*83ee113eSDavid van Moolenbroek 
690*83ee113eSDavid van Moolenbroek 	if (exit_mode)
691*83ee113eSDavid van Moolenbroek 		return 0;
692*83ee113eSDavid van Moolenbroek 	if (release_mode) {
693*83ee113eSDavid van Moolenbroek #ifndef DHCPv6
694*83ee113eSDavid van Moolenbroek 		return 0;
695*83ee113eSDavid van Moolenbroek #else
696*83ee113eSDavid van Moolenbroek 		if (local_family == AF_INET6) {
697*83ee113eSDavid van Moolenbroek 			if (onetry)
698*83ee113eSDavid van Moolenbroek 				return 0;
699*83ee113eSDavid van Moolenbroek 		} else
700*83ee113eSDavid van Moolenbroek 			return 0;
701*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
702*83ee113eSDavid van Moolenbroek 	}
703*83ee113eSDavid van Moolenbroek 
704*83ee113eSDavid van Moolenbroek 	/* Start up a listener for the object management API protocol. */
705*83ee113eSDavid van Moolenbroek 	if (top_level_config.omapi_port != -1) {
706*83ee113eSDavid van Moolenbroek 		listener = NULL;
707*83ee113eSDavid van Moolenbroek 		result = omapi_generic_new(&listener, MDL);
708*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
709*83ee113eSDavid van Moolenbroek 			log_fatal("Can't allocate new generic object: %s\n",
710*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
711*83ee113eSDavid van Moolenbroek 		result = omapi_protocol_listen(listener,
712*83ee113eSDavid van Moolenbroek 					       (unsigned)
713*83ee113eSDavid van Moolenbroek 					       top_level_config.omapi_port,
714*83ee113eSDavid van Moolenbroek 					       1);
715*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
716*83ee113eSDavid van Moolenbroek 			log_fatal("Can't start OMAPI protocol: %s",
717*83ee113eSDavid van Moolenbroek 				  isc_result_totext (result));
718*83ee113eSDavid van Moolenbroek 	}
719*83ee113eSDavid van Moolenbroek 
720*83ee113eSDavid van Moolenbroek 	/* Set up the bootp packet handler... */
721*83ee113eSDavid van Moolenbroek 	bootp_packet_handler = do_packet;
722*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
723*83ee113eSDavid van Moolenbroek 	dhcpv6_packet_handler = do_packet6;
724*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
725*83ee113eSDavid van Moolenbroek 
726*83ee113eSDavid van Moolenbroek #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
727*83ee113eSDavid van Moolenbroek 		defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
728*83ee113eSDavid van Moolenbroek 	dmalloc_cutoff_generation = dmalloc_generation;
729*83ee113eSDavid van Moolenbroek 	dmalloc_longterm = dmalloc_outstanding;
730*83ee113eSDavid van Moolenbroek 	dmalloc_outstanding = 0;
731*83ee113eSDavid van Moolenbroek #endif
732*83ee113eSDavid van Moolenbroek 
733*83ee113eSDavid van Moolenbroek         /* install signal handlers */
734*83ee113eSDavid van Moolenbroek 	signal(SIGINT, dhcp_signal_handler);   /* control-c */
735*83ee113eSDavid van Moolenbroek 	signal(SIGTERM, dhcp_signal_handler);  /* kill */
736*83ee113eSDavid van Moolenbroek 
737*83ee113eSDavid van Moolenbroek 	/* If we're not going to daemonize, write the pid file
738*83ee113eSDavid van Moolenbroek 	   now. */
739*83ee113eSDavid van Moolenbroek 	if (no_daemon || nowait)
740*83ee113eSDavid van Moolenbroek 		write_client_pid_file();
741*83ee113eSDavid van Moolenbroek 
742*83ee113eSDavid van Moolenbroek 	/* Start dispatching packets and timeouts... */
743*83ee113eSDavid van Moolenbroek 	dispatch();
744*83ee113eSDavid van Moolenbroek 
745*83ee113eSDavid van Moolenbroek 	/* In fact dispatch() never returns. */
746*83ee113eSDavid van Moolenbroek 	return 0;
747*83ee113eSDavid van Moolenbroek }
748*83ee113eSDavid van Moolenbroek 
usage()749*83ee113eSDavid van Moolenbroek static void usage()
750*83ee113eSDavid van Moolenbroek {
751*83ee113eSDavid van Moolenbroek 	log_info("%s %s", message, PACKAGE_VERSION);
752*83ee113eSDavid van Moolenbroek 	log_info(copyright);
753*83ee113eSDavid van Moolenbroek 	log_info(arr);
754*83ee113eSDavid van Moolenbroek 	log_info(url);
755*83ee113eSDavid van Moolenbroek 
756*83ee113eSDavid van Moolenbroek 
757*83ee113eSDavid van Moolenbroek 	log_fatal("Usage: dhclient "
758*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
759*83ee113eSDavid van Moolenbroek 		  "[-4|-6] [-SNTPI1dvrxi] [-nw] [-m] [-p <port>] [-D LL|LLT] \n"
760*83ee113eSDavid van Moolenbroek #else /* DHCPv6 */
761*83ee113eSDavid van Moolenbroek 		  "[-I1dvrxi] [-nw] [-m] [-p <port>] [-D LL|LLT] \n"
762*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
763*83ee113eSDavid van Moolenbroek 		  "                [-s server-addr] [-cf config-file] "
764*83ee113eSDavid van Moolenbroek 		  "[-lf lease-file]\n"
765*83ee113eSDavid van Moolenbroek 		  "                [-pf pid-file] [--no-pid] [-e VAR=val]\n"
766*83ee113eSDavid van Moolenbroek 		  "                [-sf script-file] [interface]");
767*83ee113eSDavid van Moolenbroek }
768*83ee113eSDavid van Moolenbroek 
run_stateless(int exit_mode)769*83ee113eSDavid van Moolenbroek void run_stateless(int exit_mode)
770*83ee113eSDavid van Moolenbroek {
771*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
772*83ee113eSDavid van Moolenbroek 	struct client_state *client;
773*83ee113eSDavid van Moolenbroek 	omapi_object_t *listener;
774*83ee113eSDavid van Moolenbroek 	isc_result_t result;
775*83ee113eSDavid van Moolenbroek 
776*83ee113eSDavid van Moolenbroek 	/* Discover the network interface. */
777*83ee113eSDavid van Moolenbroek 	discover_interfaces(DISCOVER_REQUESTED);
778*83ee113eSDavid van Moolenbroek 
779*83ee113eSDavid van Moolenbroek 	if (!interfaces)
780*83ee113eSDavid van Moolenbroek 		usage();
781*83ee113eSDavid van Moolenbroek 
782*83ee113eSDavid van Moolenbroek 	/* Parse the dhclient.conf file. */
783*83ee113eSDavid van Moolenbroek 	read_client_conf();
784*83ee113eSDavid van Moolenbroek 
785*83ee113eSDavid van Moolenbroek 	/* Parse the lease database. */
786*83ee113eSDavid van Moolenbroek 	read_client_leases();
787*83ee113eSDavid van Moolenbroek 
788*83ee113eSDavid van Moolenbroek 	/* Establish a default DUID. */
789*83ee113eSDavid van Moolenbroek 	if (default_duid.len == 0) {
790*83ee113eSDavid van Moolenbroek 		if (default_duid.buffer != NULL)
791*83ee113eSDavid van Moolenbroek 			data_string_forget(&default_duid, MDL);
792*83ee113eSDavid van Moolenbroek 
793*83ee113eSDavid van Moolenbroek 		form_duid(&default_duid, MDL);
794*83ee113eSDavid van Moolenbroek 	}
795*83ee113eSDavid van Moolenbroek 
796*83ee113eSDavid van Moolenbroek 	/* Start a configuration state machine. */
797*83ee113eSDavid van Moolenbroek 	for (client = interfaces->client ;
798*83ee113eSDavid van Moolenbroek 	     client != NULL ;
799*83ee113eSDavid van Moolenbroek 	     client = client->next) {
800*83ee113eSDavid van Moolenbroek 		if (exit_mode) {
801*83ee113eSDavid van Moolenbroek 			unconfigure6(client, "STOP6");
802*83ee113eSDavid van Moolenbroek 			continue;
803*83ee113eSDavid van Moolenbroek 		}
804*83ee113eSDavid van Moolenbroek 		start_info_request6(client);
805*83ee113eSDavid van Moolenbroek 	}
806*83ee113eSDavid van Moolenbroek 	if (exit_mode)
807*83ee113eSDavid van Moolenbroek 		return;
808*83ee113eSDavid van Moolenbroek 
809*83ee113eSDavid van Moolenbroek 	/* Start up a listener for the object management API protocol. */
810*83ee113eSDavid van Moolenbroek 	if (top_level_config.omapi_port != -1) {
811*83ee113eSDavid van Moolenbroek 		listener = NULL;
812*83ee113eSDavid van Moolenbroek 		result = omapi_generic_new(&listener, MDL);
813*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
814*83ee113eSDavid van Moolenbroek 			log_fatal("Can't allocate new generic object: %s\n",
815*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
816*83ee113eSDavid van Moolenbroek 		result = omapi_protocol_listen(listener,
817*83ee113eSDavid van Moolenbroek 					       (unsigned)
818*83ee113eSDavid van Moolenbroek 					       top_level_config.omapi_port,
819*83ee113eSDavid van Moolenbroek 					       1);
820*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
821*83ee113eSDavid van Moolenbroek 			log_fatal("Can't start OMAPI protocol: %s",
822*83ee113eSDavid van Moolenbroek 				  isc_result_totext(result));
823*83ee113eSDavid van Moolenbroek 	}
824*83ee113eSDavid van Moolenbroek 
825*83ee113eSDavid van Moolenbroek 	/* Set up the packet handler... */
826*83ee113eSDavid van Moolenbroek 	dhcpv6_packet_handler = do_packet6;
827*83ee113eSDavid van Moolenbroek 
828*83ee113eSDavid van Moolenbroek #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
829*83ee113eSDavid van Moolenbroek 		defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
830*83ee113eSDavid van Moolenbroek 	dmalloc_cutoff_generation = dmalloc_generation;
831*83ee113eSDavid van Moolenbroek 	dmalloc_longterm = dmalloc_outstanding;
832*83ee113eSDavid van Moolenbroek 	dmalloc_outstanding = 0;
833*83ee113eSDavid van Moolenbroek #endif
834*83ee113eSDavid van Moolenbroek 
835*83ee113eSDavid van Moolenbroek 	/* If we're not supposed to wait before getting the address,
836*83ee113eSDavid van Moolenbroek 	   don't. */
837*83ee113eSDavid van Moolenbroek 	if (nowait)
838*83ee113eSDavid van Moolenbroek 		finish_daemon();
839*83ee113eSDavid van Moolenbroek 
840*83ee113eSDavid van Moolenbroek 	/* If we're not going to daemonize, write the pid file
841*83ee113eSDavid van Moolenbroek 	   now. */
842*83ee113eSDavid van Moolenbroek 	if (no_daemon || nowait)
843*83ee113eSDavid van Moolenbroek 		write_client_pid_file();
844*83ee113eSDavid van Moolenbroek 
845*83ee113eSDavid van Moolenbroek 	/* Start dispatching packets and timeouts... */
846*83ee113eSDavid van Moolenbroek 	dispatch();
847*83ee113eSDavid van Moolenbroek 
848*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
849*83ee113eSDavid van Moolenbroek 	return;
850*83ee113eSDavid van Moolenbroek }
851*83ee113eSDavid van Moolenbroek 
find_class(struct class ** c,const char * s,const char * file,int line)852*83ee113eSDavid van Moolenbroek isc_result_t find_class (struct class **c,
853*83ee113eSDavid van Moolenbroek 		const char *s, const char *file, int line)
854*83ee113eSDavid van Moolenbroek {
855*83ee113eSDavid van Moolenbroek 	return 0;
856*83ee113eSDavid van Moolenbroek }
857*83ee113eSDavid van Moolenbroek 
check_collection(packet,lease,collection)858*83ee113eSDavid van Moolenbroek int check_collection (packet, lease, collection)
859*83ee113eSDavid van Moolenbroek 	struct packet *packet;
860*83ee113eSDavid van Moolenbroek 	struct lease *lease;
861*83ee113eSDavid van Moolenbroek 	struct collection *collection;
862*83ee113eSDavid van Moolenbroek {
863*83ee113eSDavid van Moolenbroek 	return 0;
864*83ee113eSDavid van Moolenbroek }
865*83ee113eSDavid van Moolenbroek 
classify(packet,class)866*83ee113eSDavid van Moolenbroek void classify (packet, class)
867*83ee113eSDavid van Moolenbroek 	struct packet *packet;
868*83ee113eSDavid van Moolenbroek 	struct class *class;
869*83ee113eSDavid van Moolenbroek {
870*83ee113eSDavid van Moolenbroek }
871*83ee113eSDavid van Moolenbroek 
unbill_class(lease,class)872*83ee113eSDavid van Moolenbroek int unbill_class (lease, class)
873*83ee113eSDavid van Moolenbroek 	struct lease *lease;
874*83ee113eSDavid van Moolenbroek 	struct class *class;
875*83ee113eSDavid van Moolenbroek {
876*83ee113eSDavid van Moolenbroek 	return 0;
877*83ee113eSDavid van Moolenbroek }
878*83ee113eSDavid van Moolenbroek 
find_subnet(struct subnet ** sp,struct iaddr addr,const char * file,int line)879*83ee113eSDavid van Moolenbroek int find_subnet (struct subnet **sp,
880*83ee113eSDavid van Moolenbroek 		 struct iaddr addr, const char *file, int line)
881*83ee113eSDavid van Moolenbroek {
882*83ee113eSDavid van Moolenbroek 	return 0;
883*83ee113eSDavid van Moolenbroek }
884*83ee113eSDavid van Moolenbroek 
885*83ee113eSDavid van Moolenbroek /* Individual States:
886*83ee113eSDavid van Moolenbroek  *
887*83ee113eSDavid van Moolenbroek  * Each routine is called from the dhclient_state_machine() in one of
888*83ee113eSDavid van Moolenbroek  * these conditions:
889*83ee113eSDavid van Moolenbroek  * -> entering INIT state
890*83ee113eSDavid van Moolenbroek  * -> recvpacket_flag == 0: timeout in this state
891*83ee113eSDavid van Moolenbroek  * -> otherwise: received a packet in this state
892*83ee113eSDavid van Moolenbroek  *
893*83ee113eSDavid van Moolenbroek  * Return conditions as handled by dhclient_state_machine():
894*83ee113eSDavid van Moolenbroek  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
895*83ee113eSDavid van Moolenbroek  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
896*83ee113eSDavid van Moolenbroek  * Returns 0: finish the nap which was interrupted for no good reason.
897*83ee113eSDavid van Moolenbroek  *
898*83ee113eSDavid van Moolenbroek  * Several per-interface variables are used to keep track of the process:
899*83ee113eSDavid van Moolenbroek  *   active_lease: the lease that is being used on the interface
900*83ee113eSDavid van Moolenbroek  *                 (null pointer if not configured yet).
901*83ee113eSDavid van Moolenbroek  *   offered_leases: leases corresponding to DHCPOFFER messages that have
902*83ee113eSDavid van Moolenbroek  *		     been sent to us by DHCP servers.
903*83ee113eSDavid van Moolenbroek  *   acked_leases: leases corresponding to DHCPACK messages that have been
904*83ee113eSDavid van Moolenbroek  *		   sent to us by DHCP servers.
905*83ee113eSDavid van Moolenbroek  *   sendpacket: DHCP packet we're trying to send.
906*83ee113eSDavid van Moolenbroek  *   destination: IP address to send sendpacket to
907*83ee113eSDavid van Moolenbroek  * In addition, there are several relevant per-lease variables.
908*83ee113eSDavid van Moolenbroek  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
909*83ee113eSDavid van Moolenbroek  * In the active lease, these control the process of renewing the lease;
910*83ee113eSDavid van Moolenbroek  * In leases on the acked_leases list, this simply determines when we
911*83ee113eSDavid van Moolenbroek  * can no longer legitimately use the lease.
912*83ee113eSDavid van Moolenbroek  */
913*83ee113eSDavid van Moolenbroek 
914*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
915*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: dhclient.c,v 1.9 2014/07/12 12:09:37 spz Exp $");
916*83ee113eSDavid van Moolenbroek 
state_reboot(cpp)917*83ee113eSDavid van Moolenbroek void state_reboot (cpp)
918*83ee113eSDavid van Moolenbroek 	void *cpp;
919*83ee113eSDavid van Moolenbroek {
920*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
921*83ee113eSDavid van Moolenbroek 
922*83ee113eSDavid van Moolenbroek 	/* If we don't remember an active lease, go straight to INIT. */
923*83ee113eSDavid van Moolenbroek 	if (!client -> active ||
924*83ee113eSDavid van Moolenbroek 	    client -> active -> is_bootp ||
925*83ee113eSDavid van Moolenbroek 	    client -> active -> expiry <= cur_time) {
926*83ee113eSDavid van Moolenbroek 		state_init (client);
927*83ee113eSDavid van Moolenbroek 		return;
928*83ee113eSDavid van Moolenbroek 	}
929*83ee113eSDavid van Moolenbroek 
930*83ee113eSDavid van Moolenbroek 	/* We are in the rebooting state. */
931*83ee113eSDavid van Moolenbroek 	client -> state = S_REBOOTING;
932*83ee113eSDavid van Moolenbroek 
933*83ee113eSDavid van Moolenbroek 	/*
934*83ee113eSDavid van Moolenbroek 	 * make_request doesn't initialize xid because it normally comes
935*83ee113eSDavid van Moolenbroek 	 * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
936*83ee113eSDavid van Moolenbroek 	 * so pick an xid now.
937*83ee113eSDavid van Moolenbroek 	 */
938*83ee113eSDavid van Moolenbroek 	client -> xid = random ();
939*83ee113eSDavid van Moolenbroek 
940*83ee113eSDavid van Moolenbroek 	/*
941*83ee113eSDavid van Moolenbroek 	 * Make a DHCPREQUEST packet, and set
942*83ee113eSDavid van Moolenbroek 	 * appropriate per-interface flags.
943*83ee113eSDavid van Moolenbroek 	 */
944*83ee113eSDavid van Moolenbroek 	make_request (client, client -> active);
945*83ee113eSDavid van Moolenbroek 	client -> destination = iaddr_broadcast;
946*83ee113eSDavid van Moolenbroek 	client -> first_sending = cur_time;
947*83ee113eSDavid van Moolenbroek 	client -> interval = client -> config -> initial_interval;
948*83ee113eSDavid van Moolenbroek 
949*83ee113eSDavid van Moolenbroek 	/* Zap the medium list... */
950*83ee113eSDavid van Moolenbroek 	client -> medium = NULL;
951*83ee113eSDavid van Moolenbroek 
952*83ee113eSDavid van Moolenbroek 	/* Send out the first DHCPREQUEST packet. */
953*83ee113eSDavid van Moolenbroek 	send_request (client);
954*83ee113eSDavid van Moolenbroek }
955*83ee113eSDavid van Moolenbroek 
956*83ee113eSDavid van Moolenbroek /* Called when a lease has completely expired and we've been unable to
957*83ee113eSDavid van Moolenbroek    renew it. */
958*83ee113eSDavid van Moolenbroek 
state_init(cpp)959*83ee113eSDavid van Moolenbroek void state_init (cpp)
960*83ee113eSDavid van Moolenbroek 	void *cpp;
961*83ee113eSDavid van Moolenbroek {
962*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
963*83ee113eSDavid van Moolenbroek 
964*83ee113eSDavid van Moolenbroek 	ASSERT_STATE(state, S_INIT);
965*83ee113eSDavid van Moolenbroek 
966*83ee113eSDavid van Moolenbroek 	/* Make a DHCPDISCOVER packet, and set appropriate per-interface
967*83ee113eSDavid van Moolenbroek 	   flags. */
968*83ee113eSDavid van Moolenbroek 	make_discover (client, client -> active);
969*83ee113eSDavid van Moolenbroek 	client -> xid = client -> packet.xid;
970*83ee113eSDavid van Moolenbroek 	client -> destination = iaddr_broadcast;
971*83ee113eSDavid van Moolenbroek 	client -> state = S_SELECTING;
972*83ee113eSDavid van Moolenbroek 	client -> first_sending = cur_time;
973*83ee113eSDavid van Moolenbroek 	client -> interval = client -> config -> initial_interval;
974*83ee113eSDavid van Moolenbroek 
975*83ee113eSDavid van Moolenbroek 	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
976*83ee113eSDavid van Moolenbroek 	   to go out. */
977*83ee113eSDavid van Moolenbroek 	send_discover (client);
978*83ee113eSDavid van Moolenbroek }
979*83ee113eSDavid van Moolenbroek 
980*83ee113eSDavid van Moolenbroek /*
981*83ee113eSDavid van Moolenbroek  * state_selecting is called when one or more DHCPOFFER packets have been
982*83ee113eSDavid van Moolenbroek  * received and a configurable period of time has passed.
983*83ee113eSDavid van Moolenbroek  */
984*83ee113eSDavid van Moolenbroek 
state_selecting(cpp)985*83ee113eSDavid van Moolenbroek void state_selecting (cpp)
986*83ee113eSDavid van Moolenbroek 	void *cpp;
987*83ee113eSDavid van Moolenbroek {
988*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
989*83ee113eSDavid van Moolenbroek 	struct client_lease *lp, *next, *picked;
990*83ee113eSDavid van Moolenbroek 
991*83ee113eSDavid van Moolenbroek 
992*83ee113eSDavid van Moolenbroek 	ASSERT_STATE(state, S_SELECTING);
993*83ee113eSDavid van Moolenbroek 
994*83ee113eSDavid van Moolenbroek 	/*
995*83ee113eSDavid van Moolenbroek 	 * Cancel state_selecting and send_discover timeouts, since either
996*83ee113eSDavid van Moolenbroek 	 * one could have got us here.
997*83ee113eSDavid van Moolenbroek 	 */
998*83ee113eSDavid van Moolenbroek 	cancel_timeout (state_selecting, client);
999*83ee113eSDavid van Moolenbroek 	cancel_timeout (send_discover, client);
1000*83ee113eSDavid van Moolenbroek 
1001*83ee113eSDavid van Moolenbroek 	/*
1002*83ee113eSDavid van Moolenbroek 	 * We have received one or more DHCPOFFER packets.   Currently,
1003*83ee113eSDavid van Moolenbroek 	 * the only criterion by which we judge leases is whether or
1004*83ee113eSDavid van Moolenbroek 	 * not we get a response when we arp for them.
1005*83ee113eSDavid van Moolenbroek 	 */
1006*83ee113eSDavid van Moolenbroek 	picked = NULL;
1007*83ee113eSDavid van Moolenbroek 	for (lp = client -> offered_leases; lp; lp = next) {
1008*83ee113eSDavid van Moolenbroek 		next = lp -> next;
1009*83ee113eSDavid van Moolenbroek 
1010*83ee113eSDavid van Moolenbroek 		/*
1011*83ee113eSDavid van Moolenbroek 		 * Check to see if we got an ARPREPLY for the address
1012*83ee113eSDavid van Moolenbroek 		 * in this particular lease.
1013*83ee113eSDavid van Moolenbroek 		 */
1014*83ee113eSDavid van Moolenbroek 		if (!picked) {
1015*83ee113eSDavid van Moolenbroek 			picked = lp;
1016*83ee113eSDavid van Moolenbroek 			picked -> next = NULL;
1017*83ee113eSDavid van Moolenbroek 		} else {
1018*83ee113eSDavid van Moolenbroek 			destroy_client_lease (lp);
1019*83ee113eSDavid van Moolenbroek 		}
1020*83ee113eSDavid van Moolenbroek 	}
1021*83ee113eSDavid van Moolenbroek 	client -> offered_leases = NULL;
1022*83ee113eSDavid van Moolenbroek 
1023*83ee113eSDavid van Moolenbroek 	/*
1024*83ee113eSDavid van Moolenbroek 	 * If we just tossed all the leases we were offered, go back
1025*83ee113eSDavid van Moolenbroek 	 * to square one.
1026*83ee113eSDavid van Moolenbroek 	 */
1027*83ee113eSDavid van Moolenbroek 	if (!picked) {
1028*83ee113eSDavid van Moolenbroek 		client -> state = S_INIT;
1029*83ee113eSDavid van Moolenbroek 		state_init (client);
1030*83ee113eSDavid van Moolenbroek 		return;
1031*83ee113eSDavid van Moolenbroek 	}
1032*83ee113eSDavid van Moolenbroek 
1033*83ee113eSDavid van Moolenbroek 	/* If it was a BOOTREPLY, we can just take the address right now. */
1034*83ee113eSDavid van Moolenbroek 	if (picked -> is_bootp) {
1035*83ee113eSDavid van Moolenbroek 		client -> new = picked;
1036*83ee113eSDavid van Moolenbroek 
1037*83ee113eSDavid van Moolenbroek 		/* Make up some lease expiry times
1038*83ee113eSDavid van Moolenbroek 		   XXX these should be configurable. */
1039*83ee113eSDavid van Moolenbroek 		client -> new -> expiry = cur_time + 12000;
1040*83ee113eSDavid van Moolenbroek 		client -> new -> renewal += cur_time + 8000;
1041*83ee113eSDavid van Moolenbroek 		client -> new -> rebind += cur_time + 10000;
1042*83ee113eSDavid van Moolenbroek 
1043*83ee113eSDavid van Moolenbroek 		client -> state = S_REQUESTING;
1044*83ee113eSDavid van Moolenbroek 
1045*83ee113eSDavid van Moolenbroek 		/* Bind to the address we received. */
1046*83ee113eSDavid van Moolenbroek 		bind_lease (client);
1047*83ee113eSDavid van Moolenbroek 		return;
1048*83ee113eSDavid van Moolenbroek 	}
1049*83ee113eSDavid van Moolenbroek 
1050*83ee113eSDavid van Moolenbroek 	/* Go to the REQUESTING state. */
1051*83ee113eSDavid van Moolenbroek 	client -> destination = iaddr_broadcast;
1052*83ee113eSDavid van Moolenbroek 	client -> state = S_REQUESTING;
1053*83ee113eSDavid van Moolenbroek 	client -> first_sending = cur_time;
1054*83ee113eSDavid van Moolenbroek 	client -> interval = client -> config -> initial_interval;
1055*83ee113eSDavid van Moolenbroek 
1056*83ee113eSDavid van Moolenbroek 	/* Make a DHCPREQUEST packet from the lease we picked. */
1057*83ee113eSDavid van Moolenbroek 	make_request (client, picked);
1058*83ee113eSDavid van Moolenbroek 	client -> xid = client -> packet.xid;
1059*83ee113eSDavid van Moolenbroek 
1060*83ee113eSDavid van Moolenbroek 	/* Toss the lease we picked - we'll get it back in a DHCPACK. */
1061*83ee113eSDavid van Moolenbroek 	destroy_client_lease (picked);
1062*83ee113eSDavid van Moolenbroek 
1063*83ee113eSDavid van Moolenbroek 	/* Add an immediate timeout to send the first DHCPREQUEST packet. */
1064*83ee113eSDavid van Moolenbroek 	send_request (client);
1065*83ee113eSDavid van Moolenbroek }
1066*83ee113eSDavid van Moolenbroek 
1067*83ee113eSDavid van Moolenbroek static isc_boolean_t
compare_hw_address(const char * name,struct packet * packet)1068*83ee113eSDavid van Moolenbroek compare_hw_address(const char *name, struct packet *packet) {
1069*83ee113eSDavid van Moolenbroek 	if (packet->interface->hw_address.hlen - 1 != packet->raw->hlen ||
1070*83ee113eSDavid van Moolenbroek 	    memcmp(&packet->interface->hw_address.hbuf[1],
1071*83ee113eSDavid van Moolenbroek 	    packet->raw->chaddr, packet->raw->hlen)) {
1072*83ee113eSDavid van Moolenbroek 		unsigned char *c  = packet->raw ->chaddr;
1073*83ee113eSDavid van Moolenbroek 		log_error ("%s raw = %d %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
1074*83ee113eSDavid van Moolenbroek 		    name, packet->raw->hlen,
1075*83ee113eSDavid van Moolenbroek 		    c[0], c[1], c[2], c[3], c[4], c[5]);
1076*83ee113eSDavid van Moolenbroek 		c = &packet -> interface -> hw_address.hbuf [1];
1077*83ee113eSDavid van Moolenbroek 		log_error ("%s cooked = %d %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
1078*83ee113eSDavid van Moolenbroek 		    name, packet->interface->hw_address.hlen - 1,
1079*83ee113eSDavid van Moolenbroek 		    c[0], c[1], c[2], c[3], c[4], c[5]);
1080*83ee113eSDavid van Moolenbroek 		log_error ("%s in wrong transaction (%s ignored).", name,
1081*83ee113eSDavid van Moolenbroek 		        hw_mismatch_drop ? "packet" : "error");
1082*83ee113eSDavid van Moolenbroek 		return hw_mismatch_drop;
1083*83ee113eSDavid van Moolenbroek 	}
1084*83ee113eSDavid van Moolenbroek 	return ISC_FALSE;
1085*83ee113eSDavid van Moolenbroek }
1086*83ee113eSDavid van Moolenbroek 
1087*83ee113eSDavid van Moolenbroek /* state_requesting is called when we receive a DHCPACK message after
1088*83ee113eSDavid van Moolenbroek    having sent out one or more DHCPREQUEST packets. */
1089*83ee113eSDavid van Moolenbroek 
dhcpack(packet)1090*83ee113eSDavid van Moolenbroek void dhcpack (packet)
1091*83ee113eSDavid van Moolenbroek 	struct packet *packet;
1092*83ee113eSDavid van Moolenbroek {
1093*83ee113eSDavid van Moolenbroek 	struct interface_info *ip = packet -> interface;
1094*83ee113eSDavid van Moolenbroek 	struct client_state *client;
1095*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
1096*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
1097*83ee113eSDavid van Moolenbroek 	struct data_string ds;
1098*83ee113eSDavid van Moolenbroek 
1099*83ee113eSDavid van Moolenbroek 	/* If we're not receptive to an offer right now, or if the offer
1100*83ee113eSDavid van Moolenbroek 	   has an unrecognizable transaction id, then just drop it. */
1101*83ee113eSDavid van Moolenbroek 	for (client = ip -> client; client; client = client -> next) {
1102*83ee113eSDavid van Moolenbroek 		if (client -> xid == packet -> raw -> xid)
1103*83ee113eSDavid van Moolenbroek 			break;
1104*83ee113eSDavid van Moolenbroek 	}
1105*83ee113eSDavid van Moolenbroek 	if (!client || compare_hw_address("DHCPACK", packet) == ISC_TRUE)
1106*83ee113eSDavid van Moolenbroek 		return;
1107*83ee113eSDavid van Moolenbroek 
1108*83ee113eSDavid van Moolenbroek 	if (client -> state != S_REBOOTING &&
1109*83ee113eSDavid van Moolenbroek 	    client -> state != S_REQUESTING &&
1110*83ee113eSDavid van Moolenbroek 	    client -> state != S_RENEWING &&
1111*83ee113eSDavid van Moolenbroek 	    client -> state != S_REBINDING) {
1112*83ee113eSDavid van Moolenbroek #if defined (DEBUG)
1113*83ee113eSDavid van Moolenbroek 		log_debug ("DHCPACK in wrong state.");
1114*83ee113eSDavid van Moolenbroek #endif
1115*83ee113eSDavid van Moolenbroek 		return;
1116*83ee113eSDavid van Moolenbroek 	}
1117*83ee113eSDavid van Moolenbroek 
1118*83ee113eSDavid van Moolenbroek 	log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
1119*83ee113eSDavid van Moolenbroek 
1120*83ee113eSDavid van Moolenbroek 	lease = packet_to_lease (packet, client);
1121*83ee113eSDavid van Moolenbroek 	if (!lease) {
1122*83ee113eSDavid van Moolenbroek 		log_info ("packet_to_lease failed.");
1123*83ee113eSDavid van Moolenbroek 		return;
1124*83ee113eSDavid van Moolenbroek 	}
1125*83ee113eSDavid van Moolenbroek 
1126*83ee113eSDavid van Moolenbroek 	client -> new = lease;
1127*83ee113eSDavid van Moolenbroek 
1128*83ee113eSDavid van Moolenbroek 	/* Stop resending DHCPREQUEST. */
1129*83ee113eSDavid van Moolenbroek 	cancel_timeout (send_request, client);
1130*83ee113eSDavid van Moolenbroek 
1131*83ee113eSDavid van Moolenbroek 	/* Figure out the lease time. */
1132*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, client -> new -> options,
1133*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_LEASE_TIME);
1134*83ee113eSDavid van Moolenbroek 	memset (&ds, 0, sizeof ds);
1135*83ee113eSDavid van Moolenbroek 	if (oc &&
1136*83ee113eSDavid van Moolenbroek 	    evaluate_option_cache (&ds, packet, (struct lease *)0, client,
1137*83ee113eSDavid van Moolenbroek 				   packet -> options, client -> new -> options,
1138*83ee113eSDavid van Moolenbroek 				   &global_scope, oc, MDL)) {
1139*83ee113eSDavid van Moolenbroek 		if (ds.len > 3)
1140*83ee113eSDavid van Moolenbroek 			client -> new -> expiry = getULong (ds.data);
1141*83ee113eSDavid van Moolenbroek 		else
1142*83ee113eSDavid van Moolenbroek 			client -> new -> expiry = 0;
1143*83ee113eSDavid van Moolenbroek 		data_string_forget (&ds, MDL);
1144*83ee113eSDavid van Moolenbroek 	} else
1145*83ee113eSDavid van Moolenbroek 			client -> new -> expiry = 0;
1146*83ee113eSDavid van Moolenbroek 
1147*83ee113eSDavid van Moolenbroek 	if (client->new->expiry == 0) {
1148*83ee113eSDavid van Moolenbroek 		struct timeval tv;
1149*83ee113eSDavid van Moolenbroek 
1150*83ee113eSDavid van Moolenbroek 		log_error ("no expiry time on offered lease.");
1151*83ee113eSDavid van Moolenbroek 
1152*83ee113eSDavid van Moolenbroek 		/* Quench this (broken) server.  Return to INIT to reselect. */
1153*83ee113eSDavid van Moolenbroek 		add_reject(packet);
1154*83ee113eSDavid van Moolenbroek 
1155*83ee113eSDavid van Moolenbroek 		/* 1/2 second delay to restart at INIT. */
1156*83ee113eSDavid van Moolenbroek 		tv.tv_sec = cur_tv.tv_sec;
1157*83ee113eSDavid van Moolenbroek 		tv.tv_usec = cur_tv.tv_usec + 500000;
1158*83ee113eSDavid van Moolenbroek 
1159*83ee113eSDavid van Moolenbroek 		if (tv.tv_usec >= 1000000) {
1160*83ee113eSDavid van Moolenbroek 			tv.tv_sec++;
1161*83ee113eSDavid van Moolenbroek 			tv.tv_usec -= 1000000;
1162*83ee113eSDavid van Moolenbroek 		}
1163*83ee113eSDavid van Moolenbroek 
1164*83ee113eSDavid van Moolenbroek 		add_timeout(&tv, state_init, client, 0, 0);
1165*83ee113eSDavid van Moolenbroek 		return;
1166*83ee113eSDavid van Moolenbroek 	}
1167*83ee113eSDavid van Moolenbroek 
1168*83ee113eSDavid van Moolenbroek 	/*
1169*83ee113eSDavid van Moolenbroek 	 * A number that looks negative here is really just very large,
1170*83ee113eSDavid van Moolenbroek 	 * because the lease expiry offset is unsigned.
1171*83ee113eSDavid van Moolenbroek 	 */
1172*83ee113eSDavid van Moolenbroek 	if (client->new->expiry < 0)
1173*83ee113eSDavid van Moolenbroek 		client->new->expiry = TIME_MAX;
1174*83ee113eSDavid van Moolenbroek 
1175*83ee113eSDavid van Moolenbroek 	/* Take the server-provided renewal time if there is one. */
1176*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, client -> new -> options,
1177*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_RENEWAL_TIME);
1178*83ee113eSDavid van Moolenbroek 	if (oc &&
1179*83ee113eSDavid van Moolenbroek 	    evaluate_option_cache (&ds, packet, (struct lease *)0, client,
1180*83ee113eSDavid van Moolenbroek 				   packet -> options, client -> new -> options,
1181*83ee113eSDavid van Moolenbroek 				   &global_scope, oc, MDL)) {
1182*83ee113eSDavid van Moolenbroek 		if (ds.len > 3)
1183*83ee113eSDavid van Moolenbroek 			client -> new -> renewal = getULong (ds.data);
1184*83ee113eSDavid van Moolenbroek 		else
1185*83ee113eSDavid van Moolenbroek 			client -> new -> renewal = 0;
1186*83ee113eSDavid van Moolenbroek 		data_string_forget (&ds, MDL);
1187*83ee113eSDavid van Moolenbroek 	} else
1188*83ee113eSDavid van Moolenbroek 			client -> new -> renewal = 0;
1189*83ee113eSDavid van Moolenbroek 
1190*83ee113eSDavid van Moolenbroek 	/* If it wasn't specified by the server, calculate it. */
1191*83ee113eSDavid van Moolenbroek 	if (!client -> new -> renewal)
1192*83ee113eSDavid van Moolenbroek 		client -> new -> renewal = client -> new -> expiry / 2 + 1;
1193*83ee113eSDavid van Moolenbroek 
1194*83ee113eSDavid van Moolenbroek 	if (client -> new -> renewal <= 0)
1195*83ee113eSDavid van Moolenbroek 		client -> new -> renewal = TIME_MAX;
1196*83ee113eSDavid van Moolenbroek 
1197*83ee113eSDavid van Moolenbroek 	/* Now introduce some randomness to the renewal time: */
1198*83ee113eSDavid van Moolenbroek 	if (client->new->renewal <= ((TIME_MAX / 3) - 3))
1199*83ee113eSDavid van Moolenbroek 		client->new->renewal = (((client->new->renewal * 3) + 3) / 4) +
1200*83ee113eSDavid van Moolenbroek 				(((random() % client->new->renewal) + 3) / 4);
1201*83ee113eSDavid van Moolenbroek 
1202*83ee113eSDavid van Moolenbroek 	/* Same deal with the rebind time. */
1203*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, client -> new -> options,
1204*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_REBINDING_TIME);
1205*83ee113eSDavid van Moolenbroek 	if (oc &&
1206*83ee113eSDavid van Moolenbroek 	    evaluate_option_cache (&ds, packet, (struct lease *)0, client,
1207*83ee113eSDavid van Moolenbroek 				   packet -> options, client -> new -> options,
1208*83ee113eSDavid van Moolenbroek 				   &global_scope, oc, MDL)) {
1209*83ee113eSDavid van Moolenbroek 		if (ds.len > 3)
1210*83ee113eSDavid van Moolenbroek 			client -> new -> rebind = getULong (ds.data);
1211*83ee113eSDavid van Moolenbroek 		else
1212*83ee113eSDavid van Moolenbroek 			client -> new -> rebind = 0;
1213*83ee113eSDavid van Moolenbroek 		data_string_forget (&ds, MDL);
1214*83ee113eSDavid van Moolenbroek 	} else
1215*83ee113eSDavid van Moolenbroek 			client -> new -> rebind = 0;
1216*83ee113eSDavid van Moolenbroek 
1217*83ee113eSDavid van Moolenbroek 	if (client -> new -> rebind <= 0) {
1218*83ee113eSDavid van Moolenbroek 		if (client -> new -> expiry <= TIME_MAX / 7)
1219*83ee113eSDavid van Moolenbroek 			client -> new -> rebind =
1220*83ee113eSDavid van Moolenbroek 					client -> new -> expiry * 7 / 8;
1221*83ee113eSDavid van Moolenbroek 		else
1222*83ee113eSDavid van Moolenbroek 			client -> new -> rebind =
1223*83ee113eSDavid van Moolenbroek 					client -> new -> expiry / 8 * 7;
1224*83ee113eSDavid van Moolenbroek 	}
1225*83ee113eSDavid van Moolenbroek 
1226*83ee113eSDavid van Moolenbroek 	/* Make sure our randomness didn't run the renewal time past the
1227*83ee113eSDavid van Moolenbroek 	   rebind time. */
1228*83ee113eSDavid van Moolenbroek 	if (client -> new -> renewal > client -> new -> rebind) {
1229*83ee113eSDavid van Moolenbroek 		if (client -> new -> rebind <= TIME_MAX / 3)
1230*83ee113eSDavid van Moolenbroek 			client -> new -> renewal =
1231*83ee113eSDavid van Moolenbroek 					client -> new -> rebind * 3 / 4;
1232*83ee113eSDavid van Moolenbroek 		else
1233*83ee113eSDavid van Moolenbroek 			client -> new -> renewal =
1234*83ee113eSDavid van Moolenbroek 					client -> new -> rebind / 4 * 3;
1235*83ee113eSDavid van Moolenbroek 	}
1236*83ee113eSDavid van Moolenbroek 
1237*83ee113eSDavid van Moolenbroek 	client -> new -> expiry += cur_time;
1238*83ee113eSDavid van Moolenbroek 	/* Lease lengths can never be negative. */
1239*83ee113eSDavid van Moolenbroek 	if (client -> new -> expiry < cur_time)
1240*83ee113eSDavid van Moolenbroek 		client -> new -> expiry = TIME_MAX;
1241*83ee113eSDavid van Moolenbroek 	client -> new -> renewal += cur_time;
1242*83ee113eSDavid van Moolenbroek 	if (client -> new -> renewal < cur_time)
1243*83ee113eSDavid van Moolenbroek 		client -> new -> renewal = TIME_MAX;
1244*83ee113eSDavid van Moolenbroek 	client -> new -> rebind += cur_time;
1245*83ee113eSDavid van Moolenbroek 	if (client -> new -> rebind < cur_time)
1246*83ee113eSDavid van Moolenbroek 		client -> new -> rebind = TIME_MAX;
1247*83ee113eSDavid van Moolenbroek 
1248*83ee113eSDavid van Moolenbroek 	bind_lease (client);
1249*83ee113eSDavid van Moolenbroek }
1250*83ee113eSDavid van Moolenbroek 
bind_lease(client)1251*83ee113eSDavid van Moolenbroek void bind_lease (client)
1252*83ee113eSDavid van Moolenbroek 	struct client_state *client;
1253*83ee113eSDavid van Moolenbroek {
1254*83ee113eSDavid van Moolenbroek 	struct timeval tv;
1255*83ee113eSDavid van Moolenbroek 
1256*83ee113eSDavid van Moolenbroek 	/* Remember the medium. */
1257*83ee113eSDavid van Moolenbroek 	client -> new -> medium = client -> medium;
1258*83ee113eSDavid van Moolenbroek 
1259*83ee113eSDavid van Moolenbroek 	/* Run the client script with the new parameters. */
1260*83ee113eSDavid van Moolenbroek 	script_init (client, (client -> state == S_REQUESTING
1261*83ee113eSDavid van Moolenbroek 			  ? "BOUND"
1262*83ee113eSDavid van Moolenbroek 			  : (client -> state == S_RENEWING
1263*83ee113eSDavid van Moolenbroek 			     ? "RENEW"
1264*83ee113eSDavid van Moolenbroek 			     : (client -> state == S_REBOOTING
1265*83ee113eSDavid van Moolenbroek 				? "REBOOT" : "REBIND"))),
1266*83ee113eSDavid van Moolenbroek 		     client -> new -> medium);
1267*83ee113eSDavid van Moolenbroek 	if (client -> active && client -> state != S_REBOOTING)
1268*83ee113eSDavid van Moolenbroek 		script_write_params (client, "old_", client -> active);
1269*83ee113eSDavid van Moolenbroek 	script_write_params (client, "new_", client -> new);
1270*83ee113eSDavid van Moolenbroek 	script_write_requested(client);
1271*83ee113eSDavid van Moolenbroek 	if (client -> alias)
1272*83ee113eSDavid van Moolenbroek 		script_write_params (client, "alias_", client -> alias);
1273*83ee113eSDavid van Moolenbroek 
1274*83ee113eSDavid van Moolenbroek 	/* If the BOUND/RENEW code detects another machine using the
1275*83ee113eSDavid van Moolenbroek 	   offered address, it exits nonzero.  We need to send a
1276*83ee113eSDavid van Moolenbroek 	   DHCPDECLINE and toss the lease. */
1277*83ee113eSDavid van Moolenbroek 	if (script_go (client)) {
1278*83ee113eSDavid van Moolenbroek 		make_decline (client, client -> new);
1279*83ee113eSDavid van Moolenbroek 		send_decline (client);
1280*83ee113eSDavid van Moolenbroek 		destroy_client_lease (client -> new);
1281*83ee113eSDavid van Moolenbroek 		client -> new = (struct client_lease *)0;
1282*83ee113eSDavid van Moolenbroek 		state_init (client);
1283*83ee113eSDavid van Moolenbroek 		return;
1284*83ee113eSDavid van Moolenbroek 	}
1285*83ee113eSDavid van Moolenbroek 
1286*83ee113eSDavid van Moolenbroek 	/* Write out the new lease if it has been long enough. */
1287*83ee113eSDavid van Moolenbroek 	if (!client->last_write ||
1288*83ee113eSDavid van Moolenbroek 	    (cur_time - client->last_write) >= MIN_LEASE_WRITE)
1289*83ee113eSDavid van Moolenbroek 		write_client_lease(client, client->new, 0, 0);
1290*83ee113eSDavid van Moolenbroek 
1291*83ee113eSDavid van Moolenbroek 	/* Replace the old active lease with the new one. */
1292*83ee113eSDavid van Moolenbroek 	if (client -> active)
1293*83ee113eSDavid van Moolenbroek 		destroy_client_lease (client -> active);
1294*83ee113eSDavid van Moolenbroek 	client -> active = client -> new;
1295*83ee113eSDavid van Moolenbroek 	client -> new = (struct client_lease *)0;
1296*83ee113eSDavid van Moolenbroek 
1297*83ee113eSDavid van Moolenbroek 	/* Set up a timeout to start the renewal process. */
1298*83ee113eSDavid van Moolenbroek 	tv.tv_sec = client->active->renewal;
1299*83ee113eSDavid van Moolenbroek 	tv.tv_usec = ((client->active->renewal - cur_tv.tv_sec) > 1) ?
1300*83ee113eSDavid van Moolenbroek 			random() % 1000000 : cur_tv.tv_usec;
1301*83ee113eSDavid van Moolenbroek 	add_timeout(&tv, state_bound, client, 0, 0);
1302*83ee113eSDavid van Moolenbroek 
1303*83ee113eSDavid van Moolenbroek 	log_info ("bound to %s -- renewal in %ld seconds.",
1304*83ee113eSDavid van Moolenbroek 	      piaddr (client -> active -> address),
1305*83ee113eSDavid van Moolenbroek 	      (long)(client -> active -> renewal - cur_time));
1306*83ee113eSDavid van Moolenbroek 	client -> state = S_BOUND;
1307*83ee113eSDavid van Moolenbroek 	reinitialize_interfaces ();
1308*83ee113eSDavid van Moolenbroek 	finish_daemon ();
1309*83ee113eSDavid van Moolenbroek #if defined (NSUPDATE)
1310*83ee113eSDavid van Moolenbroek 	if (client->config->do_forward_update)
1311*83ee113eSDavid van Moolenbroek 		dhclient_schedule_updates(client, &client->active->address, 1);
1312*83ee113eSDavid van Moolenbroek #endif
1313*83ee113eSDavid van Moolenbroek }
1314*83ee113eSDavid van Moolenbroek 
1315*83ee113eSDavid van Moolenbroek /* state_bound is called when we've successfully bound to a particular
1316*83ee113eSDavid van Moolenbroek    lease, but the renewal time on that lease has expired.   We are
1317*83ee113eSDavid van Moolenbroek    expected to unicast a DHCPREQUEST to the server that gave us our
1318*83ee113eSDavid van Moolenbroek    original lease. */
1319*83ee113eSDavid van Moolenbroek 
state_bound(cpp)1320*83ee113eSDavid van Moolenbroek void state_bound (cpp)
1321*83ee113eSDavid van Moolenbroek 	void *cpp;
1322*83ee113eSDavid van Moolenbroek {
1323*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
1324*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
1325*83ee113eSDavid van Moolenbroek 	struct data_string ds;
1326*83ee113eSDavid van Moolenbroek 
1327*83ee113eSDavid van Moolenbroek 	ASSERT_STATE(state, S_BOUND);
1328*83ee113eSDavid van Moolenbroek 
1329*83ee113eSDavid van Moolenbroek 	/* T1 has expired. */
1330*83ee113eSDavid van Moolenbroek 	make_request (client, client -> active);
1331*83ee113eSDavid van Moolenbroek 	client -> xid = client -> packet.xid;
1332*83ee113eSDavid van Moolenbroek 
1333*83ee113eSDavid van Moolenbroek 	memset (&ds, 0, sizeof ds);
1334*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, client -> active -> options,
1335*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_SERVER_IDENTIFIER);
1336*83ee113eSDavid van Moolenbroek 	if (oc &&
1337*83ee113eSDavid van Moolenbroek 	    evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
1338*83ee113eSDavid van Moolenbroek 				   client, (struct option_state *)0,
1339*83ee113eSDavid van Moolenbroek 				   client -> active -> options,
1340*83ee113eSDavid van Moolenbroek 				   &global_scope, oc, MDL)) {
1341*83ee113eSDavid van Moolenbroek 		if (ds.len > 3) {
1342*83ee113eSDavid van Moolenbroek 			memcpy (client -> destination.iabuf, ds.data, 4);
1343*83ee113eSDavid van Moolenbroek 			client -> destination.len = 4;
1344*83ee113eSDavid van Moolenbroek 		} else
1345*83ee113eSDavid van Moolenbroek 			client -> destination = iaddr_broadcast;
1346*83ee113eSDavid van Moolenbroek 
1347*83ee113eSDavid van Moolenbroek 		data_string_forget (&ds, MDL);
1348*83ee113eSDavid van Moolenbroek 	} else
1349*83ee113eSDavid van Moolenbroek 		client -> destination = iaddr_broadcast;
1350*83ee113eSDavid van Moolenbroek 
1351*83ee113eSDavid van Moolenbroek 	client -> first_sending = cur_time;
1352*83ee113eSDavid van Moolenbroek 	client -> interval = client -> config -> initial_interval;
1353*83ee113eSDavid van Moolenbroek 	client -> state = S_RENEWING;
1354*83ee113eSDavid van Moolenbroek 
1355*83ee113eSDavid van Moolenbroek 	/* Send the first packet immediately. */
1356*83ee113eSDavid van Moolenbroek 	send_request (client);
1357*83ee113eSDavid van Moolenbroek }
1358*83ee113eSDavid van Moolenbroek 
1359*83ee113eSDavid van Moolenbroek /* state_stop is called when we've been told to shut down.   We unconfigure
1360*83ee113eSDavid van Moolenbroek    the interfaces, and then stop operating until told otherwise. */
1361*83ee113eSDavid van Moolenbroek 
state_stop(cpp)1362*83ee113eSDavid van Moolenbroek void state_stop (cpp)
1363*83ee113eSDavid van Moolenbroek 	void *cpp;
1364*83ee113eSDavid van Moolenbroek {
1365*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
1366*83ee113eSDavid van Moolenbroek 
1367*83ee113eSDavid van Moolenbroek 	/* Cancel all timeouts. */
1368*83ee113eSDavid van Moolenbroek 	cancel_timeout(state_selecting, client);
1369*83ee113eSDavid van Moolenbroek 	cancel_timeout(send_discover, client);
1370*83ee113eSDavid van Moolenbroek 	cancel_timeout(send_request, client);
1371*83ee113eSDavid van Moolenbroek 	cancel_timeout(state_bound, client);
1372*83ee113eSDavid van Moolenbroek 
1373*83ee113eSDavid van Moolenbroek 	/* If we have an address, unconfigure it. */
1374*83ee113eSDavid van Moolenbroek 	if (client->active) {
1375*83ee113eSDavid van Moolenbroek 		script_init(client, "STOP", client->active->medium);
1376*83ee113eSDavid van Moolenbroek 		script_write_params(client, "old_", client->active);
1377*83ee113eSDavid van Moolenbroek 		script_write_requested(client);
1378*83ee113eSDavid van Moolenbroek 		if (client->alias)
1379*83ee113eSDavid van Moolenbroek 			script_write_params(client, "alias_", client->alias);
1380*83ee113eSDavid van Moolenbroek 		script_go(client);
1381*83ee113eSDavid van Moolenbroek 	}
1382*83ee113eSDavid van Moolenbroek }
1383*83ee113eSDavid van Moolenbroek 
commit_leases()1384*83ee113eSDavid van Moolenbroek int commit_leases ()
1385*83ee113eSDavid van Moolenbroek {
1386*83ee113eSDavid van Moolenbroek 	return 0;
1387*83ee113eSDavid van Moolenbroek }
1388*83ee113eSDavid van Moolenbroek 
write_lease(lease)1389*83ee113eSDavid van Moolenbroek int write_lease (lease)
1390*83ee113eSDavid van Moolenbroek 	struct lease *lease;
1391*83ee113eSDavid van Moolenbroek {
1392*83ee113eSDavid van Moolenbroek 	return 0;
1393*83ee113eSDavid van Moolenbroek }
1394*83ee113eSDavid van Moolenbroek 
write_host(host)1395*83ee113eSDavid van Moolenbroek int write_host (host)
1396*83ee113eSDavid van Moolenbroek 	struct host_decl *host;
1397*83ee113eSDavid van Moolenbroek {
1398*83ee113eSDavid van Moolenbroek 	return 0;
1399*83ee113eSDavid van Moolenbroek }
1400*83ee113eSDavid van Moolenbroek 
db_startup(testp)1401*83ee113eSDavid van Moolenbroek void db_startup (testp)
1402*83ee113eSDavid van Moolenbroek 	int testp;
1403*83ee113eSDavid van Moolenbroek {
1404*83ee113eSDavid van Moolenbroek }
1405*83ee113eSDavid van Moolenbroek 
bootp(packet)1406*83ee113eSDavid van Moolenbroek void bootp (packet)
1407*83ee113eSDavid van Moolenbroek 	struct packet *packet;
1408*83ee113eSDavid van Moolenbroek {
1409*83ee113eSDavid van Moolenbroek 	struct iaddrmatchlist *ap;
1410*83ee113eSDavid van Moolenbroek 	char addrbuf[4*16];
1411*83ee113eSDavid van Moolenbroek 	char maskbuf[4*16];
1412*83ee113eSDavid van Moolenbroek 
1413*83ee113eSDavid van Moolenbroek 	if (packet -> raw -> op != BOOTREPLY)
1414*83ee113eSDavid van Moolenbroek 		return;
1415*83ee113eSDavid van Moolenbroek 
1416*83ee113eSDavid van Moolenbroek 	/* If there's a reject list, make sure this packet's sender isn't
1417*83ee113eSDavid van Moolenbroek 	   on it. */
1418*83ee113eSDavid van Moolenbroek 	for (ap = packet -> interface -> client -> config -> reject_list;
1419*83ee113eSDavid van Moolenbroek 	     ap; ap = ap -> next) {
1420*83ee113eSDavid van Moolenbroek 		if (addr_match(&packet->client_addr, &ap->match)) {
1421*83ee113eSDavid van Moolenbroek 
1422*83ee113eSDavid van Moolenbroek 		        /* piaddr() returns its result in a static
1423*83ee113eSDavid van Moolenbroek 			   buffer sized 4*16 (see common/inet.c). */
1424*83ee113eSDavid van Moolenbroek 
1425*83ee113eSDavid van Moolenbroek 		        strcpy(addrbuf, piaddr(ap->match.addr));
1426*83ee113eSDavid van Moolenbroek 		        strcpy(maskbuf, piaddr(ap->match.mask));
1427*83ee113eSDavid van Moolenbroek 
1428*83ee113eSDavid van Moolenbroek 			log_info("BOOTREPLY from %s rejected by rule %s "
1429*83ee113eSDavid van Moolenbroek 				 "mask %s.", piaddr(packet->client_addr),
1430*83ee113eSDavid van Moolenbroek 				 addrbuf, maskbuf);
1431*83ee113eSDavid van Moolenbroek 			return;
1432*83ee113eSDavid van Moolenbroek 		}
1433*83ee113eSDavid van Moolenbroek 	}
1434*83ee113eSDavid van Moolenbroek 
1435*83ee113eSDavid van Moolenbroek 	dhcpoffer (packet);
1436*83ee113eSDavid van Moolenbroek 
1437*83ee113eSDavid van Moolenbroek }
1438*83ee113eSDavid van Moolenbroek 
dhcp(packet)1439*83ee113eSDavid van Moolenbroek void dhcp (packet)
1440*83ee113eSDavid van Moolenbroek 	struct packet *packet;
1441*83ee113eSDavid van Moolenbroek {
1442*83ee113eSDavid van Moolenbroek 	struct iaddrmatchlist *ap;
1443*83ee113eSDavid van Moolenbroek 	void (*handler) (struct packet *);
1444*83ee113eSDavid van Moolenbroek 	const char *type;
1445*83ee113eSDavid van Moolenbroek 	char addrbuf[4*16];
1446*83ee113eSDavid van Moolenbroek 	char maskbuf[4*16];
1447*83ee113eSDavid van Moolenbroek 
1448*83ee113eSDavid van Moolenbroek 	switch (packet -> packet_type) {
1449*83ee113eSDavid van Moolenbroek 	      case DHCPOFFER:
1450*83ee113eSDavid van Moolenbroek 		handler = dhcpoffer;
1451*83ee113eSDavid van Moolenbroek 		type = "DHCPOFFER";
1452*83ee113eSDavid van Moolenbroek 		break;
1453*83ee113eSDavid van Moolenbroek 
1454*83ee113eSDavid van Moolenbroek 	      case DHCPNAK:
1455*83ee113eSDavid van Moolenbroek 		handler = dhcpnak;
1456*83ee113eSDavid van Moolenbroek 		type = "DHCPNACK";
1457*83ee113eSDavid van Moolenbroek 		break;
1458*83ee113eSDavid van Moolenbroek 
1459*83ee113eSDavid van Moolenbroek 	      case DHCPACK:
1460*83ee113eSDavid van Moolenbroek 		handler = dhcpack;
1461*83ee113eSDavid van Moolenbroek 		type = "DHCPACK";
1462*83ee113eSDavid van Moolenbroek 		break;
1463*83ee113eSDavid van Moolenbroek 
1464*83ee113eSDavid van Moolenbroek 	      default:
1465*83ee113eSDavid van Moolenbroek 		return;
1466*83ee113eSDavid van Moolenbroek 	}
1467*83ee113eSDavid van Moolenbroek 
1468*83ee113eSDavid van Moolenbroek 	/* If there's a reject list, make sure this packet's sender isn't
1469*83ee113eSDavid van Moolenbroek 	   on it. */
1470*83ee113eSDavid van Moolenbroek 	for (ap = packet -> interface -> client -> config -> reject_list;
1471*83ee113eSDavid van Moolenbroek 	     ap; ap = ap -> next) {
1472*83ee113eSDavid van Moolenbroek 		if (addr_match(&packet->client_addr, &ap->match)) {
1473*83ee113eSDavid van Moolenbroek 
1474*83ee113eSDavid van Moolenbroek 		        /* piaddr() returns its result in a static
1475*83ee113eSDavid van Moolenbroek 			   buffer sized 4*16 (see common/inet.c). */
1476*83ee113eSDavid van Moolenbroek 
1477*83ee113eSDavid van Moolenbroek 		        strcpy(addrbuf, piaddr(ap->match.addr));
1478*83ee113eSDavid van Moolenbroek 		        strcpy(maskbuf, piaddr(ap->match.mask));
1479*83ee113eSDavid van Moolenbroek 
1480*83ee113eSDavid van Moolenbroek 			log_info("%s from %s rejected by rule %s mask %s.",
1481*83ee113eSDavid van Moolenbroek 				 type, piaddr(packet->client_addr),
1482*83ee113eSDavid van Moolenbroek 				 addrbuf, maskbuf);
1483*83ee113eSDavid van Moolenbroek 			return;
1484*83ee113eSDavid van Moolenbroek 		}
1485*83ee113eSDavid van Moolenbroek 	}
1486*83ee113eSDavid van Moolenbroek 	(*handler) (packet);
1487*83ee113eSDavid van Moolenbroek }
1488*83ee113eSDavid van Moolenbroek 
1489*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
1490*83ee113eSDavid van Moolenbroek void
dhcpv6(struct packet * packet)1491*83ee113eSDavid van Moolenbroek dhcpv6(struct packet *packet) {
1492*83ee113eSDavid van Moolenbroek 	struct iaddrmatchlist *ap;
1493*83ee113eSDavid van Moolenbroek 	struct client_state *client;
1494*83ee113eSDavid van Moolenbroek 	char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
1495*83ee113eSDavid van Moolenbroek 
1496*83ee113eSDavid van Moolenbroek 	/* Silently drop bogus messages. */
1497*83ee113eSDavid van Moolenbroek 	if (packet->dhcpv6_msg_type >= dhcpv6_type_name_max)
1498*83ee113eSDavid van Moolenbroek 		return;
1499*83ee113eSDavid van Moolenbroek 
1500*83ee113eSDavid van Moolenbroek 	/* Discard, with log, packets from quenched sources. */
1501*83ee113eSDavid van Moolenbroek 	for (ap = packet->interface->client->config->reject_list ;
1502*83ee113eSDavid van Moolenbroek 	     ap ; ap = ap->next) {
1503*83ee113eSDavid van Moolenbroek 		if (addr_match(&packet->client_addr, &ap->match)) {
1504*83ee113eSDavid van Moolenbroek 			strcpy(addrbuf, piaddr(packet->client_addr));
1505*83ee113eSDavid van Moolenbroek 			log_info("%s from %s rejected by rule %s",
1506*83ee113eSDavid van Moolenbroek 				 dhcpv6_type_names[packet->dhcpv6_msg_type],
1507*83ee113eSDavid van Moolenbroek 				 addrbuf,
1508*83ee113eSDavid van Moolenbroek 				 piaddrmask(&ap->match.addr, &ap->match.mask));
1509*83ee113eSDavid van Moolenbroek 			return;
1510*83ee113eSDavid van Moolenbroek 		}
1511*83ee113eSDavid van Moolenbroek 	}
1512*83ee113eSDavid van Moolenbroek 
1513*83ee113eSDavid van Moolenbroek 	/* Screen out nonsensical messages. */
1514*83ee113eSDavid van Moolenbroek 	switch(packet->dhcpv6_msg_type) {
1515*83ee113eSDavid van Moolenbroek 	      case DHCPV6_ADVERTISE:
1516*83ee113eSDavid van Moolenbroek 	      case DHCPV6_RECONFIGURE:
1517*83ee113eSDavid van Moolenbroek 		if (stateless)
1518*83ee113eSDavid van Moolenbroek 		  return;
1519*83ee113eSDavid van Moolenbroek 	      /* Falls through */
1520*83ee113eSDavid van Moolenbroek 	      case DHCPV6_REPLY:
1521*83ee113eSDavid van Moolenbroek 		log_info("RCV: %s message on %s from %s.",
1522*83ee113eSDavid van Moolenbroek 			 dhcpv6_type_names[packet->dhcpv6_msg_type],
1523*83ee113eSDavid van Moolenbroek 			 packet->interface->name, piaddr(packet->client_addr));
1524*83ee113eSDavid van Moolenbroek 		break;
1525*83ee113eSDavid van Moolenbroek 
1526*83ee113eSDavid van Moolenbroek 	      default:
1527*83ee113eSDavid van Moolenbroek 		return;
1528*83ee113eSDavid van Moolenbroek 	}
1529*83ee113eSDavid van Moolenbroek 
1530*83ee113eSDavid van Moolenbroek 	/* Find a client state that matches the incoming XID. */
1531*83ee113eSDavid van Moolenbroek 	for (client = packet->interface->client ; client ;
1532*83ee113eSDavid van Moolenbroek 	     client = client->next) {
1533*83ee113eSDavid van Moolenbroek 		if (memcmp(&client->dhcpv6_transaction_id,
1534*83ee113eSDavid van Moolenbroek 			   packet->dhcpv6_transaction_id, 3) == 0) {
1535*83ee113eSDavid van Moolenbroek 			client->v6_handler(packet, client);
1536*83ee113eSDavid van Moolenbroek 			return;
1537*83ee113eSDavid van Moolenbroek 		}
1538*83ee113eSDavid van Moolenbroek 	}
1539*83ee113eSDavid van Moolenbroek 
1540*83ee113eSDavid van Moolenbroek 	/* XXX: temporary log for debugging */
1541*83ee113eSDavid van Moolenbroek 	log_info("Packet received, but nothing done with it.");
1542*83ee113eSDavid van Moolenbroek }
1543*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
1544*83ee113eSDavid van Moolenbroek 
dhcpoffer(packet)1545*83ee113eSDavid van Moolenbroek void dhcpoffer (packet)
1546*83ee113eSDavid van Moolenbroek 	struct packet *packet;
1547*83ee113eSDavid van Moolenbroek {
1548*83ee113eSDavid van Moolenbroek 	struct interface_info *ip = packet -> interface;
1549*83ee113eSDavid van Moolenbroek 	struct client_state *client;
1550*83ee113eSDavid van Moolenbroek 	struct client_lease *lease, *lp;
1551*83ee113eSDavid van Moolenbroek 	struct option **req;
1552*83ee113eSDavid van Moolenbroek 	int i;
1553*83ee113eSDavid van Moolenbroek 	int stop_selecting;
1554*83ee113eSDavid van Moolenbroek 	const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
1555*83ee113eSDavid van Moolenbroek 	char obuf [1024];
1556*83ee113eSDavid van Moolenbroek 	struct timeval tv;
1557*83ee113eSDavid van Moolenbroek 
1558*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PACKET
1559*83ee113eSDavid van Moolenbroek 	dump_packet (packet);
1560*83ee113eSDavid van Moolenbroek #endif
1561*83ee113eSDavid van Moolenbroek 
1562*83ee113eSDavid van Moolenbroek 	/* Find a client state that matches the xid... */
1563*83ee113eSDavid van Moolenbroek 	for (client = ip -> client; client; client = client -> next)
1564*83ee113eSDavid van Moolenbroek 		if (client -> xid == packet -> raw -> xid)
1565*83ee113eSDavid van Moolenbroek 			break;
1566*83ee113eSDavid van Moolenbroek 
1567*83ee113eSDavid van Moolenbroek 	/* If we're not receptive to an offer right now, or if the offer
1568*83ee113eSDavid van Moolenbroek 	   has an unrecognizable transaction id, then just drop it. */
1569*83ee113eSDavid van Moolenbroek 	if (!client || client -> state != S_SELECTING ||
1570*83ee113eSDavid van Moolenbroek 	    compare_hw_address(name, packet) == ISC_TRUE)
1571*83ee113eSDavid van Moolenbroek 		return;
1572*83ee113eSDavid van Moolenbroek 
1573*83ee113eSDavid van Moolenbroek 	sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
1574*83ee113eSDavid van Moolenbroek 
1575*83ee113eSDavid van Moolenbroek 
1576*83ee113eSDavid van Moolenbroek 	/* If this lease doesn't supply the minimum required DHCPv4 parameters,
1577*83ee113eSDavid van Moolenbroek 	 * ignore it.
1578*83ee113eSDavid van Moolenbroek 	 */
1579*83ee113eSDavid van Moolenbroek 	req = client->config->required_options;
1580*83ee113eSDavid van Moolenbroek 	if (req != NULL) {
1581*83ee113eSDavid van Moolenbroek 		for (i = 0 ; req[i] != NULL ; i++) {
1582*83ee113eSDavid van Moolenbroek 			if ((req[i]->universe == &dhcp_universe) &&
1583*83ee113eSDavid van Moolenbroek 			    !lookup_option(&dhcp_universe, packet->options,
1584*83ee113eSDavid van Moolenbroek 					   req[i]->code)) {
1585*83ee113eSDavid van Moolenbroek 				struct option *option = NULL;
1586*83ee113eSDavid van Moolenbroek 				unsigned code = req[i]->code;
1587*83ee113eSDavid van Moolenbroek 
1588*83ee113eSDavid van Moolenbroek 				option_code_hash_lookup(&option,
1589*83ee113eSDavid van Moolenbroek 							dhcp_universe.code_hash,
1590*83ee113eSDavid van Moolenbroek 							&code, 0, MDL);
1591*83ee113eSDavid van Moolenbroek 
1592*83ee113eSDavid van Moolenbroek 				if (option)
1593*83ee113eSDavid van Moolenbroek 					log_info("%s: no %s option.", obuf,
1594*83ee113eSDavid van Moolenbroek 						 option->name);
1595*83ee113eSDavid van Moolenbroek 				else
1596*83ee113eSDavid van Moolenbroek 					log_info("%s: no unknown-%u option.",
1597*83ee113eSDavid van Moolenbroek 						 obuf, code);
1598*83ee113eSDavid van Moolenbroek 
1599*83ee113eSDavid van Moolenbroek 				option_dereference(&option, MDL);
1600*83ee113eSDavid van Moolenbroek 
1601*83ee113eSDavid van Moolenbroek 				return;
1602*83ee113eSDavid van Moolenbroek 			}
1603*83ee113eSDavid van Moolenbroek 		}
1604*83ee113eSDavid van Moolenbroek 	}
1605*83ee113eSDavid van Moolenbroek 
1606*83ee113eSDavid van Moolenbroek 	/* If we've already seen this lease, don't record it again. */
1607*83ee113eSDavid van Moolenbroek 	for (lease = client -> offered_leases; lease; lease = lease -> next) {
1608*83ee113eSDavid van Moolenbroek 		if (lease -> address.len == sizeof packet -> raw -> yiaddr &&
1609*83ee113eSDavid van Moolenbroek 		    !memcmp (lease -> address.iabuf,
1610*83ee113eSDavid van Moolenbroek 			     &packet -> raw -> yiaddr, lease -> address.len)) {
1611*83ee113eSDavid van Moolenbroek 			log_debug ("%s: already seen.", obuf);
1612*83ee113eSDavid van Moolenbroek 			return;
1613*83ee113eSDavid van Moolenbroek 		}
1614*83ee113eSDavid van Moolenbroek 	}
1615*83ee113eSDavid van Moolenbroek 
1616*83ee113eSDavid van Moolenbroek 	lease = packet_to_lease (packet, client);
1617*83ee113eSDavid van Moolenbroek 	if (!lease) {
1618*83ee113eSDavid van Moolenbroek 		log_info ("%s: packet_to_lease failed.", obuf);
1619*83ee113eSDavid van Moolenbroek 		return;
1620*83ee113eSDavid van Moolenbroek 	}
1621*83ee113eSDavid van Moolenbroek 
1622*83ee113eSDavid van Moolenbroek 	/* If this lease was acquired through a BOOTREPLY, record that
1623*83ee113eSDavid van Moolenbroek 	   fact. */
1624*83ee113eSDavid van Moolenbroek 	if (!packet -> options_valid || !packet -> packet_type)
1625*83ee113eSDavid van Moolenbroek 		lease -> is_bootp = 1;
1626*83ee113eSDavid van Moolenbroek 
1627*83ee113eSDavid van Moolenbroek 	/* Record the medium under which this lease was offered. */
1628*83ee113eSDavid van Moolenbroek 	lease -> medium = client -> medium;
1629*83ee113eSDavid van Moolenbroek 
1630*83ee113eSDavid van Moolenbroek 	/* Figure out when we're supposed to stop selecting. */
1631*83ee113eSDavid van Moolenbroek 	stop_selecting = (client -> first_sending +
1632*83ee113eSDavid van Moolenbroek 			  client -> config -> select_interval);
1633*83ee113eSDavid van Moolenbroek 
1634*83ee113eSDavid van Moolenbroek 	/* If this is the lease we asked for, put it at the head of the
1635*83ee113eSDavid van Moolenbroek 	   list, and don't mess with the arp request timeout. */
1636*83ee113eSDavid van Moolenbroek 	if (lease -> address.len == client -> requested_address.len &&
1637*83ee113eSDavid van Moolenbroek 	    !memcmp (lease -> address.iabuf,
1638*83ee113eSDavid van Moolenbroek 		     client -> requested_address.iabuf,
1639*83ee113eSDavid van Moolenbroek 		     client -> requested_address.len)) {
1640*83ee113eSDavid van Moolenbroek 		lease -> next = client -> offered_leases;
1641*83ee113eSDavid van Moolenbroek 		client -> offered_leases = lease;
1642*83ee113eSDavid van Moolenbroek 	} else {
1643*83ee113eSDavid van Moolenbroek 		/* Put the lease at the end of the list. */
1644*83ee113eSDavid van Moolenbroek 		lease -> next = (struct client_lease *)0;
1645*83ee113eSDavid van Moolenbroek 		if (!client -> offered_leases)
1646*83ee113eSDavid van Moolenbroek 			client -> offered_leases = lease;
1647*83ee113eSDavid van Moolenbroek 		else {
1648*83ee113eSDavid van Moolenbroek 			for (lp = client -> offered_leases; lp -> next;
1649*83ee113eSDavid van Moolenbroek 			     lp = lp -> next)
1650*83ee113eSDavid van Moolenbroek 				;
1651*83ee113eSDavid van Moolenbroek 			lp -> next = lease;
1652*83ee113eSDavid van Moolenbroek 		}
1653*83ee113eSDavid van Moolenbroek 	}
1654*83ee113eSDavid van Moolenbroek 
1655*83ee113eSDavid van Moolenbroek 	/* If the selecting interval has expired, go immediately to
1656*83ee113eSDavid van Moolenbroek 	   state_selecting().  Otherwise, time out into
1657*83ee113eSDavid van Moolenbroek 	   state_selecting at the select interval. */
1658*83ee113eSDavid van Moolenbroek 	if (stop_selecting <= cur_tv.tv_sec)
1659*83ee113eSDavid van Moolenbroek 		state_selecting (client);
1660*83ee113eSDavid van Moolenbroek 	else {
1661*83ee113eSDavid van Moolenbroek 		tv.tv_sec = stop_selecting;
1662*83ee113eSDavid van Moolenbroek 		tv.tv_usec = cur_tv.tv_usec;
1663*83ee113eSDavid van Moolenbroek 		add_timeout(&tv, state_selecting, client, 0, 0);
1664*83ee113eSDavid van Moolenbroek 		cancel_timeout(send_discover, client);
1665*83ee113eSDavid van Moolenbroek 	}
1666*83ee113eSDavid van Moolenbroek 	log_info("%s", obuf);
1667*83ee113eSDavid van Moolenbroek }
1668*83ee113eSDavid van Moolenbroek 
1669*83ee113eSDavid van Moolenbroek /* Allocate a client_lease structure and initialize it from the parameters
1670*83ee113eSDavid van Moolenbroek    in the specified packet. */
1671*83ee113eSDavid van Moolenbroek 
packet_to_lease(packet,client)1672*83ee113eSDavid van Moolenbroek struct client_lease *packet_to_lease (packet, client)
1673*83ee113eSDavid van Moolenbroek 	struct packet *packet;
1674*83ee113eSDavid van Moolenbroek 	struct client_state *client;
1675*83ee113eSDavid van Moolenbroek {
1676*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
1677*83ee113eSDavid van Moolenbroek 	unsigned i;
1678*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
1679*83ee113eSDavid van Moolenbroek 	struct option *option = NULL;
1680*83ee113eSDavid van Moolenbroek 	struct data_string data;
1681*83ee113eSDavid van Moolenbroek 
1682*83ee113eSDavid van Moolenbroek 	lease = (struct client_lease *)new_client_lease (MDL);
1683*83ee113eSDavid van Moolenbroek 
1684*83ee113eSDavid van Moolenbroek 	if (!lease) {
1685*83ee113eSDavid van Moolenbroek 		log_error ("packet_to_lease: no memory to record lease.\n");
1686*83ee113eSDavid van Moolenbroek 		return (struct client_lease *)0;
1687*83ee113eSDavid van Moolenbroek 	}
1688*83ee113eSDavid van Moolenbroek 
1689*83ee113eSDavid van Moolenbroek 	memset (lease, 0, sizeof *lease);
1690*83ee113eSDavid van Moolenbroek 
1691*83ee113eSDavid van Moolenbroek 	/* Copy the lease options. */
1692*83ee113eSDavid van Moolenbroek 	option_state_reference (&lease -> options, packet -> options, MDL);
1693*83ee113eSDavid van Moolenbroek 
1694*83ee113eSDavid van Moolenbroek 	lease -> address.len = sizeof (packet -> raw -> yiaddr);
1695*83ee113eSDavid van Moolenbroek 	memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
1696*83ee113eSDavid van Moolenbroek 		lease -> address.len);
1697*83ee113eSDavid van Moolenbroek 
1698*83ee113eSDavid van Moolenbroek 	memset (&data, 0, sizeof data);
1699*83ee113eSDavid van Moolenbroek 
1700*83ee113eSDavid van Moolenbroek 	if (client -> config -> vendor_space_name) {
1701*83ee113eSDavid van Moolenbroek 		i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
1702*83ee113eSDavid van Moolenbroek 
1703*83ee113eSDavid van Moolenbroek 		/* See if there was a vendor encapsulation option. */
1704*83ee113eSDavid van Moolenbroek 		oc = lookup_option (&dhcp_universe, lease -> options, i);
1705*83ee113eSDavid van Moolenbroek 		if (oc &&
1706*83ee113eSDavid van Moolenbroek 		    client -> config -> vendor_space_name &&
1707*83ee113eSDavid van Moolenbroek 		    evaluate_option_cache (&data, packet,
1708*83ee113eSDavid van Moolenbroek 					   (struct lease *)0, client,
1709*83ee113eSDavid van Moolenbroek 					   packet -> options, lease -> options,
1710*83ee113eSDavid van Moolenbroek 					   &global_scope, oc, MDL)) {
1711*83ee113eSDavid van Moolenbroek 			if (data.len) {
1712*83ee113eSDavid van Moolenbroek 				if (!option_code_hash_lookup(&option,
1713*83ee113eSDavid van Moolenbroek 						dhcp_universe.code_hash,
1714*83ee113eSDavid van Moolenbroek 						&i, 0, MDL))
1715*83ee113eSDavid van Moolenbroek 					log_fatal("Unable to find VENDOR "
1716*83ee113eSDavid van Moolenbroek 						  "option (%s:%d).", MDL);
1717*83ee113eSDavid van Moolenbroek 				parse_encapsulated_suboptions
1718*83ee113eSDavid van Moolenbroek 					(packet -> options, option,
1719*83ee113eSDavid van Moolenbroek 					 data.data, data.len, &dhcp_universe,
1720*83ee113eSDavid van Moolenbroek 					 client -> config -> vendor_space_name
1721*83ee113eSDavid van Moolenbroek 						);
1722*83ee113eSDavid van Moolenbroek 
1723*83ee113eSDavid van Moolenbroek 				option_dereference(&option, MDL);
1724*83ee113eSDavid van Moolenbroek 			}
1725*83ee113eSDavid van Moolenbroek 			data_string_forget (&data, MDL);
1726*83ee113eSDavid van Moolenbroek 		}
1727*83ee113eSDavid van Moolenbroek 	} else
1728*83ee113eSDavid van Moolenbroek 		i = 0;
1729*83ee113eSDavid van Moolenbroek 
1730*83ee113eSDavid van Moolenbroek 	/* Figure out the overload flag. */
1731*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, lease -> options,
1732*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_OPTION_OVERLOAD);
1733*83ee113eSDavid van Moolenbroek 	if (oc &&
1734*83ee113eSDavid van Moolenbroek 	    evaluate_option_cache (&data, packet, (struct lease *)0, client,
1735*83ee113eSDavid van Moolenbroek 				   packet -> options, lease -> options,
1736*83ee113eSDavid van Moolenbroek 				   &global_scope, oc, MDL)) {
1737*83ee113eSDavid van Moolenbroek 		if (data.len > 0)
1738*83ee113eSDavid van Moolenbroek 			i = data.data [0];
1739*83ee113eSDavid van Moolenbroek 		else
1740*83ee113eSDavid van Moolenbroek 			i = 0;
1741*83ee113eSDavid van Moolenbroek 		data_string_forget (&data, MDL);
1742*83ee113eSDavid van Moolenbroek 	} else
1743*83ee113eSDavid van Moolenbroek 		i = 0;
1744*83ee113eSDavid van Moolenbroek 
1745*83ee113eSDavid van Moolenbroek 	/* If the server name was filled out, copy it. */
1746*83ee113eSDavid van Moolenbroek 	if (!(i & 2) && packet -> raw -> sname [0]) {
1747*83ee113eSDavid van Moolenbroek 		unsigned len;
1748*83ee113eSDavid van Moolenbroek 		/* Don't count on the NUL terminator. */
1749*83ee113eSDavid van Moolenbroek 		for (len = 0; len < DHCP_SNAME_LEN; len++)
1750*83ee113eSDavid van Moolenbroek 			if (!packet -> raw -> sname [len])
1751*83ee113eSDavid van Moolenbroek 				break;
1752*83ee113eSDavid van Moolenbroek 		lease -> server_name = dmalloc (len + 1, MDL);
1753*83ee113eSDavid van Moolenbroek 		if (!lease -> server_name) {
1754*83ee113eSDavid van Moolenbroek 			log_error ("dhcpoffer: no memory for server name.\n");
1755*83ee113eSDavid van Moolenbroek 			destroy_client_lease (lease);
1756*83ee113eSDavid van Moolenbroek 			return (struct client_lease *)0;
1757*83ee113eSDavid van Moolenbroek 		} else {
1758*83ee113eSDavid van Moolenbroek 			memcpy (lease -> server_name,
1759*83ee113eSDavid van Moolenbroek 				packet -> raw -> sname, len);
1760*83ee113eSDavid van Moolenbroek 			lease -> server_name [len] = 0;
1761*83ee113eSDavid van Moolenbroek 		}
1762*83ee113eSDavid van Moolenbroek 	}
1763*83ee113eSDavid van Moolenbroek 
1764*83ee113eSDavid van Moolenbroek 	/* Ditto for the filename. */
1765*83ee113eSDavid van Moolenbroek 	if (!(i & 1) && packet -> raw -> file [0]) {
1766*83ee113eSDavid van Moolenbroek 		unsigned len;
1767*83ee113eSDavid van Moolenbroek 		/* Don't count on the NUL terminator. */
1768*83ee113eSDavid van Moolenbroek 		for (len = 0; len < DHCP_FILE_LEN; len++)
1769*83ee113eSDavid van Moolenbroek 			if (!packet -> raw -> file [len])
1770*83ee113eSDavid van Moolenbroek 				break;
1771*83ee113eSDavid van Moolenbroek 		lease -> filename = dmalloc (len + 1, MDL);
1772*83ee113eSDavid van Moolenbroek 		if (!lease -> filename) {
1773*83ee113eSDavid van Moolenbroek 			log_error ("dhcpoffer: no memory for filename.\n");
1774*83ee113eSDavid van Moolenbroek 			destroy_client_lease (lease);
1775*83ee113eSDavid van Moolenbroek 			return (struct client_lease *)0;
1776*83ee113eSDavid van Moolenbroek 		} else {
1777*83ee113eSDavid van Moolenbroek 			memcpy (lease -> filename,
1778*83ee113eSDavid van Moolenbroek 				packet -> raw -> file, len);
1779*83ee113eSDavid van Moolenbroek 			lease -> filename [len] = 0;
1780*83ee113eSDavid van Moolenbroek 		}
1781*83ee113eSDavid van Moolenbroek 	}
1782*83ee113eSDavid van Moolenbroek 
1783*83ee113eSDavid van Moolenbroek 	execute_statements_in_scope(NULL, (struct packet *)packet, NULL,
1784*83ee113eSDavid van Moolenbroek 				    client, lease->options, lease->options,
1785*83ee113eSDavid van Moolenbroek 				    &global_scope, client->config->on_receipt,
1786*83ee113eSDavid van Moolenbroek 				    NULL, NULL);
1787*83ee113eSDavid van Moolenbroek 
1788*83ee113eSDavid van Moolenbroek 	return lease;
1789*83ee113eSDavid van Moolenbroek }
1790*83ee113eSDavid van Moolenbroek 
dhcpnak(packet)1791*83ee113eSDavid van Moolenbroek void dhcpnak (packet)
1792*83ee113eSDavid van Moolenbroek 	struct packet *packet;
1793*83ee113eSDavid van Moolenbroek {
1794*83ee113eSDavid van Moolenbroek 	struct interface_info *ip = packet -> interface;
1795*83ee113eSDavid van Moolenbroek 	struct client_state *client;
1796*83ee113eSDavid van Moolenbroek 
1797*83ee113eSDavid van Moolenbroek 	/* Find a client state that matches the xid... */
1798*83ee113eSDavid van Moolenbroek 	for (client = ip -> client; client; client = client -> next)
1799*83ee113eSDavid van Moolenbroek 		if (client -> xid == packet -> raw -> xid)
1800*83ee113eSDavid van Moolenbroek 			break;
1801*83ee113eSDavid van Moolenbroek 
1802*83ee113eSDavid van Moolenbroek 	/* If we're not receptive to an offer right now, or if the offer
1803*83ee113eSDavid van Moolenbroek 	   has an unrecognizable transaction id, then just drop it. */
1804*83ee113eSDavid van Moolenbroek 	if (!client || compare_hw_address("DHCPNAK", packet) == ISC_TRUE)
1805*83ee113eSDavid van Moolenbroek 		return;
1806*83ee113eSDavid van Moolenbroek 
1807*83ee113eSDavid van Moolenbroek 	if (client -> state != S_REBOOTING &&
1808*83ee113eSDavid van Moolenbroek 	    client -> state != S_REQUESTING &&
1809*83ee113eSDavid van Moolenbroek 	    client -> state != S_RENEWING &&
1810*83ee113eSDavid van Moolenbroek 	    client -> state != S_REBINDING) {
1811*83ee113eSDavid van Moolenbroek #if defined (DEBUG)
1812*83ee113eSDavid van Moolenbroek 		log_debug ("DHCPNAK in wrong state.");
1813*83ee113eSDavid van Moolenbroek #endif
1814*83ee113eSDavid van Moolenbroek 		return;
1815*83ee113eSDavid van Moolenbroek 	}
1816*83ee113eSDavid van Moolenbroek 
1817*83ee113eSDavid van Moolenbroek 	log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
1818*83ee113eSDavid van Moolenbroek 
1819*83ee113eSDavid van Moolenbroek 	if (!client -> active) {
1820*83ee113eSDavid van Moolenbroek #if defined (DEBUG)
1821*83ee113eSDavid van Moolenbroek 		log_info ("DHCPNAK with no active lease.\n");
1822*83ee113eSDavid van Moolenbroek #endif
1823*83ee113eSDavid van Moolenbroek 		return;
1824*83ee113eSDavid van Moolenbroek 	}
1825*83ee113eSDavid van Moolenbroek 
1826*83ee113eSDavid van Moolenbroek 	/* If we get a DHCPNAK, we use the EXPIRE dhclient-script state
1827*83ee113eSDavid van Moolenbroek 	 * to indicate that we want all old bindings to be removed.  (It
1828*83ee113eSDavid van Moolenbroek 	 * is possible that we may get a NAK while in the RENEW state,
1829*83ee113eSDavid van Moolenbroek 	 * so we might have bindings active at that time)
1830*83ee113eSDavid van Moolenbroek 	 */
1831*83ee113eSDavid van Moolenbroek 	script_init(client, "EXPIRE", NULL);
1832*83ee113eSDavid van Moolenbroek 	script_write_params(client, "old_", client->active);
1833*83ee113eSDavid van Moolenbroek 	script_write_requested(client);
1834*83ee113eSDavid van Moolenbroek 	if (client->alias)
1835*83ee113eSDavid van Moolenbroek 		script_write_params(client, "alias_", client->alias);
1836*83ee113eSDavid van Moolenbroek 	script_go(client);
1837*83ee113eSDavid van Moolenbroek 
1838*83ee113eSDavid van Moolenbroek 	destroy_client_lease (client -> active);
1839*83ee113eSDavid van Moolenbroek 	client -> active = (struct client_lease *)0;
1840*83ee113eSDavid van Moolenbroek 
1841*83ee113eSDavid van Moolenbroek 	/* Stop sending DHCPREQUEST packets... */
1842*83ee113eSDavid van Moolenbroek 	cancel_timeout (send_request, client);
1843*83ee113eSDavid van Moolenbroek 
1844*83ee113eSDavid van Moolenbroek 	/* On some scripts, 'EXPIRE' causes the interface to be ifconfig'd
1845*83ee113eSDavid van Moolenbroek 	 * down (this expunges any routes and arp cache).  This makes the
1846*83ee113eSDavid van Moolenbroek 	 * interface unusable by state_init(), which we call next.  So, we
1847*83ee113eSDavid van Moolenbroek 	 * need to 'PREINIT' the interface to bring it back up.
1848*83ee113eSDavid van Moolenbroek 	 */
1849*83ee113eSDavid van Moolenbroek 	script_init(client, "PREINIT", NULL);
1850*83ee113eSDavid van Moolenbroek 	if (client->alias)
1851*83ee113eSDavid van Moolenbroek 		script_write_params(client, "alias_", client->alias);
1852*83ee113eSDavid van Moolenbroek 	script_go(client);
1853*83ee113eSDavid van Moolenbroek 
1854*83ee113eSDavid van Moolenbroek 	client -> state = S_INIT;
1855*83ee113eSDavid van Moolenbroek 	state_init (client);
1856*83ee113eSDavid van Moolenbroek }
1857*83ee113eSDavid van Moolenbroek 
1858*83ee113eSDavid van Moolenbroek /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1859*83ee113eSDavid van Moolenbroek    one after the right interval has expired.  If we don't get an offer by
1860*83ee113eSDavid van Moolenbroek    the time we reach the panic interval, call the panic function. */
1861*83ee113eSDavid van Moolenbroek 
send_discover(cpp)1862*83ee113eSDavid van Moolenbroek void send_discover (cpp)
1863*83ee113eSDavid van Moolenbroek 	void *cpp;
1864*83ee113eSDavid van Moolenbroek {
1865*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
1866*83ee113eSDavid van Moolenbroek 
1867*83ee113eSDavid van Moolenbroek 	int result;
1868*83ee113eSDavid van Moolenbroek 	int interval;
1869*83ee113eSDavid van Moolenbroek 	int increase = 1;
1870*83ee113eSDavid van Moolenbroek 	struct timeval tv;
1871*83ee113eSDavid van Moolenbroek 
1872*83ee113eSDavid van Moolenbroek 	/* Figure out how long it's been since we started transmitting. */
1873*83ee113eSDavid van Moolenbroek 	interval = cur_time - client -> first_sending;
1874*83ee113eSDavid van Moolenbroek 
1875*83ee113eSDavid van Moolenbroek 	/* If we're past the panic timeout, call the script and tell it
1876*83ee113eSDavid van Moolenbroek 	   we haven't found anything for this interface yet. */
1877*83ee113eSDavid van Moolenbroek 	if (interval > client -> config -> timeout) {
1878*83ee113eSDavid van Moolenbroek 		state_panic (client);
1879*83ee113eSDavid van Moolenbroek 		return;
1880*83ee113eSDavid van Moolenbroek 	}
1881*83ee113eSDavid van Moolenbroek 
1882*83ee113eSDavid van Moolenbroek 	/* If we're selecting media, try the whole list before doing
1883*83ee113eSDavid van Moolenbroek 	   the exponential backoff, but if we've already received an
1884*83ee113eSDavid van Moolenbroek 	   offer, stop looping, because we obviously have it right. */
1885*83ee113eSDavid van Moolenbroek 	if (!client -> offered_leases &&
1886*83ee113eSDavid van Moolenbroek 	    client -> config -> media) {
1887*83ee113eSDavid van Moolenbroek 		int fail = 0;
1888*83ee113eSDavid van Moolenbroek 	      again:
1889*83ee113eSDavid van Moolenbroek 		if (client -> medium) {
1890*83ee113eSDavid van Moolenbroek 			client -> medium = client -> medium -> next;
1891*83ee113eSDavid van Moolenbroek 			increase = 0;
1892*83ee113eSDavid van Moolenbroek 		}
1893*83ee113eSDavid van Moolenbroek 		if (!client -> medium) {
1894*83ee113eSDavid van Moolenbroek 			if (fail)
1895*83ee113eSDavid van Moolenbroek 				log_fatal ("No valid media types for %s!",
1896*83ee113eSDavid van Moolenbroek 				       client -> interface -> name);
1897*83ee113eSDavid van Moolenbroek 			client -> medium =
1898*83ee113eSDavid van Moolenbroek 				client -> config -> media;
1899*83ee113eSDavid van Moolenbroek 			increase = 1;
1900*83ee113eSDavid van Moolenbroek 		}
1901*83ee113eSDavid van Moolenbroek 
1902*83ee113eSDavid van Moolenbroek 		log_info ("Trying medium \"%s\" %d",
1903*83ee113eSDavid van Moolenbroek 			  client -> medium -> string, increase);
1904*83ee113eSDavid van Moolenbroek 		script_init (client, "MEDIUM", client -> medium);
1905*83ee113eSDavid van Moolenbroek 		if (script_go (client)) {
1906*83ee113eSDavid van Moolenbroek 			fail = 1;
1907*83ee113eSDavid van Moolenbroek 			goto again;
1908*83ee113eSDavid van Moolenbroek 		}
1909*83ee113eSDavid van Moolenbroek 	}
1910*83ee113eSDavid van Moolenbroek 
1911*83ee113eSDavid van Moolenbroek 	/* If we're supposed to increase the interval, do so.  If it's
1912*83ee113eSDavid van Moolenbroek 	   currently zero (i.e., we haven't sent any packets yet), set
1913*83ee113eSDavid van Moolenbroek 	   it to initial_interval; otherwise, add to it a random number
1914*83ee113eSDavid van Moolenbroek 	   between zero and two times itself.  On average, this means
1915*83ee113eSDavid van Moolenbroek 	   that it will double with every transmission. */
1916*83ee113eSDavid van Moolenbroek 	if (increase) {
1917*83ee113eSDavid van Moolenbroek 		if (!client->interval)
1918*83ee113eSDavid van Moolenbroek 			client->interval = client->config->initial_interval;
1919*83ee113eSDavid van Moolenbroek 		else
1920*83ee113eSDavid van Moolenbroek 			client->interval += random() % (2 * client->interval);
1921*83ee113eSDavid van Moolenbroek 
1922*83ee113eSDavid van Moolenbroek 		/* Don't backoff past cutoff. */
1923*83ee113eSDavid van Moolenbroek 		if (client->interval > client->config->backoff_cutoff)
1924*83ee113eSDavid van Moolenbroek 			client->interval = (client->config->backoff_cutoff / 2)
1925*83ee113eSDavid van Moolenbroek 				 + (random() % client->config->backoff_cutoff);
1926*83ee113eSDavid van Moolenbroek 	} else if (!client->interval)
1927*83ee113eSDavid van Moolenbroek 		client->interval = client->config->initial_interval;
1928*83ee113eSDavid van Moolenbroek 
1929*83ee113eSDavid van Moolenbroek 	/* If the backoff would take us to the panic timeout, just use that
1930*83ee113eSDavid van Moolenbroek 	   as the interval. */
1931*83ee113eSDavid van Moolenbroek 	if (cur_time + client -> interval >
1932*83ee113eSDavid van Moolenbroek 	    client -> first_sending + client -> config -> timeout)
1933*83ee113eSDavid van Moolenbroek 		client -> interval =
1934*83ee113eSDavid van Moolenbroek 			(client -> first_sending +
1935*83ee113eSDavid van Moolenbroek 			 client -> config -> timeout) - cur_time + 1;
1936*83ee113eSDavid van Moolenbroek 
1937*83ee113eSDavid van Moolenbroek 	/* Record the number of seconds since we started sending. */
1938*83ee113eSDavid van Moolenbroek 	if (interval < 65536)
1939*83ee113eSDavid van Moolenbroek 		client -> packet.secs = htons (interval);
1940*83ee113eSDavid van Moolenbroek 	else
1941*83ee113eSDavid van Moolenbroek 		client -> packet.secs = htons (65535);
1942*83ee113eSDavid van Moolenbroek 	client -> secs = client -> packet.secs;
1943*83ee113eSDavid van Moolenbroek 
1944*83ee113eSDavid van Moolenbroek 	log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
1945*83ee113eSDavid van Moolenbroek 	      client -> name ? client -> name : client -> interface -> name,
1946*83ee113eSDavid van Moolenbroek 	      inet_ntoa (sockaddr_broadcast.sin_addr),
1947*83ee113eSDavid van Moolenbroek 	      ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
1948*83ee113eSDavid van Moolenbroek 
1949*83ee113eSDavid van Moolenbroek 	/* Send out a packet. */
1950*83ee113eSDavid van Moolenbroek 	result = send_packet(client->interface, NULL, &client->packet,
1951*83ee113eSDavid van Moolenbroek 			     client->packet_length, inaddr_any,
1952*83ee113eSDavid van Moolenbroek                              &sockaddr_broadcast, NULL);
1953*83ee113eSDavid van Moolenbroek         if (result < 0) {
1954*83ee113eSDavid van Moolenbroek 		log_error("%s:%d: Failed to send %d byte long packet over %s "
1955*83ee113eSDavid van Moolenbroek 			  "interface.", MDL, client->packet_length,
1956*83ee113eSDavid van Moolenbroek 			  client->interface->name);
1957*83ee113eSDavid van Moolenbroek 	}
1958*83ee113eSDavid van Moolenbroek 
1959*83ee113eSDavid van Moolenbroek 	/*
1960*83ee113eSDavid van Moolenbroek 	 * If we used 0 microseconds here, and there were other clients on the
1961*83ee113eSDavid van Moolenbroek 	 * same network with a synchronized local clock (ntp), and a similar
1962*83ee113eSDavid van Moolenbroek 	 * zero-microsecond-scheduler behavior, then we could be participating
1963*83ee113eSDavid van Moolenbroek 	 * in a sub-second DOS ttck.
1964*83ee113eSDavid van Moolenbroek 	 */
1965*83ee113eSDavid van Moolenbroek 	tv.tv_sec = cur_tv.tv_sec + client->interval;
1966*83ee113eSDavid van Moolenbroek 	tv.tv_usec = client->interval > 1 ? random() % 1000000 : cur_tv.tv_usec;
1967*83ee113eSDavid van Moolenbroek 	add_timeout(&tv, send_discover, client, 0, 0);
1968*83ee113eSDavid van Moolenbroek }
1969*83ee113eSDavid van Moolenbroek 
1970*83ee113eSDavid van Moolenbroek /* state_panic gets called if we haven't received any offers in a preset
1971*83ee113eSDavid van Moolenbroek    amount of time.   When this happens, we try to use existing leases that
1972*83ee113eSDavid van Moolenbroek    haven't yet expired, and failing that, we call the client script and
1973*83ee113eSDavid van Moolenbroek    hope it can do something. */
1974*83ee113eSDavid van Moolenbroek 
state_panic(cpp)1975*83ee113eSDavid van Moolenbroek void state_panic (cpp)
1976*83ee113eSDavid van Moolenbroek 	void *cpp;
1977*83ee113eSDavid van Moolenbroek {
1978*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
1979*83ee113eSDavid van Moolenbroek 	struct client_lease *loop;
1980*83ee113eSDavid van Moolenbroek 	struct client_lease *lp;
1981*83ee113eSDavid van Moolenbroek 	struct timeval tv;
1982*83ee113eSDavid van Moolenbroek 
1983*83ee113eSDavid van Moolenbroek 	loop = lp = client -> active;
1984*83ee113eSDavid van Moolenbroek 
1985*83ee113eSDavid van Moolenbroek 	log_info ("No DHCPOFFERS received.");
1986*83ee113eSDavid van Moolenbroek 
1987*83ee113eSDavid van Moolenbroek 	/* We may not have an active lease, but we may have some
1988*83ee113eSDavid van Moolenbroek 	   predefined leases that we can try. */
1989*83ee113eSDavid van Moolenbroek 	if (!client -> active && client -> leases)
1990*83ee113eSDavid van Moolenbroek 		goto activate_next;
1991*83ee113eSDavid van Moolenbroek 
1992*83ee113eSDavid van Moolenbroek 	/* Run through the list of leases and see if one can be used. */
1993*83ee113eSDavid van Moolenbroek 	while (client -> active) {
1994*83ee113eSDavid van Moolenbroek 		if (client -> active -> expiry > cur_time) {
1995*83ee113eSDavid van Moolenbroek 			log_info ("Trying recorded lease %s",
1996*83ee113eSDavid van Moolenbroek 			      piaddr (client -> active -> address));
1997*83ee113eSDavid van Moolenbroek 			/* Run the client script with the existing
1998*83ee113eSDavid van Moolenbroek 			   parameters. */
1999*83ee113eSDavid van Moolenbroek 			script_init (client, "TIMEOUT",
2000*83ee113eSDavid van Moolenbroek 				     client -> active -> medium);
2001*83ee113eSDavid van Moolenbroek 			script_write_params (client, "new_", client -> active);
2002*83ee113eSDavid van Moolenbroek 			script_write_requested(client);
2003*83ee113eSDavid van Moolenbroek 			if (client -> alias)
2004*83ee113eSDavid van Moolenbroek 				script_write_params (client, "alias_",
2005*83ee113eSDavid van Moolenbroek 						     client -> alias);
2006*83ee113eSDavid van Moolenbroek 
2007*83ee113eSDavid van Moolenbroek 			/* If the old lease is still good and doesn't
2008*83ee113eSDavid van Moolenbroek 			   yet need renewal, go into BOUND state and
2009*83ee113eSDavid van Moolenbroek 			   timeout at the renewal time. */
2010*83ee113eSDavid van Moolenbroek 			if (!script_go (client)) {
2011*83ee113eSDavid van Moolenbroek 			    if (cur_time < client -> active -> renewal) {
2012*83ee113eSDavid van Moolenbroek 				client -> state = S_BOUND;
2013*83ee113eSDavid van Moolenbroek 				log_info ("bound: renewal in %ld %s.",
2014*83ee113eSDavid van Moolenbroek 					  (long)(client -> active -> renewal -
2015*83ee113eSDavid van Moolenbroek 						 cur_time), "seconds");
2016*83ee113eSDavid van Moolenbroek 				tv.tv_sec = client->active->renewal;
2017*83ee113eSDavid van Moolenbroek 				tv.tv_usec = ((client->active->renewal -
2018*83ee113eSDavid van Moolenbroek 						    cur_time) > 1) ?
2019*83ee113eSDavid van Moolenbroek 						random() % 1000000 :
2020*83ee113eSDavid van Moolenbroek 						cur_tv.tv_usec;
2021*83ee113eSDavid van Moolenbroek 				add_timeout(&tv, state_bound, client, 0, 0);
2022*83ee113eSDavid van Moolenbroek 			    } else {
2023*83ee113eSDavid van Moolenbroek 				client -> state = S_BOUND;
2024*83ee113eSDavid van Moolenbroek 				log_info ("bound: immediate renewal.");
2025*83ee113eSDavid van Moolenbroek 				state_bound (client);
2026*83ee113eSDavid van Moolenbroek 			    }
2027*83ee113eSDavid van Moolenbroek 			    reinitialize_interfaces ();
2028*83ee113eSDavid van Moolenbroek 			    finish_daemon ();
2029*83ee113eSDavid van Moolenbroek 			    return;
2030*83ee113eSDavid van Moolenbroek 			}
2031*83ee113eSDavid van Moolenbroek 		}
2032*83ee113eSDavid van Moolenbroek 
2033*83ee113eSDavid van Moolenbroek 		/* If there are no other leases, give up. */
2034*83ee113eSDavid van Moolenbroek 		if (!client -> leases) {
2035*83ee113eSDavid van Moolenbroek 			client -> leases = client -> active;
2036*83ee113eSDavid van Moolenbroek 			client -> active = (struct client_lease *)0;
2037*83ee113eSDavid van Moolenbroek 			break;
2038*83ee113eSDavid van Moolenbroek 		}
2039*83ee113eSDavid van Moolenbroek 
2040*83ee113eSDavid van Moolenbroek 	activate_next:
2041*83ee113eSDavid van Moolenbroek 		/* Otherwise, put the active lease at the end of the
2042*83ee113eSDavid van Moolenbroek 		   lease list, and try another lease.. */
2043*83ee113eSDavid van Moolenbroek 		for (lp = client -> leases; lp -> next; lp = lp -> next)
2044*83ee113eSDavid van Moolenbroek 			;
2045*83ee113eSDavid van Moolenbroek 		lp -> next = client -> active;
2046*83ee113eSDavid van Moolenbroek 		if (lp -> next) {
2047*83ee113eSDavid van Moolenbroek 			lp -> next -> next = (struct client_lease *)0;
2048*83ee113eSDavid van Moolenbroek 		}
2049*83ee113eSDavid van Moolenbroek 		client -> active = client -> leases;
2050*83ee113eSDavid van Moolenbroek 		client -> leases = client -> leases -> next;
2051*83ee113eSDavid van Moolenbroek 
2052*83ee113eSDavid van Moolenbroek 		/* If we already tried this lease, we've exhausted the
2053*83ee113eSDavid van Moolenbroek 		   set of leases, so we might as well give up for
2054*83ee113eSDavid van Moolenbroek 		   now. */
2055*83ee113eSDavid van Moolenbroek 		if (client -> active == loop)
2056*83ee113eSDavid van Moolenbroek 			break;
2057*83ee113eSDavid van Moolenbroek 		else if (!loop)
2058*83ee113eSDavid van Moolenbroek 			loop = client -> active;
2059*83ee113eSDavid van Moolenbroek 	}
2060*83ee113eSDavid van Moolenbroek 
2061*83ee113eSDavid van Moolenbroek 	/* No leases were available, or what was available didn't work, so
2062*83ee113eSDavid van Moolenbroek 	   tell the shell script that we failed to allocate an address,
2063*83ee113eSDavid van Moolenbroek 	   and try again later. */
2064*83ee113eSDavid van Moolenbroek 	if (onetry) {
2065*83ee113eSDavid van Moolenbroek 		if (!quiet)
2066*83ee113eSDavid van Moolenbroek 			log_info ("Unable to obtain a lease on first try.%s",
2067*83ee113eSDavid van Moolenbroek 				  "  Exiting.");
2068*83ee113eSDavid van Moolenbroek 		exit (2);
2069*83ee113eSDavid van Moolenbroek 	}
2070*83ee113eSDavid van Moolenbroek 
2071*83ee113eSDavid van Moolenbroek 	log_info ("No working leases in persistent database - sleeping.");
2072*83ee113eSDavid van Moolenbroek 	script_init (client, "FAIL", (struct string_list *)0);
2073*83ee113eSDavid van Moolenbroek 	if (client -> alias)
2074*83ee113eSDavid van Moolenbroek 		script_write_params (client, "alias_", client -> alias);
2075*83ee113eSDavid van Moolenbroek 	script_go (client);
2076*83ee113eSDavid van Moolenbroek 	client -> state = S_INIT;
2077*83ee113eSDavid van Moolenbroek 	tv.tv_sec = cur_tv.tv_sec + ((client->config->retry_interval + 1) / 2 +
2078*83ee113eSDavid van Moolenbroek 		    (random() % client->config->retry_interval));
2079*83ee113eSDavid van Moolenbroek 	tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ?
2080*83ee113eSDavid van Moolenbroek 			random() % 1000000 : cur_tv.tv_usec;
2081*83ee113eSDavid van Moolenbroek 	add_timeout(&tv, state_init, client, 0, 0);
2082*83ee113eSDavid van Moolenbroek 	finish_daemon ();
2083*83ee113eSDavid van Moolenbroek }
2084*83ee113eSDavid van Moolenbroek 
send_request(cpp)2085*83ee113eSDavid van Moolenbroek void send_request (cpp)
2086*83ee113eSDavid van Moolenbroek 	void *cpp;
2087*83ee113eSDavid van Moolenbroek {
2088*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
2089*83ee113eSDavid van Moolenbroek 
2090*83ee113eSDavid van Moolenbroek 	int result;
2091*83ee113eSDavid van Moolenbroek 	int interval;
2092*83ee113eSDavid van Moolenbroek 	struct sockaddr_in destination;
2093*83ee113eSDavid van Moolenbroek 	struct in_addr from;
2094*83ee113eSDavid van Moolenbroek 	struct timeval tv;
2095*83ee113eSDavid van Moolenbroek 
2096*83ee113eSDavid van Moolenbroek 	/* Figure out how long it's been since we started transmitting. */
2097*83ee113eSDavid van Moolenbroek 	interval = cur_time - client -> first_sending;
2098*83ee113eSDavid van Moolenbroek 
2099*83ee113eSDavid van Moolenbroek 	/* If we're in the INIT-REBOOT or REQUESTING state and we're
2100*83ee113eSDavid van Moolenbroek 	   past the reboot timeout, go to INIT and see if we can
2101*83ee113eSDavid van Moolenbroek 	   DISCOVER an address... */
2102*83ee113eSDavid van Moolenbroek 	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
2103*83ee113eSDavid van Moolenbroek 	   means either that we're on a network with no DHCP server,
2104*83ee113eSDavid van Moolenbroek 	   or that our server is down.  In the latter case, assuming
2105*83ee113eSDavid van Moolenbroek 	   that there is a backup DHCP server, DHCPDISCOVER will get
2106*83ee113eSDavid van Moolenbroek 	   us a new address, but we could also have successfully
2107*83ee113eSDavid van Moolenbroek 	   reused our old address.  In the former case, we're hosed
2108*83ee113eSDavid van Moolenbroek 	   anyway.  This is not a win-prone situation. */
2109*83ee113eSDavid van Moolenbroek 	if ((client -> state == S_REBOOTING ||
2110*83ee113eSDavid van Moolenbroek 	     client -> state == S_REQUESTING) &&
2111*83ee113eSDavid van Moolenbroek 	    interval > client -> config -> reboot_timeout) {
2112*83ee113eSDavid van Moolenbroek 	cancel:
2113*83ee113eSDavid van Moolenbroek 		client -> state = S_INIT;
2114*83ee113eSDavid van Moolenbroek 		cancel_timeout (send_request, client);
2115*83ee113eSDavid van Moolenbroek 		state_init (client);
2116*83ee113eSDavid van Moolenbroek 		return;
2117*83ee113eSDavid van Moolenbroek 	}
2118*83ee113eSDavid van Moolenbroek 
2119*83ee113eSDavid van Moolenbroek 	/* If we're in the reboot state, make sure the media is set up
2120*83ee113eSDavid van Moolenbroek 	   correctly. */
2121*83ee113eSDavid van Moolenbroek 	if (client -> state == S_REBOOTING &&
2122*83ee113eSDavid van Moolenbroek 	    !client -> medium &&
2123*83ee113eSDavid van Moolenbroek 	    client -> active -> medium ) {
2124*83ee113eSDavid van Moolenbroek 		script_init (client, "MEDIUM", client -> active -> medium);
2125*83ee113eSDavid van Moolenbroek 
2126*83ee113eSDavid van Moolenbroek 		/* If the medium we chose won't fly, go to INIT state. */
2127*83ee113eSDavid van Moolenbroek 		if (script_go (client))
2128*83ee113eSDavid van Moolenbroek 			goto cancel;
2129*83ee113eSDavid van Moolenbroek 
2130*83ee113eSDavid van Moolenbroek 		/* Record the medium. */
2131*83ee113eSDavid van Moolenbroek 		client -> medium = client -> active -> medium;
2132*83ee113eSDavid van Moolenbroek 	}
2133*83ee113eSDavid van Moolenbroek 
2134*83ee113eSDavid van Moolenbroek 	/* If the lease has expired, relinquish the address and go back
2135*83ee113eSDavid van Moolenbroek 	   to the INIT state. */
2136*83ee113eSDavid van Moolenbroek 	if (client -> state != S_REQUESTING &&
2137*83ee113eSDavid van Moolenbroek 	    cur_time > client -> active -> expiry) {
2138*83ee113eSDavid van Moolenbroek 		/* Run the client script with the new parameters. */
2139*83ee113eSDavid van Moolenbroek 		script_init (client, "EXPIRE", (struct string_list *)0);
2140*83ee113eSDavid van Moolenbroek 		script_write_params (client, "old_", client -> active);
2141*83ee113eSDavid van Moolenbroek 		script_write_requested(client);
2142*83ee113eSDavid van Moolenbroek 		if (client -> alias)
2143*83ee113eSDavid van Moolenbroek 			script_write_params (client, "alias_",
2144*83ee113eSDavid van Moolenbroek 					     client -> alias);
2145*83ee113eSDavid van Moolenbroek 		script_go (client);
2146*83ee113eSDavid van Moolenbroek 
2147*83ee113eSDavid van Moolenbroek 		/* Now do a preinit on the interface so that we can
2148*83ee113eSDavid van Moolenbroek 		   discover a new address. */
2149*83ee113eSDavid van Moolenbroek 		script_init (client, "PREINIT", (struct string_list *)0);
2150*83ee113eSDavid van Moolenbroek 		if (client -> alias)
2151*83ee113eSDavid van Moolenbroek 			script_write_params (client, "alias_",
2152*83ee113eSDavid van Moolenbroek 					     client -> alias);
2153*83ee113eSDavid van Moolenbroek 		script_go (client);
2154*83ee113eSDavid van Moolenbroek 
2155*83ee113eSDavid van Moolenbroek 		client -> state = S_INIT;
2156*83ee113eSDavid van Moolenbroek 		state_init (client);
2157*83ee113eSDavid van Moolenbroek 		return;
2158*83ee113eSDavid van Moolenbroek 	}
2159*83ee113eSDavid van Moolenbroek 
2160*83ee113eSDavid van Moolenbroek 	/* Do the exponential backoff... */
2161*83ee113eSDavid van Moolenbroek 	if (!client -> interval)
2162*83ee113eSDavid van Moolenbroek 		client -> interval = client -> config -> initial_interval;
2163*83ee113eSDavid van Moolenbroek 	else {
2164*83ee113eSDavid van Moolenbroek 		client -> interval += ((random () >> 2) %
2165*83ee113eSDavid van Moolenbroek 				       (2 * client -> interval));
2166*83ee113eSDavid van Moolenbroek 	}
2167*83ee113eSDavid van Moolenbroek 
2168*83ee113eSDavid van Moolenbroek 	/* Don't backoff past cutoff. */
2169*83ee113eSDavid van Moolenbroek 	if (client -> interval >
2170*83ee113eSDavid van Moolenbroek 	    client -> config -> backoff_cutoff)
2171*83ee113eSDavid van Moolenbroek 		client -> interval =
2172*83ee113eSDavid van Moolenbroek 			((client -> config -> backoff_cutoff / 2)
2173*83ee113eSDavid van Moolenbroek 			 + ((random () >> 2) %
2174*83ee113eSDavid van Moolenbroek 					client -> config -> backoff_cutoff));
2175*83ee113eSDavid van Moolenbroek 
2176*83ee113eSDavid van Moolenbroek 	/* If the backoff would take us to the expiry time, just set the
2177*83ee113eSDavid van Moolenbroek 	   timeout to the expiry time. */
2178*83ee113eSDavid van Moolenbroek 	if (client -> state != S_REQUESTING &&
2179*83ee113eSDavid van Moolenbroek 	    cur_time + client -> interval > client -> active -> expiry)
2180*83ee113eSDavid van Moolenbroek 		client -> interval =
2181*83ee113eSDavid van Moolenbroek 			client -> active -> expiry - cur_time + 1;
2182*83ee113eSDavid van Moolenbroek 
2183*83ee113eSDavid van Moolenbroek 	/* If the lease T2 time has elapsed, or if we're not yet bound,
2184*83ee113eSDavid van Moolenbroek 	   broadcast the DHCPREQUEST rather than unicasting. */
2185*83ee113eSDavid van Moolenbroek 	if (client -> state == S_REQUESTING ||
2186*83ee113eSDavid van Moolenbroek 	    client -> state == S_REBOOTING ||
2187*83ee113eSDavid van Moolenbroek 	    cur_time > client -> active -> rebind)
2188*83ee113eSDavid van Moolenbroek 		destination.sin_addr = sockaddr_broadcast.sin_addr;
2189*83ee113eSDavid van Moolenbroek 	else
2190*83ee113eSDavid van Moolenbroek 		memcpy (&destination.sin_addr.s_addr,
2191*83ee113eSDavid van Moolenbroek 			client -> destination.iabuf,
2192*83ee113eSDavid van Moolenbroek 			sizeof destination.sin_addr.s_addr);
2193*83ee113eSDavid van Moolenbroek 	destination.sin_port = remote_port;
2194*83ee113eSDavid van Moolenbroek 	destination.sin_family = AF_INET;
2195*83ee113eSDavid van Moolenbroek #ifdef HAVE_SA_LEN
2196*83ee113eSDavid van Moolenbroek 	destination.sin_len = sizeof destination;
2197*83ee113eSDavid van Moolenbroek #endif
2198*83ee113eSDavid van Moolenbroek 
2199*83ee113eSDavid van Moolenbroek 	if (client -> state == S_RENEWING ||
2200*83ee113eSDavid van Moolenbroek 	    client -> state == S_REBINDING)
2201*83ee113eSDavid van Moolenbroek 		memcpy (&from, client -> active -> address.iabuf,
2202*83ee113eSDavid van Moolenbroek 			sizeof from);
2203*83ee113eSDavid van Moolenbroek 	else
2204*83ee113eSDavid van Moolenbroek 		from.s_addr = INADDR_ANY;
2205*83ee113eSDavid van Moolenbroek 
2206*83ee113eSDavid van Moolenbroek 	/* Record the number of seconds since we started sending. */
2207*83ee113eSDavid van Moolenbroek 	if (client -> state == S_REQUESTING)
2208*83ee113eSDavid van Moolenbroek 		client -> packet.secs = client -> secs;
2209*83ee113eSDavid van Moolenbroek 	else {
2210*83ee113eSDavid van Moolenbroek 		if (interval < 65536)
2211*83ee113eSDavid van Moolenbroek 			client -> packet.secs = htons (interval);
2212*83ee113eSDavid van Moolenbroek 		else
2213*83ee113eSDavid van Moolenbroek 			client -> packet.secs = htons (65535);
2214*83ee113eSDavid van Moolenbroek 	}
2215*83ee113eSDavid van Moolenbroek 
2216*83ee113eSDavid van Moolenbroek 	log_info ("DHCPREQUEST on %s to %s port %d",
2217*83ee113eSDavid van Moolenbroek 	      client -> name ? client -> name : client -> interface -> name,
2218*83ee113eSDavid van Moolenbroek 	      inet_ntoa (destination.sin_addr),
2219*83ee113eSDavid van Moolenbroek 	      ntohs (destination.sin_port));
2220*83ee113eSDavid van Moolenbroek 
2221*83ee113eSDavid van Moolenbroek 	if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
2222*83ee113eSDavid van Moolenbroek 	    fallback_interface) {
2223*83ee113eSDavid van Moolenbroek 		result = send_packet(fallback_interface, NULL, &client->packet,
2224*83ee113eSDavid van Moolenbroek 				     client->packet_length, from, &destination,
2225*83ee113eSDavid van Moolenbroek 				     NULL);
2226*83ee113eSDavid van Moolenbroek 		if (result < 0) {
2227*83ee113eSDavid van Moolenbroek 			log_error("%s:%d: Failed to send %d byte long packet "
2228*83ee113eSDavid van Moolenbroek 				  "over %s interface.", MDL,
2229*83ee113eSDavid van Moolenbroek 				  client->packet_length,
2230*83ee113eSDavid van Moolenbroek 				  fallback_interface->name);
2231*83ee113eSDavid van Moolenbroek 		}
2232*83ee113eSDavid van Moolenbroek         }
2233*83ee113eSDavid van Moolenbroek 	else {
2234*83ee113eSDavid van Moolenbroek 		/* Send out a packet. */
2235*83ee113eSDavid van Moolenbroek 		result = send_packet(client->interface, NULL, &client->packet,
2236*83ee113eSDavid van Moolenbroek 				     client->packet_length, from, &destination,
2237*83ee113eSDavid van Moolenbroek 				     NULL);
2238*83ee113eSDavid van Moolenbroek 		if (result < 0) {
2239*83ee113eSDavid van Moolenbroek 			log_error("%s:%d: Failed to send %d byte long packet"
2240*83ee113eSDavid van Moolenbroek 				  " over %s interface.", MDL,
2241*83ee113eSDavid van Moolenbroek 				  client->packet_length,
2242*83ee113eSDavid van Moolenbroek 				  client->interface->name);
2243*83ee113eSDavid van Moolenbroek 		}
2244*83ee113eSDavid van Moolenbroek         }
2245*83ee113eSDavid van Moolenbroek 
2246*83ee113eSDavid van Moolenbroek 	tv.tv_sec = cur_tv.tv_sec + client->interval;
2247*83ee113eSDavid van Moolenbroek 	tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ?
2248*83ee113eSDavid van Moolenbroek 			random() % 1000000 : cur_tv.tv_usec;
2249*83ee113eSDavid van Moolenbroek 	add_timeout(&tv, send_request, client, 0, 0);
2250*83ee113eSDavid van Moolenbroek }
2251*83ee113eSDavid van Moolenbroek 
send_decline(cpp)2252*83ee113eSDavid van Moolenbroek void send_decline (cpp)
2253*83ee113eSDavid van Moolenbroek 	void *cpp;
2254*83ee113eSDavid van Moolenbroek {
2255*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
2256*83ee113eSDavid van Moolenbroek 
2257*83ee113eSDavid van Moolenbroek 	int result;
2258*83ee113eSDavid van Moolenbroek 
2259*83ee113eSDavid van Moolenbroek 	log_info ("DHCPDECLINE on %s to %s port %d",
2260*83ee113eSDavid van Moolenbroek 	      client->name ? client->name : client->interface->name,
2261*83ee113eSDavid van Moolenbroek 	      inet_ntoa(sockaddr_broadcast.sin_addr),
2262*83ee113eSDavid van Moolenbroek 	      ntohs(sockaddr_broadcast.sin_port));
2263*83ee113eSDavid van Moolenbroek 
2264*83ee113eSDavid van Moolenbroek 	/* Send out a packet. */
2265*83ee113eSDavid van Moolenbroek 	result = send_packet(client->interface, NULL, &client->packet,
2266*83ee113eSDavid van Moolenbroek 			     client->packet_length, inaddr_any,
2267*83ee113eSDavid van Moolenbroek 			     &sockaddr_broadcast, NULL);
2268*83ee113eSDavid van Moolenbroek 	if (result < 0) {
2269*83ee113eSDavid van Moolenbroek 		log_error("%s:%d: Failed to send %d byte long packet over %s"
2270*83ee113eSDavid van Moolenbroek 			  " interface.", MDL, client->packet_length,
2271*83ee113eSDavid van Moolenbroek 			  client->interface->name);
2272*83ee113eSDavid van Moolenbroek 	}
2273*83ee113eSDavid van Moolenbroek }
2274*83ee113eSDavid van Moolenbroek 
send_release(cpp)2275*83ee113eSDavid van Moolenbroek void send_release (cpp)
2276*83ee113eSDavid van Moolenbroek 	void *cpp;
2277*83ee113eSDavid van Moolenbroek {
2278*83ee113eSDavid van Moolenbroek 	struct client_state *client = cpp;
2279*83ee113eSDavid van Moolenbroek 
2280*83ee113eSDavid van Moolenbroek 	int result;
2281*83ee113eSDavid van Moolenbroek 	struct sockaddr_in destination;
2282*83ee113eSDavid van Moolenbroek 	struct in_addr from;
2283*83ee113eSDavid van Moolenbroek 
2284*83ee113eSDavid van Moolenbroek 	memcpy (&from, client -> active -> address.iabuf,
2285*83ee113eSDavid van Moolenbroek 		sizeof from);
2286*83ee113eSDavid van Moolenbroek 	memcpy (&destination.sin_addr.s_addr,
2287*83ee113eSDavid van Moolenbroek 		client -> destination.iabuf,
2288*83ee113eSDavid van Moolenbroek 		sizeof destination.sin_addr.s_addr);
2289*83ee113eSDavid van Moolenbroek 	destination.sin_port = remote_port;
2290*83ee113eSDavid van Moolenbroek 	destination.sin_family = AF_INET;
2291*83ee113eSDavid van Moolenbroek #ifdef HAVE_SA_LEN
2292*83ee113eSDavid van Moolenbroek 	destination.sin_len = sizeof destination;
2293*83ee113eSDavid van Moolenbroek #endif
2294*83ee113eSDavid van Moolenbroek 
2295*83ee113eSDavid van Moolenbroek 	/* Set the lease to end now, so that we don't accidentally
2296*83ee113eSDavid van Moolenbroek 	   reuse it if we restart before the old expiry time. */
2297*83ee113eSDavid van Moolenbroek 	client -> active -> expiry =
2298*83ee113eSDavid van Moolenbroek 		client -> active -> renewal =
2299*83ee113eSDavid van Moolenbroek 		client -> active -> rebind = cur_time;
2300*83ee113eSDavid van Moolenbroek 	if (!write_client_lease (client, client -> active, 1, 1)) {
2301*83ee113eSDavid van Moolenbroek 		log_error ("Can't release lease: lease write failed.");
2302*83ee113eSDavid van Moolenbroek 		return;
2303*83ee113eSDavid van Moolenbroek 	}
2304*83ee113eSDavid van Moolenbroek 
2305*83ee113eSDavid van Moolenbroek 	log_info ("DHCPRELEASE on %s to %s port %d",
2306*83ee113eSDavid van Moolenbroek 	      client -> name ? client -> name : client -> interface -> name,
2307*83ee113eSDavid van Moolenbroek 	      inet_ntoa (destination.sin_addr),
2308*83ee113eSDavid van Moolenbroek 	      ntohs (destination.sin_port));
2309*83ee113eSDavid van Moolenbroek 
2310*83ee113eSDavid van Moolenbroek 	if (fallback_interface) {
2311*83ee113eSDavid van Moolenbroek 		result = send_packet(fallback_interface, NULL, &client->packet,
2312*83ee113eSDavid van Moolenbroek 				      client->packet_length, from, &destination,
2313*83ee113eSDavid van Moolenbroek 				      NULL);
2314*83ee113eSDavid van Moolenbroek 		if (result < 0) {
2315*83ee113eSDavid van Moolenbroek 			log_error("%s:%d: Failed to send %d byte long packet"
2316*83ee113eSDavid van Moolenbroek 				  " over %s interface.", MDL,
2317*83ee113eSDavid van Moolenbroek 				  client->packet_length,
2318*83ee113eSDavid van Moolenbroek 				  fallback_interface->name);
2319*83ee113eSDavid van Moolenbroek 		}
2320*83ee113eSDavid van Moolenbroek         } else {
2321*83ee113eSDavid van Moolenbroek 		/* Send out a packet. */
2322*83ee113eSDavid van Moolenbroek 		result = send_packet(client->interface, NULL, &client->packet,
2323*83ee113eSDavid van Moolenbroek 				      client->packet_length, from, &destination,
2324*83ee113eSDavid van Moolenbroek 				      NULL);
2325*83ee113eSDavid van Moolenbroek 		if (result < 0) {
2326*83ee113eSDavid van Moolenbroek 			log_error ("%s:%d: Failed to send %d byte long packet"
2327*83ee113eSDavid van Moolenbroek 				   " over %s interface.", MDL,
2328*83ee113eSDavid van Moolenbroek 				   client->packet_length,
2329*83ee113eSDavid van Moolenbroek 				   client->interface->name);
2330*83ee113eSDavid van Moolenbroek 		}
2331*83ee113eSDavid van Moolenbroek 
2332*83ee113eSDavid van Moolenbroek         }
2333*83ee113eSDavid van Moolenbroek }
2334*83ee113eSDavid van Moolenbroek 
2335*83ee113eSDavid van Moolenbroek void
make_client_options(struct client_state * client,struct client_lease * lease,u_int8_t * type,struct option_cache * sid,struct iaddr * rip,struct option ** prl,struct option_state ** op)2336*83ee113eSDavid van Moolenbroek make_client_options(struct client_state *client, struct client_lease *lease,
2337*83ee113eSDavid van Moolenbroek 		    u_int8_t *type, struct option_cache *sid,
2338*83ee113eSDavid van Moolenbroek 		    struct iaddr *rip, struct option **prl,
2339*83ee113eSDavid van Moolenbroek 		    struct option_state **op)
2340*83ee113eSDavid van Moolenbroek {
2341*83ee113eSDavid van Moolenbroek 	unsigned i;
2342*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
2343*83ee113eSDavid van Moolenbroek 	struct option *option = NULL;
2344*83ee113eSDavid van Moolenbroek 	struct buffer *bp = NULL;
2345*83ee113eSDavid van Moolenbroek 
2346*83ee113eSDavid van Moolenbroek 	/* If there are any leftover options, get rid of them. */
2347*83ee113eSDavid van Moolenbroek 	if (*op)
2348*83ee113eSDavid van Moolenbroek 		option_state_dereference(op, MDL);
2349*83ee113eSDavid van Moolenbroek 
2350*83ee113eSDavid van Moolenbroek 	/* Allocate space for options. */
2351*83ee113eSDavid van Moolenbroek 	option_state_allocate(op, MDL);
2352*83ee113eSDavid van Moolenbroek 
2353*83ee113eSDavid van Moolenbroek 	/* Send the server identifier if provided. */
2354*83ee113eSDavid van Moolenbroek 	if (sid)
2355*83ee113eSDavid van Moolenbroek 		save_option(&dhcp_universe, *op, sid);
2356*83ee113eSDavid van Moolenbroek 
2357*83ee113eSDavid van Moolenbroek 	oc = NULL;
2358*83ee113eSDavid van Moolenbroek 
2359*83ee113eSDavid van Moolenbroek 	/* Send the requested address if provided. */
2360*83ee113eSDavid van Moolenbroek 	if (rip) {
2361*83ee113eSDavid van Moolenbroek 		client->requested_address = *rip;
2362*83ee113eSDavid van Moolenbroek 		i = DHO_DHCP_REQUESTED_ADDRESS;
2363*83ee113eSDavid van Moolenbroek 		if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash,
2364*83ee113eSDavid van Moolenbroek 					      &i, 0, MDL) &&
2365*83ee113eSDavid van Moolenbroek 		      make_const_option_cache(&oc, NULL, rip->iabuf, rip->len,
2366*83ee113eSDavid van Moolenbroek 					      option, MDL)))
2367*83ee113eSDavid van Moolenbroek 			log_error ("can't make requested address cache.");
2368*83ee113eSDavid van Moolenbroek 		else {
2369*83ee113eSDavid van Moolenbroek 			save_option(&dhcp_universe, *op, oc);
2370*83ee113eSDavid van Moolenbroek 			option_cache_dereference(&oc, MDL);
2371*83ee113eSDavid van Moolenbroek 		}
2372*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2373*83ee113eSDavid van Moolenbroek 	} else {
2374*83ee113eSDavid van Moolenbroek 		client->requested_address.len = 0;
2375*83ee113eSDavid van Moolenbroek 	}
2376*83ee113eSDavid van Moolenbroek 
2377*83ee113eSDavid van Moolenbroek 	i = DHO_DHCP_MESSAGE_TYPE;
2378*83ee113eSDavid van Moolenbroek 	if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0,
2379*83ee113eSDavid van Moolenbroek 				      MDL) &&
2380*83ee113eSDavid van Moolenbroek 	      make_const_option_cache(&oc, NULL, type, 1, option, MDL)))
2381*83ee113eSDavid van Moolenbroek 		log_error("can't make message type.");
2382*83ee113eSDavid van Moolenbroek 	else {
2383*83ee113eSDavid van Moolenbroek 		save_option(&dhcp_universe, *op, oc);
2384*83ee113eSDavid van Moolenbroek 		option_cache_dereference(&oc, MDL);
2385*83ee113eSDavid van Moolenbroek 	}
2386*83ee113eSDavid van Moolenbroek 	option_dereference(&option, MDL);
2387*83ee113eSDavid van Moolenbroek 
2388*83ee113eSDavid van Moolenbroek 	if (prl) {
2389*83ee113eSDavid van Moolenbroek 		int len;
2390*83ee113eSDavid van Moolenbroek 
2391*83ee113eSDavid van Moolenbroek 		/* Probe the length of the list. */
2392*83ee113eSDavid van Moolenbroek 		len = 0;
2393*83ee113eSDavid van Moolenbroek 		for (i = 0 ; prl[i] != NULL ; i++)
2394*83ee113eSDavid van Moolenbroek 			if (prl[i]->universe == &dhcp_universe)
2395*83ee113eSDavid van Moolenbroek 				len++;
2396*83ee113eSDavid van Moolenbroek 
2397*83ee113eSDavid van Moolenbroek 		if (!buffer_allocate(&bp, len, MDL))
2398*83ee113eSDavid van Moolenbroek 			log_error("can't make parameter list buffer.");
2399*83ee113eSDavid van Moolenbroek 		else {
2400*83ee113eSDavid van Moolenbroek 			unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST;
2401*83ee113eSDavid van Moolenbroek 
2402*83ee113eSDavid van Moolenbroek 			len = 0;
2403*83ee113eSDavid van Moolenbroek 			for (i = 0 ; prl[i] != NULL ; i++)
2404*83ee113eSDavid van Moolenbroek 				if (prl[i]->universe == &dhcp_universe)
2405*83ee113eSDavid van Moolenbroek 					bp->data[len++] = prl[i]->code;
2406*83ee113eSDavid van Moolenbroek 
2407*83ee113eSDavid van Moolenbroek 			if (!(option_code_hash_lookup(&option,
2408*83ee113eSDavid van Moolenbroek 						      dhcp_universe.code_hash,
2409*83ee113eSDavid van Moolenbroek 						      &code, 0, MDL) &&
2410*83ee113eSDavid van Moolenbroek 			      make_const_option_cache(&oc, &bp, NULL, len,
2411*83ee113eSDavid van Moolenbroek 						      option, MDL)))
2412*83ee113eSDavid van Moolenbroek 				log_error("can't make option cache");
2413*83ee113eSDavid van Moolenbroek 			else {
2414*83ee113eSDavid van Moolenbroek 				save_option(&dhcp_universe, *op, oc);
2415*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
2416*83ee113eSDavid van Moolenbroek 			}
2417*83ee113eSDavid van Moolenbroek 			option_dereference(&option, MDL);
2418*83ee113eSDavid van Moolenbroek 		}
2419*83ee113eSDavid van Moolenbroek 	}
2420*83ee113eSDavid van Moolenbroek 
2421*83ee113eSDavid van Moolenbroek 	/*
2422*83ee113eSDavid van Moolenbroek 	 * If requested (duid_v4 == 1) add an RFC4361 compliant client-identifier
2423*83ee113eSDavid van Moolenbroek 	 * This can be overridden by including a client id in the configuration
2424*83ee113eSDavid van Moolenbroek 	 * file.
2425*83ee113eSDavid van Moolenbroek 	 */
2426*83ee113eSDavid van Moolenbroek  	if (duid_v4 == 1) {
2427*83ee113eSDavid van Moolenbroek 		struct data_string client_identifier;
2428*83ee113eSDavid van Moolenbroek 		int hw_idx, hw_len;
2429*83ee113eSDavid van Moolenbroek 
2430*83ee113eSDavid van Moolenbroek 		memset(&client_identifier, 0, sizeof(client_identifier));
2431*83ee113eSDavid van Moolenbroek 		client_identifier.len = 1 + 4 + default_duid.len;
2432*83ee113eSDavid van Moolenbroek 		if (!buffer_allocate(&client_identifier.buffer,
2433*83ee113eSDavid van Moolenbroek 				     client_identifier.len, MDL))
2434*83ee113eSDavid van Moolenbroek 			log_fatal("no memory for default DUID!");
2435*83ee113eSDavid van Moolenbroek 		client_identifier.data = client_identifier.buffer->data;
2436*83ee113eSDavid van Moolenbroek 
2437*83ee113eSDavid van Moolenbroek 		i = DHO_DHCP_CLIENT_IDENTIFIER;
2438*83ee113eSDavid van Moolenbroek 
2439*83ee113eSDavid van Moolenbroek 		/* Client-identifier type : 1 byte */
2440*83ee113eSDavid van Moolenbroek 		*client_identifier.buffer->data = 255;
2441*83ee113eSDavid van Moolenbroek 
2442*83ee113eSDavid van Moolenbroek 		/* IAID : 4 bytes
2443*83ee113eSDavid van Moolenbroek 		 * we use the low 4 bytes from the interface address
2444*83ee113eSDavid van Moolenbroek 		 */
2445*83ee113eSDavid van Moolenbroek 		if (client->interface->hw_address.hlen > 4) {
2446*83ee113eSDavid van Moolenbroek 			hw_idx = client->interface->hw_address.hlen - 4;
2447*83ee113eSDavid van Moolenbroek 			hw_len = 4;
2448*83ee113eSDavid van Moolenbroek 		} else {
2449*83ee113eSDavid van Moolenbroek 			hw_idx = 0;
2450*83ee113eSDavid van Moolenbroek 			hw_len = client->interface->hw_address.hlen;
2451*83ee113eSDavid van Moolenbroek 		}
2452*83ee113eSDavid van Moolenbroek 		memcpy(&client_identifier.buffer->data + 5 - hw_len,
2453*83ee113eSDavid van Moolenbroek 		       client->interface->hw_address.hbuf + hw_idx,
2454*83ee113eSDavid van Moolenbroek 		       hw_len);
2455*83ee113eSDavid van Moolenbroek 
2456*83ee113eSDavid van Moolenbroek 		/* Add the default duid */
2457*83ee113eSDavid van Moolenbroek 		memcpy(&client_identifier.buffer->data+(1+4),
2458*83ee113eSDavid van Moolenbroek 		       default_duid.data, default_duid.len);
2459*83ee113eSDavid van Moolenbroek 
2460*83ee113eSDavid van Moolenbroek 		/* And save the option */
2461*83ee113eSDavid van Moolenbroek 		if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash,
2462*83ee113eSDavid van Moolenbroek 					      &i, 0, MDL) &&
2463*83ee113eSDavid van Moolenbroek 		      make_const_option_cache(&oc, NULL,
2464*83ee113eSDavid van Moolenbroek 					      (u_int8_t *)client_identifier.data,
2465*83ee113eSDavid van Moolenbroek 					      client_identifier.len,
2466*83ee113eSDavid van Moolenbroek 					      option, MDL)))
2467*83ee113eSDavid van Moolenbroek 			log_error ("can't make requested client id cache..");
2468*83ee113eSDavid van Moolenbroek 		else {
2469*83ee113eSDavid van Moolenbroek 			save_option (&dhcp_universe, *op, oc);
2470*83ee113eSDavid van Moolenbroek 			option_cache_dereference (&oc, MDL);
2471*83ee113eSDavid van Moolenbroek 		}
2472*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2473*83ee113eSDavid van Moolenbroek 	}
2474*83ee113eSDavid van Moolenbroek 
2475*83ee113eSDavid van Moolenbroek 	/* Run statements that need to be run on transmission. */
2476*83ee113eSDavid van Moolenbroek 	if (client->config->on_transmission)
2477*83ee113eSDavid van Moolenbroek 		execute_statements_in_scope(NULL, NULL, NULL, client,
2478*83ee113eSDavid van Moolenbroek 					    (lease ? lease->options : NULL),
2479*83ee113eSDavid van Moolenbroek 					    *op, &global_scope,
2480*83ee113eSDavid van Moolenbroek 					    client->config->on_transmission,
2481*83ee113eSDavid van Moolenbroek 					    NULL, NULL);
2482*83ee113eSDavid van Moolenbroek }
2483*83ee113eSDavid van Moolenbroek 
make_discover(client,lease)2484*83ee113eSDavid van Moolenbroek void make_discover (client, lease)
2485*83ee113eSDavid van Moolenbroek 	struct client_state *client;
2486*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
2487*83ee113eSDavid van Moolenbroek {
2488*83ee113eSDavid van Moolenbroek 	unsigned char discover = DHCPDISCOVER;
2489*83ee113eSDavid van Moolenbroek 	struct option_state *options = (struct option_state *)0;
2490*83ee113eSDavid van Moolenbroek 
2491*83ee113eSDavid van Moolenbroek 	memset (&client -> packet, 0, sizeof (client -> packet));
2492*83ee113eSDavid van Moolenbroek 
2493*83ee113eSDavid van Moolenbroek 	make_client_options (client,
2494*83ee113eSDavid van Moolenbroek 			     lease, &discover, (struct option_cache *)0,
2495*83ee113eSDavid van Moolenbroek 			     lease ? &lease -> address : (struct iaddr *)0,
2496*83ee113eSDavid van Moolenbroek 			     client -> config -> requested_options,
2497*83ee113eSDavid van Moolenbroek 			     &options);
2498*83ee113eSDavid van Moolenbroek 
2499*83ee113eSDavid van Moolenbroek 	/* Set up the option buffer... */
2500*83ee113eSDavid van Moolenbroek 	client -> packet_length =
2501*83ee113eSDavid van Moolenbroek 		cons_options ((struct packet *)0, &client -> packet,
2502*83ee113eSDavid van Moolenbroek 			      (struct lease *)0, client,
2503*83ee113eSDavid van Moolenbroek 			      /* maximum packet size */1500,
2504*83ee113eSDavid van Moolenbroek 			      (struct option_state *)0,
2505*83ee113eSDavid van Moolenbroek 			      options,
2506*83ee113eSDavid van Moolenbroek 			      /* scope */ &global_scope,
2507*83ee113eSDavid van Moolenbroek 			      /* overload */ 0,
2508*83ee113eSDavid van Moolenbroek 			      /* terminate */0,
2509*83ee113eSDavid van Moolenbroek 			      /* bootpp    */0,
2510*83ee113eSDavid van Moolenbroek 			      (struct data_string *)0,
2511*83ee113eSDavid van Moolenbroek 			      client -> config -> vendor_space_name);
2512*83ee113eSDavid van Moolenbroek 
2513*83ee113eSDavid van Moolenbroek 	option_state_dereference (&options, MDL);
2514*83ee113eSDavid van Moolenbroek 	if (client -> packet_length < BOOTP_MIN_LEN)
2515*83ee113eSDavid van Moolenbroek 		client -> packet_length = BOOTP_MIN_LEN;
2516*83ee113eSDavid van Moolenbroek 
2517*83ee113eSDavid van Moolenbroek 	client -> packet.op = BOOTREQUEST;
2518*83ee113eSDavid van Moolenbroek 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2519*83ee113eSDavid van Moolenbroek 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2520*83ee113eSDavid van Moolenbroek 	client -> packet.hops = 0;
2521*83ee113eSDavid van Moolenbroek 	client -> packet.xid = random ();
2522*83ee113eSDavid van Moolenbroek 	client -> packet.secs = 0; /* filled in by send_discover. */
2523*83ee113eSDavid van Moolenbroek 
2524*83ee113eSDavid van Moolenbroek 	if (can_receive_unicast_unconfigured (client -> interface))
2525*83ee113eSDavid van Moolenbroek 		client -> packet.flags = 0;
2526*83ee113eSDavid van Moolenbroek 	else
2527*83ee113eSDavid van Moolenbroek 		client -> packet.flags = htons (BOOTP_BROADCAST);
2528*83ee113eSDavid van Moolenbroek 
2529*83ee113eSDavid van Moolenbroek 	memset (&(client -> packet.ciaddr),
2530*83ee113eSDavid van Moolenbroek 		0, sizeof client -> packet.ciaddr);
2531*83ee113eSDavid van Moolenbroek 	memset (&(client -> packet.yiaddr),
2532*83ee113eSDavid van Moolenbroek 		0, sizeof client -> packet.yiaddr);
2533*83ee113eSDavid van Moolenbroek 	memset (&(client -> packet.siaddr),
2534*83ee113eSDavid van Moolenbroek 		0, sizeof client -> packet.siaddr);
2535*83ee113eSDavid van Moolenbroek 	client -> packet.giaddr = giaddr;
2536*83ee113eSDavid van Moolenbroek 	if (client -> interface -> hw_address.hlen > 0)
2537*83ee113eSDavid van Moolenbroek 	    memcpy (client -> packet.chaddr,
2538*83ee113eSDavid van Moolenbroek 		    &client -> interface -> hw_address.hbuf [1],
2539*83ee113eSDavid van Moolenbroek 		    (unsigned)(client -> interface -> hw_address.hlen - 1));
2540*83ee113eSDavid van Moolenbroek 
2541*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PACKET
2542*83ee113eSDavid van Moolenbroek 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2543*83ee113eSDavid van Moolenbroek #endif
2544*83ee113eSDavid van Moolenbroek }
2545*83ee113eSDavid van Moolenbroek 
2546*83ee113eSDavid van Moolenbroek 
make_request(client,lease)2547*83ee113eSDavid van Moolenbroek void make_request (client, lease)
2548*83ee113eSDavid van Moolenbroek 	struct client_state *client;
2549*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
2550*83ee113eSDavid van Moolenbroek {
2551*83ee113eSDavid van Moolenbroek 	unsigned char request = DHCPREQUEST;
2552*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
2553*83ee113eSDavid van Moolenbroek 
2554*83ee113eSDavid van Moolenbroek 	memset (&client -> packet, 0, sizeof (client -> packet));
2555*83ee113eSDavid van Moolenbroek 
2556*83ee113eSDavid van Moolenbroek 	if (client -> state == S_REQUESTING)
2557*83ee113eSDavid van Moolenbroek 		oc = lookup_option (&dhcp_universe, lease -> options,
2558*83ee113eSDavid van Moolenbroek 				    DHO_DHCP_SERVER_IDENTIFIER);
2559*83ee113eSDavid van Moolenbroek 	else
2560*83ee113eSDavid van Moolenbroek 		oc = (struct option_cache *)0;
2561*83ee113eSDavid van Moolenbroek 
2562*83ee113eSDavid van Moolenbroek 	if (client -> sent_options)
2563*83ee113eSDavid van Moolenbroek 		option_state_dereference (&client -> sent_options, MDL);
2564*83ee113eSDavid van Moolenbroek 
2565*83ee113eSDavid van Moolenbroek 	make_client_options (client, lease, &request, oc,
2566*83ee113eSDavid van Moolenbroek 			     ((client -> state == S_REQUESTING ||
2567*83ee113eSDavid van Moolenbroek 			       client -> state == S_REBOOTING)
2568*83ee113eSDavid van Moolenbroek 			      ? &lease -> address
2569*83ee113eSDavid van Moolenbroek 			      : (struct iaddr *)0),
2570*83ee113eSDavid van Moolenbroek 			     client -> config -> requested_options,
2571*83ee113eSDavid van Moolenbroek 			     &client -> sent_options);
2572*83ee113eSDavid van Moolenbroek 
2573*83ee113eSDavid van Moolenbroek 	/* Set up the option buffer... */
2574*83ee113eSDavid van Moolenbroek 	client -> packet_length =
2575*83ee113eSDavid van Moolenbroek 		cons_options ((struct packet *)0, &client -> packet,
2576*83ee113eSDavid van Moolenbroek 			      (struct lease *)0, client,
2577*83ee113eSDavid van Moolenbroek 			      /* maximum packet size */1500,
2578*83ee113eSDavid van Moolenbroek 			      (struct option_state *)0,
2579*83ee113eSDavid van Moolenbroek 			      client -> sent_options,
2580*83ee113eSDavid van Moolenbroek 			      /* scope */ &global_scope,
2581*83ee113eSDavid van Moolenbroek 			      /* overload */ 0,
2582*83ee113eSDavid van Moolenbroek 			      /* terminate */0,
2583*83ee113eSDavid van Moolenbroek 			      /* bootpp    */0,
2584*83ee113eSDavid van Moolenbroek 			      (struct data_string *)0,
2585*83ee113eSDavid van Moolenbroek 			      client -> config -> vendor_space_name);
2586*83ee113eSDavid van Moolenbroek 
2587*83ee113eSDavid van Moolenbroek 	if (client -> packet_length < BOOTP_MIN_LEN)
2588*83ee113eSDavid van Moolenbroek 		client -> packet_length = BOOTP_MIN_LEN;
2589*83ee113eSDavid van Moolenbroek 
2590*83ee113eSDavid van Moolenbroek 	client -> packet.op = BOOTREQUEST;
2591*83ee113eSDavid van Moolenbroek 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2592*83ee113eSDavid van Moolenbroek 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2593*83ee113eSDavid van Moolenbroek 	client -> packet.hops = 0;
2594*83ee113eSDavid van Moolenbroek 	client -> packet.xid = client -> xid;
2595*83ee113eSDavid van Moolenbroek 	client -> packet.secs = 0; /* Filled in by send_request. */
2596*83ee113eSDavid van Moolenbroek 
2597*83ee113eSDavid van Moolenbroek 	/* If we own the address we're requesting, put it in ciaddr;
2598*83ee113eSDavid van Moolenbroek 	   otherwise set ciaddr to zero. */
2599*83ee113eSDavid van Moolenbroek 	if (client -> state == S_BOUND ||
2600*83ee113eSDavid van Moolenbroek 	    client -> state == S_RENEWING ||
2601*83ee113eSDavid van Moolenbroek 	    client -> state == S_REBINDING) {
2602*83ee113eSDavid van Moolenbroek 		memcpy (&client -> packet.ciaddr,
2603*83ee113eSDavid van Moolenbroek 			lease -> address.iabuf, lease -> address.len);
2604*83ee113eSDavid van Moolenbroek 		client -> packet.flags = 0;
2605*83ee113eSDavid van Moolenbroek 	} else {
2606*83ee113eSDavid van Moolenbroek 		memset (&client -> packet.ciaddr, 0,
2607*83ee113eSDavid van Moolenbroek 			sizeof client -> packet.ciaddr);
2608*83ee113eSDavid van Moolenbroek 		if (can_receive_unicast_unconfigured (client -> interface))
2609*83ee113eSDavid van Moolenbroek 			client -> packet.flags = 0;
2610*83ee113eSDavid van Moolenbroek 		else
2611*83ee113eSDavid van Moolenbroek 			client -> packet.flags = htons (BOOTP_BROADCAST);
2612*83ee113eSDavid van Moolenbroek 	}
2613*83ee113eSDavid van Moolenbroek 
2614*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.yiaddr, 0,
2615*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.yiaddr);
2616*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.siaddr, 0,
2617*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.siaddr);
2618*83ee113eSDavid van Moolenbroek 	if (client -> state != S_BOUND &&
2619*83ee113eSDavid van Moolenbroek 	    client -> state != S_RENEWING)
2620*83ee113eSDavid van Moolenbroek 		client -> packet.giaddr = giaddr;
2621*83ee113eSDavid van Moolenbroek 	else
2622*83ee113eSDavid van Moolenbroek 		memset (&client -> packet.giaddr, 0,
2623*83ee113eSDavid van Moolenbroek 			sizeof client -> packet.giaddr);
2624*83ee113eSDavid van Moolenbroek 	if (client -> interface -> hw_address.hlen > 0)
2625*83ee113eSDavid van Moolenbroek 	    memcpy (client -> packet.chaddr,
2626*83ee113eSDavid van Moolenbroek 		    &client -> interface -> hw_address.hbuf [1],
2627*83ee113eSDavid van Moolenbroek 		    (unsigned)(client -> interface -> hw_address.hlen - 1));
2628*83ee113eSDavid van Moolenbroek 
2629*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PACKET
2630*83ee113eSDavid van Moolenbroek 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2631*83ee113eSDavid van Moolenbroek #endif
2632*83ee113eSDavid van Moolenbroek }
2633*83ee113eSDavid van Moolenbroek 
make_decline(client,lease)2634*83ee113eSDavid van Moolenbroek void make_decline (client, lease)
2635*83ee113eSDavid van Moolenbroek 	struct client_state *client;
2636*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
2637*83ee113eSDavid van Moolenbroek {
2638*83ee113eSDavid van Moolenbroek 	unsigned char decline = DHCPDECLINE;
2639*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
2640*83ee113eSDavid van Moolenbroek 
2641*83ee113eSDavid van Moolenbroek 	struct option_state *options = (struct option_state *)0;
2642*83ee113eSDavid van Moolenbroek 
2643*83ee113eSDavid van Moolenbroek 	/* Create the options cache. */
2644*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, lease -> options,
2645*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_SERVER_IDENTIFIER);
2646*83ee113eSDavid van Moolenbroek 	make_client_options(client, lease, &decline, oc, &lease->address,
2647*83ee113eSDavid van Moolenbroek 			    NULL, &options);
2648*83ee113eSDavid van Moolenbroek 
2649*83ee113eSDavid van Moolenbroek 	/* Consume the options cache into the option buffer. */
2650*83ee113eSDavid van Moolenbroek 	memset (&client -> packet, 0, sizeof (client -> packet));
2651*83ee113eSDavid van Moolenbroek 	client -> packet_length =
2652*83ee113eSDavid van Moolenbroek 		cons_options ((struct packet *)0, &client -> packet,
2653*83ee113eSDavid van Moolenbroek 			      (struct lease *)0, client, 0,
2654*83ee113eSDavid van Moolenbroek 			      (struct option_state *)0, options,
2655*83ee113eSDavid van Moolenbroek 			      &global_scope, 0, 0, 0, (struct data_string *)0,
2656*83ee113eSDavid van Moolenbroek 			      client -> config -> vendor_space_name);
2657*83ee113eSDavid van Moolenbroek 
2658*83ee113eSDavid van Moolenbroek 	/* Destroy the options cache. */
2659*83ee113eSDavid van Moolenbroek 	option_state_dereference (&options, MDL);
2660*83ee113eSDavid van Moolenbroek 
2661*83ee113eSDavid van Moolenbroek 	if (client -> packet_length < BOOTP_MIN_LEN)
2662*83ee113eSDavid van Moolenbroek 		client -> packet_length = BOOTP_MIN_LEN;
2663*83ee113eSDavid van Moolenbroek 
2664*83ee113eSDavid van Moolenbroek 	client -> packet.op = BOOTREQUEST;
2665*83ee113eSDavid van Moolenbroek 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2666*83ee113eSDavid van Moolenbroek 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2667*83ee113eSDavid van Moolenbroek 	client -> packet.hops = 0;
2668*83ee113eSDavid van Moolenbroek 	client -> packet.xid = client -> xid;
2669*83ee113eSDavid van Moolenbroek 	client -> packet.secs = 0; /* Filled in by send_request. */
2670*83ee113eSDavid van Moolenbroek 	if (can_receive_unicast_unconfigured (client -> interface))
2671*83ee113eSDavid van Moolenbroek 		client -> packet.flags = 0;
2672*83ee113eSDavid van Moolenbroek 	else
2673*83ee113eSDavid van Moolenbroek 		client -> packet.flags = htons (BOOTP_BROADCAST);
2674*83ee113eSDavid van Moolenbroek 
2675*83ee113eSDavid van Moolenbroek 	/* ciaddr must always be zero. */
2676*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.ciaddr, 0,
2677*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.ciaddr);
2678*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.yiaddr, 0,
2679*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.yiaddr);
2680*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.siaddr, 0,
2681*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.siaddr);
2682*83ee113eSDavid van Moolenbroek 	client -> packet.giaddr = giaddr;
2683*83ee113eSDavid van Moolenbroek 	memcpy (client -> packet.chaddr,
2684*83ee113eSDavid van Moolenbroek 		&client -> interface -> hw_address.hbuf [1],
2685*83ee113eSDavid van Moolenbroek 		client -> interface -> hw_address.hlen);
2686*83ee113eSDavid van Moolenbroek 
2687*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PACKET
2688*83ee113eSDavid van Moolenbroek 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2689*83ee113eSDavid van Moolenbroek #endif
2690*83ee113eSDavid van Moolenbroek }
2691*83ee113eSDavid van Moolenbroek 
make_release(client,lease)2692*83ee113eSDavid van Moolenbroek void make_release (client, lease)
2693*83ee113eSDavid van Moolenbroek 	struct client_state *client;
2694*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
2695*83ee113eSDavid van Moolenbroek {
2696*83ee113eSDavid van Moolenbroek 	unsigned char request = DHCPRELEASE;
2697*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
2698*83ee113eSDavid van Moolenbroek 
2699*83ee113eSDavid van Moolenbroek 	struct option_state *options = (struct option_state *)0;
2700*83ee113eSDavid van Moolenbroek 
2701*83ee113eSDavid van Moolenbroek 	memset (&client -> packet, 0, sizeof (client -> packet));
2702*83ee113eSDavid van Moolenbroek 
2703*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, lease -> options,
2704*83ee113eSDavid van Moolenbroek 			    DHO_DHCP_SERVER_IDENTIFIER);
2705*83ee113eSDavid van Moolenbroek 	make_client_options(client, lease, &request, oc, NULL, NULL, &options);
2706*83ee113eSDavid van Moolenbroek 
2707*83ee113eSDavid van Moolenbroek 	/* Set up the option buffer... */
2708*83ee113eSDavid van Moolenbroek 	client -> packet_length =
2709*83ee113eSDavid van Moolenbroek 		cons_options ((struct packet *)0, &client -> packet,
2710*83ee113eSDavid van Moolenbroek 			      (struct lease *)0, client,
2711*83ee113eSDavid van Moolenbroek 			      /* maximum packet size */1500,
2712*83ee113eSDavid van Moolenbroek 			      (struct option_state *)0,
2713*83ee113eSDavid van Moolenbroek 			      options,
2714*83ee113eSDavid van Moolenbroek 			      /* scope */ &global_scope,
2715*83ee113eSDavid van Moolenbroek 			      /* overload */ 0,
2716*83ee113eSDavid van Moolenbroek 			      /* terminate */0,
2717*83ee113eSDavid van Moolenbroek 			      /* bootpp    */0,
2718*83ee113eSDavid van Moolenbroek 			      (struct data_string *)0,
2719*83ee113eSDavid van Moolenbroek 			      client -> config -> vendor_space_name);
2720*83ee113eSDavid van Moolenbroek 
2721*83ee113eSDavid van Moolenbroek 	if (client -> packet_length < BOOTP_MIN_LEN)
2722*83ee113eSDavid van Moolenbroek 		client -> packet_length = BOOTP_MIN_LEN;
2723*83ee113eSDavid van Moolenbroek 	option_state_dereference (&options, MDL);
2724*83ee113eSDavid van Moolenbroek 
2725*83ee113eSDavid van Moolenbroek 	client -> packet.op = BOOTREQUEST;
2726*83ee113eSDavid van Moolenbroek 	client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2727*83ee113eSDavid van Moolenbroek 	client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2728*83ee113eSDavid van Moolenbroek 	client -> packet.hops = 0;
2729*83ee113eSDavid van Moolenbroek 	client -> packet.xid = random ();
2730*83ee113eSDavid van Moolenbroek 	client -> packet.secs = 0;
2731*83ee113eSDavid van Moolenbroek 	client -> packet.flags = 0;
2732*83ee113eSDavid van Moolenbroek 	memcpy (&client -> packet.ciaddr,
2733*83ee113eSDavid van Moolenbroek 		lease -> address.iabuf, lease -> address.len);
2734*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.yiaddr, 0,
2735*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.yiaddr);
2736*83ee113eSDavid van Moolenbroek 	memset (&client -> packet.siaddr, 0,
2737*83ee113eSDavid van Moolenbroek 		sizeof client -> packet.siaddr);
2738*83ee113eSDavid van Moolenbroek 	client -> packet.giaddr = giaddr;
2739*83ee113eSDavid van Moolenbroek 	memcpy (client -> packet.chaddr,
2740*83ee113eSDavid van Moolenbroek 		&client -> interface -> hw_address.hbuf [1],
2741*83ee113eSDavid van Moolenbroek 		client -> interface -> hw_address.hlen);
2742*83ee113eSDavid van Moolenbroek 
2743*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PACKET
2744*83ee113eSDavid van Moolenbroek 	dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2745*83ee113eSDavid van Moolenbroek #endif
2746*83ee113eSDavid van Moolenbroek }
2747*83ee113eSDavid van Moolenbroek 
destroy_client_lease(lease)2748*83ee113eSDavid van Moolenbroek void destroy_client_lease (lease)
2749*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
2750*83ee113eSDavid van Moolenbroek {
2751*83ee113eSDavid van Moolenbroek 	if (lease -> server_name)
2752*83ee113eSDavid van Moolenbroek 		dfree (lease -> server_name, MDL);
2753*83ee113eSDavid van Moolenbroek 	if (lease -> filename)
2754*83ee113eSDavid van Moolenbroek 		dfree (lease -> filename, MDL);
2755*83ee113eSDavid van Moolenbroek 	option_state_dereference (&lease -> options, MDL);
2756*83ee113eSDavid van Moolenbroek 	free_client_lease (lease, MDL);
2757*83ee113eSDavid van Moolenbroek }
2758*83ee113eSDavid van Moolenbroek 
2759*83ee113eSDavid van Moolenbroek FILE *leaseFile = NULL;
2760*83ee113eSDavid van Moolenbroek int leases_written = 0;
2761*83ee113eSDavid van Moolenbroek 
rewrite_client_leases()2762*83ee113eSDavid van Moolenbroek void rewrite_client_leases ()
2763*83ee113eSDavid van Moolenbroek {
2764*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
2765*83ee113eSDavid van Moolenbroek 	struct client_state *client;
2766*83ee113eSDavid van Moolenbroek 	struct client_lease *lp;
2767*83ee113eSDavid van Moolenbroek 
2768*83ee113eSDavid van Moolenbroek 	if (leaseFile != NULL)
2769*83ee113eSDavid van Moolenbroek 		fclose (leaseFile);
2770*83ee113eSDavid van Moolenbroek 	leaseFile = fopen (path_dhclient_db, "w");
2771*83ee113eSDavid van Moolenbroek 	if (leaseFile == NULL) {
2772*83ee113eSDavid van Moolenbroek 		log_error ("can't create %s: %m", path_dhclient_db);
2773*83ee113eSDavid van Moolenbroek 		return;
2774*83ee113eSDavid van Moolenbroek 	}
2775*83ee113eSDavid van Moolenbroek 
2776*83ee113eSDavid van Moolenbroek 	/* If there is a default duid, write it out. */
2777*83ee113eSDavid van Moolenbroek 	if (default_duid.len != 0)
2778*83ee113eSDavid van Moolenbroek 		write_duid(&default_duid);
2779*83ee113eSDavid van Moolenbroek 
2780*83ee113eSDavid van Moolenbroek 	/* Write out all the leases attached to configured interfaces that
2781*83ee113eSDavid van Moolenbroek 	   we know about. */
2782*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip -> next) {
2783*83ee113eSDavid van Moolenbroek 		for (client = ip -> client; client; client = client -> next) {
2784*83ee113eSDavid van Moolenbroek 			for (lp = client -> leases; lp; lp = lp -> next) {
2785*83ee113eSDavid van Moolenbroek 				write_client_lease (client, lp, 1, 0);
2786*83ee113eSDavid van Moolenbroek 			}
2787*83ee113eSDavid van Moolenbroek 			if (client -> active)
2788*83ee113eSDavid van Moolenbroek 				write_client_lease (client,
2789*83ee113eSDavid van Moolenbroek 						    client -> active, 1, 0);
2790*83ee113eSDavid van Moolenbroek 
2791*83ee113eSDavid van Moolenbroek 			if (client->active_lease != NULL)
2792*83ee113eSDavid van Moolenbroek 				write_client6_lease(client,
2793*83ee113eSDavid van Moolenbroek 						    client->active_lease,
2794*83ee113eSDavid van Moolenbroek 						    1, 0);
2795*83ee113eSDavid van Moolenbroek 
2796*83ee113eSDavid van Moolenbroek 			/* Reset last_write after rewrites. */
2797*83ee113eSDavid van Moolenbroek 			client->last_write = 0;
2798*83ee113eSDavid van Moolenbroek 		}
2799*83ee113eSDavid van Moolenbroek 	}
2800*83ee113eSDavid van Moolenbroek 
2801*83ee113eSDavid van Moolenbroek 	/* Write out any leases that are attached to interfaces that aren't
2802*83ee113eSDavid van Moolenbroek 	   currently configured. */
2803*83ee113eSDavid van Moolenbroek 	for (ip = dummy_interfaces; ip; ip = ip -> next) {
2804*83ee113eSDavid van Moolenbroek 		for (client = ip -> client; client; client = client -> next) {
2805*83ee113eSDavid van Moolenbroek 			for (lp = client -> leases; lp; lp = lp -> next) {
2806*83ee113eSDavid van Moolenbroek 				write_client_lease (client, lp, 1, 0);
2807*83ee113eSDavid van Moolenbroek 			}
2808*83ee113eSDavid van Moolenbroek 			if (client -> active)
2809*83ee113eSDavid van Moolenbroek 				write_client_lease (client,
2810*83ee113eSDavid van Moolenbroek 						    client -> active, 1, 0);
2811*83ee113eSDavid van Moolenbroek 
2812*83ee113eSDavid van Moolenbroek 			if (client->active_lease != NULL)
2813*83ee113eSDavid van Moolenbroek 				write_client6_lease(client,
2814*83ee113eSDavid van Moolenbroek 						    client->active_lease,
2815*83ee113eSDavid van Moolenbroek 						    1, 0);
2816*83ee113eSDavid van Moolenbroek 
2817*83ee113eSDavid van Moolenbroek 			/* Reset last_write after rewrites. */
2818*83ee113eSDavid van Moolenbroek 			client->last_write = 0;
2819*83ee113eSDavid van Moolenbroek 		}
2820*83ee113eSDavid van Moolenbroek 	}
2821*83ee113eSDavid van Moolenbroek 	fflush (leaseFile);
2822*83ee113eSDavid van Moolenbroek }
2823*83ee113eSDavid van Moolenbroek 
write_lease_option(struct option_cache * oc,struct packet * packet,struct lease * lease,struct client_state * client_state,struct option_state * in_options,struct option_state * cfg_options,struct binding_scope ** scope,struct universe * u,void * stuff)2824*83ee113eSDavid van Moolenbroek void write_lease_option (struct option_cache *oc,
2825*83ee113eSDavid van Moolenbroek 			 struct packet *packet, struct lease *lease,
2826*83ee113eSDavid van Moolenbroek 			 struct client_state *client_state,
2827*83ee113eSDavid van Moolenbroek 			 struct option_state *in_options,
2828*83ee113eSDavid van Moolenbroek 			 struct option_state *cfg_options,
2829*83ee113eSDavid van Moolenbroek 			 struct binding_scope **scope,
2830*83ee113eSDavid van Moolenbroek 			 struct universe *u, void *stuff)
2831*83ee113eSDavid van Moolenbroek {
2832*83ee113eSDavid van Moolenbroek 	const char *name, *dot;
2833*83ee113eSDavid van Moolenbroek 	struct data_string ds;
2834*83ee113eSDavid van Moolenbroek 	char *preamble = stuff;
2835*83ee113eSDavid van Moolenbroek 
2836*83ee113eSDavid van Moolenbroek 	memset (&ds, 0, sizeof ds);
2837*83ee113eSDavid van Moolenbroek 
2838*83ee113eSDavid van Moolenbroek 	if (u != &dhcp_universe) {
2839*83ee113eSDavid van Moolenbroek 		name = u -> name;
2840*83ee113eSDavid van Moolenbroek 		dot = ".";
2841*83ee113eSDavid van Moolenbroek 	} else {
2842*83ee113eSDavid van Moolenbroek 		name = "";
2843*83ee113eSDavid van Moolenbroek 		dot = "";
2844*83ee113eSDavid van Moolenbroek 	}
2845*83ee113eSDavid van Moolenbroek 	if (evaluate_option_cache (&ds, packet, lease, client_state,
2846*83ee113eSDavid van Moolenbroek 				   in_options, cfg_options, scope, oc, MDL)) {
2847*83ee113eSDavid van Moolenbroek 		/* The option name */
2848*83ee113eSDavid van Moolenbroek 		fprintf(leaseFile, "%soption %s%s%s", preamble,
2849*83ee113eSDavid van Moolenbroek 			name, dot, oc->option->name);
2850*83ee113eSDavid van Moolenbroek 
2851*83ee113eSDavid van Moolenbroek 		/* The option value if there is one */
2852*83ee113eSDavid van Moolenbroek 		if ((oc->option->format == NULL) ||
2853*83ee113eSDavid van Moolenbroek 		    (oc->option->format[0] != 'Z')) {
2854*83ee113eSDavid van Moolenbroek 			fprintf(leaseFile, " %s",
2855*83ee113eSDavid van Moolenbroek 				pretty_print_option(oc->option, ds.data,
2856*83ee113eSDavid van Moolenbroek 						    ds.len, 1, 1));
2857*83ee113eSDavid van Moolenbroek 		}
2858*83ee113eSDavid van Moolenbroek 
2859*83ee113eSDavid van Moolenbroek 		/* The closing semi-colon and newline */
2860*83ee113eSDavid van Moolenbroek 		fprintf(leaseFile, ";\n");
2861*83ee113eSDavid van Moolenbroek 
2862*83ee113eSDavid van Moolenbroek 		data_string_forget (&ds, MDL);
2863*83ee113eSDavid van Moolenbroek 	}
2864*83ee113eSDavid van Moolenbroek }
2865*83ee113eSDavid van Moolenbroek 
2866*83ee113eSDavid van Moolenbroek /* Write an option cache to the lease store. */
2867*83ee113eSDavid van Moolenbroek static void
write_options(struct client_state * client,struct option_state * options,const char * preamble)2868*83ee113eSDavid van Moolenbroek write_options(struct client_state *client, struct option_state *options,
2869*83ee113eSDavid van Moolenbroek 	      const char *preamble)
2870*83ee113eSDavid van Moolenbroek {
2871*83ee113eSDavid van Moolenbroek 	int i;
2872*83ee113eSDavid van Moolenbroek 
2873*83ee113eSDavid van Moolenbroek 	for (i = 0; i < options->universe_count; i++) {
2874*83ee113eSDavid van Moolenbroek 		option_space_foreach(NULL, NULL, client, NULL, options,
2875*83ee113eSDavid van Moolenbroek 				     &global_scope, universes[i],
2876*83ee113eSDavid van Moolenbroek 				     (char *)preamble, write_lease_option);
2877*83ee113eSDavid van Moolenbroek 	}
2878*83ee113eSDavid van Moolenbroek }
2879*83ee113eSDavid van Moolenbroek 
2880*83ee113eSDavid van Moolenbroek /*
2881*83ee113eSDavid van Moolenbroek  * The "best" default DUID, since we cannot predict any information
2882*83ee113eSDavid van Moolenbroek  * about the system (such as whether or not the hardware addresses are
2883*83ee113eSDavid van Moolenbroek  * integrated into the motherboard or similar), is the "LLT", link local
2884*83ee113eSDavid van Moolenbroek  * plus time, DUID. For real stateless "LL" is better.
2885*83ee113eSDavid van Moolenbroek  *
2886*83ee113eSDavid van Moolenbroek  * Once generated, this duid is stored into the state database, and
2887*83ee113eSDavid van Moolenbroek  * retained across restarts.
2888*83ee113eSDavid van Moolenbroek  *
2889*83ee113eSDavid van Moolenbroek  * For the time being, there is probably a different state database for
2890*83ee113eSDavid van Moolenbroek  * every daemon, so this winds up being a per-interface identifier...which
2891*83ee113eSDavid van Moolenbroek  * is not how it is intended.  Upcoming rearchitecting the client should
2892*83ee113eSDavid van Moolenbroek  * address this "one daemon model."
2893*83ee113eSDavid van Moolenbroek  */
2894*83ee113eSDavid van Moolenbroek void
form_duid(struct data_string * duid,const char * file,int line)2895*83ee113eSDavid van Moolenbroek form_duid(struct data_string *duid, const char *file, int line)
2896*83ee113eSDavid van Moolenbroek {
2897*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
2898*83ee113eSDavid van Moolenbroek 	int len;
2899*83ee113eSDavid van Moolenbroek 
2900*83ee113eSDavid van Moolenbroek 	/* For now, just use the first interface on the list. */
2901*83ee113eSDavid van Moolenbroek 	ip = interfaces;
2902*83ee113eSDavid van Moolenbroek 
2903*83ee113eSDavid van Moolenbroek 	if (ip == NULL)
2904*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
2905*83ee113eSDavid van Moolenbroek 
2906*83ee113eSDavid van Moolenbroek 	if ((ip->hw_address.hlen == 0) ||
2907*83ee113eSDavid van Moolenbroek 	    (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
2908*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible hardware address length at %s:%d.", MDL);
2909*83ee113eSDavid van Moolenbroek 
2910*83ee113eSDavid van Moolenbroek 	if (duid_type == 0)
2911*83ee113eSDavid van Moolenbroek 		duid_type = stateless ? DUID_LL : DUID_LLT;
2912*83ee113eSDavid van Moolenbroek 
2913*83ee113eSDavid van Moolenbroek 	/*
2914*83ee113eSDavid van Moolenbroek 	 * 2 bytes for the 'duid type' field.
2915*83ee113eSDavid van Moolenbroek 	 * 2 bytes for the 'htype' field.
2916*83ee113eSDavid van Moolenbroek 	 * (DUID_LLT) 4 bytes for the 'current time'.
2917*83ee113eSDavid van Moolenbroek 	 * enough bytes for the hardware address (note that hw_address has
2918*83ee113eSDavid van Moolenbroek 	 * the 'htype' on byte zero).
2919*83ee113eSDavid van Moolenbroek 	 */
2920*83ee113eSDavid van Moolenbroek 	len = 4 + (ip->hw_address.hlen - 1);
2921*83ee113eSDavid van Moolenbroek 	if (duid_type == DUID_LLT)
2922*83ee113eSDavid van Moolenbroek 		len += 4;
2923*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate(&duid->buffer, len, MDL))
2924*83ee113eSDavid van Moolenbroek 		log_fatal("no memory for default DUID!");
2925*83ee113eSDavid van Moolenbroek 	duid->data = duid->buffer->data;
2926*83ee113eSDavid van Moolenbroek 	duid->len = len;
2927*83ee113eSDavid van Moolenbroek 
2928*83ee113eSDavid van Moolenbroek 	/* Basic Link Local Address type of DUID. */
2929*83ee113eSDavid van Moolenbroek 	if (duid_type == DUID_LLT) {
2930*83ee113eSDavid van Moolenbroek 		putUShort(duid->buffer->data, DUID_LLT);
2931*83ee113eSDavid van Moolenbroek 		putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
2932*83ee113eSDavid van Moolenbroek 		putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
2933*83ee113eSDavid van Moolenbroek 		memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
2934*83ee113eSDavid van Moolenbroek 		       ip->hw_address.hlen - 1);
2935*83ee113eSDavid van Moolenbroek 	} else {
2936*83ee113eSDavid van Moolenbroek 		putUShort(duid->buffer->data, DUID_LL);
2937*83ee113eSDavid van Moolenbroek 		putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
2938*83ee113eSDavid van Moolenbroek 		memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
2939*83ee113eSDavid van Moolenbroek 		       ip->hw_address.hlen - 1);
2940*83ee113eSDavid van Moolenbroek 	}
2941*83ee113eSDavid van Moolenbroek }
2942*83ee113eSDavid van Moolenbroek 
2943*83ee113eSDavid van Moolenbroek /* Write the default DUID to the lease store. */
2944*83ee113eSDavid van Moolenbroek static isc_result_t
write_duid(struct data_string * duid)2945*83ee113eSDavid van Moolenbroek write_duid(struct data_string *duid)
2946*83ee113eSDavid van Moolenbroek {
2947*83ee113eSDavid van Moolenbroek 	char *str;
2948*83ee113eSDavid van Moolenbroek 	int stat;
2949*83ee113eSDavid van Moolenbroek 
2950*83ee113eSDavid van Moolenbroek 	if ((duid == NULL) || (duid->len <= 2))
2951*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
2952*83ee113eSDavid van Moolenbroek 
2953*83ee113eSDavid van Moolenbroek 	if (leaseFile == NULL) {	/* XXX? */
2954*83ee113eSDavid van Moolenbroek 		leaseFile = fopen(path_dhclient_db, "w");
2955*83ee113eSDavid van Moolenbroek 		if (leaseFile == NULL) {
2956*83ee113eSDavid van Moolenbroek 			log_error("can't create %s: %m", path_dhclient_db);
2957*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
2958*83ee113eSDavid van Moolenbroek 		}
2959*83ee113eSDavid van Moolenbroek 	}
2960*83ee113eSDavid van Moolenbroek 
2961*83ee113eSDavid van Moolenbroek 	/* It would make more sense to write this as a hex string,
2962*83ee113eSDavid van Moolenbroek 	 * but our function to do that (print_hex_n) uses a fixed
2963*83ee113eSDavid van Moolenbroek 	 * length buffer...and we can't guarantee a duid would be
2964*83ee113eSDavid van Moolenbroek 	 * less than the fixed length.
2965*83ee113eSDavid van Moolenbroek 	 */
2966*83ee113eSDavid van Moolenbroek 	str = quotify_buf(duid->data, duid->len, MDL);
2967*83ee113eSDavid van Moolenbroek 	if (str == NULL)
2968*83ee113eSDavid van Moolenbroek 		return ISC_R_NOMEMORY;
2969*83ee113eSDavid van Moolenbroek 
2970*83ee113eSDavid van Moolenbroek 	stat = fprintf(leaseFile, "default-duid \"%s\";\n", str);
2971*83ee113eSDavid van Moolenbroek 	dfree(str, MDL);
2972*83ee113eSDavid van Moolenbroek 	if (stat <= 0)
2973*83ee113eSDavid van Moolenbroek 		return ISC_R_IOERROR;
2974*83ee113eSDavid van Moolenbroek 
2975*83ee113eSDavid van Moolenbroek 	if (fflush(leaseFile) != 0)
2976*83ee113eSDavid van Moolenbroek 		return ISC_R_IOERROR;
2977*83ee113eSDavid van Moolenbroek 
2978*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
2979*83ee113eSDavid van Moolenbroek }
2980*83ee113eSDavid van Moolenbroek 
2981*83ee113eSDavid van Moolenbroek /* Write a DHCPv6 lease to the store. */
2982*83ee113eSDavid van Moolenbroek isc_result_t
write_client6_lease(struct client_state * client,struct dhc6_lease * lease,int rewrite,int sync)2983*83ee113eSDavid van Moolenbroek write_client6_lease(struct client_state *client, struct dhc6_lease *lease,
2984*83ee113eSDavid van Moolenbroek 		    int rewrite, int sync)
2985*83ee113eSDavid van Moolenbroek {
2986*83ee113eSDavid van Moolenbroek 	struct dhc6_ia *ia;
2987*83ee113eSDavid van Moolenbroek 	struct dhc6_addr *addr;
2988*83ee113eSDavid van Moolenbroek 	int stat;
2989*83ee113eSDavid van Moolenbroek 	const char *ianame;
2990*83ee113eSDavid van Moolenbroek 
2991*83ee113eSDavid van Moolenbroek 	/* This should include the current lease. */
2992*83ee113eSDavid van Moolenbroek 	if (!rewrite && (leases_written++ > 20)) {
2993*83ee113eSDavid van Moolenbroek 		rewrite_client_leases();
2994*83ee113eSDavid van Moolenbroek 		leases_written = 0;
2995*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
2996*83ee113eSDavid van Moolenbroek 	}
2997*83ee113eSDavid van Moolenbroek 
2998*83ee113eSDavid van Moolenbroek 	if (client == NULL || lease == NULL)
2999*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
3000*83ee113eSDavid van Moolenbroek 
3001*83ee113eSDavid van Moolenbroek 	if (leaseFile == NULL) {	/* XXX? */
3002*83ee113eSDavid van Moolenbroek 		leaseFile = fopen(path_dhclient_db, "w");
3003*83ee113eSDavid van Moolenbroek 		if (leaseFile == NULL) {
3004*83ee113eSDavid van Moolenbroek 			log_error("can't create %s: %m", path_dhclient_db);
3005*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
3006*83ee113eSDavid van Moolenbroek 		}
3007*83ee113eSDavid van Moolenbroek 	}
3008*83ee113eSDavid van Moolenbroek 
3009*83ee113eSDavid van Moolenbroek 	stat = fprintf(leaseFile, "lease6 {\n");
3010*83ee113eSDavid van Moolenbroek 	if (stat <= 0)
3011*83ee113eSDavid van Moolenbroek 		return ISC_R_IOERROR;
3012*83ee113eSDavid van Moolenbroek 
3013*83ee113eSDavid van Moolenbroek 	stat = fprintf(leaseFile, "  interface \"%s\";\n",
3014*83ee113eSDavid van Moolenbroek 		       client->interface->name);
3015*83ee113eSDavid van Moolenbroek 	if (stat <= 0)
3016*83ee113eSDavid van Moolenbroek 		return ISC_R_IOERROR;
3017*83ee113eSDavid van Moolenbroek 
3018*83ee113eSDavid van Moolenbroek 	for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
3019*83ee113eSDavid van Moolenbroek 		switch (ia->ia_type) {
3020*83ee113eSDavid van Moolenbroek 			case D6O_IA_NA:
3021*83ee113eSDavid van Moolenbroek 			default:
3022*83ee113eSDavid van Moolenbroek 				ianame = "ia-na";
3023*83ee113eSDavid van Moolenbroek 				break;
3024*83ee113eSDavid van Moolenbroek 			case D6O_IA_TA:
3025*83ee113eSDavid van Moolenbroek 				ianame = "ia-ta";
3026*83ee113eSDavid van Moolenbroek 				break;
3027*83ee113eSDavid van Moolenbroek 			case D6O_IA_PD:
3028*83ee113eSDavid van Moolenbroek 				ianame = "ia-pd";
3029*83ee113eSDavid van Moolenbroek 				break;
3030*83ee113eSDavid van Moolenbroek 		}
3031*83ee113eSDavid van Moolenbroek 		stat = fprintf(leaseFile, "  %s %s {\n",
3032*83ee113eSDavid van Moolenbroek 			       ianame, print_hex_1(4, ia->iaid, 12));
3033*83ee113eSDavid van Moolenbroek 		if (stat <= 0)
3034*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
3035*83ee113eSDavid van Moolenbroek 
3036*83ee113eSDavid van Moolenbroek 		if (ia->ia_type != D6O_IA_TA)
3037*83ee113eSDavid van Moolenbroek 			stat = fprintf(leaseFile, "    starts %d;\n"
3038*83ee113eSDavid van Moolenbroek 						  "    renew %u;\n"
3039*83ee113eSDavid van Moolenbroek 						  "    rebind %u;\n",
3040*83ee113eSDavid van Moolenbroek 				       (int)ia->starts, ia->renew, ia->rebind);
3041*83ee113eSDavid van Moolenbroek 		else
3042*83ee113eSDavid van Moolenbroek 			stat = fprintf(leaseFile, "    starts %d;\n",
3043*83ee113eSDavid van Moolenbroek 				       (int)ia->starts);
3044*83ee113eSDavid van Moolenbroek 		if (stat <= 0)
3045*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
3046*83ee113eSDavid van Moolenbroek 
3047*83ee113eSDavid van Moolenbroek 		for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3048*83ee113eSDavid van Moolenbroek 			if (ia->ia_type != D6O_IA_PD)
3049*83ee113eSDavid van Moolenbroek 				stat = fprintf(leaseFile,
3050*83ee113eSDavid van Moolenbroek 					       "    iaaddr %s {\n",
3051*83ee113eSDavid van Moolenbroek 					       piaddr(addr->address));
3052*83ee113eSDavid van Moolenbroek 			else
3053*83ee113eSDavid van Moolenbroek 				stat = fprintf(leaseFile,
3054*83ee113eSDavid van Moolenbroek 					       "    iaprefix %s/%d {\n",
3055*83ee113eSDavid van Moolenbroek 					       piaddr(addr->address),
3056*83ee113eSDavid van Moolenbroek 					       (int)addr->plen);
3057*83ee113eSDavid van Moolenbroek 			if (stat <= 0)
3058*83ee113eSDavid van Moolenbroek 				return ISC_R_IOERROR;
3059*83ee113eSDavid van Moolenbroek 
3060*83ee113eSDavid van Moolenbroek 			stat = fprintf(leaseFile, "      starts %d;\n"
3061*83ee113eSDavid van Moolenbroek 						  "      preferred-life %u;\n"
3062*83ee113eSDavid van Moolenbroek 						  "      max-life %u;\n",
3063*83ee113eSDavid van Moolenbroek 				       (int)addr->starts, addr->preferred_life,
3064*83ee113eSDavid van Moolenbroek 				       addr->max_life);
3065*83ee113eSDavid van Moolenbroek 			if (stat <= 0)
3066*83ee113eSDavid van Moolenbroek 				return ISC_R_IOERROR;
3067*83ee113eSDavid van Moolenbroek 
3068*83ee113eSDavid van Moolenbroek 			if (addr->options != NULL)
3069*83ee113eSDavid van Moolenbroek 				write_options(client, addr->options, "      ");
3070*83ee113eSDavid van Moolenbroek 
3071*83ee113eSDavid van Moolenbroek 			stat = fprintf(leaseFile, "    }\n");
3072*83ee113eSDavid van Moolenbroek 			if (stat <= 0)
3073*83ee113eSDavid van Moolenbroek 				return ISC_R_IOERROR;
3074*83ee113eSDavid van Moolenbroek 		}
3075*83ee113eSDavid van Moolenbroek 
3076*83ee113eSDavid van Moolenbroek 		if (ia->options != NULL)
3077*83ee113eSDavid van Moolenbroek 			write_options(client, ia->options, "    ");
3078*83ee113eSDavid van Moolenbroek 
3079*83ee113eSDavid van Moolenbroek 		stat = fprintf(leaseFile, "  }\n");
3080*83ee113eSDavid van Moolenbroek 		if (stat <= 0)
3081*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
3082*83ee113eSDavid van Moolenbroek 	}
3083*83ee113eSDavid van Moolenbroek 
3084*83ee113eSDavid van Moolenbroek 	if (lease->released) {
3085*83ee113eSDavid van Moolenbroek 		stat = fprintf(leaseFile, "  released;\n");
3086*83ee113eSDavid van Moolenbroek 		if (stat <= 0)
3087*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
3088*83ee113eSDavid van Moolenbroek 	}
3089*83ee113eSDavid van Moolenbroek 
3090*83ee113eSDavid van Moolenbroek 	if (lease->options != NULL)
3091*83ee113eSDavid van Moolenbroek 		write_options(client, lease->options, "  ");
3092*83ee113eSDavid van Moolenbroek 
3093*83ee113eSDavid van Moolenbroek 	stat = fprintf(leaseFile, "}\n");
3094*83ee113eSDavid van Moolenbroek 	if (stat <= 0)
3095*83ee113eSDavid van Moolenbroek 		return ISC_R_IOERROR;
3096*83ee113eSDavid van Moolenbroek 
3097*83ee113eSDavid van Moolenbroek 	if (fflush(leaseFile) != 0)
3098*83ee113eSDavid van Moolenbroek 		return ISC_R_IOERROR;
3099*83ee113eSDavid van Moolenbroek 
3100*83ee113eSDavid van Moolenbroek 	if (sync) {
3101*83ee113eSDavid van Moolenbroek 		if (fsync(fileno(leaseFile)) < 0) {
3102*83ee113eSDavid van Moolenbroek 			log_error("write_client_lease: fsync(): %m");
3103*83ee113eSDavid van Moolenbroek 			return ISC_R_IOERROR;
3104*83ee113eSDavid van Moolenbroek 		}
3105*83ee113eSDavid van Moolenbroek 	}
3106*83ee113eSDavid van Moolenbroek 
3107*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
3108*83ee113eSDavid van Moolenbroek }
3109*83ee113eSDavid van Moolenbroek 
write_client_lease(client,lease,rewrite,makesure)3110*83ee113eSDavid van Moolenbroek int write_client_lease (client, lease, rewrite, makesure)
3111*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3112*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
3113*83ee113eSDavid van Moolenbroek 	int rewrite;
3114*83ee113eSDavid van Moolenbroek 	int makesure;
3115*83ee113eSDavid van Moolenbroek {
3116*83ee113eSDavid van Moolenbroek 	struct data_string ds;
3117*83ee113eSDavid van Moolenbroek 	int errors = 0;
3118*83ee113eSDavid van Moolenbroek 	char *s;
3119*83ee113eSDavid van Moolenbroek 	const char *tval;
3120*83ee113eSDavid van Moolenbroek 
3121*83ee113eSDavid van Moolenbroek 	if (!rewrite) {
3122*83ee113eSDavid van Moolenbroek 		if (leases_written++ > 20) {
3123*83ee113eSDavid van Moolenbroek 			rewrite_client_leases ();
3124*83ee113eSDavid van Moolenbroek 			leases_written = 0;
3125*83ee113eSDavid van Moolenbroek 		}
3126*83ee113eSDavid van Moolenbroek 	}
3127*83ee113eSDavid van Moolenbroek 
3128*83ee113eSDavid van Moolenbroek 	/* If the lease came from the config file, we don't need to stash
3129*83ee113eSDavid van Moolenbroek 	   a copy in the lease database. */
3130*83ee113eSDavid van Moolenbroek 	if (lease -> is_static)
3131*83ee113eSDavid van Moolenbroek 		return 1;
3132*83ee113eSDavid van Moolenbroek 
3133*83ee113eSDavid van Moolenbroek 	if (leaseFile == NULL) {	/* XXX */
3134*83ee113eSDavid van Moolenbroek 		leaseFile = fopen (path_dhclient_db, "w");
3135*83ee113eSDavid van Moolenbroek 		if (leaseFile == NULL) {
3136*83ee113eSDavid van Moolenbroek 			log_error ("can't create %s: %m", path_dhclient_db);
3137*83ee113eSDavid van Moolenbroek 			return 0;
3138*83ee113eSDavid van Moolenbroek 		}
3139*83ee113eSDavid van Moolenbroek 	}
3140*83ee113eSDavid van Moolenbroek 
3141*83ee113eSDavid van Moolenbroek 	errno = 0;
3142*83ee113eSDavid van Moolenbroek 	fprintf (leaseFile, "lease {\n");
3143*83ee113eSDavid van Moolenbroek 	if (lease -> is_bootp) {
3144*83ee113eSDavid van Moolenbroek 		fprintf (leaseFile, "  bootp;\n");
3145*83ee113eSDavid van Moolenbroek 		if (errno) {
3146*83ee113eSDavid van Moolenbroek 			++errors;
3147*83ee113eSDavid van Moolenbroek 			errno = 0;
3148*83ee113eSDavid van Moolenbroek 		}
3149*83ee113eSDavid van Moolenbroek 	}
3150*83ee113eSDavid van Moolenbroek 	fprintf (leaseFile, "  interface \"%s\";\n",
3151*83ee113eSDavid van Moolenbroek 		 client -> interface -> name);
3152*83ee113eSDavid van Moolenbroek 	if (errno) {
3153*83ee113eSDavid van Moolenbroek 		++errors;
3154*83ee113eSDavid van Moolenbroek 		errno = 0;
3155*83ee113eSDavid van Moolenbroek 	}
3156*83ee113eSDavid van Moolenbroek 	if (client -> name) {
3157*83ee113eSDavid van Moolenbroek 		fprintf (leaseFile, "  name \"%s\";\n", client -> name);
3158*83ee113eSDavid van Moolenbroek 		if (errno) {
3159*83ee113eSDavid van Moolenbroek 			++errors;
3160*83ee113eSDavid van Moolenbroek 			errno = 0;
3161*83ee113eSDavid van Moolenbroek 		}
3162*83ee113eSDavid van Moolenbroek 	}
3163*83ee113eSDavid van Moolenbroek 	fprintf (leaseFile, "  fixed-address %s;\n",
3164*83ee113eSDavid van Moolenbroek 		 piaddr (lease -> address));
3165*83ee113eSDavid van Moolenbroek 	if (errno) {
3166*83ee113eSDavid van Moolenbroek 		++errors;
3167*83ee113eSDavid van Moolenbroek 		errno = 0;
3168*83ee113eSDavid van Moolenbroek 	}
3169*83ee113eSDavid van Moolenbroek 	if (lease -> filename) {
3170*83ee113eSDavid van Moolenbroek 		s = quotify_string (lease -> filename, MDL);
3171*83ee113eSDavid van Moolenbroek 		if (s) {
3172*83ee113eSDavid van Moolenbroek 			fprintf (leaseFile, "  filename \"%s\";\n", s);
3173*83ee113eSDavid van Moolenbroek 			if (errno) {
3174*83ee113eSDavid van Moolenbroek 				++errors;
3175*83ee113eSDavid van Moolenbroek 				errno = 0;
3176*83ee113eSDavid van Moolenbroek 			}
3177*83ee113eSDavid van Moolenbroek 			dfree (s, MDL);
3178*83ee113eSDavid van Moolenbroek 		} else
3179*83ee113eSDavid van Moolenbroek 			errors++;
3180*83ee113eSDavid van Moolenbroek 
3181*83ee113eSDavid van Moolenbroek 	}
3182*83ee113eSDavid van Moolenbroek 	if (lease->server_name != NULL) {
3183*83ee113eSDavid van Moolenbroek 		s = quotify_string(lease->server_name, MDL);
3184*83ee113eSDavid van Moolenbroek 		if (s != NULL) {
3185*83ee113eSDavid van Moolenbroek 			fprintf(leaseFile, "  server-name \"%s\";\n", s);
3186*83ee113eSDavid van Moolenbroek 			if (errno) {
3187*83ee113eSDavid van Moolenbroek 				++errors;
3188*83ee113eSDavid van Moolenbroek 				errno = 0;
3189*83ee113eSDavid van Moolenbroek 			}
3190*83ee113eSDavid van Moolenbroek 			dfree(s, MDL);
3191*83ee113eSDavid van Moolenbroek 		} else
3192*83ee113eSDavid van Moolenbroek 			++errors;
3193*83ee113eSDavid van Moolenbroek 	}
3194*83ee113eSDavid van Moolenbroek 	if (lease -> medium) {
3195*83ee113eSDavid van Moolenbroek 		s = quotify_string (lease -> medium -> string, MDL);
3196*83ee113eSDavid van Moolenbroek 		if (s) {
3197*83ee113eSDavid van Moolenbroek 			fprintf (leaseFile, "  medium \"%s\";\n", s);
3198*83ee113eSDavid van Moolenbroek 			if (errno) {
3199*83ee113eSDavid van Moolenbroek 				++errors;
3200*83ee113eSDavid van Moolenbroek 				errno = 0;
3201*83ee113eSDavid van Moolenbroek 			}
3202*83ee113eSDavid van Moolenbroek 			dfree (s, MDL);
3203*83ee113eSDavid van Moolenbroek 		} else
3204*83ee113eSDavid van Moolenbroek 			errors++;
3205*83ee113eSDavid van Moolenbroek 	}
3206*83ee113eSDavid van Moolenbroek 	if (errno != 0) {
3207*83ee113eSDavid van Moolenbroek 		errors++;
3208*83ee113eSDavid van Moolenbroek 		errno = 0;
3209*83ee113eSDavid van Moolenbroek 	}
3210*83ee113eSDavid van Moolenbroek 
3211*83ee113eSDavid van Moolenbroek 	memset (&ds, 0, sizeof ds);
3212*83ee113eSDavid van Moolenbroek 
3213*83ee113eSDavid van Moolenbroek 	write_options(client, lease->options, "  ");
3214*83ee113eSDavid van Moolenbroek 
3215*83ee113eSDavid van Moolenbroek 	tval = print_time(lease->renewal);
3216*83ee113eSDavid van Moolenbroek 	if (tval == NULL ||
3217*83ee113eSDavid van Moolenbroek 	    fprintf(leaseFile, "  renew %s\n", tval) < 0)
3218*83ee113eSDavid van Moolenbroek 		errors++;
3219*83ee113eSDavid van Moolenbroek 
3220*83ee113eSDavid van Moolenbroek 	tval = print_time(lease->rebind);
3221*83ee113eSDavid van Moolenbroek 	if (tval == NULL ||
3222*83ee113eSDavid van Moolenbroek 	    fprintf(leaseFile, "  rebind %s\n", tval) < 0)
3223*83ee113eSDavid van Moolenbroek 		errors++;
3224*83ee113eSDavid van Moolenbroek 
3225*83ee113eSDavid van Moolenbroek 	tval = print_time(lease->expiry);
3226*83ee113eSDavid van Moolenbroek 	if (tval == NULL ||
3227*83ee113eSDavid van Moolenbroek 	    fprintf(leaseFile, "  expire %s\n", tval) < 0)
3228*83ee113eSDavid van Moolenbroek 		errors++;
3229*83ee113eSDavid van Moolenbroek 
3230*83ee113eSDavid van Moolenbroek 	if (fprintf(leaseFile, "}\n") < 0)
3231*83ee113eSDavid van Moolenbroek 		errors++;
3232*83ee113eSDavid van Moolenbroek 
3233*83ee113eSDavid van Moolenbroek 	if (fflush(leaseFile) != 0)
3234*83ee113eSDavid van Moolenbroek 		errors++;
3235*83ee113eSDavid van Moolenbroek 
3236*83ee113eSDavid van Moolenbroek 	client->last_write = cur_time;
3237*83ee113eSDavid van Moolenbroek 
3238*83ee113eSDavid van Moolenbroek 	if (!errors && makesure) {
3239*83ee113eSDavid van Moolenbroek 		if (fsync (fileno (leaseFile)) < 0) {
3240*83ee113eSDavid van Moolenbroek 			log_info ("write_client_lease: %m");
3241*83ee113eSDavid van Moolenbroek 			return 0;
3242*83ee113eSDavid van Moolenbroek 		}
3243*83ee113eSDavid van Moolenbroek 	}
3244*83ee113eSDavid van Moolenbroek 
3245*83ee113eSDavid van Moolenbroek 	return errors ? 0 : 1;
3246*83ee113eSDavid van Moolenbroek }
3247*83ee113eSDavid van Moolenbroek 
3248*83ee113eSDavid van Moolenbroek /* Variables holding name of script and file pointer for writing to
3249*83ee113eSDavid van Moolenbroek    script.   Needless to say, this is not reentrant - only one script
3250*83ee113eSDavid van Moolenbroek    can be invoked at a time. */
3251*83ee113eSDavid van Moolenbroek char scriptName [256];
3252*83ee113eSDavid van Moolenbroek FILE *scriptFile;
3253*83ee113eSDavid van Moolenbroek 
script_init(client,reason,medium)3254*83ee113eSDavid van Moolenbroek void script_init (client, reason, medium)
3255*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3256*83ee113eSDavid van Moolenbroek 	const char *reason;
3257*83ee113eSDavid van Moolenbroek 	struct string_list *medium;
3258*83ee113eSDavid van Moolenbroek {
3259*83ee113eSDavid van Moolenbroek 	struct string_list *sl, *next;
3260*83ee113eSDavid van Moolenbroek 
3261*83ee113eSDavid van Moolenbroek 	if (client) {
3262*83ee113eSDavid van Moolenbroek 		for (sl = client -> env; sl; sl = next) {
3263*83ee113eSDavid van Moolenbroek 			next = sl -> next;
3264*83ee113eSDavid van Moolenbroek 			dfree (sl, MDL);
3265*83ee113eSDavid van Moolenbroek 		}
3266*83ee113eSDavid van Moolenbroek 		client -> env = (struct string_list *)0;
3267*83ee113eSDavid van Moolenbroek 		client -> envc = 0;
3268*83ee113eSDavid van Moolenbroek 
3269*83ee113eSDavid van Moolenbroek 		if (client -> interface) {
3270*83ee113eSDavid van Moolenbroek 			client_envadd (client, "", "interface", "%s",
3271*83ee113eSDavid van Moolenbroek 				       client -> interface -> name);
3272*83ee113eSDavid van Moolenbroek 		}
3273*83ee113eSDavid van Moolenbroek 		if (client -> name)
3274*83ee113eSDavid van Moolenbroek 			client_envadd (client,
3275*83ee113eSDavid van Moolenbroek 				       "", "client", "%s", client -> name);
3276*83ee113eSDavid van Moolenbroek 		if (medium)
3277*83ee113eSDavid van Moolenbroek 			client_envadd (client,
3278*83ee113eSDavid van Moolenbroek 				       "", "medium", "%s", medium -> string);
3279*83ee113eSDavid van Moolenbroek 
3280*83ee113eSDavid van Moolenbroek 		client_envadd (client, "", "reason", "%s", reason);
3281*83ee113eSDavid van Moolenbroek 		client_envadd (client, "", "pid", "%ld", (long int)getpid ());
3282*83ee113eSDavid van Moolenbroek 	}
3283*83ee113eSDavid van Moolenbroek }
3284*83ee113eSDavid van Moolenbroek 
client_option_envadd(struct option_cache * oc,struct packet * packet,struct lease * lease,struct client_state * client_state,struct option_state * in_options,struct option_state * cfg_options,struct binding_scope ** scope,struct universe * u,void * stuff)3285*83ee113eSDavid van Moolenbroek void client_option_envadd (struct option_cache *oc,
3286*83ee113eSDavid van Moolenbroek 			   struct packet *packet, struct lease *lease,
3287*83ee113eSDavid van Moolenbroek 			   struct client_state *client_state,
3288*83ee113eSDavid van Moolenbroek 			   struct option_state *in_options,
3289*83ee113eSDavid van Moolenbroek 			   struct option_state *cfg_options,
3290*83ee113eSDavid van Moolenbroek 			   struct binding_scope **scope,
3291*83ee113eSDavid van Moolenbroek 			   struct universe *u, void *stuff)
3292*83ee113eSDavid van Moolenbroek {
3293*83ee113eSDavid van Moolenbroek 	struct envadd_state *es = stuff;
3294*83ee113eSDavid van Moolenbroek 	struct data_string data;
3295*83ee113eSDavid van Moolenbroek 	memset (&data, 0, sizeof data);
3296*83ee113eSDavid van Moolenbroek 
3297*83ee113eSDavid van Moolenbroek 	if (evaluate_option_cache (&data, packet, lease, client_state,
3298*83ee113eSDavid van Moolenbroek 				   in_options, cfg_options, scope, oc, MDL)) {
3299*83ee113eSDavid van Moolenbroek 		if (data.len) {
3300*83ee113eSDavid van Moolenbroek 			char name [256];
3301*83ee113eSDavid van Moolenbroek 			if (dhcp_option_ev_name (name, sizeof name,
3302*83ee113eSDavid van Moolenbroek 						 oc->option)) {
3303*83ee113eSDavid van Moolenbroek 				const char *value;
3304*83ee113eSDavid van Moolenbroek 				size_t length;
3305*83ee113eSDavid van Moolenbroek 				value = pretty_print_option(oc->option,
3306*83ee113eSDavid van Moolenbroek 							    data.data,
3307*83ee113eSDavid van Moolenbroek 							    data.len, 0, 0);
3308*83ee113eSDavid van Moolenbroek 				length = strlen(value);
3309*83ee113eSDavid van Moolenbroek 
3310*83ee113eSDavid van Moolenbroek 				if (check_option_values(oc->option->universe,
3311*83ee113eSDavid van Moolenbroek 							oc->option->code,
3312*83ee113eSDavid van Moolenbroek 							value, length) == 0) {
3313*83ee113eSDavid van Moolenbroek 					client_envadd(es->client, es->prefix,
3314*83ee113eSDavid van Moolenbroek 						      name, "%s", value);
3315*83ee113eSDavid van Moolenbroek 				} else {
3316*83ee113eSDavid van Moolenbroek 					log_error("suspect value in %s "
3317*83ee113eSDavid van Moolenbroek 						  "option - discarded",
3318*83ee113eSDavid van Moolenbroek 						  name);
3319*83ee113eSDavid van Moolenbroek 				}
3320*83ee113eSDavid van Moolenbroek 				data_string_forget (&data, MDL);
3321*83ee113eSDavid van Moolenbroek 			}
3322*83ee113eSDavid van Moolenbroek 		}
3323*83ee113eSDavid van Moolenbroek 	}
3324*83ee113eSDavid van Moolenbroek }
3325*83ee113eSDavid van Moolenbroek 
script_write_params(client,prefix,lease)3326*83ee113eSDavid van Moolenbroek void script_write_params (client, prefix, lease)
3327*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3328*83ee113eSDavid van Moolenbroek 	const char *prefix;
3329*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
3330*83ee113eSDavid van Moolenbroek {
3331*83ee113eSDavid van Moolenbroek 	int i;
3332*83ee113eSDavid van Moolenbroek 	struct data_string data;
3333*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
3334*83ee113eSDavid van Moolenbroek 	struct envadd_state es;
3335*83ee113eSDavid van Moolenbroek 
3336*83ee113eSDavid van Moolenbroek 	es.client = client;
3337*83ee113eSDavid van Moolenbroek 	es.prefix = prefix;
3338*83ee113eSDavid van Moolenbroek 
3339*83ee113eSDavid van Moolenbroek 	client_envadd (client,
3340*83ee113eSDavid van Moolenbroek 		       prefix, "ip_address", "%s", piaddr (lease -> address));
3341*83ee113eSDavid van Moolenbroek 
3342*83ee113eSDavid van Moolenbroek 	/* For the benefit of Linux (and operating systems which may
3343*83ee113eSDavid van Moolenbroek 	   have similar needs), compute the network address based on
3344*83ee113eSDavid van Moolenbroek 	   the supplied ip address and netmask, if provided.  Also
3345*83ee113eSDavid van Moolenbroek 	   compute the broadcast address (the host address all ones
3346*83ee113eSDavid van Moolenbroek 	   broadcast address, not the host address all zeroes
3347*83ee113eSDavid van Moolenbroek 	   broadcast address). */
3348*83ee113eSDavid van Moolenbroek 
3349*83ee113eSDavid van Moolenbroek 	memset (&data, 0, sizeof data);
3350*83ee113eSDavid van Moolenbroek 	oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
3351*83ee113eSDavid van Moolenbroek 	if (oc && evaluate_option_cache (&data, (struct packet *)0,
3352*83ee113eSDavid van Moolenbroek 					 (struct lease *)0, client,
3353*83ee113eSDavid van Moolenbroek 					 (struct option_state *)0,
3354*83ee113eSDavid van Moolenbroek 					 lease -> options,
3355*83ee113eSDavid van Moolenbroek 					 &global_scope, oc, MDL)) {
3356*83ee113eSDavid van Moolenbroek 		if (data.len > 3) {
3357*83ee113eSDavid van Moolenbroek 			struct iaddr netmask, subnet, broadcast;
3358*83ee113eSDavid van Moolenbroek 
3359*83ee113eSDavid van Moolenbroek 			/*
3360*83ee113eSDavid van Moolenbroek 			 * No matter the length of the subnet-mask option,
3361*83ee113eSDavid van Moolenbroek 			 * use only the first four octets.  Note that
3362*83ee113eSDavid van Moolenbroek 			 * subnet-mask options longer than 4 octets are not
3363*83ee113eSDavid van Moolenbroek 			 * in conformance with RFC 2132, but servers with this
3364*83ee113eSDavid van Moolenbroek 			 * flaw do exist.
3365*83ee113eSDavid van Moolenbroek 			 */
3366*83ee113eSDavid van Moolenbroek 			memcpy(netmask.iabuf, data.data, 4);
3367*83ee113eSDavid van Moolenbroek 			netmask.len = 4;
3368*83ee113eSDavid van Moolenbroek 			data_string_forget (&data, MDL);
3369*83ee113eSDavid van Moolenbroek 
3370*83ee113eSDavid van Moolenbroek 			subnet = subnet_number (lease -> address, netmask);
3371*83ee113eSDavid van Moolenbroek 			if (subnet.len) {
3372*83ee113eSDavid van Moolenbroek 			    client_envadd (client, prefix, "network_number",
3373*83ee113eSDavid van Moolenbroek 					   "%s", piaddr (subnet));
3374*83ee113eSDavid van Moolenbroek 
3375*83ee113eSDavid van Moolenbroek 			    oc = lookup_option (&dhcp_universe,
3376*83ee113eSDavid van Moolenbroek 						lease -> options,
3377*83ee113eSDavid van Moolenbroek 						DHO_BROADCAST_ADDRESS);
3378*83ee113eSDavid van Moolenbroek 			    if (!oc ||
3379*83ee113eSDavid van Moolenbroek 				!(evaluate_option_cache
3380*83ee113eSDavid van Moolenbroek 				  (&data, (struct packet *)0,
3381*83ee113eSDavid van Moolenbroek 				   (struct lease *)0, client,
3382*83ee113eSDavid van Moolenbroek 				   (struct option_state *)0,
3383*83ee113eSDavid van Moolenbroek 				   lease -> options,
3384*83ee113eSDavid van Moolenbroek 				   &global_scope, oc, MDL))) {
3385*83ee113eSDavid van Moolenbroek 				broadcast = broadcast_addr (subnet, netmask);
3386*83ee113eSDavid van Moolenbroek 				if (broadcast.len) {
3387*83ee113eSDavid van Moolenbroek 				    client_envadd (client,
3388*83ee113eSDavid van Moolenbroek 						   prefix, "broadcast_address",
3389*83ee113eSDavid van Moolenbroek 						   "%s", piaddr (broadcast));
3390*83ee113eSDavid van Moolenbroek 				}
3391*83ee113eSDavid van Moolenbroek 			    }
3392*83ee113eSDavid van Moolenbroek 			}
3393*83ee113eSDavid van Moolenbroek 		}
3394*83ee113eSDavid van Moolenbroek 		data_string_forget (&data, MDL);
3395*83ee113eSDavid van Moolenbroek 	}
3396*83ee113eSDavid van Moolenbroek 
3397*83ee113eSDavid van Moolenbroek 	if (lease->filename) {
3398*83ee113eSDavid van Moolenbroek 		if (check_option_values(NULL, DHO_ROOT_PATH,
3399*83ee113eSDavid van Moolenbroek 					lease->filename,
3400*83ee113eSDavid van Moolenbroek 					strlen(lease->filename)) == 0) {
3401*83ee113eSDavid van Moolenbroek 			client_envadd(client, prefix, "filename",
3402*83ee113eSDavid van Moolenbroek 				      "%s", lease->filename);
3403*83ee113eSDavid van Moolenbroek 		} else {
3404*83ee113eSDavid van Moolenbroek 			log_error("suspect value in %s "
3405*83ee113eSDavid van Moolenbroek 				  "option - discarded",
3406*83ee113eSDavid van Moolenbroek 				  lease->filename);
3407*83ee113eSDavid van Moolenbroek 		}
3408*83ee113eSDavid van Moolenbroek 	}
3409*83ee113eSDavid van Moolenbroek 
3410*83ee113eSDavid van Moolenbroek 	if (lease->server_name) {
3411*83ee113eSDavid van Moolenbroek 		if (check_option_values(NULL, DHO_HOST_NAME,
3412*83ee113eSDavid van Moolenbroek 					lease->server_name,
3413*83ee113eSDavid van Moolenbroek 					strlen(lease->server_name)) == 0 ) {
3414*83ee113eSDavid van Moolenbroek 			client_envadd (client, prefix, "server_name",
3415*83ee113eSDavid van Moolenbroek 				       "%s", lease->server_name);
3416*83ee113eSDavid van Moolenbroek 		} else {
3417*83ee113eSDavid van Moolenbroek 			log_error("suspect value in %s "
3418*83ee113eSDavid van Moolenbroek 				  "option - discarded",
3419*83ee113eSDavid van Moolenbroek 				  lease->server_name);
3420*83ee113eSDavid van Moolenbroek 		}
3421*83ee113eSDavid van Moolenbroek 	}
3422*83ee113eSDavid van Moolenbroek 
3423*83ee113eSDavid van Moolenbroek 	for (i = 0; i < lease -> options -> universe_count; i++) {
3424*83ee113eSDavid van Moolenbroek 		option_space_foreach ((struct packet *)0, (struct lease *)0,
3425*83ee113eSDavid van Moolenbroek 				      client, (struct option_state *)0,
3426*83ee113eSDavid van Moolenbroek 				      lease -> options, &global_scope,
3427*83ee113eSDavid van Moolenbroek 				      universes [i],
3428*83ee113eSDavid van Moolenbroek 				      &es, client_option_envadd);
3429*83ee113eSDavid van Moolenbroek 	}
3430*83ee113eSDavid van Moolenbroek 	client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
3431*83ee113eSDavid van Moolenbroek }
3432*83ee113eSDavid van Moolenbroek 
3433*83ee113eSDavid van Moolenbroek /*
3434*83ee113eSDavid van Moolenbroek  * Write out the environment variables for the objects that the
3435*83ee113eSDavid van Moolenbroek  * client requested.  If the object was requested the variable will be:
3436*83ee113eSDavid van Moolenbroek  * requested_<option_name>=1
3437*83ee113eSDavid van Moolenbroek  * If it wasn't requested there won't be a variable.
3438*83ee113eSDavid van Moolenbroek  */
script_write_requested(client)3439*83ee113eSDavid van Moolenbroek void script_write_requested(client)
3440*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3441*83ee113eSDavid van Moolenbroek {
3442*83ee113eSDavid van Moolenbroek 	int i;
3443*83ee113eSDavid van Moolenbroek 	struct option **req;
3444*83ee113eSDavid van Moolenbroek 	char name[256];
3445*83ee113eSDavid van Moolenbroek 	req = client->config->requested_options;
3446*83ee113eSDavid van Moolenbroek 
3447*83ee113eSDavid van Moolenbroek 	if (req == NULL)
3448*83ee113eSDavid van Moolenbroek 		return;
3449*83ee113eSDavid van Moolenbroek 
3450*83ee113eSDavid van Moolenbroek 	for (i = 0 ; req[i] != NULL ; i++) {
3451*83ee113eSDavid van Moolenbroek 		if ((req[i]->universe == &dhcp_universe) &&
3452*83ee113eSDavid van Moolenbroek 		    dhcp_option_ev_name(name, sizeof(name), req[i])) {
3453*83ee113eSDavid van Moolenbroek 			client_envadd(client, "requested_", name, "%d", 1);
3454*83ee113eSDavid van Moolenbroek 		}
3455*83ee113eSDavid van Moolenbroek 	}
3456*83ee113eSDavid van Moolenbroek }
3457*83ee113eSDavid van Moolenbroek 
script_go(client)3458*83ee113eSDavid van Moolenbroek int script_go (client)
3459*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3460*83ee113eSDavid van Moolenbroek {
3461*83ee113eSDavid van Moolenbroek 	char *scriptName;
3462*83ee113eSDavid van Moolenbroek 	char *argv [2];
3463*83ee113eSDavid van Moolenbroek 	char **envp;
3464*83ee113eSDavid van Moolenbroek 	char reason [] = "REASON=NBI";
3465*83ee113eSDavid van Moolenbroek 	static char client_path [] = CLIENT_PATH;
3466*83ee113eSDavid van Moolenbroek 	int i;
3467*83ee113eSDavid van Moolenbroek 	struct string_list *sp, *next;
3468*83ee113eSDavid van Moolenbroek 	int pid, wpid, wstatus;
3469*83ee113eSDavid van Moolenbroek 
3470*83ee113eSDavid van Moolenbroek 	if (client)
3471*83ee113eSDavid van Moolenbroek 		scriptName = client -> config -> script_name;
3472*83ee113eSDavid van Moolenbroek 	else
3473*83ee113eSDavid van Moolenbroek 		scriptName = top_level_config.script_name;
3474*83ee113eSDavid van Moolenbroek 
3475*83ee113eSDavid van Moolenbroek 	envp = dmalloc (((client ? client -> envc : 2) +
3476*83ee113eSDavid van Moolenbroek 			 client_env_count + 2) * sizeof (char *), MDL);
3477*83ee113eSDavid van Moolenbroek 	if (!envp) {
3478*83ee113eSDavid van Moolenbroek 		log_error ("No memory for client script environment.");
3479*83ee113eSDavid van Moolenbroek 		return 0;
3480*83ee113eSDavid van Moolenbroek 	}
3481*83ee113eSDavid van Moolenbroek 	i = 0;
3482*83ee113eSDavid van Moolenbroek 	/* Copy out the environment specified on the command line,
3483*83ee113eSDavid van Moolenbroek 	   if any. */
3484*83ee113eSDavid van Moolenbroek 	for (sp = client_env; sp; sp = sp -> next) {
3485*83ee113eSDavid van Moolenbroek 		envp [i++] = sp -> string;
3486*83ee113eSDavid van Moolenbroek 	}
3487*83ee113eSDavid van Moolenbroek 	/* Copy out the environment specified by dhclient. */
3488*83ee113eSDavid van Moolenbroek 	if (client) {
3489*83ee113eSDavid van Moolenbroek 		for (sp = client -> env; sp; sp = sp -> next) {
3490*83ee113eSDavid van Moolenbroek 			envp [i++] = sp -> string;
3491*83ee113eSDavid van Moolenbroek 		}
3492*83ee113eSDavid van Moolenbroek 	} else {
3493*83ee113eSDavid van Moolenbroek 		envp [i++] = reason;
3494*83ee113eSDavid van Moolenbroek 	}
3495*83ee113eSDavid van Moolenbroek 	/* Set $PATH. */
3496*83ee113eSDavid van Moolenbroek 	envp [i++] = client_path;
3497*83ee113eSDavid van Moolenbroek 	envp [i] = (char *)0;
3498*83ee113eSDavid van Moolenbroek 
3499*83ee113eSDavid van Moolenbroek 	argv [0] = scriptName;
3500*83ee113eSDavid van Moolenbroek 	argv [1] = (char *)0;
3501*83ee113eSDavid van Moolenbroek 
3502*83ee113eSDavid van Moolenbroek 	pid = fork ();
3503*83ee113eSDavid van Moolenbroek 	if (pid < 0) {
3504*83ee113eSDavid van Moolenbroek 		log_error ("fork: %m");
3505*83ee113eSDavid van Moolenbroek 		wstatus = 0;
3506*83ee113eSDavid van Moolenbroek 	} else if (pid) {
3507*83ee113eSDavid van Moolenbroek 		do {
3508*83ee113eSDavid van Moolenbroek 			wpid = wait (&wstatus);
3509*83ee113eSDavid van Moolenbroek 		} while (wpid != pid && wpid > 0);
3510*83ee113eSDavid van Moolenbroek 		if (wpid < 0) {
3511*83ee113eSDavid van Moolenbroek 			log_error ("wait: %m");
3512*83ee113eSDavid van Moolenbroek 			wstatus = 0;
3513*83ee113eSDavid van Moolenbroek 		}
3514*83ee113eSDavid van Moolenbroek 	} else {
3515*83ee113eSDavid van Moolenbroek 		/* We don't want to pass an open file descriptor for
3516*83ee113eSDavid van Moolenbroek 		 * dhclient.leases when executing dhclient-script.
3517*83ee113eSDavid van Moolenbroek 		 */
3518*83ee113eSDavid van Moolenbroek 		if (leaseFile != NULL)
3519*83ee113eSDavid van Moolenbroek 			fclose(leaseFile);
3520*83ee113eSDavid van Moolenbroek 		execve (scriptName, argv, envp);
3521*83ee113eSDavid van Moolenbroek 		log_error ("execve (%s, ...): %m", scriptName);
3522*83ee113eSDavid van Moolenbroek 		exit (0);
3523*83ee113eSDavid van Moolenbroek 	}
3524*83ee113eSDavid van Moolenbroek 
3525*83ee113eSDavid van Moolenbroek 	if (client) {
3526*83ee113eSDavid van Moolenbroek 		for (sp = client -> env; sp; sp = next) {
3527*83ee113eSDavid van Moolenbroek 			next = sp -> next;
3528*83ee113eSDavid van Moolenbroek 			dfree (sp, MDL);
3529*83ee113eSDavid van Moolenbroek 		}
3530*83ee113eSDavid van Moolenbroek 		client -> env = (struct string_list *)0;
3531*83ee113eSDavid van Moolenbroek 		client -> envc = 0;
3532*83ee113eSDavid van Moolenbroek 	}
3533*83ee113eSDavid van Moolenbroek 	dfree (envp, MDL);
3534*83ee113eSDavid van Moolenbroek 	gettimeofday(&cur_tv, NULL);
3535*83ee113eSDavid van Moolenbroek 	return (WIFEXITED (wstatus) ?
3536*83ee113eSDavid van Moolenbroek 		WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
3537*83ee113eSDavid van Moolenbroek }
3538*83ee113eSDavid van Moolenbroek 
client_envadd(struct client_state * client,const char * prefix,const char * name,const char * fmt,...)3539*83ee113eSDavid van Moolenbroek void client_envadd (struct client_state *client,
3540*83ee113eSDavid van Moolenbroek 		    const char *prefix, const char *name, const char *fmt, ...)
3541*83ee113eSDavid van Moolenbroek {
3542*83ee113eSDavid van Moolenbroek 	char spbuf [1024];
3543*83ee113eSDavid van Moolenbroek 	char *s;
3544*83ee113eSDavid van Moolenbroek 	unsigned len;
3545*83ee113eSDavid van Moolenbroek 	struct string_list *val;
3546*83ee113eSDavid van Moolenbroek 	va_list list;
3547*83ee113eSDavid van Moolenbroek 
3548*83ee113eSDavid van Moolenbroek 	va_start (list, fmt);
3549*83ee113eSDavid van Moolenbroek 	len = vsnprintf (spbuf, sizeof spbuf, fmt, list);
3550*83ee113eSDavid van Moolenbroek 	va_end (list);
3551*83ee113eSDavid van Moolenbroek 
3552*83ee113eSDavid van Moolenbroek 	val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
3553*83ee113eSDavid van Moolenbroek 		       len + sizeof *val, MDL);
3554*83ee113eSDavid van Moolenbroek 	if (!val)
3555*83ee113eSDavid van Moolenbroek 		return;
3556*83ee113eSDavid van Moolenbroek 	s = val -> string;
3557*83ee113eSDavid van Moolenbroek 	strcpy (s, prefix);
3558*83ee113eSDavid van Moolenbroek 	strcat (s, name);
3559*83ee113eSDavid van Moolenbroek 	s += strlen (s);
3560*83ee113eSDavid van Moolenbroek 	*s++ = '=';
3561*83ee113eSDavid van Moolenbroek 	if (len >= sizeof spbuf) {
3562*83ee113eSDavid van Moolenbroek 		va_start (list, fmt);
3563*83ee113eSDavid van Moolenbroek 		vsnprintf (s, len + 1, fmt, list);
3564*83ee113eSDavid van Moolenbroek 		va_end (list);
3565*83ee113eSDavid van Moolenbroek 	} else
3566*83ee113eSDavid van Moolenbroek 		strcpy (s, spbuf);
3567*83ee113eSDavid van Moolenbroek 	val -> next = client -> env;
3568*83ee113eSDavid van Moolenbroek 	client -> env = val;
3569*83ee113eSDavid van Moolenbroek 	client -> envc++;
3570*83ee113eSDavid van Moolenbroek }
3571*83ee113eSDavid van Moolenbroek 
dhcp_option_ev_name(buf,buflen,option)3572*83ee113eSDavid van Moolenbroek int dhcp_option_ev_name (buf, buflen, option)
3573*83ee113eSDavid van Moolenbroek 	char *buf;
3574*83ee113eSDavid van Moolenbroek 	size_t buflen;
3575*83ee113eSDavid van Moolenbroek 	struct option *option;
3576*83ee113eSDavid van Moolenbroek {
3577*83ee113eSDavid van Moolenbroek 	int i, j;
3578*83ee113eSDavid van Moolenbroek 	const char *s;
3579*83ee113eSDavid van Moolenbroek 
3580*83ee113eSDavid van Moolenbroek 	j = 0;
3581*83ee113eSDavid van Moolenbroek 	if (option -> universe != &dhcp_universe) {
3582*83ee113eSDavid van Moolenbroek 		s = option -> universe -> name;
3583*83ee113eSDavid van Moolenbroek 		i = 0;
3584*83ee113eSDavid van Moolenbroek 	} else {
3585*83ee113eSDavid van Moolenbroek 		s = option -> name;
3586*83ee113eSDavid van Moolenbroek 		i = 1;
3587*83ee113eSDavid van Moolenbroek 	}
3588*83ee113eSDavid van Moolenbroek 
3589*83ee113eSDavid van Moolenbroek 	do {
3590*83ee113eSDavid van Moolenbroek 		while (*s) {
3591*83ee113eSDavid van Moolenbroek 			if (j + 1 == buflen)
3592*83ee113eSDavid van Moolenbroek 				return 0;
3593*83ee113eSDavid van Moolenbroek 			if (*s == '-')
3594*83ee113eSDavid van Moolenbroek 				buf [j++] = '_';
3595*83ee113eSDavid van Moolenbroek 			else
3596*83ee113eSDavid van Moolenbroek 				buf [j++] = *s;
3597*83ee113eSDavid van Moolenbroek 			++s;
3598*83ee113eSDavid van Moolenbroek 		}
3599*83ee113eSDavid van Moolenbroek 		if (!i) {
3600*83ee113eSDavid van Moolenbroek 			s = option -> name;
3601*83ee113eSDavid van Moolenbroek 			if (j + 1 == buflen)
3602*83ee113eSDavid van Moolenbroek 				return 0;
3603*83ee113eSDavid van Moolenbroek 			buf [j++] = '_';
3604*83ee113eSDavid van Moolenbroek 		}
3605*83ee113eSDavid van Moolenbroek 		++i;
3606*83ee113eSDavid van Moolenbroek 	} while (i != 2);
3607*83ee113eSDavid van Moolenbroek 
3608*83ee113eSDavid van Moolenbroek 	buf [j] = 0;
3609*83ee113eSDavid van Moolenbroek 	return 1;
3610*83ee113eSDavid van Moolenbroek }
3611*83ee113eSDavid van Moolenbroek 
3612*83ee113eSDavid van Moolenbroek static int pfd[2];
finish_daemon(void)3613*83ee113eSDavid van Moolenbroek void finish_daemon (void)
3614*83ee113eSDavid van Moolenbroek {
3615*83ee113eSDavid van Moolenbroek 	static int state = 0;
3616*83ee113eSDavid van Moolenbroek 
3617*83ee113eSDavid van Moolenbroek 	if (no_daemon)
3618*83ee113eSDavid van Moolenbroek 		return;
3619*83ee113eSDavid van Moolenbroek 
3620*83ee113eSDavid van Moolenbroek 	if (interfaces_left && --interfaces_left)
3621*83ee113eSDavid van Moolenbroek 		return;
3622*83ee113eSDavid van Moolenbroek 
3623*83ee113eSDavid van Moolenbroek 	/* Only do it once. */
3624*83ee113eSDavid van Moolenbroek 	if (state)
3625*83ee113eSDavid van Moolenbroek 		return;
3626*83ee113eSDavid van Moolenbroek 	state = 1;
3627*83ee113eSDavid van Moolenbroek 
3628*83ee113eSDavid van Moolenbroek 	/* Stop logging to stderr... */
3629*83ee113eSDavid van Moolenbroek 	log_perror = 0;
3630*83ee113eSDavid van Moolenbroek 
3631*83ee113eSDavid van Moolenbroek 	/* Become session leader and get pid... */
3632*83ee113eSDavid van Moolenbroek 	(void) setsid();
3633*83ee113eSDavid van Moolenbroek 
3634*83ee113eSDavid van Moolenbroek 	/* Close standard I/O descriptors. */
3635*83ee113eSDavid van Moolenbroek 	(void) close(0);
3636*83ee113eSDavid van Moolenbroek 	(void) close(1);
3637*83ee113eSDavid van Moolenbroek 	(void) close(2);
3638*83ee113eSDavid van Moolenbroek 
3639*83ee113eSDavid van Moolenbroek 	/* Reopen them on /dev/null. */
3640*83ee113eSDavid van Moolenbroek 	(void) open("/dev/null", O_RDWR);
3641*83ee113eSDavid van Moolenbroek 	(void) open("/dev/null", O_RDWR);
3642*83ee113eSDavid van Moolenbroek 	(void) open("/dev/null", O_RDWR);
3643*83ee113eSDavid van Moolenbroek 
3644*83ee113eSDavid van Moolenbroek 	write_client_pid_file ();
3645*83ee113eSDavid van Moolenbroek 
3646*83ee113eSDavid van Moolenbroek 	IGNORE_RET (chdir("/"));
3647*83ee113eSDavid van Moolenbroek 	write(pfd[0], "X", 1);
3648*83ee113eSDavid van Moolenbroek 	close(pfd[0]);
3649*83ee113eSDavid van Moolenbroek }
3650*83ee113eSDavid van Moolenbroek 
go_daemon(void)3651*83ee113eSDavid van Moolenbroek void go_daemon (void)
3652*83ee113eSDavid van Moolenbroek {
3653*83ee113eSDavid van Moolenbroek 	pid_t pid;
3654*83ee113eSDavid van Moolenbroek 
3655*83ee113eSDavid van Moolenbroek 	/* Don't become a daemon if the user requested otherwise. */
3656*83ee113eSDavid van Moolenbroek 	if (no_daemon) {
3657*83ee113eSDavid van Moolenbroek 		write_client_pid_file ();
3658*83ee113eSDavid van Moolenbroek 		return;
3659*83ee113eSDavid van Moolenbroek 	}
3660*83ee113eSDavid van Moolenbroek 
3661*83ee113eSDavid van Moolenbroek 
3662*83ee113eSDavid van Moolenbroek 	if (pipe(pfd) == -1)
3663*83ee113eSDavid van Moolenbroek 		log_fatal ("Can't pipe to child: %m");
3664*83ee113eSDavid van Moolenbroek 	/* Become a daemon... */
3665*83ee113eSDavid van Moolenbroek 	if ((pid = fork ()) < 0)
3666*83ee113eSDavid van Moolenbroek 		log_fatal ("Can't fork daemon: %m");
3667*83ee113eSDavid van Moolenbroek 	else if (pid) {
3668*83ee113eSDavid van Moolenbroek 		char c;
3669*83ee113eSDavid van Moolenbroek 		close(pfd[0]);
3670*83ee113eSDavid van Moolenbroek 		read(pfd[1], &c, 1);
3671*83ee113eSDavid van Moolenbroek 		exit (0);
3672*83ee113eSDavid van Moolenbroek 	} else
3673*83ee113eSDavid van Moolenbroek 		close(pfd[1]);
3674*83ee113eSDavid van Moolenbroek }
3675*83ee113eSDavid van Moolenbroek 
write_client_pid_file()3676*83ee113eSDavid van Moolenbroek void write_client_pid_file ()
3677*83ee113eSDavid van Moolenbroek {
3678*83ee113eSDavid van Moolenbroek 	FILE *pf;
3679*83ee113eSDavid van Moolenbroek 	int pfdesc;
3680*83ee113eSDavid van Moolenbroek 
3681*83ee113eSDavid van Moolenbroek 	/* nothing to do if the user doesn't want a pid file */
3682*83ee113eSDavid van Moolenbroek 	if (path_dhclient_pid == NULL || no_pid_file == ISC_TRUE) {
3683*83ee113eSDavid van Moolenbroek 		return;
3684*83ee113eSDavid van Moolenbroek 	}
3685*83ee113eSDavid van Moolenbroek 
3686*83ee113eSDavid van Moolenbroek 	pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
3687*83ee113eSDavid van Moolenbroek 
3688*83ee113eSDavid van Moolenbroek 	if (pfdesc < 0) {
3689*83ee113eSDavid van Moolenbroek 		log_error ("Can't create %s: %m", path_dhclient_pid);
3690*83ee113eSDavid van Moolenbroek 		return;
3691*83ee113eSDavid van Moolenbroek 	}
3692*83ee113eSDavid van Moolenbroek 
3693*83ee113eSDavid van Moolenbroek 	pf = fdopen (pfdesc, "w");
3694*83ee113eSDavid van Moolenbroek 	if (!pf) {
3695*83ee113eSDavid van Moolenbroek 		close(pfdesc);
3696*83ee113eSDavid van Moolenbroek 		log_error ("Can't fdopen %s: %m", path_dhclient_pid);
3697*83ee113eSDavid van Moolenbroek 	} else {
3698*83ee113eSDavid van Moolenbroek 		fprintf (pf, "%ld\n", (long)getpid ());
3699*83ee113eSDavid van Moolenbroek 		fclose (pf);
3700*83ee113eSDavid van Moolenbroek 	}
3701*83ee113eSDavid van Moolenbroek }
3702*83ee113eSDavid van Moolenbroek 
client_location_changed()3703*83ee113eSDavid van Moolenbroek void client_location_changed ()
3704*83ee113eSDavid van Moolenbroek {
3705*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
3706*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3707*83ee113eSDavid van Moolenbroek 
3708*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip -> next) {
3709*83ee113eSDavid van Moolenbroek 		for (client = ip -> client; client; client = client -> next) {
3710*83ee113eSDavid van Moolenbroek 			switch (client -> state) {
3711*83ee113eSDavid van Moolenbroek 			      case S_SELECTING:
3712*83ee113eSDavid van Moolenbroek 				cancel_timeout (send_discover, client);
3713*83ee113eSDavid van Moolenbroek 				break;
3714*83ee113eSDavid van Moolenbroek 
3715*83ee113eSDavid van Moolenbroek 			      case S_BOUND:
3716*83ee113eSDavid van Moolenbroek 				cancel_timeout (state_bound, client);
3717*83ee113eSDavid van Moolenbroek 				break;
3718*83ee113eSDavid van Moolenbroek 
3719*83ee113eSDavid van Moolenbroek 			      case S_REBOOTING:
3720*83ee113eSDavid van Moolenbroek 			      case S_REQUESTING:
3721*83ee113eSDavid van Moolenbroek 			      case S_RENEWING:
3722*83ee113eSDavid van Moolenbroek 				cancel_timeout (send_request, client);
3723*83ee113eSDavid van Moolenbroek 				break;
3724*83ee113eSDavid van Moolenbroek 
3725*83ee113eSDavid van Moolenbroek 			      case S_INIT:
3726*83ee113eSDavid van Moolenbroek 			      case S_REBINDING:
3727*83ee113eSDavid van Moolenbroek 			      case S_STOPPED:
3728*83ee113eSDavid van Moolenbroek 				break;
3729*83ee113eSDavid van Moolenbroek 			}
3730*83ee113eSDavid van Moolenbroek 			client -> state = S_INIT;
3731*83ee113eSDavid van Moolenbroek 			state_reboot (client);
3732*83ee113eSDavid van Moolenbroek 		}
3733*83ee113eSDavid van Moolenbroek 	}
3734*83ee113eSDavid van Moolenbroek }
3735*83ee113eSDavid van Moolenbroek 
do_release(client)3736*83ee113eSDavid van Moolenbroek void do_release(client)
3737*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3738*83ee113eSDavid van Moolenbroek {
3739*83ee113eSDavid van Moolenbroek 	struct data_string ds;
3740*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
3741*83ee113eSDavid van Moolenbroek 
3742*83ee113eSDavid van Moolenbroek 	/* Pick a random xid. */
3743*83ee113eSDavid van Moolenbroek 	client -> xid = random ();
3744*83ee113eSDavid van Moolenbroek 
3745*83ee113eSDavid van Moolenbroek 	/* is there even a lease to release? */
3746*83ee113eSDavid van Moolenbroek 	if (client -> active) {
3747*83ee113eSDavid van Moolenbroek 		/* Make a DHCPRELEASE packet, and set appropriate per-interface
3748*83ee113eSDavid van Moolenbroek 		   flags. */
3749*83ee113eSDavid van Moolenbroek 		make_release (client, client -> active);
3750*83ee113eSDavid van Moolenbroek 
3751*83ee113eSDavid van Moolenbroek 		memset (&ds, 0, sizeof ds);
3752*83ee113eSDavid van Moolenbroek 		oc = lookup_option (&dhcp_universe,
3753*83ee113eSDavid van Moolenbroek 				    client -> active -> options,
3754*83ee113eSDavid van Moolenbroek 				    DHO_DHCP_SERVER_IDENTIFIER);
3755*83ee113eSDavid van Moolenbroek 		if (oc &&
3756*83ee113eSDavid van Moolenbroek 		    evaluate_option_cache (&ds, (struct packet *)0,
3757*83ee113eSDavid van Moolenbroek 					   (struct lease *)0, client,
3758*83ee113eSDavid van Moolenbroek 					   (struct option_state *)0,
3759*83ee113eSDavid van Moolenbroek 					   client -> active -> options,
3760*83ee113eSDavid van Moolenbroek 					   &global_scope, oc, MDL)) {
3761*83ee113eSDavid van Moolenbroek 			if (ds.len > 3) {
3762*83ee113eSDavid van Moolenbroek 				memcpy (client -> destination.iabuf,
3763*83ee113eSDavid van Moolenbroek 					ds.data, 4);
3764*83ee113eSDavid van Moolenbroek 				client -> destination.len = 4;
3765*83ee113eSDavid van Moolenbroek 			} else
3766*83ee113eSDavid van Moolenbroek 				client -> destination = iaddr_broadcast;
3767*83ee113eSDavid van Moolenbroek 
3768*83ee113eSDavid van Moolenbroek 			data_string_forget (&ds, MDL);
3769*83ee113eSDavid van Moolenbroek 		} else
3770*83ee113eSDavid van Moolenbroek 			client -> destination = iaddr_broadcast;
3771*83ee113eSDavid van Moolenbroek 		client -> first_sending = cur_time;
3772*83ee113eSDavid van Moolenbroek 		client -> interval = client -> config -> initial_interval;
3773*83ee113eSDavid van Moolenbroek 
3774*83ee113eSDavid van Moolenbroek 		/* Zap the medium list... */
3775*83ee113eSDavid van Moolenbroek 		client -> medium = (struct string_list *)0;
3776*83ee113eSDavid van Moolenbroek 
3777*83ee113eSDavid van Moolenbroek 		/* Send out the first and only DHCPRELEASE packet. */
3778*83ee113eSDavid van Moolenbroek 		send_release (client);
3779*83ee113eSDavid van Moolenbroek 
3780*83ee113eSDavid van Moolenbroek 		/* Do the client script RELEASE operation. */
3781*83ee113eSDavid van Moolenbroek 		script_init (client,
3782*83ee113eSDavid van Moolenbroek 			     "RELEASE", (struct string_list *)0);
3783*83ee113eSDavid van Moolenbroek 		if (client -> alias)
3784*83ee113eSDavid van Moolenbroek 			script_write_params (client, "alias_",
3785*83ee113eSDavid van Moolenbroek 					     client -> alias);
3786*83ee113eSDavid van Moolenbroek 		script_write_params (client, "old_", client -> active);
3787*83ee113eSDavid van Moolenbroek 		script_write_requested(client);
3788*83ee113eSDavid van Moolenbroek 		script_go (client);
3789*83ee113eSDavid van Moolenbroek 	}
3790*83ee113eSDavid van Moolenbroek 
3791*83ee113eSDavid van Moolenbroek 	/* Cancel any timeouts. */
3792*83ee113eSDavid van Moolenbroek 	cancel_timeout (state_bound, client);
3793*83ee113eSDavid van Moolenbroek 	cancel_timeout (send_discover, client);
3794*83ee113eSDavid van Moolenbroek 	cancel_timeout (state_init, client);
3795*83ee113eSDavid van Moolenbroek 	cancel_timeout (send_request, client);
3796*83ee113eSDavid van Moolenbroek 	cancel_timeout (state_reboot, client);
3797*83ee113eSDavid van Moolenbroek 	client -> state = S_STOPPED;
3798*83ee113eSDavid van Moolenbroek }
3799*83ee113eSDavid van Moolenbroek 
dhclient_interface_shutdown_hook(struct interface_info * interface)3800*83ee113eSDavid van Moolenbroek int dhclient_interface_shutdown_hook (struct interface_info *interface)
3801*83ee113eSDavid van Moolenbroek {
3802*83ee113eSDavid van Moolenbroek 	do_release (interface -> client);
3803*83ee113eSDavid van Moolenbroek 
3804*83ee113eSDavid van Moolenbroek 	return 1;
3805*83ee113eSDavid van Moolenbroek }
3806*83ee113eSDavid van Moolenbroek 
dhclient_interface_discovery_hook(struct interface_info * tmp)3807*83ee113eSDavid van Moolenbroek int dhclient_interface_discovery_hook (struct interface_info *tmp)
3808*83ee113eSDavid van Moolenbroek {
3809*83ee113eSDavid van Moolenbroek 	struct interface_info *last, *ip;
3810*83ee113eSDavid van Moolenbroek 	/* See if we can find the client from dummy_interfaces */
3811*83ee113eSDavid van Moolenbroek 	last = 0;
3812*83ee113eSDavid van Moolenbroek 	for (ip = dummy_interfaces; ip; ip = ip -> next) {
3813*83ee113eSDavid van Moolenbroek 		if (!strcmp (ip -> name, tmp -> name)) {
3814*83ee113eSDavid van Moolenbroek 			/* Remove from dummy_interfaces */
3815*83ee113eSDavid van Moolenbroek 			if (last) {
3816*83ee113eSDavid van Moolenbroek 				ip = (struct interface_info *)0;
3817*83ee113eSDavid van Moolenbroek 				interface_reference (&ip, last -> next, MDL);
3818*83ee113eSDavid van Moolenbroek 				interface_dereference (&last -> next, MDL);
3819*83ee113eSDavid van Moolenbroek 				if (ip -> next) {
3820*83ee113eSDavid van Moolenbroek 					interface_reference (&last -> next,
3821*83ee113eSDavid van Moolenbroek 							     ip -> next, MDL);
3822*83ee113eSDavid van Moolenbroek 					interface_dereference (&ip -> next,
3823*83ee113eSDavid van Moolenbroek 							       MDL);
3824*83ee113eSDavid van Moolenbroek 				}
3825*83ee113eSDavid van Moolenbroek 			} else {
3826*83ee113eSDavid van Moolenbroek 				ip = (struct interface_info *)0;
3827*83ee113eSDavid van Moolenbroek 				interface_reference (&ip,
3828*83ee113eSDavid van Moolenbroek 						     dummy_interfaces, MDL);
3829*83ee113eSDavid van Moolenbroek 				interface_dereference (&dummy_interfaces, MDL);
3830*83ee113eSDavid van Moolenbroek 				if (ip -> next) {
3831*83ee113eSDavid van Moolenbroek 					interface_reference (&dummy_interfaces,
3832*83ee113eSDavid van Moolenbroek 							     ip -> next, MDL);
3833*83ee113eSDavid van Moolenbroek 					interface_dereference (&ip -> next,
3834*83ee113eSDavid van Moolenbroek 							       MDL);
3835*83ee113eSDavid van Moolenbroek 				}
3836*83ee113eSDavid van Moolenbroek 			}
3837*83ee113eSDavid van Moolenbroek 			/* Copy "client" to tmp */
3838*83ee113eSDavid van Moolenbroek 			if (ip -> client) {
3839*83ee113eSDavid van Moolenbroek 				tmp -> client = ip -> client;
3840*83ee113eSDavid van Moolenbroek 				tmp -> client -> interface = tmp;
3841*83ee113eSDavid van Moolenbroek 			}
3842*83ee113eSDavid van Moolenbroek 			interface_dereference (&ip, MDL);
3843*83ee113eSDavid van Moolenbroek 			break;
3844*83ee113eSDavid van Moolenbroek 		}
3845*83ee113eSDavid van Moolenbroek 		last = ip;
3846*83ee113eSDavid van Moolenbroek 	}
3847*83ee113eSDavid van Moolenbroek 	return 1;
3848*83ee113eSDavid van Moolenbroek }
3849*83ee113eSDavid van Moolenbroek 
dhclient_interface_startup_hook(struct interface_info * interface)3850*83ee113eSDavid van Moolenbroek isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
3851*83ee113eSDavid van Moolenbroek {
3852*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
3853*83ee113eSDavid van Moolenbroek 	struct client_state *client;
3854*83ee113eSDavid van Moolenbroek 
3855*83ee113eSDavid van Moolenbroek 	/* This code needs some rethinking.   It doesn't test against
3856*83ee113eSDavid van Moolenbroek 	   a signal name, and it just kind of bulls into doing something
3857*83ee113eSDavid van Moolenbroek 	   that may or may not be appropriate. */
3858*83ee113eSDavid van Moolenbroek 
3859*83ee113eSDavid van Moolenbroek 	if (interfaces) {
3860*83ee113eSDavid van Moolenbroek 		interface_reference (&interface -> next, interfaces, MDL);
3861*83ee113eSDavid van Moolenbroek 		interface_dereference (&interfaces, MDL);
3862*83ee113eSDavid van Moolenbroek 	}
3863*83ee113eSDavid van Moolenbroek 	interface_reference (&interfaces, interface, MDL);
3864*83ee113eSDavid van Moolenbroek 
3865*83ee113eSDavid van Moolenbroek 	discover_interfaces (DISCOVER_UNCONFIGURED);
3866*83ee113eSDavid van Moolenbroek 
3867*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip -> next) {
3868*83ee113eSDavid van Moolenbroek 		/* If interfaces were specified, don't configure
3869*83ee113eSDavid van Moolenbroek 		   interfaces that weren't specified! */
3870*83ee113eSDavid van Moolenbroek 		if (ip -> flags & INTERFACE_RUNNING ||
3871*83ee113eSDavid van Moolenbroek 		   (ip -> flags & (INTERFACE_REQUESTED |
3872*83ee113eSDavid van Moolenbroek 				     INTERFACE_AUTOMATIC)) !=
3873*83ee113eSDavid van Moolenbroek 		     INTERFACE_REQUESTED)
3874*83ee113eSDavid van Moolenbroek 			continue;
3875*83ee113eSDavid van Moolenbroek 		script_init (ip -> client,
3876*83ee113eSDavid van Moolenbroek 			     "PREINIT", (struct string_list *)0);
3877*83ee113eSDavid van Moolenbroek 		if (ip -> client -> alias)
3878*83ee113eSDavid van Moolenbroek 			script_write_params (ip -> client, "alias_",
3879*83ee113eSDavid van Moolenbroek 					     ip -> client -> alias);
3880*83ee113eSDavid van Moolenbroek 		script_go (ip -> client);
3881*83ee113eSDavid van Moolenbroek 	}
3882*83ee113eSDavid van Moolenbroek 
3883*83ee113eSDavid van Moolenbroek 	discover_interfaces (interfaces_requested != 0
3884*83ee113eSDavid van Moolenbroek 			     ? DISCOVER_REQUESTED
3885*83ee113eSDavid van Moolenbroek 			     : DISCOVER_RUNNING);
3886*83ee113eSDavid van Moolenbroek 
3887*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip -> next) {
3888*83ee113eSDavid van Moolenbroek 		if (ip -> flags & INTERFACE_RUNNING)
3889*83ee113eSDavid van Moolenbroek 			continue;
3890*83ee113eSDavid van Moolenbroek 		ip -> flags |= INTERFACE_RUNNING;
3891*83ee113eSDavid van Moolenbroek 		for (client = ip->client ; client ; client = client->next) {
3892*83ee113eSDavid van Moolenbroek 			client->state = S_INIT;
3893*83ee113eSDavid van Moolenbroek 			state_reboot(client);
3894*83ee113eSDavid van Moolenbroek 		}
3895*83ee113eSDavid van Moolenbroek 	}
3896*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
3897*83ee113eSDavid van Moolenbroek }
3898*83ee113eSDavid van Moolenbroek 
3899*83ee113eSDavid van Moolenbroek /* The client should never receive a relay agent information option,
3900*83ee113eSDavid van Moolenbroek    so if it does, log it and discard it. */
3901*83ee113eSDavid van Moolenbroek 
parse_agent_information_option(packet,len,data)3902*83ee113eSDavid van Moolenbroek int parse_agent_information_option (packet, len, data)
3903*83ee113eSDavid van Moolenbroek 	struct packet *packet;
3904*83ee113eSDavid van Moolenbroek 	int len;
3905*83ee113eSDavid van Moolenbroek 	u_int8_t *data;
3906*83ee113eSDavid van Moolenbroek {
3907*83ee113eSDavid van Moolenbroek 	return 1;
3908*83ee113eSDavid van Moolenbroek }
3909*83ee113eSDavid van Moolenbroek 
3910*83ee113eSDavid van Moolenbroek /* The client never sends relay agent information options. */
3911*83ee113eSDavid van Moolenbroek 
cons_agent_information_options(cfg_options,outpacket,agentix,length)3912*83ee113eSDavid van Moolenbroek unsigned cons_agent_information_options (cfg_options, outpacket,
3913*83ee113eSDavid van Moolenbroek 					 agentix, length)
3914*83ee113eSDavid van Moolenbroek 	struct option_state *cfg_options;
3915*83ee113eSDavid van Moolenbroek 	struct dhcp_packet *outpacket;
3916*83ee113eSDavid van Moolenbroek 	unsigned agentix;
3917*83ee113eSDavid van Moolenbroek 	unsigned length;
3918*83ee113eSDavid van Moolenbroek {
3919*83ee113eSDavid van Moolenbroek 	return length;
3920*83ee113eSDavid van Moolenbroek }
3921*83ee113eSDavid van Moolenbroek 
shutdown_exit(void * foo)3922*83ee113eSDavid van Moolenbroek static void shutdown_exit (void *foo)
3923*83ee113eSDavid van Moolenbroek {
3924*83ee113eSDavid van Moolenbroek 	exit (0);
3925*83ee113eSDavid van Moolenbroek }
3926*83ee113eSDavid van Moolenbroek 
3927*83ee113eSDavid van Moolenbroek #if defined (NSUPDATE)
3928*83ee113eSDavid van Moolenbroek /*
3929*83ee113eSDavid van Moolenbroek  * If the first query fails, the updater MUST NOT delete the DNS name.  It
3930*83ee113eSDavid van Moolenbroek  * may be that the host whose lease on the server has expired has moved
3931*83ee113eSDavid van Moolenbroek  * to another network and obtained a lease from a different server,
3932*83ee113eSDavid van Moolenbroek  * which has caused the client's A RR to be replaced. It may also be
3933*83ee113eSDavid van Moolenbroek  * that some other client has been configured with a name that matches
3934*83ee113eSDavid van Moolenbroek  * the name of the DHCP client, and the policy was that the last client
3935*83ee113eSDavid van Moolenbroek  * to specify the name would get the name.  In this case, the DHCID RR
3936*83ee113eSDavid van Moolenbroek  * will no longer match the updater's notion of the client-identity of
3937*83ee113eSDavid van Moolenbroek  * the host pointed to by the DNS name.
3938*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
3939*83ee113eSDavid van Moolenbroek  */
3940*83ee113eSDavid van Moolenbroek 
3941*83ee113eSDavid van Moolenbroek /* The first and second stages are pretty similar so we combine them */
3942*83ee113eSDavid van Moolenbroek static void
client_dns_remove_action(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)3943*83ee113eSDavid van Moolenbroek client_dns_remove_action(dhcp_ddns_cb_t *ddns_cb,
3944*83ee113eSDavid van Moolenbroek 			 isc_result_t    eresult)
3945*83ee113eSDavid van Moolenbroek {
3946*83ee113eSDavid van Moolenbroek 
3947*83ee113eSDavid van Moolenbroek 	isc_result_t result;
3948*83ee113eSDavid van Moolenbroek 
3949*83ee113eSDavid van Moolenbroek 	if ((eresult == ISC_R_SUCCESS) &&
3950*83ee113eSDavid van Moolenbroek 	    (ddns_cb->state == DDNS_STATE_REM_FW_YXDHCID)) {
3951*83ee113eSDavid van Moolenbroek 		/* Do the second stage of the FWD removal */
3952*83ee113eSDavid van Moolenbroek 		ddns_cb->state = DDNS_STATE_REM_FW_NXRR;
3953*83ee113eSDavid van Moolenbroek 
3954*83ee113eSDavid van Moolenbroek 		result = ddns_modify_fwd(ddns_cb, MDL);
3955*83ee113eSDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
3956*83ee113eSDavid van Moolenbroek 			return;
3957*83ee113eSDavid van Moolenbroek 		}
3958*83ee113eSDavid van Moolenbroek 	}
3959*83ee113eSDavid van Moolenbroek 
3960*83ee113eSDavid van Moolenbroek 	/* If we are done or have an error clean up */
3961*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
3962*83ee113eSDavid van Moolenbroek 	return;
3963*83ee113eSDavid van Moolenbroek }
3964*83ee113eSDavid van Moolenbroek 
3965*83ee113eSDavid van Moolenbroek void
client_dns_remove(struct client_state * client,struct iaddr * addr)3966*83ee113eSDavid van Moolenbroek client_dns_remove(struct client_state *client,
3967*83ee113eSDavid van Moolenbroek 		  struct iaddr        *addr)
3968*83ee113eSDavid van Moolenbroek {
3969*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t *ddns_cb;
3970*83ee113eSDavid van Moolenbroek 	isc_result_t result;
3971*83ee113eSDavid van Moolenbroek 
3972*83ee113eSDavid van Moolenbroek 	/* if we have an old ddns request for this client, cancel it */
3973*83ee113eSDavid van Moolenbroek 	if (client->ddns_cb != NULL) {
3974*83ee113eSDavid van Moolenbroek 		ddns_cancel(client->ddns_cb, MDL);
3975*83ee113eSDavid van Moolenbroek 		client->ddns_cb = NULL;
3976*83ee113eSDavid van Moolenbroek 	}
3977*83ee113eSDavid van Moolenbroek 
3978*83ee113eSDavid van Moolenbroek 	ddns_cb = ddns_cb_alloc(MDL);
3979*83ee113eSDavid van Moolenbroek 	if (ddns_cb != NULL) {
3980*83ee113eSDavid van Moolenbroek 		ddns_cb->address = *addr;
3981*83ee113eSDavid van Moolenbroek 		ddns_cb->timeout = 0;
3982*83ee113eSDavid van Moolenbroek 
3983*83ee113eSDavid van Moolenbroek 		ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID;
3984*83ee113eSDavid van Moolenbroek 		ddns_cb->flags = DDNS_UPDATE_ADDR;
3985*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func = client_dns_remove_action;
3986*83ee113eSDavid van Moolenbroek 
3987*83ee113eSDavid van Moolenbroek 		result = client_dns_update(client, ddns_cb);
3988*83ee113eSDavid van Moolenbroek 
3989*83ee113eSDavid van Moolenbroek 		if (result != ISC_R_TIMEDOUT) {
3990*83ee113eSDavid van Moolenbroek 			ddns_cb_free(ddns_cb, MDL);
3991*83ee113eSDavid van Moolenbroek 		}
3992*83ee113eSDavid van Moolenbroek 	}
3993*83ee113eSDavid van Moolenbroek }
3994*83ee113eSDavid van Moolenbroek #endif
3995*83ee113eSDavid van Moolenbroek 
dhcp_set_control_state(control_object_state_t oldstate,control_object_state_t newstate)3996*83ee113eSDavid van Moolenbroek isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
3997*83ee113eSDavid van Moolenbroek 				     control_object_state_t newstate)
3998*83ee113eSDavid van Moolenbroek {
3999*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
4000*83ee113eSDavid van Moolenbroek 	struct client_state *client;
4001*83ee113eSDavid van Moolenbroek 	struct timeval tv;
4002*83ee113eSDavid van Moolenbroek 
4003*83ee113eSDavid van Moolenbroek 	if (newstate == server_shutdown) {
4004*83ee113eSDavid van Moolenbroek 		/* Re-entry */
4005*83ee113eSDavid van Moolenbroek 		if (shutdown_signal == SIGUSR1)
4006*83ee113eSDavid van Moolenbroek 			return ISC_R_SUCCESS;
4007*83ee113eSDavid van Moolenbroek 		/* Log shutdown on signal. */
4008*83ee113eSDavid van Moolenbroek 		if ((shutdown_signal == SIGINT) ||
4009*83ee113eSDavid van Moolenbroek 		    (shutdown_signal == SIGTERM)) {
4010*83ee113eSDavid van Moolenbroek 			log_info("Received signal %d, initiating shutdown.",
4011*83ee113eSDavid van Moolenbroek 				 shutdown_signal);
4012*83ee113eSDavid van Moolenbroek 		}
4013*83ee113eSDavid van Moolenbroek 		/* Mark it was called. */
4014*83ee113eSDavid van Moolenbroek 		shutdown_signal = SIGUSR1;
4015*83ee113eSDavid van Moolenbroek 	}
4016*83ee113eSDavid van Moolenbroek 
4017*83ee113eSDavid van Moolenbroek 	/* Do the right thing for each interface. */
4018*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip -> next) {
4019*83ee113eSDavid van Moolenbroek 	    for (client = ip -> client; client; client = client -> next) {
4020*83ee113eSDavid van Moolenbroek 		switch (newstate) {
4021*83ee113eSDavid van Moolenbroek 		  case server_startup:
4022*83ee113eSDavid van Moolenbroek 		    return ISC_R_SUCCESS;
4023*83ee113eSDavid van Moolenbroek 
4024*83ee113eSDavid van Moolenbroek 		  case server_running:
4025*83ee113eSDavid van Moolenbroek 		    return ISC_R_SUCCESS;
4026*83ee113eSDavid van Moolenbroek 
4027*83ee113eSDavid van Moolenbroek 		  case server_shutdown:
4028*83ee113eSDavid van Moolenbroek 		    if (client -> active &&
4029*83ee113eSDavid van Moolenbroek 			client -> active -> expiry > cur_time) {
4030*83ee113eSDavid van Moolenbroek #if defined (NSUPDATE)
4031*83ee113eSDavid van Moolenbroek 			    if (client->config->do_forward_update) {
4032*83ee113eSDavid van Moolenbroek 				    client_dns_remove(client,
4033*83ee113eSDavid van Moolenbroek 						      &client->active->address);
4034*83ee113eSDavid van Moolenbroek 			    }
4035*83ee113eSDavid van Moolenbroek #endif
4036*83ee113eSDavid van Moolenbroek 			    do_release (client);
4037*83ee113eSDavid van Moolenbroek 		    }
4038*83ee113eSDavid van Moolenbroek 		    break;
4039*83ee113eSDavid van Moolenbroek 
4040*83ee113eSDavid van Moolenbroek 		  case server_hibernate:
4041*83ee113eSDavid van Moolenbroek 		    state_stop (client);
4042*83ee113eSDavid van Moolenbroek 		    break;
4043*83ee113eSDavid van Moolenbroek 
4044*83ee113eSDavid van Moolenbroek 		  case server_awaken:
4045*83ee113eSDavid van Moolenbroek 		    state_reboot (client);
4046*83ee113eSDavid van Moolenbroek 		    break;
4047*83ee113eSDavid van Moolenbroek 		}
4048*83ee113eSDavid van Moolenbroek 	    }
4049*83ee113eSDavid van Moolenbroek 	}
4050*83ee113eSDavid van Moolenbroek 
4051*83ee113eSDavid van Moolenbroek 	if (newstate == server_shutdown) {
4052*83ee113eSDavid van Moolenbroek 		tv.tv_sec = cur_tv.tv_sec;
4053*83ee113eSDavid van Moolenbroek 		tv.tv_usec = cur_tv.tv_usec + 1;
4054*83ee113eSDavid van Moolenbroek 		add_timeout(&tv, shutdown_exit, 0, 0, 0);
4055*83ee113eSDavid van Moolenbroek 	}
4056*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
4057*83ee113eSDavid van Moolenbroek }
4058*83ee113eSDavid van Moolenbroek 
4059*83ee113eSDavid van Moolenbroek #if defined (NSUPDATE)
4060*83ee113eSDavid van Moolenbroek /*
4061*83ee113eSDavid van Moolenbroek  * Called after a timeout if the DNS update failed on the previous try.
4062*83ee113eSDavid van Moolenbroek  * Starts the retry process.  If the retry times out it will schedule
4063*83ee113eSDavid van Moolenbroek  * this routine to run again after a 10x wait.
4064*83ee113eSDavid van Moolenbroek  */
4065*83ee113eSDavid van Moolenbroek void
client_dns_update_timeout(void * cp)4066*83ee113eSDavid van Moolenbroek client_dns_update_timeout (void *cp)
4067*83ee113eSDavid van Moolenbroek {
4068*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)cp;
4069*83ee113eSDavid van Moolenbroek 	struct client_state *client = (struct client_state *)ddns_cb->lease;
4070*83ee113eSDavid van Moolenbroek 	isc_result_t status = ISC_R_FAILURE;
4071*83ee113eSDavid van Moolenbroek 
4072*83ee113eSDavid van Moolenbroek 	if ((client != NULL) &&
4073*83ee113eSDavid van Moolenbroek 	    ((client->active != NULL) ||
4074*83ee113eSDavid van Moolenbroek 	     (client->active_lease != NULL)))
4075*83ee113eSDavid van Moolenbroek 		status = client_dns_update(client, ddns_cb);
4076*83ee113eSDavid van Moolenbroek 
4077*83ee113eSDavid van Moolenbroek 	/*
4078*83ee113eSDavid van Moolenbroek 	 * A status of timedout indicates that we started the update and
4079*83ee113eSDavid van Moolenbroek 	 * have released control of the control block.  Any other status
4080*83ee113eSDavid van Moolenbroek 	 * indicates that we should clean up the control block.  We either
4081*83ee113eSDavid van Moolenbroek 	 * got a success which indicates that we didn't really need to
4082*83ee113eSDavid van Moolenbroek 	 * send an update or some other error in which case we weren't able
4083*83ee113eSDavid van Moolenbroek 	 * to start the update process.  In both cases we still own
4084*83ee113eSDavid van Moolenbroek 	 * the control block and should free it.
4085*83ee113eSDavid van Moolenbroek 	 */
4086*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_TIMEDOUT) {
4087*83ee113eSDavid van Moolenbroek 		if (client != NULL) {
4088*83ee113eSDavid van Moolenbroek 			client->ddns_cb = NULL;
4089*83ee113eSDavid van Moolenbroek 		}
4090*83ee113eSDavid van Moolenbroek 		ddns_cb_free(ddns_cb, MDL);
4091*83ee113eSDavid van Moolenbroek 	}
4092*83ee113eSDavid van Moolenbroek }
4093*83ee113eSDavid van Moolenbroek 
4094*83ee113eSDavid van Moolenbroek /*
4095*83ee113eSDavid van Moolenbroek  * If the first query succeeds, the updater can conclude that it
4096*83ee113eSDavid van Moolenbroek  * has added a new name whose only RRs are the A and DHCID RR records.
4097*83ee113eSDavid van Moolenbroek  * The A RR update is now complete (and a client updater is finished,
4098*83ee113eSDavid van Moolenbroek  * while a server might proceed to perform a PTR RR update).
4099*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
4100*83ee113eSDavid van Moolenbroek  *
4101*83ee113eSDavid van Moolenbroek  * If the second query succeeds, the updater can conclude that the current
4102*83ee113eSDavid van Moolenbroek  * client was the last client associated with the domain name, and that
4103*83ee113eSDavid van Moolenbroek  * the name now contains the updated A RR. The A RR update is now
4104*83ee113eSDavid van Moolenbroek  * complete (and a client updater is finished, while a server would
4105*83ee113eSDavid van Moolenbroek  * then proceed to perform a PTR RR update).
4106*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
4107*83ee113eSDavid van Moolenbroek  *
4108*83ee113eSDavid van Moolenbroek  * If the second query fails with NXRRSET, the updater must conclude
4109*83ee113eSDavid van Moolenbroek  * that the client's desired name is in use by another host.  At this
4110*83ee113eSDavid van Moolenbroek  * juncture, the updater can decide (based on some administrative
4111*83ee113eSDavid van Moolenbroek  * configuration outside of the scope of this document) whether to let
4112*83ee113eSDavid van Moolenbroek  * the existing owner of the name keep that name, and to (possibly)
4113*83ee113eSDavid van Moolenbroek  * perform some name disambiguation operation on behalf of the current
4114*83ee113eSDavid van Moolenbroek  * client, or to replace the RRs on the name with RRs that represent
4115*83ee113eSDavid van Moolenbroek  * the current client. If the configured policy allows replacement of
4116*83ee113eSDavid van Moolenbroek  * existing records, the updater submits a query that deletes the
4117*83ee113eSDavid van Moolenbroek  * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
4118*83ee113eSDavid van Moolenbroek  * represent the IP address and client-identity of the new client.
4119*83ee113eSDavid van Moolenbroek  *   -- "Interaction between DHCP and DNS"
4120*83ee113eSDavid van Moolenbroek  */
4121*83ee113eSDavid van Moolenbroek 
4122*83ee113eSDavid van Moolenbroek /* The first and second stages are pretty similar so we combine them */
4123*83ee113eSDavid van Moolenbroek static void
client_dns_update_action(dhcp_ddns_cb_t * ddns_cb,isc_result_t eresult)4124*83ee113eSDavid van Moolenbroek client_dns_update_action(dhcp_ddns_cb_t *ddns_cb,
4125*83ee113eSDavid van Moolenbroek 			 isc_result_t    eresult)
4126*83ee113eSDavid van Moolenbroek {
4127*83ee113eSDavid van Moolenbroek 	isc_result_t result;
4128*83ee113eSDavid van Moolenbroek 	struct timeval tv;
4129*83ee113eSDavid van Moolenbroek 
4130*83ee113eSDavid van Moolenbroek 	switch(eresult) {
4131*83ee113eSDavid van Moolenbroek 	case ISC_R_SUCCESS:
4132*83ee113eSDavid van Moolenbroek 	default:
4133*83ee113eSDavid van Moolenbroek 		/* Either we succeeded or broke in a bad way, clean up */
4134*83ee113eSDavid van Moolenbroek 		break;
4135*83ee113eSDavid van Moolenbroek 
4136*83ee113eSDavid van Moolenbroek 	case DNS_R_YXRRSET:
4137*83ee113eSDavid van Moolenbroek 		/*
4138*83ee113eSDavid van Moolenbroek 		 * This is the only difference between the two stages,
4139*83ee113eSDavid van Moolenbroek 		 * check to see if it is the first stage, in which case
4140*83ee113eSDavid van Moolenbroek 		 * start the second stage
4141*83ee113eSDavid van Moolenbroek 		 */
4142*83ee113eSDavid van Moolenbroek 		if (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) {
4143*83ee113eSDavid van Moolenbroek 			ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
4144*83ee113eSDavid van Moolenbroek 			ddns_cb->cur_func = client_dns_update_action;
4145*83ee113eSDavid van Moolenbroek 
4146*83ee113eSDavid van Moolenbroek 			result = ddns_modify_fwd(ddns_cb, MDL);
4147*83ee113eSDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
4148*83ee113eSDavid van Moolenbroek 				return;
4149*83ee113eSDavid van Moolenbroek 			}
4150*83ee113eSDavid van Moolenbroek 		}
4151*83ee113eSDavid van Moolenbroek 		break;
4152*83ee113eSDavid van Moolenbroek 
4153*83ee113eSDavid van Moolenbroek 	case ISC_R_TIMEDOUT:
4154*83ee113eSDavid van Moolenbroek 		/*
4155*83ee113eSDavid van Moolenbroek 		 * We got a timeout response from the DNS module.  Schedule
4156*83ee113eSDavid van Moolenbroek 		 * another attempt for later.  We forget the name, dhcid and
4157*83ee113eSDavid van Moolenbroek 		 * zone so if it gets changed we will get the new information.
4158*83ee113eSDavid van Moolenbroek 		 */
4159*83ee113eSDavid van Moolenbroek 		data_string_forget(&ddns_cb->fwd_name, MDL);
4160*83ee113eSDavid van Moolenbroek 		data_string_forget(&ddns_cb->dhcid, MDL);
4161*83ee113eSDavid van Moolenbroek 		if (ddns_cb->zone != NULL) {
4162*83ee113eSDavid van Moolenbroek 			forget_zone((struct dns_zone **)&ddns_cb->zone);
4163*83ee113eSDavid van Moolenbroek 		}
4164*83ee113eSDavid van Moolenbroek 
4165*83ee113eSDavid van Moolenbroek 		/* Reset to doing the first stage */
4166*83ee113eSDavid van Moolenbroek 		ddns_cb->state    = DDNS_STATE_ADD_FW_NXDOMAIN;
4167*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func = client_dns_update_action;
4168*83ee113eSDavid van Moolenbroek 
4169*83ee113eSDavid van Moolenbroek 		/* and update our timer */
4170*83ee113eSDavid van Moolenbroek 		if (ddns_cb->timeout < 3600)
4171*83ee113eSDavid van Moolenbroek 			ddns_cb->timeout *= 10;
4172*83ee113eSDavid van Moolenbroek 		tv.tv_sec = cur_tv.tv_sec + ddns_cb->timeout;
4173*83ee113eSDavid van Moolenbroek 		tv.tv_usec = cur_tv.tv_usec;
4174*83ee113eSDavid van Moolenbroek 		add_timeout(&tv, client_dns_update_timeout,
4175*83ee113eSDavid van Moolenbroek 			    ddns_cb, NULL, NULL);
4176*83ee113eSDavid van Moolenbroek 		return;
4177*83ee113eSDavid van Moolenbroek 	}
4178*83ee113eSDavid van Moolenbroek 
4179*83ee113eSDavid van Moolenbroek 	ddns_cb_free(ddns_cb, MDL);
4180*83ee113eSDavid van Moolenbroek 	return;
4181*83ee113eSDavid van Moolenbroek }
4182*83ee113eSDavid van Moolenbroek 
4183*83ee113eSDavid van Moolenbroek /* See if we should do a DNS update, and if so, do it. */
4184*83ee113eSDavid van Moolenbroek 
4185*83ee113eSDavid van Moolenbroek isc_result_t
client_dns_update(struct client_state * client,dhcp_ddns_cb_t * ddns_cb)4186*83ee113eSDavid van Moolenbroek client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb)
4187*83ee113eSDavid van Moolenbroek {
4188*83ee113eSDavid van Moolenbroek 	struct data_string client_identifier;
4189*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
4190*83ee113eSDavid van Moolenbroek 	int ignorep;
4191*83ee113eSDavid van Moolenbroek 	int result;
4192*83ee113eSDavid van Moolenbroek 	int ddns_v4_type;
4193*83ee113eSDavid van Moolenbroek 	isc_result_t rcode;
4194*83ee113eSDavid van Moolenbroek 
4195*83ee113eSDavid van Moolenbroek 	/* If we didn't send an FQDN option, we certainly aren't going to
4196*83ee113eSDavid van Moolenbroek 	   be doing an update. */
4197*83ee113eSDavid van Moolenbroek 	if (!client -> sent_options)
4198*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
4199*83ee113eSDavid van Moolenbroek 
4200*83ee113eSDavid van Moolenbroek 	/* If we don't have a lease, we can't do an update. */
4201*83ee113eSDavid van Moolenbroek 	if ((client->active == NULL) && (client->active_lease == NULL))
4202*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
4203*83ee113eSDavid van Moolenbroek 
4204*83ee113eSDavid van Moolenbroek 	/* If we set the no client update flag, don't do the update. */
4205*83ee113eSDavid van Moolenbroek 	if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
4206*83ee113eSDavid van Moolenbroek 				  FQDN_NO_CLIENT_UPDATE)) &&
4207*83ee113eSDavid van Moolenbroek 	    evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
4208*83ee113eSDavid van Moolenbroek 					   (struct lease *)0, client,
4209*83ee113eSDavid van Moolenbroek 					   client -> sent_options,
4210*83ee113eSDavid van Moolenbroek 					   (struct option_state *)0,
4211*83ee113eSDavid van Moolenbroek 					   &global_scope, oc, MDL))
4212*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
4213*83ee113eSDavid van Moolenbroek 
4214*83ee113eSDavid van Moolenbroek 	/* If we set the "server, please update" flag, or didn't set it
4215*83ee113eSDavid van Moolenbroek 	   to false, don't do the update. */
4216*83ee113eSDavid van Moolenbroek 	if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
4217*83ee113eSDavid van Moolenbroek 				  FQDN_SERVER_UPDATE)) ||
4218*83ee113eSDavid van Moolenbroek 	    evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
4219*83ee113eSDavid van Moolenbroek 					   (struct lease *)0, client,
4220*83ee113eSDavid van Moolenbroek 					   client -> sent_options,
4221*83ee113eSDavid van Moolenbroek 					   (struct option_state *)0,
4222*83ee113eSDavid van Moolenbroek 					   &global_scope, oc, MDL))
4223*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
4224*83ee113eSDavid van Moolenbroek 
4225*83ee113eSDavid van Moolenbroek 	/* If no FQDN option was supplied, don't do the update. */
4226*83ee113eSDavid van Moolenbroek 	if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
4227*83ee113eSDavid van Moolenbroek 				  FQDN_FQDN)) ||
4228*83ee113eSDavid van Moolenbroek 	    !evaluate_option_cache (&ddns_cb->fwd_name, (struct packet *)0,
4229*83ee113eSDavid van Moolenbroek 				    (struct lease *)0, client,
4230*83ee113eSDavid van Moolenbroek 				    client -> sent_options,
4231*83ee113eSDavid van Moolenbroek 				    (struct option_state *)0,
4232*83ee113eSDavid van Moolenbroek 				    &global_scope, oc, MDL))
4233*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
4234*83ee113eSDavid van Moolenbroek 
4235*83ee113eSDavid van Moolenbroek 	/*
4236*83ee113eSDavid van Moolenbroek 	 * Construct the DHCID value for use in the DDNS update process
4237*83ee113eSDavid van Moolenbroek 	 * We have the newer standard version and the older interim version
4238*83ee113eSDavid van Moolenbroek 	 * chosen by the '-I' option.  The interim version is left as is
4239*83ee113eSDavid van Moolenbroek 	 * for backwards compatibility.  The standard version is based on
4240*83ee113eSDavid van Moolenbroek 	 * RFC 4701 section 3.3
4241*83ee113eSDavid van Moolenbroek 	 */
4242*83ee113eSDavid van Moolenbroek 
4243*83ee113eSDavid van Moolenbroek 	result = 0;
4244*83ee113eSDavid van Moolenbroek 	POST(result);
4245*83ee113eSDavid van Moolenbroek 	memset(&client_identifier, 0, sizeof(client_identifier));
4246*83ee113eSDavid van Moolenbroek 
4247*83ee113eSDavid van Moolenbroek 	if (std_dhcid == 1) {
4248*83ee113eSDavid van Moolenbroek 		/* standard style */
4249*83ee113eSDavid van Moolenbroek 		ddns_cb->dhcid_class = dns_rdatatype_dhcid;
4250*83ee113eSDavid van Moolenbroek 		ddns_v4_type = 1;
4251*83ee113eSDavid van Moolenbroek 	} else {
4252*83ee113eSDavid van Moolenbroek 		/* interim style */
4253*83ee113eSDavid van Moolenbroek 		ddns_cb->dhcid_class = dns_rdatatype_txt;
4254*83ee113eSDavid van Moolenbroek 		/* for backwards compatibility */
4255*83ee113eSDavid van Moolenbroek 		ddns_v4_type = DHO_DHCP_CLIENT_IDENTIFIER;
4256*83ee113eSDavid van Moolenbroek 	}
4257*83ee113eSDavid van Moolenbroek 	if (client->active_lease != NULL) {
4258*83ee113eSDavid van Moolenbroek 		/* V6 request, get the client identifier, then
4259*83ee113eSDavid van Moolenbroek 		 * construct the dhcid for either standard
4260*83ee113eSDavid van Moolenbroek 		 * or interim */
4261*83ee113eSDavid van Moolenbroek 		if (((oc = lookup_option(&dhcpv6_universe,
4262*83ee113eSDavid van Moolenbroek 					 client->sent_options,
4263*83ee113eSDavid van Moolenbroek 					 D6O_CLIENTID)) != NULL) &&
4264*83ee113eSDavid van Moolenbroek 		    evaluate_option_cache(&client_identifier, NULL,
4265*83ee113eSDavid van Moolenbroek 					  NULL, client,
4266*83ee113eSDavid van Moolenbroek 					  client->sent_options, NULL,
4267*83ee113eSDavid van Moolenbroek 					  &global_scope, oc, MDL)) {
4268*83ee113eSDavid van Moolenbroek 			result = get_dhcid(ddns_cb, 2,
4269*83ee113eSDavid van Moolenbroek 					   client_identifier.data,
4270*83ee113eSDavid van Moolenbroek 					   client_identifier.len);
4271*83ee113eSDavid van Moolenbroek 			data_string_forget(&client_identifier, MDL);
4272*83ee113eSDavid van Moolenbroek 		} else
4273*83ee113eSDavid van Moolenbroek 			log_fatal("Impossible condition at %s:%d.", MDL);
4274*83ee113eSDavid van Moolenbroek 	} else {
4275*83ee113eSDavid van Moolenbroek 		/*
4276*83ee113eSDavid van Moolenbroek 		 * V4 request, use the client id if there is one or the
4277*83ee113eSDavid van Moolenbroek 		 * mac address if there isn't.  If we have a client id
4278*83ee113eSDavid van Moolenbroek 		 * we check to see if it is an embedded DUID.
4279*83ee113eSDavid van Moolenbroek 		 */
4280*83ee113eSDavid van Moolenbroek 		if (((oc = lookup_option(&dhcp_universe,
4281*83ee113eSDavid van Moolenbroek 					 client->sent_options,
4282*83ee113eSDavid van Moolenbroek 					 DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) &&
4283*83ee113eSDavid van Moolenbroek 		    evaluate_option_cache(&client_identifier, NULL,
4284*83ee113eSDavid van Moolenbroek 					  NULL, client,
4285*83ee113eSDavid van Moolenbroek 					  client->sent_options, NULL,
4286*83ee113eSDavid van Moolenbroek 					  &global_scope, oc, MDL)) {
4287*83ee113eSDavid van Moolenbroek 			if ((std_dhcid == 1) && (duid_v4 == 1) &&
4288*83ee113eSDavid van Moolenbroek 			    (client_identifier.data[0] == 255)) {
4289*83ee113eSDavid van Moolenbroek 				/*
4290*83ee113eSDavid van Moolenbroek 				 * This appears to be an embedded DUID,
4291*83ee113eSDavid van Moolenbroek 				 * extract it and treat it as such
4292*83ee113eSDavid van Moolenbroek 				 */
4293*83ee113eSDavid van Moolenbroek 				if (client_identifier.len <= 5)
4294*83ee113eSDavid van Moolenbroek 					log_fatal("Impossible condition at %s:%d.",
4295*83ee113eSDavid van Moolenbroek 						  MDL);
4296*83ee113eSDavid van Moolenbroek 				result = get_dhcid(ddns_cb, 2,
4297*83ee113eSDavid van Moolenbroek 						   client_identifier.data + 5,
4298*83ee113eSDavid van Moolenbroek 						   client_identifier.len - 5);
4299*83ee113eSDavid van Moolenbroek 			} else {
4300*83ee113eSDavid van Moolenbroek 				result = get_dhcid(ddns_cb, ddns_v4_type,
4301*83ee113eSDavid van Moolenbroek 						   client_identifier.data,
4302*83ee113eSDavid van Moolenbroek 						   client_identifier.len);
4303*83ee113eSDavid van Moolenbroek 			}
4304*83ee113eSDavid van Moolenbroek 			data_string_forget(&client_identifier, MDL);
4305*83ee113eSDavid van Moolenbroek 		} else
4306*83ee113eSDavid van Moolenbroek 			result = get_dhcid(ddns_cb, 0,
4307*83ee113eSDavid van Moolenbroek 					   client->interface->hw_address.hbuf,
4308*83ee113eSDavid van Moolenbroek 					   client->interface->hw_address.hlen);
4309*83ee113eSDavid van Moolenbroek 	}
4310*83ee113eSDavid van Moolenbroek 
4311*83ee113eSDavid van Moolenbroek 	if (!result) {
4312*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
4313*83ee113eSDavid van Moolenbroek 	}
4314*83ee113eSDavid van Moolenbroek 
4315*83ee113eSDavid van Moolenbroek 	/*
4316*83ee113eSDavid van Moolenbroek 	 * Perform updates.
4317*83ee113eSDavid van Moolenbroek 	 */
4318*83ee113eSDavid van Moolenbroek 	if (ddns_cb->fwd_name.len && ddns_cb->dhcid.len) {
4319*83ee113eSDavid van Moolenbroek 		rcode = ddns_modify_fwd(ddns_cb, MDL);
4320*83ee113eSDavid van Moolenbroek 	} else
4321*83ee113eSDavid van Moolenbroek 		rcode = ISC_R_FAILURE;
4322*83ee113eSDavid van Moolenbroek 
4323*83ee113eSDavid van Moolenbroek 	/*
4324*83ee113eSDavid van Moolenbroek 	 * A success from the modify routine means we are performing
4325*83ee113eSDavid van Moolenbroek 	 * async processing, for which we use the timedout error message.
4326*83ee113eSDavid van Moolenbroek 	 */
4327*83ee113eSDavid van Moolenbroek 	if (rcode == ISC_R_SUCCESS) {
4328*83ee113eSDavid van Moolenbroek 		rcode = ISC_R_TIMEDOUT;
4329*83ee113eSDavid van Moolenbroek 	}
4330*83ee113eSDavid van Moolenbroek 
4331*83ee113eSDavid van Moolenbroek 	return rcode;
4332*83ee113eSDavid van Moolenbroek }
4333*83ee113eSDavid van Moolenbroek 
4334*83ee113eSDavid van Moolenbroek 
4335*83ee113eSDavid van Moolenbroek /*
4336*83ee113eSDavid van Moolenbroek  * Schedule the first update.  They will continue to retry occasionally
4337*83ee113eSDavid van Moolenbroek  * until they no longer time out (or fail).
4338*83ee113eSDavid van Moolenbroek  */
4339*83ee113eSDavid van Moolenbroek void
dhclient_schedule_updates(struct client_state * client,struct iaddr * addr,int offset)4340*83ee113eSDavid van Moolenbroek dhclient_schedule_updates(struct client_state *client,
4341*83ee113eSDavid van Moolenbroek 			  struct iaddr        *addr,
4342*83ee113eSDavid van Moolenbroek 			  int                  offset)
4343*83ee113eSDavid van Moolenbroek {
4344*83ee113eSDavid van Moolenbroek 	dhcp_ddns_cb_t *ddns_cb;
4345*83ee113eSDavid van Moolenbroek 	struct timeval tv;
4346*83ee113eSDavid van Moolenbroek 
4347*83ee113eSDavid van Moolenbroek 	if (!client->config->do_forward_update)
4348*83ee113eSDavid van Moolenbroek 		return;
4349*83ee113eSDavid van Moolenbroek 
4350*83ee113eSDavid van Moolenbroek 	/* cancel any outstanding ddns requests */
4351*83ee113eSDavid van Moolenbroek 	if (client->ddns_cb != NULL) {
4352*83ee113eSDavid van Moolenbroek 		ddns_cancel(client->ddns_cb, MDL);
4353*83ee113eSDavid van Moolenbroek 		client->ddns_cb = NULL;
4354*83ee113eSDavid van Moolenbroek 	}
4355*83ee113eSDavid van Moolenbroek 
4356*83ee113eSDavid van Moolenbroek 	ddns_cb = ddns_cb_alloc(MDL);
4357*83ee113eSDavid van Moolenbroek 
4358*83ee113eSDavid van Moolenbroek 	if (ddns_cb != NULL) {
4359*83ee113eSDavid van Moolenbroek 		ddns_cb->lease = (void *)client;
4360*83ee113eSDavid van Moolenbroek 		ddns_cb->address = *addr;
4361*83ee113eSDavid van Moolenbroek 		ddns_cb->timeout = 1;
4362*83ee113eSDavid van Moolenbroek 
4363*83ee113eSDavid van Moolenbroek 		/*
4364*83ee113eSDavid van Moolenbroek 		 * XXX: DNS TTL is a problem we need to solve properly.
4365*83ee113eSDavid van Moolenbroek 		 * Until that time, 300 is a placeholder default for
4366*83ee113eSDavid van Moolenbroek 		 * something that is less insane than a value scaled
4367*83ee113eSDavid van Moolenbroek 		 * by lease timeout.
4368*83ee113eSDavid van Moolenbroek 		 */
4369*83ee113eSDavid van Moolenbroek 		ddns_cb->ttl = 300;
4370*83ee113eSDavid van Moolenbroek 
4371*83ee113eSDavid van Moolenbroek 		ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN;
4372*83ee113eSDavid van Moolenbroek 		ddns_cb->cur_func = client_dns_update_action;
4373*83ee113eSDavid van Moolenbroek 		ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_INCLUDE_RRSET;
4374*83ee113eSDavid van Moolenbroek 
4375*83ee113eSDavid van Moolenbroek 		client->ddns_cb = ddns_cb;
4376*83ee113eSDavid van Moolenbroek 
4377*83ee113eSDavid van Moolenbroek 		tv.tv_sec = cur_tv.tv_sec + offset;
4378*83ee113eSDavid van Moolenbroek 		tv.tv_usec = cur_tv.tv_usec;
4379*83ee113eSDavid van Moolenbroek 		add_timeout(&tv, client_dns_update_timeout,
4380*83ee113eSDavid van Moolenbroek 			    ddns_cb, NULL, NULL);
4381*83ee113eSDavid van Moolenbroek 	} else {
4382*83ee113eSDavid van Moolenbroek 		log_error("Unable to allocate dns update state for %s",
4383*83ee113eSDavid van Moolenbroek 			  piaddr(*addr));
4384*83ee113eSDavid van Moolenbroek 	}
4385*83ee113eSDavid van Moolenbroek }
4386*83ee113eSDavid van Moolenbroek #endif
4387*83ee113eSDavid van Moolenbroek 
4388*83ee113eSDavid van Moolenbroek void
dhcpv4_client_assignments(void)4389*83ee113eSDavid van Moolenbroek dhcpv4_client_assignments(void)
4390*83ee113eSDavid van Moolenbroek {
4391*83ee113eSDavid van Moolenbroek 	struct servent *ent;
4392*83ee113eSDavid van Moolenbroek 
4393*83ee113eSDavid van Moolenbroek 	if (path_dhclient_pid == NULL)
4394*83ee113eSDavid van Moolenbroek 		path_dhclient_pid = _PATH_DHCLIENT_PID;
4395*83ee113eSDavid van Moolenbroek 	if (path_dhclient_db == NULL)
4396*83ee113eSDavid van Moolenbroek 		path_dhclient_db = _PATH_DHCLIENT_DB;
4397*83ee113eSDavid van Moolenbroek 
4398*83ee113eSDavid van Moolenbroek 	/* Default to the DHCP/BOOTP port. */
4399*83ee113eSDavid van Moolenbroek 	if (!local_port) {
4400*83ee113eSDavid van Moolenbroek 		/* If we're faking a relay agent, and we're not using loopback,
4401*83ee113eSDavid van Moolenbroek 		   use the server port, not the client port. */
4402*83ee113eSDavid van Moolenbroek 		if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
4403*83ee113eSDavid van Moolenbroek 			local_port = htons(67);
4404*83ee113eSDavid van Moolenbroek 		} else {
4405*83ee113eSDavid van Moolenbroek 			ent = getservbyname ("dhcpc", "udp");
4406*83ee113eSDavid van Moolenbroek 			if (!ent)
4407*83ee113eSDavid van Moolenbroek 				local_port = htons (68);
4408*83ee113eSDavid van Moolenbroek 			else
4409*83ee113eSDavid van Moolenbroek 				local_port = ent -> s_port;
4410*83ee113eSDavid van Moolenbroek #ifndef __CYGWIN32__
4411*83ee113eSDavid van Moolenbroek 			endservent ();
4412*83ee113eSDavid van Moolenbroek #endif
4413*83ee113eSDavid van Moolenbroek 		}
4414*83ee113eSDavid van Moolenbroek 	}
4415*83ee113eSDavid van Moolenbroek 
4416*83ee113eSDavid van Moolenbroek 	/* If we're faking a relay agent, and we're not using loopback,
4417*83ee113eSDavid van Moolenbroek 	   we're using the server port, not the client port. */
4418*83ee113eSDavid van Moolenbroek 	if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
4419*83ee113eSDavid van Moolenbroek 		remote_port = local_port;
4420*83ee113eSDavid van Moolenbroek 	} else
4421*83ee113eSDavid van Moolenbroek 		remote_port = htons (ntohs (local_port) - 1);   /* XXX */
4422*83ee113eSDavid van Moolenbroek }
4423*83ee113eSDavid van Moolenbroek 
4424*83ee113eSDavid van Moolenbroek /*
4425*83ee113eSDavid van Moolenbroek  * The following routines are used to check that certain
4426*83ee113eSDavid van Moolenbroek  * strings are reasonable before we pass them to the scripts.
4427*83ee113eSDavid van Moolenbroek  * This avoids some problems with scripts treating the strings
4428*83ee113eSDavid van Moolenbroek  * as commands - see ticket 23722
4429*83ee113eSDavid van Moolenbroek  * The domain checking code should be done as part of assembling
4430*83ee113eSDavid van Moolenbroek  * the string but we are doing it here for now due to time
4431*83ee113eSDavid van Moolenbroek  * constraints.
4432*83ee113eSDavid van Moolenbroek  */
4433*83ee113eSDavid van Moolenbroek 
check_domain_name(const char * ptr,size_t len,int dots)4434*83ee113eSDavid van Moolenbroek static int check_domain_name(const char *ptr, size_t len, int dots)
4435*83ee113eSDavid van Moolenbroek {
4436*83ee113eSDavid van Moolenbroek 	const char *p;
4437*83ee113eSDavid van Moolenbroek 
4438*83ee113eSDavid van Moolenbroek 	/* not empty or complete length not over 255 characters   */
4439*83ee113eSDavid van Moolenbroek 	if ((len == 0) || (len > 256))
4440*83ee113eSDavid van Moolenbroek 		return(-1);
4441*83ee113eSDavid van Moolenbroek 
4442*83ee113eSDavid van Moolenbroek 	/* consists of [[:alnum:]-]+ labels separated by [.]      */
4443*83ee113eSDavid van Moolenbroek 	/* a [_] is against RFC but seems to be "widely used"...  */
4444*83ee113eSDavid van Moolenbroek 	for (p=ptr; (*p != 0) && (len-- > 0); p++) {
4445*83ee113eSDavid van Moolenbroek 		if ((*p == '-') || (*p == '_')) {
4446*83ee113eSDavid van Moolenbroek 			/* not allowed at begin or end of a label */
4447*83ee113eSDavid van Moolenbroek 			if (((p - ptr) == 0) || (len == 0) || (p[1] == '.'))
4448*83ee113eSDavid van Moolenbroek 				return(-1);
4449*83ee113eSDavid van Moolenbroek 		} else if (*p == '.') {
4450*83ee113eSDavid van Moolenbroek 			/* each label has to be 1-63 characters;
4451*83ee113eSDavid van Moolenbroek 			   we allow [.] at the end ('foo.bar.')   */
4452*83ee113eSDavid van Moolenbroek 			size_t d = p - ptr;
4453*83ee113eSDavid van Moolenbroek 			if ((d <= 0) || (d >= 64))
4454*83ee113eSDavid van Moolenbroek 				return(-1);
4455*83ee113eSDavid van Moolenbroek 			ptr = p + 1; /* jump to the next label    */
4456*83ee113eSDavid van Moolenbroek 			if ((dots > 0) && (len > 0))
4457*83ee113eSDavid van Moolenbroek 				dots--;
4458*83ee113eSDavid van Moolenbroek 		} else if (isalnum((unsigned char)*p) == 0) {
4459*83ee113eSDavid van Moolenbroek 			/* also numbers at the begin are fine     */
4460*83ee113eSDavid van Moolenbroek 			return(-1);
4461*83ee113eSDavid van Moolenbroek 		}
4462*83ee113eSDavid van Moolenbroek 	}
4463*83ee113eSDavid van Moolenbroek 	return(dots ? -1 : 0);
4464*83ee113eSDavid van Moolenbroek }
4465*83ee113eSDavid van Moolenbroek 
check_domain_name_list(const char * ptr,size_t len,int dots)4466*83ee113eSDavid van Moolenbroek static int check_domain_name_list(const char *ptr, size_t len, int dots)
4467*83ee113eSDavid van Moolenbroek {
4468*83ee113eSDavid van Moolenbroek 	const char *p;
4469*83ee113eSDavid van Moolenbroek 	int ret = -1; /* at least one needed */
4470*83ee113eSDavid van Moolenbroek 
4471*83ee113eSDavid van Moolenbroek 	if ((ptr == NULL) || (len == 0))
4472*83ee113eSDavid van Moolenbroek 		return(-1);
4473*83ee113eSDavid van Moolenbroek 
4474*83ee113eSDavid van Moolenbroek 	for (p=ptr; (*p != 0) && (len > 0); p++, len--) {
4475*83ee113eSDavid van Moolenbroek 		if (*p != ' ')
4476*83ee113eSDavid van Moolenbroek 			continue;
4477*83ee113eSDavid van Moolenbroek 		if (p > ptr) {
4478*83ee113eSDavid van Moolenbroek 			if (check_domain_name(ptr, p - ptr, dots) != 0)
4479*83ee113eSDavid van Moolenbroek 				return(-1);
4480*83ee113eSDavid van Moolenbroek 			ret = 0;
4481*83ee113eSDavid van Moolenbroek 		}
4482*83ee113eSDavid van Moolenbroek 		ptr = p + 1;
4483*83ee113eSDavid van Moolenbroek 	}
4484*83ee113eSDavid van Moolenbroek 	if (p > ptr)
4485*83ee113eSDavid van Moolenbroek 		return(check_domain_name(ptr, p - ptr, dots));
4486*83ee113eSDavid van Moolenbroek 	else
4487*83ee113eSDavid van Moolenbroek 		return(ret);
4488*83ee113eSDavid van Moolenbroek }
4489*83ee113eSDavid van Moolenbroek 
check_option_values(struct universe * universe,unsigned int opt,const char * ptr,size_t len)4490*83ee113eSDavid van Moolenbroek static int check_option_values(struct universe *universe,
4491*83ee113eSDavid van Moolenbroek 			       unsigned int opt,
4492*83ee113eSDavid van Moolenbroek 			       const char *ptr,
4493*83ee113eSDavid van Moolenbroek 			       size_t len)
4494*83ee113eSDavid van Moolenbroek {
4495*83ee113eSDavid van Moolenbroek 	if (ptr == NULL)
4496*83ee113eSDavid van Moolenbroek 		return(-1);
4497*83ee113eSDavid van Moolenbroek 
4498*83ee113eSDavid van Moolenbroek 	/* just reject options we want to protect, will be escaped anyway */
4499*83ee113eSDavid van Moolenbroek 	if ((universe == NULL) || (universe == &dhcp_universe)) {
4500*83ee113eSDavid van Moolenbroek 		switch(opt) {
4501*83ee113eSDavid van Moolenbroek 		      case DHO_DOMAIN_NAME:
4502*83ee113eSDavid van Moolenbroek #ifdef ACCEPT_LIST_IN_DOMAIN_NAME
4503*83ee113eSDavid van Moolenbroek 			      return check_domain_name_list(ptr, len, 0);
4504*83ee113eSDavid van Moolenbroek #else
4505*83ee113eSDavid van Moolenbroek 			      return check_domain_name(ptr, len, 0);
4506*83ee113eSDavid van Moolenbroek #endif
4507*83ee113eSDavid van Moolenbroek 		      case DHO_HOST_NAME:
4508*83ee113eSDavid van Moolenbroek 		      case DHO_NIS_DOMAIN:
4509*83ee113eSDavid van Moolenbroek 		      case DHO_NETBIOS_SCOPE:
4510*83ee113eSDavid van Moolenbroek 			return check_domain_name(ptr, len, 0);
4511*83ee113eSDavid van Moolenbroek 			break;
4512*83ee113eSDavid van Moolenbroek 		      case DHO_DOMAIN_SEARCH:
4513*83ee113eSDavid van Moolenbroek 			return check_domain_name_list(ptr, len, 0);
4514*83ee113eSDavid van Moolenbroek 			break;
4515*83ee113eSDavid van Moolenbroek 		      case DHO_ROOT_PATH:
4516*83ee113eSDavid van Moolenbroek 			if (len == 0)
4517*83ee113eSDavid van Moolenbroek 				return(-1);
4518*83ee113eSDavid van Moolenbroek 			for (; (*ptr != 0) && (len-- > 0); ptr++) {
4519*83ee113eSDavid van Moolenbroek 				if(!(isalnum((unsigned char)*ptr) ||
4520*83ee113eSDavid van Moolenbroek 				     *ptr == '#'  || *ptr == '%' ||
4521*83ee113eSDavid van Moolenbroek 				     *ptr == '+'  || *ptr == '-' ||
4522*83ee113eSDavid van Moolenbroek 				     *ptr == '_'  || *ptr == ':' ||
4523*83ee113eSDavid van Moolenbroek 				     *ptr == '.'  || *ptr == ',' ||
4524*83ee113eSDavid van Moolenbroek 				     *ptr == '@'  || *ptr == '~' ||
4525*83ee113eSDavid van Moolenbroek 				     *ptr == '\\' || *ptr == '/' ||
4526*83ee113eSDavid van Moolenbroek 				     *ptr == '['  || *ptr == ']' ||
4527*83ee113eSDavid van Moolenbroek 				     *ptr == '='  || *ptr == ' '))
4528*83ee113eSDavid van Moolenbroek 					return(-1);
4529*83ee113eSDavid van Moolenbroek 			}
4530*83ee113eSDavid van Moolenbroek 			return(0);
4531*83ee113eSDavid van Moolenbroek 			break;
4532*83ee113eSDavid van Moolenbroek 		}
4533*83ee113eSDavid van Moolenbroek 	}
4534*83ee113eSDavid van Moolenbroek 
4535*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
4536*83ee113eSDavid van Moolenbroek 	if (universe == &dhcpv6_universe) {
4537*83ee113eSDavid van Moolenbroek 		switch(opt) {
4538*83ee113eSDavid van Moolenbroek 		      case D6O_SIP_SERVERS_DNS:
4539*83ee113eSDavid van Moolenbroek 		      case D6O_DOMAIN_SEARCH:
4540*83ee113eSDavid van Moolenbroek 		      case D6O_NIS_DOMAIN_NAME:
4541*83ee113eSDavid van Moolenbroek 		      case D6O_NISP_DOMAIN_NAME:
4542*83ee113eSDavid van Moolenbroek 			return check_domain_name_list(ptr, len, 0);
4543*83ee113eSDavid van Moolenbroek 			break;
4544*83ee113eSDavid van Moolenbroek 		}
4545*83ee113eSDavid van Moolenbroek 	}
4546*83ee113eSDavid van Moolenbroek #endif
4547*83ee113eSDavid van Moolenbroek 
4548*83ee113eSDavid van Moolenbroek 	return(0);
4549*83ee113eSDavid van Moolenbroek }
4550*83ee113eSDavid van Moolenbroek 
4551*83ee113eSDavid van Moolenbroek static void
add_reject(struct packet * packet)4552*83ee113eSDavid van Moolenbroek add_reject(struct packet *packet) {
4553*83ee113eSDavid van Moolenbroek 	struct iaddrmatchlist *list;
4554*83ee113eSDavid van Moolenbroek 
4555*83ee113eSDavid van Moolenbroek 	list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
4556*83ee113eSDavid van Moolenbroek 	if (!list)
4557*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for reject list!");
4558*83ee113eSDavid van Moolenbroek 
4559*83ee113eSDavid van Moolenbroek 	/*
4560*83ee113eSDavid van Moolenbroek 	 * client_addr is misleading - it is set to source address in common
4561*83ee113eSDavid van Moolenbroek 	 * code.
4562*83ee113eSDavid van Moolenbroek 	 */
4563*83ee113eSDavid van Moolenbroek 	list->match.addr = packet->client_addr;
4564*83ee113eSDavid van Moolenbroek 	/* Set mask to indicate host address. */
4565*83ee113eSDavid van Moolenbroek 	list->match.mask.len = list->match.addr.len;
4566*83ee113eSDavid van Moolenbroek 	memset(list->match.mask.iabuf, 0xff, sizeof(list->match.mask.iabuf));
4567*83ee113eSDavid van Moolenbroek 
4568*83ee113eSDavid van Moolenbroek 	/* Append to reject list for the source interface. */
4569*83ee113eSDavid van Moolenbroek 	list->next = packet->interface->client->config->reject_list;
4570*83ee113eSDavid van Moolenbroek 	packet->interface->client->config->reject_list = list;
4571*83ee113eSDavid van Moolenbroek 
4572*83ee113eSDavid van Moolenbroek 	/*
4573*83ee113eSDavid van Moolenbroek 	 * We should inform user that we won't be accepting this server
4574*83ee113eSDavid van Moolenbroek 	 * anymore.
4575*83ee113eSDavid van Moolenbroek 	 */
4576*83ee113eSDavid van Moolenbroek 	log_info("Server added to list of rejected servers.");
4577*83ee113eSDavid van Moolenbroek }
4578*83ee113eSDavid van Moolenbroek 
4579