--- old/usr/src/lib/libipadm/common/ipadm_addr.c	Mon Nov 14 16:21:16 2016
+++ new/usr/src/lib/libipadm/common/ipadm_addr.c	Mon Nov 14 16:21:16 2016
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  */
 
 /*
@@ -32,6 +33,7 @@
  */
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/param.h>
 #include <netdb.h>
 #include <inet/ip.h>
 #include <string.h>
@@ -48,6 +50,8 @@
 #include <ctype.h>
 #include <dhcpagent_util.h>
 #include <dhcpagent_ipc.h>
+#include <dhcp_inittab.h>
+#include <dhcp_symbol.h>
 #include <ipadm_ndpd.h>
 #include <libdladm.h>
 #include <libdllink.h>
@@ -64,6 +68,7 @@
 			    uint32_t);
 static ipadm_status_t	i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
 			    boolean_t);
+static ipadm_status_t	i_ipadm_refresh_dhcp(ipadm_addrobj_t);
 static ipadm_status_t	i_ipadm_get_db_addr(ipadm_handle_t, const char *,
 			    const char *, nvlist_t **);
 static ipadm_status_t	i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
@@ -77,6 +82,7 @@
 static ipadm_status_t	i_ipadm_get_static_addr_db(ipadm_handle_t,
 			    ipadm_addrobj_t);
 static boolean_t	i_ipadm_is_user_aobjname_valid(const char *);
+static ipadm_prop_desc_t *	i_ipadm_get_addrprop_desc(const char *pname);
 
 /*
  * Callback functions to retrieve property values from the kernel. These
@@ -85,16 +91,21 @@
  * for a given property.
  */
 static ipadm_pd_getf_t	i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
-			i_ipadm_get_zone, i_ipadm_get_broadcast;
+			i_ipadm_get_zone, i_ipadm_get_broadcast, i_ipadm_get_primary,
+			i_ipadm_get_reqhost;
 
 /*
  * Callback functions to set property values. These functions translate the
  * values to a format suitable for kernel consumption, allocate the necessary
- * ioctl buffers and then invoke ioctl().
+ * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
+ * collaborating agent to set the value.
  */
 static ipadm_pd_setf_t	i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
-			i_ipadm_set_zone;
+			i_ipadm_set_zone, i_ipadm_set_reqhost;
 
+static ipadm_status_t	i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,
+			ipadm_addrobj_t ipaddr, uint_t flags, const char *propname);
+
 /* address properties description table */
 ipadm_prop_desc_t ipadm_addrprop_table[] = {
 	{ "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
@@ -104,13 +115,24 @@
 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff,
 	    i_ipadm_get_addr_flag },
 
-	{ "prefixlen", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
+	{ IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 	    i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
 	    i_ipadm_get_prefixlen },
 
+	/*
+	 * primary is read-only because there is no operation to un-set
+	 * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then
+	 * re-create-addr.
+	 */
+	{ "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
+		NULL, NULL, i_ipadm_get_primary },
+
 	{ "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 
+	{ IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
+	    i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
+
 	{ "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
 
@@ -201,9 +223,17 @@
 	ipaddr->ipadm_atype = rval.ir_atype;
 	ipaddr->ipadm_af = rval.ir_family;
 	ipaddr->ipadm_flags = rval.ir_flags;
-	if (rval.ir_atype == IPADM_ADDR_IPV6_ADDRCONF) {
-		(void) memcpy(&ipaddr->ipadm_intfid, &rval.ir_ifid,
-		    sizeof (ipaddr->ipadm_intfid));
+	switch (rval.ir_atype) {
+	case IPADM_ADDR_IPV6_ADDRCONF:
+		ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid;
+		break;
+	case IPADM_ADDR_DHCP:
+		ipaddr->ipadm_primary = rval.ipmgmt_ir_primary;
+		(void) strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
+		    sizeof (ipaddr->ipadm_reqhost));
+		break;
+	default:
+		break;
 	}
 
 	return (IPADM_SUCCESS);
@@ -1041,6 +1071,84 @@
 }
 
 /*
+ * Callback function that sets the property `reqhost' on the address
+ * object in `arg' to the value in `pval'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
+{
+	ipadm_status_t	status;
+	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
+
+	if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
+		return (IPADM_NOTSUP);
+
+	/*
+	 * If requested to set reqhost just from active config but the
+	 * address is not in active config, return error.
+	 */
+	if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) &&
+	    (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
+		return (IPADM_NOTFOUND);
+	}
+
+	status = ipadm_set_reqhost(ipaddr, pval);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
+		status = i_ipadm_refresh_dhcp(ipaddr);
+
+		/*
+		 * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since it is
+		 * only a soft error to indicate the caller that the lease might be
+		 * renewed after the function returns.
+		 */
+		if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
+			return (status);
+	}
+
+	status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags,
+	    IPADM_NVP_REQHOST);
+	return (status);
+}
+
+/*
+ * Used by address object property callback functions that need to do a
+ * two-stage update because the addrprop is cached on the address object.
+ */
+static ipadm_status_t
+i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
+			uint_t flags, const char *propname)
+{
+	ipadm_status_t	status;
+	uint32_t		two_stage_flags;
+
+	/*
+	 * Send the updated address object information to ipmgmtd, since the
+	 * cached version of an addrprop resides on an aobjmap, but do
+	 * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request
+	 * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage
+	 * per the existing aobjmap flags and a second stage encoded in
+	 * IPADM_OPT_PERSIST_PROPS.
+	 */
+	two_stage_flags = (flags | IPADM_OPT_SET_PROPS)
+	    & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST);
+	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE)
+		two_stage_flags |= IPADM_OPT_ACTIVE;
+	if (ipaddr->ipadm_flags & IPMGMT_PERSIST)
+		two_stage_flags |= IPADM_OPT_PERSIST;
+	if (flags & IPADM_OPT_PERSIST)
+		two_stage_flags |= IPADM_OPT_PERSIST_PROPS;
+
+	status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags,
+	    propname);
+	return (status);
+}
+
+/*
  * Callback function that gets the property `broadcast' for the address
  * object in `arg'.
  */
