revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / client / dhclient.c
blobada126f068e6e2271c2b4e4102d523d0f65f97c6
1 /* dhclient.c
3 DHCP Client. */
5 /*
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This code is based on the original client state machine that was
28 * written by Elliot Poger. The code has been extensively hacked on
29 * by Ted Lemon since then, so any mistakes you find are probably his
30 * fault and not Elliot's.
33 const char dhcp_ocopyright[] =
34 "$Id$ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
36 #include "dhcpd.h"
37 #include "version.h"
39 #ifdef AMIGA
40 #include <proto/dos.h>
41 #include <proto/exec.h>
42 #endif
44 #ifdef __AROS__
45 struct Library *MiamiBase = NULL;
46 struct Library *SocketBase = NULL;
48 static void __close_bsdsocket()
50 if (MiamiBase)
52 CloseLibrary(MiamiBase);
53 MiamiBase = NULL;
55 if (SocketBase)
57 CloseLibrary(SocketBase);
58 SocketBase = NULL;
62 void openlog(const char *ident, int logstat, int logfac)
64 log_debug("openlog %s %d %d\n", ident, logstat, logfac);
67 int setlogmask(int pmask)
69 log_debug("setlogmask %d\n", pmask);
70 return -1;
72 #endif
74 TIME default_lease_time = 43200; /* 12 hours... */
75 TIME max_lease_time = 86400; /* 24 hours... */
77 const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
78 const char *path_dhclient_db = _PATH_DHCLIENT_DB;
79 const char *path_dhclient_pid = _PATH_DHCLIENT_PID;
80 static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT;
81 char *path_dhclient_script = path_dhclient_script_array;
83 int dhcp_max_agent_option_packet_length = 0;
85 int interfaces_requested = 0;
87 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
88 struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
89 struct in_addr inaddr_any;
90 struct sockaddr_in sockaddr_broadcast;
91 struct in_addr giaddr;
93 /* ASSERT_STATE() does nothing now; it used to be
94 assert (state_is == state_shouldbe). */
95 #define ASSERT_STATE(state_is, state_shouldbe) {}
97 static char copyright[] = "Copyright 2004-2005 Internet Systems Consortium.";
98 static char arr [] = "All rights reserved.";
99 static char message [] = "Internet Systems Consortium DHCP Client";
100 static char url [] = "For info, please visit http://www.isc.org/products/DHCP";
102 u_int16_t local_port=0;
103 u_int16_t remote_port=0;
104 int no_daemon=0;
105 struct string_list *client_env=NULL;
106 int client_env_count=0;
107 int onetry=0;
108 int quiet=0;
109 int nowait=0;
111 static void usage PROTO ((void));
113 void do_release(struct client_state *);
115 #ifdef __GNUC__
116 static inline u_long ia2ulong(struct iaddr *ia) { u_long *p = (u_long *)&ia->iabuf[0]; return *p; }
117 #else
118 #define ia2ulong(x) (*(u_long *)((x)->iabuf))
119 #endif
120 void interface_preinit (struct client_state *);
121 int interface_medium (struct client_state *, char *);
122 int interface_bind (struct client_state *);
123 /*void interface_expire (struct client_state *);
124 void interface_fail (struct client_state *);
125 void interface_release (struct client_state *);*/
126 #define interface_expire interface_stop
127 #define interface_fail interface_stop
128 #define interface_release interface_stop
129 void interface_stop (struct client_state *);
130 int interface_timeout (struct client_state *);
132 int main (argc, argv, envp)
133 int argc;
134 char **argv, **envp;
136 int i;
137 struct servent *ent;
138 struct interface_info *ip;
139 struct client_state *client;
140 unsigned seed;
141 char *server = (char *)0;
142 char *relay = (char *)0;
143 isc_result_t status;
144 int release_mode = 0;
145 omapi_object_t *listener;
146 isc_result_t result;
147 int persist = 0;
148 int no_dhclient_conf = 0;
149 int no_dhclient_db = 0;
150 int no_dhclient_pid = 0;
151 int no_dhclient_script = 0;
152 char *s;
154 /* Make sure we have stdin, stdout and stderr. */
155 #ifdef AMIGA
156 struct Process *me;
158 me = (struct Process *)FindTask(NULL);
159 if (!me->pr_COS)
160 log_perror = 0;
161 #else
162 i = open ("/dev/null", O_RDWR);
163 if (i == 0)
164 i = open ("/dev/null", O_RDWR);
165 if (i == 1) {
166 i = open ("/dev/null", O_RDWR);
167 log_perror = 0; /* No sense logging to /dev/null. */
168 } else if (i != -1)
169 close (i);
170 #endif
172 #ifdef __AROS__
173 if (!(SocketBase = OpenLibrary("bsdsocket.library", 4)))
175 fprintf(stderr, "No TCP/IP Stack running!\n");
176 return RETURN_FAIL;
178 if (!(MiamiBase = OpenLibrary("miami.library", 0)))
180 fprintf(stderr, "No miami available!\n");
181 return RETURN_FAIL;
183 atexit(__close_bsdsocket);
184 SetErrnoPtr(&errno, sizeof(errno));
186 static TEXT dh_conf[256];
187 static TEXT dh_db[288];
188 LONG len;
190 dh_conf[0] = dh_db[0] = '\0';
192 if ((len = GetVar("AROSTCP/Config", dh_conf, 256, 0)) > 0)
194 sprintf(dh_db, "%s/dhclient.lease", dh_conf);
195 strcpy(dh_conf + len, "/dhclient.conf");
197 path_dhclient_conf = dh_conf;
198 path_dhclient_db = dh_db;
201 #endif
203 #ifdef SYSLOG_4_2
204 openlog ("dhclient", LOG_NDELAY);
205 log_priority = LOG_DAEMON;
206 #else
207 openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
208 #endif
210 #if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
211 setlogmask (LOG_UPTO (LOG_INFO));
212 #endif
214 #if defined (DEBUG)
215 log_debug("conf: %s", path_dhclient_conf);
216 log_debug("db: %s", path_dhclient_db);
217 #endif
219 /* Set up the OMAPI. */
220 status = omapi_init ();
221 if (status != ISC_R_SUCCESS)
222 log_fatal ("Can't initialize OMAPI: %s",
223 isc_result_totext (status));
225 /* Set up the OMAPI wrappers for various server database internal
226 objects. */
227 dhcp_common_objects_setup ();
229 dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
230 dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
231 dhcp_interface_startup_hook = dhclient_interface_startup_hook;
233 for (i = 1; i < argc; i++) {
234 if (!strcmp (argv [i], "-r")) {
235 release_mode = 1;
236 no_daemon = 1;
237 } else if (!strcmp (argv [i], "-p")) {
238 if (++i == argc)
239 usage ();
240 local_port = htons (atoi (argv [i]));
241 log_debug ("binding to user-specified port %d",
242 ntohs (local_port));
243 } else if (!strcmp (argv [i], "-d")) {
244 no_daemon = 1;
245 } else if (!strcmp (argv [i], "-pf")) {
246 if (++i == argc)
247 usage ();
248 path_dhclient_pid = argv [i];
249 no_dhclient_pid = 1;
250 } else if (!strcmp (argv [i], "-cf")) {
251 if (++i == argc)
252 usage ();
253 path_dhclient_conf = argv [i];
254 no_dhclient_conf = 1;
255 } else if (!strcmp (argv [i], "-lf")) {
256 if (++i == argc)
257 usage ();
258 path_dhclient_db = argv [i];
259 no_dhclient_db = 1;
260 } else if (!strcmp (argv [i], "-sf")) {
261 if (++i == argc)
262 usage ();
263 path_dhclient_script = argv [i];
264 no_dhclient_script = 1;
265 } else if (!strcmp (argv [i], "-1")) {
266 onetry = 1;
267 } else if (!strcmp (argv [i], "-q")) {
268 quiet = 1;
269 quiet_interface_discovery = 1;
270 } else if (!strcmp (argv [i], "-s")) {
271 if (++i == argc)
272 usage ();
273 server = argv [i];
274 } else if (!strcmp (argv [i], "-g")) {
275 if (++i == argc)
276 usage ();
277 relay = argv [i];
278 } else if (!strcmp (argv [i], "-nw")) {
279 nowait = 1;
280 } else if (!strcmp (argv [i], "-n")) {
281 /* do not start up any interfaces */
282 interfaces_requested = 1;
283 } else if (!strcmp (argv [i], "-w")) {
284 /* do not exit if there are no broadcast interfaces. */
285 persist = 1;
286 } else if (!strcmp (argv [i], "-e")) {
287 struct string_list *tmp;
288 if (++i == argc)
289 usage ();
290 tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL);
291 if (!tmp)
292 log_fatal ("No memory for %s", argv [i]);
293 strcpy (tmp -> string, argv [i]);
294 tmp -> next = client_env;
295 client_env = tmp;
296 client_env_count++;
297 } else if (!strcmp (argv [i], "--version")) {
298 log_info ("isc-dhclient-%s", DHCP_VERSION);
299 exit (0);
300 } else if (argv [i][0] == '-') {
301 usage ();
302 } else {
303 struct interface_info *tmp = (struct interface_info *)0;
304 status = interface_allocate (&tmp, MDL);
305 if (status != ISC_R_SUCCESS)
306 log_fatal ("Can't record interface %s:%s",
307 argv [i], isc_result_totext (status));
308 if (strlen (argv [i]) > sizeof tmp -> name)
309 log_fatal ("%s: interface name too long (max %ld)",
310 argv [i], (long)strlen (argv [i]));
311 strcpy (tmp -> name, argv [i]);
312 if (interfaces) {
313 interface_reference (&tmp -> next,
314 interfaces, MDL);
315 interface_dereference (&interfaces, MDL);
317 interface_reference (&interfaces, tmp, MDL);
318 tmp -> flags = INTERFACE_REQUESTED;
319 interfaces_requested = 1;
323 if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
324 path_dhclient_conf = s;
326 if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) {
327 path_dhclient_db = s;
329 if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) {
330 path_dhclient_pid = s;
332 if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) {
333 path_dhclient_script = s;
336 /* first kill of any currently running client */
337 if (release_mode) {
338 FILE *pidfd;
339 pid_t oldpid;
340 long temp;
341 int e;
343 oldpid = 0;
344 if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
345 e = fscanf(pidfd, "%ld\n", &temp);
346 oldpid = (pid_t)temp;
348 if (e != 0 && e != EOF) {
349 if (oldpid) {
350 if (kill(oldpid, SIGTERM) == 0)
351 unlink(path_dhclient_pid);
354 fclose(pidfd);
358 if (!quiet) {
359 log_info ("%s %s", message, DHCP_VERSION);
360 log_info ("%s", copyright);
361 log_info ("%s", arr);
362 log_info ("%s", url);
363 log_info ("%s", "");
364 } else
365 log_perror = 0;
367 /* If we're given a relay agent address to insert, for testing
368 purposes, figure out what it is. */
369 if (relay) {
370 if (!inet_aton (relay, &giaddr)) {
371 struct hostent *he;
372 he = gethostbyname (relay);
373 if (he) {
374 memcpy (&giaddr, he -> h_addr_list [0],
375 sizeof giaddr);
376 } else {
377 log_fatal ("%s: no such host", relay);
382 /* Default to the DHCP/BOOTP port. */
383 if (!local_port) {
384 /* If we're faking a relay agent, and we're not using loopback,
385 use the server port, not the client port. */
386 if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
387 local_port = htons(67);
388 } else {
389 ent = getservbyname ("dhcpc", "udp");
390 if (!ent)
391 local_port = htons (68);
392 else
393 local_port = ent -> s_port;
394 #ifndef __CYGWIN32__
395 #ifndef __AROS__
396 endservent ();
397 #endif
398 #endif
402 /* If we're faking a relay agent, and we're not using loopback,
403 we're using the server port, not the client port. */
404 if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
405 remote_port = local_port;
406 } else
407 remote_port = htons (ntohs (local_port) - 1); /* XXX */
409 /* Get the current time... */
410 GET_TIME (&cur_time);
412 sockaddr_broadcast.sin_family = AF_INET;
413 sockaddr_broadcast.sin_port = remote_port;
414 if (server) {
415 if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) {
416 struct hostent *he;
417 he = gethostbyname (server);
418 if (he) {
419 memcpy (&sockaddr_broadcast.sin_addr,
420 he -> h_addr_list [0],
421 sizeof sockaddr_broadcast.sin_addr);
422 } else
423 sockaddr_broadcast.sin_addr.s_addr =
424 INADDR_BROADCAST;
426 } else {
427 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
430 inaddr_any.s_addr = INADDR_ANY;
432 /* Discover all the network interfaces. */
433 discover_interfaces (DISCOVER_UNCONFIGURED);
435 /* Parse the dhclient.conf file. */
436 read_client_conf ();
438 /* Parse the lease database. */
439 read_client_leases ();
441 /* Rewrite the lease database... */
442 rewrite_client_leases ();
444 /* XXX */
445 /* config_counter(&snd_counter, &rcv_counter); */
447 /* If no broadcast interfaces were discovered, call the script
448 and tell it so. */
449 if (!interfaces) {
450 #ifndef BUILTIN_IFCONFIG
451 /* Call dhclient-script with the NBI flag, in case somebody
452 cares. */
453 script_init ((struct client_state *)0, "NBI",
454 (struct string_list *)0);
455 script_go ((struct client_state *)0);
456 #endif
457 /* If we haven't been asked to persist, waiting for new
458 interfaces, then just exit. */
459 if (!persist) {
460 /* Nothing more to do. */
461 log_info ("No broadcast interfaces found - exiting.");
462 exit (0);
464 } else if (!release_mode) {
465 /* Call the script with the list of interfaces. */
466 for (ip = interfaces; ip; ip = ip -> next) {
467 /* If interfaces were specified, don't configure
468 interfaces that weren't specified! */
469 if (interfaces_requested &&
470 ((ip -> flags & (INTERFACE_REQUESTED |
471 INTERFACE_AUTOMATIC)) !=
472 INTERFACE_REQUESTED))
473 continue;
474 #ifdef BUILTIN_IFCONFIG
475 interface_preinit (ip->client);
476 #else
477 script_init (ip -> client,
478 "PREINIT", (struct string_list *)0);
479 if (ip -> client -> alias)
480 script_write_params (ip -> client, "alias_",
481 ip -> client -> alias);
482 script_go (ip -> client);
483 #endif
487 /* At this point, all the interfaces that the script thinks
488 are relevant should be running, so now we once again call
489 discover_interfaces(), and this time ask it to actually set
490 up the interfaces. */
491 discover_interfaces (interfaces_requested
492 ? DISCOVER_REQUESTED
493 : DISCOVER_RUNNING);
495 /* Make up a seed for the random number generator from current
496 time plus the sum of the last four bytes of each
497 interface's hardware address interpreted as an integer.
498 Not much entropy, but we're booting, so we're not likely to
499 find anything better. */
500 seed = 0;
501 for (ip = interfaces; ip; ip = ip -> next) {
502 int junk;
503 memcpy (&junk,
504 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
505 sizeof seed], sizeof seed);
506 seed += junk;
508 srandom (seed + cur_time);
510 /* Start a configuration state machine for each interface. */
511 for (ip = interfaces; ip; ip = ip -> next) {
512 ip -> flags |= INTERFACE_RUNNING;
513 for (client = ip -> client; client; client = client -> next) {
514 if (release_mode)
515 do_release (client);
516 else {
517 client -> state = S_INIT;
518 /* Set up a timeout to start the initialization
519 process. */
520 add_timeout (cur_time + random () % 5,
521 state_reboot, client, 0, 0);
526 if (release_mode)
527 return 0;
529 /* Start up a listener for the object management API protocol. */
530 if (top_level_config.omapi_port != -1) {
531 listener = (omapi_object_t *)0;
532 result = omapi_generic_new (&listener, MDL);
533 if (result != ISC_R_SUCCESS)
534 log_fatal ("Can't allocate new generic object: %s\n",
535 isc_result_totext (result));
536 result = omapi_protocol_listen (listener,
537 (unsigned)
538 top_level_config.omapi_port,
540 if (result != ISC_R_SUCCESS)
541 log_fatal ("Can't start OMAPI protocol: %s",
542 isc_result_totext (result));
545 /* Set up the bootp packet handler... */
546 bootp_packet_handler = do_packet;
548 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
549 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
550 dmalloc_cutoff_generation = dmalloc_generation;
551 dmalloc_longterm = dmalloc_outstanding;
552 dmalloc_outstanding = 0;
553 #endif
555 /* If we're not supposed to wait before getting the address,
556 don't. */
557 if (nowait)
558 go_daemon ();
560 /* If we're not going to daemonize, write the pid file
561 now. */
562 if (no_daemon || nowait)
563 write_client_pid_file ();
565 /* Start dispatching packets and timeouts... */
566 dispatch ();
568 /*NOTREACHED*/
569 return 0;
572 static void usage ()
574 log_info ("%s %s", message, DHCP_VERSION);
575 log_info ("%s", copyright);
576 log_info ("%s", arr);
577 log_info ("%s", url);
579 log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s",
580 "[-s server]");
581 log_error (" [-cf config-file] [-lf lease-file]%s",
582 "[-pf pid-file] [-e VAR=val]");
583 log_fatal (" [-sf script-file] [interface]");
586 isc_result_t find_class (struct class **c,
587 const char *s, const char *file, int line)
589 return 0;
592 int check_collection (packet, lease, collection)
593 struct packet *packet;
594 struct lease *lease;
595 struct collection *collection;
597 return 0;
600 void classify (packet, class)
601 struct packet *packet;
602 struct class *class;
606 int unbill_class (lease, class)
607 struct lease *lease;
608 struct class *class;
610 return 0;
613 int find_subnet (struct subnet **sp,
614 struct iaddr addr, const char *file, int line)
616 return 0;
619 /* Individual States:
621 * Each routine is called from the dhclient_state_machine() in one of
622 * these conditions:
623 * -> entering INIT state
624 * -> recvpacket_flag == 0: timeout in this state
625 * -> otherwise: received a packet in this state
627 * Return conditions as handled by dhclient_state_machine():
628 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
629 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
630 * Returns 0: finish the nap which was interrupted for no good reason.
632 * Several per-interface variables are used to keep track of the process:
633 * active_lease: the lease that is being used on the interface
634 * (null pointer if not configured yet).
635 * offered_leases: leases corresponding to DHCPOFFER messages that have
636 * been sent to us by DHCP servers.
637 * acked_leases: leases corresponding to DHCPACK messages that have been
638 * sent to us by DHCP servers.
639 * sendpacket: DHCP packet we're trying to send.
640 * destination: IP address to send sendpacket to
641 * In addition, there are several relevant per-lease variables.
642 * T1_expiry, T2_expiry, lease_expiry: lease milestones
643 * In the active lease, these control the process of renewing the lease;
644 * In leases on the acked_leases list, this simply determines when we
645 * can no longer legitimately use the lease.
648 void state_reboot (cpp)
649 void *cpp;
651 struct client_state *client = cpp;
653 /* If we don't remember an active lease, go straight to INIT. */
654 if (!client -> active ||
655 client -> active -> is_bootp ||
656 client -> active -> expiry <= cur_time) {
657 state_init (client);
658 return;
661 /* We are in the rebooting state. */
662 client -> state = S_REBOOTING;
664 /* make_request doesn't initialize xid because it normally comes
665 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
666 so pick an xid now. */
667 client -> xid = random ();
669 /* Make a DHCPREQUEST packet, and set appropriate per-interface
670 flags. */
671 make_request (client, client -> active);
672 client -> destination = iaddr_broadcast;
673 client -> first_sending = cur_time;
674 client -> interval = client -> config -> initial_interval;
676 /* Zap the medium list... */
677 client -> medium = (struct string_list *)0;
679 /* Send out the first DHCPREQUEST packet. */
680 send_request (client);
683 /* Called when a lease has completely expired and we've been unable to
684 renew it. */
686 void state_init (cpp)
687 void *cpp;
689 struct client_state *client = cpp;
691 ASSERT_STATE(state, S_INIT);
693 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
694 flags. */
695 make_discover (client, client -> active);
696 client -> xid = client -> packet.xid;
697 client -> destination = iaddr_broadcast;
698 client -> state = S_SELECTING;
699 client -> first_sending = cur_time;
700 client -> interval = client -> config -> initial_interval;
702 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
703 to go out. */
704 send_discover (client);
707 /* state_selecting is called when one or more DHCPOFFER packets have been
708 received and a configurable period of time has passed. */
710 void state_selecting (cpp)
711 void *cpp;
713 struct client_state *client = cpp;
714 struct client_lease *lp, *next, *picked;
717 ASSERT_STATE(state, S_SELECTING);
719 /* Cancel state_selecting and send_discover timeouts, since either
720 one could have got us here. */
721 cancel_timeout (state_selecting, client);
722 cancel_timeout (send_discover, client);
724 /* We have received one or more DHCPOFFER packets. Currently,
725 the only criterion by which we judge leases is whether or
726 not we get a response when we arp for them. */
727 picked = (struct client_lease *)0;
728 for (lp = client -> offered_leases; lp; lp = next) {
729 next = lp -> next;
731 /* Check to see if we got an ARPREPLY for the address
732 in this particular lease. */
733 if (!picked) {
734 picked = lp;
735 picked -> next = (struct client_lease *)0;
736 } else {
737 destroy_client_lease (lp);
740 client -> offered_leases = (struct client_lease *)0;
742 /* If we just tossed all the leases we were offered, go back
743 to square one. */
744 if (!picked) {
745 client -> state = S_INIT;
746 state_init (client);
747 return;
750 /* If it was a BOOTREPLY, we can just take the address right now. */
751 if (picked -> is_bootp) {
752 client -> new = picked;
754 /* Make up some lease expiry times
755 XXX these should be configurable. */
756 client -> new -> expiry = cur_time + 12000;
757 client -> new -> renewal += cur_time + 8000;
758 client -> new -> rebind += cur_time + 10000;
760 client -> state = S_REQUESTING;
762 /* Bind to the address we received. */
763 bind_lease (client);
764 return;
767 /* Go to the REQUESTING state. */
768 client -> destination = iaddr_broadcast;
769 client -> state = S_REQUESTING;
770 client -> first_sending = cur_time;
771 client -> interval = client -> config -> initial_interval;
773 /* Make a DHCPREQUEST packet from the lease we picked. */
774 make_request (client, picked);
775 client -> xid = client -> packet.xid;
777 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
778 destroy_client_lease (picked);
780 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
781 send_request (client);
784 /* state_requesting is called when we receive a DHCPACK message after
785 having sent out one or more DHCPREQUEST packets. */
787 void dhcpack (packet)
788 struct packet *packet;
790 struct interface_info *ip = packet -> interface;
791 struct client_state *client;
792 struct client_lease *lease;
793 struct option_cache *oc;
794 struct data_string ds;
796 /* If we're not receptive to an offer right now, or if the offer
797 has an unrecognizable transaction id, then just drop it. */
798 for (client = ip -> client; client; client = client -> next) {
799 if (client -> xid == packet -> raw -> xid)
800 break;
802 if (!client ||
803 (packet -> interface -> hw_address.hlen - 1 !=
804 packet -> raw -> hlen) ||
805 (memcmp (&packet -> interface -> hw_address.hbuf [1],
806 packet -> raw -> chaddr, packet -> raw -> hlen))) {
807 #if defined (DEBUG)
808 log_debug ("DHCPACK in wrong transaction.");
809 #endif
810 return;
813 if (client -> state != S_REBOOTING &&
814 client -> state != S_REQUESTING &&
815 client -> state != S_RENEWING &&
816 client -> state != S_REBINDING) {
817 #if defined (DEBUG)
818 log_debug ("DHCPACK in wrong state.");
819 #endif
820 return;
823 log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
825 lease = packet_to_lease (packet, client);
826 if (!lease) {
827 log_info ("packet_to_lease failed.");
828 return;
831 client -> new = lease;
833 /* Stop resending DHCPREQUEST. */
834 cancel_timeout (send_request, client);
836 /* Figure out the lease time. */
837 oc = lookup_option (&dhcp_universe, client -> new -> options,
838 DHO_DHCP_LEASE_TIME);
839 memset (&ds, 0, sizeof ds);
840 if (oc &&
841 evaluate_option_cache (&ds, packet, (struct lease *)0, client,
842 packet -> options, client -> new -> options,
843 &global_scope, oc, MDL)) {
844 if (ds.len > 3)
845 client -> new -> expiry = getULong (ds.data);
846 else
847 client -> new -> expiry = 0;
848 data_string_forget (&ds, MDL);
849 } else
850 client -> new -> expiry = 0;
852 if (!client -> new -> expiry) {
853 log_error ("no expiry time on offered lease.");
854 /* XXX this is going to be bad - if this _does_
855 XXX happen, we should probably dynamically
856 XXX disqualify the DHCP server that gave us the
857 XXX bad packet from future selections and
858 XXX then go back into the init state. */
859 state_init (client);
860 return;
863 /* A number that looks negative here is really just very large,
864 because the lease expiry offset is unsigned. */
865 if (client -> new -> expiry < 0)
866 client -> new -> expiry = TIME_MAX;
867 /* Take the server-provided renewal time if there is one. */
868 oc = lookup_option (&dhcp_universe, client -> new -> options,
869 DHO_DHCP_RENEWAL_TIME);
870 if (oc &&
871 evaluate_option_cache (&ds, packet, (struct lease *)0, client,
872 packet -> options, client -> new -> options,
873 &global_scope, oc, MDL)) {
874 if (ds.len > 3)
875 client -> new -> renewal = getULong (ds.data);
876 else
877 client -> new -> renewal = 0;
878 data_string_forget (&ds, MDL);
879 } else
880 client -> new -> renewal = 0;
882 /* If it wasn't specified by the server, calculate it. */
883 if (!client -> new -> renewal)
884 client -> new -> renewal = client -> new -> expiry / 2 + 1;
886 if (client -> new -> renewal <= 0)
887 client -> new -> renewal = TIME_MAX;
889 /* Now introduce some randomness to the renewal time: */
890 if (client -> new -> renewal <= TIME_MAX / 3 - 3)
891 client -> new -> renewal =
892 (((client -> new -> renewal + 3) * 3 / 4) +
893 (random () % /* XXX NUMS */
894 ((client -> new -> renewal + 3) / 4)));
896 /* Same deal with the rebind time. */
897 oc = lookup_option (&dhcp_universe, client -> new -> options,
898 DHO_DHCP_REBINDING_TIME);
899 if (oc &&
900 evaluate_option_cache (&ds, packet, (struct lease *)0, client,
901 packet -> options, client -> new -> options,
902 &global_scope, oc, MDL)) {
903 if (ds.len > 3)
904 client -> new -> rebind = getULong (ds.data);
905 else
906 client -> new -> rebind = 0;
907 data_string_forget (&ds, MDL);
908 } else
909 client -> new -> rebind = 0;
911 if (client -> new -> rebind <= 0) {
912 if (client -> new -> expiry <= TIME_MAX / 7)
913 client -> new -> rebind =
914 client -> new -> expiry * 7 / 8;
915 else
916 client -> new -> rebind =
917 client -> new -> expiry / 8 * 7;
920 /* Make sure our randomness didn't run the renewal time past the
921 rebind time. */
922 if (client -> new -> renewal > client -> new -> rebind) {
923 if (client -> new -> rebind <= TIME_MAX / 3)
924 client -> new -> renewal =
925 client -> new -> rebind * 3 / 4;
926 else
927 client -> new -> renewal =
928 client -> new -> rebind / 4 * 3;
931 client -> new -> expiry += cur_time;
932 /* Lease lengths can never be negative. */
933 if (client -> new -> expiry < cur_time)
934 client -> new -> expiry = TIME_MAX;
935 client -> new -> renewal += cur_time;
936 if (client -> new -> renewal < cur_time)
937 client -> new -> renewal = TIME_MAX;
938 client -> new -> rebind += cur_time;
939 if (client -> new -> rebind < cur_time)
940 client -> new -> rebind = TIME_MAX;
942 bind_lease (client);
945 void bind_lease (client)
946 struct client_state *client;
948 /* Remember the medium. */
949 client -> new -> medium = client -> medium;
951 #ifdef BUILTIN_IFCONFIG
952 if (interface_bind (client)) {
953 #else
954 /* Run the client script with the new parameters. */
955 script_init (client, (client -> state == S_REQUESTING
956 ? "BOUND"
957 : (client -> state == S_RENEWING
958 ? "RENEW"
959 : (client -> state == S_REBOOTING
960 ? "REBOOT" : "REBIND"))),
961 client -> new -> medium);
962 if (client -> active && client -> state != S_REBOOTING)
963 script_write_params (client, "old_", client -> active);
964 script_write_params (client, "new_", client -> new);
965 if (client -> alias)
966 script_write_params (client, "alias_", client -> alias);
968 /* If the BOUND/RENEW code detects another machine using the
969 offered address, it exits nonzero. We need to send a
970 DHCPDECLINE and toss the lease. */
971 if (script_go (client)) {
972 #endif
973 make_decline (client, client -> new);
974 send_decline (client);
975 destroy_client_lease (client -> new);
976 client -> new = (struct client_lease *)0;
977 state_init (client);
978 return;
981 /* Write out the new lease. */
982 write_client_lease (client, client -> new, 0, 0);
984 /* Replace the old active lease with the new one. */
985 if (client -> active)
986 destroy_client_lease (client -> active);
987 client -> active = client -> new;
988 client -> new = (struct client_lease *)0;
990 /* Set up a timeout to start the renewal process. */
991 add_timeout (client -> active -> renewal,
992 state_bound, client, 0, 0);
994 log_info ("bound to %s -- renewal in %ld seconds.",
995 piaddr (client -> active -> address),
996 (long)(client -> active -> renewal - cur_time));
997 client -> state = S_BOUND;
998 reinitialize_interfaces ();
999 go_daemon ();
1000 if (client -> config -> do_forward_update) {
1001 client -> dns_update_timeout = 1;
1002 add_timeout (cur_time + 1, client_dns_update_timeout,
1003 client, 0, 0);
1007 /* state_bound is called when we've successfully bound to a particular
1008 lease, but the renewal time on that lease has expired. We are
1009 expected to unicast a DHCPREQUEST to the server that gave us our
1010 original lease. */
1012 void state_bound (cpp)
1013 void *cpp;
1015 struct client_state *client = cpp;
1016 struct option_cache *oc;
1017 struct data_string ds;
1019 ASSERT_STATE(state, S_BOUND);
1021 /* T1 has expired. */
1022 make_request (client, client -> active);
1023 client -> xid = client -> packet.xid;
1025 memset (&ds, 0, sizeof ds);
1026 oc = lookup_option (&dhcp_universe, client -> active -> options,
1027 DHO_DHCP_SERVER_IDENTIFIER);
1028 if (oc &&
1029 evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
1030 client, (struct option_state *)0,
1031 client -> active -> options,
1032 &global_scope, oc, MDL)) {
1033 if (ds.len > 3) {
1034 memcpy (client -> destination.iabuf, ds.data, 4);
1035 client -> destination.len = 4;
1036 } else
1037 client -> destination = iaddr_broadcast;
1039 data_string_forget (&ds, MDL);
1040 } else
1041 client -> destination = iaddr_broadcast;
1043 client -> first_sending = cur_time;
1044 client -> interval = client -> config -> initial_interval;
1045 client -> state = S_RENEWING;
1047 /* Send the first packet immediately. */
1048 send_request (client);
1051 /* state_stop is called when we've been told to shut down. We unconfigure
1052 the interfaces, and then stop operating until told otherwise. */
1054 void state_stop (cpp)
1055 void *cpp;
1057 struct client_state *client = cpp;
1059 /* Cancel all timeouts. */
1060 cancel_timeout (state_selecting, client);
1061 cancel_timeout (send_discover, client);
1062 cancel_timeout (send_request, client);
1063 cancel_timeout (state_bound, client);
1065 /* If we have an address, unconfigure it. */
1066 if (client -> active) {
1067 #ifdef BUILTIN_IFCONFIG
1068 interface_stop (client);
1069 #else
1070 script_init (client, "STOP", client -> active -> medium);
1071 script_write_params (client, "old_", client -> active);
1072 if (client -> alias)
1073 script_write_params (client, "alias_",
1074 client -> alias);
1075 script_go (client);
1076 #endif
1080 int commit_leases ()
1082 return 0;
1085 int write_lease (lease)
1086 struct lease *lease;
1088 return 0;
1091 int write_host (host)
1092 struct host_decl *host;
1094 return 0;
1097 void db_startup (testp)
1098 int testp;
1102 void bootp (packet)
1103 struct packet *packet;
1105 struct iaddrlist *ap;
1107 if (packet -> raw -> op != BOOTREPLY)
1108 return;
1110 /* If there's a reject list, make sure this packet's sender isn't
1111 on it. */
1112 for (ap = packet -> interface -> client -> config -> reject_list;
1113 ap; ap = ap -> next) {
1114 if (addr_eq (packet -> client_addr, ap -> addr)) {
1115 log_info ("BOOTREPLY from %s rejected.",
1116 piaddr (ap -> addr));
1117 return;
1121 dhcpoffer (packet);
1125 void dhcp (packet)
1126 struct packet *packet;
1128 struct iaddrlist *ap;
1129 void (*handler) PROTO ((struct packet *));
1130 const char *type;
1132 switch (packet -> packet_type) {
1133 case DHCPOFFER:
1134 handler = dhcpoffer;
1135 type = "DHCPOFFER";
1136 break;
1138 case DHCPNAK:
1139 handler = dhcpnak;
1140 type = "DHCPNACK";
1141 break;
1143 case DHCPACK:
1144 handler = dhcpack;
1145 type = "DHCPACK";
1146 break;
1148 default:
1149 return;
1152 /* If there's a reject list, make sure this packet's sender isn't
1153 on it. */
1154 for (ap = packet -> interface -> client -> config -> reject_list;
1155 ap; ap = ap -> next) {
1156 if (addr_eq (packet -> client_addr, ap -> addr)) {
1157 log_info ("%s from %s rejected.",
1158 type, piaddr (ap -> addr));
1159 return;
1162 (*handler) (packet);
1165 void dhcpoffer (packet)
1166 struct packet *packet;
1168 struct interface_info *ip = packet -> interface;
1169 struct client_state *client;
1170 struct client_lease *lease, *lp;
1171 int i;
1172 int stop_selecting;
1173 const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
1174 char obuf [1024];
1176 #ifdef DEBUG_PACKET
1177 dump_packet (packet);
1178 #endif
1180 /* Find a client state that matches the xid... */
1181 for (client = ip -> client; client; client = client -> next)
1182 if (client -> xid == packet -> raw -> xid)
1183 break;
1185 /* If we're not receptive to an offer right now, or if the offer
1186 has an unrecognizable transaction id, then just drop it. */
1187 if (!client ||
1188 client -> state != S_SELECTING ||
1189 (packet -> interface -> hw_address.hlen - 1 !=
1190 packet -> raw -> hlen) ||
1191 (memcmp (&packet -> interface -> hw_address.hbuf [1],
1192 packet -> raw -> chaddr, packet -> raw -> hlen))) {
1193 #if defined (DEBUG)
1194 log_debug ("%s in wrong transaction.", name);
1195 #endif
1196 return;
1199 sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
1202 /* If this lease doesn't supply the minimum required parameters,
1203 blow it off. */
1204 if (client -> config -> required_options) {
1205 for (i = 0; client -> config -> required_options [i]; i++) {
1206 if (!lookup_option
1207 (&dhcp_universe, packet -> options,
1208 client -> config -> required_options [i])) {
1209 log_info ("%s: no %s option.",
1210 obuf, (dhcp_universe.options
1211 [client -> config -> required_options [i]]
1212 -> name));
1213 return;
1218 /* If we've already seen this lease, don't record it again. */
1219 for (lease = client -> offered_leases; lease; lease = lease -> next) {
1220 if (lease -> address.len == sizeof packet -> raw -> yiaddr &&
1221 !memcmp (lease -> address.iabuf,
1222 &packet -> raw -> yiaddr, lease -> address.len)) {
1223 log_debug ("%s: already seen.", obuf);
1224 return;
1228 lease = packet_to_lease (packet, client);
1229 if (!lease) {
1230 log_info ("%s: packet_to_lease failed.", obuf);
1231 return;
1234 /* If this lease was acquired through a BOOTREPLY, record that
1235 fact. */
1236 if (!packet -> options_valid || !packet -> packet_type)
1237 lease -> is_bootp = 1;
1239 /* Record the medium under which this lease was offered. */
1240 lease -> medium = client -> medium;
1242 /* Figure out when we're supposed to stop selecting. */
1243 stop_selecting = (client -> first_sending +
1244 client -> config -> select_interval);
1246 /* If this is the lease we asked for, put it at the head of the
1247 list, and don't mess with the arp request timeout. */
1248 if (lease -> address.len == client -> requested_address.len &&
1249 !memcmp (lease -> address.iabuf,
1250 client -> requested_address.iabuf,
1251 client -> requested_address.len)) {
1252 lease -> next = client -> offered_leases;
1253 client -> offered_leases = lease;
1254 } else {
1255 /* Put the lease at the end of the list. */
1256 lease -> next = (struct client_lease *)0;
1257 if (!client -> offered_leases)
1258 client -> offered_leases = lease;
1259 else {
1260 for (lp = client -> offered_leases; lp -> next;
1261 lp = lp -> next)
1263 lp -> next = lease;
1267 /* If the selecting interval has expired, go immediately to
1268 state_selecting(). Otherwise, time out into
1269 state_selecting at the select interval. */
1270 if (stop_selecting <= 0)
1271 state_selecting (client);
1272 else {
1273 add_timeout (stop_selecting, state_selecting, client, 0, 0);
1274 cancel_timeout (send_discover, client);
1276 log_info ("%s", obuf);
1279 /* Allocate a client_lease structure and initialize it from the parameters
1280 in the specified packet. */
1282 struct client_lease *packet_to_lease (packet, client)
1283 struct packet *packet;
1284 struct client_state *client;
1286 struct client_lease *lease;
1287 unsigned i;
1288 struct option_cache *oc;
1289 struct data_string data;
1291 lease = (struct client_lease *)new_client_lease (MDL);
1293 if (!lease) {
1294 log_error ("packet_to_lease: no memory to record lease.\n");
1295 return (struct client_lease *)0;
1298 memset (lease, 0, sizeof *lease);
1300 /* Copy the lease options. */
1301 option_state_reference (&lease -> options, packet -> options, MDL);
1303 lease -> address.len = sizeof (packet -> raw -> yiaddr);
1304 memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
1305 lease -> address.len);
1307 memset (&data, 0, sizeof data);
1309 if (client -> config -> vendor_space_name) {
1310 i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
1312 /* See if there was a vendor encapsulation option. */
1313 oc = lookup_option (&dhcp_universe, lease -> options, i);
1314 if (oc &&
1315 client -> config -> vendor_space_name &&
1316 evaluate_option_cache (&data, packet,
1317 (struct lease *)0, client,
1318 packet -> options, lease -> options,
1319 &global_scope, oc, MDL)) {
1320 if (data.len) {
1321 parse_encapsulated_suboptions
1322 (packet -> options, &dhcp_options [i],
1323 data.data, data.len, &dhcp_universe,
1324 client -> config -> vendor_space_name
1327 data_string_forget (&data, MDL);
1329 } else
1330 i = 0;
1332 /* Figure out the overload flag. */
1333 oc = lookup_option (&dhcp_universe, lease -> options,
1334 DHO_DHCP_OPTION_OVERLOAD);
1335 if (oc &&
1336 evaluate_option_cache (&data, packet, (struct lease *)0, client,
1337 packet -> options, lease -> options,
1338 &global_scope, oc, MDL)) {
1339 if (data.len > 0)
1340 i = data.data [0];
1341 else
1342 i = 0;
1343 data_string_forget (&data, MDL);
1344 } else
1345 i = 0;
1347 /* If the server name was filled out, copy it. */
1348 if (!(i & 2) && packet -> raw -> sname [0]) {
1349 unsigned len;
1350 /* Don't count on the NUL terminator. */
1351 for (len = 0; len < 64; len++)
1352 if (!packet -> raw -> sname [len])
1353 break;
1354 lease -> server_name = dmalloc (len + 1, MDL);
1355 if (!lease -> server_name) {
1356 log_error ("dhcpoffer: no memory for server name.\n");
1357 destroy_client_lease (lease);
1358 return (struct client_lease *)0;
1359 } else {
1360 memcpy (lease -> server_name,
1361 packet -> raw -> sname, len);
1362 lease -> server_name [len] = 0;
1366 /* Ditto for the filename. */
1367 if (!(i & 1) && packet -> raw -> file [0]) {
1368 unsigned len;
1369 /* Don't count on the NUL terminator. */
1370 for (len = 0; len < 64; len++)
1371 if (!packet -> raw -> file [len])
1372 break;
1373 lease -> filename = dmalloc (len + 1, MDL);
1374 if (!lease -> filename) {
1375 log_error ("dhcpoffer: no memory for filename.\n");
1376 destroy_client_lease (lease);
1377 return (struct client_lease *)0;
1378 } else {
1379 memcpy (lease -> filename,
1380 packet -> raw -> file, len);
1381 lease -> filename [len] = 0;
1385 execute_statements_in_scope ((struct binding_value **)0,
1386 (struct packet *)packet,
1387 (struct lease *)0, client,
1388 lease -> options, lease -> options,
1389 &global_scope,
1390 client -> config -> on_receipt,
1391 (struct group *)0);
1393 return lease;
1396 void dhcpnak (packet)
1397 struct packet *packet;
1399 struct interface_info *ip = packet -> interface;
1400 struct client_state *client;
1402 /* Find a client state that matches the xid... */
1403 for (client = ip -> client; client; client = client -> next)
1404 if (client -> xid == packet -> raw -> xid)
1405 break;
1407 /* If we're not receptive to an offer right now, or if the offer
1408 has an unrecognizable transaction id, then just drop it. */
1409 if (!client ||
1410 (packet -> interface -> hw_address.hlen - 1 !=
1411 packet -> raw -> hlen) ||
1412 (memcmp (&packet -> interface -> hw_address.hbuf [1],
1413 packet -> raw -> chaddr, packet -> raw -> hlen))) {
1414 #if defined (DEBUG)
1415 log_debug ("DHCPNAK in wrong transaction.");
1416 #endif
1417 return;
1420 if (client -> state != S_REBOOTING &&
1421 client -> state != S_REQUESTING &&
1422 client -> state != S_RENEWING &&
1423 client -> state != S_REBINDING) {
1424 #if defined (DEBUG)
1425 log_debug ("DHCPNAK in wrong state.");
1426 #endif
1427 return;
1430 log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
1432 if (!client -> active) {
1433 #if defined (DEBUG)
1434 log_info ("DHCPNAK with no active lease.\n");
1435 #endif
1436 return;
1439 destroy_client_lease (client -> active);
1440 client -> active = (struct client_lease *)0;
1442 /* Stop sending DHCPREQUEST packets... */
1443 cancel_timeout (send_request, client);
1445 client -> state = S_INIT;
1446 state_init (client);
1449 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1450 one after the right interval has expired. If we don't get an offer by
1451 the time we reach the panic interval, call the panic function. */
1453 void send_discover (cpp)
1454 void *cpp;
1456 struct client_state *client = cpp;
1458 int result;
1459 int interval;
1460 int increase = 1;
1462 /* Figure out how long it's been since we started transmitting. */
1463 interval = cur_time - client -> first_sending;
1465 /* If we're past the panic timeout, call the script and tell it
1466 we haven't found anything for this interface yet. */
1467 if (interval > client -> config -> timeout) {
1468 state_panic (client);
1469 return;
1472 /* If we're selecting media, try the whole list before doing
1473 the exponential backoff, but if we've already received an
1474 offer, stop looping, because we obviously have it right. */
1475 if (!client -> offered_leases &&
1476 client -> config -> media) {
1477 int fail = 0;
1478 again:
1479 if (client -> medium) {
1480 client -> medium = client -> medium -> next;
1481 increase = 0;
1483 if (!client -> medium) {
1484 if (fail)
1485 log_fatal ("No valid media types for %s!",
1486 client -> interface -> name);
1487 client -> medium =
1488 client -> config -> media;
1489 increase = 1;
1492 log_info ("Trying medium \"%s\" %d",
1493 client -> medium -> string, increase);
1494 #ifdef BUILTIN_IFCONFIG
1495 if (interface_medium (client, client -> medium -> string)) {
1496 #else
1497 script_init (client, "MEDIUM", client -> medium);
1498 if (script_go (client)) {
1499 #endif
1500 fail = 1;
1501 goto again;
1505 /* If we're supposed to increase the interval, do so. If it's
1506 currently zero (i.e., we haven't sent any packets yet), set
1507 it to initial_interval; otherwise, add to it a random number
1508 between zero and two times itself. On average, this means
1509 that it will double with every transmission. */
1510 if (increase) {
1511 if (!client -> interval)
1512 client -> interval =
1513 client -> config -> initial_interval;
1514 else
1515 client -> interval += ((random () >> 2) %
1516 (2 * client -> interval));
1518 /* Don't backoff past cutoff. */
1519 if (client -> interval >
1520 client -> config -> backoff_cutoff)
1521 client -> interval =
1522 ((client -> config -> backoff_cutoff / 2)
1523 + ((random () >> 2) %
1524 client -> config -> backoff_cutoff));
1525 } else if (!client -> interval)
1526 client -> interval = client -> config -> initial_interval;
1528 /* If the backoff would take us to the panic timeout, just use that
1529 as the interval. */
1530 if (cur_time + client -> interval >
1531 client -> first_sending + client -> config -> timeout)
1532 client -> interval =
1533 (client -> first_sending +
1534 client -> config -> timeout) - cur_time + 1;
1536 /* Record the number of seconds since we started sending. */
1537 if (interval < 65536)
1538 client -> packet.secs = htons (interval);
1539 else
1540 client -> packet.secs = htons (65535);
1541 client -> secs = client -> packet.secs;
1543 log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
1544 client -> name ? client -> name : client -> interface -> name,
1545 inet_ntoa (sockaddr_broadcast.sin_addr),
1546 ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
1548 /* Send out a packet. */
1549 result = send_packet (client -> interface, (struct packet *)0,
1550 &client -> packet,
1551 client -> packet_length,
1552 inaddr_any, &sockaddr_broadcast,
1553 (struct hardware *)0);
1555 if (result < 0) {
1556 /* FIXME: Shouldn't we log an error here? */
1559 add_timeout (cur_time + client -> interval,
1560 send_discover, client, 0, 0);
1563 /* state_panic gets called if we haven't received any offers in a preset
1564 amount of time. When this happens, we try to use existing leases that
1565 haven't yet expired, and failing that, we call the client script and
1566 hope it can do something. */
1568 void state_panic (cpp)
1569 void *cpp;
1571 struct client_state *client = cpp;
1572 struct client_lease *loop;
1573 struct client_lease *lp;
1575 loop = lp = client -> active;
1577 log_info ("No DHCPOFFERS received.");
1579 /* We may not have an active lease, but we may have some
1580 predefined leases that we can try. */
1581 if (!client -> active && client -> leases)
1582 goto activate_next;
1584 /* Run through the list of leases and see if one can be used. */
1585 while (client -> active) {
1586 if (client -> active -> expiry > cur_time) {
1587 log_info ("Trying recorded lease %s",
1588 piaddr (client -> active -> address));
1589 #ifdef BUILTIN_IFCONFIG
1590 if (interface_timeout (client)) {
1591 #else
1592 /* Run the client script with the existing
1593 parameters. */
1594 script_init (client, "TIMEOUT",
1595 client -> active -> medium);
1596 script_write_params (client, "new_", client -> active);
1597 if (client -> alias)
1598 script_write_params (client, "alias_",
1599 client -> alias);
1601 /* If the old lease is still good and doesn't
1602 yet need renewal, go into BOUND state and
1603 timeout at the renewal time. */
1604 if (!script_go (client)) {
1605 #endif
1606 if (cur_time < client -> active -> renewal) {
1607 client -> state = S_BOUND;
1608 log_info ("bound: renewal in %ld %s.",
1609 (long)(client -> active -> renewal -
1610 cur_time), "seconds");
1611 add_timeout (client -> active -> renewal,
1612 state_bound, client, 0, 0);
1613 } else {
1614 client -> state = S_BOUND;
1615 log_info ("bound: immediate renewal.");
1616 state_bound (client);
1618 reinitialize_interfaces ();
1619 go_daemon ();
1620 return;
1624 /* If there are no other leases, give up. */
1625 if (!client -> leases) {
1626 client -> leases = client -> active;
1627 client -> active = (struct client_lease *)0;
1628 break;
1631 activate_next:
1632 /* Otherwise, put the active lease at the end of the
1633 lease list, and try another lease.. */
1634 for (lp = client -> leases; lp -> next; lp = lp -> next)
1636 lp -> next = client -> active;
1637 if (lp -> next) {
1638 lp -> next -> next = (struct client_lease *)0;
1640 client -> active = client -> leases;
1641 client -> leases = client -> leases -> next;
1643 /* If we already tried this lease, we've exhausted the
1644 set of leases, so we might as well give up for
1645 now. */
1646 if (client -> active == loop)
1647 break;
1648 else if (!loop)
1649 loop = client -> active;
1652 /* No leases were available, or what was available didn't work, so
1653 tell the shell script that we failed to allocate an address,
1654 and try again later. */
1655 if (onetry) {
1656 if (!quiet)
1657 log_info ("Unable to obtain a lease on first try.%s",
1658 " Exiting.");
1659 exit (2);
1662 log_info ("No working leases in persistent database - sleeping.");
1663 #ifdef BUILTIN_IFCONFIG
1664 interface_fail (client);
1665 #else
1666 script_init (client, "FAIL", (struct string_list *)0);
1667 if (client -> alias)
1668 script_write_params (client, "alias_", client -> alias);
1669 script_go (client);
1670 #endif
1671 client -> state = S_INIT;
1672 add_timeout (cur_time +
1673 ((client -> config -> retry_interval + 1) / 2 +
1674 (random () % client -> config -> retry_interval)),
1675 state_init, client, 0, 0);
1676 go_daemon ();
1679 void send_request (cpp)
1680 void *cpp;
1682 struct client_state *client = cpp;
1684 int result;
1685 int interval;
1686 struct sockaddr_in destination;
1687 struct in_addr from;
1689 /* Figure out how long it's been since we started transmitting. */
1690 interval = cur_time - client -> first_sending;
1692 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1693 past the reboot timeout, go to INIT and see if we can
1694 DISCOVER an address... */
1695 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1696 means either that we're on a network with no DHCP server,
1697 or that our server is down. In the latter case, assuming
1698 that there is a backup DHCP server, DHCPDISCOVER will get
1699 us a new address, but we could also have successfully
1700 reused our old address. In the former case, we're hosed
1701 anyway. This is not a win-prone situation. */
1702 if ((client -> state == S_REBOOTING ||
1703 client -> state == S_REQUESTING) &&
1704 interval > client -> config -> reboot_timeout) {
1705 cancel:
1706 client -> state = S_INIT;
1707 cancel_timeout (send_request, client);
1708 state_init (client);
1709 return;
1712 /* If we're in the reboot state, make sure the media is set up
1713 correctly. */
1714 if (client -> state == S_REBOOTING &&
1715 !client -> medium &&
1716 client -> active -> medium ) {
1717 #ifdef BUILTIN_IFCONFIG
1718 if (interface_medium (client, client -> active -> medium -> string))
1719 #else
1720 script_init (client, "MEDIUM", client -> active -> medium);
1722 /* If the medium we chose won't fly, go to INIT state. */
1723 if (script_go (client))
1724 #endif
1725 goto cancel;
1727 /* Record the medium. */
1728 client -> medium = client -> active -> medium;
1731 /* If the lease has expired, relinquish the address and go back
1732 to the INIT state. */
1733 if (client -> state != S_REQUESTING &&
1734 cur_time > client -> active -> expiry) {
1735 #ifdef BUILTIN_IFCONFIG
1736 interface_expire (client);
1737 interface_preinit (client);
1738 #else
1739 /* Run the client script with the new parameters. */
1740 script_init (client, "EXPIRE", (struct string_list *)0);
1741 script_write_params (client, "old_", client -> active);
1742 if (client -> alias)
1743 script_write_params (client, "alias_",
1744 client -> alias);
1745 script_go (client);
1747 /* Now do a preinit on the interface so that we can
1748 discover a new address. */
1749 script_init (client, "PREINIT", (struct string_list *)0);
1750 if (client -> alias)
1751 script_write_params (client, "alias_",
1752 client -> alias);
1753 script_go (client);
1754 #endif
1756 client -> state = S_INIT;
1757 state_init (client);
1758 return;
1761 /* Do the exponential backoff... */
1762 if (!client -> interval)
1763 client -> interval = client -> config -> initial_interval;
1764 else {
1765 client -> interval += ((random () >> 2) %
1766 (2 * client -> interval));
1769 /* Don't backoff past cutoff. */
1770 if (client -> interval >
1771 client -> config -> backoff_cutoff)
1772 client -> interval =
1773 ((client -> config -> backoff_cutoff / 2)
1774 + ((random () >> 2) %
1775 client -> config -> backoff_cutoff));
1777 /* If the backoff would take us to the expiry time, just set the
1778 timeout to the expiry time. */
1779 if (client -> state != S_REQUESTING &&
1780 cur_time + client -> interval > client -> active -> expiry)
1781 client -> interval =
1782 client -> active -> expiry - cur_time + 1;
1784 /* If the lease T2 time has elapsed, or if we're not yet bound,
1785 broadcast the DHCPREQUEST rather than unicasting. */
1786 if (client -> state == S_REQUESTING ||
1787 client -> state == S_REBOOTING ||
1788 cur_time > client -> active -> rebind)
1789 destination.sin_addr = sockaddr_broadcast.sin_addr;
1790 else
1791 memcpy (&destination.sin_addr.s_addr,
1792 client -> destination.iabuf,
1793 sizeof destination.sin_addr.s_addr);
1794 destination.sin_port = remote_port;
1795 destination.sin_family = AF_INET;
1796 #ifdef HAVE_SA_LEN
1797 destination.sin_len = sizeof destination;
1798 #endif
1800 if (client -> state == S_RENEWING ||
1801 client -> state == S_REBINDING)
1802 memcpy (&from, client -> active -> address.iabuf,
1803 sizeof from);
1804 else
1805 from.s_addr = INADDR_ANY;
1807 /* Record the number of seconds since we started sending. */
1808 if (client -> state == S_REQUESTING)
1809 client -> packet.secs = client -> secs;
1810 else {
1811 if (interval < 65536)
1812 client -> packet.secs = htons (interval);
1813 else
1814 client -> packet.secs = htons (65535);
1817 log_info ("DHCPREQUEST on %s to %s port %d",
1818 client -> name ? client -> name : client -> interface -> name,
1819 inet_ntoa (destination.sin_addr),
1820 ntohs (destination.sin_port));
1822 if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
1823 fallback_interface)
1824 result = send_packet (fallback_interface,
1825 (struct packet *)0,
1826 &client -> packet,
1827 client -> packet_length,
1828 from, &destination,
1829 (struct hardware *)0);
1830 else
1831 /* Send out a packet. */
1832 result = send_packet (client -> interface, (struct packet *)0,
1833 &client -> packet,
1834 client -> packet_length,
1835 from, &destination,
1836 (struct hardware *)0);
1838 if (result < 0) {
1839 /* FIXME: Shouldn't an error be logged here? */
1842 add_timeout (cur_time + client -> interval,
1843 send_request, client, 0, 0);
1846 void send_decline (cpp)
1847 void *cpp;
1849 struct client_state *client = cpp;
1851 int result;
1853 log_info ("DHCPDECLINE on %s to %s port %d",
1854 client -> name ? client -> name : client -> interface -> name,
1855 inet_ntoa (sockaddr_broadcast.sin_addr),
1856 ntohs (sockaddr_broadcast.sin_port));
1858 /* Send out a packet. */
1859 result = send_packet (client -> interface, (struct packet *)0,
1860 &client -> packet,
1861 client -> packet_length,
1862 inaddr_any, &sockaddr_broadcast,
1863 (struct hardware *)0);
1865 if (result < 0) {
1866 /* FIXME: Shouldn't an error be logged here? */
1870 void send_release (cpp)
1871 void *cpp;
1873 struct client_state *client = cpp;
1875 int result;
1876 struct sockaddr_in destination;
1877 struct in_addr from;
1879 memcpy (&from, client -> active -> address.iabuf,
1880 sizeof from);
1881 memcpy (&destination.sin_addr.s_addr,
1882 client -> destination.iabuf,
1883 sizeof destination.sin_addr.s_addr);
1884 destination.sin_port = remote_port;
1885 destination.sin_family = AF_INET;
1886 #ifdef HAVE_SA_LEN
1887 destination.sin_len = sizeof destination;
1888 #endif
1890 /* Set the lease to end now, so that we don't accidentally
1891 reuse it if we restart before the old expiry time. */
1892 client -> active -> expiry =
1893 client -> active -> renewal =
1894 client -> active -> rebind = cur_time;
1895 if (!write_client_lease (client, client -> active, 1, 1)) {
1896 log_error ("Can't release lease: lease write failed.");
1897 return;
1900 log_info ("DHCPRELEASE on %s to %s port %d",
1901 client -> name ? client -> name : client -> interface -> name,
1902 inet_ntoa (destination.sin_addr),
1903 ntohs (destination.sin_port));
1905 if (fallback_interface)
1906 result = send_packet (fallback_interface,
1907 (struct packet *)0,
1908 &client -> packet,
1909 client -> packet_length,
1910 from, &destination,
1911 (struct hardware *)0);
1912 else
1913 /* Send out a packet. */
1914 result = send_packet (client -> interface, (struct packet *)0,
1915 &client -> packet,
1916 client -> packet_length,
1917 from, &destination,
1918 (struct hardware *)0);
1920 if (result < 0) {
1921 /* FIXME: Shouldn't an error be logged here? */
1925 void make_client_options (client, lease, type, sid, rip, prl, op)
1926 struct client_state *client;
1927 struct client_lease *lease;
1928 u_int8_t *type;
1929 struct option_cache *sid;
1930 struct iaddr *rip;
1931 u_int32_t *prl;
1932 struct option_state **op;
1934 unsigned i;
1935 struct option_cache *oc;
1936 struct buffer *bp = (struct buffer *)0;
1938 /* If there are any leftover options, get rid of them. */
1939 if (*op)
1940 option_state_dereference (op, MDL);
1942 /* Allocate space for options. */
1943 option_state_allocate (op, MDL);
1945 /* Send the server identifier if provided. */
1946 if (sid)
1947 save_option (&dhcp_universe, *op, sid);
1949 oc = (struct option_cache *)0;
1951 /* Send the requested address if provided. */
1952 if (rip) {
1953 client -> requested_address = *rip;
1954 if (!(make_const_option_cache
1955 (&oc, (struct buffer **)0, rip -> iabuf, rip -> len,
1956 &dhcp_options [DHO_DHCP_REQUESTED_ADDRESS], MDL)))
1957 log_error ("can't make requested address cache.");
1958 else {
1959 save_option (&dhcp_universe, *op, oc);
1960 option_cache_dereference (&oc, MDL);
1962 } else {
1963 client -> requested_address.len = 0;
1966 if (!(make_const_option_cache
1967 (&oc, (struct buffer **)0,
1968 type, 1, &dhcp_options [DHO_DHCP_MESSAGE_TYPE], MDL)))
1969 log_error ("can't make message type.");
1970 else {
1971 save_option (&dhcp_universe, *op, oc);
1972 option_cache_dereference (&oc, MDL);
1975 if (prl) {
1976 /* Figure out how many parameters were requested. */
1977 for (i = 0; prl [i]; i++)
1979 if (!buffer_allocate (&bp, i, MDL))
1980 log_error ("can't make parameter list buffer.");
1981 else {
1982 for (i = 0; prl [i]; i++)
1983 bp -> data [i] = prl [i];
1984 if (!(make_const_option_cache
1985 (&oc, &bp, (u_int8_t *)0, i,
1986 &dhcp_options [DHO_DHCP_PARAMETER_REQUEST_LIST],
1987 MDL)))
1988 log_error ("can't make option cache");
1989 else {
1990 save_option (&dhcp_universe, *op, oc);
1991 option_cache_dereference (&oc, MDL);
1996 /* Run statements that need to be run on transmission. */
1997 if (client -> config -> on_transmission)
1998 execute_statements_in_scope
1999 ((struct binding_value **)0,
2000 (struct packet *)0, (struct lease *)0, client,
2001 (lease ? lease -> options : (struct option_state *)0),
2002 *op, &global_scope,
2003 client -> config -> on_transmission,
2004 (struct group *)0);
2007 void make_discover (client, lease)
2008 struct client_state *client;
2009 struct client_lease *lease;
2011 unsigned char discover = DHCPDISCOVER;
2012 struct option_state *options = (struct option_state *)0;
2014 memset (&client -> packet, 0, sizeof (client -> packet));
2016 make_client_options (client,
2017 lease, &discover, (struct option_cache *)0,
2018 lease ? &lease -> address : (struct iaddr *)0,
2019 client -> config -> requested_options,
2020 &options);
2022 /* Set up the option buffer... */
2023 client -> packet_length =
2024 cons_options ((struct packet *)0, &client -> packet,
2025 (struct lease *)0, client,
2026 /* maximum packet size */1500,
2027 (struct option_state *)0,
2028 options,
2029 /* scope */ &global_scope,
2030 /* overload */ 0,
2031 /* terminate */0,
2032 /* bootpp */0,
2033 (struct data_string *)0,
2034 client -> config -> vendor_space_name);
2036 option_state_dereference (&options, MDL);
2037 if (client -> packet_length < BOOTP_MIN_LEN)
2038 client -> packet_length = BOOTP_MIN_LEN;
2040 client -> packet.op = BOOTREQUEST;
2041 client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2042 client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2043 client -> packet.hops = 0;
2044 client -> packet.xid = random ();
2045 client -> packet.secs = 0; /* filled in by send_discover. */
2047 if (can_receive_unicast_unconfigured (client -> interface))
2048 client -> packet.flags = 0;
2049 else
2050 client -> packet.flags = htons (BOOTP_BROADCAST);
2052 memset (&(client -> packet.ciaddr),
2053 0, sizeof client -> packet.ciaddr);
2054 memset (&(client -> packet.yiaddr),
2055 0, sizeof client -> packet.yiaddr);
2056 memset (&(client -> packet.siaddr),
2057 0, sizeof client -> packet.siaddr);
2058 client -> packet.giaddr = giaddr;
2059 if (client -> interface -> hw_address.hlen > 0)
2060 memcpy (client -> packet.chaddr,
2061 &client -> interface -> hw_address.hbuf [1],
2062 (unsigned)(client -> interface -> hw_address.hlen - 1));
2064 #ifdef DEBUG_PACKET
2065 dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2066 #endif
2070 void make_request (client, lease)
2071 struct client_state *client;
2072 struct client_lease *lease;
2074 unsigned char request = DHCPREQUEST;
2075 struct option_cache *oc;
2077 memset (&client -> packet, 0, sizeof (client -> packet));
2079 if (client -> state == S_REQUESTING)
2080 oc = lookup_option (&dhcp_universe, lease -> options,
2081 DHO_DHCP_SERVER_IDENTIFIER);
2082 else
2083 oc = (struct option_cache *)0;
2085 if (client -> sent_options)
2086 option_state_dereference (&client -> sent_options, MDL);
2088 make_client_options (client, lease, &request, oc,
2089 ((client -> state == S_REQUESTING ||
2090 client -> state == S_REBOOTING)
2091 ? &lease -> address
2092 : (struct iaddr *)0),
2093 client -> config -> requested_options,
2094 &client -> sent_options);
2096 /* Set up the option buffer... */
2097 client -> packet_length =
2098 cons_options ((struct packet *)0, &client -> packet,
2099 (struct lease *)0, client,
2100 /* maximum packet size */1500,
2101 (struct option_state *)0,
2102 client -> sent_options,
2103 /* scope */ &global_scope,
2104 /* overload */ 0,
2105 /* terminate */0,
2106 /* bootpp */0,
2107 (struct data_string *)0,
2108 client -> config -> vendor_space_name);
2110 if (client -> packet_length < BOOTP_MIN_LEN)
2111 client -> packet_length = BOOTP_MIN_LEN;
2113 client -> packet.op = BOOTREQUEST;
2114 client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2115 client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2116 client -> packet.hops = 0;
2117 client -> packet.xid = client -> xid;
2118 client -> packet.secs = 0; /* Filled in by send_request. */
2120 /* If we own the address we're requesting, put it in ciaddr;
2121 otherwise set ciaddr to zero. */
2122 if (client -> state == S_BOUND ||
2123 client -> state == S_RENEWING ||
2124 client -> state == S_REBINDING) {
2125 memcpy (&client -> packet.ciaddr,
2126 lease -> address.iabuf, lease -> address.len);
2127 client -> packet.flags = 0;
2128 } else {
2129 memset (&client -> packet.ciaddr, 0,
2130 sizeof client -> packet.ciaddr);
2131 if (can_receive_unicast_unconfigured (client -> interface))
2132 client -> packet.flags = 0;
2133 else
2134 client -> packet.flags = htons (BOOTP_BROADCAST);
2137 memset (&client -> packet.yiaddr, 0,
2138 sizeof client -> packet.yiaddr);
2139 memset (&client -> packet.siaddr, 0,
2140 sizeof client -> packet.siaddr);
2141 if (client -> state != S_BOUND &&
2142 client -> state != S_RENEWING)
2143 client -> packet.giaddr = giaddr;
2144 else
2145 memset (&client -> packet.giaddr, 0,
2146 sizeof client -> packet.giaddr);
2147 if (client -> interface -> hw_address.hlen > 0)
2148 memcpy (client -> packet.chaddr,
2149 &client -> interface -> hw_address.hbuf [1],
2150 (unsigned)(client -> interface -> hw_address.hlen - 1));
2152 #ifdef DEBUG_PACKET
2153 dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2154 #endif
2157 void make_decline (client, lease)
2158 struct client_state *client;
2159 struct client_lease *lease;
2161 unsigned char decline = DHCPDECLINE;
2162 struct option_cache *oc;
2164 struct option_state *options = (struct option_state *)0;
2166 oc = lookup_option (&dhcp_universe, lease -> options,
2167 DHO_DHCP_SERVER_IDENTIFIER);
2168 make_client_options (client, lease, &decline, oc,
2169 &lease -> address, (u_int32_t *)0, &options);
2171 /* Set up the option buffer... */
2172 memset (&client -> packet, 0, sizeof (client -> packet));
2173 client -> packet_length =
2174 cons_options ((struct packet *)0, &client -> packet,
2175 (struct lease *)0, client, 0,
2176 (struct option_state *)0, options,
2177 &global_scope, 0, 0, 0, (struct data_string *)0,
2178 client -> config -> vendor_space_name);
2179 option_state_dereference (&options, MDL);
2180 if (client -> packet_length < BOOTP_MIN_LEN)
2181 client -> packet_length = BOOTP_MIN_LEN;
2182 option_state_dereference (&options, MDL);
2184 client -> packet.op = BOOTREQUEST;
2185 client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2186 client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2187 client -> packet.hops = 0;
2188 client -> packet.xid = client -> xid;
2189 client -> packet.secs = 0; /* Filled in by send_request. */
2190 if (can_receive_unicast_unconfigured (client -> interface))
2191 client -> packet.flags = 0;
2192 else
2193 client -> packet.flags = htons (BOOTP_BROADCAST);
2195 /* ciaddr must always be zero. */
2196 memset (&client -> packet.ciaddr, 0,
2197 sizeof client -> packet.ciaddr);
2198 memset (&client -> packet.yiaddr, 0,
2199 sizeof client -> packet.yiaddr);
2200 memset (&client -> packet.siaddr, 0,
2201 sizeof client -> packet.siaddr);
2202 client -> packet.giaddr = giaddr;
2203 memcpy (client -> packet.chaddr,
2204 &client -> interface -> hw_address.hbuf [1],
2205 client -> interface -> hw_address.hlen);
2207 #ifdef DEBUG_PACKET
2208 dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2209 #endif
2212 void make_release (client, lease)
2213 struct client_state *client;
2214 struct client_lease *lease;
2216 unsigned char request = DHCPRELEASE;
2217 struct option_cache *oc;
2219 struct option_state *options = (struct option_state *)0;
2221 memset (&client -> packet, 0, sizeof (client -> packet));
2223 oc = lookup_option (&dhcp_universe, lease -> options,
2224 DHO_DHCP_SERVER_IDENTIFIER);
2225 make_client_options (client, lease, &request, oc,
2226 (struct iaddr *)0, (u_int32_t *)0,
2227 &options);
2229 /* Set up the option buffer... */
2230 client -> packet_length =
2231 cons_options ((struct packet *)0, &client -> packet,
2232 (struct lease *)0, client,
2233 /* maximum packet size */1500,
2234 (struct option_state *)0,
2235 options,
2236 /* scope */ &global_scope,
2237 /* overload */ 0,
2238 /* terminate */0,
2239 /* bootpp */0,
2240 (struct data_string *)0,
2241 client -> config -> vendor_space_name);
2243 if (client -> packet_length < BOOTP_MIN_LEN)
2244 client -> packet_length = BOOTP_MIN_LEN;
2245 option_state_dereference (&options, MDL);
2247 client -> packet.op = BOOTREQUEST;
2248 client -> packet.htype = client -> interface -> hw_address.hbuf [0];
2249 client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
2250 client -> packet.hops = 0;
2251 client -> packet.xid = random ();
2252 client -> packet.secs = 0;
2253 client -> packet.flags = 0;
2254 memcpy (&client -> packet.ciaddr,
2255 lease -> address.iabuf, lease -> address.len);
2256 memset (&client -> packet.yiaddr, 0,
2257 sizeof client -> packet.yiaddr);
2258 memset (&client -> packet.siaddr, 0,
2259 sizeof client -> packet.siaddr);
2260 client -> packet.giaddr = giaddr;
2261 memcpy (client -> packet.chaddr,
2262 &client -> interface -> hw_address.hbuf [1],
2263 client -> interface -> hw_address.hlen);
2265 #ifdef DEBUG_PACKET
2266 dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
2267 #endif
2270 void destroy_client_lease (lease)
2271 struct client_lease *lease;
2273 if (lease -> server_name)
2274 dfree (lease -> server_name, MDL);
2275 if (lease -> filename)
2276 dfree (lease -> filename, MDL);
2277 option_state_dereference (&lease -> options, MDL);
2278 free_client_lease (lease, MDL);
2281 FILE *leaseFile;
2283 void rewrite_client_leases ()
2285 struct interface_info *ip;
2286 struct client_state *client;
2287 struct client_lease *lp;
2289 if (leaseFile)
2290 fclose (leaseFile);
2291 leaseFile = fopen (path_dhclient_db, "w");
2292 if (!leaseFile) {
2293 log_error ("can't create %s: %m", path_dhclient_db);
2294 return;
2297 /* Write out all the leases attached to configured interfaces that
2298 we know about. */
2299 for (ip = interfaces; ip; ip = ip -> next) {
2300 for (client = ip -> client; client; client = client -> next) {
2301 for (lp = client -> leases; lp; lp = lp -> next) {
2302 write_client_lease (client, lp, 1, 0);
2304 if (client -> active)
2305 write_client_lease (client,
2306 client -> active, 1, 0);
2310 /* Write out any leases that are attached to interfaces that aren't
2311 currently configured. */
2312 for (ip = dummy_interfaces; ip; ip = ip -> next) {
2313 for (client = ip -> client; client; client = client -> next) {
2314 for (lp = client -> leases; lp; lp = lp -> next) {
2315 write_client_lease (client, lp, 1, 0);
2317 if (client -> active)
2318 write_client_lease (client,
2319 client -> active, 1, 0);
2322 fflush (leaseFile);
2325 void write_lease_option (struct option_cache *oc,
2326 struct packet *packet, struct lease *lease,
2327 struct client_state *client_state,
2328 struct option_state *in_options,
2329 struct option_state *cfg_options,
2330 struct binding_scope **scope,
2331 struct universe *u, void *stuff)
2333 const char *name, *dot;
2334 struct data_string ds;
2336 memset (&ds, 0, sizeof ds);
2338 if (u != &dhcp_universe) {
2339 name = u -> name;
2340 dot = ".";
2341 } else {
2342 name = "";
2343 dot = "";
2345 if (evaluate_option_cache (&ds, packet, lease, client_state,
2346 in_options, cfg_options, scope, oc, MDL)) {
2347 fprintf (leaseFile,
2348 " option %s%s%s %s;\n",
2349 name, dot, oc -> option -> name,
2350 pretty_print_option (oc -> option,
2351 ds.data, ds.len, 1, 1));
2352 data_string_forget (&ds, MDL);
2356 int write_client_lease (client, lease, rewrite, makesure)
2357 struct client_state *client;
2358 struct client_lease *lease;
2359 int rewrite;
2360 int makesure;
2362 int i;
2363 struct tm *t;
2364 static int leases_written;
2365 struct data_string ds;
2366 int errors = 0;
2367 char *s;
2369 if (!rewrite) {
2370 if (leases_written++ > 20) {
2371 rewrite_client_leases ();
2372 leases_written = 0;
2376 /* If the lease came from the config file, we don't need to stash
2377 a copy in the lease database. */
2378 if (lease -> is_static)
2379 return 1;
2381 if (!leaseFile) { /* XXX */
2382 leaseFile = fopen (path_dhclient_db, "w");
2383 if (!leaseFile) {
2384 log_error ("can't create %s: %m", path_dhclient_db);
2385 return 0;
2389 errno = 0;
2390 fprintf (leaseFile, "lease {\n");
2391 if (lease -> is_bootp) {
2392 fprintf (leaseFile, " bootp;\n");
2393 if (errno) {
2394 ++errors;
2395 errno = 0;
2398 fprintf (leaseFile, " interface \"%s\";\n",
2399 client -> interface -> name);
2400 if (errno) {
2401 ++errors;
2402 errno = 0;
2404 if (client -> name) {
2405 fprintf (leaseFile, " name \"%s\";\n", client -> name);
2406 if (errno) {
2407 ++errors;
2408 errno = 0;
2411 fprintf (leaseFile, " fixed-address %s;\n",
2412 piaddr (lease -> address));
2413 if (errno) {
2414 ++errors;
2415 errno = 0;
2417 if (lease -> filename) {
2418 s = quotify_string (lease -> filename, MDL);
2419 if (s) {
2420 fprintf (leaseFile, " filename \"%s\";\n", s);
2421 if (errno) {
2422 ++errors;
2423 errno = 0;
2425 dfree (s, MDL);
2426 } else
2427 errors++;
2430 if (lease -> server_name) {
2431 s = quotify_string (lease -> filename, MDL);
2432 if (s) {
2433 fprintf (leaseFile, " server-name \"%s\";\n", s);
2434 if (errno) {
2435 ++errors;
2436 errno = 0;
2438 dfree (s, MDL);
2439 } else
2440 ++errors;
2442 if (lease -> medium) {
2443 s = quotify_string (lease -> medium -> string, MDL);
2444 if (s) {
2445 fprintf (leaseFile, " medium \"%s\";\n", s);
2446 if (errno) {
2447 ++errors;
2448 errno = 0;
2450 dfree (s, MDL);
2451 } else
2452 errors++;
2454 if (errno != 0) {
2455 errors++;
2456 errno = 0;
2459 memset (&ds, 0, sizeof ds);
2461 for (i = 0; i < lease -> options -> universe_count; i++) {
2462 option_space_foreach ((struct packet *)0, (struct lease *)0,
2463 client, (struct option_state *)0,
2464 lease -> options, &global_scope,
2465 universes [i],
2466 client, write_lease_option);
2469 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
2470 somebody invents a time machine, I think we can safely disregard
2471 it. */
2472 t = gmtime (&lease -> renewal);
2473 fprintf (leaseFile,
2474 " renew %d %d/%d/%d %02d:%02d:%02d;\n",
2475 t -> tm_wday, t -> tm_year + 1900,
2476 t -> tm_mon + 1, t -> tm_mday,
2477 t -> tm_hour, t -> tm_min, t -> tm_sec);
2478 if (errno != 0) {
2479 errors++;
2480 errno = 0;
2482 t = gmtime (&lease -> rebind);
2483 fprintf (leaseFile,
2484 " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
2485 t -> tm_wday, t -> tm_year + 1900,
2486 t -> tm_mon + 1, t -> tm_mday,
2487 t -> tm_hour, t -> tm_min, t -> tm_sec);
2488 if (errno != 0) {
2489 errors++;
2490 errno = 0;
2492 t = gmtime (&lease -> expiry);
2493 fprintf (leaseFile,
2494 " expire %d %d/%d/%d %02d:%02d:%02d;\n",
2495 t -> tm_wday, t -> tm_year + 1900,
2496 t -> tm_mon + 1, t -> tm_mday,
2497 t -> tm_hour, t -> tm_min, t -> tm_sec);
2498 if (errno != 0) {
2499 errors++;
2500 errno = 0;
2502 fprintf (leaseFile, "}\n");
2503 if (errno != 0) {
2504 errors++;
2505 errno = 0;
2507 fflush (leaseFile);
2508 if (errno != 0) {
2509 errors++;
2510 errno = 0;
2512 #ifndef FSYNC_MISSING
2513 if (!errors && makesure) {
2514 if (fsync (fileno (leaseFile)) < 0) {
2515 log_info ("write_client_lease: %m");
2516 return 0;
2519 #endif
2520 return errors ? 0 : 1;
2523 #ifdef BUILTIN_IFCONFIG
2524 #ifndef SOCKET_IS_NOT_A_FILE
2525 #define IoctlSocket ioctl
2526 #define CloseSocket close
2527 #endif
2529 static inline void setaddr (struct sockaddr_in *sa, u_long addr, u_short af)
2531 sa->sin_len = sizeof (struct sockaddr_in);
2532 sa->sin_family = af;
2533 sa->sin_addr.s_addr = addr;
2536 void ifconfig (char *name, u_long addr, u_long mask, u_long bcast)
2538 int s;
2539 struct ifaliasreq req;
2541 s = socket (AF_INET, SOCK_DGRAM, 0);
2542 if (s < 0) {
2543 log_error ("Can't create configuration socket: %m");
2544 return;
2546 memset (&req, 0, sizeof (req));
2547 strncpy (req.ifra_name, name, sizeof (req.ifra_name) - 1);
2548 IoctlSocket (s, SIOCDIFADDR, (char *)&req);
2549 setaddr ((struct sockaddr_in *)&req.ifra_addr, addr, AF_INET);
2550 setaddr ((struct sockaddr_in *)&req.ifra_mask, mask, AF_UNSPEC);
2551 if (bcast)
2552 setaddr ((struct sockaddr_in *)&req.ifra_broadaddr, bcast, AF_INET);
2553 if (IoctlSocket (s, SIOCAIFADDR, (char *)&req) < 0)
2554 log_error ("Can't set interface configuration: %m");
2555 CloseSocket (s);
2558 void ifdeconfig (char *name)
2560 int s;
2561 struct ifaliasreq req;
2563 s = socket (AF_INET, SOCK_DGRAM, 0);
2564 if (s < 0) {
2565 log_error ("Can't create configuration socket: %m");
2566 return;
2568 memset (&req, 0, sizeof (req));
2569 strncpy (req.ifra_name, name, sizeof (req.ifra_name) - 1);
2570 IoctlSocket (s, SIOCDIFADDR, (char *)&req);
2571 CloseSocket (s);
2574 void addroute (u_long dest, u_long gate, short flags)
2576 int s;
2577 struct ortentry route;
2579 s = socket (AF_INET, SOCK_RAW, 0);
2580 if (s < 0) {
2581 log_error ("Can't create route socket: %m");
2582 return;
2584 memset (&route, 0, sizeof (route));
2585 setaddr ((struct sockaddr_in *)&route.rt_dst, dest, AF_INET);
2586 setaddr ((struct sockaddr_in *)&route.rt_gateway, gate, AF_INET);
2587 route.rt_flags = flags;
2588 IoctlSocket (s, SIOCADDRT, (char *)&route);
2589 CloseSocket (s);
2592 void delroute (u_long dest)
2594 int s;
2595 struct ortentry route;
2597 s = socket (AF_INET, SOCK_RAW, 0);
2598 if (s < 0) {
2599 log_error ("Can't create route socket: %m");
2600 return;
2602 memset (&route, 0, sizeof (route));
2603 setaddr ((struct sockaddr_in *)&route.rt_dst, dest, AF_INET);
2604 IoctlSocket (s, SIOCDELRT, (char *)&route);
2605 CloseSocket (s);
2608 void interface_preinit (struct client_state *client)
2610 log_debug ("PREINIT %s", client->interface->name);
2611 if (client -> alias) {
2612 log_debug ("Alias IP: %s", piaddr (client->alias->address));
2613 /* TODO: remove alias and its routes */
2615 /* TODO: clear ARP cache and remove old interface's routes (ifdown ???) */
2616 ifconfig (client->interface->name, INADDR_ANY, INADDR_ANY, INADDR_BROADCAST);
2617 addroute (INADDR_BROADCAST, INADDR_ANY, RTF_UP|RTF_HOST);
2620 int interface_medium (struct client_state *client, char *medium)
2622 log_debug ("MEDIUM %s %s", client->interface->name, medium);
2623 /* TODO */
2624 return 0;
2627 void client_option_dump (struct option_cache *oc,
2628 struct packet *packet, struct lease *lease,
2629 struct client_state *client_state,
2630 struct option_state *in_options,
2631 struct option_state *cfg_options,
2632 struct binding_scope **scope,
2633 struct universe *u, void *stuff)
2635 struct data_string data;
2636 memset (&data, 0, sizeof data);
2638 if (evaluate_option_cache (&data, packet, lease, client_state,
2639 in_options, cfg_options, scope, oc, MDL)) {
2640 if (data.len) {
2641 char name [256];
2642 if (dhcp_option_ev_name (name, sizeof name,
2643 oc -> option)) {
2644 log_debug ("%s: %s", name,
2645 (pretty_print_option
2646 (oc -> option,
2647 data.data, data.len,
2648 0, 0)));
2649 data_string_forget (&data, MDL);
2655 void dump_params (struct client_state *client, struct client_lease *lease)
2657 int i;
2659 log_debug ("ip_address: %s", piaddr (lease -> address));
2661 if (lease -> filename)
2662 log_debug ("filename: %s", lease -> filename);
2664 if (lease -> server_name)
2665 log_debug ("server_name: %s", lease -> server_name);
2667 for (i = 0; i < lease -> options -> universe_count; i++) {
2668 option_space_foreach ((struct packet *)0, (struct lease *)0,
2669 client, (struct option_state *)0,
2670 lease -> options, &global_scope,
2671 universes [i],
2672 0, client_option_dump);
2674 log_debug ("expiry: %d", (int)(lease -> expiry));
2677 int data_cmp (struct data_string *d1, struct data_string *d2)
2679 if (d1->len != d2->len)
2680 return 1;
2681 else {
2682 if (d1->len)
2683 return memcmp (d1->data, d2->data, d1->len);
2684 else
2685 return 0;
2689 int interface_bind (struct client_state *client)
2691 struct data_string data = {0};
2692 struct option_cache *oc;
2693 int i;
2694 u_long old_netmask = INADDR_ANY;
2695 u_long old_broadcast = INADDR_ANY;
2696 struct data_string old_gateways_data = {0};
2697 struct data_string old_hostname_data = {0};
2698 struct data_string old_dns_data = {0};
2699 struct data_string old_domain_data = {0};
2700 u_long new_netmask = INADDR_ANY;
2701 u_long new_broadcast = INADDR_ANY;
2702 struct data_string new_gateways_data = {0};
2703 struct data_string new_hostname_data = {0};
2704 struct data_string new_dns_data = {0};
2705 struct data_string new_domain_data = {0};
2706 short new_ifconfig = 1;
2707 short new_gateways = 1;
2708 short new_hostname = 1;
2709 short new_routes = 1;
2710 short new_dns = 1;
2711 short new_domain = 1;
2713 log_debug ("%s %s", (client -> state == S_REQUESTING
2714 ? "BOUND"
2715 : (client -> state == S_RENEWING
2716 ? "RENEW"
2717 : (client -> state == S_REBOOTING
2718 ? "REBOOT"
2719 : (client -> state == S_REBINDING
2720 ? "REBIND" : "BAD STATE")))), client->interface->name);
2721 if (client -> alias) {
2722 log_debug ("Alias parameters:");
2723 dump_params (client, client -> alias);
2724 /* TODO: process alias */
2727 /* Parse new options */
2728 oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_SUBNET_MASK);
2729 if (oc && evaluate_option_cache (&data, (struct packet *)0,
2730 (struct lease *)0, client,
2731 (struct option_state *)0,
2732 client -> new -> options,
2733 &global_scope, oc, MDL)) {
2734 memcpy (&new_netmask, data.data, 4);
2735 data_string_forget (&data, MDL);
2737 oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_BROADCAST_ADDRESS);
2738 if (oc && evaluate_option_cache (&data, (struct packet *)0,
2739 (struct lease *)0, client,
2740 (struct option_state *)0,
2741 client -> new -> options,
2742 &global_scope, oc, MDL)) {
2743 memcpy (&new_broadcast, data.data, 4);
2744 data_string_forget (&data, MDL);
2746 oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_ROUTERS);
2747 if (oc)
2748 evaluate_option_cache (&new_gateways_data, (struct packet *)0,
2749 (struct lease *)0, client,
2750 (struct option_state *)0,
2751 client -> new -> options,
2752 &global_scope, oc, MDL);
2753 oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_HOST_NAME);
2754 if (oc)
2755 evaluate_option_cache (&new_hostname_data, (struct packet *)0,
2756 (struct lease *)0, client,
2757 (struct option_state *)0,
2758 client -> new -> options,
2759 &global_scope, oc, MDL);
2760 oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_DOMAIN_NAME_SERVERS);
2761 if (oc)
2762 evaluate_option_cache (&new_dns_data, (struct packet *)0,
2763 (struct lease *)0, client,
2764 (struct option_state *)0,
2765 client -> new -> options,
2766 &global_scope, oc, MDL);
2767 oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_DOMAIN_NAME);
2768 if (oc)
2769 evaluate_option_cache (&new_domain_data, (struct packet *)0,
2770 (struct lease *)0, client,
2771 (struct option_state *)0,
2772 client -> new -> options,
2773 &global_scope, oc, MDL);
2774 /* Perform actions depending on our state */
2775 switch (client->state) {
2776 case S_RENEWING:
2777 new_ifconfig = 0;
2778 case S_REBINDING:
2779 if (client -> active) {
2780 log_debug ("Old parameters:");
2781 dump_params (client, client -> active);
2782 } else
2783 log_fatal ("Inconsistent state: old parameters not specified");
2784 if (new_ifconfig) {
2785 oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_SUBNET_MASK);
2786 if (oc && evaluate_option_cache (&data, (struct packet *)0,
2787 (struct lease *)0, client,
2788 (struct option_state *)0,
2789 client -> active -> options,
2790 &global_scope, oc, MDL)) {
2791 memcpy (&old_netmask, data.data, 4);
2792 data_string_forget (&data, MDL);
2794 oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_BROADCAST_ADDRESS);
2795 if (oc && evaluate_option_cache (&data, (struct packet *)0,
2796 (struct lease *)0, client,
2797 (struct option_state *)0,
2798 client -> active -> options,
2799 &global_scope, oc, MDL)) {
2800 memcpy (&old_broadcast, data.data, 4);
2801 data_string_forget (&data, MDL);
2803 if ((addr_eq(client->active->address, client->new->address)) &&
2804 (old_netmask == new_netmask) && (old_broadcast == new_broadcast))
2805 new_ifconfig = 0;
2807 oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_ROUTERS);
2808 if (oc && evaluate_option_cache (&old_gateways_data, (struct packet *)0,
2809 (struct lease *)0, client,
2810 (struct option_state *)0,
2811 client -> active -> options,
2812 &global_scope, oc, MDL)) {
2813 if (!(data_cmp (&new_gateways_data, &old_gateways_data)))
2814 new_gateways = 0;
2815 data_string_forget (&old_gateways_data, MDL);
2817 oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_HOST_NAME);
2818 if (oc && evaluate_option_cache (&old_hostname_data, (struct packet *)0,
2819 (struct lease *)0, client,
2820 (struct option_state *)0,
2821 client -> active -> options,
2822 &global_scope, oc, MDL)) {
2823 if (!(data_cmp (&new_hostname_data, &old_hostname_data)))
2824 new_hostname = 0;
2825 data_string_forget (&old_hostname_data, MDL);
2827 oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_DOMAIN_NAME_SERVERS);
2828 if (oc && evaluate_option_cache (&old_dns_data, (struct packet *)0,
2829 (struct lease *)0, client,
2830 (struct option_state *)0,
2831 client -> active -> options,
2832 &global_scope, oc, MDL)) {
2833 if (!(data_cmp (&new_dns_data, &old_dns_data)))
2834 new_dns = 0;
2835 data_string_forget (&old_dns_data, MDL);
2837 oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_DOMAIN_NAME);
2838 if (oc && evaluate_option_cache (&old_domain_data, (struct packet *)0,
2839 (struct lease *)0, client,
2840 (struct option_state *)0,
2841 client -> active -> options,
2842 &global_scope, oc, MDL)) {
2843 if (!(data_cmp (&new_domain_data, &old_domain_data)))
2844 new_domain = 0;
2845 data_string_forget (&old_domain_data, MDL);
2847 case S_REBOOTING:
2848 case S_REQUESTING:
2849 log_debug ("New parameters:");
2850 dump_params (client, client -> new);
2851 if (new_ifconfig) {
2852 delroute (INADDR_BROADCAST);
2853 ifconfig (client->interface->name, ia2ulong(&client->new->address), new_netmask, new_broadcast);
2855 if (new_gateways) {
2856 delroute (INADDR_ANY);
2857 if (new_gateways_data.data)
2858 addroute (INADDR_ANY, htonl(getULong(new_gateways_data.data)), RTF_UP | RTF_GATEWAY);
2859 /* TODO: process all gateways not only first one */
2861 if (new_hostname && new_hostname_data.data) {
2862 log_debug ("New hostname: %s", new_hostname_data.data);
2863 sethostname (new_hostname_data.data, new_hostname_data.len);
2865 if (new_routes) {
2866 /* TODO: add new static routes */
2868 if (new_dns) {
2869 ClearDynNameServ();
2870 if (new_dns_data.data) {
2871 struct sockaddr_in ns_addr;
2872 u_long *addrs = (u_long *)new_dns_data.data;
2873 int len = new_dns_data.len/4;
2874 ns_addr.sin_len = sizeof(ns_addr);
2875 ns_addr.sin_family = AF_INET;
2876 for (i=0; i<len; i++) {
2877 log_debug ("New DNS server: %s", Inet_NtoA(addrs[i]));
2878 ns_addr.sin_addr.s_addr = addrs[i];
2879 AddDynNameServ((struct sockaddr *)&ns_addr);
2882 EndDynNameServ();
2884 if (new_domain) {
2885 ClearDynDomain();
2886 if (new_domain_data.data) {
2887 log_debug ("New domain name: %s", new_domain_data.data);
2888 AddDynDomain((unsigned char *)new_domain_data.data);
2890 EndDynDomain();
2892 /* TODO: do something with other options (place to some file ?) */
2893 data_string_forget (&new_gateways_data, MDL);
2894 data_string_forget (&new_hostname_data, MDL);
2895 data_string_forget (&new_dns_data, MDL);
2896 data_string_forget (&new_domain_data, MDL);
2897 break;
2898 default:
2899 log_debug ("Inconsistent state: %d", client->state);
2901 return 0;
2904 void interface_expire (struct client_state *client)
2906 log_debug ("EXPIRE %s", client->interface->name);
2907 *** TODO ***
2910 void interface_fail (struct client_state *client)
2912 log_debug ("FAIL %s", client->interface->name);
2913 *** TODO ***
2916 void interface_release (struct client_state *client)
2918 log_debug ("RELEASE %s", client->interface->name);
2919 *** TODO ***
2922 void interface_stop (struct client_state *client)
2924 log_debug ("STOP %s", client->interface->name);
2925 ifdeconfig (client->interface->name);
2926 delroute (INADDR_ANY);
2927 ClearDynNameServ();
2928 EndDynNameServ();
2929 ClearDynDomain();
2930 EndDynDomain();
2933 int interface_timeout (struct client_state *client)
2935 log_debug ("TIMEOUT %s", client->interface->name);
2936 /* TODO */
2937 return 1;
2940 #else
2942 /* Variables holding name of script and file pointer for writing to
2943 script. Needless to say, this is not reentrant - only one script
2944 can be invoked at a time. */
2945 char scriptName [256];
2946 FILE *scriptFile;
2948 void script_init (client, reason, medium)
2949 struct client_state *client;
2950 const char *reason;
2951 struct string_list *medium;
2953 struct string_list *sl, *next;
2955 if (client) {
2956 for (sl = client -> env; sl; sl = next) {
2957 next = sl -> next;
2958 dfree (sl, MDL);
2960 client -> env = (struct string_list *)0;
2961 client -> envc = 0;
2963 if (client -> interface) {
2964 client_envadd (client, "", "interface", "%s",
2965 client -> interface -> name);
2967 if (client -> name)
2968 client_envadd (client,
2969 "", "client", "%s", client -> name);
2970 if (medium)
2971 client_envadd (client,
2972 "", "medium", "%s", medium -> string);
2974 client_envadd (client, "", "reason", "%s", reason);
2975 client_envadd (client, "", "pid", "%ld", (long int)getpid ());
2979 struct envadd_state {
2980 struct client_state *client;
2981 const char *prefix;
2984 void client_option_envadd (struct option_cache *oc,
2985 struct packet *packet, struct lease *lease,
2986 struct client_state *client_state,
2987 struct option_state *in_options,
2988 struct option_state *cfg_options,
2989 struct binding_scope **scope,
2990 struct universe *u, void *stuff)
2992 struct envadd_state *es = stuff;
2993 struct data_string data;
2994 memset (&data, 0, sizeof data);
2996 if (evaluate_option_cache (&data, packet, lease, client_state,
2997 in_options, cfg_options, scope, oc, MDL)) {
2998 if (data.len) {
2999 char name [256];
3000 if (dhcp_option_ev_name (name, sizeof name,
3001 oc -> option)) {
3002 client_envadd (es -> client, es -> prefix,
3003 name, "%s",
3004 (pretty_print_option
3005 (oc -> option,
3006 data.data, data.len,
3007 0, 0)));
3008 data_string_forget (&data, MDL);
3014 void script_write_params (client, prefix, lease)
3015 struct client_state *client;
3016 const char *prefix;
3017 struct client_lease *lease;
3019 int i;
3020 struct data_string data;
3021 struct option_cache *oc;
3022 pair *hash;
3023 char *s, *t;
3024 struct envadd_state es;
3026 es.client = client;
3027 es.prefix = prefix;
3029 client_envadd (client,
3030 prefix, "ip_address", "%s", piaddr (lease -> address));
3032 /* For the benefit of Linux (and operating systems which may
3033 have similar needs), compute the network address based on
3034 the supplied ip address and netmask, if provided. Also
3035 compute the broadcast address (the host address all ones
3036 broadcast address, not the host address all zeroes
3037 broadcast address). */
3039 memset (&data, 0, sizeof data);
3040 oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
3041 if (oc && evaluate_option_cache (&data, (struct packet *)0,
3042 (struct lease *)0, client,
3043 (struct option_state *)0,
3044 lease -> options,
3045 &global_scope, oc, MDL)) {
3046 if (data.len > 3) {
3047 struct iaddr netmask, subnet, broadcast;
3049 memcpy (netmask.iabuf, data.data, data.len);
3050 netmask.len = data.len;
3051 data_string_forget (&data, MDL);
3053 subnet = subnet_number (lease -> address, netmask);
3054 if (subnet.len) {
3055 client_envadd (client, prefix, "network_number",
3056 "%s", piaddr (subnet));
3058 oc = lookup_option (&dhcp_universe,
3059 lease -> options,
3060 DHO_BROADCAST_ADDRESS);
3061 if (!oc ||
3062 !(evaluate_option_cache
3063 (&data, (struct packet *)0,
3064 (struct lease *)0, client,
3065 (struct option_state *)0,
3066 lease -> options,
3067 &global_scope, oc, MDL))) {
3068 broadcast = broadcast_addr (subnet, netmask);
3069 if (broadcast.len) {
3070 client_envadd (client,
3071 prefix, "broadcast_address",
3072 "%s", piaddr (broadcast));
3077 data_string_forget (&data, MDL);
3080 if (lease -> filename)
3081 client_envadd (client,
3082 prefix, "filename", "%s", lease -> filename);
3083 if (lease -> server_name)
3084 client_envadd (client, prefix, "server_name",
3085 "%s", lease -> server_name);
3087 for (i = 0; i < lease -> options -> universe_count; i++) {
3088 option_space_foreach ((struct packet *)0, (struct lease *)0,
3089 client, (struct option_state *)0,
3090 lease -> options, &global_scope,
3091 universes [i],
3092 &es, client_option_envadd);
3094 client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
3097 int script_go (client)
3098 struct client_state *client;
3100 int rval;
3101 char *scriptName;
3102 char *argv [2];
3103 char **envp;
3104 char *epp [3];
3105 char reason [] = "REASON=NBI";
3106 static char client_path [] = CLIENT_PATH;
3107 int i;
3108 struct string_list *sp, *next;
3109 int pid, wpid, wstatus;
3111 if (client)
3112 scriptName = client -> config -> script_name;
3113 else
3114 scriptName = top_level_config.script_name;
3116 envp = dmalloc (((client ? client -> envc : 2) +
3117 client_env_count + 2) * sizeof (char *), MDL);
3118 if (!envp) {
3119 log_error ("No memory for client script environment.");
3120 return 0;
3122 i = 0;
3123 /* Copy out the environment specified on the command line,
3124 if any. */
3125 for (sp = client_env; sp; sp = sp -> next) {
3126 envp [i++] = sp -> string;
3128 /* Copy out the environment specified by dhclient. */
3129 if (client) {
3130 for (sp = client -> env; sp; sp = sp -> next) {
3131 envp [i++] = sp -> string;
3133 } else {
3134 envp [i++] = reason;
3136 /* Set $PATH. */
3137 envp [i++] = client_path;
3138 envp [i] = (char *)0;
3140 argv [0] = scriptName;
3141 argv [1] = (char *)0;
3143 pid = fork ();
3144 if (pid < 0) {
3145 log_error ("fork: %m");
3146 wstatus = 0;
3147 } else if (pid) {
3148 do {
3149 wpid = wait (&wstatus);
3150 } while (wpid != pid && wpid > 0);
3151 if (wpid < 0) {
3152 log_error ("wait: %m");
3153 wstatus = 0;
3155 } else {
3156 execve (scriptName, argv, envp);
3157 log_error ("execve (%s, ...): %m", scriptName);
3158 exit (0);
3161 if (client) {
3162 for (sp = client -> env; sp; sp = next) {
3163 next = sp -> next;
3164 dfree (sp, MDL);
3166 client -> env = (struct string_list *)0;
3167 client -> envc = 0;
3169 dfree (envp, MDL);
3170 GET_TIME (&cur_time);
3171 return (WIFEXITED (wstatus) ?
3172 WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
3175 void client_envadd (struct client_state *client,
3176 const char *prefix, const char *name, const char *fmt, ...)
3178 char spbuf [1024];
3179 char *s;
3180 unsigned len, i;
3181 struct string_list *val;
3182 va_list list;
3184 va_start (list, fmt);
3185 len = vsnprintf (spbuf, sizeof spbuf, fmt, list);
3186 va_end (list);
3188 val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
3189 len + sizeof *val, MDL);
3190 if (!val)
3191 return;
3192 s = val -> string;
3193 strcpy (s, prefix);
3194 strcat (s, name);
3195 s += strlen (s);
3196 *s++ = '=';
3197 if (len >= sizeof spbuf) {
3198 va_start (list, fmt);
3199 vsnprintf (s, len + 1, fmt, list);
3200 va_end (list);
3201 } else
3202 strcpy (s, spbuf);
3203 val -> next = client -> env;
3204 client -> env = val;
3205 client -> envc++;
3207 #endif
3209 int dhcp_option_ev_name (buf, buflen, option)
3210 char *buf;
3211 size_t buflen;
3212 struct option *option;
3214 int i, j;
3215 const char *s;
3217 j = 0;
3218 if (option -> universe != &dhcp_universe) {
3219 s = option -> universe -> name;
3220 i = 0;
3221 } else {
3222 s = option -> name;
3223 i = 1;
3226 do {
3227 while (*s) {
3228 if (j + 1 == buflen)
3229 return 0;
3230 if (*s == '-')
3231 buf [j++] = '_';
3232 else
3233 buf [j++] = *s;
3234 ++s;
3236 if (!i) {
3237 s = option -> name;
3238 if (j + 1 == buflen)
3239 return 0;
3240 buf [j++] = '_';
3242 ++i;
3243 } while (i != 2);
3245 buf [j] = 0;
3246 return 1;
3249 void go_daemon ()
3251 #ifndef FORK_MISSING
3252 static int state = 0;
3253 int pid;
3254 int i;
3256 /* Don't become a daemon if the user requested otherwise. */
3257 if (no_daemon) {
3258 write_client_pid_file ();
3259 return;
3262 /* Only do it once. */
3263 if (state)
3264 return;
3265 state = 1;
3267 /* Stop logging to stderr... */
3268 log_perror = 0;
3270 /* Become a daemon... */
3271 if ((pid = fork ()) < 0)
3272 log_fatal ("Can't fork daemon: %m");
3273 else if (pid)
3274 exit (0);
3275 /* Become session leader and get pid... */
3276 pid = setsid ();
3278 /* Close standard I/O descriptors. */
3279 close(0);
3280 close(1);
3281 close(2);
3283 /* Reopen them on /dev/null. */
3284 i = open ("/dev/null", O_RDWR);
3285 if (i == 0)
3286 i = open ("/dev/null", O_RDWR);
3287 if (i == 1) {
3288 i = open ("/dev/null", O_RDWR);
3289 log_perror = 0; /* No sense logging to /dev/null. */
3290 } else if (i != -1)
3291 close (i);
3292 #endif
3293 write_client_pid_file ();
3296 void write_client_pid_file ()
3298 FILE *pf;
3299 int pfdesc;
3301 pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
3303 if (pfdesc < 0) {
3304 log_error ("Can't create %s: %m", path_dhclient_pid);
3305 return;
3308 pf = fdopen (pfdesc, "w");
3309 if (!pf)
3310 log_error ("Can't fdopen %s: %m", path_dhclient_pid);
3311 else {
3312 fprintf (pf, "%ld\n", (long)getpid ());
3313 fclose (pf);
3317 void client_location_changed ()
3319 struct interface_info *ip;
3320 struct client_state *client;
3322 for (ip = interfaces; ip; ip = ip -> next) {
3323 for (client = ip -> client; client; client = client -> next) {
3324 switch (client -> state) {
3325 case S_SELECTING:
3326 cancel_timeout (send_discover, client);
3327 break;
3329 case S_BOUND:
3330 cancel_timeout (state_bound, client);
3331 break;
3333 case S_REBOOTING:
3334 case S_REQUESTING:
3335 case S_RENEWING:
3336 cancel_timeout (send_request, client);
3337 break;
3339 case S_INIT:
3340 case S_REBINDING:
3341 case S_STOPPED:
3342 break;
3344 client -> state = S_INIT;
3345 state_reboot (client);
3350 void do_release(client)
3351 struct client_state *client;
3353 struct data_string ds;
3354 struct option_cache *oc;
3356 /* Pick a random xid. */
3357 client -> xid = random ();
3359 /* is there even a lease to release? */
3360 if (client -> active) {
3361 /* Make a DHCPRELEASE packet, and set appropriate per-interface
3362 flags. */
3363 make_release (client, client -> active);
3365 memset (&ds, 0, sizeof ds);
3366 oc = lookup_option (&dhcp_universe,
3367 client -> active -> options,
3368 DHO_DHCP_SERVER_IDENTIFIER);
3369 if (oc &&
3370 evaluate_option_cache (&ds, (struct packet *)0,
3371 (struct lease *)0, client,
3372 (struct option_state *)0,
3373 client -> active -> options,
3374 &global_scope, oc, MDL)) {
3375 if (ds.len > 3) {
3376 memcpy (client -> destination.iabuf,
3377 ds.data, 4);
3378 client -> destination.len = 4;
3379 } else
3380 client -> destination = iaddr_broadcast;
3382 data_string_forget (&ds, MDL);
3383 } else
3384 client -> destination = iaddr_broadcast;
3385 client -> first_sending = cur_time;
3386 client -> interval = client -> config -> initial_interval;
3388 /* Zap the medium list... */
3389 client -> medium = (struct string_list *)0;
3391 /* Send out the first and only DHCPRELEASE packet. */
3392 send_release (client);
3394 #ifdef BUILTIN_IFCONFIG
3395 interface_release (client);
3396 #else
3397 /* Do the client script RELEASE operation. */
3398 script_init (client,
3399 "RELEASE", (struct string_list *)0);
3400 if (client -> alias)
3401 script_write_params (client, "alias_",
3402 client -> alias);
3403 script_write_params (client, "old_", client -> active);
3404 script_go (client);
3405 #endif
3408 /* Cancel any timeouts. */
3409 cancel_timeout (state_bound, client);
3410 cancel_timeout (send_discover, client);
3411 cancel_timeout (state_init, client);
3412 cancel_timeout (send_request, client);
3413 cancel_timeout (state_reboot, client);
3414 client -> state = S_STOPPED;
3417 int dhclient_interface_shutdown_hook (struct interface_info *interface)
3419 do_release (interface -> client);
3421 return 1;
3424 int dhclient_interface_discovery_hook (struct interface_info *tmp)
3426 struct interface_info *last, *ip;
3427 /* See if we can find the client from dummy_interfaces */
3428 last = 0;
3429 for (ip = dummy_interfaces; ip; ip = ip -> next) {
3430 if (!strcmp (ip -> name, tmp -> name)) {
3431 /* Remove from dummy_interfaces */
3432 if (last) {
3433 ip = (struct interface_info *)0;
3434 interface_reference (&ip, last -> next, MDL);
3435 interface_dereference (&last -> next, MDL);
3436 if (ip -> next) {
3437 interface_reference (&last -> next,
3438 ip -> next, MDL);
3439 interface_dereference (&ip -> next,
3440 MDL);
3442 } else {
3443 ip = (struct interface_info *)0;
3444 interface_reference (&ip,
3445 dummy_interfaces, MDL);
3446 interface_dereference (&dummy_interfaces, MDL);
3447 if (ip -> next) {
3448 interface_reference (&dummy_interfaces,
3449 ip -> next, MDL);
3450 interface_dereference (&ip -> next,
3451 MDL);
3454 /* Copy "client" to tmp */
3455 if (ip -> client) {
3456 tmp -> client = ip -> client;
3457 tmp -> client -> interface = tmp;
3459 interface_dereference (&ip, MDL);
3460 break;
3462 last = ip;
3464 return 1;
3467 isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
3469 struct interface_info *ip;
3470 struct client_state *client;
3472 /* This code needs some rethinking. It doesn't test against
3473 a signal name, and it just kind of bulls into doing something
3474 that may or may not be appropriate. */
3476 if (interfaces) {
3477 interface_reference (&interface -> next, interfaces, MDL);
3478 interface_dereference (&interfaces, MDL);
3480 interface_reference (&interfaces, interface, MDL);
3482 discover_interfaces (DISCOVER_UNCONFIGURED);
3484 for (ip = interfaces; ip; ip = ip -> next) {
3485 /* If interfaces were specified, don't configure
3486 interfaces that weren't specified! */
3487 if (ip -> flags & INTERFACE_RUNNING ||
3488 (ip -> flags & (INTERFACE_REQUESTED |
3489 INTERFACE_AUTOMATIC)) !=
3490 INTERFACE_REQUESTED)
3491 continue;
3492 #ifdef BUILTIN_IFCONFIG
3493 interface_preinit (ip -> client);
3494 #else
3495 script_init (ip -> client,
3496 "PREINIT", (struct string_list *)0);
3497 if (ip -> client -> alias)
3498 script_write_params (ip -> client, "alias_",
3499 ip -> client -> alias);
3500 script_go (ip -> client);
3501 #endif
3504 discover_interfaces (interfaces_requested
3505 ? DISCOVER_REQUESTED
3506 : DISCOVER_RUNNING);
3508 for (ip = interfaces; ip; ip = ip -> next) {
3509 if (ip -> flags & INTERFACE_RUNNING)
3510 continue;
3511 ip -> flags |= INTERFACE_RUNNING;
3512 for (client = ip -> client; client; client = client -> next) {
3513 client -> state = S_INIT;
3514 /* Set up a timeout to start the initialization
3515 process. */
3516 add_timeout (cur_time + random () % 5,
3517 state_reboot, client, 0, 0);
3520 return ISC_R_SUCCESS;
3523 /* The client should never receive a relay agent information option,
3524 so if it does, log it and discard it. */
3526 int parse_agent_information_option (packet, len, data)
3527 struct packet *packet;
3528 int len;
3529 u_int8_t *data;
3531 return 1;
3534 /* The client never sends relay agent information options. */
3536 unsigned cons_agent_information_options (cfg_options, outpacket,
3537 agentix, length)
3538 struct option_state *cfg_options;
3539 struct dhcp_packet *outpacket;
3540 unsigned agentix;
3541 unsigned length;
3543 return length;
3546 static void shutdown_exit (void *foo)
3548 exit (0);
3551 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
3552 control_object_state_t newstate)
3554 struct interface_info *ip;
3555 struct client_state *client;
3557 /* Do the right thing for each interface. */
3558 for (ip = interfaces; ip; ip = ip -> next) {
3559 for (client = ip -> client; client; client = client -> next) {
3560 switch (newstate) {
3561 case server_startup:
3562 return ISC_R_SUCCESS;
3564 case server_running:
3565 return ISC_R_SUCCESS;
3567 case server_shutdown:
3568 if (client -> active &&
3569 client -> active -> expiry > cur_time) {
3570 if (client -> config -> do_forward_update)
3571 client_dns_update (client, 0, 0);
3572 do_release (client);
3574 break;
3576 case server_hibernate:
3577 state_stop (client);
3578 break;
3580 case server_awaken:
3581 state_reboot (client);
3582 break;
3586 if (newstate == server_shutdown)
3587 add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0);
3588 return ISC_R_SUCCESS;
3591 /* Called after a timeout if the DNS update failed on the previous try.
3592 Retries the update, and if it times out, schedules a retry after
3593 ten times as long of a wait. */
3595 void client_dns_update_timeout (void *cp)
3597 struct client_state *client = cp;
3598 isc_result_t status;
3600 if (client -> active) {
3601 status = client_dns_update (client, 1,
3602 (client -> active -> renewal -
3603 cur_time));
3604 if (status == ISC_R_TIMEDOUT) {
3605 client -> dns_update_timeout *= 10;
3606 add_timeout (cur_time + client -> dns_update_timeout,
3607 client_dns_update_timeout, client, 0, 0);
3612 /* See if we should do a DNS update, and if so, do it. */
3614 isc_result_t client_dns_update (struct client_state *client, int addp, int ttl)
3616 struct data_string ddns_fwd_name,
3617 ddns_dhcid, client_identifier;
3618 struct option_cache *oc;
3619 int ignorep;
3620 int result;
3621 isc_result_t rcode;
3623 /* If we didn't send an FQDN option, we certainly aren't going to
3624 be doing an update. */
3625 if (!client -> sent_options)
3626 return ISC_R_SUCCESS;
3628 /* If we don't have a lease, we can't do an update. */
3629 if (!client -> active)
3630 return ISC_R_SUCCESS;
3632 /* If we set the no client update flag, don't do the update. */
3633 if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
3634 FQDN_NO_CLIENT_UPDATE)) &&
3635 evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
3636 (struct lease *)0, client,
3637 client -> sent_options,
3638 (struct option_state *)0,
3639 &global_scope, oc, MDL))
3640 return ISC_R_SUCCESS;
3642 /* If we set the "server, please update" flag, or didn't set it
3643 to false, don't do the update. */
3644 if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
3645 FQDN_SERVER_UPDATE)) ||
3646 evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
3647 (struct lease *)0, client,
3648 client -> sent_options,
3649 (struct option_state *)0,
3650 &global_scope, oc, MDL))
3651 return ISC_R_SUCCESS;
3653 /* If no FQDN option was supplied, don't do the update. */
3654 memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
3655 if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
3656 FQDN_FQDN)) ||
3657 !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
3658 (struct lease *)0, client,
3659 client -> sent_options,
3660 (struct option_state *)0,
3661 &global_scope, oc, MDL))
3662 return ISC_R_SUCCESS;
3664 /* Make a dhcid string out of either the client identifier,
3665 if we are sending one, or the interface's MAC address,
3666 otherwise. */
3667 memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
3669 memset (&client_identifier, 0, sizeof client_identifier);
3670 if ((oc = lookup_option (&dhcp_universe, client -> sent_options,
3671 DHO_DHCP_CLIENT_IDENTIFIER)) &&
3672 evaluate_option_cache (&client_identifier, (struct packet *)0,
3673 (struct lease *)0, client,
3674 client -> sent_options,
3675 (struct option_state *)0,
3676 &global_scope, oc, MDL)) {
3677 result = get_dhcid (&ddns_dhcid,
3678 DHO_DHCP_CLIENT_IDENTIFIER,
3679 client_identifier.data,
3680 client_identifier.len);
3681 data_string_forget (&client_identifier, MDL);
3682 } else
3683 result = get_dhcid (&ddns_dhcid, 0,
3684 client -> interface -> hw_address.hbuf,
3685 client -> interface -> hw_address.hlen);
3686 if (!result) {
3687 data_string_forget (&ddns_fwd_name, MDL);
3688 return ISC_R_SUCCESS;
3691 /* Start the resolver, if necessary. */
3692 if (!resolver_inited) {
3693 minires_ninit (&resolver_state);
3694 resolver_inited = 1;
3695 resolver_state.retrans = 1;
3696 resolver_state.retry = 1;
3700 * Perform updates.
3702 if (ddns_fwd_name.len && ddns_dhcid.len) {
3703 if (addp)
3704 rcode = ddns_update_a (&ddns_fwd_name,
3705 client -> active -> address,
3706 &ddns_dhcid, ttl,
3708 else
3709 rcode = ddns_remove_a (&ddns_fwd_name,
3710 client -> active -> address,
3711 &ddns_dhcid);
3712 } else
3713 rcode = ISC_R_FAILURE;
3715 data_string_forget (&ddns_fwd_name, MDL);
3716 data_string_forget (&ddns_dhcid, MDL);
3717 return rcode;