Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
*** 19,28 ****
--- 19,29 ----
* 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,39 ****
--- 31,41 ----
* 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,55 ****
--- 48,59 ----
#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,71 ****
--- 66,76 ----
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,118 ****
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 *);
/*
* 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;
/*
* 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().
*/
static ipadm_pd_setf_t i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
! i_ipadm_set_zone;
/* 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,
i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
i_ipadm_get_prefixlen },
{ "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
{ "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 },
--- 80,140 ----
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_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(); 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_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 },
! { 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,211 ****
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));
}
return (IPADM_SUCCESS);
}
--- 221,241 ----
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;
! 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,1048 ****
--- 1069,1156 ----
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,1378 ****
--- 1477,1558 ----
}
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,1782 ****
--- 1953,1963 ----
}
*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,1908 ****
--- 2080,2111 ----
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,2074 ****
* 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;
nvpair_t *nvp;
char *name;
struct ipadm_addrobj_s ipaddr;
! char *aobjname;
int err = 0;
/* 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);
if (err != 0)
return (ipadm_errno2status(err));
}
for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
--- 2251,2280 ----
* 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 = 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 = 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,2095 ****
--- 2292,2304 ----
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,2738 ****
legacy_addr.ipadm_lifnum >= 0) {
return (status);
}
}
status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
! flags);
}
ret:
if (status != IPADM_SUCCESS && !legacy)
(void) i_ipadm_delete_addr(iph, ipaddr);
return (status);
--- 2937,2947 ----
legacy_addr.ipadm_lifnum >= 0) {
return (status);
}
}
status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
! flags, NULL);
}
ret:
if (status != IPADM_SUCCESS && !legacy)
(void) i_ipadm_delete_addr(iph, ipaddr);
return (status);
*** 2885,2895 ****
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);
if (status != IPADM_SUCCESS)
goto fail;
return (dh_status);
fail:
--- 3094,3104 ----
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, NULL);
if (status != IPADM_SUCCESS)
goto fail;
return (dh_status);
fail:
*** 2945,2966 ****
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;
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)
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;
--- 3154,3208 ----
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;
!
! /* 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,2976 ****
--- 3209,3219 ----
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,3048 ****
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
* 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)
{
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)
--- 3267,3289 ----
freeifaddrs((struct ifaddrs *)ainfo);
}
/*
* Makes a door call to ipmgmtd to update its `aobjmap' with the address
! * 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, const char *propname)
{
char *aname = ipaddr->ipadm_aobjname;
nvlist_t *nvl;
int err = 0;
ipadm_status_t status;
uint_t pflags = 0;
/*
* Construct the nvl to send to the door.
*/
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
*** 3058,3078 ****
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);
break;
case IPADM_ADDR_IPV6_ADDRCONF:
status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
break;
}
--- 3299,3329 ----
switch (ipaddr->ipadm_atype) {
case IPADM_ADDR_STATIC:
status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
if (status != IPADM_SUCCESS)
goto ret;
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,3120 ****
} else {
if (flags & IPADM_OPT_ACTIVE)
pflags |= IPMGMT_ACTIVE;
if (flags & IPADM_OPT_PERSIST)
pflags |= IPMGMT_PERSIST;
}
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;
}
assert(pdp != NULL);
! status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
}
ret:
nvlist_free(nvl);
return (status);
}
--- 3343,3408 ----
} 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) {
/*
! * 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;
+ }
+
+ if (pval != NULL) {
assert(pdp != NULL);
! status = i_ipadm_persist_propval(iph, pdp, pval,
! ipaddr, flags);
}
+ }
+
ret:
nvlist_free(nvl);
return (status);
}
*** 3320,3330 ****
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);
--- 3608,3617 ----
*** 3362,3383 ****
}
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);
/*
* 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);
}
! } else {
! status = IPADM_NOTSUP;
! }
return (status);
}
/*
* This is called from ipadm_create_addr() to validate the address parameters.
--- 3649,3686 ----
}
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_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);
}
!
return (status);
}
/*
* This is called from ipadm_create_addr() to validate the address parameters.
*** 3492,3526 ****
return (IPADM_SUCCESS);
}
ipadm_status_t
! i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl,
const char *aobjname)
{
! nvpair_t *nvp, *prefixnvp;
nvlist_t *tnvl;
char *aname;
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));
}
return (ipadm_errno2status(err));
}
}
return (IPADM_SUCCESS);
}
/*
* Re-enables the address object `aobjname' based on the saved
--- 3795,3841 ----
return (IPADM_SUCCESS);
}
ipadm_status_t
! i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
const char *aobjname)
{
! 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, 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_SUCCESS);
}
/*
* Re-enables the address object `aobjname' based on the saved
*** 3563,3574 ****
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,
aobjname);
if (status != IPADM_SUCCESS)
continue;
}
iph->iph_flags |= IPH_INIT;
--- 3878,3890 ----
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) ||
! 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;