@@ -1371,6 +1479,78 @@
 	return (IPADM_SUCCESS);
 }
 
+/*
+ * Callback function that retrieves the value of the property `primary'
+ * for the address object in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_primary(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
+    uint_t valtype)
+{
+	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
+	const char *	onoff = "";
+	size_t		nbytes;
+
+	switch (valtype) {
+	case MOD_PROP_DEFAULT:
+		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
+			onoff = IPADM_OFFSTR;
+		break;
+	case MOD_PROP_ACTIVE:
+		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
+			onoff = ipaddr->ipadm_primary ? IPADM_ONSTR : IPADM_OFFSTR;
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+
+	nbytes = strlcpy(buf, onoff, *bufsize);
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Callback function that retrieves the value of the property `reqhost'
+ * for the address object in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
+    uint_t valtype)
+{
+	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
+	const char *	reqhost = "";
+	size_t		nbytes;
+
+	switch (valtype) {
+	case MOD_PROP_DEFAULT:
+		break;
+	case MOD_PROP_ACTIVE:
+		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
+			reqhost = ipaddr->ipadm_reqhost;
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+
+	nbytes = strlcpy(buf, reqhost, *bufsize);
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+
+	return (IPADM_SUCCESS);
+}
+
 static ipadm_prop_desc_t *
 i_ipadm_get_addrprop_desc(const char *pname)
 {
@@ -1775,6 +1955,7 @@
 
 	return (IPADM_SUCCESS);
 }
+
 /*
  * Set up tunnel destination address in ipaddr by contacting DNS.
  * The function works similar to ipadm_set_addr().
@@ -1901,6 +2082,28 @@
 }
 
 /*
+ * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr',
+ * but validate any non-nil value using ipadm_is_valid_hostname() and also
+ * check length.
+ */
+ipadm_status_t
+ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost)
+{
+	const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost);
+
+	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
+		return (IPADM_INVALID_ARG);
+
+	if (ipadm_is_nil_hostname(reqhost))
+		*ipaddr->ipadm_reqhost = '\0';
+	else if (!ipadm_is_valid_hostname(reqhost))
+		return (IPADM_INVALID_ARG);
+	else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN)
+		return (IPADM_INVALID_ARG);
+	return (IPADM_SUCCESS);
+}
+
+/*
  * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
  * If the `aobjname' already exists in the daemon's `aobjmap' then
  * IPADM_ADDROBJ_EXISTS will be returned.
@@ -2050,14 +2253,15 @@
 ipadm_status_t
 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
 {
-	int32_t			wait;
-	boolean_t		primary;
-	nvlist_t		*nvdhcp;
+	int32_t			wait = IPADM_DHCP_WAIT_DEFAULT;
+	boolean_t		primary = B_FALSE;
+	nvlist_t		*nvdhcp = NULL;
 	nvpair_t		*nvp;
 	char			*name;
 	struct ipadm_addrobj_s	ipaddr;
-	char			*aobjname;
+	char			*aobjname = NULL, *reqhost = NULL;
 	int			err = 0;
+	ipadm_status_t	ipadm_err = IPADM_SUCCESS;
 
 	/* Extract the dhcp parameters */
 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
