diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 1999-02-16 01:59:46 +0000 | 
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 1999-02-16 01:59:46 +0000 | 
| commit | bcb29ac16cc991f99f0c976390dff6be1a1b9058 (patch) | |
| tree | ea5e3b237aafbf9d5ae15bc5abb0faaa102742d6 /contrib/isc-dhcp/client/dhclient.c | |
| parent | 496747cdd475144f5df2af67677fad487337c6e8 (diff) | |
Diffstat (limited to 'contrib/isc-dhcp/client/dhclient.c')
| -rw-r--r-- | contrib/isc-dhcp/client/dhclient.c | 2128 | 
1 files changed, 0 insertions, 2128 deletions
| diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c deleted file mode 100644 index f5f8eb78fd27b..0000000000000 --- a/contrib/isc-dhcp/client/dhclient.c +++ /dev/null @@ -1,2128 +0,0 @@ -/* dhclient.c - -   DHCP Client. */ - -/* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium.    All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - *    notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - *    notice, this list of conditions and the following disclaimer in the - *    documentation and/or other materials provided with the distribution. - * 3. Neither the name of The Internet Software Consortium nor the names - *    of its contributors may be used to endorse or promote products derived - *    from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND - * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises.  To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''.  To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. - * - * This client was substantially modified and enhanced by Elliot Poger - * for use on Linux while he was working on the MosquitoNet project at - * Stanford. - * - * The current version owes much to Elliot's Linux enhancements, but - * was substantially reorganized and partially rewritten by Ted Lemon - * so as to use the same networking framework that the Internet Software - * Consortium DHCP server uses.   Much system-specific configuration code - * was moved into a shell script so that as support for more operating - * systems is added, it will not be necessary to port and maintain - * system-specific configuration code to these operating systems - instead, - * the shell script can invoke the native tools to accomplish the same - * purpose. - */ - -#ifndef lint -static char ocopyright[] = -"$Id: dhclient.c,v 1.44.2.14 1999/02/09 04:59:50 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n"; -#endif /* not lint */ - -#include "dhcpd.h" - -TIME cur_time; -TIME default_lease_time = 43200; /* 12 hours... */ -TIME max_lease_time = 86400; /* 24 hours... */ -struct tree_cache *global_options [256]; - -char *path_dhclient_conf = _PATH_DHCLIENT_CONF; -char *path_dhclient_db = _PATH_DHCLIENT_DB; -char *path_dhclient_pid = _PATH_DHCLIENT_PID; - -int interfaces_requested = 0; - -int log_perror = 1; - -struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; -struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; -struct in_addr inaddr_any; -struct sockaddr_in sockaddr_broadcast; - -/* ASSERT_STATE() does nothing now; it used to be -   assert (state_is == state_shouldbe). */ -#define ASSERT_STATE(state_is, state_shouldbe) {} - -u_int16_t local_port; -u_int16_t remote_port; -int log_priority; -int no_daemon; -int save_scripts; -int onetry; - -static char copyright[] = -"Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium."; -static char arr [] = "All rights reserved."; -static char message [] = "Internet Software Consortium DHCP Client V2.0b1pl11"; -static char contrib [] = "\nPlease contribute if you find this software useful."; -static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html\n"; - -static void usage PROTO ((void)); - -int main (argc, argv, envp) -	int argc; -	char **argv, **envp; -{ -	int i; -	struct servent *ent; -	struct interface_info *ip; -	int seed; -	int quiet; - -#ifdef SYSLOG_4_2 -	openlog ("dhclient", LOG_NDELAY); -	log_priority = LOG_DAEMON; -#else -	openlog ("dhclient", LOG_NDELAY, LOG_DAEMON); -#endif - -#if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__)) -	setlogmask (LOG_UPTO (LOG_INFO)); -#endif	 - -	for (i = 1; i < argc; i++) { -		if (!strcmp (argv [i], "-p")) { -			if (++i == argc) -				usage (); -			local_port = htons (atoi (argv [i])); -			debug ("binding to user-specified port %d", -			       ntohs (local_port)); -		} else if (!strcmp (argv [i], "-d")) { -			no_daemon = 1; -		} else if (!strcmp (argv [i], "-D")) { -			save_scripts = 1; -		} else if (!strcmp (argv [i], "-1")) { -			onetry = 1; -		} else if (!strcmp (argv [i], "-lf")) { -			if (++i == argc) -				usage (); -			path_dhclient_db = argv [i]; -		} else if (!strcmp (argv [i], "-q")) { -			quiet = 1; -			quiet_interface_discovery = 1; - 		} else if (argv [i][0] == '-') { - 		    usage (); - 		} else { - 		    struct interface_info *tmp = - 			((struct interface_info *) - 			 dmalloc (sizeof *tmp, "specified_interface")); - 		    if (!tmp) - 			error ("Insufficient memory to %s %s", - 			       "record interface", argv [i]); - 		    memset (tmp, 0, sizeof *tmp); - 		    strcpy (tmp -> name, argv [i]); - 		    tmp -> next = interfaces; - 		    tmp -> flags = INTERFACE_REQUESTED; -		    interfaces_requested = 1; - 		    interfaces = tmp; - 		} -	} - -	if (!quiet) { -		note (message); -		note (copyright); -		note (arr); -		note (contrib); -		note (url); -	} - -	/* Default to the DHCP/BOOTP port. */ -	if (!local_port) { -		ent = getservbyname ("dhcpc", "udp"); -		if (!ent) -			local_port = htons (68); -		else -			local_port = ent -> s_port; -#ifndef __CYGWIN32__ -		endservent (); -#endif -	} -	remote_port = htons (ntohs (local_port) - 1);	/* XXX */ -   -	/* Get the current time... */ -	GET_TIME (&cur_time); - -	sockaddr_broadcast.sin_family = AF_INET; -	sockaddr_broadcast.sin_port = remote_port; -	sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; -#ifdef HAVE_SA_LEN -	sockaddr_broadcast.sin_len = sizeof sockaddr_broadcast; -#endif -	inaddr_any.s_addr = INADDR_ANY; - -	/* Discover all the network interfaces. */ -	discover_interfaces (DISCOVER_UNCONFIGURED); - -	/* Parse the dhclient.conf file. */ -	read_client_conf (); - -	/* Parse the lease database. */ -	read_client_leases (); - -	/* Rewrite the lease database... */ -	rewrite_client_leases (); - -	/* If no broadcast interfaces were discovered, call the script -	   and tell it so. */ -	if (!interfaces) { -		script_init ((struct interface_info *)0, "NBI", -			     (struct string_list *)0); -		script_go ((struct interface_info *)0); - -		note ("No broadcast interfaces found - exiting."); -		/* Nothing more to do. */ -		exit (0); -	} else { -		/* Call the script with the list of interfaces. */ -		for (ip = interfaces; ip; ip = ip -> next) { -			/* If interfaces were specified, don't configure -			   interfaces that weren't specified! */ -			if (interfaces_requested && -			    ((ip -> flags & (INTERFACE_REQUESTED | -					     INTERFACE_AUTOMATIC)) != -			     INTERFACE_REQUESTED)) -				continue; -			script_init (ip, "PREINIT", (struct string_list *)0); -			if (ip -> client -> alias) -				script_write_params (ip, "alias_", -						     ip -> client -> alias); -			script_go (ip); -		} -	} - -	/* At this point, all the interfaces that the script thinks -	   are relevant should be running, so now we once again call -	   discover_interfaces(), and this time ask it to actually set -	   up the interfaces. */ -	discover_interfaces (interfaces_requested -			     ? DISCOVER_REQUESTED -			     : DISCOVER_RUNNING); - -	/* Make up a seed for the random number generator from current -	   time plus the sum of the last four bytes of each -	   interface's hardware address interpreted as an integer. -	   Not much entropy, but we're booting, so we're not likely to -	   find anything better. */ -	seed = 0; /* Unfortunately, what's on the stack isn't random. :') */ -	for (ip = interfaces; ip; ip = ip -> next) { -		int junk; -		memcpy (&junk, -			&ip -> hw_address.haddr [ip -> hw_address.hlen - -						 sizeof seed], sizeof seed); -		seed += junk; -	} -	srandom (seed + cur_time); - -	/* Start a configuration state machine for each interface. */ -	for (ip = interfaces; ip; ip = ip -> next) { -		ip -> client -> state = S_INIT; -		state_reboot (ip); -	} - -	/* Set up the bootp packet handler... */ -	bootp_packet_handler = do_packet; - -	/* Start dispatching packets and timeouts... */ -	dispatch (); - -	/*NOTREACHED*/ -	return 0; -} - -static void usage () -{ -	error ("Usage: dhclient [-1] [-c] [-p <port>] [-lf lease-file] [interface]"); -} - -void cleanup () -{ -} - -/* Individual States: - *  - * Each routine is called from the dhclient_state_machine() in one of - * these conditions: - * -> entering INIT state - * -> recvpacket_flag == 0: timeout in this state - * -> otherwise: received a packet in this state - * - * Return conditions as handled by dhclient_state_machine(): - * Returns 1, sendpacket_flag = 1: send packet, reset timer. - * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). - * Returns 0: finish the nap which was interrupted for no good reason. - * - * Several per-interface variables are used to keep track of the process: - *   active_lease: the lease that is being used on the interface - *                 (null pointer if not configured yet). - *   offered_leases: leases corresponding to DHCPOFFER messages that have - *		     been sent to us by DHCP servers. - *   acked_leases: leases corresponding to DHCPACK messages that have been - *		   sent to us by DHCP servers. - *   sendpacket: DHCP packet we're trying to send. - *   destination: IP address to send sendpacket to - * In addition, there are several relevant per-lease variables. - *   T1_expiry, T2_expiry, lease_expiry: lease milestones - * In the active lease, these control the process of renewing the lease; - * In leases on the acked_leases list, this simply determines when we - * can no longer legitimately use the lease. - */ - -void state_reboot (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	/* If we don't remember an active lease, go straight to INIT. */ -	if (!ip -> client -> active || -	    ip -> client -> active -> is_bootp) { -		state_init (ip); -		return; -	} - -	/* We are in the rebooting state. */ -	ip -> client -> state = S_REBOOTING; - -	/* make_request doesn't initialize xid because it normally comes -	   from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, -	   so pick an xid now. */ -	ip -> client -> xid = random (); - -	/* Make a DHCPREQUEST packet, and set appropriate per-interface -	   flags. */ -	make_request (ip, ip -> client -> active); -	ip -> client -> destination = iaddr_broadcast; -	ip -> client -> first_sending = cur_time; -	ip -> client -> interval = ip -> client -> config -> initial_interval; - -	/* Zap the medium list... */ -	ip -> client -> medium = (struct string_list *)0; - -	/* Send out the first DHCPREQUEST packet. */ -	send_request (ip); -} - -/* Called when a lease has completely expired and we've been unable to -   renew it. */ - -void state_init (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	ASSERT_STATE(state, S_INIT); - -	/* Make a DHCPDISCOVER packet, and set appropriate per-interface -	   flags. */ -	make_discover (ip, ip -> client -> active); -	ip -> client -> xid = ip -> client -> packet.xid; -	ip -> client -> destination = iaddr_broadcast; -	ip -> client -> state = S_SELECTING; -	ip -> client -> first_sending = cur_time; -	ip -> client -> interval = ip -> client -> config -> initial_interval; - -	/* Add an immediate timeout to cause the first DHCPDISCOVER packet -	   to go out. */ -	send_discover (ip); -} - -/* state_selecting is called when one or more DHCPOFFER packets have been -   received and a configurable period of time has passed. */ - -void state_selecting (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	struct client_lease *lp, *next, *picked; - -	ASSERT_STATE(state, S_SELECTING); - -	/* Cancel state_selecting and send_discover timeouts, since either -	   one could have got us here. */ -	cancel_timeout (state_selecting, ip); -	cancel_timeout (send_discover, ip); - -	/* We have received one or more DHCPOFFER packets.   Currently, -	   the only criterion by which we judge leases is whether or -	   not we get a response when we arp for them. */ -	picked = (struct client_lease *)0; -	for (lp = ip -> client -> offered_leases; lp; lp = next) { -		next = lp -> next; - -		/* Check to see if we got an ARPREPLY for the address -		   in this particular lease. */ -		if (!picked) { -			script_init (ip, "ARPCHECK", lp -> medium); -			script_write_params (ip, "check_", lp); - -			/* If the ARPCHECK code detects another -			   machine using the offered address, it exits -			   nonzero.  We need to send a DHCPDECLINE and -			   toss the lease. */ -			if (script_go (ip)) { -				make_decline (ip, lp); -				send_decline (ip); -				goto freeit; -			} -			picked = lp; -			picked -> next = (struct client_lease *)0; -		} else { -		      freeit: -			free_client_lease (lp); -		} -	} -	ip -> client -> offered_leases = (struct client_lease *)0; - -	/* If we just tossed all the leases we were offered, go back -	   to square one. */ -	if (!picked) { -		ip -> client -> state = S_INIT; -		state_init (ip); -		return; -	} - -	/* If it was a BOOTREPLY, we can just take the address right now. */ -	if (!picked -> options [DHO_DHCP_MESSAGE_TYPE].len) { -		ip -> client -> new = picked; - -		/* Make up some lease expiry times -		   XXX these should be configurable. */ -		ip -> client -> new -> expiry = cur_time + 12000; -		ip -> client -> new -> renewal += cur_time + 8000; -		ip -> client -> new -> rebind += cur_time + 10000; - -		ip -> client -> state = S_REQUESTING; - -		/* Bind to the address we received. */ -		bind_lease (ip); -		return; -	} - -	/* Go to the REQUESTING state. */ -	ip -> client -> destination = iaddr_broadcast; -	ip -> client -> state = S_REQUESTING; -	ip -> client -> first_sending = cur_time; -	ip -> client -> interval = ip -> client -> config -> initial_interval; - -	/* Make a DHCPREQUEST packet from the lease we picked. */ -	make_request (ip, picked); -	ip -> client -> xid = ip -> client -> packet.xid; - -	/* Toss the lease we picked - we'll get it back in a DHCPACK. */ -	free_client_lease (picked); - -	/* Add an immediate timeout to send the first DHCPREQUEST packet. */ -	send_request (ip); -}   - -/* state_requesting is called when we receive a DHCPACK message after -   having sent out one or more DHCPREQUEST packets. */ - -void dhcpack (packet) -	struct packet *packet; -{ -	struct interface_info *ip = packet -> interface; -	struct client_lease *lease; -	int i; -	 -	/* If we're not receptive to an offer right now, or if the offer -	   has an unrecognizable transaction id, then just drop it. */ -	if (packet -> interface -> client -> xid != packet -> raw -> xid || -	    (packet -> interface -> hw_address.hlen != -	     packet -> raw -> hlen) || -	    (memcmp (packet -> interface -> hw_address.haddr, -		     packet -> raw -> chaddr, packet -> raw -> hlen))) { -		debug ("DHCPACK in wrong transaction."); -		return; -	} - -	if (ip -> client -> state != S_REBOOTING && -	    ip -> client -> state != S_REQUESTING && -	    ip -> client -> state != S_RENEWING && -	    ip -> client -> state != S_REBINDING) { -		debug ("DHCPACK in wrong state."); -		return; -	} - -	note ("DHCPACK from %s", piaddr (packet -> client_addr)); - -	lease = packet_to_lease (packet); -	if (!lease) { -		note ("packet_to_lease failed."); -		return; -	} - -	ip -> client -> new = lease; - -	/* Stop resending DHCPREQUEST. */ -	cancel_timeout (send_request, ip); - -	/* Figure out the lease time. */ -	ip -> client -> new -> expiry = -		getULong (ip -> client -> -			  new -> options [DHO_DHCP_LEASE_TIME].data); - -	/* Take the server-provided renewal time if there is one; -	   otherwise figure it out according to the spec. */ -	if (ip -> client -> new -> options [DHO_DHCP_RENEWAL_TIME].len) -		ip -> client -> new -> renewal = -			getULong (ip -> client -> -				  new -> options [DHO_DHCP_RENEWAL_TIME].data); -	else -		ip -> client -> new -> renewal = -			ip -> client -> new -> expiry / 2; - -	/* Same deal with the rebind time. */ -	if (ip -> client -> new -> options [DHO_DHCP_REBINDING_TIME].len) -		ip -> client -> new -> rebind = -			getULong (ip -> client -> new -> -				  options [DHO_DHCP_REBINDING_TIME].data); -	else -		ip -> client -> new -> rebind = -			ip -> client -> new -> renewal + -				ip -> client -> new -> renewal / 2 + -					ip -> client -> new -> renewal / 4; - -	ip -> client -> new -> expiry += cur_time; -	ip -> client -> new -> renewal += cur_time; -	ip -> client -> new -> rebind += cur_time; - -	bind_lease (ip); -} - -void bind_lease (ip) -	struct interface_info *ip; -{ -	/* Remember the medium. */ -	ip -> client -> new -> medium = ip -> client -> medium; - -	/* Write out the new lease. */ -	write_client_lease (ip, ip -> client -> new, 0); - -	/* Run the client script with the new parameters. */ -	script_init (ip, (ip -> client -> state == S_REQUESTING -			  ? "BOUND" -			  : (ip -> client -> state == S_RENEWING -			     ? "RENEW" -			     : (ip -> client -> state == S_REBOOTING -				? "REBOOT" : "REBIND"))), -		     ip -> client -> new -> medium); -	if (ip -> client -> active && ip -> client -> state != S_REBOOTING) -		script_write_params (ip, "old_", ip -> client -> active); -	script_write_params (ip, "new_", ip -> client -> new); -	if (ip -> client -> alias) -		script_write_params (ip, "alias_", ip -> client -> alias); -	script_go (ip); - -	/* Replace the old active lease with the new one. */ -	if (ip -> client -> active) -		free_client_lease (ip -> client -> active); -	ip -> client -> active = ip -> client -> new; -	ip -> client -> new = (struct client_lease *)0; - -	/* Set up a timeout to start the renewal process. */ -	add_timeout (ip -> client -> active -> renewal, -		     state_bound, ip); - -	note ("bound to %s -- renewal in %d seconds.", -	      piaddr (ip -> client -> active -> address), -	      ip -> client -> active -> renewal - cur_time); -	ip -> client -> state = S_BOUND; -	reinitialize_interfaces (); -	go_daemon (); -}   - -/* state_bound is called when we've successfully bound to a particular -   lease, but the renewal time on that lease has expired.   We are -   expected to unicast a DHCPREQUEST to the server that gave us our -   original lease. */ - -void state_bound (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	ASSERT_STATE(state, S_BOUND); - -	/* T1 has expired. */ -	make_request (ip, ip -> client -> active); -	ip -> client -> xid = ip -> client -> packet.xid; - -	if (ip -> client -> active -> -	    options [DHO_DHCP_SERVER_IDENTIFIER].len == 4) { -		memcpy (ip -> client -> destination.iabuf, -			ip -> client -> active -> -			options [DHO_DHCP_SERVER_IDENTIFIER].data, 4); -		ip -> client -> destination.len = 4; -	} else -		ip -> client -> destination = iaddr_broadcast; - -	ip -> client -> first_sending = cur_time; -	ip -> client -> interval = ip -> client -> config -> initial_interval; -	ip -> client -> state = S_RENEWING; - -	/* Send the first packet immediately. */ -	send_request (ip); -}   - -int commit_leases () -{ -	return 0; -} - -int write_lease (lease) -	struct lease *lease; -{ -	return 0; -} - -void db_startup () -{ -} - -void bootp (packet) -	struct packet *packet; -{ -	struct iaddrlist *ap; - -	if (packet -> raw -> op != BOOTREPLY) -		return; - -	/* If there's a reject list, make sure this packet's sender isn't -	   on it. */ -	for (ap = packet -> interface -> client -> config -> reject_list; -	     ap; ap = ap -> next) { -		if (addr_eq (packet -> client_addr, ap -> addr)) { -			note ("BOOTREPLY from %s rejected.", -			      piaddr (ap -> addr)); -			return; -		} -	} -	 -	dhcpoffer (packet); - -} - -void dhcp (packet) -	struct packet *packet; -{ -	struct iaddrlist *ap; -	void (*handler) PROTO ((struct packet *)); -	char *type; - -	switch (packet -> packet_type) { -	      case DHCPOFFER: -		handler = dhcpoffer; -		type = "DHCPOFFER"; -		break; - -	      case DHCPNAK: -		handler = dhcpnak; -		type = "DHCPNACK"; -		break; - -	      case DHCPACK: -		handler = dhcpack; -		type = "DHCPACK"; -		break; - -	      default: -		return; -	} - -	/* If there's a reject list, make sure this packet's sender isn't -	   on it. */ -	for (ap = packet -> interface -> client -> config -> reject_list; -	     ap; ap = ap -> next) { -		if (addr_eq (packet -> client_addr, ap -> addr)) { -			note ("%s from %s rejected.", -			      type, piaddr (ap -> addr)); -			return; -		} -	} -	(*handler) (packet); -} - -void dhcpoffer (packet) -	struct packet *packet; -{ -	struct interface_info *ip = packet -> interface; -	struct client_lease *lease, *lp; -	int i; -	int arp_timeout_needed, stop_selecting; -	char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len -		      ? "DHCPOFFER" : "BOOTREPLY"); -	struct iaddrlist *ap; -	 -#ifdef DEBUG_PACKET -	dump_packet (packet); -#endif	 - -	/* If we're not receptive to an offer right now, or if the offer -	   has an unrecognizable transaction id, then just drop it. */ -	if (ip -> client -> state != S_SELECTING || -	    packet -> interface -> client -> xid != packet -> raw -> xid || -	    (packet -> interface -> hw_address.hlen != -	     packet -> raw -> hlen) || -	    (memcmp (packet -> interface -> hw_address.haddr, -		     packet -> raw -> chaddr, packet -> raw -> hlen))) { -		debug ("%s in wrong transaction.", name); -		return; -	} - -	note ("%s from %s", name, piaddr (packet -> client_addr)); - - -	/* If this lease doesn't supply the minimum required parameters, -	   blow it off. */ -	for (i = 0; ip -> client -> config -> required_options [i]; i++) { -		if (!packet -> options [ip -> client -> config -> -					required_options [i]].len) { -			note ("%s isn't satisfactory.", name); -			return; -		} -	} - -	/* If we've already seen this lease, don't record it again. */ -	for (lease = ip -> client -> offered_leases; -	     lease; lease = lease -> next) { -		if (lease -> address.len == sizeof packet -> raw -> yiaddr && -		    !memcmp (lease -> address.iabuf, -			     &packet -> raw -> yiaddr, lease -> address.len)) { -			debug ("%s already seen.", name); -			return; -		} -	} - -	lease = packet_to_lease (packet); -	if (!lease) { -		note ("packet_to_lease failed."); -		return; -	} - -	/* If this lease was acquired through a BOOTREPLY, record that -	   fact. */ -	if (!packet -> options [DHO_DHCP_MESSAGE_TYPE].len) -		lease -> is_bootp = 1; - -	/* Record the medium under which this lease was offered. */ -	lease -> medium = ip -> client -> medium; - -	/* Send out an ARP Request for the offered IP address. */ -	script_init (ip, "ARPSEND", lease -> medium); -	script_write_params (ip, "check_", lease); -	/* If the script can't send an ARP request without waiting,  -	   we'll be waiting when we do the ARPCHECK, so don't wait now. */ -	if (script_go (ip)) -		arp_timeout_needed = 0; -	else -		arp_timeout_needed = 2; - -	/* Figure out when we're supposed to stop selecting. */ -	stop_selecting = (ip -> client -> first_sending + -			  ip -> client -> config -> select_interval); - -	/* If this is the lease we asked for, put it at the head of the -	   list, and don't mess with the arp request timeout. */ -	if (lease -> address.len == ip -> client -> requested_address.len && -	    !memcmp (lease -> address.iabuf, -		     ip -> client -> requested_address.iabuf, -		     ip -> client -> requested_address.len)) { -		lease -> next = ip -> client -> offered_leases; -		ip -> client -> offered_leases = lease; -	} else { -		/* If we already have an offer, and arping for this -		   offer would take us past the selection timeout, -		   then don't extend the timeout - just hope for the -		   best. */ -		if (ip -> client -> offered_leases && -		    (cur_time + arp_timeout_needed) > stop_selecting) -			arp_timeout_needed = 0; - -		/* Put the lease at the end of the list. */ -		lease -> next = (struct client_lease *)0; -		if (!ip -> client -> offered_leases) -			ip -> client -> offered_leases = lease; -		else { -			for (lp = ip -> client -> offered_leases; lp -> next; -			     lp = lp -> next) -				; -			lp -> next = lease; -		} -	} - -	/* If we're supposed to stop selecting before we've had time -	   to wait for the ARPREPLY, add some delay to wait for -	   the ARPREPLY. */ -	if (stop_selecting - cur_time < arp_timeout_needed) -		stop_selecting = cur_time + arp_timeout_needed; - -	/* If the selecting interval has expired, go immediately to -	   state_selecting().  Otherwise, time out into -	   state_selecting at the select interval. */ -	if (stop_selecting <= 0) -		state_selecting (ip); -	else { -		add_timeout (stop_selecting, state_selecting, ip); -		cancel_timeout (send_discover, ip); -	} -} - -/* Allocate a client_lease structure and initialize it from the parameters -   in the specified packet. */ - -struct client_lease *packet_to_lease (packet) -	struct packet *packet; -{ -	struct client_lease *lease; -	int i; - -	lease = (struct client_lease *)malloc (sizeof (struct client_lease)); - -	if (!lease) { -		warn ("dhcpoffer: no memory to record lease.\n"); -		return (struct client_lease *)0; -	} - -	memset (lease, 0, sizeof *lease); - -	/* Copy the lease options. */ -	for (i = 0; i < 256; i++) { -		if (packet -> options [i].len) { -			lease -> options [i].data = -				(unsigned char *) -					malloc (packet -> options [i].len + 1); -			if (!lease -> options [i].data) { -				warn ("dhcpoffer: no memory for option %d\n", -				      i); -				free_client_lease (lease); -				return (struct client_lease *)0; -			} else { -				memcpy (lease -> options [i].data, -					packet -> options [i].data, -					packet -> options [i].len); -				lease -> options [i].len = -					packet -> options [i].len; -				lease -> options [i].data -					[lease -> options [i].len] = 0; -			} -		} -	} - -	lease -> address.len = sizeof (packet -> raw -> yiaddr); -	memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr, -		lease -> address.len); - -	/* If the server name was filled out, copy it. */ -	if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len || -	     !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)) && -	    packet -> raw -> sname [0]) { -		int len; -		/* Don't count on the NUL terminator. */ -		for (len = 0; len < 64; len++) -			if (!packet -> raw -> sname [len]) -				break; -		lease -> server_name = malloc (len + 1); -		if (!lease -> server_name) { -			warn ("dhcpoffer: no memory for filename.\n"); -			free_client_lease (lease); -			return (struct client_lease *)0; -		} else { -			memcpy (lease -> server_name, -				packet -> raw -> sname, len); -			lease -> server_name [len] = 0; -		} -	} - -	/* Ditto for the filename. */ -	if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len || -	     !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)) && -	    packet -> raw -> file [0]) { -		int len; -		/* Don't count on the NUL terminator. */ -		for (len = 0; len < 64; len++) -			if (!packet -> raw -> file [len]) -				break; -		lease -> filename = malloc (len + 1); -		if (!lease -> filename) { -			warn ("dhcpoffer: no memory for filename.\n"); -			free_client_lease (lease); -			return (struct client_lease *)0; -		} else { -			memcpy (lease -> filename, -				packet -> raw -> file, len); -			lease -> filename [len] = 0; -		} -	} -	return lease; -}	 - -void dhcpnak (packet) -	struct packet *packet; -{ -	struct interface_info *ip = packet -> interface; - -	/* If we're not receptive to an offer right now, or if the offer -	   has an unrecognizable transaction id, then just drop it. */ -	if (packet -> interface -> client -> xid != packet -> raw -> xid || -	    (packet -> interface -> hw_address.hlen != -	     packet -> raw -> hlen) || -	    (memcmp (packet -> interface -> hw_address.haddr, -		     packet -> raw -> chaddr, packet -> raw -> hlen))) { -		debug ("DHCPNAK in wrong transaction."); -		return; -	} - -	if (ip -> client -> state != S_REBOOTING && -	    ip -> client -> state != S_REQUESTING && -	    ip -> client -> state != S_RENEWING && -	    ip -> client -> state != S_REBINDING) { -		debug ("DHCPNAK in wrong state."); -		return; -	} - -	note ("DHCPNAK from %s", piaddr (packet -> client_addr)); - -	if (!ip -> client -> active) { -		note ("DHCPNAK with no active lease.\n"); -		return; -	} - -	free_client_lease (ip -> client -> active); -	ip -> client -> active = (struct client_lease *)0; - -	/* Stop sending DHCPREQUEST packets... */ -	cancel_timeout (send_request, ip); - -	ip -> client -> state = S_INIT; -	state_init (ip); -} - -/* Send out a DHCPDISCOVER packet, and set a timeout to send out another -   one after the right interval has expired.  If we don't get an offer by -   the time we reach the panic interval, call the panic function. */ - -void send_discover (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	int result; -	int interval; -	int increase = 1; - -	/* Figure out how long it's been since we started transmitting. */ -	interval = cur_time - ip -> client -> first_sending; - -	/* If we're past the panic timeout, call the script and tell it -	   we haven't found anything for this interface yet. */ -	if (interval > ip -> client -> config -> timeout) { -		state_panic (ip); -		return; -	} - -	/* If we're selecting media, try the whole list before doing -	   the exponential backoff, but if we've already received an -	   offer, stop looping, because we obviously have it right. */ -	if (!ip -> client -> offered_leases && -	    ip -> client -> config -> media) { -		int fail = 0; -	      again: -		if (ip -> client -> medium) { -			ip -> client -> medium = -				ip -> client -> medium -> next; -			increase = 0; -		}  -		if (!ip -> client -> medium) { -			if (fail) -				error ("No valid media types for %s!", -				       ip -> name); -			ip -> client -> medium = -				ip -> client -> config -> media; -			increase = 1; -		} -			 -		note ("Trying medium \"%s\" %d", -		      ip -> client -> medium -> string, increase); -		script_init (ip, "MEDIUM", ip -> client -> medium); -		if (script_go (ip)) { -			goto again; -		} -	} - -	/* If we're supposed to increase the interval, do so.  If it's -	   currently zero (i.e., we haven't sent any packets yet), set -	   it to one; otherwise, add to it a random number between -	   zero and two times itself.  On average, this means that it -	   will double with every transmission. */ -	if (increase) { -		if (!ip -> client -> interval) -			ip -> client -> interval = -				ip -> client -> config -> initial_interval; -		else { -			ip -> client -> interval += -				((random () >> 2) % -				 (2 * ip -> client -> interval)); -		} - -		/* Don't backoff past cutoff. */ -		if (ip -> client -> interval > -		    ip -> client -> config -> backoff_cutoff) -			ip -> client -> interval = -				((ip -> client -> config -> backoff_cutoff / 2) -				 + ((random () >> 2) % -				    ip -> client -> config -> backoff_cutoff)); -	} else if (!ip -> client -> interval) -		ip -> client -> interval = -			ip -> client -> config -> initial_interval; -		 -	/* If the backoff would take us to the panic timeout, just use that -	   as the interval. */ -	if (cur_time + ip -> client -> interval > -	    ip -> client -> first_sending + ip -> client -> config -> timeout) -		ip -> client -> interval = -			(ip -> client -> first_sending + -			 ip -> client -> config -> timeout) - cur_time + 1; - -	/* Record the number of seconds since we started sending. */ -	if (interval < 255) -		ip -> client -> packet.secs = interval; -	else -		ip -> client -> packet.secs = 255; - -	note ("DHCPDISCOVER on %s to %s port %d interval %ld", -	      ip -> name, -	      inet_ntoa (sockaddr_broadcast.sin_addr), -	      ntohs (sockaddr_broadcast.sin_port), ip -> client -> interval); - -	/* Send out a packet. */ -	result = send_packet (ip, (struct packet *)0, -			      &ip -> client -> packet, -			      ip -> client -> packet_length, -			      inaddr_any, &sockaddr_broadcast, -			      (struct hardware *)0); -	if (result < 0) -		warn ("send_packet: %m"); - -	add_timeout (cur_time + ip -> client -> interval, send_discover, ip); -} - -/* state_panic gets called if we haven't received any offers in a preset -   amount of time.   When this happens, we try to use existing leases that -   haven't yet expired, and failing that, we call the client script and -   hope it can do something. */ - -void state_panic (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	struct client_lease *loop = ip -> client -> active; -	struct client_lease *lp; - -	note ("No DHCPOFFERS received."); - -	/* We may not have an active lease, but we may have some -	   predefined leases that we can try. */ -	if (!ip -> client -> active && ip -> client -> leases) -		goto activate_next; - -	/* Run through the list of leases and see if one can be used. */ -	while (ip -> client -> active) { -		if (ip -> client -> active -> expiry > cur_time) { -			note ("Trying recorded lease %s", -			      piaddr (ip -> client -> active -> address)); -			/* Run the client script with the existing -			   parameters. */ -			script_init (ip, "TIMEOUT", -				     ip -> client -> active -> medium); -			script_write_params (ip, "new_", -					     ip -> client -> active); -			if (ip -> client -> alias) -				script_write_params (ip, "alias_", -						     ip -> client -> alias); - -			/* If the old lease is still good and doesn't -			   yet need renewal, go into BOUND state and -			   timeout at the renewal time. */ -			if (!script_go (ip)) { -				if (cur_time < -				    ip -> client -> active -> renewal) { -					ip -> client -> state = S_BOUND; -					note ("bound: renewal in %d seconds.", -					      ip -> client -> active -> renewal -					      - cur_time); -					add_timeout ((ip -> client -> -						      active -> renewal), -						     state_bound, ip); -				} else { -					ip -> client -> state = S_BOUND; -					note ("bound: immediate renewal."); -					state_bound (ip); -				} -				reinitialize_interfaces (); -				go_daemon (); -				return; -			} -		} - -		/* If there are no other leases, give up. */ -		if (!ip -> client -> leases) { -			ip -> client -> leases = ip -> client -> active; -			ip -> client -> active = (struct client_lease *)0; -			break; -		} - -	activate_next: -		/* Otherwise, put the active lease at the end of the -		   lease list, and try another lease.. */ -		for (lp = ip -> client -> leases; lp -> next; lp = lp -> next) -			; -		lp -> next = ip -> client -> active; -		if (lp -> next) { -			lp -> next -> next = (struct client_lease *)0; -		} -		ip -> client -> active = ip -> client -> leases; -		ip -> client -> leases = ip -> client -> leases -> next; - -		/* If we already tried this lease, we've exhausted the -		   set of leases, so we might as well give up for -		   now. */ -		if (ip -> client -> active == loop) -			break; -		else if (!loop) -			loop = ip -> client -> active; -	} - -	/* No leases were available, or what was available didn't work, so -	   tell the shell script that we failed to allocate an address, -	   and try again later. */ -	if (onetry) { -		exit(1); -		note ("Unable to obtain a lease on first try - exiting.\n"); -	} -	note ("No working leases in persistent database - sleeping.\n"); -	script_init (ip, "FAIL", (struct string_list *)0); -	if (ip -> client -> alias) -		script_write_params (ip, "alias_", ip -> client -> alias); -	script_go (ip); -	ip -> client -> state = S_INIT; -	add_timeout (cur_time + ip -> client -> config -> retry_interval, -		     state_init, ip); -	go_daemon (); -} - -void send_request (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	int result; -	int interval; -	struct sockaddr_in destination; -	struct in_addr from; - -	/* Figure out how long it's been since we started transmitting. */ -	interval = cur_time - ip -> client -> first_sending; - -	/* If we're in the INIT-REBOOT or REQUESTING state and we're -	   past the reboot timeout, go to INIT and see if we can -	   DISCOVER an address... */ -	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it -	   means either that we're on a network with no DHCP server, -	   or that our server is down.  In the latter case, assuming -	   that there is a backup DHCP server, DHCPDISCOVER will get -	   us a new address, but we could also have successfully -	   reused our old address.  In the former case, we're hosed -	   anyway.  This is not a win-prone situation. */ -	if ((ip -> client -> state == S_REBOOTING || -	     ip -> client -> state == S_REQUESTING) && -	    interval > ip -> client -> config -> reboot_timeout) { -	cancel: -		ip -> client -> state = S_INIT; -		cancel_timeout (send_request, ip); -		state_init (ip); -		return; -	} - -	/* If we're in the reboot state, make sure the media is set up -	   correctly. */ -	if (ip -> client -> state == S_REBOOTING && -	    !ip -> client -> medium && -	    ip -> client -> active -> medium ) { -		script_init (ip, "MEDIUM", ip -> client -> active -> medium); - -		/* If the medium we chose won't fly, go to INIT state. */ -		if (script_go (ip)) -			goto cancel; - -		/* Record the medium. */ -		ip -> client -> medium = ip -> client -> active -> medium; -	} - -	/* If the lease has expired, relinquish the address and go back -	   to the INIT state. */ -	if (ip -> client -> state != S_REQUESTING && -	    cur_time > ip -> client -> active -> expiry) { -		/* Run the client script with the new parameters. */ -		script_init (ip, "EXPIRE", (struct string_list *)0); -		script_write_params (ip, "old_", ip -> client -> active); -		if (ip -> client -> alias) -			script_write_params (ip, "alias_", -					     ip -> client -> alias); -		script_go (ip); - -		/* Now do a preinit on the interface so that we can -		   discover a new address. */ -		script_init (ip, "PREINIT", (struct string_list *)0); -		if (ip -> client -> alias) -			script_write_params (ip, "alias_", -					     ip -> client -> alias); -		script_go (ip); - -		ip -> client -> state = S_INIT; -		state_init (ip); -		return; -	} - -	/* Do the exponential backoff... */ -	if (!ip -> client -> interval) -		ip -> client -> interval = -			ip -> client -> config -> initial_interval; -	else { -		ip -> client -> interval += -			((random () >> 2) % -			 (2 * ip -> client -> interval)); -	} -	 -	/* Don't backoff past cutoff. */ -	if (ip -> client -> interval > -	    ip -> client -> config -> backoff_cutoff) -		ip -> client -> interval = -			((ip -> client -> config -> backoff_cutoff / 2) -			 + ((random () >> 2) -			    % ip -> client -> interval)); - -	/* If the backoff would take us to the expiry time, just set the -	   timeout to the expiry time. */ -	if (ip -> client -> state != S_REQUESTING && -	    cur_time + ip -> client -> interval > -	    ip -> client -> active -> expiry) -		ip -> client -> interval = -			ip -> client -> active -> expiry - cur_time + 1; - -	/* If the lease T2 time has elapsed, or if we're not yet bound, -	   broadcast the DHCPREQUEST rather than unicasting. */ -	if (ip -> client -> state == S_REQUESTING || -	    ip -> client -> state == S_REBOOTING || -	    cur_time > ip -> client -> active -> rebind) -		destination.sin_addr.s_addr = INADDR_BROADCAST; -	else -		memcpy (&destination.sin_addr.s_addr, -			ip -> client -> destination.iabuf, -			sizeof destination.sin_addr.s_addr); -	destination.sin_port = remote_port; -	destination.sin_family = AF_INET; -#ifdef HAVE_SA_LEN -	destination.sin_len = sizeof destination; -#endif - -	if (ip -> client -> state != S_REQUESTING) -		memcpy (&from, ip -> client -> active -> address.iabuf, -			sizeof from); -	else -		from.s_addr = INADDR_ANY; - -	/* Record the number of seconds since we started sending. */ -	if (interval < 255) -		ip -> client -> packet.secs = interval; -	else -		ip -> client -> packet.secs = 255; - -	note ("DHCPREQUEST on %s to %s port %d", ip -> name, -	      inet_ntoa (destination.sin_addr), -	      ntohs (destination.sin_port)); - -	if (destination.sin_addr.s_addr != INADDR_BROADCAST && -	    fallback_interface) -		result = send_packet (fallback_interface, -				      (struct packet *)0, -				      &ip -> client -> packet, -				      ip -> client -> packet_length, -				      from, &destination, -				      (struct hardware *)0); -	else -		/* Send out a packet. */ -		result = send_packet (ip, (struct packet *)0, -				      &ip -> client -> packet, -				      ip -> client -> packet_length, -				      from, &destination, -				      (struct hardware *)0); - -	if (result < 0) -		warn ("send_packet: %m"); - -	add_timeout (cur_time + ip -> client -> interval, -		     send_request, ip); -} - -void send_decline (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	int result; - -	note ("DHCPDECLINE on %s to %s port %d", ip -> name, -	      inet_ntoa (sockaddr_broadcast.sin_addr), -	      ntohs (sockaddr_broadcast.sin_port)); - -	/* Send out a packet. */ -	result = send_packet (ip, (struct packet *)0, -			      &ip -> client -> packet, -			      ip -> client -> packet_length, -			      inaddr_any, &sockaddr_broadcast, -			      (struct hardware *)0); -	if (result < 0) -		warn ("send_packet: %m"); -} - -void send_release (ipp) -	void *ipp; -{ -	struct interface_info *ip = ipp; - -	int result; - -	note ("DHCPRELEASE on %s to %s port %d", ip -> name, -	      inet_ntoa (sockaddr_broadcast.sin_addr), -	      ntohs (sockaddr_broadcast.sin_port)); - -	/* Send out a packet. */ -	result = send_packet (ip, (struct packet *)0, -			      &ip -> client -> packet, -			      ip -> client -> packet_length, -			      inaddr_any, &sockaddr_broadcast, -			      (struct hardware *)0); -	if (result < 0) -		warn ("send_packet: %m"); -} - -void make_discover (ip, lease) -	struct interface_info *ip; -	struct client_lease *lease; -{ -	struct dhcp_packet *raw; -	unsigned char discover = DHCPDISCOVER; -	int i; - -	struct tree_cache *options [256]; -	struct tree_cache option_elements [256]; - -	memset (option_elements, 0, sizeof option_elements); -	memset (options, 0, sizeof options); -	memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - -	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ -	i = DHO_DHCP_MESSAGE_TYPE; -	options [i] = &option_elements [i]; -	options [i] -> value = &discover; -	options [i] -> len = sizeof discover; -	options [i] -> buf_size = sizeof discover; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* Request the options we want */ -	i  = DHO_DHCP_PARAMETER_REQUEST_LIST; -	options [i] = &option_elements [i]; -	options [i] -> value = ip -> client -> config -> requested_options; -	options [i] -> len = ip -> client -> config -> requested_option_count; -	options [i] -> buf_size = -		ip -> client -> config -> requested_option_count; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* If we had an address, try to get it again. */ -	if (lease) { -		ip -> client -> requested_address = lease -> address; -		i = DHO_DHCP_REQUESTED_ADDRESS; -		options [i] = &option_elements [i]; -		options [i] -> value = lease -> address.iabuf; -		options [i] -> len = lease -> address.len; -		options [i] -> buf_size = lease -> address.len; -		options [i] -> timeout = 0xFFFFFFFF; -		options [i] -> tree = (struct tree *)0; -	} else { -		ip -> client -> requested_address.len = 0; -	} - -	/* Send any options requested in the config file. */ -	for (i = 0; i < 256; i++) { -		if (!options [i] && -		    ip -> client -> config -> send_options [i].data) { -			options [i] = &option_elements [i]; -			options [i] -> value = ip -> client -> config -> -				send_options [i].data; -			options [i] -> len = ip -> client -> config -> -				send_options [i].len; -			options [i] -> buf_size = ip -> client -> config -> -				send_options [i].len; -			options [i] -> timeout = 0xFFFFFFFF; -			options [i] -> tree = (struct tree *)0; -		} -	} - -	/* Set up the option buffer... */ -	ip -> client -> packet_length = -		cons_options ((struct packet *)0, &ip -> client -> packet, -			      options, 0, 0, 0); -	if (ip -> client -> packet_length < BOOTP_MIN_LEN) -		ip -> client -> packet_length = BOOTP_MIN_LEN; - -	ip -> client -> packet.op = BOOTREQUEST; -	ip -> client -> packet.htype = ip -> hw_address.htype; -	ip -> client -> packet.hlen = ip -> hw_address.hlen; -	ip -> client -> packet.hops = 0; -	ip -> client -> packet.xid = random (); -	ip -> client -> packet.secs = 0; /* filled in by send_discover. */ -	ip -> client -> packet.flags = htons (BOOTP_BROADCAST); /* XXX */ -	memset (&(ip -> client -> packet.ciaddr), -		0, sizeof ip -> client -> packet.ciaddr); -	memset (&(ip -> client -> packet.yiaddr), -		0, sizeof ip -> client -> packet.yiaddr); -	memset (&(ip -> client -> packet.siaddr), -		0, sizeof ip -> client -> packet.siaddr); -	memset (&(ip -> client -> packet.giaddr), -		0, sizeof ip -> client -> packet.giaddr); -	memcpy (ip -> client -> packet.chaddr, -		ip -> hw_address.haddr, ip -> hw_address.hlen); - -#ifdef DEBUG_PACKET -	dump_packet (sendpkt); -	dump_raw ((unsigned char *)ip -> client -> packet, -		  sendpkt->packet_length); -#endif -} - - -void make_request (ip, lease) -	struct interface_info *ip; -	struct client_lease *lease; -{ -	unsigned char request = DHCPREQUEST; -	int i; - -	struct tree_cache *options [256]; -	struct tree_cache option_elements [256]; - -	memset (options, 0, sizeof options); -	memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - -	/* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ -	i = DHO_DHCP_MESSAGE_TYPE; -	options [i] = &option_elements [i]; -	options [i] -> value = &request; -	options [i] -> len = sizeof request; -	options [i] -> buf_size = sizeof request; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* Request the options we want */ -	i = DHO_DHCP_PARAMETER_REQUEST_LIST; -	options [i] = &option_elements [i]; -	options [i] -> value = ip -> client -> config -> requested_options; -	options [i] -> len = ip -> client -> config -> requested_option_count; -	options [i] -> buf_size = -		ip -> client -> config -> requested_option_count; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* If we are requesting an address that hasn't yet been assigned -	   to us, use the DHCP Requested Address option. */ -	if (ip -> client -> state == S_REQUESTING) { -		/* Send back the server identifier... */ -		i = DHO_DHCP_SERVER_IDENTIFIER; -		options [i] = &option_elements [i]; -		options [i] -> value = lease -> options [i].data; -		options [i] -> len = lease -> options [i].len; -		options [i] -> buf_size = lease -> options [i].len; -		options [i] -> timeout = 0xFFFFFFFF; -		options [i] -> tree = (struct tree *)0; -	} -	if (ip -> client -> state == S_REQUESTING || -	    ip -> client -> state == S_REBOOTING) { -		ip -> client -> requested_address = lease -> address; -		i = DHO_DHCP_REQUESTED_ADDRESS; -		options [i] = &option_elements [i]; -		options [i] -> value = lease -> address.iabuf; -		options [i] -> len = lease -> address.len; -		options [i] -> buf_size = lease -> address.len; -		options [i] -> timeout = 0xFFFFFFFF; -		options [i] -> tree = (struct tree *)0; -	} else { -		ip -> client -> requested_address.len = 0; -	} - -	/* Send any options requested in the config file. */ -	for (i = 0; i < 256; i++) { -		if (!options [i] && -		    ip -> client -> config -> send_options [i].data) { -			options [i] = &option_elements [i]; -			options [i] -> value = ip -> client -> config -> -				send_options [i].data; -			options [i] -> len = ip -> client -> config -> -				send_options [i].len; -			options [i] -> buf_size = ip -> client -> config -> -				send_options [i].len; -			options [i] -> timeout = 0xFFFFFFFF; -			options [i] -> tree = (struct tree *)0; -		} -	} - -	/* Set up the option buffer... */ -	ip -> client -> packet_length = -		cons_options ((struct packet *)0, &ip -> client -> packet, -			      options, 0, 0, 0); -	if (ip -> client -> packet_length < BOOTP_MIN_LEN) -		ip -> client -> packet_length = BOOTP_MIN_LEN; - -	ip -> client -> packet.op = BOOTREQUEST; -	ip -> client -> packet.htype = ip -> hw_address.htype; -	ip -> client -> packet.hlen = ip -> hw_address.hlen; -	ip -> client -> packet.hops = 0; -	ip -> client -> packet.xid = ip -> client -> xid; -	ip -> client -> packet.secs = 0; /* Filled in by send_request. */ - -	/* If we own the address we're requesting, put it in ciaddr; -	   otherwise set ciaddr to zero. */ -	if (ip -> client -> state == S_BOUND || -	    ip -> client -> state == S_RENEWING || -	    ip -> client -> state == S_REBINDING) { -		memcpy (&ip -> client -> packet.ciaddr, -			lease -> address.iabuf, lease -> address.len); -		ip -> client -> packet.flags = 0; -	} else { -		memset (&ip -> client -> packet.ciaddr, 0, -			sizeof ip -> client -> packet.ciaddr); -		ip -> client -> packet.flags = htons (BOOTP_BROADCAST); -	} - -	memset (&ip -> client -> packet.yiaddr, 0, -		sizeof ip -> client -> packet.yiaddr); -	memset (&ip -> client -> packet.siaddr, 0, -		sizeof ip -> client -> packet.siaddr); -	memset (&ip -> client -> packet.giaddr, 0, -		sizeof ip -> client -> packet.giaddr); -	memcpy (ip -> client -> packet.chaddr, -		ip -> hw_address.haddr, ip -> hw_address.hlen); - -#ifdef DEBUG_PACKET -	dump_packet (sendpkt); -	dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); -#endif -} - -void make_decline (ip, lease) -	struct interface_info *ip; -	struct client_lease *lease; -{ -	unsigned char decline = DHCPDECLINE; -	int i; - -	struct tree_cache *options [256]; -	struct tree_cache message_type_tree; -	struct tree_cache requested_address_tree; -	struct tree_cache server_id_tree; -	struct tree_cache client_id_tree; - -	memset (options, 0, sizeof options); -	memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - -	/* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ -	i = DHO_DHCP_MESSAGE_TYPE; -	options [i] = &message_type_tree; -	options [i] -> value = &decline; -	options [i] -> len = sizeof decline; -	options [i] -> buf_size = sizeof decline; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* Send back the server identifier... */ -	i = DHO_DHCP_SERVER_IDENTIFIER; -        options [i] = &server_id_tree; -        options [i] -> value = lease -> options [i].data; -        options [i] -> len = lease -> options [i].len; -        options [i] -> buf_size = lease -> options [i].len; -        options [i] -> timeout = 0xFFFFFFFF; -        options [i] -> tree = (struct tree *)0; - -	/* Send back the address we're declining. */ -	i = DHO_DHCP_REQUESTED_ADDRESS; -	options [i] = &requested_address_tree; -	options [i] -> value = lease -> address.iabuf; -	options [i] -> len = lease -> address.len; -	options [i] -> buf_size = lease -> address.len; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* Send the uid if the user supplied one. */ -	i = DHO_DHCP_CLIENT_IDENTIFIER; -	if (ip -> client -> config -> send_options [i].len) { -		options [i] = &client_id_tree; -		options [i] -> value = ip -> client -> config -> -			send_options [i].data; -		options [i] -> len = ip -> client -> config -> -			send_options [i].len; -		options [i] -> buf_size = ip -> client -> config -> -			send_options [i].len; -		options [i] -> timeout = 0xFFFFFFFF; -		options [i] -> tree = (struct tree *)0; -	} - - -	/* Set up the option buffer... */ -	ip -> client -> packet_length = -		cons_options ((struct packet *)0, &ip -> client -> packet, -			      options, 0, 0, 0); -	if (ip -> client -> packet_length < BOOTP_MIN_LEN) -		ip -> client -> packet_length = BOOTP_MIN_LEN; - -	ip -> client -> packet.op = BOOTREQUEST; -	ip -> client -> packet.htype = ip -> hw_address.htype; -	ip -> client -> packet.hlen = ip -> hw_address.hlen; -	ip -> client -> packet.hops = 0; -	ip -> client -> packet.xid = ip -> client -> xid; -	ip -> client -> packet.secs = 0; /* Filled in by send_request. */ -	ip -> client -> packet.flags = htons (BOOTP_BROADCAST); - -	/* ciaddr must always be zero. */ -	memset (&ip -> client -> packet.ciaddr, 0, -		sizeof ip -> client -> packet.ciaddr); -	memset (&ip -> client -> packet.yiaddr, 0, -		sizeof ip -> client -> packet.yiaddr); -	memset (&ip -> client -> packet.siaddr, 0, -		sizeof ip -> client -> packet.siaddr); -	memset (&ip -> client -> packet.giaddr, 0, -		sizeof ip -> client -> packet.giaddr); -	memcpy (ip -> client -> packet.chaddr, -		ip -> hw_address.haddr, ip -> hw_address.hlen); - -#ifdef DEBUG_PACKET -	dump_packet (sendpkt); -	dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); -#endif -} - -void make_release (ip, lease) -	struct interface_info *ip; -	struct client_lease *lease; -{ -	unsigned char request = DHCPRELEASE; -	int i; - -	struct tree_cache *options [256]; -	struct tree_cache message_type_tree; -	struct tree_cache requested_address_tree; -	struct tree_cache server_id_tree; - -	memset (options, 0, sizeof options); -	memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - -	/* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */ -	i = DHO_DHCP_MESSAGE_TYPE; -	options [i] = &message_type_tree; -	options [i] -> value = &request; -	options [i] -> len = sizeof request; -	options [i] -> buf_size = sizeof request; -	options [i] -> timeout = 0xFFFFFFFF; -	options [i] -> tree = (struct tree *)0; - -	/* Send back the server identifier... */ -	i = DHO_DHCP_SERVER_IDENTIFIER; -        options [i] = &server_id_tree; -        options [i] -> value = lease -> options [i].data; -        options [i] -> len = lease -> options [i].len; -        options [i] -> buf_size = lease -> options [i].len; -        options [i] -> timeout = 0xFFFFFFFF; -        options [i] -> tree = (struct tree *)0; - -	/* Set up the option buffer... */ -	ip -> client -> packet_length = -		cons_options ((struct packet *)0, &ip -> client -> packet, -			      options, 0, 0, 0); -	if (ip -> client -> packet_length < BOOTP_MIN_LEN) -		ip -> client -> packet_length = BOOTP_MIN_LEN; - -	ip -> client -> packet.op = BOOTREQUEST; -	ip -> client -> packet.htype = ip -> hw_address.htype; -	ip -> client -> packet.hlen = ip -> hw_address.hlen; -	ip -> client -> packet.hops = 0; -	ip -> client -> packet.xid = ip -> client -> xid; -	ip -> client -> packet.secs = 0; -	ip -> client -> packet.flags = 0; -	memcpy (&ip -> client -> packet.ciaddr, -		lease -> address.iabuf, lease -> address.len); -	memset (&ip -> client -> packet.yiaddr, 0, -		sizeof ip -> client -> packet.yiaddr); -	memset (&ip -> client -> packet.siaddr, 0, -		sizeof ip -> client -> packet.siaddr); -	memset (&ip -> client -> packet.giaddr, 0, -		sizeof ip -> client -> packet.giaddr); -	memcpy (ip -> client -> packet.chaddr, -		ip -> hw_address.haddr, ip -> hw_address.hlen); - -#ifdef DEBUG_PACKET -	dump_packet (sendpkt); -	dump_raw ((unsigned char *)ip -> client -> packet, -		  ip -> client -> packet_length); -#endif -} - -void free_client_lease (lease) -	struct client_lease *lease; -{ -	int i; - -	if (lease -> server_name) -		free (lease -> server_name); -	if (lease -> filename) -		free (lease -> filename); -	for (i = 0; i < 256; i++) { -		if (lease -> options [i].len) -			free (lease -> options [i].data); -	} -	free (lease); -} - -FILE *leaseFile; - -void rewrite_client_leases () -{ -	struct interface_info *ip; -	struct client_lease *lp; - -	if (leaseFile) -		fclose (leaseFile); -	leaseFile = fopen (path_dhclient_db, "w"); -	if (!leaseFile) -		error ("can't create %s: %m", path_dhclient_db); - -	/* Write out all the leases attached to configured interfaces that -	   we know about. */ -	for (ip = interfaces; ip; ip = ip -> next) { -		for (lp = ip -> client -> leases; lp; lp = lp -> next) { -			write_client_lease (ip, lp, 1); -		} -		if (ip -> client -> active) -			write_client_lease (ip, ip -> client -> active, 1); -	} - -	/* Write out any leases that are attached to interfaces that aren't -	   currently configured. */ -	for (ip = dummy_interfaces; ip; ip = ip -> next) { -		for (lp = ip -> client -> leases; lp; lp = lp -> next) { -			write_client_lease (ip, lp, 1); -		} -		if (ip -> client -> active) -			write_client_lease (ip, ip -> client -> active, 1); -	} -	fflush (leaseFile); -} - -void write_client_lease (ip, lease, rewrite) -	struct interface_info *ip; -	struct client_lease *lease; -	int rewrite; -{ -	int i; -	struct tm *t; -	static int leases_written; - -	if (!rewrite) { -		if (leases_written++ > 20) { -			rewrite_client_leases (); -			leases_written = 0; -		} -	} - -	/* If the lease came from the config file, we don't need to stash -	   a copy in the lease database. */ -	if (lease -> is_static) -		return; - -	if (!leaseFile) {	/* XXX */ -		leaseFile = fopen (path_dhclient_db, "w"); -		if (!leaseFile) -			error ("can't create %s: %m", path_dhclient_db); -	} - -	fprintf (leaseFile, "lease {\n"); -	if (lease -> is_bootp) -		fprintf (leaseFile, "  bootp;\n"); -	fprintf (leaseFile, "  interface \"%s\";\n", ip -> name); -	fprintf (leaseFile, "  fixed-address %s;\n", -		 piaddr (lease -> address)); -	if (lease -> filename) -		fprintf (leaseFile, "  filename \"%s\";\n", -			 lease -> filename); -	if (lease -> server_name) -		fprintf (leaseFile, "  server-name \"%s\";\n", -			 lease -> filename); -	if (lease -> medium) -		fprintf (leaseFile, "  medium \"%s\";\n", -			 lease -> medium -> string); -	for (i = 0; i < 256; i++) { -		if (lease -> options [i].len) { -			fprintf (leaseFile, -				 "  option %s %s;\n", -				 dhcp_options [i].name, -				 pretty_print_option -				 (i, lease -> options [i].data, -				  lease -> options [i].len, 1, 1)); -		} -	} - -	/* Note: the following is not a Y2K bug - it's a Y1.9K bug.   Until -	   somebody invents a time machine, I think we can safely disregard -	   it. */ -	t = gmtime (&lease -> renewal); -	fprintf (leaseFile, -		 "  renew %d %d/%d/%d %02d:%02d:%02d;\n", -		 t -> tm_wday, t -> tm_year + 1900, -		 t -> tm_mon + 1, t -> tm_mday, -		 t -> tm_hour, t -> tm_min, t -> tm_sec); -	t = gmtime (&lease -> rebind); -	fprintf (leaseFile, -		 "  rebind %d %d/%d/%d %02d:%02d:%02d;\n", -		 t -> tm_wday, t -> tm_year + 1900, -		 t -> tm_mon + 1, t -> tm_mday, -		 t -> tm_hour, t -> tm_min, t -> tm_sec); -	t = gmtime (&lease -> expiry); -	fprintf (leaseFile, -		 "  expire %d %d/%d/%d %02d:%02d:%02d;\n", -		 t -> tm_wday, t -> tm_year + 1900, -		 t -> tm_mon + 1, t -> tm_mday, -		 t -> tm_hour, t -> tm_min, t -> tm_sec); -	fprintf (leaseFile, "}\n"); -	fflush (leaseFile); -} - -/* Variables holding name of script and file pointer for writing to -   script.   Needless to say, this is not reentrant - only one script -   can be invoked at a time. */ -char scriptName [256]; -FILE *scriptFile; - -void script_init (ip, reason, medium) -	struct interface_info *ip; -	char *reason; -	struct string_list *medium; -{ -	int fd; -#ifndef HAVE_MKSTEMP - -	do { -#endif -		strcpy (scriptName, "/tmp/dcsXXXXXX"); -#ifdef HAVE_MKSTEMP -		fd = mkstemp (scriptName); -#else -		if (!mktemp (scriptName)) -			error ("can't create temporary client script %s: %m", -			       scriptName); -		fd = creat (scriptName, 0600); -	} while (fd < 0); -#endif - -	scriptFile = fdopen (fd, "w"); -	if (!scriptFile) -		error ("can't write script file: %m"); -	fprintf (scriptFile, "#!/bin/sh\n\n"); -	if (ip) { -		fprintf (scriptFile, "interface=\"%s\"\n", ip -> name); -		fprintf (scriptFile, "export interface\n"); -	} -	if (medium) { -		fprintf (scriptFile, "medium=\"%s\"\n", medium -> string); -		fprintf (scriptFile, "export medium\n"); -	} -	fprintf (scriptFile, "reason=\"%s\"\n", reason); -	fprintf (scriptFile, "export reason\n"); -} - -void script_write_params (ip, prefix, lease) -	struct interface_info *ip; -	char *prefix; -	struct client_lease *lease; -{ -	int i; -	u_int8_t dbuf [1500]; -	int len; - -	fprintf (scriptFile, "%sip_address=\"%s\"\n", -		 prefix, piaddr (lease -> address)); -	fprintf (scriptFile, "export %sip_address\n", prefix); - -	/* For the benefit of Linux (and operating systems which may -	   have similar needs), compute the network address based on -	   the supplied ip address and netmask, if provided.  Also -	   compute the broadcast address (the host address all ones -	   broadcast address, not the host address all zeroes -	   broadcast address). */ - -	if (lease -> options [DHO_SUBNET_MASK].len && -	    (lease -> options [DHO_SUBNET_MASK].len < -	     sizeof lease -> address.iabuf)) { -		struct iaddr netmask, subnet, broadcast; - -		memcpy (netmask.iabuf, -			lease -> options [DHO_SUBNET_MASK].data, -			lease -> options [DHO_SUBNET_MASK].len); -		netmask.len = lease -> options [DHO_SUBNET_MASK].len; - -		subnet = subnet_number (lease -> address, netmask); -		if (subnet.len) { -			fprintf (scriptFile, "%snetwork_number=\"%s\";\n", -				 prefix, piaddr (subnet)); -			fprintf (scriptFile, "export %snetwork_number\n", -				 prefix); - -			if (!lease -> options [DHO_BROADCAST_ADDRESS].len) { -				broadcast = broadcast_addr (subnet, netmask); -				if (broadcast.len) { -					fprintf (scriptFile, -						 "%s%s=\"%s\";\n", prefix, -						 "broadcast_address", -						 piaddr (broadcast)); -					fprintf (scriptFile, -						 "export %s%s\n", prefix, -						 "broadcast_address"); -				} -			} -		} -	} - -	if (lease -> filename) { -		fprintf (scriptFile, "%sfilename=\"%s\";\n", -			 prefix, lease -> filename); -		fprintf (scriptFile, "export %sfilename\n", prefix); -	} -	if (lease -> server_name) { -		fprintf (scriptFile, "%sserver_name=\"%s\";\n", -			 prefix, lease -> server_name); -		fprintf (scriptFile, "export %sserver_name\n", prefix); -	} -	for (i = 0; i < 256; i++) { -		u_int8_t *dp; - -		if (ip -> client -> config -> defaults [i].len) { -			if (lease -> options [i].len) { -				switch (ip -> client -> -					config -> default_actions [i]) { -				      case ACTION_DEFAULT: -					dp = lease -> options [i].data; -					len = lease -> options [i].len; -					break; -				      case ACTION_SUPERSEDE: -				      supersede: -					dp = ip -> client -> -						config -> defaults [i].data; -					len = ip -> client -> -						config -> defaults [i].len; -					break; -				      case ACTION_PREPEND: -					len = (ip -> client -> -					       config -> defaults [i].len + -					       lease -> options [i].len); -					if (len > sizeof dbuf) { -						warn ("no space to %s %s", -						      "prepend option", -						      dhcp_options [i].name); -						goto supersede; -					} -					dp = dbuf; -					memcpy (dp, -						ip -> client ->  -						config -> defaults [i].data, -						ip -> client ->  -						config -> defaults [i].len); -					memcpy (dp + ip -> client ->  -						config -> defaults [i].len, -						lease -> options [i].data, -						lease -> options [i].len); -					break; -				      case ACTION_APPEND: -					len = (ip -> client -> -					       config -> defaults [i].len + -					       lease -> options [i].len); -					if (len > sizeof dbuf) { -						warn ("no space to %s %s", -						      "prepend option", -						      dhcp_options [i].name); -						goto supersede; -					} -					dp = dbuf; -					memcpy (dp, -						ip -> client ->  -						config -> defaults [i].data, -						ip -> client ->  -						config -> defaults [i].len); -					memcpy (dp + ip -> client ->  -						config -> defaults [i].len, -						lease -> options [i].data, -						lease -> options [i].len); -				} -			} else { -				dp = ip -> client -> -					config -> defaults [i].data; -				len = ip -> client -> -					config -> defaults [i].len; -			} -		} else if (lease -> options [i].len) { -			len = lease -> options [i].len; -			dp = lease -> options [i].data; -		} else { -			len = 0; -		} -		if (len) { -			char *s = dhcp_option_ev_name (&dhcp_options [i]); -				 -			fprintf (scriptFile, "%s%s=\"%s\"\n", prefix, s, -				 pretty_print_option (i, dp, len, 0, 0)); -			fprintf (scriptFile, "export %s%s\n", prefix, s); -		} -	} -	fprintf (scriptFile, "%sexpiry=\"%d\"\n", -		 prefix, (int)lease -> expiry); /* XXX */ -	fprintf (scriptFile, "export %sexpiry\n", prefix); -} - -int script_go (ip) -	struct interface_info *ip; -{ -	int rval; - -	if (ip) -		fprintf (scriptFile, "%s\n", -			 ip -> client -> config -> script_name); -	else -		fprintf (scriptFile, "%s\n", -			 top_level_config.script_name); -	fprintf (scriptFile, "exit $?\n"); -	fclose (scriptFile); -	chmod (scriptName, 0700); -	rval = system (scriptName);	 -	if (!save_scripts) -		unlink (scriptName); -	return rval; -} - -char *dhcp_option_ev_name (option) -	struct option *option; -{ -	static char evbuf [256]; -	int i; - -	if (strlen (option -> name) + 1 > sizeof evbuf) -		error ("option %s name is larger than static buffer."); -	for (i = 0; option -> name [i]; i++) { -		if (option -> name [i] == '-') -			evbuf [i] = '_'; -		else -			evbuf [i] = option -> name [i]; -	} - -	evbuf [i] = 0; -	return evbuf; -} - -void go_daemon () -{ -	static int state = 0; -	int pid; - -	/* Don't become a daemon if the user requested otherwise. */ -	if (no_daemon) { -		write_client_pid_file (); -		return; -	} - -	/* Only do it once. */ -	if (state) -		return; -	state = 1; - -	/* Stop logging to stderr... */ -	log_perror = 0; - -	/* Become a daemon... */ -	if ((pid = fork ()) < 0) -		error ("Can't fork daemon: %m"); -	else if (pid) -		exit (0); -	/* Become session leader and get pid... */ -	pid = setsid (); - -	write_client_pid_file (); -} - -void write_client_pid_file () -{ -	FILE *pf; -	int pfdesc; - -	pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644); - -	if (pfdesc < 0) { -		warn ("Can't create %s: %m", path_dhclient_pid); -		return; -	} - -	pf = fdopen (pfdesc, "w"); -	if (!pf) -		warn ("Can't fdopen %s: %m", path_dhclient_pid); -	else { -		fprintf (pf, "%ld\n", (long)getpid ()); -		fclose (pf); -	} -} | 
