summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2017-09-13 11:45:18 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2017-09-13 11:45:18 +0000
commitb34e44c2aefdd578084f80084c5ad0566f74694f (patch)
tree7a9d1e4ddfe18e6af0790b9d8fd8ee2255668f37
parent7bfe322ee94b337d8bc759f81b83d026f599b267 (diff)
parent2ee1ed1ec5dfdf07d2c92db58b11f630de2a6e87 (diff)
downloadillumos-joyent-b34e44c2aefdd578084f80084c5ad0566f74694f.tar.gz
[illumos-gate merge]
commit 2ee1ed1ec5dfdf07d2c92db58b11f630de2a6e87 7388 Support -h <hostname> for ipadm DHCP (fix man lint) commit b31320a79e2054c6739b5229259dbf98f3afc547 7388 Support -h <hostname> for ipadm DHCP 8517 Add ipadm and nwam options to allow designating a DHCP address as the primary interface 8518 Allow using system-generated IAID/DUID for all DHCPv4 8519 Add ns_name_pton2 to libresolv2 mapfile commit c6e58d8c85cf3e5d0db157501b40276eb59edf16 8479 nvmeadm doesn't handle namespaces with EUI64 commit faeab80b5dcf1bc503f1f02494131eb0e6da46c3 8649 SD_RESET_THROTTLE_TIMEOUT is defined twice
-rw-r--r--usr/src/cmd/cmd-inet/etc/dhcp/inittab5
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c60
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h18
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c71
-rw-r--r--usr/src/cmd/cmd-inet/lib/nwamd/ncu.c70
-rw-r--r--usr/src/cmd/cmd-inet/lib/nwamd/ncu.h3
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile4
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c166
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c3
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c7
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.h7
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/dhcpagent.dfl68
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c29
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/ipc_action.c9
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c79
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h5
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c4
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c6
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c28
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c19
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h14
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c568
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/util.h5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c41
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile3
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c24
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y25
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l3
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.c1
-rw-r--r--usr/src/common/net/dhcp/dhcp_impl.h8
-rw-r--r--usr/src/head/arpa/nameser.h3
-rw-r--r--usr/src/lib/Makefile5
-rw-r--r--usr/src/lib/libipadm/Makefile.com3
-rw-r--r--usr/src/lib/libipadm/common/ipadm_addr.c525
-rw-r--r--usr/src/lib/libipadm/common/ipadm_ipmgmt.h32
-rw-r--r--usr/src/lib/libipadm/common/ipadm_ndpd.c3
-rw-r--r--usr/src/lib/libipadm/common/libipadm.c87
-rw-r--r--usr/src/lib/libipadm/common/libipadm.h25
-rw-r--r--usr/src/lib/libipadm/common/libipadm_impl.h8
-rw-r--r--usr/src/lib/libipadm/common/mapfile-vers4
-rw-r--r--usr/src/lib/libnwam/Makefile.com4
-rw-r--r--usr/src/lib/libnwam/common/libnwam.h3
-rw-r--r--usr/src/lib/libnwam/common/libnwam_ncp.c25
-rw-r--r--usr/src/lib/libresolv2/common/mapfile-vers2
-rw-r--r--usr/src/man/man1m/dhcpagent.1m187
-rw-r--r--usr/src/man/man1m/ipadm.1m53
-rw-r--r--usr/src/man/man4/dhcp_inittab.413
-rw-r--r--usr/src/uts/common/netinet/dhcp.h10
-rw-r--r--usr/src/uts/common/sys/scsi/targets/sddef.h6
50 files changed, 2019 insertions, 337 deletions
diff --git a/usr/src/cmd/cmd-inet/etc/dhcp/inittab b/usr/src/cmd/cmd-inet/etc/dhcp/inittab
index 42a0d099c6..162183939d 100644
--- a/usr/src/cmd/cmd-inet/etc/dhcp/inittab
+++ b/usr/src/cmd/cmd-inet/etc/dhcp/inittab
@@ -1,6 +1,7 @@
#
# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
# CDDL HEADER START
#
@@ -22,7 +23,6 @@
#
# CDDL HEADER END
#
-# ident "%Z%%M% %I% %E% SMI"
#
# This file provides information about all supported DHCP options, for
# use by DHCP-related programs. This file should only be modified to
@@ -114,6 +114,7 @@ STDAservs STANDARD, 76, IP, 1, 0, sdmi
UserClas STANDARD, 77, ASCII, 1, 0, sdi
SLP_DA STANDARD, 78, OCTET, 1, 0, sdmi
SLP_SS STANDARD, 79, OCTET, 1, 0, sdmi
+ClientFQDN STANDARD, 81, OCTET, 1, 0, sdmi
AgentOpt STANDARD, 82, OCTET, 1, 0, sdi
FQDN STANDARD, 89, OCTET, 1, 0, sdmi
@@ -177,7 +178,7 @@ SHTTPproxy VENDOR, 17, ASCII, 1, 0, smi
# The following option describes an option named ipPairs, that is in
# the SITE category, meaning it is defined by each individual site.
# It is option code 132, which is of type IP Address, consisting of
-# a potentially infinite number of pairs of IP addresses. (See
+# a potentially infinite number of pairs of IP addresses. (See
# dhcp_inittab(4) for details)
#
# ipPairs SITE, 132, IP, 2, 0, sdmi
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
index 9f546bcad9..bb4ffcbf0e 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -236,8 +237,6 @@ i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
char *aobjname = NULL, *ifname = NULL;
int32_t lnum;
nvlist_t *nvladdr;
- struct sockaddr_storage addr;
- uint_t n;
sa_family_t af = AF_UNSPEC;
ipadm_addr_type_t addrtype = IPADM_ADDR_NONE;
int err = 0;
@@ -255,16 +254,37 @@ i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
af = AF_INET;
addrtype = IPADM_ADDR_STATIC;
- } else if (nvlist_exists(nvl, IPADM_NVP_DHCP)) {
+ } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) {
+ char *reqhost;
+
af = AF_INET;
addrtype = IPADM_ADDR_DHCP;
+
+ /*
+ * ipmgmt_am_reqhost comes through in `nvl' for purposes of
+ * updating the cached representation, but it is persisted as
+ * a stand-alone DB line; so remove it after copying it.
+ */
+ if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) {
+ *nodep->ipmgmt_am_reqhost = '\0';
+ } else {
+ if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST,
+ &reqhost)) != 0)
+ return (err);
+
+ (void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost,
+ sizeof (nodep->ipmgmt_am_reqhost));
+ (void) nvlist_remove(nvl, IPADM_NVP_REQHOST,
+ DATA_TYPE_STRING);
+ }
} else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
af = AF_INET6;
addrtype = IPADM_ADDR_STATIC;
} else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+ struct sockaddr_in6 sin6 = {0};
uint8_t *addr6;
uint32_t plen;
+ uint_t n;
af = AF_INET6;
addrtype = IPADM_ADDR_IPV6_ADDRCONF;
@@ -275,14 +295,15 @@ i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
if (nvlist_lookup_uint8_array(nvladdr,
IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
return (EINVAL);
- bcopy(addr6, &sin6->sin6_addr, n);
- } else {
- bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
+ bcopy(addr6, &sin6.sin6_addr, n);
}
+
+ nodep->ipmgmt_am_linklocal = B_TRUE;
+ nodep->ipmgmt_am_ifid = sin6;
}
/*
- * populate the `*nodep' with retrieved values.
+ * populate the non-addrtype-specific `*nodep' with retrieved values.
*/
(void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
(void) strlcpy(nodep->am_aobjname, aobjname,
@@ -290,10 +311,6 @@ i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
nodep->am_lnum = lnum;
nodep->am_family = af;
nodep->am_atype = addrtype;
- if (addrtype == IPADM_ADDR_IPV6_ADDRCONF) {
- nodep->am_linklocal = B_TRUE;
- nodep->am_ifid = addr;
- }
nodep->am_next = NULL;
/*
@@ -308,15 +325,15 @@ i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
/*
* Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
- * node to the list `aobjmap' and then persists the address information in the
- * DB.
+ * node to the list `aobjmap' and optionally persists the address
+ * information in the DB.
*/
static void
ipmgmt_setaddr_handler(void *argp)
{
ipmgmt_setaddr_arg_t *sargp = argp;
ipmgmt_retval_t rval;
- ipmgmt_aobjmap_t node;
+ ipmgmt_aobjmap_t node = {0};
nvlist_t *nvl = NULL;
char *nvlbuf;
size_t nvlsize = sargp->ia_nvlsize;
@@ -332,11 +349,11 @@ ipmgmt_setaddr_handler(void *argp)
if (flags & IPMGMT_INIT)
node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
else
- node.am_flags = flags;
+ node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
goto ret;
}
- if (flags & IPMGMT_PERSIST) {
+ if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
ipadm_dbwrite_cbarg_t cb;
cb.dbw_nvl = nvl;
@@ -350,7 +367,7 @@ ret:
}
/*
- * Handles the door commands that modify the `aobjmap' structure.
+ * Handles the door commands that read or modify the `aobjmap' structure.
*
* IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
* after ensuring that the namespace is not taken. If required, also
@@ -452,7 +469,7 @@ ipmgmt_aobjop_handler(void *argp)
* have am_ifid set.
*/
if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
- head->am_linklocal) {
+ head->ipmgmt_am_linklocal) {
break;
}
}
@@ -467,9 +484,7 @@ ipmgmt_aobjop_handler(void *argp)
aobjrval.ir_family = head->am_family;
aobjrval.ir_flags = head->am_flags;
aobjrval.ir_atype = head->am_atype;
- if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF &&
- head->am_linklocal)
- aobjrval.ir_ifid = head->am_ifid;
+ aobjrval.ir_atype_cache = head->am_atype_cache;
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
break;
case IPMGMT_CMD_LIF2ADDROBJ:
@@ -498,6 +513,7 @@ ipmgmt_aobjop_handler(void *argp)
sizeof (aobjrval.ir_aobjname));
aobjrval.ir_atype = head->am_atype;
aobjrval.ir_flags = head->am_flags;
+ aobjrval.ir_atype_cache = head->am_atype_cache;
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
break;
default:
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
index 32d752a6eb..f4d6d30645 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Joyent, Inc.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _IPMGMT_IMPL_H
@@ -104,8 +105,11 @@ extern db_wfunc_t ipmgmt_db_initif;
* of `aobjname'.
* - address type (static, dhcp or addrconf)
* - `am_flags' indicates if this addrobj in active and/or persist config
- * - if `am_atype' is IPADM_ADDR_IPV6_ADDRCONF then `am_ifid' holds the
- * interface-id used to configure auto-configured addresses
+ * - other, ipadm_addr_type_t-specific values are cached in
+ * am_addr_cache (see type ipmgmt_addr_cache_u):
+ * - ipv6: ipmgmt_am_linklocal (macro)
+ * - ipv6: ipmgmt_am_ifid (macro)
+ * - dhcp: ipmgmt_am_reqhost (macro)
*/
typedef struct ipmgmt_aobjmap_s {
struct ipmgmt_aobjmap_s *am_next;
@@ -116,10 +120,16 @@ typedef struct ipmgmt_aobjmap_s {
ipadm_addr_type_t am_atype;
uint32_t am_nextnum;
uint32_t am_flags;
- boolean_t am_linklocal;
- struct sockaddr_storage am_ifid;
+ ipmgmt_addr_type_cache_u am_atype_cache;
} ipmgmt_aobjmap_t;
+#define ipmgmt_am_linklocal \
+ am_atype_cache.ipmgmt_ipv6_cache_s.ipmgmt_linklocal
+#define ipmgmt_am_ifid \
+ am_atype_cache.ipmgmt_ipv6_cache_s.ipmgmt_ifid
+#define ipmgmt_am_reqhost \
+ am_atype_cache.ipmgmt_dhcp_cache_s.ipmgmt_reqhost
+
/* linked list of `aobjmap' nodes, protected by RW lock */
typedef struct ipmgmt_aobjmap_list_s {
ipmgmt_aobjmap_t *aobjmap_head;
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
index 8718abae3e..5950562fd6 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
@@ -23,6 +23,7 @@
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Joyent, Inc.
* Copyright 2016 Argo Technologie SA.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -918,7 +919,8 @@ ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
if (strcmp(head->am_aobjname,
nodep->am_aobjname) == 0 &&
(head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
- head->am_linklocal == nodep->am_linklocal))
+ head->ipmgmt_am_linklocal ==
+ nodep->ipmgmt_am_linklocal))
break;
}
@@ -930,10 +932,7 @@ ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
head->am_family = nodep->am_family;
head->am_flags = nodep->am_flags;
head->am_atype = nodep->am_atype;
- if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
- head->am_ifid = nodep->am_ifid;
- head->am_linklocal = nodep->am_linklocal;
- }
+ head->am_atype_cache = nodep->am_atype_cache;
} else {
for (head = aobjmap.aobjmap_head; head != NULL;
head = head->am_next) {
@@ -1078,29 +1077,43 @@ i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
goto fail;
- if (np->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
- struct sockaddr_in6 *in6;
+ switch (np->am_atype) {
+ case IPADM_ADDR_IPV6_ADDRCONF: {
+ struct sockaddr_in6 *in6;
- in6 = (struct sockaddr_in6 *)&np->am_ifid;
- if (np->am_linklocal &&
- IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
- if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
- "default")) != 0)
- goto fail;
- } else {
- if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
- IPMGMT_STRSIZE) == NULL) {
- err = errno;
- goto fail;
+ in6 = &np->ipmgmt_am_ifid;
+ if (np->ipmgmt_am_linklocal &&
+ IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
+ if ((err = nvlist_add_string(*nvl,
+ IPADM_NVP_IPNUMADDR, "default")) != 0) {
+ goto fail;
+ }
+ } else {
+ if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
+ IPMGMT_STRSIZE) == NULL) {
+ err = errno;
+ goto fail;
+ }
+ if ((err = nvlist_add_string(*nvl,
+ IPADM_NVP_IPNUMADDR, strval)) != 0) {
+ goto fail;
+ }
}
- if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
- strval)) != 0)
+ }
+ break;
+ case IPADM_ADDR_DHCP: {
+ if (np->ipmgmt_am_reqhost &&
+ *np->ipmgmt_am_reqhost != '\0' &&
+ (err = nvlist_add_string(*nvl, IPADM_NVP_REQHOST,
+ np->ipmgmt_am_reqhost)) != 0)
goto fail;
}
- } else {
- if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
- "")) != 0)
- goto fail;
+ /* FALLTHRU */
+ default:
+ if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
+ "")) != 0)
+ goto fail;
+ break;
}
return (err);
fail:
@@ -1148,16 +1161,18 @@ ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
node.am_atype = (ipadm_addr_type_t)atoi(strval);
} else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
- in6 = (struct sockaddr_in6 *)&node.am_ifid;
+ in6 = &node.ipmgmt_am_ifid;
if (strcmp(strval, "default") == 0) {
- bzero(in6, sizeof (node.am_ifid));
- node.am_linklocal = B_TRUE;
+ bzero(in6,
+ sizeof (node.ipmgmt_am_ifid));
+ node.ipmgmt_am_linklocal = B_TRUE;
} else {
(void) inet_pton(AF_INET6, strval,
&in6->sin6_addr);
if (IN6_IS_ADDR_UNSPECIFIED(
&in6->sin6_addr))
- node.am_linklocal = B_TRUE;
+ node.ipmgmt_am_linklocal =
+ B_TRUE;
}
}
}
diff --git a/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c b/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c
index 52d03076f7..46b8391e51 100644
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <arpa/inet.h>
@@ -33,6 +34,7 @@
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>
+#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -128,6 +130,17 @@ nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh, nwam_value_t *val,
return (nwam_value_get_uint64_array(*val, uintval, cnt));
}
+nwam_error_t
+nwamd_get_ncu_boolean(nwam_ncu_handle_t ncuh, nwam_value_t *val,
+ boolean_t **boolval, uint_t *cnt, const char *prop)
+{
+ nwam_error_t err;
+
+ if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS)
+ return (err);
+ return (nwam_value_get_boolean_array(*val, boolval, cnt));
+}
+
/*
* Run link/interface state machine in response to a state change
* or enable/disable action event.
@@ -733,13 +746,13 @@ populate_ip_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
{
nwamd_if_t *nif = &ncu_data->ncu_if;
struct nwamd_if_address **nifa, *nifai, *nifait;
- boolean_t static_addr = B_FALSE;
+ boolean_t static_addr = B_FALSE, *boolvalue, dhcp_primary = B_FALSE;
uint64_t *addrsrcvalue;
nwam_value_t ncu_prop;
nwam_error_t err;
ipadm_addrobj_t ipaddr;
ipadm_status_t ipstatus;
- char **addrvalue;
+ char **addrvalue, ipreqhost[MAXNAMELEN];
uint_t numvalues;
uint64_t *ipversion;
int i;
@@ -776,6 +789,39 @@ populate_ip_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
nwam_value_free(ncu_prop);
}
+ /* ip-primary */
+ if ((err = nwamd_get_ncu_boolean(ncuh, &ncu_prop, &boolvalue,
+ &numvalues, NWAM_NCU_PROP_IP_PRIMARY)) != NWAM_SUCCESS) {
+ /* ip-primary is optional, so do not LOG_ERR */
+ nlog(LOG_DEBUG, "populate_ip_ncu_properties: "
+ "could not get %s value: %s",
+ NWAM_NCU_PROP_IP_PRIMARY, nwam_strerror(err));
+ } else {
+ if (numvalues > 0)
+ dhcp_primary = boolvalue[0];
+ nwam_value_free(ncu_prop);
+ }
+
+ /* ip-reqhost */
+ *ipreqhost = '\0';
+
+ if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
+ &numvalues, NWAM_NCU_PROP_IP_REQHOST)) != NWAM_SUCCESS) {
+ /* ip-reqhost is optional, so do not LOG_ERR */
+ nlog(LOG_DEBUG, "populate_ip_ncu_properties: "
+ "could not get %s value: %s",
+ NWAM_NCU_PROP_IP_REQHOST, nwam_strerror(err));
+ } else {
+ if (numvalues > 0 && strlcpy(ipreqhost, addrvalue[0],
+ sizeof (ipreqhost)) >= sizeof (ipreqhost)) {
+ nlog(LOG_WARNING, "populate_ip_ncu_properties: "
+ "too long %s value: %s",
+ NWAM_NCU_PROP_IP_REQHOST, addrvalue[0]);
+ *ipreqhost = '\0';
+ }
+ nwam_value_free(ncu_prop);
+ }
+
/* Free the old list. */
for (nifai = nif->nwamd_if_list; nifai != NULL; nifai = nifait) {
nifait = nifai->next;
@@ -828,6 +874,22 @@ populate_ip_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data)
ipadm_destroy_addrobj(ipaddr);
goto skip_ipv4_dhcp;
}
+ ipstatus = ipadm_set_primary(ipaddr, dhcp_primary);
+ if (ipstatus != IPADM_SUCCESS) {
+ nlog(LOG_ERR, "populate_ip_ncu_properties: "
+ "ipadm_set_primary failed for v4 dhcp: %s",
+ ipadm_status2str(ipstatus));
+ ipadm_destroy_addrobj(ipaddr);
+ goto skip_ipv4_dhcp;
+ }
+ ipstatus = ipadm_set_reqhost(ipaddr, ipreqhost);
+ if (ipstatus != IPADM_SUCCESS) {
+ nlog(LOG_ERR, "populate_ip_ncu_properties: "
+ "ipadm_set_reqhost failed for v4 dhcp: %s",
+ ipadm_status2str(ipstatus));
+ ipadm_destroy_addrobj(ipaddr);
+ goto skip_ipv4_dhcp;
+ }
if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) {
(*nifa)->family = AF_INET;
(*nifa)->ipaddr_atype = IPADM_ADDR_DHCP;
@@ -848,7 +910,7 @@ skip_ipv4_dhcp:
if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
&numvalues, NWAM_NCU_PROP_IPV4_ADDR)) != NWAM_SUCCESS) {
nlog(LOG_ERR, "populate_ip_ncu_properties: "
- "could not get %s value; %s",
+ "could not get %s value: %s",
NWAM_NCU_PROP_IPV4_ADDR, nwam_strerror(err));
} else {
for (i = 0; i < numvalues; i++) {
@@ -995,7 +1057,7 @@ skip_ipv6_addrconf:
if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue,
&numvalues, NWAM_NCU_PROP_IPV6_ADDR)) != NWAM_SUCCESS) {
nlog(LOG_ERR, "populate_ip_ncu_properties: "
- "could not get %s value; %s",
+ "could not get %s value: %s",
NWAM_NCU_PROP_IPV6_ADDR, nwam_strerror(err));
} else {
for (i = 0; i < numvalues; i++) {
diff --git a/usr/src/cmd/cmd-inet/lib/nwamd/ncu.h b/usr/src/cmd/cmd-inet/lib/nwamd/ncu.h
index a0c41751ec..7f0f5a1d7d 100644
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu.h
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _NCU_H
@@ -225,6 +226,8 @@ extern nwam_error_t nwamd_get_ncu_uint(nwam_ncu_handle_t, nwam_value_t *,
uint64_t **, uint_t *, const char *);
extern nwam_error_t nwamd_get_ncu_string(nwam_ncu_handle_t, nwam_value_t *,
char ***, uint_t *, const char *);
+extern nwam_error_t nwamd_get_ncu_boolean(nwam_ncu_handle_t, nwam_value_t *,
+ boolean_t **, uint_t *, const char *);
extern void nwamd_walk_physical_configuration(void);
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile b/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile
index 34c68c967b..f94222fc72 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile
@@ -21,6 +21,7 @@
#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
PROG = dhcpagent
@@ -45,7 +46,8 @@ CERRWARN += -_gcc=-Wno-parentheses
#
CPPFLAGS += -D_XOPEN_SOURCE=500 -D__EXTENSIONS__
-LDLIBS += -lxnet -lnvpair -ldhcpagent -ldhcputil -linetutil -ldevinfo -ldlpi
+LDLIBS += -lxnet -lnvpair -ldhcpagent -ldhcputil -linetutil -ldevinfo \
+ -ldlpi -lresolv -lsocket -lipadm
# Disable warnings that affect all XPG applications.
LINTFLAGS += -erroff=E_INCONS_ARG_DECL2 -erroff=E_INCONS_VAL_TYPE_DECL2
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c
index ef25380c32..812bb8e414 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#include <sys/types.h>
@@ -36,6 +37,8 @@
#include <dhcpagent_ipc.h>
#include <dhcpagent_util.h>
#include <dhcpmsg.h>
+#include <dhcp_inittab.h>
+#include <dhcp_symbol.h>
#include <netinet/dhcp.h>
#include <net/route.h>
#include <sys/sockio.h>
@@ -70,6 +73,10 @@ static boolean_t shutdown_started = B_FALSE;
static boolean_t do_adopt = B_FALSE;
static unsigned int debug_level = 0;
static iu_eh_callback_t accept_event, ipc_event, rtsock_event;
+static void dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp,
+ ipc_action_t *iap);
+static DHCP_OPT * dhcp_get_ack_or_state(const dhcp_smach_t *dsmp,
+ const PKT_LIST *plp, uint_t codenum, boolean_t *did_alloc);
/*
* The ipc_cmd_allowed[] table indicates which IPC commands are allowed in
@@ -754,6 +761,7 @@ ipc_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
break; /* not an immediate function */
case DHCP_EXTEND:
+ dhcp_smach_set_msg_reqhost(dsmp, iap);
(void) dhcp_extending(dsmp);
break;
@@ -793,8 +801,8 @@ load_option:
opt = dhcpv6_pkt_option(ack, NULL, optnum.code,
NULL);
} else {
- if (optnum.code <= DHCP_LAST_OPT)
- opt = ack->opts[optnum.code];
+ opt = dhcp_get_ack_or_state(dsmp, ack,
+ optnum.code, &did_alloc);
}
break;
@@ -876,11 +884,7 @@ load_option:
if (optnum.code + optnum.size > sizeof (PKT))
break;
- /*
- * + 2 to account for option code and length
- * byte
- */
- opt = malloc(optnum.size + 2);
+ opt = malloc(optnum.size + DHCP_OPT_META_LEN);
if (opt != NULL) {
DHCP_OPT *v4opt = opt;
@@ -905,8 +909,7 @@ load_option:
}
/*
- * return the option payload, if there was one. the "+ 2"
- * accounts for the option code number and length byte.
+ * return the option payload, if there was one.
*/
if (opt != NULL) {
@@ -916,7 +919,8 @@ load_option:
(void) memcpy(&d6ov, opt, sizeof (d6ov));
optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov);
} else {
- optlen = ((DHCP_OPT *)opt)->len + 2;
+ optlen = ((DHCP_OPT *)opt)->len +
+ DHCP_OPT_META_LEN;
}
send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen);
@@ -971,6 +975,7 @@ load_option:
PKT_LIST *plp[2];
deprecate_leases(dsmp);
+ dhcp_smach_set_msg_reqhost(dsmp, iap);
/*
* if we have a valid hostconf lying around, then jump
@@ -1059,6 +1064,147 @@ load_option:
}
/*
+ * dhcp_smach_set_msg_reqhost(): set dsm_msg_reqhost based on the message
+ * content of a DHCP IPC message
+ *
+ * input: dhcp_smach_t *: the state machine instance;
+ * ipc_action_t *: the decoded DHCP IPC message;
+ * output: void
+ */
+
+static void
+dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp, ipc_action_t *iap)
+{
+ DHCP_OPT *d4o;
+ dhcp_symbol_t *entry;
+ char *value;
+
+ if (dsmp->dsm_msg_reqhost != NULL) {
+ dhcpmsg(MSG_DEBUG,
+ "dhcp_smach_set_msg_reqhost: nullify former value, %s",
+ dsmp->dsm_msg_reqhost);
+ free(dsmp->dsm_msg_reqhost);
+ dsmp->dsm_msg_reqhost = NULL;
+ }
+
+ /*
+ * if a STANDARD/HOSTNAME was sent in the IPC request, then copy that
+ * value into the state machine data if decoding succeeds. Otherwise,
+ * log to indicate at what step the decoding stopped.
+ */
+
+ if (dsmp->dsm_isv6) {
+ dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: ipv6 is not"
+ " handled");
+ return;
+ } else if (iap->ia_request->data_type != DHCP_TYPE_OPTION) {
+ dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: request type"
+ " %d is not DHCP_TYPE_OPTION", iap->ia_request->data_type);
+ return;
+ }
+
+ if (iap->ia_request->buffer == NULL ||
+ iap->ia_request->data_length <= DHCP_OPT_META_LEN) {
+ dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:"
+ " DHCP_TYPE_OPTION ia_request buffer is NULL (0) or"
+ " short (1): %d",
+ iap->ia_request->buffer == NULL ? 0 : 1);
+ return;
+ }
+
+ d4o = (DHCP_OPT *)iap->ia_request->buffer;
+ if (d4o->code != CD_HOSTNAME) {
+ dhcpmsg(MSG_DEBUG,
+ "dhcp_smach_set_msg_reqhost: ignoring DHCPv4"
+ " option %u", d4o->code);
+ return;
+ } else if (iap->ia_request->data_length - DHCP_OPT_META_LEN
+ != d4o->len) {
+ dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:"
+ " unexpected DHCP_OPT buffer length %u for CD_HOSTNAME"
+ " option length %u", iap->ia_request->data_length,
+ d4o->len);
+ return;
+ }
+
+ entry = inittab_getbycode(ITAB_CAT_STANDARD, ITAB_CONS_INFO,
+ CD_HOSTNAME);
+ if (entry == NULL) {
+ dhcpmsg(MSG_WARNING,
+ "dhcp_smach_set_msg_reqhost: error getting"
+ " ITAB_CAT_STANDARD ITAB_CONS_INFO"
+ " CD_HOSTNAME entry");
+ return;
+ }
+
+ value = inittab_decode(entry, d4o->value, d4o->len,
+ /* just_payload */ B_TRUE);
+ if (value == NULL) {
+ dhcpmsg(MSG_WARNING,
+ "dhcp_smach_set_msg_reqhost: error decoding"
+ " CD_HOSTNAME value from DHCP_OPT");
+ } else {
+ dhcpmsg(MSG_DEBUG,
+ "dhcp_smach_set_msg_reqhost: host %s", value);
+ free(dsmp->dsm_msg_reqhost);
+ dsmp->dsm_msg_reqhost = value;
+ }
+ free(entry);
+}
+
+/*
+ * dhcp_get_ack_or_state(): get a v4 option from the ACK or from the state
+ * machine state for certain codes that are not ACKed (e.g., CD_CLIENT_ID)
+ *
+ * input: dhcp_smach_t *: the state machine instance;
+ * PKT_LIST *: the decoded DHCP IPC message;
+ * uint_t: the DHCP client option code;
+ * boolean_t *: a pointer to a value that will be set to B_TRUE if
+ * the return value must be freed (or else set to B_FALSE);
+ * output: the option if found or else NULL.
+ */
+
+static DHCP_OPT *
+dhcp_get_ack_or_state(const dhcp_smach_t *dsmp, const PKT_LIST *plp,
+ uint_t codenum, boolean_t *did_alloc)
+{
+ DHCP_OPT *opt;
+
+ *did_alloc = B_FALSE;
+
+ if (codenum > DHCP_LAST_OPT)
+ return (NULL);
+
+ /* check the ACK first for all codes */
+ opt = plp->opts[codenum];
+ if (opt != NULL)
+ return (opt);
+
+ /* check the machine state also for certain codes */
+ switch (codenum) {
+ case CD_CLIENT_ID:
+ /*
+ * CD_CLIENT_ID is not sent in an ACK, but it's possibly
+ * available from the state machine data
+ */
+
+ if (dsmp->dsm_cidlen > 0) {
+ if ((opt = malloc(dsmp->dsm_cidlen + DHCP_OPT_META_LEN))
+ != NULL) {
+ *did_alloc = B_TRUE;
+ (void) encode_dhcp_opt(opt,
+ B_FALSE /* is IPv6 */, CD_CLIENT_ID,
+ dsmp->dsm_cid, dsmp->dsm_cidlen);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return (opt);
+}
+
+/*
* check_rtm_addr(): determine if routing socket message matches interface
* address
*
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c
index 9907b8397d..1acf2d5626 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Chris Fraire <cfraire@me.com>.
*
* BOUND state of the DHCP client state machine.
*/
@@ -106,6 +107,8 @@ dhcp_bound(dhcp_smach_t *dsmp, PKT_LIST *ack)
/* Save the first ack as the original */
if (dsmp->dsm_orig_ack == NULL)
dsmp->dsm_orig_ack = ack;
+
+ save_domainname(dsmp, ack);
}
oldstate = dsmp->dsm_state;
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c
index ac94cec99b..e6a88304a7 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#include <sys/types.h>
@@ -60,7 +61,11 @@ static struct dhcp_default defaults[] = {
{ "DEBUG_LEVEL", "0", 0, 3 },
{ "VERBOSE", "0", 0, 0 },
{ "VERIFIED_LEASE_ONLY", "0", 0, 0 },
- { "PARAM_IGNORE_LIST", NULL, 0, 0 }
+ { "PARAM_IGNORE_LIST", NULL, 0, 0 },
+ { "REQUEST_FQDN", "1", 0, 0 },
+ { "V4_DEFAULT_IAID_DUID", "0", 0, 0 },
+ { "DNS_DOMAINNAME", NULL, 0, 0 },
+ { "ADOPT_DOMAINNAME", "0", 0, 0 },
};
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.h
index 89063362d0..17a60b8125 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.h
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.h
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#ifndef DEFAULTS_H
@@ -54,7 +55,11 @@ enum {
DF_DEBUG_LEVEL, /* set debug level (undocumented) */
DF_VERBOSE, /* set verbose mode (undocumented) */
DF_VERIFIED_LEASE_ONLY, /* send RELEASE on SIGTERM and need verify */
- DF_PARAM_IGNORE_LIST /* our parameter ignore list */
+ DF_PARAM_IGNORE_LIST, /* our parameter ignore list */
+ DF_REQUEST_FQDN, /* request FQDN associated with interface */
+ DF_V4_DEFAULT_IAID_DUID, /* IAID/DUID if no DF_CLIENT_ID */
+ DF_DNS_DOMAINNAME, /* static domain name if not in --reqhost */
+ DF_ADOPT_DOMAINNAME /* adopt DHCP domain if not in --reqhost */
};
#define DHCP_AGENT_DEFAULTS "/etc/default/dhcpagent"
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dhcpagent.dfl b/usr/src/cmd/cmd-inet/sbin/dhcpagent/dhcpagent.dfl
index 3b1c194784..7f5ffd2559 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dhcpagent.dfl
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/dhcpagent.dfl
@@ -22,6 +22,7 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
#
#
@@ -90,16 +91,73 @@
#
# CLIENT_ID=
+# By default, for an IPv4 interface that is not in an IP network
+# multipathing (IPMP) group, that is not IP over InfiniBand (IPoIB), and
+# that is not a logical interface, the DHCP agent will forgo sending a
+# client identifier unless CLIENT_ID is defined.
+#
+# To use a system-managed, RFC 3315-style (i.e., DHCPv6-style) binding
+# identifier as documented in RFC 4361, "Node-specific Client Identifiers
+# for DHCPv4," for all IPv4 interfaces (unless CLIENT_ID is defined),
+# uncomment the following line.
+#
+# V4_DEFAULT_IAID_DUID=yes
+
+# By default, the DHCP agent will try to request the Fully Qualified Domain
+# Name (FQDN) currently associated with the interface performing DHCP. The
+# hostname is defined by using the -h,--reqhost option of ipadm(1M) or the
+# ncu ip-reqhost property of nwamcfg(1M) or by flagging the interface as
+# primary so that nodename(4) is used as the hostname.
+#
+# A defined hostname will be used as the FQDN if it is "rooted" (i.e., if
+# it ends with a '.') or if it consists of at least three DNS labels (e.g.,
+# srv.example.com). If the hostname is not an FQDN, then DNS_DOMAINNAME
+# will be appended if defined or ADOPT_DOMAINNAME discernment will be used
+# if active. If no FQDN can be determined, the option will not be used.
+#
+# If this REQUEST_FQDN option is enabled, an FQDN will be sent in messages
+# to the DHCP server along with RFC 4702 options to request that a
+# collaborating DNS server perform DNS updates for A and PTR resource
+# records. To prevent sending FQDN and DNS options, uncomment the line
+# below.
+#
+# If an FQDN is sent, REQUEST_HOSTNAME processing will not be done, per RFC
+# 4702 (3.1): "clients that send the Client FQDN option in their messages
+# MUST NOT also send the Host Name."
+#
+# REQUEST_FQDN=no
+
+# By default, the DHCP agent will not attempt to construct an FQDN from a
+# PQDN specified by the -h,--reqhost option of ipadm(1M), by the ncu
+# ip-reqhost property of nwamcfg(1M), or by nodename(4). Set and
+# uncomment the following parameter to indicate a domain name to be used by
+# the DHCP agent to construct if necessary an FQDN.
+#
+# DNS_DOMAINNAME=
+
+# By default, the DHCP agent will not attempt to use a domain name returned
+# by the DHCP server or the domain in resolv.conf(4) to construct an FQDN
+# from a PQDN specified by the -h,--reqhost option of ipadm(1M), by the ncu
+# ip-reqhost property of nwamcfg(1M), or by nodename(4). Set and uncomment
+# the following parameter to indicate that a returned DHCPv4 DNSdmain or the
+# domain from resolv.conf(4) should be adopted by the DHCP agent to
+# construct if necessary an FQDN.
+#
+# ADOPT_DOMAINNAME=yes
+
# By default, the DHCP agent will try to request the hostname currently
# associated with the interface performing DHCP. If this option is
-# enabled, the agent will attempt to find a host name in /etc/hostname.<if>,
-# which must contain a line of the form
+# enabled, the agent will attempt to use an -h,--reqhost option saved with
+# ipadm(1M) or an ncu ip-reqhost property set with nwamcfg(1M); or else
+# attempt to find a host name in /etc/hostname.<if>, which must contain a
+# line of the form
#
# inet name
#
-# where "name" is a single RFC 1101-compliant token. If found, the token
-# will be used to request that host name from the DHCP server. To prevent
-# this, uncomment the following line.
+# where "name" is a single RFC 1101-compliant token; or else use
+# nodename(4) for a DHCP interface flagged as primary. If found in any of
+# these configurations, the token will be used to request that host name
+# from the DHCP server. To prevent this, uncomment the following line.
#
# REQUEST_HOSTNAME=no
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c
index c239287e1d..e2562345ec 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c
@@ -21,13 +21,13 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*
* INIT_REBOOT state of the DHCP client state machine.
*/
#include <sys/types.h>
#include <stdio.h>
-#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/dhcp.h>
@@ -58,8 +58,6 @@ static void
dhcp_init_reboot_v4(dhcp_smach_t *dsmp)
{
dhcp_pkt_t *dpkt;
- const char *reqhost;
- char hostfile[PATH_MAX + 1];
/*
* assemble DHCPREQUEST message. The max dhcp message size
@@ -79,29 +77,8 @@ dhcp_init_reboot_v4(dhcp_smach_t *dsmp)
(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
(void) add_pkt_prl(dpkt, dsmp);
- /*
- * Set CD_HOSTNAME option if REQUEST_HOSTNAME is set and a hostname
- * is found in /etc/hostname.<ifname>
- */
- if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6, DF_REQUEST_HOSTNAME)) {
- (void) snprintf(hostfile, sizeof (hostfile), "/etc/hostname.%s",
- dsmp->dsm_name);
-
- if ((reqhost = iffile_to_hostname(hostfile)) != NULL) {
- dhcpmsg(MSG_DEBUG, "dhcp_selecting: host %s", reqhost);
- if ((dsmp->dsm_reqhost = strdup(reqhost)) != NULL)
- (void) add_pkt_opt(dpkt, CD_HOSTNAME,
- dsmp->dsm_reqhost,
- strlen(dsmp->dsm_reqhost));
- else
- dhcpmsg(MSG_WARNING, "dhcp_selecting: cannot"
- " allocate memory for host name option");
- } else {
- dhcpmsg(MSG_DEBUG,
- "dhcp_selecting: no hostname for %s",
- dsmp->dsm_name);
- }
- }
+ if (!dhcp_add_fqdn_opt(dpkt, dsmp))
+ (void) dhcp_add_hostname_opt(dpkt, dsmp);
(void) add_pkt_opt(dpkt, CD_END, NULL, 0);
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/ipc_action.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/ipc_action.c
index 4f33b2593e..5519e50e22 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/ipc_action.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/ipc_action.c
@@ -21,10 +21,9 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <sys/types.h>
#include <dhcpmsg.h>
@@ -106,8 +105,10 @@ ipc_action_start(dhcp_smach_t *dsmp, ipc_action_t *iareq)
/* We've taken ownership, so the input request is now invalid */
ipc_action_init(iareq);
- dhcpmsg(MSG_DEBUG, "ipc_action_start: started %s (command %d) on %s",
- dhcp_ipc_type_to_string(ia->ia_cmd), ia->ia_cmd, dsmp->dsm_name);
+ dhcpmsg(MSG_DEBUG, "ipc_action_start: started %s (command %d) on %s,"
+ " buffer length %u",
+ dhcp_ipc_type_to_string(ia->ia_cmd), ia->ia_cmd, dsmp->dsm_name,
+ ia->ia_request == NULL ? 0 : ia->ia_request->data_length);
dsmp->dsm_dflags |= DHCP_IF_BUSY;
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c
index a763530436..92adeb1a30 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <string.h>
@@ -413,15 +414,13 @@ add_pkt_opt(dhcp_pkt_t *dpkt, uint_t opt_type, const void *opt_val,
uint_t opt_len)
{
uchar_t *raw_pkt;
- int req_len;
+ size_t req_len;
void *optr;
raw_pkt = (uchar_t *)dpkt->pkt;
optr = raw_pkt + dpkt->pkt_cur_len;
if (dpkt->pkt_isv6) {
- dhcpv6_option_t d6o;
-
- req_len = opt_len + sizeof (d6o);
+ req_len = opt_len + sizeof (dhcpv6_option_t);
if (dpkt->pkt_cur_len + req_len > dpkt->pkt_max_len) {
dhcpmsg(MSG_WARNING,
@@ -430,17 +429,8 @@ add_pkt_opt(dhcp_pkt_t *dpkt, uint_t opt_type, const void *opt_val,
dpkt->pkt_cur_len, req_len, dpkt->pkt_max_len);
return (NULL);
}
- d6o.d6o_code = htons(opt_type);
- d6o.d6o_len = htons(opt_len);
- (void) memcpy(&raw_pkt[dpkt->pkt_cur_len], &d6o, sizeof (d6o));
- dpkt->pkt_cur_len += sizeof (d6o);
- if (opt_len > 0) {
- (void) memcpy(&raw_pkt[dpkt->pkt_cur_len], opt_val,
- opt_len);
- dpkt->pkt_cur_len += opt_len;
- }
} else {
- req_len = opt_len + 2; /* + 2 for code & length bytes */
+ req_len = opt_len + DHCP_OPT_META_LEN;
/* CD_END and CD_PAD options don't have a length field */
if (opt_type == CD_END || opt_type == CD_PAD) {
@@ -457,19 +447,62 @@ add_pkt_opt(dhcp_pkt_t *dpkt, uint_t opt_type, const void *opt_val,
"packet", opt_type);
return (NULL);
}
+ }
+
+ req_len = encode_dhcp_opt(&raw_pkt[dpkt->pkt_cur_len], dpkt->pkt_isv6,
+ opt_type, opt_val, opt_len);
+ dpkt->pkt_cur_len += req_len;
- raw_pkt[dpkt->pkt_cur_len++] = opt_type;
+ return (optr);
+}
- if (req_len > 1) {
- raw_pkt[dpkt->pkt_cur_len++] = opt_len;
- if (opt_len > 0) {
- (void) memcpy(&raw_pkt[dpkt->pkt_cur_len],
- opt_val, opt_len);
- dpkt->pkt_cur_len += opt_len;
- }
+/*
+ * encode_dhcp_opt(): sets the fields of an allocated DHCP option buffer
+ *
+ * input: void *: the buffer allocated for enough space for
+ * (DHCPv6) dhcpv6_option_t and value, or for
+ * (DHCPv4) opt_type + length + value (length/value are
+ * skipped for CD_END or CD_PAD);
+ * boolean_t: a value indicating whether DHCPv6 or not;
+ * uint_t: the type of option being added;
+ * const void *: the value of that option;
+ * uint_t: the length of the value of the option
+ * output: size_t: the number of bytes written starting at opt.
+ */
+
+size_t
+encode_dhcp_opt(void *dopt, boolean_t isv6, uint_t opt_type,
+ const void *opt_val, uint_t opt_len)
+{
+ boolean_t do_copy_value = B_FALSE;
+ size_t res_len = 0;
+ uint8_t *pval;
+
+ if (isv6) {
+ dhcpv6_option_t d6o;
+ d6o.d6o_code = htons(opt_type);
+ d6o.d6o_len = htons(opt_len);
+ (void) memcpy(dopt, &d6o, sizeof (d6o));
+ res_len += sizeof (d6o);
+
+ do_copy_value = B_TRUE;
+ } else {
+ pval = (uint8_t *)dopt;
+ pval[res_len++] = opt_type;
+
+ if (opt_type != CD_END && opt_type != CD_PAD) {
+ pval[res_len++] = opt_len;
+ do_copy_value = B_TRUE;
}
}
- return (optr);
+
+ pval = (uint8_t *)dopt + res_len;
+ if (do_copy_value && opt_len > 0) {
+ (void) memcpy(pval, opt_val, opt_len);
+ res_len += opt_len;
+ }
+
+ return (res_len);
}
/*
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h
index 0ec64c4117..1d97a4b01f 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h
@@ -21,13 +21,12 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _PACKET_H
#define _PACKET_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/dhcp.h>
@@ -122,6 +121,8 @@ dhcp_pkt_t *init_pkt(dhcp_smach_t *, uchar_t);
boolean_t remove_pkt_opt(dhcp_pkt_t *, uint_t);
boolean_t update_v6opt_len(dhcpv6_option_t *, int);
void *add_pkt_opt(dhcp_pkt_t *, uint_t, const void *, uint_t);
+size_t encode_dhcp_opt(void *, boolean_t, uint_t, const void *,
+ uint_t);
void *add_pkt_subopt(dhcp_pkt_t *, dhcpv6_option_t *, uint_t,
const void *, uint_t);
void *add_pkt_opt16(dhcp_pkt_t *, uint_t, uint16_t);
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c
index 8d0c46c8a5..8b86f10abf 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#include <sys/types.h>
@@ -490,7 +491,8 @@ dhcp_extending(dhcp_smach_t *dsmp)
* dhcp_selecting() if the REQUEST_HOSTNAME option was set and
* a host name was found.
*/
- if (dsmp->dsm_reqhost != NULL) {
+ if (!dhcp_add_fqdn_opt(dpkt, dsmp) &&
+ dsmp->dsm_reqhost != NULL) {
(void) add_pkt_opt(dpkt, CD_HOSTNAME, dsmp->dsm_reqhost,
strlen(dsmp->dsm_reqhost));
}
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
index 9a710f9125..7517f2c094 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
@@ -22,6 +22,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2011 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*
* REQUESTING state of the client state machine.
*/
@@ -247,6 +248,8 @@ dhcp_requesting(iu_tq_t *tqp, void *arg)
return;
}
+ save_domainname(dsmp, offer);
+
if (isv6) {
const char *estr, *msg;
const dhcpv6_option_t *d6o;
@@ -315,7 +318,8 @@ dhcp_requesting(iu_tq_t *tqp, void *arg)
* dhcp_selecting() if the DF_REQUEST_HOSTNAME option set and a
* host name was found
*/
- if (dsmp->dsm_reqhost != NULL) {
+ if (!dhcp_add_fqdn_opt(dpkt, dsmp) &&
+ dsmp->dsm_reqhost != NULL) {
(void) add_pkt_opt(dpkt, CD_HOSTNAME, dsmp->dsm_reqhost,
strlen(dsmp->dsm_reqhost));
}
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
index 611e8339af..e2570a4f0f 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*
* SELECTING state of the client state machine.
*/
@@ -29,7 +30,6 @@
#include <stdlib.h>
#include <strings.h>
#include <time.h>
-#include <limits.h>
#include <netinet/in.h>
#include <net/route.h>
#include <net/if.h>
@@ -106,8 +106,6 @@ void
dhcp_selecting(dhcp_smach_t *dsmp)
{
dhcp_pkt_t *dpkt;
- const char *reqhost;
- char hostfile[PATH_MAX + 1];
/*
* We first set up to collect OFFER/Advertise packets as they arrive.
@@ -201,27 +199,9 @@ dhcp_selecting(dhcp_smach_t *dsmp)
}
(void) add_pkt_prl(dpkt, dsmp);
- if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6,
- DF_REQUEST_HOSTNAME)) {
- dhcpmsg(MSG_DEBUG,
- "dhcp_selecting: DF_REQUEST_HOSTNAME");
- (void) snprintf(hostfile, sizeof (hostfile),
- "/etc/hostname.%s", dsmp->dsm_name);
-
- if ((reqhost = iffile_to_hostname(hostfile)) != NULL) {
- dhcpmsg(MSG_DEBUG, "dhcp_selecting: host %s",
- reqhost);
- dsmp->dsm_reqhost = strdup(reqhost);
- if (dsmp->dsm_reqhost != NULL)
- (void) add_pkt_opt(dpkt, CD_HOSTNAME,
- dsmp->dsm_reqhost,
- strlen(dsmp->dsm_reqhost));
- else
- dhcpmsg(MSG_WARNING,
- "dhcp_selecting: cannot allocate "
- "memory for host name option");
- }
- }
+ if (!dhcp_add_fqdn_opt(dpkt, dsmp))
+ (void) dhcp_add_hostname_opt(dpkt, dsmp);
+
(void) add_pkt_opt(dpkt, CD_END, NULL, 0);
(void) send_pkt(dsmp, dpkt, htonl(INADDR_BROADCAST),
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c
index 8f9649cf2b..5a85ced3cd 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*
* This module contains core functions for managing DHCP state machine
* instances.
@@ -332,6 +333,8 @@ free_smach(dhcp_smach_t *dsmp)
free(dsmp->dsm_pil);
free(dsmp->dsm_routers);
free(dsmp->dsm_reqhost);
+ free(dsmp->dsm_msg_reqhost);
+ free(dsmp->dsm_dhcp_domainname);
free(dsmp);
/* no big deal if this fails */
@@ -1049,14 +1052,17 @@ no_specified_id:
* unable to parse it. We need to determine if a Client ID is required
* and, if so, generate one.
*
- * If it's IPv4, not in an IPMP group, and not a logical interface,
+ * If it's IPv4, not in an IPMP group, not a logical interface,
+ * and a DHCP default for DF_V4_DEFAULT_IAID_DUID is not affirmative,
* then we need to preserve backward-compatibility by avoiding
* new-fangled DUID/IAID construction. (Note: even for IPMP test
* addresses, we construct a DUID/IAID since we may renew a lease for
* an IPMP test address on any functioning IP interface in the group.)
*/
if (!pif->pif_isv6 && pif->pif_grifname[0] == '\0' &&
- strchr(dsmp->dsm_name, ':') == NULL) {
+ strchr(dsmp->dsm_name, ':') == NULL &&
+ !df_get_bool(dsmp->dsm_name, pif->pif_isv6,
+ DF_V4_DEFAULT_IAID_DUID)) {
if (pif->pif_hwtype == ARPHRD_IB) {
/*
* This comes from the DHCP over IPoIB specification.
@@ -1218,6 +1224,15 @@ reset_smach(dhcp_smach_t *dsmp)
free(dsmp->dsm_reqhost);
dsmp->dsm_reqhost = NULL;
+ /*
+ * Do not reset dsm_msg_reqhost here. Unlike dsm_reqhost coming from
+ * /etc/host.*, dsm_msg_reqhost comes externally, and it survives until
+ * it is reset from another external message.
+ */
+
+ free(dsmp->dsm_dhcp_domainname);
+ dsmp->dsm_dhcp_domainname = NULL;
+
cancel_smach_timers(dsmp);
(void) set_smach_state(dsmp, INIT);
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h
index 1630555d87..14dc8331db 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#ifndef STATES_H
@@ -201,6 +202,19 @@ struct dhcp_smach_s {
char *dsm_reqhost;
/*
+ * The host name we've been asked by IPC message (e.g.,
+ * `ipadm -T dhcp -h ...') to request is remembered here until it is
+ * reset by another external message.
+ */
+ char *dsm_msg_reqhost;
+
+ /*
+ * The domain name returned for v4 DNSdmain is decoded here for use
+ * (if configured and needed) to determine an FQDN.
+ */
+ char *dsm_dhcp_domainname;
+
+ /*
* V4 and V6 use slightly different timers. For v4, we must count
* seconds from the point where we first try to configure the
* interface. For v6, only seconds while performing a transaction
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c
index eb1887f947..6b69dfffe7 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.c
@@ -20,11 +20,13 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/utsname.h>
#include <stdlib.h>
#include <netinet/in.h> /* struct in_addr */
#include <netinet/dhcp.h>
@@ -35,16 +37,25 @@
#include <string.h>
#include <dhcpmsg.h>
#include <ctype.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdio.h>
#include <dhcp_hostconf.h>
+#include <dhcp_inittab.h>
+#include <dhcp_symbol.h>
+#include <limits.h>
+#include <strings.h>
+#include <libipadm.h>
#include "states.h"
#include "agent.h"
#include "interface.h"
#include "util.h"
#include "packet.h"
+#include "defaults.h"
/*
* this file contains utility functions that have no real better home
@@ -67,6 +78,12 @@
* o true miscellany -- anything else
*/
+#define ETCNODENAME "/etc/nodename"
+
+static boolean_t is_fqdn(const char *);
+static boolean_t dhcp_assemble_fqdn(char *fqdnbuf, size_t buflen,
+ dhcp_smach_t *dsmp);
+
/*
* pkt_type_to_string(): stringifies a packet type
*
@@ -466,35 +483,6 @@ bind_sock_v6(int fd, in_port_t port_hbo, const in6_addr_t *addr_nbo)
}
/*
- * valid_hostname(): check whether a string is a valid hostname
- *
- * input: const char *: the string to verify as a hostname
- * output: boolean_t: B_TRUE if the string is a valid hostname
- *
- * Note that we accept both host names beginning with a digit and
- * those containing hyphens. Neither is strictly legal according
- * to the RFCs, but both are in common practice, so we endeavour
- * to not break what customers are using.
- */
-
-static boolean_t
-valid_hostname(const char *hostname)
-{
- unsigned int i;
-
- for (i = 0; hostname[i] != '\0'; i++) {
-
- if (isalpha(hostname[i]) || isdigit(hostname[i]) ||
- (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0)))
- continue;
-
- return (B_FALSE);
- }
-
- return (i > 0);
-}
-
-/*
* iffile_to_hostname(): return the hostname contained on a line of the form
*
* [ ^I]*inet[ ^I]+hostname[\n]*\0
@@ -556,7 +544,7 @@ iffile_to_hostname(const char *path)
" host name too long");
return (NULL);
}
- if (valid_hostname(p)) {
+ if (ipadm_is_valid_hostname(p)) {
return (p);
} else {
dhcpmsg(MSG_WARNING,
@@ -705,3 +693,523 @@ write_lease_to_hostconf(dhcp_smach_t *dsmp)
"not use cached configuration)", hcfile);
}
}
+
+/*
+ * Try to get a string from the first line of a file, up to but not
+ * including any space (0x20) or newline.
+ *
+ * input: const char *: file name;
+ * char *: allocated buffer space;
+ * size_t: space available in buf;
+ * output: boolean_t: B_TRUE if a non-empty string was written to buf;
+ * B_FALSE otherwise.
+ */
+
+static boolean_t
+dhcp_get_oneline(const char *filename, char *buf, size_t buflen)
+{
+ char value[SYS_NMLN], *c;
+ int fd, i;
+
+ if ((fd = open(filename, O_RDONLY)) <= 0) {
+ dhcpmsg(MSG_DEBUG, "dhcp_get_oneline: could not open %s",
+ filename);
+ *buf = '\0';
+ } else {
+ if ((i = read(fd, value, SYS_NMLN - 1)) <= 0) {
+ dhcpmsg(MSG_WARNING, "dhcp_get_oneline: no line in %s",
+ filename);
+ *buf = '\0';
+ } else {
+ value[i] = '\0';
+ if ((c = strchr(value, '\n')) != NULL)
+ *c = '\0';
+ if ((c = strchr(value, ' ')) != NULL)
+ *c = '\0';
+
+ if (strlcpy(buf, value, buflen) >= buflen) {
+ dhcpmsg(MSG_WARNING, "dhcp_get_oneline: too"
+ " long value, %s", value);
+ *buf = '\0';
+ }
+ }
+ (void) close(fd);
+ }
+
+ return (*buf != '\0');
+}
+
+/*
+ * Try to get the hostname from the /etc/nodename file. uname(2) cannot
+ * be used, because that is initialized after DHCP has solicited, in order
+ * to allow for the possibility that utsname.nodename can be set from
+ * DHCP Hostname. Here, though, we want to send a value specified
+ * advance of DHCP, so read /etc/nodename directly.
+ *
+ * input: char *: allocated buffer space;
+ * size_t: space available in buf;
+ * output: boolean_t: B_TRUE if a non-empty string was written to buf;
+ * B_FALSE otherwise.
+ */
+
+static boolean_t
+dhcp_get_nodename(char *buf, size_t buflen)
+{
+ return (dhcp_get_oneline(ETCNODENAME, buf, buflen));
+}
+
+/*
+ * dhcp_add_hostname_opt(): Set CD_HOSTNAME option if REQUEST_HOSTNAME is
+ * affirmative and if 1) dsm_msg_reqhost is available;
+ * or 2) hostname is read from an extant
+ * /etc/hostname.<ifname> file; or 3) interface is
+ * primary and nodename(4) is defined.
+ *
+ * input: dhcp_pkt_t *: pointer to DHCP message being constructed;
+ * dhcp_smach_t *: pointer to interface DHCP state machine;
+ * output: B_TRUE if a client hostname was added; B_FALSE otherwise.
+ */
+
+boolean_t
+dhcp_add_hostname_opt(dhcp_pkt_t *dpkt, dhcp_smach_t *dsmp)
+{
+ const char *reqhost;
+ char nodename[MAXNAMELEN];
+
+ if (!df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6, DF_REQUEST_HOSTNAME))
+ return (B_FALSE);
+
+ dhcpmsg(MSG_DEBUG, "dhcp_add_hostname_opt: DF_REQUEST_HOSTNAME");
+
+ if (dsmp->dsm_msg_reqhost != NULL &&
+ ipadm_is_valid_hostname(dsmp->dsm_msg_reqhost)) {
+ reqhost = dsmp->dsm_msg_reqhost;
+ } else {
+ char hostfile[PATH_MAX + 1];
+
+ (void) snprintf(hostfile, sizeof (hostfile),
+ "/etc/hostname.%s", dsmp->dsm_name);
+ reqhost = iffile_to_hostname(hostfile);
+ }
+
+ if (reqhost == NULL && (dsmp->dsm_dflags & DHCP_IF_PRIMARY) &&
+ dhcp_get_nodename(nodename, sizeof (nodename))) {
+ reqhost = nodename;
+ }
+
+ if (reqhost != NULL) {
+ free(dsmp->dsm_reqhost);
+ if ((dsmp->dsm_reqhost = strdup(reqhost)) == NULL)
+ dhcpmsg(MSG_WARNING, "dhcp_add_hostname_opt: cannot"
+ " allocate memory for host name option");
+ }
+
+ if (dsmp->dsm_reqhost != NULL) {
+ dhcpmsg(MSG_DEBUG, "dhcp_add_hostname_opt: host %s for %s",
+ dsmp->dsm_reqhost, dsmp->dsm_name);
+ (void) add_pkt_opt(dpkt, CD_HOSTNAME, dsmp->dsm_reqhost,
+ strlen(dsmp->dsm_reqhost));
+ return (B_FALSE);
+ } else {
+ dhcpmsg(MSG_DEBUG, "dhcp_add_hostname_opt: no hostname for %s",
+ dsmp->dsm_name);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * dhcp_add_fqdn_opt(): Set client FQDN option if dhcp_assemble_fqdn()
+ * initializes an FQDN, or else do nothing.
+ *
+ * input: dhcp_pkt_t *: pointer to DHCP message being constructed;
+ * dhcp_smach_t *: pointer to interface DHCP state machine;
+ * output: B_TRUE if a client FQDN was added; B_FALSE otherwise.
+ */
+
+boolean_t
+dhcp_add_fqdn_opt(dhcp_pkt_t *dpkt, dhcp_smach_t *dsmp)
+{
+ /*
+ * RFC 4702 section 2:
+ *
+ * The format of the Client FQDN option is:
+ *
+ * Code Len Flags RCODE1 RCODE2 Domain Name
+ * +------+------+------+------+------+------+--
+ * | 81 | n | | | | ...
+ * +------+------+------+------+------+------+--
+ *
+ * Code and Len are distinct, and the remainder is in a single buffer,
+ * opt81, for Flags + (unused) RCODE1 and RCODE2 (all octets) and a
+ * potentially maximum-length domain name.
+ *
+ * The format of the Flags field is:
+ *
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | MBZ |N|E|O|S|
+ * +-+-+-+-+-+-+-+-+
+ *
+ * where MBZ is ignored and NEOS are:
+ *
+ * S = 1 to request that "the server SHOULD perform the A RR (FQDN-to-
+ * address) DNS updates;
+ *
+ * O = 0, for a server-only response bit;
+ *
+ * E = 1 to indicate the domain name is in "canonical wire format,
+ * without compression (i.e., ns_name_pton2) .... This encoding SHOULD
+ * be used by clients ....";
+ *
+ * N = 0 to request that "the server SHALL perform DNS updates [of the
+ * PTR RR]." (1 would request SHALL NOT update).
+ */
+
+ const uint8_t S_BIT_POS = 7;
+ const uint8_t E_BIT_POS = 5;
+ const uint8_t S_BIT = 1 << (7 - S_BIT_POS);
+ const uint8_t E_BIT = 1 << (7 - E_BIT_POS);
+ const size_t OPT_FQDN_METALEN = 3;
+ char fqdnbuf[MAXNAMELEN];
+ uchar_t enc_fqdnbuf[MAXNAMELEN];
+ uint8_t fqdnopt[MAXNAMELEN + OPT_FQDN_METALEN];
+ uint_t fqdncode;
+ size_t len, metalen;
+
+ if (dsmp->dsm_isv6)
+ return (B_FALSE);
+
+ if (!dhcp_assemble_fqdn(fqdnbuf, sizeof (fqdnbuf), dsmp))
+ return (B_FALSE);
+
+ /* encode the FQDN in canonical wire format */
+
+ if (ns_name_pton2(fqdnbuf, enc_fqdnbuf, sizeof (enc_fqdnbuf),
+ &len) < 0) {
+ dhcpmsg(MSG_WARNING, "dhcp_add_fqdn_opt: error encoding domain"
+ " name %s", fqdnbuf);
+ return (B_FALSE);
+ }
+
+ dhcpmsg(MSG_DEBUG, "dhcp_add_fqdn_opt: interface FQDN is %s"
+ " for %s", fqdnbuf, dsmp->dsm_name);
+
+ bzero(fqdnopt, sizeof (fqdnopt));
+ fqdncode = CD_CLIENTFQDN;
+ metalen = OPT_FQDN_METALEN;
+ *fqdnopt = S_BIT | E_BIT;
+ (void) memcpy(fqdnopt + metalen, enc_fqdnbuf, len);
+ (void) add_pkt_opt(dpkt, fqdncode, fqdnopt, metalen + len);
+
+ return (B_TRUE);
+}
+
+/*
+ * dhcp_adopt_domainname(): Set namebuf if either dsm_dhcp_domainname or
+ * resolv's "default domain (deprecated)" is defined.
+ *
+ * input: char *: pointer to buffer to which domain name will be written;
+ * size_t length of buffer;
+ * dhcp_smach_t *: pointer to interface DHCP state machine;
+ * output: B_TRUE if namebuf was set to a valid domain name; B_FALSE
+ * otherwise.
+ */
+
+static boolean_t
+dhcp_adopt_domainname(char *namebuf, size_t buflen, dhcp_smach_t *dsmp)
+{
+ const char *domainname;
+ struct __res_state res_state;
+ int lasterrno;
+
+ domainname = dsmp->dsm_dhcp_domainname;
+
+ if (ipadm_is_nil_hostname(domainname)) {
+ /*
+ * fall back to resolv's "default domain (deprecated)"
+ */
+ bzero(&res_state, sizeof (struct __res_state));
+
+ if ((lasterrno = res_ninit(&res_state)) != 0) {
+ dhcpmsg(MSG_WARNING, "dhcp_adopt_domainname: error %d"
+ " initializing resolver", lasterrno);
+ return (B_FALSE);
+ }
+
+ domainname = NULL;
+ if (!ipadm_is_nil_hostname(res_state.defdname))
+ domainname = res_state.defdname;
+
+ /* N.b. res_state.defdname survives the following call */
+ res_ndestroy(&res_state);
+ }
+
+ if (domainname == NULL)
+ return (B_FALSE);
+
+ if (strlcpy(namebuf, domainname, buflen) >= buflen) {
+ dhcpmsg(MSG_WARNING,
+ "dhcp_adopt_domainname: too long adopted domain"
+ " name %s for %s", domainname, dsmp->dsm_name);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * dhcp_pick_domainname(): Set namebuf if DNS_DOMAINNAME is defined in
+ * /etc/default/dhcpagent or if dhcp_adopt_domainname()
+ * succeeds.
+ *
+ * input: char *: pointer to buffer to which domain name will be written;
+ * size_t length of buffer;
+ * dhcp_smach_t *: pointer to interface DHCP state machine;
+ * output: B_TRUE if namebuf was set to a valid domain name; B_FALSE
+ * otherwise.
+ */
+
+static boolean_t
+dhcp_pick_domainname(char *namebuf, size_t buflen, dhcp_smach_t *dsmp)
+{
+ const char *domainname;
+
+ /*
+ * Try to use a static DNS_DOMAINNAME if defined in
+ * /etc/default/dhcpagent.
+ */
+ domainname = df_get_string(dsmp->dsm_name, dsmp->dsm_isv6,
+ DF_DNS_DOMAINNAME);
+ if (!ipadm_is_nil_hostname(domainname)) {
+ if (strlcpy(namebuf, domainname, buflen) >= buflen) {
+ dhcpmsg(MSG_WARNING, "dhcp_pick_domainname: too long"
+ " DNS_DOMAINNAME %s for %s", domainname,
+ dsmp->dsm_name);
+ return (B_FALSE);
+ }
+ return (B_TRUE);
+ } else if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6,
+ DF_ADOPT_DOMAINNAME)) {
+ return (dhcp_adopt_domainname(namebuf, buflen, dsmp));
+ } else {
+ return (B_FALSE);
+ }
+}
+
+/*
+ * dhcp_assemble_fqdn(): Set fqdnbuf if REQUEST_FQDN is set and
+ * either a host name was sent in the IPC message (e.g.,
+ * from ipadm(1M) -h,--reqhost) or the interface is
+ * primary and a nodename(4) is defined. If the host
+ * name is not already fully qualified per is_fqdn(),
+ * then dhcp_pick_domainname() is tried to select a
+ * domain to be used to construct an FQDN.
+ *
+ * input: char *: pointer to buffer to which FQDN will be written;
+ * size_t length of buffer;
+ * dhcp_smach_t *: pointer to interface DHCP state machine;
+ * output: B_TRUE if fqdnbuf was assigned a valid FQDN; B_FALSE otherwise.
+ */
+
+static boolean_t
+dhcp_assemble_fqdn(char *fqdnbuf, size_t buflen, dhcp_smach_t *dsmp)
+{
+ char nodename[MAXNAMELEN], *reqhost;
+ size_t pos, len;
+
+
+ if (!df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6, DF_REQUEST_FQDN))
+ return (B_FALSE);
+
+ dhcpmsg(MSG_DEBUG, "dhcp_assemble_fqdn: DF_REQUEST_FQDN");
+
+ /* It's convenient to ensure fqdnbuf is always null-terminated */
+ bzero(fqdnbuf, buflen);
+
+ reqhost = dsmp->dsm_msg_reqhost;
+ if (ipadm_is_nil_hostname(reqhost) &&
+ (dsmp->dsm_dflags & DHCP_IF_PRIMARY) &&
+ dhcp_get_nodename(nodename, sizeof (nodename))) {
+ reqhost = nodename;
+ }
+
+ if (ipadm_is_nil_hostname(reqhost)) {
+ dhcpmsg(MSG_DEBUG,
+ "dhcp_assemble_fqdn: no interface reqhost for %s",
+ dsmp->dsm_name);
+ return (B_FALSE);
+ }
+
+ if ((pos = strlcpy(fqdnbuf, reqhost, buflen)) >= buflen) {
+ dhcpmsg(MSG_WARNING, "dhcp_assemble_fqdn: too long reqhost %s"
+ " for %s", reqhost, dsmp->dsm_name);
+ return (B_FALSE);
+ }
+
+ /*
+ * If not yet FQDN, construct if possible
+ */
+ if (!is_fqdn(reqhost)) {
+ char domainname[MAXNAMELEN];
+ size_t needdots;
+
+ if (!dhcp_pick_domainname(domainname, sizeof (domainname),
+ dsmp)) {
+ dhcpmsg(MSG_DEBUG,
+ "dhcp_assemble_fqdn: no domain name for %s",
+ dsmp->dsm_name);
+ return (B_FALSE);
+ }
+
+ /*
+ * Finish constructing FQDN. Account for space needed to hold a
+ * separator '.' and a terminating '.'.
+ */
+ len = strlen(domainname);
+ needdots = 1 + (domainname[len - 1] != '.');
+
+ if (pos + len + needdots >= buflen) {
+ dhcpmsg(MSG_WARNING, "dhcp_assemble_fqdn: too long"
+ " FQDN %s.%s for %s", fqdnbuf, domainname,
+ dsmp->dsm_name);
+ return (B_FALSE);
+ }
+
+ /* add separator and then domain name */
+ fqdnbuf[pos++] = '.';
+ if (strlcpy(fqdnbuf + pos, domainname, buflen - pos) >=
+ buflen - pos) {
+ /* shouldn't get here as we checked above */
+ return (B_FALSE);
+ }
+ pos += len;
+
+ /* ensure the final character is '.' */
+ if (needdots > 1)
+ fqdnbuf[pos++] = '.'; /* following is already zeroed */
+ }
+
+ if (!ipadm_is_valid_hostname(fqdnbuf)) {
+ dhcpmsg(MSG_WARNING, "dhcp_assemble_fqdn: invalid FQDN %s"
+ " for %s", fqdnbuf, dsmp->dsm_name);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * is_fqdn() : Determine if the `hostname' can be considered as a Fully
+ * Qualified Domain Name by being "rooted" (i.e., ending in '.')
+ * or by containing at least three DNS labels (e.g.,
+ * srv.example.com).
+ *
+ * input: const char *: the hostname to inspect;
+ * output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
+ * criteria above; otherwise, B_FALSE;
+ */
+
+boolean_t
+is_fqdn(const char *hostname)
+{
+ const char *c;
+ size_t i;
+
+ if (hostname == NULL)
+ return (B_FALSE);
+
+ i = strlen(hostname);
+ if (i > 0 && hostname[i - 1] == '.')
+ return (B_TRUE);
+
+ c = hostname;
+ i = 0;
+ while ((c = strchr(c, '.')) != NULL) {
+ ++i;
+ ++c;
+ }
+
+ /* at least two separators is inferred to be fully-qualified */
+ return (i >= 2);
+}
+
+/*
+ * terminate_at_space(): Reset the first space, 0x20, to 0x0 in the
+ * specified string.
+ *
+ * input: char *: NULL or a null-terminated string;
+ * output: void.
+ */
+
+static void
+terminate_at_space(char *value)
+{
+ if (value != NULL) {
+ char *sp;
+
+ sp = strchr(value, ' ');
+ if (sp != NULL)
+ *sp = '\0';
+ }
+}
+
+/*
+ * get_offered_domainname_v4(): decode a defined v4 DNSdmain value if it
+ * exists to return a copy of the domain
+ * name.
+ *
+ * input: dhcp_smach_t *: the state machine REQUESTs are being sent from;
+ * PKT_LIST *: the best packet to be used to construct a REQUEST;
+ * output: char *: NULL or a copy of the domain name ('\0' terminated);
+ */
+
+static char *
+get_offered_domainname_v4(PKT_LIST *offer)
+{
+ char *domainname = NULL;
+ DHCP_OPT *opt;
+
+ if ((opt = offer->opts[CD_DNSDOMAIN]) != NULL) {
+ uchar_t *valptr;
+ dhcp_symbol_t *symp;
+
+ valptr = (uchar_t *)opt + DHCP_OPT_META_LEN;
+
+ symp = inittab_getbycode(
+ ITAB_CAT_STANDARD, ITAB_CONS_INFO, opt->code);
+ if (symp != NULL) {
+ domainname = inittab_decode(symp, valptr,
+ opt->len, B_TRUE);
+ terminate_at_space(domainname);
+ free(symp);
+ }
+ }
+
+ return (domainname);
+}
+
+/*
+ * save_domainname(): assign dsm_dhcp_domainname from
+ * get_offered_domainname_v4 or leave the field NULL if no
+ * option is present.
+ *
+ * input: dhcp_smach_t *: the state machine REQUESTs are being sent from;
+ * PKT_LIST *: the best packet to be used to construct a REQUEST;
+ * output: void
+ */
+
+void
+save_domainname(dhcp_smach_t *dsmp, PKT_LIST *offer)
+{
+ char *domainname = NULL;
+
+ free(dsmp->dsm_dhcp_domainname);
+ dsmp->dsm_dhcp_domainname = NULL;
+
+ if (!dsmp->dsm_isv6) {
+ domainname = get_offered_domainname_v4(offer);
+ }
+
+ dsmp->dsm_dhcp_domainname = domainname;
+}
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.h
index 587b9a9a31..906d3599f0 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.h
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/util.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
#ifndef UTIL_H
@@ -33,6 +34,7 @@
#include <dhcpagent_ipc.h>
#include "common.h"
+#include "packet.h"
/*
* general utility functions which have no better home. see util.c
@@ -75,6 +77,9 @@ const char *iffile_to_hostname(const char *);
int dhcpv6_status_code(const dhcpv6_option_t *, uint_t,
const char **, const char **, uint_t *);
void write_lease_to_hostconf(dhcp_smach_t *);
+boolean_t dhcp_add_hostname_opt(dhcp_pkt_t *, dhcp_smach_t *);
+boolean_t dhcp_add_fqdn_opt(dhcp_pkt_t *, dhcp_smach_t *);
+void save_domainname(dhcp_smach_t *, PKT_LIST *);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
index 5c6f5bf1c8..23d665cec1 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
@@ -24,6 +24,7 @@
* Copyright 2017 Nexenta Systems, Inc.
* Copyright 2017 Joyent, Inc.
* Copyright 2017 Gary Mills
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <arpa/inet.h>
@@ -95,7 +96,8 @@ static cmd_t cmds[] = {
{ "create-addr", do_create_addr,
"\tcreate-addr\t[-t] -T static [-d] "
"-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
- "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever] <addrobj>\n"
+ "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever]\n"
+ "\t\t\t[-1] [-h <hostname>] <addrobj>\n"
"\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
"\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
{ "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>" },
@@ -168,7 +170,9 @@ static const struct option addr_longopts[] = {
{"address", required_argument, 0, 'a' },
{"down", no_argument, 0, 'd' },
{"interface-id", required_argument, 0, 'i' },
+ {"primary", no_argument, 0, '1' },
{"prop", required_argument, 0, 'p' },
+ {"reqhost", required_argument, 0, 'h' },
{"temporary", no_argument, 0, 't' },
{"type", required_argument, 0, 'T' },
{"wait", required_argument, 0, 'w' },
@@ -618,8 +622,8 @@ show_property(void *arg, const char *pname, uint_t proto)
/*
* Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
- * for all the properties for the specified object, relavant information, will
- * be displayed. Otherwise, for the selected property set, display relevant
+ * for all the properties for the specified object, display relevant
+ * information. Otherwise, for the selected property set, display relevant
* information
*/
static void
@@ -1244,14 +1248,19 @@ do_create_addr(int argc, char *argv[], const char *use)
char *addrconf_arg = NULL;
char *interface_id = NULL;
char *wait = NULL;
+ char *reqhost = NULL;
boolean_t s_opt = _B_FALSE; /* static addr options */
boolean_t auto_opt = _B_FALSE; /* Addrconf options */
boolean_t dhcp_opt = _B_FALSE; /* dhcp options */
+ boolean_t primary_opt = _B_FALSE; /* dhcp primary option */
opterr = 0;
- while ((option = getopt_long(argc, argv, ":T:a:di:p:w:t",
+ while ((option = getopt_long(argc, argv, ":1T:a:dh:i:p:w:t",
addr_longopts, NULL)) != -1) {
switch (option) {
+ case '1':
+ primary_opt = _B_TRUE;
+ break;
case 'T':
atype = optarg;
break;
@@ -1263,6 +1272,9 @@ do_create_addr(int argc, char *argv[], const char *use)
flags &= ~IPADM_OPT_UP;
s_opt = _B_TRUE;
break;
+ case 'h':
+ reqhost = optarg;
+ break;
case 'i':
interface_id = optarg;
auto_opt = _B_TRUE;
@@ -1294,7 +1306,8 @@ do_create_addr(int argc, char *argv[], const char *use)
* Allocate and initialize the addrobj based on the address type.
*/
if (strcmp(atype, "static") == 0) {
- if (static_arg == NULL || auto_opt || dhcp_opt) {
+ if (static_arg == NULL || auto_opt || dhcp_opt ||
+ reqhost != NULL || primary_opt) {
die("Invalid arguments for type %s\nusage: %s",
atype, use);
}
@@ -1331,13 +1344,27 @@ do_create_addr(int argc, char *argv[], const char *use)
ipadm_status2str(status));
}
}
+ if (primary_opt) {
+ status = ipadm_set_primary(ipaddr, _B_TRUE);
+ if (status != IPADM_SUCCESS) {
+ die("Error in setting primary flag: %s",
+ ipadm_status2str(status));
+ }
+ }
+ if (reqhost != NULL) {
+ status = ipadm_set_reqhost(ipaddr, reqhost);
+ if (status != IPADM_SUCCESS) {
+ die("Error in setting reqhost: %s",
+ ipadm_status2str(status));
+ }
+ }
} else if (strcmp(atype, "addrconf") == 0) {
- if (dhcp_opt || s_opt) {
+ if (dhcp_opt || s_opt || reqhost != NULL || primary_opt) {
die("Invalid arguments for type %s\nusage: %s",
atype, use);
}
- /* Initialize the addrobj for dhcp addresses. */
+ /* Initialize the addrobj for ipv6-addrconf addresses. */
status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
argv[optind], &ipaddr);
if (status != IPADM_SUCCESS) {
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile
index 3fc271c39a..0c51a0301b 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile
@@ -22,6 +22,7 @@
#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
# cmd/cmd-inet/usr.sbin/nwamcfg/Makefile
@@ -56,7 +57,7 @@ install: all $(ROOTUSRSBINPROG)
nwamcfg_lex.c: nwamcfg_lex.l nwamcfg_grammar.tab.h nwamcfg.h
$(LEX) $(LFLAGS) nwamcfg_lex.l > $@
-nwamcfg_grammar.tab.h nwamcfg_grammar.tab.c: nwamcfg_grammar.y nwamcfg.h
+nwamcfg_grammar.tab.h + nwamcfg_grammar.tab.c: nwamcfg_grammar.y nwamcfg.h
$(YACC) $(YFLAGS) nwamcfg_grammar.y
nwamcfg_lex.o nwamcfg_grammar.tab.o := CCVERBOSE =
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c
index e4896f565d..690377cc2d 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -198,7 +199,9 @@ static char *pt_types[] = {
NWAM_KNOWN_WLAN_PROP_PRIORITY,
NWAM_KNOWN_WLAN_PROP_KEYNAME,
NWAM_KNOWN_WLAN_PROP_KEYSLOT,
- NWAM_KNOWN_WLAN_PROP_SECURITY_MODE
+ NWAM_KNOWN_WLAN_PROP_SECURITY_MODE,
+ NWAM_NCU_PROP_IP_PRIMARY,
+ NWAM_NCU_PROP_IP_REQHOST
};
/* properties table: maps PT_* constants to property names */
@@ -226,6 +229,8 @@ static prop_table_entry_t ncu_prop_table[] = {
{ PT_IPV6_ADDRSRC, NWAM_NCU_PROP_IPV6_ADDRSRC },
{ PT_IPV6_ADDR, NWAM_NCU_PROP_IPV6_ADDR },
{ PT_IPV6_DEFAULT_ROUTE, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE },
+ { PT_IP_PRIMARY, NWAM_NCU_PROP_IP_PRIMARY },
+ { PT_IP_REQHOST, NWAM_NCU_PROP_IP_REQHOST },
{ 0, NULL }
};
@@ -626,7 +631,8 @@ rt2_to_str(int res_type)
/* Returns "ncp, "ncu", "loc", "enm", or "wlan" according to the scope */
static const char *
-scope_to_str(int scope) {
+scope_to_str(int scope)
+{
switch (scope) {
case NWAM_SCOPE_GBL:
return ("global");
@@ -664,11 +670,15 @@ pt_to_str(int prop_type)
return (pt_types[prop_type]);
}
-/* Return B_TRUE if string starts with "t" or is 1, B_FALSE otherwise */
+/*
+ * Return B_TRUE if string starts with "t" or "on" or is 1;
+ * B_FALSE otherwise
+ */
static boolean_t
str_to_boolean(const char *str)
{
- if (strncasecmp(str, "t", 1) == 0 || atoi(str) == 1)
+ if (strncasecmp(str, "t", 1) == 0 || strncasecmp(str, "on", 2) == 0 ||
+ atoi(str) == 1)
return (B_TRUE);
else
return (B_FALSE);
@@ -2197,6 +2207,12 @@ static prop_display_entry_t ncu_prop_display_entry_table[] = {
/* show ipv6-default-route if ip-version == ipv6 */
{ NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_NCU_PROP_IP_VERSION,
{ IPV6_VERSION, -1 } },
+ /* show ip-primary if ipv4-addrsrc == dhcp */
+ { NWAM_NCU_PROP_IP_PRIMARY, NWAM_NCU_PROP_IPV4_ADDRSRC,
+ { NWAM_ADDRSRC_DHCP, -1 } },
+ /* show ip-reqhost if ipv4-addrsrc == dhcp */
+ { NWAM_NCU_PROP_IP_REQHOST, NWAM_NCU_PROP_IPV4_ADDRSRC,
+ { NWAM_ADDRSRC_DHCP, -1 } },
{ NULL, NULL, { -1 } }
};
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h
index c9b1049c99..63ad154d87 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _NWAMCFG_H
@@ -133,12 +134,14 @@ extern "C" {
#define PT_WLAN_KEYNAME 42
#define PT_WLAN_KEYSLOT 43
#define PT_WLAN_SECURITY_MODE 44
+#define PT_IP_PRIMARY 45
+#define PT_IP_REQHOST 46
/*
* If any new PT_ are defined here, make sure it is added in the same
* order into the pt_types array in nwamcfg.c
*/
#define PT_MIN PT_UNKNOWN
-#define PT_MAX PT_WLAN_SECURITY_MODE
+#define PT_MAX PT_IP_REQHOST
#define MAX_SUBCMD_ARGS 3
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y
index c40dc2c963..f7c3d64b26 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y
@@ -23,6 +23,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <stdio.h>
@@ -67,6 +68,7 @@ extern boolean_t newline_terminated;
%token LOC_IPF_CONFIG LOC_IPF_V6_CONFIG
%token LOC_IPNAT_CONFIG LOC_IPPOOL_CONFIG LOC_IKE_CONFIG LOC_IPSECPOL_CONFIG
%token WLAN_BSSIDS WLAN_PRIORITY WLAN_KEYNAME WLAN_KEYSLOT WLAN_SECURITY_MODE
+%token IP_PRIMARY IP_REQHOST
%type <strval> TOKEN EQUAL OPTION
%type <ival> resource1_type LOC NCP ENM WLAN
@@ -86,6 +88,7 @@ extern boolean_t newline_terminated;
LOC_IPF_CONFIG LOC_IPF_V6_CONFIG
LOC_IPNAT_CONFIG LOC_IPPOOL_CONFIG LOC_IKE_CONFIG LOC_IPSECPOL_CONFIG
WLAN_BSSIDS WLAN_PRIORITY WLAN_KEYNAME WLAN_KEYSLOT WLAN_SECURITY_MODE
+ IP_PRIMARY IP_REQHOST
%type <cmd> command
%type <cmd> cancel_command CANCEL
%type <cmd> clear_command CLEAR
@@ -617,11 +620,26 @@ list_command: LIST
command_usage(CMD_LIST);
YYERROR;
}
+ | LIST OPTION resource1_type
+ {
+ command_usage(CMD_LIST);
+ YYERROR;
+ }
| LIST resource2_type
{
command_usage(CMD_LIST);
YYERROR;
}
+ | LIST OPTION resource2_type
+ {
+ command_usage(CMD_LIST);
+ YYERROR;
+ }
+ | LIST OPTION resource2_type ncu_class_type
+ {
+ command_usage(CMD_LIST);
+ YYERROR;
+ }
| LIST resource1_type TOKEN
{
/* list enm/loc/ncp test */
@@ -743,6 +761,11 @@ select_command: SELECT
command_usage(CMD_SELECT);
YYERROR;
}
+ | SELECT resource2_type ncu_class_type
+ {
+ command_usage(CMD_SELECT);
+ YYERROR;
+ }
| SELECT resource1_type TOKEN
{
/* select enm/loc/ncp test */
@@ -900,5 +923,7 @@ property_type: UNKNOWN { $$ = PT_UNKNOWN; }
| WLAN_KEYNAME { $$ = PT_WLAN_KEYNAME; }
| WLAN_KEYSLOT { $$ = PT_WLAN_KEYSLOT; }
| WLAN_SECURITY_MODE { $$ = PT_WLAN_SECURITY_MODE; }
+ | IP_PRIMARY { $$ = PT_IP_PRIMARY; }
+ | IP_REQHOST { $$ = PT_IP_REQHOST; }
%%
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l
index e6fc23ff20..e237f43475 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l
@@ -23,6 +23,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <string.h>
@@ -182,6 +183,8 @@ char *safe_strdup(char *s);
<TSTATE>ipv6-addrsrc { return IPV6_ADDRSRC; }
<TSTATE>ipv6-addr { return IPV6_ADDR; }
<TSTATE>ipv6-default-route { return IPV6_DEFAULT_ROUTE; }
+<TSTATE>ip-primary { return IP_PRIMARY; }
+<TSTATE>ip-reqhost { return IP_REQHOST; }
<TSTATE>state { return ENM_STATE; }
<TSTATE>fmri { return ENM_FMRI; }
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.c b/usr/src/cmd/nvmeadm/nvmeadm.c
index a08fa59258..00931bf77e 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm.c
@@ -11,6 +11,7 @@
/*
* Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2017 Joyent, Inc.
*/
/*
diff --git a/usr/src/common/net/dhcp/dhcp_impl.h b/usr/src/common/net/dhcp/dhcp_impl.h
index 8d9dca577b..de9255aeaa 100644
--- a/usr/src/common/net/dhcp/dhcp_impl.h
+++ b/usr/src/common/net/dhcp/dhcp_impl.h
@@ -21,13 +21,12 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _DHCP_IMPL_H
#define _DHCP_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Common definitions used by Sun DHCP implementations
*/
@@ -94,6 +93,11 @@ typedef struct {
uint8_t value[1];
} DHCP_OPT;
+/*
+ * Defines the size of DHCP_OPT code + len
+ */
+#define DHCP_OPT_META_LEN 2
+
typedef union sockaddr46_s {
struct sockaddr_in v4;
struct sockaddr_in6 v6;
diff --git a/usr/src/head/arpa/nameser.h b/usr/src/head/arpa/nameser.h
index 29a1c5b38e..dc199077b3 100644
--- a/usr/src/head/arpa/nameser.h
+++ b/usr/src/head/arpa/nameser.h
@@ -1,6 +1,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -576,6 +577,7 @@ typedef enum __ns_cert_types {
#define ns_name_ntol __ns_name_ntol
#define ns_name_ntop __ns_name_ntop
#define ns_name_pton __ns_name_pton
+#define ns_name_pton2 __ns_name_pton2
#define ns_name_unpack __ns_name_unpack
#define ns_name_pack __ns_name_pack
#define ns_name_compress __ns_name_compress
@@ -632,6 +634,7 @@ uint32_t ns_datetosecs(const char *cp, int *errp);
int ns_name_ntol(const uchar_t *, uchar_t *, size_t);
int ns_name_ntop(const uchar_t *, char *, size_t);
int ns_name_pton(const char *, uchar_t *, size_t);
+int ns_name_pton2(const char *, uchar_t *, size_t, size_t *);
int ns_name_unpack(const uchar_t *, const uchar_t *,
const uchar_t *, uchar_t *, size_t);
int ns_name_pack(const uchar_t *, uchar_t *, int,
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 0f6aa5a0bf..44045e5b1d 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -28,6 +28,7 @@
# Copyright (c) 2015 Gary Mills
# Copyright 2016 Toomas Soome <tsoome@me.com>
# Copyright 2017 Nexenta Systems, Inc.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
include ../Makefile.master
@@ -636,7 +637,7 @@ libidmap: libavl libuutil
libidspace: libumem
libinetsvc: libscf
libinstzones: libzonecfg libcontract
-libipadm: libinetutil libdlpi libdhcpagent libdladm libsecdb
+libipadm: libinetutil libdlpi libdhcpagent libdladm libsecdb libdhcputil
libipmp: libinetutil
libipsecutil: libtecla libtsol
libiscsit: libstmf libuuid
@@ -646,7 +647,7 @@ libldap5: libsasl
libmapid: libresolv2 libscf
libndmp: libscf
libnisdb: libldap5
-libnwam: libscf libbsm libdladm
+libnwam: libscf libbsm libdladm libipadm
libpcp: libumem libdevinfo
libpctx: libproc
libpkg: libwanboot libscf libadm
diff --git a/usr/src/lib/libipadm/Makefile.com b/usr/src/lib/libipadm/Makefile.com
index 33685ff755..d195ea19c6 100644
--- a/usr/src/lib/libipadm/Makefile.com
+++ b/usr/src/lib/libipadm/Makefile.com
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
#
@@ -35,7 +36,7 @@ include ../../Makefile.rootfs
LIBS = $(DYNLIB) $(LINTLIB)
LDLIBS += -lc -lnsl -linetutil -lsocket -ldlpi -lnvpair -ldhcpagent \
- -ldladm -lsecdb
+ -ldladm -lsecdb -ldhcputil
SRCDIR = ../common
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
diff --git a/usr/src/lib/libipadm/common/ipadm_addr.c b/usr/src/lib/libipadm/common/ipadm_addr.c
index a62bcb165b..0b1de43c14 100644
--- a/usr/src/lib/libipadm/common/ipadm_addr.c
+++ b/usr/src/lib/libipadm/common/ipadm_addr.c
@@ -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-2017, 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,10 +68,13 @@ 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_dhcp_status(ipadm_addrobj_t addr,
+ dhcp_status_t *status, int *dhcperror);
static ipadm_status_t i_ipadm_validate_create_addr(ipadm_handle_t,
ipadm_addrobj_t, uint32_t);
static ipadm_status_t i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
@@ -77,6 +84,7 @@ static ipadm_status_t i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
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,15 +93,20 @@ static boolean_t i_ipadm_is_user_aobjname_valid(const char *);
* 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[] = {
@@ -104,13 +117,24 @@ ipadm_prop_desc_t ipadm_addrprop_table[] = {
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 +225,23 @@ i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
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:
+ if (strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
+ sizeof (ipaddr->ipadm_reqhost)) >=
+ sizeof (ipaddr->ipadm_reqhost)) {
+ /*
+ * shouldn't get here as the buffers are defined
+ * with same length, MAX_NAME_LEN
+ */
+ return (IPADM_FAILURE);
+ }
+ break;
+ default:
+ break;
}
return (IPADM_SUCCESS);
@@ -1041,6 +1079,84 @@ i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
}
/*
+ * 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 +1487,90 @@ i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
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) {
+ dhcp_status_t dhcp_status;
+ ipadm_status_t ipc_status;
+ int error;
+
+ ipc_status = i_ipadm_dhcp_status(ipaddr, &dhcp_status,
+ &error);
+ if (ipc_status != IPADM_SUCCESS &&
+ ipc_status != IPADM_NOTFOUND)
+ return (ipc_status);
+
+ onoff = dhcp_status.if_dflags & DHCP_IF_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 +1975,7 @@ ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
return (IPADM_SUCCESS);
}
+
/*
* Set up tunnel destination address in ipaddr by contacting DNS.
* The function works similar to ipadm_set_addr().
@@ -1901,6 +2102,28 @@ ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
}
/*
+ * 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 +2273,15 @@ i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *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;
@@ -2067,6 +2291,8 @@ i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
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 +2314,9 @@ i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
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 +2959,7 @@ retry:
}
}
status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
- flags);
+ flags, NULL);
}
ret:
if (status != IPADM_SUCCESS && !legacy)
@@ -2887,7 +3116,7 @@ retry:
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 +3176,10 @@ 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;
@@ -2956,9 +3189,37 @@ i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
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 +3230,7 @@ i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
/* 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);
@@ -2986,6 +3248,62 @@ i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
}
/*
+ * Communicates with the dhcpagent to send a dhcp message of type
+ * DHCP_STATUS, and copy on success into the `status' instance owned by the
+ * caller. It returns any dhcp error in `dhcperror' if a non-null pointer
+ * is provided.
+ */
+static ipadm_status_t
+i_ipadm_dhcp_status(ipadm_addrobj_t addr, dhcp_status_t *status,
+ int *dhcperror)
+{
+ dhcp_ipc_type_t type = DHCP_STATUS;
+ dhcp_ipc_request_t *request;
+ dhcp_ipc_reply_t *reply;
+ dhcp_status_t *private_status;
+ size_t reply_size;
+ int error;
+
+ if (addr->ipadm_af == AF_INET6)
+ type |= DHCP_V6;
+
+ request = dhcp_ipc_alloc_request(type, addr->ipadm_ifname, NULL, 0,
+ DHCP_TYPE_NONE);
+ if (request == NULL)
+ return (IPADM_NO_MEMORY);
+
+ error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
+ free(request);
+ if (error != 0) {
+ if (dhcperror != NULL)
+ *dhcperror = error;
+ return (error != DHCP_IPC_E_TIMEOUT ? IPADM_DHCP_IPC_ERROR
+ : IPADM_DHCP_IPC_TIMEOUT);
+ }
+
+ error = reply->return_code;
+ if (error == DHCP_IPC_E_UNKIF) {
+ free(reply);
+ bzero(status, sizeof (dhcp_status_t));
+ return (IPADM_NOTFOUND);
+ }
+
+ private_status = dhcp_ipc_get_data(reply, &reply_size, NULL);
+ if (reply_size < DHCP_STATUS_VER1_SIZE) {
+ free(reply);
+ return (IPADM_DHCP_IPC_ERROR);
+ }
+
+ /*
+ * Copy the status out of the memory allocated by this function into
+ * memory owned by the caller.
+ */
+ *status = *private_status;
+ free(reply);
+ return (IPADM_SUCCESS);
+}
+
+/*
* Returns the IP addresses of the specified interface in both the
* active and the persistent configuration. If no
* interface is specified, it returns all non-zero IP addresses
@@ -3026,21 +3344,19 @@ ipadm_free_addr_info(ipadm_addr_info_t *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.
@@ -3060,8 +3376,6 @@ i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
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 +3385,18 @@ i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
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 +3420,64 @@ i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
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;
+ }
+
+ if (pval != NULL) {
+ assert(pdp != NULL);
+ status = i_ipadm_persist_propval(iph, pdp, pval,
+ ipaddr, flags);
}
- assert(pdp != NULL);
- status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
}
+
ret:
nvlist_free(nvl);
return (status);
@@ -3322,7 +3687,6 @@ ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
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 +3728,7 @@ ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
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 +3736,30 @@ ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
}
/*
+ * 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 +3874,45 @@ i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
}
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 +3961,9 @@ ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
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;
diff --git a/usr/src/lib/libipadm/common/ipadm_ipmgmt.h b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
index 6a53cebc4b..06e870f30b 100644
--- a/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
+++ b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _IPADM_IPMGMT_H
@@ -51,8 +52,8 @@ extern "C" {
* For more information on these definitions please refer to the top of
* ipadm_persist.c. These are the name of the nvpairs which hold the
* respective values. All nvpairs private to ipadm have names that begin
- * with "_". Note below that 'prefixlen' is an address property and therefore
- * not a private nvpair name.
+ * with "_". Note below that 'prefixlen' and 'reqhost' are address
+ * properties and therefore not a private nvpair name.
*/
#define IPADM_NVP_PROTONAME "_protocol" /* protocol name */
#define IPADM_NVP_IFNAME "_ifname" /* interface name */
@@ -63,6 +64,7 @@ extern "C" {
#define IPADM_NVP_IPADDRHNAME "_aname" /* local hostname */
#define IPADM_NVP_IPDADDRHNAME "_dname" /* remote hostname */
#define IPADM_NVP_PREFIXLEN "prefixlen" /* prefixlen */
+#define IPADM_NVP_REQHOST "reqhost" /* requested hostname */
#define IPADM_NVP_IPV6ADDR "_ipv6addr" /* name of IPv6 addr nvlist */
#define IPADM_NVP_DHCP "_dhcp" /* name of DHCP nvlist */
#define IPADM_NVP_WAIT "_wait" /* DHCP timeout value */
@@ -152,6 +154,20 @@ typedef struct ipmgmt_prop_arg_s {
#define IPMGMT_APPEND 0x00000001
#define IPMGMT_REMOVE 0x00000002
+/*
+ * ipadm_addr_type_t-specific values that are cached in ipmgmtd and can
+ * make a round-trip back to client programs
+ */
+typedef union {
+ struct {
+ boolean_t ipmgmt_linklocal;
+ struct sockaddr_in6 ipmgmt_ifid;
+ } ipmgmt_ipv6_cache_s;
+ struct {
+ char ipmgmt_reqhost[MAXNAMELEN];
+ } ipmgmt_dhcp_cache_s;
+} ipmgmt_addr_type_cache_u;
+
/* IPMGMT_CMD_GETIF door_call argument structure */
typedef struct ipmgmt_getif_arg_s {
ipmgmt_door_cmd_type_t ia_cmd;
@@ -221,10 +237,15 @@ typedef struct ipmgmt_aobjop_arg_s {
* - PERSIST updates the permanent data store
* - INIT indicates that operation being performed is under init
* context
+ * - PROPS_ONLY indicates the update changes the running configuration of
+ * "props" data on the interface/address object. The props are
+ * cached there on the parent, so a PROPS_ONLY change does not
+ * affect the ACTIVE/PERSIST state of the parent.
*/
#define IPMGMT_ACTIVE 0x00000001
#define IPMGMT_PERSIST 0x00000002
#define IPMGMT_INIT 0x00000004
+#define IPMGMT_PROPS_ONLY 0x00000008
/* door call return value */
typedef struct ipmgmt_retval_s {
@@ -260,9 +281,14 @@ typedef struct ipmgmt_aobjop_rval_s {
sa_family_t ir_family;
uint32_t ir_flags;
ipadm_addr_type_t ir_atype;
- struct sockaddr_storage ir_ifid;
+ ipmgmt_addr_type_cache_u ir_atype_cache;
} ipmgmt_aobjop_rval_t;
+#define ipmgmt_ir_intfid ir_atype_cache. \
+ ipmgmt_ipv6_cache_s.ipmgmt_ifid
+#define ipmgmt_ir_reqhost ir_atype_cache. \
+ ipmgmt_dhcp_cache_s.ipmgmt_reqhost
+
/* DB walk callback functions */
typedef boolean_t db_wfunc_t(void *, nvlist_t *, char *, size_t, int *);
extern int ipadm_rw_db(db_wfunc_t *, void *, const char *, mode_t,
diff --git a/usr/src/lib/libipadm/common/ipadm_ndpd.c b/usr/src/lib/libipadm/common/ipadm_ndpd.c
index 88b9560236..29ea8ccf51 100644
--- a/usr/src/lib/libipadm/common/ipadm_ndpd.c
+++ b/usr/src/lib/libipadm/common/ipadm_ndpd.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -107,7 +108,7 @@ i_ipadm_create_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t addr,
}
/* Persist the intfid. */
- status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags);
+ status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags, NULL);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_addr(iph, addr);
(void) i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
diff --git a/usr/src/lib/libipadm/common/libipadm.c b/usr/src/lib/libipadm/common/libipadm.c
index 58297eda6b..9d57e1f16d 100644
--- a/usr/src/lib/libipadm/common/libipadm.c
+++ b/usr/src/lib/libipadm/common/libipadm.c
@@ -23,6 +23,7 @@
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Joyent, Inc.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <stdio.h>
@@ -737,12 +738,13 @@ i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
} else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
&aobjstr) == 0) {
/*
- * For a static address, we need to search for
- * the prefixlen in the nvlist `ifnvl'.
+ * For addresses, we need to relocate addrprops from the
+ * nvlist `ifnvl'.
*/
if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
- nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
- status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
+ nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
+ nvlist_exists(nvl, IPADM_NVP_DHCP)) {
+ status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
nvl, aobjstr);
if (status != IPADM_SUCCESS)
continue;
@@ -977,3 +979,80 @@ reopen:
}
return (err);
}
+
+/*
+ * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
+ * NULL, empty, or a single space (e.g., as returned by
+ * domainname(1M)/sysinfo).
+ *
+ * input: const char *: the hostname to inspect;
+ * output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
+ * criteria above; otherwise, B_FALSE;
+ */
+
+boolean_t
+ipadm_is_nil_hostname(const char *hostname)
+{
+ return (hostname == NULL || *hostname == '\0' ||
+ (*hostname == ' ' && hostname[1] == '\0'));
+}
+
+/*
+ * ipadm_is_valid_hostname(): check whether a string is a valid hostname
+ *
+ * input: const char *: the string to verify as a hostname
+ * output: boolean_t: B_TRUE if the string is a valid hostname
+ *
+ * Note that we accept host names beginning with a digit, which is not
+ * strictly legal according to the RFCs but is in common practice, so we
+ * endeavour to not break what customers are using.
+ *
+ * RFC 1035 limits a wire-format domain name to 255 octets. For a printable
+ * `hostname' as we have, the limit is therefore 253 characters (excluding
+ * the terminating '\0'--or 254 characters if the last character of
+ * `hostname' is a '.'.
+ *
+ * Excerpt from section 2.3.1., Preferred name syntax:
+ *
+ * <domain> ::= <subdomain> | " "
+ * <subdomain> ::= <label> | <subdomain> "." <label>
+ * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+ * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+ * <let-dig-hyp> ::= <let-dig> | "-"
+ * <let-dig> ::= <letter> | <digit>
+ */
+boolean_t
+ipadm_is_valid_hostname(const char *hostname)
+{
+ const size_t MAX_READABLE_NAME_LEN = 253;
+ char last_char;
+ size_t has_last_dot, namelen, i;
+
+ if (hostname == NULL)
+ return (B_FALSE);
+
+ namelen = strlen(hostname);
+ if (namelen < 1)
+ return (B_FALSE);
+
+ last_char = hostname[namelen - 1];
+ has_last_dot = last_char == '.';
+
+ if (namelen > MAX_READABLE_NAME_LEN + has_last_dot ||
+ last_char == '-')
+ return (B_FALSE);
+
+ for (i = 0; hostname[i] != '\0'; i++) {
+ /*
+ * As noted above, this deviates from RFC 1035 in that it
+ * allows a leading digit.
+ */
+ if (isalpha(hostname[i]) || isdigit(hostname[i]) ||
+ (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0)))
+ continue;
+
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
diff --git a/usr/src/lib/libipadm/common/libipadm.h b/usr/src/lib/libipadm/common/libipadm.h
index d26f07e7ef..0d8e3fdd7b 100644
--- a/usr/src/lib/libipadm/common/libipadm.h
+++ b/usr/src/lib/libipadm/common/libipadm.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#ifndef _LIBIPADM_H
#define _LIBIPADM_H
@@ -29,6 +30,7 @@ extern "C" {
#endif
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netdb.h>
@@ -100,8 +102,8 @@ typedef enum {
*
* - IPADM_OPT_PERSIST:
* For all the create/delete/up/down/set/get functions,
- * requests to persist the configuration so that it can be
- * re-enabled or reapplied on boot.
+ * requests to persist the configuration so that it can be
+ * re-enabled or re-applied on boot.
*
* - IPADM_OPT_ACTIVE:
* Requests to apply configuration without persisting it and
@@ -141,7 +143,17 @@ typedef enum {
* Used to bring up a static address on creation
*
* - IPADM_OPT_V46
- * Used to plumb both IPv4 and IPv6 interfaces by ipadm_create_addr()
+ * Used to plumb both IPv4 and IPv6 interfaces by ipadm_create_addr()
+ *
+ * - IPADM_OPT_SET_PROPS
+ * Used to indicate the update changes the running configuration of
+ * "props" data on the object. The props are cached there on the parent,
+ * but the PROPS_ONLY change does not affect the ACTIVE/PERSIST state of
+ * the parent.
+ *
+ * - IPADM_OPT_PERSIST_PROPS
+ * Used when IPADM_OPT_SET_PROPS is active to indicate the update changes
+ * the persistent configuration of the "props" data on the object.
*/
#define IPADM_OPT_PERSIST 0x00000001
#define IPADM_OPT_ACTIVE 0x00000002
@@ -157,6 +169,8 @@ typedef enum {
#define IPADM_OPT_INFORM 0x00000800
#define IPADM_OPT_UP 0x00001000
#define IPADM_OPT_V46 0x00002000
+#define IPADM_OPT_SET_PROPS 0x00004000
+#define IPADM_OPT_PERSIST_PROPS 0x00008000
/* IPADM property class */
#define IPADMPROP_CLASS_MODULE 0x00000001 /* on 'protocol' only */
@@ -257,7 +271,7 @@ extern void ipadm_close(ipadm_handle_t);
/* Check authorization for network configuration */
extern boolean_t ipadm_check_auth(void);
/*
- * Interface mangement functions
+ * Interface management functions
*/
extern ipadm_status_t ipadm_create_if(ipadm_handle_t, char *, sa_family_t,
uint32_t);
@@ -315,6 +329,7 @@ extern ipadm_status_t ipadm_set_stateful(ipadm_addrobj_t, boolean_t);
/* Functions to set fields in addrobj for DHCP */
extern ipadm_status_t ipadm_set_primary(ipadm_addrobj_t, boolean_t);
extern ipadm_status_t ipadm_set_wait_time(ipadm_addrobj_t, int32_t);
+extern ipadm_status_t ipadm_set_reqhost(ipadm_addrobj_t, const char *);
/*
* Property management functions
@@ -357,6 +372,8 @@ extern int ipadm_legacy2new_propname(const char *, char *,
uint_t, uint_t *);
extern int ipadm_new2legacy_propname(const char *, char *,
uint_t, uint_t);
+extern boolean_t ipadm_is_valid_hostname(const char *hostname);
+extern boolean_t ipadm_is_nil_hostname(const char *hostname);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libipadm/common/libipadm_impl.h b/usr/src/lib/libipadm/common/libipadm_impl.h
index 93230d8380..98b95092d9 100644
--- a/usr/src/lib/libipadm/common/libipadm_impl.h
+++ b/usr/src/lib/libipadm/common/libipadm_impl.h
@@ -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>.
*/
#ifndef _LIBIPADM_IMPL_H
@@ -87,6 +88,7 @@ struct ipadm_addrobj_s {
struct {
boolean_t ipadm_primary;
int32_t ipadm_wait;
+ char ipadm_reqhost[MAXNAMELEN];
} ipadm_dhcp_s;
} ipadm_addr_u;
};
@@ -102,6 +104,7 @@ struct ipadm_addrobj_s {
#define ipadm_stateful ipadm_addr_u.ipadm_ipv6_intfid_s.ipadm_stateful
#define ipadm_primary ipadm_addr_u.ipadm_dhcp_s.ipadm_primary
#define ipadm_wait ipadm_addr_u.ipadm_dhcp_s.ipadm_wait
+#define ipadm_reqhost ipadm_addr_u.ipadm_dhcp_s.ipadm_reqhost
/*
* Data structures and callback functions related to property management
@@ -145,7 +148,8 @@ extern ipadm_status_t i_ipadm_init_ifobj(ipadm_handle_t, const char *,
nvlist_t *);
extern ipadm_status_t i_ipadm_init_addrobj(ipadm_handle_t, nvlist_t *);
extern ipadm_status_t i_ipadm_addr_persist(ipadm_handle_t,
- const ipadm_addrobj_t, boolean_t, uint32_t);
+ const ipadm_addrobj_t, boolean_t, uint32_t,
+ const char *);
extern ipadm_status_t i_ipadm_delete_addr(ipadm_handle_t, ipadm_addrobj_t);
extern int i_ipadm_strioctl(int, int, char *, int);
extern boolean_t i_ipadm_is_loopback(const char *);
@@ -185,7 +189,7 @@ extern ipadm_status_t i_ipadm_get_persist_propval(ipadm_handle_t,
/* ipadm_addr.c */
extern void i_ipadm_init_addr(ipadm_addrobj_t, const char *,
const char *, ipadm_addr_type_t);
-extern ipadm_status_t i_ipadm_merge_prefixlen_from_nvl(nvlist_t *, nvlist_t *,
+extern ipadm_status_t i_ipadm_merge_addrprops_from_nvl(nvlist_t *, nvlist_t *,
const char *);
extern ipadm_status_t i_ipadm_get_addrobj(ipadm_handle_t, ipadm_addrobj_t);
extern ipadm_status_t i_ipadm_enable_static(ipadm_handle_t, const char *,
diff --git a/usr/src/lib/libipadm/common/mapfile-vers b/usr/src/lib/libipadm/common/mapfile-vers
index 7bb23f9895..7b03b77f33 100644
--- a/usr/src/lib/libipadm/common/mapfile-vers
+++ b/usr/src/lib/libipadm/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
#
@@ -67,6 +68,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
ipadm_if_info;
ipadm_if_move;
ipadm_init_net_from_gz;
+ ipadm_is_nil_hostname;
+ ipadm_is_valid_hostname;
ipadm_legacy2new_propname;
ipadm_ndpd_read;
ipadm_ndpd_write;
@@ -80,6 +83,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
ipadm_set_addr;
ipadm_set_addrprop;
ipadm_set_dst_addr;
+ ipadm_set_reqhost;
ipadm_set_ifprop;
ipadm_set_interface_id;
ipadm_set_primary;
diff --git a/usr/src/lib/libnwam/Makefile.com b/usr/src/lib/libnwam/Makefile.com
index b569916b63..41b2af85d0 100644
--- a/usr/src/lib/libnwam/Makefile.com
+++ b/usr/src/lib/libnwam/Makefile.com
@@ -21,6 +21,7 @@
#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
LIBRARY= libnwam.a
@@ -43,7 +44,8 @@ include ../../Makefile.lib
include ../../Makefile.rootfs
LIBS = $(DYNLIB) $(LINTLIB)
-LDLIBS += -lbsm -lc -ldladm -lnsl -lnvpair -lscf -lsecdb -lsocket
+LDLIBS += -lbsm -lc -ldladm -lnsl -lnvpair -lscf -lsecdb -lsocket \
+ -lipadm
SRCDIR = ../common
$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
diff --git a/usr/src/lib/libnwam/common/libnwam.h b/usr/src/lib/libnwam/common/libnwam.h
index 3cc7c724b5..7d9025a399 100644
--- a/usr/src/lib/libnwam/common/libnwam.h
+++ b/usr/src/lib/libnwam/common/libnwam.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -447,6 +448,8 @@ typedef enum {
#define NWAM_NCU_PROP_IPV6_ADDRSRC "ipv6-addrsrc"
#define NWAM_NCU_PROP_IPV6_ADDR "ipv6-addr"
#define NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE "ipv6-default-route"
+#define NWAM_NCU_PROP_IP_PRIMARY "ip-primary"
+#define NWAM_NCU_PROP_IP_REQHOST "ip-reqhost"
/* Some properties should only be set on creation */
#define NWAM_NCU_PROP_SETONCE(prop) \
diff --git a/usr/src/lib/libnwam/common/libnwam_ncp.c b/usr/src/lib/libnwam/common/libnwam_ncp.c
index 75f5b5827a..ed6948e0b5 100644
--- a/usr/src/lib/libnwam/common/libnwam_ncp.c
+++ b/usr/src/lib/libnwam/common/libnwam_ncp.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
#include <assert.h>
@@ -39,6 +40,7 @@
#include <strings.h>
#include <unistd.h>
#include <libdladm.h>
+#include <libipadm.h>
#include "libnwam_impl.h"
#include <libnwam_priv.h>
@@ -73,6 +75,7 @@ static nwam_error_t valid_link_mtu(nwam_value_t);
static nwam_error_t valid_ip_version(nwam_value_t);
static nwam_error_t valid_addrsrc_v4(nwam_value_t);
static nwam_error_t valid_addrsrc_v6(nwam_value_t);
+static nwam_error_t valid_reqhost(nwam_value_t);
struct nwam_prop_table_entry ncu_prop_table_entries[] = {
{NWAM_NCU_PROP_TYPE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1, valid_type,
@@ -149,7 +152,16 @@ struct nwam_prop_table_entry ncu_prop_table_entries[] = {
{NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
1, nwam_valid_route_v6,
"specifies per-interface default IPv6 route",
- NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}
+ NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
+ {NWAM_NCU_PROP_IP_PRIMARY, NWAM_VALUE_TYPE_BOOLEAN, B_FALSE, 0,
+ 1, nwam_valid_boolean,
+ "specifies the status of an interface as primary for the delivery"
+ " of client-wide configuration data",
+ NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
+ {NWAM_NCU_PROP_IP_REQHOST, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
+ 1, valid_reqhost,
+ "specifies a requested hostname for the interface",
+ NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
};
#define NWAM_NUM_NCU_PROPS (sizeof (ncu_prop_table_entries) / \
@@ -1648,6 +1660,17 @@ valid_addrsrc_v6(nwam_value_t value)
return (NWAM_ENTITY_INVALID_VALUE);
}
+static nwam_error_t
+valid_reqhost(nwam_value_t value)
+{
+ char *hostname;
+
+ if (nwam_value_get_string(value, &hostname) != NWAM_SUCCESS)
+ return (NWAM_ENTITY_INVALID_VALUE);
+ return (ipadm_is_valid_hostname(hostname) ? NWAM_SUCCESS
+ : NWAM_ENTITY_INVALID_VALUE);
+}
+
/* ARGSUSED0 */
static nwam_error_t
valid_link_mtu(nwam_value_t value)
diff --git a/usr/src/lib/libresolv2/common/mapfile-vers b/usr/src/lib/libresolv2/common/mapfile-vers
index cc19f12da1..28691e09c0 100644
--- a/usr/src/lib/libresolv2/common/mapfile-vers
+++ b/usr/src/lib/libresolv2/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
#
#
@@ -104,6 +105,7 @@ SYMBOL_VERSION SUNWprivate_2.2 {
isc_puthexstring;
__log_close_debug_channels;
__memactive;
+ __ns_name_pton2;
p_sockun;
res_gethostbyname2;
res_getservers;
diff --git a/usr/src/man/man1m/dhcpagent.1m b/usr/src/man/man1m/dhcpagent.1m
index 03c0c8b8ca..045056d89c 100644
--- a/usr/src/man/man1m/dhcpagent.1m
+++ b/usr/src/man/man1m/dhcpagent.1m
@@ -1,9 +1,10 @@
'\" te
.\" Copyright (c) 1992-1996 Competitive Automation, Inc. Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DHCPAGENT 1M "Dec 11, 2015"
+.TH DHCPAGENT 1M "Jun 30, 2017"
.SH NAME
dhcpagent \- Dynamic Host Configuration Protocol (DHCP) client daemon
.SH SYNOPSIS
@@ -15,7 +16,7 @@ dhcpagent \- Dynamic Host Configuration Protocol (DHCP) client daemon
.SH DESCRIPTION
.LP
\fBdhcpagent\fR implements the client half of the Dynamic Host Configuration
-Protocol \fB(DHCP)\fR for machines running Solaris software.
+Protocol \fB(DHCP)\fR for machines running illumos software.
.sp
.LP
The \fBdhcpagent\fR daemon obtains configuration parameters for the client
@@ -28,11 +29,12 @@ it must negotiate an extension using \fBDHCP\fR. For this reason,
powers down.
.sp
.LP
-For IPv4, the \fBdhcpagent\fR daemon is controlled through \fBifconfig\fR(1M)
-in much the same way that the \fBinit\fR(1M) daemon is controlled by
-\fBtelinit\fR(1M). \fBdhcpagent\fR can be invoked as a user process, albeit one
-requiring root privileges, but this is not necessary, as \fBifconfig\fR(1M)
-will start it automatically.
+For IPv4, the \fBdhcpagent\fR daemon is controlled through \fBipadm\fR(1M),
+\fBnwamcfg\fR(1M), or \fBifconfig\fR(1M) in much the same way that the
+\fBinit\fR(1M) daemon is controlled by \fBtelinit\fR(1M). \fBdhcpagent\fR can
+be invoked as a user process, albeit one requiring root privileges, but this is
+not necessary, as \fBipadm\fR(1M), \fBnwamcfg\fR(1M), or \fBifconfig\fR(1M)
+will start \fBdhcpagent\fR automatically.
.sp
.LP
For IPv6, the \fBdhcpagent\fR daemon is invoked automatically by
@@ -41,16 +43,20 @@ necessary.
.sp
.LP
When invoked, \fBdhcpagent\fR enters a passive state while it awaits
-instructions from \fBifconfig\fR(1M) or \fBin.ndpd\fR(1M). When it receives a
-command to configure an interface, it brings up the interface (if necessary)
-and starts DHCP. Once DHCP is complete, \fBdhcpagent\fR can be queried for the
-values of the various network parameters. In addition, if DHCP was used to
-obtain a lease on an address for an interface, it configures the address for
-use. When a lease is obtained, it is automatically renewed as necessary. If the
+instructions from \fBipadm\fR(1M), \fBnwamcfg\fR(1M), \fBifconfig\fR(1M), or
+\fBin.ndpd\fR(1M). When \fBdhcpagent\fR receives a command to configure an
+interface, \fBdhcpagent\fR brings up the interface (if necessary) and starts
+DHCP. Once DHCP is complete, \fBdhcpagent\fR can be queried for the values of
+the various network parameters. In addition, if DHCP was used to obtain a lease
+on an address for an interface, \fBdhcpagent\fR configures the address for use.
+When a lease is obtained, it is automatically renewed as necessary. If the
lease cannot be renewed, \fBdhcpagent\fR will unconfigure the address, but the
-interface will be left up and \fBdhcpagent\fR will attempt to acquire a new
-address lease. \fBdhcpagent\fR monitors system suspend/resume events and will
-validate any non-permanent leases with the DHCP server upon resume. Similarly,
+interface will be left up, and \fBdhcpagent\fR will attempt to acquire a new
+address lease.
+.sp
+.LP
+\fBdhcpagent\fR monitors system suspend/resume events and will validate any
+non-permanent leases with the DHCP server upon resume. Similarly,
\fBdhcpagent\fR monitors link up/down events and will validate any
non-permanent leases with the DHCP server when the downed link is brought back
up. The lease validation mechanism will restart DHCP if the server indicates
@@ -102,10 +108,10 @@ parameters in the case where no specific interface is requested. See
.sp
.LP
For IPv4, the \fBdhcpagent\fR daemon can be configured to request a particular
-host name. See the \fBREQUEST_HOSTNAME\fR description in the \fBFILES\fR
-section. When first configuring a client to request a host name, you must
-perform the following steps as root to ensure that the full DHCP negotiation
-takes place:
+Fully Qualified Domain Name (FQDN) or host name. See the \fBREQUEST_FQDN\fR or
+\fBREQUEST_HOSTNAME\fR description in the \fBFILES\fR section. When first
+configuring a client to request an FQDN or host name, you must perform the
+following steps as root to ensure that the full DHCP negotiation takes place:
.sp
.in +2
.nf
@@ -494,9 +500,14 @@ using REQUEST (for DHCPv4) or Confirm (DHCPv6).
.ad
.sp .6
.RS 4n
-Contains persistent storage for DUID (DHCP Unique Identifier) and IAID
-(Identity Association Identifier) values. The format of these files is
-undocumented, and applications should not read from or write to them.
+Contains persistent storage for system-generated DUID (DHCP Unique Identifier)
+and interface-specific IAID (Identity Association Identifier) values which are
+used if no \fBCLIENT_ID\fR is defined (see below). The format of these files is
+undocumented, and applications should not read from or write to them. Instead,
+\fBdhcpinfo\fR(1) can be used to query the \fBdhcpagent\fR for \fIClientID\fR.
+For DHCPv6 interfaces, the result will contain the DUID. For DHCPv4 interfaces
+with \fBV4_DEFAULT_IAID_DUID\fR enabled (see below), the result will contain
+the IAID and DUID.
.RE
.sp
@@ -536,6 +547,8 @@ remaining) and a new one obtained.
.sp
Enabling this option is often desirable on mobile systems, such as laptops, to
allow the system to recover quickly from moves.
+.sp
+Default value of this option is \fIno\fR.
.RE
.sp
@@ -545,9 +558,11 @@ allow the system to recover quickly from moves.
.ad
.sp .6
.RS 4n
-Indicates how long to wait between checking for valid \fBOFFER\fRs after
-sending a \fBDISCOVER\fR. For DHCPv6, sets the time to wait between checking
-for valid Advertisements after sending a Solicit.
+Indicates how long to wait in seconds between checking for valid
+\fBOFFER\fRs after sending a \fBDISCOVER\fR. For DHCPv6, sets the time to
+wait between checking for valid Advertisements after sending a Solicit.
+.sp
+Default value of this option is \fI3\fR.
.RE
.sp
@@ -630,6 +645,26 @@ format. Thus, "\fBSun\fR" and \fB0x53756E\fR are equivalent.
.sp
.ne 2
.na
+\fB\fBV4_DEFAULT_IAID_DUID\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates whether to use, when CLIENT_ID is not defined, a system-managed,
+RFC 3315-style (i.e., DHCPv6-style) binding identifier as documented in
+RFC 4361, "Node-specific Client Identifiers for DHCPv4," for IPv4
+interfaces which for purposes of backward compatibility do not normally get
+default binding identifiers.
+.sp
+An IPv4 interface that is not in an IP network multipathing (IPMP) group,
+that is not IP over InfiniBand (IPoIB), and that is not a logical interface
+does not normally get a default binding identifier.
+.sp
+Default value of this option is \fIno\fR.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBPARAM_REQUEST_LIST\fR\fR
.ad
.sp .6
@@ -658,13 +693,106 @@ default router.
.sp
.ne 2
.na
+\fB\fBREQUEST_FQDN\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates the client requests the DHCP server to map the client's leased
+IPv4 address to the Fully Qualified Domain Name (FQDN) associated with the
+network interface that performs DHCP on the client and to collaborate with
+a compatible DNS server to manage A and PTR resource records for the FQDN
+for the life of the lease.
+.sp .6
+The \fIhostname\fR in the FQDN is determined from the following possible
+configurations:
+.sp
+.ne 2
+.na
+1. \fBipadm\fR(1M): include the \fB-1,--primary\fR flag when creating an
+address that uses DHCP so that \fBnodename\fR(4) is used as the
+\fIhostname\fR.
+.ad
+.sp
+.ne 2
+.na
+2. \fBipadm\fR(1M): include the \fB-h,--reqhost\fR \fIhostname\fR switch
+when executing the \fBcreate-addr -T dhcp\fR subcommand, or use the
+\fBset-addrprop -p reqhost=\fR\fIhostname\fR subcommand for any existing
+DHCP address.
+.ad
+.sp
+.ne 2
+.na
+3. \fBnwamcfg\fR(1M): set a property,
+\fBip-primary=\fR\fIon\fR, for an ncu ip that uses DHCP so that
+\fBnodename\fR(4) is used as the \fIhostname\fR.
+.ad
+.sp
+.ne 2
+.na
+4. \fBnwamcfg\fR(1M): set a property,
+\fBip-reqhost=\fR\fIhostname\fR, for an ncu ip that uses DHCP.
+.ad
+.sp
+The \fIhostname\fR value is either a Partially Qualified Domain Name (PQDN)
+or an FQDN (i.e., a "rooted" domain name ending with a '.' or one inferred
+to be an FQDN if it contains at least three DNS labels such as
+srv.example.com). If a PQDN is specified, then an FQDN is constructed if
+\fBDNS_DOMAINNAME\fR is defined or if \fBADOPT_DOMAINNAME\fR is set to
+\fIyes\fR and an eligible domain name (as described below) is available.
+.sp
+If an FQDN is sent, \fBREQUEST_HOSTNAME\fR processing will not be done,
+per RFC 4702 (3.1): "clients that send the Client FQDN option in their
+messages MUST NOT also send the Host Name."
+.sp
+Default value of this option is \fIyes\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBDNS_DOMAINNAME\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates the value that should be appended to a PQDN specified by the
+\fB-h,--reqhost\fR option of \fBipadm\fR(1M), by the ncu \fBip-reqhost\fR
+property of \fBnwamcfg\fR(1M), or by \fBnodename\fR(4) to construct an FQDN
+for \fBREQUEST_FQDN\fR processing.
+If the \fIhostname\fR value is already an FQDN, then the value of this
+option is not used.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBADOPT_DOMAINNAME\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates that a domain name returned by the DHCP server or the \fBdomain\fR
+from \fBresolv.conf\fR(4) should be adopted if needed to construct an FQDN
+from a PQDN specified by the \fB-h,--reqhost\fR option of \fBipadm\fR(1M),
+by the ncu \fBip-reqhost\fR property of \fBnwamcfg\fR(1M), or by
+\fBnodename\fR(4).
+If the \fIhostname\fR value is already an FQDN, then the value of this
+option is not applicable.
+The eligible DHCP option for domain name is DHCPv4 \fBDNSdmain\fR.
+.sp
+Default value of this option is \fIno\fR.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBREQUEST_HOSTNAME\fR\fR
.ad
.sp .6
.RS 4n
Indicates the client requests the DHCP server to map the client's leased IPv4
address to the host name associated with the network interface that performs
-DHCP on the client. The host name must be specified in the
+DHCP on the client. The host name must be specified as documented for a
+PQDN in \fBREQUEST_FQDN\fR above or specified in the
\fB/etc/hostname.\fIinterface\fR\fR file for the relevant interface on a line
of the form
.sp
@@ -678,6 +806,8 @@ inet \fIhostname\fR
where \fIhostname\fR is the host name requested.
.sp
This option works with DHCPv4 only.
+.sp
+Default value of this option is \fIyes\fR.
.RE
.RE
@@ -710,7 +840,8 @@ Interface Stability Committed
.SH SEE ALSO
.LP
\fBdhcpinfo\fR(1), \fBifconfig\fR(1M), \fBinit\fR(1M), \fBin.mpathd\fR(1M),
-\fBin.ndpd\fR(1M), \fBsyslog\fR(3C), \fBattributes\fR(5), \fBdhcp\fR(5)
+\fBin.ndpd\fR(1M), \fBipadm\fR(1M), \fBnwamcfg\fR(1M), \fBsyslog\fR(3C),
+\fBnodename\fR(4), \fBresolv.conf\fR(4), \fBattributes\fR(5), \fBdhcp\fR(5)
.sp
.LP
\fI\fR
diff --git a/usr/src/man/man1m/ipadm.1m b/usr/src/man/man1m/ipadm.1m
index 1a8ea8a54d..ecc7ea87ca 100644
--- a/usr/src/man/man1m/ipadm.1m
+++ b/usr/src/man/man1m/ipadm.1m
@@ -12,8 +12,9 @@
.\" Copyright (c) 2012, Joyent, Inc. All Rights Reserved
.\" Copyright (c) 2013 by Delphix. All rights reserved.
.\" Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+.\" Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
.\"
-.Dd April 9, 2016
+.Dd June 16, 2017
.Dt IPADM 1M
.Os
.Sh NAME
@@ -70,6 +71,8 @@
.Op Fl t
.Fl T Cm dhcp
.Op Fl w Ar seconds Ns | Ns Cm forever
+.Op Fl 1
+.Op Fl h Ar hostname
.Ar addrobj
.Nm
.Ic create-addr
@@ -418,6 +421,8 @@ subcommand for the list of property names.
.Op Fl t
.Fl T Cm dhcp
.Op Fl w Ar seconds Ns | Ns Cm forever
+.Op Fl 1
+.Op Fl h Ar hostname
.Ar addrobj
.br
.Nm
@@ -466,7 +471,32 @@ Obtain the address via DHCP.
This takes the following options:
.Bl -tag -width ""
.It Fl w Ns \&, Ns Fl -wait
-Specify the time, in seconds, that the command should wait to obtain an address.
+Specify the time, in seconds, that the command should wait to obtain an
+address; or specify
+.Cm forever
+to wait without interruption.
+The default value is 120.
+.It Fl 1 Ns \&, Ns Fl -primary
+Specify that the interface is primary.
+One effect will be that
+.Xr nodename 4
+will serve as
+.Fl h Ns \&, Ns Fl -reqhost
+if that switch is not otherwise specified.
+.It Fl h Ns \&, Ns Fl -reqhost
+Specify the host name to send to the DHCP server in order to request an
+association of a Fully Qualified Domain Name to the interface.
+An FQDN is determined from
+.Ar hostname
+if it is "rooted" (ending in a '.'), or if it consists of at least three
+DNS labels, or by appending to
+.Ar hostname
+the DNS domain name value configured in
+.Pa /etc/default/dhcpagent
+for
+.Xr dhcpagent 1m .
+N.b. that the DHCP server implementation ultimately determines whether and
+how the client-sent FQDN is used.
.El
.It Fl T Cm addrconf
Create an auto-configured address.
@@ -647,14 +677,29 @@ The address should not be used to send packets but can still receive packets
.Pq Cm on Ns / Ns Cm off .
.It Cm prefixlen
The number of bits in the IPv4 netmask or IPv6 prefix.
+.It Cm primary
+The DHCP primary interface flag (read-only).
.It Cm private
The address is not advertised to routing
.Pq Cm on Ns / Ns Cm off .
+.It Cm reqhost
+The host name to send to the DHCP server in order to request an association
+of an FQDN to the interface.
+For a primary DHCP interface,
+.Xr nodename 4
+is sent if this property is not defined.
+See the
+.Nm
+.Ic create-addr
+.Fl T Cm dhcp
+subcommand for an explanation of how an FQDN is determined.
.It Cm transmit
Packets can be transmitted
.Pq Cm on Ns / Ns Cm off .
.It Cm zone
-The zone the addrobj is in.
+The zone the addrobj is in (temporary-only--use
+.Xr zonecfg 1M
+to make persistent).
.El
.It Fl t Ns \&, Ns Fl -temporary
Temporary, not persistent across reboots.
@@ -847,10 +892,12 @@ subcommand for the list of property names.
.Sh SEE ALSO
.Xr arp 1M ,
.Xr cfgadm 1M ,
+.Xr dhcpagent 1M ,
.Xr dladm 1M ,
.Xr if_mpadm 1M ,
.Xr ifconfig 1M ,
.Xr ndd 1M ,
.Xr zonecfg 1M ,
+.Xr nodename 4 ,
.Xr nsswitch.conf 4 ,
.Xr dhcp 5
diff --git a/usr/src/man/man4/dhcp_inittab.4 b/usr/src/man/man4/dhcp_inittab.4
index a22148a405..bf0c305f62 100644
--- a/usr/src/man/man4/dhcp_inittab.4
+++ b/usr/src/man/man4/dhcp_inittab.4
@@ -1,13 +1,13 @@
'\" te
.\" Copyright (C) 2009, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with
.\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DHCP_INITTAB 4 "Aug 31, 2009"
+.TH DHCP_INITTAB 4 "Oct 31, 2016"
.SH NAME
dhcp_inittab \- information repository for DHCP options
.SH DESCRIPTION
-.sp
.LP
The \fB/etc/dhcp/inittab\fR and the \fB/etc/dhcp/inittab6\fR files contain
information about the Dynamic Host Configuration Protocol (\fBDHCP\fR) options,
@@ -123,7 +123,6 @@ be further defined.
.RE
.SS "DHCP \fBinittab\fR and \fBinittab6\fR Format"
-.sp
.LP
Data entries are written one per line and have seven fields; each entry
provides information for one option. Each field is separated by a comma, except
@@ -361,7 +360,6 @@ this information, and should always be defined as \fBsdmi\fR for newly added
options.
.RE
.SS "Mnemonic Identifiers for IPv4 Options"
-.sp
.LP
The following table maps the mnemonic identifiers used in Solaris DHCP to
\fIRFC 2132\fR options:
@@ -377,7 +375,7 @@ _
Subnet Mask, dotted Internet address (IP).
T}
\fBUTCoffst\fR \fB2\fR T{
-Coordinated Universal time offset (seconds).
+Coordinated Universal time offset (seconds) [deprecated].
T}
\fBRouter\fR \fB3\fR List of Routers, IP.
\fBTimeserv\fR \fB4\fR List of RFC-868 servers, IP.
@@ -475,6 +473,7 @@ T}
\fBUserClas\fR \fB77\fR User class information, ASCII.
\fBSLP_DA\fR \fB78\fR Directory agent, OCTET.
\fBSLP_SS\fR \fB79\fR Service scope, OCTET.
+\fBClientFQDN\fR \fB81\fR Fully Qualified Domain Name, OCTET.
\fBAgentOpt\fR \fB82\fR Agent circuit ID, OCTET.
\fBFQDN\fR \fB89\fR Fully Qualified Domain Name, OCTET.
\fBPXEarch\fR \fB93\fR Client system architecture, NUMBER.
@@ -491,7 +490,6 @@ T}
.TE
.SS "Mnemonic Identifiers for IPv6 Options"
-.sp
.LP
The following table maps the mnemonic identifiers used in Solaris DHCP to RFC
3315, 3319, 3646, 3898, 4075, and 4280 options:
@@ -559,7 +557,6 @@ is of type \fBIP\fR Address, consisting of a potentially infinite number of
pairs of \fBIP\fR addresses.
.SH FILES
-.br
.in +2
\fB/etc/dhcp/inittab\fR
.in -2
@@ -568,7 +565,6 @@ pairs of \fBIP\fR addresses.
\fB/etc/dhcp/inittabv6\fR
.in -2
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -584,7 +580,6 @@ Interface Stability Committed
.TE
.SH SEE ALSO
-.sp
.LP
\fBdhcpinfo\fR(1), \fBdhcpagent\fR(1M), \fBisspace\fR(3C), \fBdhcptab\fR(4),
\fBattributes\fR(5), \fBdhcp\fR(5), \fBdhcp_modules\fR(5)
diff --git a/usr/src/uts/common/netinet/dhcp.h b/usr/src/uts/common/netinet/dhcp.h
index 0cf5660af3..73b233ad33 100644
--- a/usr/src/uts/common/netinet/dhcp.h
+++ b/usr/src/uts/common/netinet/dhcp.h
@@ -22,6 +22,7 @@
/*
* Copyright 1996-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
/*
@@ -31,8 +32,6 @@
#ifndef _DHCP_H
#define _DHCP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -157,8 +156,15 @@ extern "C" {
#define CD_SLPDA 78
#define CD_SLPSS 79
+#define CD_CLIENTFQDN 81
#define CD_AGENTOPT 82
+
+/*
+ * Per RFC 3679, option 89 was "Never published as standard and [is] not in
+ * general use". See active CD_CLIENTFQDN and RFC 4702.
+ */
#define CD_FQDN 89
+
#define CD_PXEARCHi 93
#define CD_PXENIIi 94
#define CD_PXECID 95
diff --git a/usr/src/uts/common/sys/scsi/targets/sddef.h b/usr/src/uts/common/sys/scsi/targets/sddef.h
index a9c8c903da..da9f25c4ae 100644
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h
@@ -1752,12 +1752,6 @@ struct sd_fm_internal {
#endif
/*
- * 60 seconds is what we will wait for to reset the
- * throttle back to it SD_MAX_THROTTLE.
- */
-#define SD_RESET_THROTTLE_TIMEOUT 60
-
-/*
* Number of times we'll retry a normal operation.
*
* This includes retries due to transport failure