diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c
index 11963496..5ebcd9d 100644
--- a/sbin/dhclient/clparse.c
+++ b/sbin/dhclient/clparse.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: clparse.c,v 1.34 2007/02/14 23:19:26 deraadt Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/clparse.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/clparse.c,v 1.38 2011/12/10 17:15:27 krw Exp $	*/
 
 /* Parser for dhclient config and lease files... */
 
@@ -54,7 +53,6 @@ int
 read_client_conf(void)
 {
 	FILE *cfile;
-	char *val;
 	int token;
 
 	new_parse(path_dhclient_conf);
@@ -86,12 +84,12 @@ read_client_conf(void)
 
 	if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
 		do {
-			token = peek_token(&val, cfile);
+			token = peek_token(NULL, cfile);
 			if (token == EOF)
 				break;
 			parse_client_statement(cfile);
 		} while (1);
-		token = next_token(&val, cfile); /* Clear the peek buffer */
+		token = next_token(NULL, cfile); /* Clear the peek buffer */
 		fclose(cfile);
 	}
 
@@ -107,7 +105,6 @@ void
 read_client_leases(void)
 {
 	FILE	*cfile;
-	char	*val;
 	int	 token;
 
 	new_parse(path_dhclient_db);
@@ -117,7 +114,7 @@ read_client_leases(void)
 	if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
 		return;
 	do {
-		token = next_token(&val, cfile);
+		token = next_token(NULL, cfile);
 		if (token == EOF)
 			break;
 		if (token != TOK_LEASE) {
@@ -157,10 +154,9 @@ read_client_leases(void)
 void
 parse_client_statement(FILE *cfile)
 {
-	char *val;
 	int token, code;
 
-	switch (next_token(&val, cfile)) {
+	switch (next_token(NULL, cfile)) {
 	case TOK_SEND:
 		parse_option_decl(cfile, &config->send_options[0]);
 		return;
@@ -185,7 +181,7 @@ parse_client_statement(FILE *cfile)
 			config->default_actions[code] = ACTION_PREPEND;
 		return;
 	case TOK_MEDIA:
-		parse_string_list(cfile, &config->media, 1);
+		skip_to_semi(cfile);
 		return;
 	case TOK_HARDWARE:
 		parse_hardware_param(cfile, &ifi->hw_address);
@@ -230,7 +226,7 @@ parse_client_statement(FILE *cfile)
 		parse_client_lease_statement(cfile, 1);
 		return;
 	case TOK_ALIAS:
-		parse_client_lease_statement(cfile, 2);
+		skip_to_semi(cfile);
 		return;
 	case TOK_REJECT:
 		parse_reject_statement(cfile);
@@ -240,7 +236,7 @@ parse_client_statement(FILE *cfile)
 		skip_to_semi(cfile);
 		break;
 	}
-	token = next_token(&val, cfile);
+	token = next_token(NULL, cfile);
 	if (token != ';') {
 		parse_warn("semicolon expected.");
 		skip_to_semi(cfile);
@@ -392,9 +388,8 @@ parse_client_lease_statement(FILE *cfile, int is_static)
 {
 	struct client_lease	*lease, *lp, *pl;
 	int			 token;
-	char			*val;
 
-	token = next_token(&val, cfile);
+	token = next_token(NULL, cfile);
 	if (token != '{') {
 		parse_warn("expecting left brace.");
 		skip_to_semi(cfile);
@@ -408,7 +403,7 @@ parse_client_lease_statement(FILE *cfile, int is_static)
 	lease->is_static = is_static;
 
 	do {
-		token = peek_token(&val, cfile);
+		token = peek_token(NULL, cfile);
 		if (token == EOF) {
 			parse_warn("unterminated lease declaration.");
 			return;
@@ -417,7 +412,7 @@ parse_client_lease_statement(FILE *cfile, int is_static)
 			break;
 		parse_client_lease_declaration(cfile, lease);
 	} while (1);
-	token = next_token(&val, cfile);
+	token = next_token(NULL, cfile);
 
 	/* If the lease declaration didn't include an interface
 	 * declaration that we recognized, it's of no use to us.
@@ -427,12 +422,6 @@ parse_client_lease_statement(FILE *cfile, int is_static)
 		return;
 	}
 
-	/* If this is an alias lease, it doesn't need to be sorted in. */
-	if (is_static == 2) {
-		client->alias = lease;
-		return;
-	}
-
 	/*
 	 * The new lease may supersede a lease that's not the active
 	 * lease but is still on the lease list, so scan the lease list
@@ -441,16 +430,15 @@ parse_client_lease_statement(FILE *cfile, int is_static)
 	 */
 	pl = NULL;
 	for (lp = client->leases; lp; lp = lp->next) {
-		if (lp->address.len == lease->address.len &&
-		    !memcmp(lp->address.iabuf, lease->address.iabuf,
-		    lease->address.len)) {
+		if (addr_eq(lp->address, lease->address)) {
 			if (pl)
 				pl->next = lp->next;
 			else
 				client->leases = lp->next;
 			free_client_lease(lp);
 			break;
-		}
+		} else
+			pl = lp;
 	}
 
 	/*
@@ -480,10 +468,7 @@ parse_client_lease_statement(FILE *cfile, int is_static)
 	if (client->active) {
 		if (client->active->expiry < cur_time)
 			free_client_lease(client->active);
-		else if (client->active->address.len ==
-		    lease->address.len &&
-		    !memcmp(client->active->address.iabuf,
-		    lease->address.iabuf, lease->address.len))
+		else if (addr_eq(client->active->address, lease->address))
 			free_client_lease(client->active);
 		else {
 			client->active->next = client->leases;
@@ -536,7 +521,7 @@ parse_client_lease_declaration(FILE *cfile, struct client_lease *lease)
 			return;
 		break;
 	case TOK_MEDIUM:
-		parse_string_list(cfile, &lease->medium, 0);
+		skip_to_semi(cfile);
 		return;
 	case TOK_FILENAME:
 		lease->filename = parse_string(cfile);
@@ -725,55 +710,10 @@ bad_flag:
 }
 
 void
-parse_string_list(FILE *cfile, struct string_list **lp, int multiple)
-{
-	int			 token;
-	char			*val;
-	struct string_list	*cur, *tmp;
-
-	/* Find the last medium in the media list. */
-	if (*lp)
-		for (cur = *lp; cur->next; cur = cur->next)
-			;	/* nothing */
-	else
-		cur = NULL;
-
-	do {
-		token = next_token(&val, cfile);
-		if (token != TOK_STRING) {
-			parse_warn("Expecting media options.");
-			skip_to_semi(cfile);
-			return;
-		}
-
-		tmp = malloc(sizeof(struct string_list) + strlen(val));
-		if (tmp == NULL)
-			error("no memory for string list entry.");
-		strlcpy(tmp->string, val, strlen(val) + 1);
-		tmp->next = NULL;
-
-		/* Store this medium at the end of the media list. */
-		if (cur)
-			cur->next = tmp;
-		else
-			*lp = tmp;
-		cur = tmp;
-
-		token = next_token(&val, cfile);
-	} while (multiple && token == ',');
-
-	if (token != ';') {
-		parse_warn("expecting semicolon.");
-		skip_to_semi(cfile);
-	}
-}
-
-void
 parse_reject_statement(FILE *cfile)
 {
 	struct iaddrlist *list;
 	struct iaddr addr;
-	char *val;
 	int token;
 
 	do {
@@ -791,7 +731,7 @@ parse_reject_statement(FILE *cfile)
 		list->next = config->reject_list;
 		config->reject_list = list;
 
-		token = next_token(&val, cfile);
+		token = next_token(NULL, cfile);
 	} while (token == ',');
 
 	if (token != ';') {
diff --git a/sbin/dhclient/conflex.c b/sbin/dhclient/conflex.c
index a4698e1..fc988e3 100644
--- a/sbin/dhclient/conflex.c
+++ b/sbin/dhclient/conflex.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: conflex.c,v 1.13 2006/12/17 17:41:56 stevesk Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/conflex.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/conflex.c,v 1.14 2011/12/10 17:36:40 krw Exp $	*/
 
 /* Lexical scanner for dhclient config file... */
 
@@ -76,12 +75,25 @@ static int intern(char *, int);
 void
 new_parse(char *name)
 {
-	tlname = name;
+	/*
+	 * Initialize all parsing state, as we are starting to parse a
+	 * new file, 'name'.
+	 */
+
+	bzero(line1, sizeof(line1));
+	bzero(line2, sizeof(line2));
+	bzero(tokbuf, sizeof(tokbuf));
+
 	lpos = line = 1;
+	tlpos = tline = token = ugflag = 0;
+	tval = NULL;
+
+	lexline = lexchar = 0;
 	cur_line = line1;
 	prev_line = line2;
 	token_line = cur_line;
-	cur_line[0] = prev_line[0] = 0;
+	tlname = name;
+
 	warnings_occurred = 0;
 }
 
diff --git a/sbin/dhclient/dhclient-script b/sbin/dhclient/dhclient-script
index dde2f84..433deee 100644
--- a/sbin/dhclient/dhclient-script
+++ b/sbin/dhclient/dhclient-script
@@ -1,7 +1,6 @@
 #!/bin/sh
 #
-# $OpenBSD: dhclient-script,v 1.12 2007/08/11 17:58:55 krw Exp $
-# $DragonFly: src/sbin/dhclient/dhclient-script,v 1.1 2008/08/30 16:07:58 hasso Exp $
+# $OpenBSD: src/sbin/dhclient/dhclient-script,v 1.22 2011/04/09 19:53:00 krw Exp $
 #
 # Copyright (c) 2003 Kenneth R Westerback <krw@openbsd.org>
 #
@@ -25,7 +24,7 @@
 
 delete_old_address() {
 	if [ -n "$old_ip_address" ]; then
-		ifconfig $interface inet $old_ip_address delete $medium
+		ifconfig $interface inet $old_ip_address delete
 		#route delete "$old_ip_address" 127.0.0.1 >/dev/null 2>&1
 	fi
 }
@@ -34,37 +33,13 @@ add_new_address() {
 	ifconfig $interface \
 		inet $new_ip_address \
 		netmask $new_subnet_mask \
-		broadcast $new_broadcast_address \
-		$medium
+		broadcast $new_broadcast_address
 
 	# XXX Original TIMEOUT code did not do this unless $new_routers was set?
 	#route add $new_ip_address 127.0.0.1 >/dev/null 2>&1
 }
 
-delete_old_alias() {
-	if [ -n "$alias_ip_address" ]; then
-		ifconfig $interface inet $alias_ip_address delete > /dev/null 2>&1
-#		#route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1
-	fi
-}
-
-add_new_alias() {
-	if [ -n "$alias_ip_address" ]; then
-		ifconfig $interface inet $alias_ip_address alias netmask \
-		    $alias_subnet_mask
-		#route add $alias_ip_address 127.0.0.1
-	fi
-}
-
 delete_old_routes() {
-	if [ -n "$old_static_routes" ]; then
-		set $old_static_routes
-		while [ $# -gt 1 ]; do
-			route delete "$1" "$2"
-			shift; shift
-		done
-	fi
-
 	arp -dan
 }
 
@@ -80,22 +55,12 @@ add_new_routes() {
 		# stop processing the list after the first one.
 		break
 	done
-
-	if [ -n "$new_static_routes" ]; then
-		set $new_static_routes
-		while [ $# -gt 1 ]; do
-			route add $1 $2
-			shift; shift
-		done
-	fi
 }
 
 add_new_resolv_conf() {
-	# XXX Old code did not create/update resolv.conf unless both
-	# $new_domain_name and $new_domain_name_servers were provided.  PR
-	# #3135 reported some ISPs only provide $new_domain_name_servers and
-	# thus broke the script. This code creates the resolv.conf if either
-	# are provided.
+	# Create resolv.conf when either $new_domain_name_servers or
+	# $new_domain_name are provided. As reported in PR#3135, some ISPs
+	# provide only $new_domain_name_servers.
 
 	rm -f /etc/resolv.conf.std
 
@@ -140,23 +105,25 @@ add_new_resolv_conf() {
 
 case $reason in
 MEDIUM)
-	ifconfig $interface $medium
-	sleep 1
+	# Not called by OpenBSD dhclient(8).
 	;;
 
 PREINIT)
-	delete_old_alias
-	ifconfig $interface up
+	# Not called by OpenBSD dhclient(8).
 	;;
 
-ARPCHECK|ARPSEND)
+ARPSEND)
+	# Not called by OpenBSD dhclient(8).
+	exit 1
+	;;
+
+ARPCHECK)
+	# Not called by OpenBSD dhclient(8).
+	# Always succeed. i.e. accept lease.
 	;;
 
 BOUND|RENEW|REBIND|REBOOT)
 	if [ -n "$old_ip_address" ]; then
-		if [ "$old_ip_address" != "$alias_ip_address" ]; then
-			delete_old_alias
-		fi
 		if [ "$old_ip_address" != "$new_ip_address" ]; then
 			delete_old_address
 			delete_old_routes
@@ -169,42 +136,32 @@ BOUND|RENEW|REBIND|REBOOT)
 		add_new_address
 		add_new_routes
 	fi
-	if [ "$new_ip_address" != "$alias_ip_address" ]; then
-		add_new_alias
-	fi
 	add_new_resolv_conf
 	;;
 
 EXPIRE|FAIL)
-	delete_old_alias
 	if [ -n "$old_ip_address" ]; then
 		delete_old_address
 		delete_old_routes
 	fi
-	# XXX Why add alias we just deleted above?
-	add_new_alias
 	if [ -f /etc/resolv.conf.save ]; then
 		cat /etc/resolv.conf.save > /etc/resolv.conf
 	fi
 	;;
 
 TIMEOUT)
-	delete_old_alias
 	add_new_address
 	sleep 1
 	if [ -n "$new_routers" ]; then
 		set "$new_routers"
 		if ping -q -c 1 -w 1 "$1"; then
-			if [ "$new_ip_address" != "$alias_ip_address" ]; then
-				add_new_alias
-			fi
 			add_new_routes
 			if add_new_resolv_conf; then
 				exit 0
 			fi
 		fi
 	fi
-	ifconfig $interface inet $new_ip_address delete $medium
+	ifconfig $interface inet $new_ip_address delete
 	# XXX Why not a delete_old_address as before all other invocations of
 	#     delete_old_routes?
 	delete_old_routes
diff --git a/sbin/dhclient/dhclient-script.8 b/sbin/dhclient/dhclient-script.8
index 392d6c7..8932ead 100644
--- a/sbin/dhclient/dhclient-script.8
+++ b/sbin/dhclient/dhclient-script.8
@@ -1,5 +1,4 @@
-.\"	$OpenBSD: dhclient-script.8,v 1.5 2007/05/31 19:19:43 jmc Exp $
-.\"	$DragonFly: src/sbin/dhclient/dhclient-script.8,v 1.3 2008/09/01 10:48:29 swildner Exp $
+.\" $OpenBSD: src/sbin/dhclient/dhclient-script.8,v 1.6 2011/04/04 11:43:20 krw Exp $
 .\"
 .\" Copyright (c) 1997 The Internet Software Consortium.
 .\" All rights reserved.
@@ -37,7 +36,7 @@
 .\" see ``http://www.isc.org/isc''.  To learn more about Vixie
 .\" Enterprises, see ``http://www.vix.com''.
 .\"
-.Dd August 30, 2008
+.Dd August 4, 2012
 .Dt DHCLIENT-SCRIPT 8
 .Os
 .Sh NAME
@@ -47,12 +46,6 @@
 The DHCP client network configuration script is invoked from time to
 time by
 .Xr dhclient 8 .
-This script is used by the DHCP client to set each interface's initial
-configuration prior to requesting an address, to test the address once it
-has been offered, and to set the interface's final configuration once a
-lease has been acquired.
-If no lease is acquired, the script is used to test predefined leases, if
-any, and also called once if no valid lease can be identified.
 .Pp
 .\" No standard client script exists for some operating systems, even though
 .\" the actual client may work, so a pioneering user may well need to create
@@ -71,60 +64,14 @@ In all cases,
 .Va $reason
 is set to the name of the reason why the script has been invoked.
 The following reasons are currently defined:
-MEDIUM, PREINIT, ARPCHECK, ARPSEND, BOUND, RENEW, REBIND, REBOOT,
-EXPIRE, FAIL and TIMEOUT.
+BOUND, RENEW, REBIND, REBOOT, EXPIRE, FAIL and TIMEOUT.
 .Bl -tag -width "ARPCHECK"
-.It MEDIUM
-The DHCP client is requesting that an interface's media type be set.
-The interface name is passed in
-.Va $interface ,
-and the media type is passed in
-.Va $medium .
-.It PREINIT
-The DHCP client is requesting that an interface be configured as
-required in order to send packets prior to receiving an actual address.
-.\" For clients which use the BSD socket library,
-This means configuring the interface with an IP address of 0.0.0.0
-and a broadcast address of 255.255.255.255.
-.\" For other clients, it may be possible to simply configure the interface up
-.\" without actually giving it an IP address at all.
-The interface name is passed in
-.Va $interface ,
-and the media type in
-.Va $medium .
-.Pp
-If an IP alias has been declared in
-.Xr dhclient.conf 5 ,
-its address will be passed in
-.Va $alias_ip_address ,
-and that IP alias should be deleted from the interface,
-along with any routes to it.
-.It ARPSEND
-The DHCP client is requesting that an address that has been offered to
-it be checked to see if somebody else is using it, by sending an ARP
-request for that address.
-It's not clear how to implement this, so no examples exist yet.
-The IP address to check is passed in
-.Va $new_ip_address ,
-and the interface name is passed in
-.Va $interface .
-.It ARPCHECK
-The DHCP client wants to know if a response to the ARP request sent
-using ARPSEND has been received.
-If one has, the script should exit with a nonzero status, indicating that
-the offered address has already been requested and should be declined.
-.Va $new_ip_address
-and
-.Va $interface
-are set as with ARPSEND.
 .It BOUND
 The DHCP client has done an initial binding to a new address.
 The new IP address is passed in
 .Va $new_ip_address ,
 and the interface name is passed in
 .Va $interface .
-The media type is passed in
-.Va $medium .
 Any options acquired from the server are passed using the option name
 described in
 .Xr dhcp-options 5 ,
@@ -166,16 +113,6 @@ by
 .\".Xr resolv.conf.tail 5
 .\"for further information.
 .Pp
-If an IP alias has been declared, it must be set up here.
-The alias IP address will be written as
-.Va $alias_ip_address ,
-and other DHCP options that are set for the alias (e.g., subnet mask)
-will be passed in variables named as described previously except starting with
-$alias_ instead of $new_.
-Care should be taken that the alias IP address not be used if it is identical
-to the bound IP address
-.Pq Va $new_ip_address ,
-since the other alias parameters may be incorrect in this case.
 .It RENEW
 When a binding has been renewed, the script is called as in BOUND,
 except that in addition to all the variables starting with $new_,
diff --git a/sbin/dhclient/dhclient.8 b/sbin/dhclient/dhclient.8
index 0662998..674e847 100644
--- a/sbin/dhclient/dhclient.8
+++ b/sbin/dhclient/dhclient.8
@@ -1,5 +1,4 @@
-.\" $OpenBSD: dhclient.8,v 1.6 2007/05/31 19:19:43 jmc Exp $
-.\" $DragonFly: src/sbin/dhclient/dhclient.8,v 1.3 2008/09/03 08:02:34 matthias Exp $
+.\" $OpenBSD: src/sbin/dhclient/dhclient.8,v 1.8 2011/03/02 07:44:42 jmc Exp $
 .\"
 .\" Copyright (c) 1997 The Internet Software Consortium.
 .\" All rights reserved.
@@ -148,12 +147,11 @@ In that case, it may be advantageous to
 arrange with the network administrator for an entry on the BOOTP
 database, so that the host can boot quickly on that network rather
 than cycling through the list of old leases.
-.Sh NOTES
-You must have the Berkeley Packet Filter (BPF) configured in your kernel.
+.Pp
 .Nm
 requires at least one
 .Pa /dev/bpf*
-file for each broadcast network interface that is attached to your system.
+file for each broadcast network interface.
 See
 .Xr bpf 4
 for more information.
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index 293f424..159e956 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: src/sbin/dhclient/dhclient.c,v 1.119 2008/05/26 03:11:48 deraadt Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/dhclient.c,v 1.146 2012/07/09 16:21:21 krw Exp $	*/
 
 /*
  * Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -52,6 +52,7 @@
  * the shell script can invoke the native tools to accomplish the same
  * purpose.
  */
+#include <sys/ioctl.h>
 
 #include <ctype.h>
 #include <poll.h>
@@ -95,7 +96,7 @@ int		 ipv4addrs(char * buf);
 int		 res_hnok(const char *dn);
 char		*option_as_string(unsigned int code, unsigned char *data, int len);
 int		 fork_privchld(int, int);
-
+void		 get_ifname(char *, char *);
 #define	ROUNDUP(a) \
 	    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
 #define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
@@ -153,7 +154,6 @@ get_ifa(char *cp, int n)
 }
 struct iaddr defaddr = { .len = 4 }; /* NULL is for silence warnings */
 
-/* ARGSUSED */
 void
 routehandler(void)
 {
@@ -168,6 +168,7 @@ routehandler(void)
 	struct sockaddr *sa;
 	struct iaddr a;
 	ssize_t n;
+	char *errmsg, buf[64];
 
 	do {
 		n = read(routefd, &msg, sizeof(msg));
@@ -186,8 +187,10 @@ routehandler(void)
 		if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
 			break;
 		sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
-		if (sa == NULL)
+		if (sa == NULL) {
+			errmsg = "sa == NULL";
 			goto die;
+		}
 
 		if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
 			error("king bula sez: len mismatch");
@@ -195,15 +198,19 @@ routehandler(void)
 		if (addr_eq(a, defaddr))
 			break;
 
-		for (l = client->active; l != NULL; l = l->next)
+		/* state_panic() can try unexpired existing leases */
+		if (client->active && addr_eq(a, client->active->address))
+			break;
+		for (l = client->leases; l != NULL; l = l->next)
 			if (addr_eq(a, l->address))
 				break;
 
-		if (l != NULL || (client->alias &&
-		    addr_eq(a, client->alias->address)))
+		if (l != NULL)
 			/* new addr is the one we set */
 			break;
-
+		snprintf(buf, sizeof(buf), "%s: %s",
+		    "new address not one we set", piaddr(a));
+		errmsg = buf;
 		goto die;
 	case RTM_DELADDR:
 		ifam = (struct ifa_msghdr *)rtm;
@@ -211,25 +218,31 @@ routehandler(void)
 			break;
 		if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
 			break;
+		/* XXX check addrs like RTM_NEWADDR instead of this? */
 		if (scripttime == 0 || t < scripttime + 10)
 			break;
+		errmsg = "interface address deleted";
 		goto die;
 	case RTM_IFINFO:
 		ifm = (struct if_msghdr *)rtm;
 		if (ifm->ifm_index != ifi->index)
 			break;
-		if ((rtm->rtm_flags & RTF_UP) == 0)
+		if ((rtm->rtm_flags & RTF_UP) == 0) {
+			errmsg = "interface down";
 			goto die;
+		}
 
 		linkstat =
 		    LINK_STATE_IS_UP(ifm->ifm_data.ifi_link_state) ? 1 : 0;
 		if (linkstat != ifi->linkstat) {
+#ifdef DEBUG
 			debug("link state %s -> %s",
 			    ifi->linkstat ? "up" : "down",
 			    linkstat ? "up" : "down");
-			ifi->linkstat = interface_link_status(ifi->name);
+#endif
+			ifi->linkstat = interface_status(ifi->name);
 			if (ifi->linkstat) {
-				client->state = S_INIT;
+				client->state = S_REBOOTING;
 				state_reboot();
 			}
 		}
@@ -237,8 +250,10 @@ routehandler(void)
 	case RTM_IFANNOUNCE:
 		ifan = (struct if_announcemsghdr *)rtm;
 		if (ifan->ifan_what == IFAN_DEPARTURE &&
-		    ifan->ifan_index == ifi->index)
+		    ifan->ifan_index == ifi->index) {
+			errmsg = "interface departure";
 			goto die;
+		}
 		break;
 	default:
 		break;
@@ -246,11 +261,9 @@ routehandler(void)
 	return;
 
 die:
-	script_init("FAIL", NULL);
-	if (client->alias)
-		script_write_params("alias_", client->alias);
+	script_init("FAIL");
 	script_go();
-	exit(1);
+	error("routehandler: %s", errmsg);
 }
 
 int
@@ -300,8 +313,7 @@ main(int argc, char *argv[])
 	if (config == NULL)
 		error("config calloc");
 
-	if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
-		error("Interface name too long");
+	get_ifname(ifi->name, argv[0]);
 	if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
 	    _PATH_DHCLIENT_DB, ifi->name) == -1)
 		error("asprintf");
@@ -328,7 +340,7 @@ main(int argc, char *argv[])
 	} else
 		i = 0;
 
-	while (!(ifi->linkstat = interface_link_status(ifi->name))) {
+	while (!(ifi->linkstat = interface_status(ifi->name))) {
 		if (i == 0)
 			fprintf(stderr, "%s: no link ...", ifi->name);
 		else if (i > 0)
@@ -340,18 +352,15 @@ main(int argc, char *argv[])
 		}
 		sleep(1);
 	}
-	if (i >= 0)
+	if (i > 0)
 		fprintf(stderr, " got link\n");
 
  dispatch:
 	if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
 		error("cannot open %s: %m", _PATH_DEVNULL);
 
-	if ((pw = getpwnam("_dhcp")) == NULL) {
-		warning("no such user: _dhcp, falling back to \"nobody\"");
-		if ((pw = getpwnam("nobody")) == NULL)
-			error("no such user: nobody");
-	}
+	if ((pw = getpwnam("_dhcp")) == NULL)
+		error("no such user: _dhcp");
 
 	if (pipe(pipe_fd) == -1)
 		error("pipe");
@@ -369,11 +378,6 @@ main(int argc, char *argv[])
 	rewrite_client_leases();
 	close(fd);
 
-	priv_script_init("PREINIT", NULL);
-	if (client->alias)
-		priv_script_write_params("alias_", client->alias);
-	priv_script_go();
-
 	if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
 		error("socket(PF_ROUTE, SOCK_RAW): %m");
 
@@ -397,7 +401,7 @@ main(int argc, char *argv[])
 	setproctitle("%s", ifi->name);
 
 	if (ifi->linkstat) {
-		client->state = S_INIT;
+		client->state = S_REBOOTING;
 		state_reboot();
 	} else
 		go_daemon();
@@ -448,15 +452,17 @@ usage(void)
 void
 state_reboot(void)
 {
+	/* Cancel all timeouts, since a link state change gets us here
+	   and can happen anytime. */
+	cancel_timeout();
+
 	/* If we don't remember an active lease, go straight to INIT. */
 	if (!client->active || client->active->is_bootp) {
+		client->state = S_INIT;
 		state_init();
 		return;
 	}
 
-	/* We are in the rebooting state. */
-	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. */
@@ -467,10 +473,7 @@ state_reboot(void)
 	make_request(client->active);
 	client->destination = iaddr_broadcast;
 	client->first_sending = cur_time;
-	client->interval = config->initial_interval;
-
-	/* Zap the medium list... */
-	client->medium = NULL;
+	client->interval = 0;
 
 	/* Send out the first DHCPREQUEST packet. */
 	send_request();
@@ -490,7 +493,7 @@ state_init(void)
 	client->destination = iaddr_broadcast;
 	client->state = S_SELECTING;
 	client->first_sending = cur_time;
-	client->interval = config->initial_interval;
+	client->interval = 0;
 
 	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
 	   to go out. */
@@ -508,8 +511,7 @@ state_selecting(void)
 
 	/* Cancel state_selecting and send_discover timeouts, since either
 	   one could have got us here. */
-	cancel_timeout(state_selecting);
-	cancel_timeout(send_discover);
+	cancel_timeout();
 
 	/* We have received one or more DHCPOFFER packets.   Currently,
 	   the only criterion by which we judge leases is whether or
@@ -518,25 +520,11 @@ state_selecting(void)
 	for (lp = 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("ARPCHECK", lp->medium);
-			script_write_params("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()) {
-				make_decline(lp);
-				send_decline();
-				goto freeit;
-			}
 			picked = lp;
-			picked->next = NULL;
 		} else {
-freeit:
+			make_decline(lp);
+			send_decline();
 			free_client_lease(lp);
 		}
 	}
@@ -549,6 +537,7 @@ freeit:
 		state_init();
 		return;
 	}
+	picked->next = NULL;
 
 	/* If it was a BOOTREPLY, we can just take the address right now. */
 	if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
@@ -571,7 +560,7 @@ freeit:
 	client->destination = iaddr_broadcast;
 	client->state = S_REQUESTING;
 	client->first_sending = cur_time;
-	client->interval = config->initial_interval;
+	client->interval = 0;
 
 	/* Make a DHCPREQUEST packet from the lease we picked. */
 	make_request(picked);
@@ -589,8 +578,6 @@ dhcpack(struct iaddr client_addr, struct option_data *options)
 {
 	struct client_lease *lease;
 
-	if (client->xid != client->packet.xid)
-		return;
 
 	if (client->state != S_REBOOTING &&
 	    client->state != S_REQUESTING &&
@@ -598,7 +585,6 @@ dhcpack(struct iaddr client_addr, struct option_data *options)
 	    client->state != S_REBINDING)
 		return;
 
-	note("DHCPACK from %s", piaddr(client_addr));
 
 	lease = packet_to_lease(options);
 	if (!lease) {
@@ -609,7 +595,7 @@ dhcpack(struct iaddr client_addr, struct option_data *options)
 	client->new = lease;
 
 	/* Stop resending DHCPREQUEST. */
-	cancel_timeout(send_request);
+	cancel_timeout();
 
 	/* Figure out the lease time. */
 	if (client->new->options[DHO_DHCP_LEASE_TIME].data)
@@ -658,22 +644,13 @@ dhcpack(struct iaddr client_addr, struct option_data *options)
 void
 bind_lease(void)
 {
-	/* Remember the medium. */
-	client->new->medium = client->medium;
-
-	/* Write out the new lease. */
-	write_client_lease(client->new, 0);
-
 	/* Run the client script with the new parameters. */
 	script_init((client->state == S_REQUESTING ? "BOUND" :
 	    (client->state == S_RENEWING ? "RENEW" :
-	    (client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
-	    client->new->medium);
+		(client->state == S_REBOOTING ? "REBOOT" : "REBIND"))));
 	if (client->active && client->state != S_REBOOTING)
 		script_write_params("old_", client->active);
 	script_write_params("new_", client->new);
-	if (client->alias)
-		script_write_params("alias_", client->alias);
 	script_go();
 
 	/* Replace the old active lease with the new one. */
@@ -682,8 +659,11 @@ bind_lease(void)
 	client->active = client->new;
 	client->new = NULL;
 
-	/* Set up a timeout to start the renewal process. */
-	add_timeout(client->active->renewal, state_bound);
+	/* Write out new leases file. */
+	rewrite_client_leases();
+
+	/* Set timeout to start the renewal process. */
+	set_timeout(client->active->renewal, state_bound);
 
 	note("bound to %s -- renewal in %ld seconds.",
 	    piaddr(client->active->address),
@@ -715,7 +695,7 @@ state_bound(void)
 		client->destination = iaddr_broadcast;
 
 	client->first_sending = cur_time;
-	client->interval = config->initial_interval;
+	client->interval = 0;
 	client->state = S_RENEWING;
 
 	/* Send the first packet immediately. */
@@ -727,17 +707,14 @@ dhcpoffer(struct iaddr client_addr, struct option_data *options)
 {
 	struct client_lease *lease, *lp;
 	int i;
-	int arp_timeout_needed, stop_selecting;
+	int stop_selecting;
 	char *name = options[DHO_DHCP_MESSAGE_TYPE].len ? "DHCPOFFER" :
 	    "BOOTREPLY";
 
-	if (client->xid != client->packet.xid)
-		return;
 
 	if (client->state != S_SELECTING)
 		return;
 
-	note("%s from %s", name, piaddr(client_addr));
 
 	/* If this lease doesn't supply the minimum required parameters,
 	   blow it off. */
@@ -754,7 +731,9 @@ dhcpoffer(struct iaddr client_addr, struct option_data *options)
 		if (lease->address.len == sizeof(client->packet.yiaddr) &&
 		    !memcmp(lease->address.iabuf,
 		    &client->packet.yiaddr, lease->address.len)) {
+#ifdef DEBUG
 			debug("%s already seen.", name);
+#endif
 			return;
 		}
 	}
@@ -770,39 +749,15 @@ dhcpoffer(struct iaddr client_addr, struct option_data *options)
 	if (!options[DHO_DHCP_MESSAGE_TYPE].len)
 		lease->is_bootp = 1;
 
-	/* Record the medium under which this lease was offered. */
-	lease->medium = client->medium;
-
-	/* Send out an ARP Request for the offered IP address. */
-	script_init("ARPSEND", lease->medium);
-	script_write_params("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())
-		arp_timeout_needed = 0;
-	else
-		arp_timeout_needed = 2;
-
 	/* Figure out when we're supposed to stop selecting. */
 	stop_selecting = client->first_sending + 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 == client->requested_address.len &&
-	    !memcmp(lease->address.iabuf,
-	    client->requested_address.iabuf,
-	    client->requested_address.len)) {
+	if (addr_eq(lease->address, client->requested_address)) {
 		lease->next = client->offered_leases;
 		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 (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 = NULL;
 		if (!client->offered_leases)
@@ -815,20 +770,13 @@ dhcpoffer(struct iaddr client_addr, struct option_data *options)
 		}
 	}
 
-	/* 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)
+	if (stop_selecting <= cur_time)
 		state_selecting();
 	else {
-		add_timeout(stop_selecting, state_selecting);
-		cancel_timeout(send_discover);
+		set_timeout(stop_selecting, state_selecting);
 	}
 }
 
@@ -909,8 +857,6 @@ packet_to_lease(struct option_data *options)
 void
 dhcpnak(struct iaddr client_addr, struct option_data *options)
 {
-	if (client->xid != client->packet.xid)
-		return;
 
 	if (client->state != S_REBOOTING &&
 	    client->state != S_REQUESTING &&
@@ -918,7 +864,6 @@ dhcpnak(struct iaddr client_addr, struct option_data *options)
 	    client->state != S_REBINDING)
 		return;
 
-	note("DHCPNAK from %s", piaddr(client_addr));
 
 	if (!client->active) {
 		note("DHCPNAK with no active lease.");
@@ -929,7 +874,7 @@ dhcpnak(struct iaddr client_addr, struct option_data *options)
 	client->active = NULL;
 
 	/* Stop sending DHCPREQUEST packets... */
-	cancel_timeout(send_request);
+	cancel_timeout();
 
 	client->state = S_INIT;
 	state_init();
@@ -955,30 +900,6 @@ send_discover(void)
 		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 (!client->offered_leases && config->media) {
-		int fail = 0;
-again:
-		if (client->medium) {
-			client->medium = client->medium->next;
-			increase = 0;
-		}
-		if (!client->medium) {
-			if (fail)
-				error("No valid media types for %s!", ifi->name);
-			client->medium = config->media;
-			increase = 1;
-		}
-
-		note("Trying medium \"%s\" %d", client->medium->string,
-		    increase);
-		script_init("MEDIUM", client->medium);
-		if (script_go())
-			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
@@ -1023,7 +944,7 @@ again:
 	/* Send out a packet. */
 	send_packet(inaddr_any, &sockaddr_broadcast, NULL);
 
-	add_timeout(cur_time + client->interval, send_discover);
+	set_timeout(cur_time + client->interval, send_discover);
 }
 
 /*
@@ -1052,12 +973,8 @@ state_panic(void)
 			    piaddr(client->active->address));
 			/* Run the client script with the existing
 			   parameters. */
-			script_init("TIMEOUT",
-			    client->active->medium);
+			script_init("TIMEOUT");
 			script_write_params("new_", client->active);
-			if (client->alias)
-				script_write_params("alias_",
-				    client->alias);
 
 			/* If the old lease is still good and doesn't
 			   yet need renewal, go into BOUND state and
@@ -1069,7 +986,7 @@ state_panic(void)
 					note("bound: renewal in %ld seconds.",
 					    client->active->renewal -
 					    cur_time);
-					add_timeout(client->active->renewal,
+					set_timeout(client->active->renewal,
 					    state_bound);
 				} else {
 					client->state = S_BOUND;
@@ -1113,12 +1030,10 @@ activate_next:
 	   tell the shell script that we failed to allocate an address,
 	   and try again later. */
 	note("No working leases in persistent database - sleeping.");
-	script_init("FAIL", NULL);
-	if (client->alias)
-		script_write_params("alias_", client->alias);
+	script_init("FAIL");
 	script_go();
 	client->state = S_INIT;
-	add_timeout(cur_time + config->retry_interval, state_init);
+	set_timeout(cur_time + config->retry_interval, state_init);
 	go_daemon();
 }
 
@@ -1145,44 +1060,19 @@ send_request(void)
 	if ((client->state == S_REBOOTING ||
 	    client->state == S_REQUESTING) &&
 	    interval > config->reboot_timeout) {
-cancel:
 		client->state = S_INIT;
-		cancel_timeout(send_request);
+		cancel_timeout();
 		state_init();
 		return;
 	}
 
-	/* If we're in the reboot state, make sure the media is set up
-	   correctly. */
-	if (client->state == S_REBOOTING &&
-	    !client->medium &&
-	    client->active->medium) {
-		script_init("MEDIUM", client->active->medium);
-
-		/* If the medium we chose won't fly, go to INIT state. */
-		if (script_go())
-			goto cancel;
-
-		/* Record the medium. */
-		client->medium = client->active->medium;
-	}
-
 	/* If the lease has expired, relinquish the address and go back
 	   to the INIT state. */
 	if (client->state != S_REQUESTING &&
 	    cur_time > client->active->expiry) {
 		/* Run the client script with the new parameters. */
-		script_init("EXPIRE", NULL);
+		script_init("EXPIRE");
 		script_write_params("old_", client->active);
-		if (client->alias)
-			script_write_params("alias_", client->alias);
-		script_go();
-
-		/* Now do a preinit on the interface so that we can
-		   discover a new address. */
-		script_init("PREINIT", NULL);
-		if (client->alias)
-			script_write_params("alias_", client->alias);
 		script_go();
 
 		client->state = S_INIT;
@@ -1243,7 +1133,7 @@ cancel:
 	/* Send out a packet. */
 	send_packet(from, &destination, NULL);
 
-	add_timeout(cur_time + client->interval, send_request);
+	set_timeout(cur_time + client->interval, send_request);
 }
 
 void
@@ -1295,8 +1185,7 @@ make_discover(struct client_lease *lease)
 		}
 
 	/* Set up the option buffer to fit in a minimal UDP packet. */
-	i = cons_options(client->packet.options, 576 - DHCP_FIXED_LEN,
-	    options);
+	i = cons_options(options);
 	if (i == -1 || client->packet.options[i] != DHO_END)
 		error("options do not fit in DHCPDISCOVER packet.");
 	client->packet_length = DHCP_FIXED_NON_UDP+i+1;
@@ -1364,8 +1253,7 @@ make_request(struct client_lease * lease)
 		}
 
 	/* Set up the option buffer to fit in a minimal UDP packet. */
-	i = cons_options(client->packet.options, 576 - DHCP_FIXED_LEN,
-	    options);
+	i = cons_options(options);
 	if (i == -1 || client->packet.options[i] != DHO_END)
 		error("options do not fit in DHCPREQUEST packet.");
 	client->packet_length = DHCP_FIXED_NON_UDP+i+1;
@@ -1432,8 +1320,7 @@ make_decline(struct client_lease *lease)
 	}
 
 	/* Set up the option buffer to fit in a minimal UDP packet. */
-	i = cons_options(client->packet.options, 576 - DHCP_FIXED_LEN,
-	    options);
+	i = cons_options(options);
 	if (i == -1 || client->packet.options[i] != DHO_END)
 		error("options do not fit in DHCPDECLINE packet.");
 	client->packet_length = DHCP_FIXED_NON_UDP+i+1;
@@ -1484,10 +1371,15 @@ rewrite_client_leases(void)
 	fflush(leaseFile);
 	rewind(leaseFile);
 
-	for (lp = client->leases; lp; lp = lp->next)
-		write_client_lease(lp, 1);
+	for (lp = client->leases; lp; lp = lp->next) {
+		if (client->active && addr_eq(lp->address,
+			client->active->address))
+			continue;
+		write_client_lease(lp);
+	}
+
 	if (client->active)
-		write_client_lease(client->active, 1);
+		write_client_lease(client->active);
 
 	fflush(leaseFile);
 	ftruncate(fileno(leaseFile), ftello(leaseFile));
@@ -1495,19 +1387,11 @@ rewrite_client_leases(void)
 }
 
 void
-write_client_lease(struct client_lease *lease, int rewrite)
+write_client_lease(struct client_lease *lease)
 {
-	static int leases_written;
 	struct tm *t;
 	int i;
 
-	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)
@@ -1526,8 +1410,6 @@ write_client_lease(struct client_lease *lease, int rewrite)
 	if (lease->server_name)
 		fprintf(leaseFile, "  server-name \"%s\";\n",
 		    lease->server_name);
-	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",
@@ -1552,26 +1434,17 @@ write_client_lease(struct client_lease *lease, int rewrite)
 }
 
 void
-script_init(char *reason, struct string_list *medium)
+script_init(char *reason)
 {
-	size_t		 len, mediumlen = 0;
+	size_t		 len;
 	struct imsg_hdr	 hdr;
 	struct buf	*buf;
 
-	if (medium != NULL && medium->string != NULL)
-		mediumlen = strlen(medium->string);
-
 	hdr.code = IMSG_SCRIPT_INIT;
-	hdr.len = sizeof(struct imsg_hdr) +
-	    sizeof(size_t) + mediumlen +
-	    sizeof(size_t) + strlen(reason);
-
+	hdr.len = sizeof(struct imsg_hdr) + sizeof(size_t) + strlen(reason);
 	buf = buf_open(hdr.len);
 
 	buf_add(buf, &hdr, sizeof(hdr));
-	buf_add(buf, &mediumlen, sizeof(mediumlen));
-	if (mediumlen > 0)
-		buf_add(buf, medium->string, mediumlen);
 	len = strlen(reason);
 	buf_add(buf, &len, sizeof(len));
 	buf_add(buf, reason, len);
@@ -1580,7 +1453,7 @@ script_init(char *reason, struct string_list *medium)
 }
 
 void
-priv_script_init(char *reason, char *medium)
+priv_script_init(char *reason)
 {
 	client->scriptEnvsize = 100;
 	if (client->scriptEnv == NULL)
@@ -1597,9 +1470,6 @@ priv_script_init(char *reason, char *medium)
 
 	script_set_env("", "interface", ifi->name);
 
-	if (medium)
-		script_set_env("", "medium", medium);
-
 	script_set_env("", "reason", reason);
 }
 
@@ -1658,7 +1528,7 @@ supersede:
 				case ACTION_PREPEND:
 					len = config->defaults[i].len +
 					    lease->options[i].len;
-					if (len > sizeof(dbuf)) {
+					if (len >= sizeof(dbuf)) {
 						warning("no space to %s %s",
 						    "prepend option",
 						    dhcp_options[i].name);
@@ -1677,7 +1547,7 @@ supersede:
 				case ACTION_APPEND:
 					len = config->defaults[i].len +
 					    lease->options[i].len;
-					if (len > sizeof(dbuf)) {
+					if (len >= sizeof(dbuf)) {
 						warning("no space to %s %s",
 						    "append option",
 						    dhcp_options[i].name);
@@ -1951,6 +1821,24 @@ check_option(struct client_lease *l, int option)
 
 	switch (option) {
 	case DHO_SUBNET_MASK:
+	case DHO_SWAP_SERVER:
+	case DHO_BROADCAST_ADDRESS:
+	case DHO_DHCP_SERVER_IDENTIFIER:
+	case DHO_ROUTER_SOLICITATION_ADDRESS:
+	case DHO_DHCP_REQUESTED_ADDRESS:
+		if (ipv4addrs(opbuf) == 0) {
+			warning("Invalid IP address in option %s: %s",
+			    dhcp_options[option].name, opbuf);
+			return (0);
+		}
+		if (l->options[option].len != 4) { /* RFC 2132 */
+			warning("warning: Only 1 IP address allowed in "
+			    "%s option; length %d, must be 4",
+			    dhcp_options[option].name,
+			    l->options[option].len);
+			l->options[option].len = 4;
+		}
+		return (1);
 	case DHO_TIME_SERVERS:
 	case DHO_NAME_SERVERS:
 	case DHO_ROUTERS:
@@ -1960,16 +1848,14 @@ check_option(struct client_lease *l, int option)
 	case DHO_LPR_SERVERS:
 	case DHO_IMPRESS_SERVERS:
 	case DHO_RESOURCE_LOCATION_SERVERS:
-	case DHO_SWAP_SERVER:
-	case DHO_BROADCAST_ADDRESS:
 	case DHO_NIS_SERVERS:
 	case DHO_NTP_SERVERS:
 	case DHO_NETBIOS_NAME_SERVERS:
 	case DHO_NETBIOS_DD_SERVER:
 	case DHO_FONT_SERVERS:
-	case DHO_DHCP_SERVER_IDENTIFIER:
-		if (!ipv4addrs(opbuf)) {
-			warning("Invalid IP address in option: %s", opbuf);
+		if (ipv4addrs(opbuf) == 0) {
+			warning("Invalid IP address in option %s: %s",
+			    dhcp_options[option].name, opbuf);
 			return (0);
 		}
 		return (1);
@@ -2001,7 +1887,6 @@ check_option(struct client_lease *l, int option)
 	case DHO_PERFORM_MASK_DISCOVERY:
 	case DHO_MASK_SUPPLIER:
 	case DHO_ROUTER_DISCOVERY:
-	case DHO_ROUTER_SOLICITATION_ADDRESS:
 	case DHO_STATIC_ROUTES:
 	case DHO_TRAILER_ENCAPSULATION:
 	case DHO_ARP_CACHE_TIMEOUT:
@@ -2013,7 +1898,6 @@ check_option(struct client_lease *l, int option)
 	case DHO_NETBIOS_NODE_TYPE:
 	case DHO_NETBIOS_SCOPE:
 	case DHO_X_DISPLAY_MANAGER:
-	case DHO_DHCP_REQUESTED_ADDRESS:
 	case DHO_DHCP_LEASE_TIME:
 	case DHO_DHCP_OPTION_OVERLOAD:
 	case DHO_DHCP_MESSAGE_TYPE:
@@ -2025,10 +1909,12 @@ check_option(struct client_lease *l, int option)
 	case DHO_DHCP_CLASS_IDENTIFIER:
 	case DHO_DHCP_CLIENT_IDENTIFIER:
 	case DHO_DHCP_USER_CLASS_ID:
+	case DHO_TFTP_SERVER:
 	case DHO_END:
 		return (1);
 	default:
-		warning("unknown dhcp option value 0x%x", option);
+		if (!unknown_ok)
+			warning("unknown dhcp option value 0x%x", option);
 		return (unknown_ok);
 	}
 }
@@ -2169,3 +2055,45 @@ fork_privchld(int fd, int fd2)
 		dispatch_imsg(fd);
 	}
 }
+
+void
+get_ifname(char *ifname, char *arg)
+{
+	struct ifgroupreq ifgr;
+	struct ifg_req *ifg;
+	int s, len;
+
+	if (!strcmp(arg, "egress")) {
+		s = socket(AF_INET, SOCK_DGRAM, 0);
+		if (s == -1)
+			error("socket error");
+		bzero(&ifgr, sizeof(ifgr));
+		strlcpy(ifgr.ifgr_name, "egress", sizeof(ifgr.ifgr_name));
+		if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
+			if (errno == ENOENT)
+				error("no interface in group egress found");
+			error("ioctl SIOCGIFGMEMB: %m");
+		}
+		len = ifgr.ifgr_len;
+		if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
+			error("get_ifname");
+		if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
+			error("ioctl SIOCGIFGMEMB: %m");
+
+		arg = NULL;
+		for (ifg = ifgr.ifgr_groups;
+		     ifg && len >= sizeof(struct ifg_req); ifg++) {
+			len -= sizeof(struct ifg_req);
+			if (arg)
+				error("too many interfaces in group egress");
+			arg = ifg->ifgrq_member;
+		}
+
+		if (strlcpy(ifi->name, arg, IFNAMSIZ) >= IFNAMSIZ)
+			error("Interface name too long: %m");
+
+		free(ifgr.ifgr_groups);
+		close(s);
+	} else if (strlcpy(ifi->name, arg, IFNAMSIZ) >= IFNAMSIZ)
+		error("Interface name too long");
+}
diff --git a/sbin/dhclient/dhclient.conf.5 b/sbin/dhclient/dhclient.conf.5
index 41ad909..7487221 100644
--- a/sbin/dhclient/dhclient.conf.5
+++ b/sbin/dhclient/dhclient.conf.5
@@ -1,5 +1,4 @@
-.\"	$OpenBSD: dhclient.conf.5,v 1.14 2007/10/16 05:03:23 jmc Exp $
-.\"	$DragonFly: src/sbin/dhclient/dhclient.conf.5,v 1.3 2008/09/01 10:48:29 swildner Exp $
+.\" $OpenBSD: src/sbin/dhclient/dhclient.conf.5,v 1.21 2011/04/09 19:53:00 krw Exp $
 .\"
 .\" Copyright (c) 1997 The Internet Software Consortium.
 .\" All rights reserved.
@@ -37,7 +36,7 @@
 .\" see ``http://www.isc.org/isc''.  To learn more about Vixie
 .\" Enterprises, see ``http://www.vix.com''.
 .\"
-.Dd August 30, 2008
+.Dd August 4, 2012
 .Dt DHCLIENT.CONF 5
 .Os
 .Sh NAME
@@ -144,7 +143,7 @@ The
 .Ic backoff-cutoff
 statement determines the maximum amount of time that the client is
 allowed to back off.
-It defaults to 15 seconds.
+It defaults to fifteen seconds.
 .It Ic initial-interval Ar time ;
 The
 .Ic initial-interval
@@ -154,14 +153,15 @@ Each time a message is sent, the interval between messages is incremented by
 twice the current interval multiplied by a random number between zero and one.
 If it is greater than the backoff-cutoff amount, it is set to that
 amount.
-It defaults to ten seconds.
+It defaults to three seconds.
 .It Ic link-timeout Ar time ;
 The
 .Ic link-timeout
 statement sets the amount of time to wait for an interface link before timing
 out.
-The default value is 10 seconds, but the special value 0 requests that dhclient
-not wait for a link state change before timing out.
+The default value is ten seconds.
+The value zero requests that
+dhclient not wait for a link state change before timing out.
 .El
 .Sh LEASE REQUIREMENTS AND REQUESTS
 The DHCP protocol allows the client to request that the server send it
@@ -213,12 +213,18 @@ that will allow it to differentiate between this client and other
 clients or kinds of clients.
 .El
 .Sh OPTION MODIFIERS
-In some cases, a client may receive option data from the server which
-is not really appropriate for that client, or may not receive
-information that it needs, and for which a useful default value exists.
-It may also receive information which is useful, but which needs to be
-supplemented with local information.
-To handle these needs, several option modifiers are available.
+Options in the lease can be modified before being passed to the client
+configuration script,
+.Xr dhclient-script 8 .
+.Pp
+The default client configuration script
+processes only options 1 (subnet
+mask), 3 (routers), 6 (domain name servers), 15 (domain-name).
+Use of option modifiers on other options will have no effect unless
+.Xr dhclient-script 8
+the client configuration script is modified.
+.Pp
+Several option modifiers are available.
 .Bl -tag -width Ds
 .It Xo
 .Ic default No { Op Ar option declaration
@@ -343,24 +349,6 @@ or, in the case of predefined leases declared in
 .Nm ,
 the value that the user wishes the client configuration script to use if the
 predefined lease is used.
-.It Ic medium Ar \&"media setup\&" ;
-The
-.Ic medium
-statement can be used on systems where network interfaces cannot
-automatically determine the type of network to which they are connected.
-The media setup string is a system-dependent parameter which is passed
-to the DHCP client configuration script when initializing the interface.
-On
-.Ux
-and UNIX-like systems, the argument is passed on the ifconfig command line
-when configuring the interface.
-.Pp
-The DHCP client automatically declares this parameter if it used a
-media type (see the
-.Ic media
-statement) when configuring the interface in order to obtain a lease.
-This statement should be used in predefined leases only if the network
-interface requires media type configuration.
 .It Ic renew Ar date ;
 .It Ic rebind Ar date ;
 .It Ic expire Ar date ;
@@ -405,27 +393,6 @@ The day of the month is likewise specified starting with 1.
 The hour is a number between 0 and 23,
 the minute a number between 0 and 59,
 and the second also a number between 0 and 59.
-.Sh ALIAS DECLARATIONS
-.Ic alias No { Ar declarations ... No }
-.Pp
-Some DHCP clients running TCP/IP roaming protocols may require that in
-addition to the lease they may acquire via DHCP, their interface also
-be configured with a predefined IP alias so that they can have a
-permanent IP address even while roaming.
-The Internet Software Consortium DHCP client doesn't support roaming with
-fixed addresses directly, but in order to facilitate such experimentation,
-the DHCP client can be set up to configure an IP alias using the
-.Ic alias
-declaration.
-.Pp
-The
-.Ic alias
-declaration resembles a lease declaration, except that options other than
-the subnet-mask option are ignored by the standard client configuration
-script, and expiry times are ignored.
-A typical alias declaration includes an interface declaration, a fixed-address
-declaration for the IP alias address, and a subnet-mask option declaration.
-A medium statement should never be included in an alias declaration.
 .Sh OTHER DECLARATIONS
 .Bl -tag -width Ds
 .It Ic reject Ar ip-address ;
@@ -442,39 +409,17 @@ the bad DHCP server and fix it.
 .Xc
 A client with more than one network interface may require different
 behaviour depending on which interface is being configured.
-All timing parameters and declarations other than lease and alias
+All timing parameters and declarations other than lease
 declarations can be enclosed in an interface declaration, and those
 parameters will then be used only for the interface that matches the
 specified name.
 Interfaces for which there is no interface declaration will use the
 parameters declared outside of any interface declaration,
 or the default settings.
-.It Xo
-.Ic media Ar \&"media setup\&"
-.Oo , Ar \&"media setup\&" , ... Oc ;
-.Xc
-The
-.Ic media
-statement defines one or more media configuration parameters which may
-be tried while attempting to acquire an IP address.
-The DHCP client will cycle through each media setup string on the list,
-configuring the interface using that setup and attempting to boot,
-and then trying the next one.
-This can be used for network interfaces which aren't capable of sensing
-the media type unaided \- whichever media type succeeds in getting a request
-to the server and hearing the reply is probably right (no guarantees).
-.Pp
-The media setup is only used for the initial phase of address
-acquisition (the DHCPDISCOVER and DHCPOFFER packets).
-Once an address has been acquired, the DHCP client will record it in its
-lease database and will record the media type used to acquire the address.
-Whenever the client tries to renew the lease, it will use that same media type.
-The lease must expire before the client will go back to cycling through media
-types.
 .It Ic script Ar \&"script-name\&" ;
 The
 .Ic script
-statement is used to specify the pathname of the DHCP client configuration
+statement is used to specify the pathname of the client configuration
 script.
 This script is used by the DHCP client to set each interface's initial
 configuration prior to requesting an address, to test the address once it
@@ -487,8 +432,7 @@ For more information, see
 .El
 .Sh EXAMPLES
 The following configuration file is used on a laptop
-which has an IP alias of 192.5.5.213, and has one interface,
-ep0 (a 3Com 3C589C).
+which has one interface, ep0 (a 3Com 3C589C).
 Booting intervals have been shortened somewhat from the default, because
 the client is known to spend most of its time on networks with little DHCP
 activity.
@@ -511,13 +455,6 @@ interface "ep0" {
 	    domain-name, domain-name-servers, host-name;
     require subnet-mask, domain-name-servers;
     script "/etc/dhclient-script";
-    media "media 10baseT/UTP", "media 10base2/BNC";
-}
-
-alias {
-  interface "ep0";
-  fixed-address 192.5.5.213;
-  option subnet-mask 255.255.255.255;
 }
 .Ed
 .Pp
@@ -529,6 +466,7 @@ In many cases, it's sufficient to just create an empty
 file \- the defaults are usually fine.
 .Sh SEE ALSO
 .Xr dhclient.leases 5 ,
+.Xr dhclient-script 8 ,
 .Xr dhcp-options 5 ,
 .Xr dhcpd.conf 5 Pq Pa pkgsrc/net/isc-dhcpd4 ,
 .Xr dhclient 8 ,
diff --git a/sbin/dhclient/dhcp.h b/sbin/dhclient/dhcp.h
index b1bb20f..fa6f53f 100644
--- a/sbin/dhclient/dhcp.h
+++ b/sbin/dhclient/dhcp.h
@@ -1,5 +1,4 @@
-/*	$OpenBSD: dhcp.h,v 1.7 2007/02/01 22:39:43 krw Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/dhcp.h,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/dhcp.h,v 1.9 2011/05/11 14:38:36 krw Exp $	*/
 
 /* Protocol structures... */
 
@@ -87,7 +86,8 @@ struct dhcp_packet {
 
 /* Magic cookie validating dhcp options field (and bootp vendor
    extensions field). */
-#define DHCP_OPTIONS_COOKIE	"\143\202\123\143"
+#define DHCP_OPTIONS_COOKIE		"\143\202\123\143"
+#define DHCP_OPTIONS_MESSAGE_TYPE	"\065\001\000"
 
 /* DHCP Option codes: */
 
@@ -153,6 +153,7 @@ struct dhcp_packet {
 #define DHO_DHCP_REBINDING_TIME		59
 #define DHO_DHCP_CLASS_IDENTIFIER	60
 #define DHO_DHCP_CLIENT_IDENTIFIER	61
+#define DHO_TFTP_SERVER			66
 #define DHO_DHCP_USER_CLASS_ID		77
 #define DHO_END				255
 
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index 7d8601c..6b208c9 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: src/sbin/dhclient/dhcpd.h,v 1.67 2008/05/26 03:11:48 deraadt Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/dhcpd.h,v 1.76 2012/07/09 16:21:21 krw Exp $	*/
 
 /*
  * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -51,6 +51,7 @@
 #include <net/if_dl.h>
 #include <net/route.h>
 #include <netinet/in.h>
+#include <netinet/if_ether.h>
 
 #include <ctype.h>
 #include <errno.h>
@@ -108,7 +109,6 @@ struct client_lease {
 	struct iaddr		 address;
 	char			*server_name;
 	char			*filename;
-	struct string_list	*medium;
 	unsigned int		 is_static : 1;
 	unsigned int		 is_bootp : 1;
 	struct option_data	 options[256];
@@ -145,11 +145,9 @@ struct client_config {
 	time_t			 select_interval;
 	time_t			 reboot_timeout;
 	time_t			 backoff_cutoff;
-	struct string_list	*media;
 	char			*script_name;
 	enum { IGNORE, ACCEPT, PREFER }
 				 bootp_policy;
-	struct string_list	*medium;
 	struct iaddrlist	*reject_list;
 };
 
@@ -158,14 +156,12 @@ struct client_state {
 	struct client_lease	 *new;
 	struct client_lease	 *offered_leases;
 	struct client_lease	 *leases;
-	struct client_lease	 *alias;
 	enum dhcp_state		  state;
 	struct iaddr		  destination;
 	u_int32_t		  xid;
 	u_int16_t		  secs;
 	time_t			  first_sending;
 	time_t			  interval;
-	struct string_list	 *medium;
 	struct dhcp_packet	  packet;
 	int			  packet_length;
 	struct iaddr		  requested_address;
@@ -209,7 +205,7 @@ extern struct client_state *client;
 extern struct client_config *config;
 
 /* options.c */
-int cons_options(unsigned char *, const int, struct option_data *);
+int cons_options(struct option_data *);
 char *pretty_print_option(unsigned int, unsigned char *, int, int, int);
 void do_packet(int, unsigned int, struct iaddr, struct hardware *);
 
@@ -218,7 +214,9 @@ extern int warnings_occurred;
 void error(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
 int warning(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
 int note(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+#ifdef DEBUG
 int debug(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+#endif
 int parse_warn(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
 
 /* conflex.c */
@@ -251,12 +249,10 @@ void discover_interface(void);
 void reinitialize_interface(void);
 void dispatch(void);
 void got_one(void);
-void add_timeout(time_t, void (*)(void));
-void cancel_timeout(void (*)(void));
+void set_timeout(time_t, void (*)(void));
+void cancel_timeout(void);
 int interface_status(char *);
-int interface_link_status(char *);
 int interface_link_forceup(char *);
-void interface_link_forcedown(char *);
 
 /* tables.c */
 extern const struct option dhcp_options[256];
@@ -306,13 +302,13 @@ void make_decline(struct client_lease *);
 
 void free_client_lease(struct client_lease *);
 void rewrite_client_leases(void);
-void write_client_lease(struct client_lease *, int);
+void write_client_lease(struct client_lease *);
 
-void	 priv_script_init(char *, char *);
+void	 priv_script_init(char *);
 void	 priv_script_write_params(char *, struct client_lease *);
 int	 priv_script_go(void);
 
-void script_init(char *, struct string_list *);
+void script_init(char *);
 void script_write_params(char *, struct client_lease *);
 int script_go(void);
 void script_set_env(const char *, const char *, const char *);
diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c
index 1057966..9cf4a77 100644
--- a/sbin/dhclient/dispatch.c
+++ b/sbin/dhclient/dispatch.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: src/sbin/dhclient/dispatch.c,v 1.42 2008/05/26 03:11:49 deraadt Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/dispatch.c,v 1.53 2012/07/26 18:42:58 krw Exp $	*/
 
 /*
  * Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -48,8 +48,7 @@
 
 #include "dhcpd.h"
 
-struct timeout *timeouts;
-static struct timeout *free_timeouts;
+struct timeout timeout;
 static int interfaces_invalidated;
 
 /*
@@ -125,35 +124,35 @@ dispatch(void)
 	int count, to_msec;
 	struct pollfd fds[2];
 	time_t howlong;
+	void (*func)(void);
 
 	do {
 		/*
-		 * Call any expired timeouts, and then if there's still
+		 * Call expired timeout, and then if there's still
 		 * a timeout registered, time out the select call then.
 		 */
 another:
+		if (!ifi)
+			error("No interfaces available");
+
 		if (!ifi->linkstat)
 			interfaces_invalidated = 0;
 
-		if (timeouts) {
-			struct timeout *t;
-
-			if (timeouts->when <= cur_time) {
-				t = timeouts;
-				timeouts = timeouts->next;
-				(*(t->func))();
-				t->next = free_timeouts;
-				free_timeouts = t;
+		if (timeout.func) {
+			time(&cur_time);
+			if (timeout.when <= cur_time) {
+				func = timeout.func;
+				cancel_timeout();
+				(*(func))();
 				goto another;
 			}
-
 			/*
 			 * Figure timeout in milliseconds, and check for
 			 * potential overflow, so we can cram into an
 			 * int for poll, while not polling with a
 			 * negative timeout and blocking indefinitely.
 			 */
-			howlong = timeouts->when - cur_time;
+			howlong = timeout.when - cur_time;
 			if (howlong > INT_MAX / 1000)
 				howlong = INT_MAX / 1000;
 			to_msec = howlong * 1000;
@@ -171,9 +170,6 @@ another:
 		/* Wait for a packet or a timeout... XXX */
 		count = poll(fds, 2, to_msec);
 
-		/* Get the current time... */
-		time(&cur_time);
-
 		/* Not likely to be transitory... */
 		if (count == -1) {
 			if (errno == EAGAIN || errno == EINTR) {
@@ -183,8 +179,7 @@ another:
 		}
 
 		if ((fds[0].revents & (POLLIN | POLLHUP))) {
-			if (ifi->linkstat &&
-			    ifi && ifi->rfdesc != -1)
+			if (ifi && ifi->linkstat && ifi->rfdesc != -1)
 				got_one();
 		}
 		if ((fds[1].revents & (POLLIN | POLLHUP))) {
@@ -211,11 +206,8 @@ got_one(void)
 		if ((!interface_status(ifi->name)) ||
 		    (ifi->noifmedia && ifi->errors > 20)) {
 			/* our interface has gone away. */
-			warning("Interface %s no longer appears valid.",
+			error("Interface %s no longer appears valid.",
 			    ifi->name);
-			interfaces_invalidated = 1;
-			close(ifi->rfdesc);
-			ifi->rfdesc = -1;
 		}
 		return;
 	}
@@ -257,33 +249,6 @@ interface_link_forceup(char *ifname)
 	return (1);
 }
 
-void
-interface_link_forcedown(char *ifname)
-{
-	struct ifreq ifr;
-	int sock;
-
-	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-		error("Can't create socket");
-
-	memset(&ifr, 0, sizeof(ifr));
-	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
-		close(sock);
-		return;
-	}
-
-	if ((ifr.ifr_flags & IFF_UP) == IFF_UP) {
-		ifr.ifr_flags &= ~IFF_UP;
-		if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
-			close(sock);
-			return;
-		}
-	}
-
-	close(sock);
-}
-
 int
 interface_status(char *ifname)
 {
@@ -297,9 +262,8 @@ interface_status(char *ifname)
 	/* get interface flags */
 	memset(&ifr, 0, sizeof(ifr));
 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-	if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
-		warning("ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
-		goto inactive;
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
+		error("ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
 	}
 
 	/*
@@ -314,14 +278,15 @@ interface_status(char *ifname)
 		goto active;
 	memset(&ifmr, 0, sizeof(ifmr));
 	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
-	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
 		/*
 		 * EINVAL or ENOTTY simply means that the interface
 		 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
 		 */
+#ifdef DEBUG
 		if (errno != EINVAL && errno != ENOTTY)
 			debug("ioctl(SIOCGIFMEDIA) on %s: %m", ifname);
-
+#endif
 		ifi->noifmedia = 1;
 		goto active;
 	}
@@ -331,122 +296,27 @@ interface_status(char *ifname)
 		else
 			goto inactive;
 	}
-inactive:
-	close(sock);
-	return (0);
+
+	/* Assume 'active' if IFM_AVALID is not set. */
+
 active:
 	close(sock);
 	return (1);
+inactive:
+	close(sock);
+	return (0);
 }
 
 void
-add_timeout(time_t when, void (*where)(void))
+set_timeout(time_t when, void (*where)(void))
 {
-	struct timeout *t, *q;
-
-	/* See if this timeout supersedes an existing timeout. */
-	t = NULL;
-	for (q = timeouts; q; q = q->next) {
-		if (q->func == where) {
-			if (t)
-				t->next = q->next;
-			else
-				timeouts = q->next;
-			break;
-		}
-		t = q;
-	}
-
-	/* If we didn't supersede a timeout, allocate a timeout
-	   structure now. */
-	if (!q) {
-		if (free_timeouts) {
-			q = free_timeouts;
-			free_timeouts = q->next;
-			q->func = where;
-		} else {
-			q = malloc(sizeof(struct timeout));
-			if (!q)
-				error("Can't allocate timeout structure!");
-			q->func = where;
-		}
-	}
-
-	q->when = when;
-
-	/* Now sort this timeout into the timeout list. */
-
-	/* Beginning of list? */
-	if (!timeouts || timeouts->when > q->when) {
-		q->next = timeouts;
-		timeouts = q;
-		return;
-	}
-
-	/* Middle of list? */
-	for (t = timeouts; t->next; t = t->next) {
-		if (t->next->when > q->when) {
-			q->next = t->next;
-			t->next = q;
-			return;
-		}
-	}
-
-	/* End of list. */
-	t->next = q;
-	q->next = NULL;
+	timeout.when = when;
+	timeout.func = where;
 }
 
 void
-cancel_timeout(void (*where)(void))
-{
-	struct timeout *t, *q;
-
-	/* Look for this timeout on the list, and unlink it if we find it. */
-	t = NULL;
-	for (q = timeouts; q; q = q->next) {
-		if (q->func == where) {
-			if (t)
-				t->next = q->next;
-			else
-				timeouts = q->next;
-			break;
-		}
-		t = q;
-	}
-
-	/* If we found the timeout, put it on the free list. */
-	if (q) {
-		q->next = free_timeouts;
-		free_timeouts = q;
-	}
-}
-
-int
-interface_link_status(char *ifname)
+cancel_timeout(void)
 {
-	struct ifmediareq ifmr;
-	int sock;
-
-	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-		error("Can't create socket");
-
-	memset(&ifmr, 0, sizeof(ifmr));
-	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
-	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
-		/* EINVAL/ENOTTY -> link state unknown. treat as active */
-		if (errno != EINVAL && errno != ENOTTY)
-			debug("ioctl(SIOCGIFMEDIA) on %s: %m", ifname);
-		close(sock);
-		return (1);
-	}
-	close(sock);
-
-	if (ifmr.ifm_status & IFM_AVALID) {
-		if (ifmr.ifm_status & IFM_ACTIVE)
-			return (1);
-		else
-			return (0);
-	}
-	return (1);
+	timeout.when = 0;
+	timeout.func = NULL;
 }
diff --git a/sbin/dhclient/errwarn.c b/sbin/dhclient/errwarn.c
index d8dbcba..100727b 100644
--- a/sbin/dhclient/errwarn.c
+++ b/sbin/dhclient/errwarn.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: errwarn.c,v 1.15 2007/03/02 11:31:17 henning Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/errwarn.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/errwarn.c,v 1.17 2009/11/26 23:14:29 krw Exp $	*/
 
 /* Errors and warnings... */
 
@@ -80,9 +79,7 @@ error(char *fmt, ...)
 		write(STDERR_FILENO, "\n", 1);
 	}
 
-	syslog(LOG_CRIT, "exiting.");
 	if (log_perror) {
-		fprintf(stderr, "exiting.\n");
 		fflush(stderr);
 	}
 	exit(1);
@@ -140,6 +137,7 @@ note(char *fmt, ...)
 	return (0);
 }
 
+#ifdef DEBUG
 /*
  * Log a debug message...
  */
@@ -154,9 +152,7 @@ debug(char *fmt, ...)
 	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
 	va_end(list);
 
-#ifndef DEBUG
 	syslog(LOG_DEBUG, "%s", mbuf);
-#endif
 
 	if (log_perror) {
 		write(STDERR_FILENO, mbuf, strlen(mbuf));
@@ -165,7 +161,7 @@ debug(char *fmt, ...)
 
 	return (0);
 }
-
+#endif
 /*
  * Find %m in the input string and substitute an error message string.
  */
diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c
index d56ee2e..b6edda6 100644
--- a/sbin/dhclient/options.c
+++ b/sbin/dhclient/options.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: options.c,v 1.36 2007/06/02 01:29:11 pvalchev Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/options.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/options.c,v 1.41 2012/06/26 14:46:42 krw Exp $	*/
 
 /* DHCP options parsing and reassembly. */
 
@@ -69,24 +68,39 @@ parse_option_buffer(struct option_data *options, unsigned char *buffer,
 		}
 
 		/*
-		 * All options other than DHO_PAD and DHO_END have a
-		 * one-byte length field.
+		 * All options other than DHO_PAD and DHO_END have a one-byte
+		 * length field. It could be 0! Make sure that the length byte
+		 * is present, and all the data is available.
 		 */
-		if (s + 2 > end)
-			len = 0;
-		else
+		if (s + 1 < end) {
 			len = s[1];
+			if (s + 1 + len < end) {
+				; /* option data is all there. */
+			} else {
+				warning("option %s (%d) larger than buffer.",
+				    dhcp_options[code].name, len);
+				warning("rejecting bogus offer.");
+				return (0);
+			}
+		} else {
+			warning("option %s has no length field.",
+			    dhcp_options[code].name);
+			warning("rejecting bogus offer.");
+			return (0);
+		}
 
 		/*
-		 * If the option claims to extend beyond the end of the buffer
-		 * then mark the options buffer bad.
+		 * Strip trailing NULs from ascii ('t') options. They
+		 * will be treated as DHO_PAD options. i.e. ignored. RFC 2132
+		 * says "Options containing NVT ASCII data SHOULD NOT include
+		 * a trailing NULL; however, the receiver of such options
+		 * MUST be prepared to delete trailing nulls if they exist."
 		 */
-		if (s + len + 2 > end) {
-			warning("option %s (%d) larger than buffer.",
-			    dhcp_options[code].name, len);
-			warning("rejecting bogus offer.");
-			return (0);
+		if (dhcp_options[code].format[0] == 't') {
+			while (len > 0 && s[len + 1] == '\0')
+				len--;
 		}
+
 		/*
 		 * If we haven't seen this option before, just make
 		 * space for it and copy it there.
@@ -132,18 +146,24 @@ parse_option_buffer(struct option_data *options, unsigned char *buffer,
  * to see if it's DHO_END to decide if all the options were copied.
  */
 int
-cons_options(unsigned char *buf, const int buflen, struct option_data *options)
+cons_options(struct option_data *options)
 {
+	unsigned char *buf = client->packet.options;
+	int buflen = 576 - DHCP_FIXED_LEN;
 	int ix, incr, length, bufix, code, lastopt = -1;
 
 	bzero(buf, buflen);
 
-	if (buflen > 3)
-		memcpy(buf, DHCP_OPTIONS_COOKIE, 4);
-	bufix = 4;
+	memcpy(buf, DHCP_OPTIONS_COOKIE, 4);
+	if (options[DHO_DHCP_MESSAGE_TYPE].data) {
+		memcpy(&buf[4], DHCP_OPTIONS_MESSAGE_TYPE, 3);
+		buf[6] = options[DHO_DHCP_MESSAGE_TYPE].data[0];
+		bufix = 7;
+	} else
+		bufix = 4;
 
 	for (code = DHO_SUBNET_MASK; code < DHO_END; code++) {
-		if (!options[code].data)
+		if (!options[code].data || code == DHO_DHCP_MESSAGE_TYPE)
 			continue;
 
 		length = options[code].len;
@@ -213,6 +233,13 @@ pretty_print_option(unsigned int code, unsigned char *data, int len,
 			--numelem;
 			fmtbuf[i] = 0;
 			numhunk = 0;
+			if (hunksize == 0) {
+				warning("%s: no size indicator before A"
+				    " in format string: %s",
+				    dhcp_options[code].name,
+				    dhcp_options[code].format);
+				return ("<fmt error>");
+			}
 			break;
 		case 'X':
 			for (k = 0; k < len; k++)
@@ -491,6 +518,15 @@ do_packet(int len, unsigned int from_port, struct iaddr from,
 		type = "BOOTREPLY";
 	}
 
+	if (handler && client->xid == client->packet.xid) {
+		if (hfrom->hlen == 6)
+			note("%s from %s (%s)", type, piaddr(from),
+			    ether_ntoa((struct ether_addr *)hfrom->haddr));
+		else
+			note("%s from %s", type, piaddr(from));
+	} else
+		handler = NULL;
+
 	for (ap = config->reject_list; ap && handler; ap = ap->next)
 		if (addr_eq(from, ap->addr)) {
 			note("%s from %s rejected.", type, piaddr(from));
diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c
index 8e88ad9..6a1ac4c 100644
--- a/sbin/dhclient/packet.c
+++ b/sbin/dhclient/packet.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: packet.c,v 1.12 2006/12/28 01:10:46 stevesk Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/packet.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/packet.c,v 1.13 2009/06/06 04:02:42 krw Exp $	*/
 
 /* Packet assembly code, originally contributed by Archie Cobbs. */
 
@@ -190,10 +189,11 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from,
 		return (-1);
 	}
 
+#ifdef DEBUG
 	if (ntohs(ip->ip_len) != buflen)
 		debug("ip length %d disagrees with bytes received %d.",
 		    ntohs(ip->ip_len), buflen);
-
+#endif
 	memcpy(&from->sin_addr, &ip->ip_src, 4);
 
 	/*
@@ -218,8 +218,10 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from,
 			}
 			return (-1);
 		}
+#ifdef DEBUG
 		if (len + data != buf + bufix + buflen)
 			debug("accepting packet with data after udp payload.");
+#endif
 	}
 
 	usum = udp->uh_sum;
diff --git a/sbin/dhclient/parse.c b/sbin/dhclient/parse.c
index 1e00765..ae25582 100644
--- a/sbin/dhclient/parse.c
+++ b/sbin/dhclient/parse.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: parse.c,v 1.18 2007/01/08 13:34:38 krw Exp $	*/
-/*	$DragonFly: src/sbin/dhclient/parse.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/parse.c,v 1.20 2011/12/10 17:15:27 krw Exp $	*/
 
 /* Common parser code for dhcpd and dhclient. */
 
@@ -63,14 +62,13 @@ void
 skip_to_semi(FILE *cfile)
 {
 	int		 token;
-	char		*val;
 	int		 brace_count = 0;
 
 	do {
-		token = peek_token(&val, cfile);
+		token = peek_token(NULL, cfile);
 		if (token == '}') {
 			if (brace_count) {
-				token = next_token(&val, cfile);
+				token = next_token(NULL, cfile);
 				if (!--brace_count)
 					return;
 			} else
@@ -78,7 +76,7 @@ skip_to_semi(FILE *cfile)
 		} else if (token == '{') {
 			brace_count++;
 		} else if (token == ';' && !brace_count) {
-			token = next_token(&val, cfile);
+			token = next_token(NULL, cfile);
 			return;
 		} else if (token == '\n') {
 			/*
@@ -87,10 +85,10 @@ skip_to_semi(FILE *cfile)
 			 * semicolon because the resolv.conf file is
 			 * line-oriented.
 			 */
-			token = next_token(&val, cfile);
+			token = next_token(NULL, cfile);
 			return;
 		}
-		token = next_token(&val, cfile);
+		token = next_token(NULL, cfile);
 	} while (token != EOF);
 }
 
@@ -98,9 +96,8 @@ int
 parse_semi(FILE *cfile)
 {
 	int token;
-	char *val;
 
-	token = next_token(&val, cfile);
+	token = next_token(NULL, cfile);
 	if (token != ';') {
 		parse_warn("semicolon expected.");
 		skip_to_semi(cfile);
@@ -124,10 +121,9 @@ parse_string(FILE *cfile)
 		skip_to_semi(cfile);
 		return (NULL);
 	}
-	s = malloc(strlen(val) + 1);
+	s = strdup(val);
 	if (!s)
 		error("no memory for string %s.", val);
-	strlcpy(s, val, strlen(val) + 1);
 
 	if (!parse_semi(cfile)) {
 		free(s);
@@ -152,9 +148,8 @@ void
 parse_hardware_param(FILE *cfile, struct hardware *hardware)
 {
 	int token;
-	char *val;
 
-	token = next_token(&val, cfile);
+	token = next_token(NULL, cfile);
 	switch (token) {
 	case TOK_ETHERNET:
 		hardware->htype = HTYPE_ETHER;
@@ -178,7 +173,7 @@ parse_hardware_param(FILE *cfile, struct hardware *hardware)
 	    ':', 16) == 0)
 		return;
 
-	token = next_token(&val, cfile);
+	token = next_token(NULL, cfile);
 	if (token != ';') {
 		parse_warn("expecting semicolon.");
 		skip_to_semi(cfile);
diff --git a/sbin/dhclient/privsep.c b/sbin/dhclient/privsep.c
index 646bdd7..4c626fa 100644
--- a/sbin/dhclient/privsep.c
+++ b/sbin/dhclient/privsep.c
@@ -1,5 +1,4 @@
-/*	$OpenBSD: privsep.c,v 1.14 2007/02/15 15:22:27 stevesk Exp $ */
-/*	$DragonFly: src/sbin/dhclient/privsep.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
+/*	$OpenBSD: src/sbin/dhclient/privsep.c,v 1.16 2011/04/04 11:14:52 krw Exp $	*/
 
 /*
  * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -78,7 +77,9 @@ buf_read(int sock, void *buf, size_t nbytes)
 	do {
 		n = read(sock, buf, nbytes);
 		if (n == 0) {			/* connection closed */
+#ifdef DEBUG
 			debug("buf_read (connection closed)");
+#endif
 			exit(1);
 		}
 		if (n != -1 && n < nbytes)
@@ -93,9 +94,9 @@ void
 dispatch_imsg(int fd)
 {
 	struct imsg_hdr		 hdr;
-	char			*medium, *reason, *filename,
+	char			*reason, *filename,
 				*servername, *prefix;
-	size_t			 medium_len, reason_len, filename_len,
+	size_t			 reason_len, filename_len,
 				 servername_len, prefix_len, totlen;
 	struct client_lease	 lease;
 	int			 ret, i, optlen;
@@ -107,19 +108,8 @@ dispatch_imsg(int fd)
 	case IMSG_SCRIPT_INIT:
 		if (hdr.len < sizeof(hdr) + sizeof(size_t))
 			error("corrupted message received");
-		buf_read(fd, &medium_len, sizeof(medium_len));
-		if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr)
-		    + sizeof(size_t) || medium_len == SIZE_T_MAX)
-			error("corrupted message received");
-		if (medium_len > 0) {
-			if ((medium = calloc(1, medium_len + 1)) == NULL)
-				error("%m");
-			buf_read(fd, medium, medium_len);
-		} else
-			medium = NULL;
-
 		buf_read(fd, &reason_len, sizeof(reason_len));
-		if (hdr.len < medium_len + reason_len + sizeof(hdr) ||
+		if (hdr.len < reason_len + sizeof(hdr) + sizeof(size_t) ||
 		    reason_len == SIZE_T_MAX)
 			error("corrupted message received");
 		if (reason_len > 0) {
@@ -129,9 +119,8 @@ dispatch_imsg(int fd)
 		} else
 			reason = NULL;
 
-		priv_script_init(reason, medium);
+		priv_script_init(reason);
 		free(reason);
-		free(medium);
 		break;
 	case IMSG_SCRIPT_WRITE_PARAMS:
 		bzero(&lease, sizeof lease);