@@ -2067,6 +2271,8 @@
 			err = nvpair_value_nvlist(nvp, &nvdhcp);
 		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
 			err = nvpair_value_string(nvp, &aobjname);
+		else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
+			err = nvpair_value_string(nvp, &reqhost);
 		if (err != 0)
 			return (ipadm_errno2status(err));
 	}
@@ -2088,6 +2294,9 @@
 		ipaddr.ipadm_wait = 0;
 	else
 		ipaddr.ipadm_wait = wait;
+	ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
+	if (ipadm_err != IPADM_SUCCESS)
+		return ipadm_err;
 	ipaddr.ipadm_af = AF_INET;
 	return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
 }
@@ -2730,7 +2939,7 @@
 			}
 		}
 		status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
-		    flags);
+		    flags, NULL);
 	}
 ret:
 	if (status != IPADM_SUCCESS && !legacy)
@@ -2887,7 +3096,7 @@
 	dh_status = status;
 
 	/* Persist the address object information in ipmgmtd. */
-	status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags);
+	status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
 	if (status != IPADM_SUCCESS)
 		goto fail;
 
@@ -2947,6 +3156,10 @@
 {
 	dhcp_ipc_request_t	*request;
 	dhcp_ipc_reply_t	*reply	= NULL;
+	dhcp_symbol_t		*entry = NULL;
+	dhcp_data_type_t	dtype = DHCP_TYPE_NONE;
+	void				*d4o = NULL;
+	uint16_t			d4olen = 0;
 	char			ifname[LIFNAMSIZ];
 	int			error;
 	int			dhcp_timeout;
@@ -2956,9 +3169,38 @@
 	i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
 	if (addr->ipadm_primary)
 		type |= DHCP_PRIMARY;
-	request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
-	if (request == NULL)
+
+	/* Set up a CD_HOSTNAME option, if applicable, to send through IPC */
+	switch (DHCP_IPC_CMD(type)) {
+	case DHCP_START:
+	case DHCP_EXTEND:
+		if (addr->ipadm_af == AF_INET && addr->ipadm_reqhost != NULL
+		    && *addr->ipadm_reqhost != '\0')
+		{
+			entry = inittab_getbycode(ITAB_CAT_STANDARD, ITAB_CONS_INFO,
+			    CD_HOSTNAME);
+			if (entry == NULL) {
+				return (IPADM_FAILURE);
+			} else {
+				d4o = inittab_encode(entry, addr->ipadm_reqhost, &d4olen,
+				    B_FALSE);
+				free(entry);
+				entry = NULL;
+				if (d4o == NULL)
+					return (IPADM_FAILURE);
+				dtype = DHCP_TYPE_OPTION;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype);
+	if (request == NULL) {
+		free(d4o);
 		return (IPADM_NO_MEMORY);
+	}
 
 	if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
 		dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
@@ -2969,6 +3211,7 @@
 	/* Send the message to dhcpagent. */
 	error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
 	free(request);
+	free(d4o);
 	if (error == 0) {
 		error = reply->return_code;
 		free(reply);
@@ -3026,21 +3269,19 @@
 
 /*
  * Makes a door call to ipmgmtd to update its `aobjmap' with the address
- * object in `ipaddr'. This door call also updates the persistent DB to
+ * object in `ipaddr'. This door call also can update the persistent DB to
  * remember address object to be recreated on next reboot or on an
  * ipadm_enable_addr()/ipadm_enable_if() call.
  */
 ipadm_status_t
 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
-    boolean_t default_prefixlen, uint32_t flags)
+    boolean_t default_prefixlen, uint32_t flags, const char *propname)
 {
 	char			*aname = ipaddr->ipadm_aobjname;
 	nvlist_t		*nvl;
 	int			err = 0;
 	ipadm_status_t		status;
-	char			pval[MAXPROPVALLEN];
 	uint_t			pflags = 0;
-	ipadm_prop_desc_t	*pdp = NULL;
 
 	/*
 	 * Construct the nvl to send to the door.
@@ -3060,8 +3301,6 @@
 		status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
 		if (status != IPADM_SUCCESS)
 			goto ret;
-		(void) snprintf(pval, sizeof (pval), "%d",
-		    ipaddr->ipadm_static_prefixlen);
 		if (flags & IPADM_OPT_UP)
 			err = nvlist_add_string(nvl, "up", "yes");
 		else
@@ -3071,6 +3310,18 @@
 	case IPADM_ADDR_DHCP:
 		status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
 		    ipaddr->ipadm_wait);
+		if (status != IPADM_SUCCESS)
+			goto ret;
+
+		/*
+		 * For purposes of updating the ipmgmtd cached representation of
+		 * reqhost (ipmgmt_am_reqhost), include a value here in `nvl', but
+		 * the value is actually fully persisted as a separate
+		 * i_ipadm_persist_propval below.
+		 */
+		err = nvlist_add_string(nvl, IPADM_NVP_REQHOST,
+		    ipaddr->ipadm_reqhost);
+		status = ipadm_errno2status(err);
 		break;
 	case IPADM_ADDR_IPV6_ADDRCONF:
 		status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
@@ -3094,25 +3345,62 @@
 			pflags |= IPMGMT_ACTIVE;
 		if (flags & IPADM_OPT_PERSIST)
 			pflags |= IPMGMT_PERSIST;
+		if (flags & IPADM_OPT_SET_PROPS)
+			pflags |= IPMGMT_PROPS_ONLY;
 	}
 	status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
-	/*
-	 * prefixlen is stored in a separate line in the DB and not along
-	 * with the address itself, since it is also an address property and
-	 * all address properties are stored in separate lines. We need to
-	 * persist the prefixlen by calling the function that persists
-	 * address properties.
-	 */
-	if (status == IPADM_SUCCESS && !default_prefixlen &&
-	    ipaddr->ipadm_atype == IPADM_ADDR_STATIC &&
-	    (flags & IPADM_OPT_PERSIST)) {
-		for (pdp = ipadm_addrprop_table; pdp->ipd_name != NULL; pdp++) {
-			if (strcmp("prefixlen", pdp->ipd_name) == 0)
-				break;
+
+	if (flags & IPADM_OPT_SET_PROPS) {
+		/*
+		 * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
+		 * SET_PROPS bits.
+		 */
+		flags |= IPADM_OPT_ACTIVE;
+		if (flags & IPADM_OPT_PERSIST_PROPS)
+			flags |= IPADM_OPT_PERSIST;
+		else
+			flags &= ~IPADM_OPT_PERSIST;
+		flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS);
+	}
+
+	if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) {
+		char	pbuf[MAXPROPVALLEN], *pval = NULL;
+		ipadm_prop_desc_t	*pdp = NULL;
+
+		/*
+		 * addprop properties are stored on separate lines in the DB and
+		 * not along with the address itself. Call the function that
+		 * persists address properties.
+		 */
+
+		switch (ipaddr->ipadm_atype) {
+		case IPADM_ADDR_STATIC:
+			if (!default_prefixlen && (propname == NULL ||
+			    strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) {
+				pdp = i_ipadm_get_addrprop_desc(IPADM_NVP_PREFIXLEN);
+				(void) snprintf(pbuf, sizeof (pbuf), "%u",
+				    ipaddr->ipadm_static_prefixlen);
+				pval = pbuf;
+			}
+			break;
+		case IPADM_ADDR_DHCP:
+			if (propname == NULL ||
+			    strcmp(propname, IPADM_NVP_REQHOST) == 0) {
+				pdp = i_ipadm_get_addrprop_desc(IPADM_NVP_REQHOST);
+				pval = ipaddr->ipadm_reqhost;
+			}
+			break;
+		default:
+			break;
 		}
-		assert(pdp != NULL);
-		status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
+
+		if (pval != NULL) {
+			assert(pdp != NULL);
+			status = i_ipadm_persist_propval(iph, pdp, pval,
+				ipaddr, flags);
+		}
 	}
+
 ret:
 	nvlist_free(nvl);
 	return (status);
@@ -3322,7 +3610,6 @@
 	char			lifname[LIFNAMSIZ];
 	boolean_t		inform =
 	    ((ipadm_flags & IPADM_OPT_INFORM) != 0);
-	int			dherr;
 
 	/* check for solaris.network.interface.config authorization */
 	if (!ipadm_check_auth())
@@ -3364,15 +3651,7 @@
 			return (IPADM_SUCCESS);
 		status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
 	} else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
-		status = i_ipadm_op_dhcp(&ipaddr, DHCP_EXTEND, &dherr);
-		/*
-		 * Restart the dhcp address negotiation with server if no
-		 * address has been acquired yet.
-		 */
-		if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
-			ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
-			status = i_ipadm_op_dhcp(&ipaddr, DHCP_START, NULL);
-		}
+		status = i_ipadm_refresh_dhcp(&ipaddr);
 	} else {
 		status = IPADM_NOTSUP;
 	}
