Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
@@ -19,10 +19,11 @@
* CDDL HEADER END
*/
/*
* 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>.
*/
/*
* This file contains functions for address management such as creating
* an address, deleting an address, enabling an address, disabling an
@@ -30,10 +31,11 @@
* on an address object and listing address information
* for all addresses in active as well as persistent configuration.
*/
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/param.h>
#include <netdb.h>
#include <inet/ip.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
@@ -46,10 +48,12 @@
#include <arpa/inet.h>
#include <fcntl.h>
#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>
#include <libdliptun.h>
#include <ifaddrs.h>
@@ -62,10 +66,11 @@
uint32_t);
static ipadm_status_t i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
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,
int *);
static ipadm_status_t i_ipadm_validate_create_addr(ipadm_handle_t,
@@ -75,44 +80,61 @@
static ipadm_status_t i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
uint32_t *);
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
* functions, when required, translate the values from the kernel to a format
* suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
* 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,
NULL, NULL, i_ipadm_get_broadcast },
{ "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
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 },
{ "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
i_ipadm_set_zone, NULL, i_ipadm_get_zone },
@@ -199,13 +221,21 @@
sizeof (ipaddr->ipadm_ifname));
ipaddr->ipadm_lifnum = rval.ir_lnum;
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);
}
@@ -1039,10 +1069,88 @@
return (IPADM_SUCCESS);
}
/*
+ * 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'.
*/
/* ARGSUSED */
static ipadm_status_t
@@ -1369,10 +1477,82 @@
}
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)
{
int i;
@@ -1773,10 +1953,11 @@
}
*addr = ipaddr->ipadm_static_addr;
return (IPADM_SUCCESS);
}
+
/*
* Set up tunnel destination address in ipaddr by contacting DNS.
* The function works similar to ipadm_set_addr().
* The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
* if dst_addr resolves to more than one address. The caller has to verify
@@ -1899,10 +2080,32 @@
ipaddr->ipadm_wait = wait;
return (IPADM_SUCCESS);
}
/*
+ * 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.
*
* If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
@@ -2048,27 +2251,30 @@
* IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
*/
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;
nvp = nvlist_next_nvpair(nvl, nvp)) {
name = nvpair_name(nvp);
if (strcmp(name, IPADM_NVP_DHCP) == 0)
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));
}
for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
@@ -2086,10 +2292,13 @@
ipaddr.ipadm_primary = primary;
if (iph->iph_flags & IPH_INIT)
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));
}
/*
@@ -2728,11 +2937,11 @@
legacy_addr.ipadm_lifnum >= 0) {
return (status);
}
}
status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
- flags);
+ flags, NULL);
}
ret:
if (status != IPADM_SUCCESS && !legacy)
(void) i_ipadm_delete_addr(iph, ipaddr);
return (status);
@@ -2885,11 +3094,11 @@
if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
goto fail;
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;
return (dh_status);
fail:
@@ -2945,22 +3154,55 @@
static ipadm_status_t
i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
{
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;
/* Construct a message to the dhcpagent. */
bzero(&ifname, sizeof (ifname));
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;
else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
@@ -2967,10 +3209,11 @@
else
dhcp_timeout = addr->ipadm_wait;
/* 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);
}
if (error != 0) {
@@ -3024,25 +3267,23 @@
freeifaddrs((struct ifaddrs *)ainfo);
}
/*
* 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.
*/
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
@@ -3058,21 +3299,31 @@
switch (ipaddr->ipadm_atype) {
case IPADM_ADDR_STATIC:
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
err = nvlist_add_string(nvl, "up", "no");
status = ipadm_errno2status(err);
break;
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);
break;
}
@@ -3092,29 +3343,66 @@
} else {
if (flags & IPADM_OPT_ACTIVE)
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);
+
+ if (flags & IPADM_OPT_SET_PROPS) {
/*
- * 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.
+ * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
+ * SET_PROPS bits.
*/
- 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)
+ 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;
+ }
+
+ if (pval != NULL) {
assert(pdp != NULL);
- status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
+ status = i_ipadm_persist_propval(iph, pdp, pval,
+ ipaddr, flags);
}
+ }
+
ret:
nvlist_free(nvl);
return (status);
}
@@ -3320,11 +3608,10 @@
struct ipadm_addrobj_s ipaddr;
sa_family_t af;
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())
return (IPADM_EAUTH);
@@ -3362,22 +3649,38 @@
}
if (!(flags & IFF_DUPLICATE))
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);
+ status = i_ipadm_refresh_dhcp(&ipaddr);
+ } else {
+ status = IPADM_NOTSUP;
+ }
+ return (status);
+}
+
+/*
+ * 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);
+ ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
+ status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
}
- } else {
- status = IPADM_NOTSUP;
- }
+
return (status);
}
/*
* This is called from ipadm_create_addr() to validate the address parameters.
@@ -3492,35 +3795,47 @@
return (IPADM_SUCCESS);
}
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 (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, IPADM_NVP_PREFIXLEN) &&
+ nvlist_exists(tnvl, propname) &&
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);
+
+ /* 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_SUCCESS);
}
/*
* Re-enables the address object `aobjname' based on the saved
@@ -3563,12 +3878,13 @@
nvp = nvlist_next_nvpair(addrnvl, nvp)) {
if (nvpair_value_nvlist(nvp, &nvl) != 0)
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;
}
iph->iph_flags |= IPH_INIT;