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;