@@ -3380,6 +3659,30 @@
 }
 
 /*
+ * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to
+ * send a DHCP_EXTEND message and possibly a DHCP_START message
+ * to the dhcpagent.
+ */
+static ipadm_status_t
+i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)
+{
+	ipadm_status_t		status;
+	int			dherr;
+
+	status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr);
+	/*
+	 * Restart the dhcp address negotiation with server if no
+	 * address has been acquired yet.
+	 */
+	if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
+		ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
+		status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
+	}
+
+	return (status);
+}
+
+/*
  * This is called from ipadm_create_addr() to validate the address parameters.
  * It does the following steps:
  * 1. Validates the interface name.
@@ -3494,29 +3797,41 @@
 }
 
 ipadm_status_t
-i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl,
+i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
     const char *aobjname)
 {
-	nvpair_t	*nvp, *prefixnvp;
+	const char * const	ADDRPROPS[] =
+	    { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST };
+	const size_t		ADDRPROPSLEN =
+	    sizeof (ADDRPROPS) / sizeof (*ADDRPROPS);
+	nvpair_t	*nvp, *propnvp;
 	nvlist_t	*tnvl;
 	char		*aname;
+	const char	*propname;
+	size_t		i;
 	int		err;
 
-	for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
-	    nvp = nvlist_next_nvpair(invl, nvp)) {
-		if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
-		    nvlist_exists(tnvl, IPADM_NVP_PREFIXLEN) &&
-		    nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
-		    &aname) == 0 && strcmp(aname, aobjname) == 0) {
-			/* prefixlen exists for given address object */
-			(void) nvlist_lookup_nvpair(tnvl, IPADM_NVP_PREFIXLEN,
-			    &prefixnvp);
-			err = nvlist_add_nvpair(onvl, prefixnvp);
-			if (err == 0) {
-				err = nvlist_remove(invl, nvpair_name(nvp),
-				    nvpair_type(nvp));
+	for (i = 0; i < ADDRPROPSLEN; ++i) {
+		propname = ADDRPROPS[i];
+
+		for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
+			nvp = nvlist_next_nvpair(invl, nvp)) {
+			if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
+			    nvlist_exists(tnvl, propname) &&
+			    nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
+			    &aname) == 0 && strcmp(aname, aobjname) == 0) {
+
+				/* property named `propname' exists for given aobj */
+				(void) nvlist_lookup_nvpair(tnvl, propname, &propnvp);
+				err = nvlist_add_nvpair(onvl, propnvp);
+				if (err == 0) {
+					err = nvlist_remove(invl, nvpair_name(nvp),
+					    nvpair_type(nvp));
+				}
+				if (err != 0)
+					return (ipadm_errno2status(err));
+				break;
 			}
-			return (ipadm_errno2status(err));
 		}
 	}
 	return (IPADM_SUCCESS);
@@ -3565,8 +3880,9 @@
 			continue;
 
 		if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
-		    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
-			status = i_ipadm_merge_prefixlen_from_nvl(addrnvl, nvl,
+		    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
+		    nvlist_exists(nvl, IPADM_NVP_DHCP)) {
+			status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
 			    aobjname);
 			if (status != IPADM_SUCCESS)
 				continue;
